增加/api/Menu/GetConfig?configName=HelperDescrip接口,根据HTTP状态码匹配帮助描述文本

This commit is contained in:
Allen 2025-05-18 12:56:40 +08:00
parent 8d89be590b
commit 89ee08789d
5 changed files with 323 additions and 233 deletions

View File

@ -5,275 +5,307 @@ const EIAC_DESKTOP_API_HOST = process.env.EIAC_DESKTOP_API_HOST || 'http://1.12.
* EIAC API
*/
export class EIAC_Desktop_Api {
private host: string;
/**
* API Host
*/
constructor(host = EIAC_DESKTOP_API_HOST) {
this.host = host;
}
private host: string;
/**
* API Host
*/
constructor(host = EIAC_DESKTOP_API_HOST) {
this.host = host;
}
/**
*
*/
public Auth = {
/**
*
* /api/Auth/Login
* @param request
* @param init
* @returns
*/
public Auth = {
/**
* /api/Auth/Login
* @param request
* @param init
* @returns
*/
LoginAsync: async (request: LoginRequest, init?: RequestInit) => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Auth/Login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(request),
...init
});
return await response.json() as ApiResponse<LoginResponse>;
}
};
/**
*
*/
public Menu = {
/**
* /api/Menu/GetMenu
* @param init
* @returns
*/
GetMenuAsync: async (init?: RequestInit) => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Menu/GetMenu`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
...init
});
return await response.json() as ApiResponse<MenuItem[]>;
LoginAsync: async (request: LoginRequest, init?: RequestInit): Promise<ApiResponse<LoginResponse>> => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Auth/Login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
/**
* /api/Menu/GetConfig
* @param configName
* @param init
* @returns
*/
GetConfigAsync: async (configName = 'TagResolution', init?: RequestInit) => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Menu/GetConfig?configName=${configName}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
...init
});
body: JSON.stringify(request),
...init
});
return await response.json() as ApiResponse<TagResolutionConfig[]>;
}
};
return await response.json() as ApiResponse<LoginResponse>;
}
};
/**
*
*/
public Menu = {
/**
* /api/Menu/GetMenu
* @param init
* @returns
*/
GetMenuAsync: async (init?: RequestInit): Promise<ApiResponse<MenuItem[]>> => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Menu/GetMenu`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
...init
});
return await response.json() as ApiResponse<MenuItem[]>;
},
/**
* /api/Menu/GetConfig
* @param configName
* @param init
* @returns
*/
GetConfigAsync: async <T>(configName: string, init?: RequestInit): Promise<ApiResponse<T>> => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Menu/GetConfig?configName=${configName}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
...init
});
return await response.json() as ApiResponse<T>;
},
/**
*
* /api/Menu/GetConfig?configName=TagResolution
* @param init
* @returns
*/
public Help = {
/**
* /api/Help/FaultReporting
* @param request
* @param init
* @returns
*/
FaultReportingAsync: async (request: FaultReportingRequest, init?: RequestInit) => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Help/FaultReporting`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(request),
...init
});
GetTagResolutionsAsync: (init?: RequestInit): Promise<ApiResponse<TagResolutionConfig[]>> => {
return this.Menu.GetConfigAsync<TagResolutionConfig[]>('TagResolution', init);
},
return await response.json() as ApiResponse<FaultReportingResponse>;
}
};
/**
* /api/Menu/GetConfig?configName=HelperDescrip
* @param init
* @returns
*/
GetHelperDescripsAsync: (init?: RequestInit): Promise<ApiResponse<HelperDescription[]>> => {
return this.Menu.GetConfigAsync<HelperDescription[]>('HelperDescrip', init);
}
};
/**
*
*/
public Help = {
/**
* /api/Help/FaultReporting
* @param request
* @param init
* @returns
*/
FaultReportingAsync: async (request: FaultReportingRequest, init?: RequestInit): Promise<ApiResponse<FaultReportingResponse>> => {
const response = await fetch(`${this.host}/EIAC_Desktop_Api/api/Help/FaultReporting`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(request),
...init
});
return await response.json() as ApiResponse<FaultReportingResponse>;
}
};
}
/**
* API
*/
export interface ApiResponse<T = any> {
/**
* 00
*/
status: number;
/**
* HTTP状态码
*/
code: number;
/**
*
*/
msg: string;
/**
*
*/
data: T;
/**
* 00
*/
status: number;
/**
* HTTP状态码
*/
code: number;
/**
*
*/
msg: string;
/**
*
*/
data: T;
}
/**
*
*/
export interface LoginRequest {
/**
*
*/
Account: string;
/**
*
*/
Password: string;
/**
*
*/
Account: string;
/**
*
*/
Password: string;
}
/**
*
*/
export interface LoginResponse {
/**
*
*/
IsNeedSendSMS: boolean;
/**
*
*/
Token: string;
/**
* Cookies
*/
Cookies: Array<{ Key: string, Value: string }>;
/**
*
*/
IsNeedSendSMS: boolean;
/**
*
*/
Token: string;
/**
* Cookies
*/
Cookies: Array<{ Key: string, Value: string }>;
}
/**
*
*/
export interface MenuItem {
/**
*
*/
ShowName: string;
/**
*
*/
Url: string;
/**
*
*/
IconConfig: IconConfig;
/**
*
*/
Children: MenuItem[] | null;
/**
*
*/
ShowName: string;
/**
*
*/
Url: string;
/**
*
*/
IconConfig: IconConfig;
/**
*
*/
Children: MenuItem[] | null;
}
/**
*
*/
export interface IconConfig {
/**
* 1x
*/
_1x: {
/**
* 1x
*
*/
_1x: {
/**
*
*/
Default: string;
/**
*
*/
Selected: string;
};
Default: string;
/**
* 2x
*
*/
_2x: {
/**
*
*/
Default: string;
/**
*
*/
Selected: string;
};
Selected: string;
};
/**
* 2x
*/
_2x: {
/**
*
*/
Default: string;
/**
*
*/
Selected: string;
};
}
/**
* TagResolution
*/
export interface TagResolutionConfig {
/**
* ','
*/
Resolutions: string;
/**
*
*/
Percentage: string | number;
/**
*
*/
SpecialPUrl: SpecialPUrlItem[];
/**
* ','
*/
Resolutions: string;
/**
*
*/
Percentage: string | number;
/**
*
*/
SpecialPUrl: SpecialPUrlItem[];
}
/**
*
*/
export interface SpecialPUrlItem {
/**
* URL
*/
SPUrl: string;
/**
*
*/
SPPer: string | number;
/**
* URL
*/
SPUrl: string;
/**
*
*/
SPPer: string | number;
}
/**
*
*/
export interface HelperDescription {
/**
* HTTP状态码403*使
*/
Code: string;
/**
*
*/
Descrip: string;
}
/**
*
*/
export interface FaultReportingRequest {
/**
* IP
*/
IP: string;
/**
* URL
*/
Url: string;
/**
*
*/
Account: string;
/**
* Base64
*/
ImgBase64: string;
/**
*
*/
Explain: string;
/**
* IP
*/
IP: string;
/**
* URL
*/
Url: string;
/**
*
*/
Account: string;
/**
* Base64
*/
ImgBase64: string;
/**
*
*/
Explain: string;
}
/**
*
*/
export interface FaultReportingResponse {
/**
* ID
*/
FaultReportingId: string;
/**
* ID
*/
FaultReportingId: string;
}
export const EIACDesktopApi = new EIAC_Desktop_Api();

View File

@ -3,29 +3,45 @@ import http from 'http';
import https from 'https';
import os from 'os';
import { URL } from 'url';
import { ApiResponse, MenuItem, TagResolutionConfig, EIACDesktopApi, SpecialPUrlItem, FaultReportingResponse } from './EIAC_Desktop_Api';
import { ApiResponse, MenuItem, TagResolutionConfig, EIACDesktopApi, SpecialPUrlItem, FaultReportingResponse, HelperDescription } from './EIAC_Desktop_Api';
const memoryCache = new Map<string, any>();
export function initialize(): void {
// Set cache
ipcMain.handle('cache:set', (_event, key: string, value: any) => {
ipcMain.handle('cache:set', (_event, key: string, value: any): void => {
memoryCache.set(key, value);
});
// Get cache
ipcMain.handle('cache:get', (_event, key: string) => {
ipcMain.handle('cache:get', (_event, key: string): any | null => {
return memoryCache.get(key) ?? null;
});
// Get menu cache
ipcMain.handle('get-menu-cache', async () => menuData ?? await menuDataReadyPromise);
// Get config cache
ipcMain.handle('get-config-cache', async () => configData ?? await configDataReadyPromise);
// Get helper descrip by code
ipcMain.handle('get-helper-descrip', async (event, code: string): Promise<string | null> => {
if (!helperDescriptionData) {
await helperDescriptionDataReadyPromise;
}
if (helperDescriptionData.code != 200 || helperDescriptionData.status != 0) {
console.error('Get config failed:', helperDescriptionData.msg + ', status: ' + helperDescriptionData.status + ', code: ' + helperDescriptionData.code);
return null;
}
let helperDescrip: HelperDescription | null = helperDescriptionData.data.find(h => h.Code === code);
if (!helperDescrip) {
helperDescrip = helperDescriptionData.data.find(h => h.Code === '*');
}
return helperDescrip ? helperDescrip.Descrip : null;
});
// Get zoom factor
ipcMain.handle('get-zoom-factor-by-url', async (event, url: string) => {
ipcMain.handle('get-zoom-factor-by-url', async (event, url: string): Promise<number> => {
const display: Electron.Display = screen.getPrimaryDisplay();
const physicalSize: Electron.Size = {
width: display.size.width * display.scaleFactor,
@ -36,16 +52,16 @@ export function initialize(): void {
console.log(`Resolution: ${display.size.width}*${display.size.height}`);
console.log(`ScaleFactor: ${display.scaleFactor}`);
if (!configData) {
await configDataReadyPromise;
if (!tagResolutionData) {
await tagResolutionDataReadyPromise;
}
if (configData.code != 200 || configData.status != 0) {
console.error('Get config failed:', configData.msg + ', status: ' + configData.status + ', code: ' + configData.code);
if (tagResolutionData.code != 200 || tagResolutionData.status != 0) {
console.error('Get config failed:', tagResolutionData.msg + ', status: ' + tagResolutionData.status + ', code: ' + tagResolutionData.code);
return display.scaleFactor;
}
const configList: TagResolutionConfig[] = configData.data;
const configList: TagResolutionConfig[] = tagResolutionData.data;
let config: TagResolutionConfig = configList.find(c => c.Resolutions.includes(resolution));
if (!config) {
config = configList.find(c => c.Resolutions === '*');
@ -71,7 +87,7 @@ export function initialize(): void {
});
// Check if the URL is available
ipcMain.handle('check-url-available', async (event, rawUrl: string) => {
ipcMain.handle('check-url-available', async (event, rawUrl: string): Promise<{ ok: boolean, status: number, message: string }> => {
try {
const url: URL = new URL(rawUrl);
const lib = url.protocol === 'https:' ? https : http;
@ -138,7 +154,7 @@ export function initialize(): void {
});
// Set webviews cookie
ipcMain.handle('set-webview-cookie', async (event, url: string, cookie: string) => {
ipcMain.handle('set-webview-cookie', async (event, url: string, cookie: string): Promise<boolean> => {
try {
const parsedUrl = new URL(url);
const cookies: Array<{ Key: string, Value: string }> = JSON.parse(cookie);
@ -162,7 +178,7 @@ export function initialize(): void {
});
// Fault reporting
ipcMain.handle('fault-reporting', async (event, url: string, message: string, status: number) => {
ipcMain.handle('fault-reporting', async (event, url: string, message: string, status: number): Promise<{ ok: boolean, status: number, message: string }> => {
console.log('Fault reporting:', url, message, status);
const webContents = event.sender;
@ -197,6 +213,10 @@ export function initialize(): void {
});
}
/**
* IP地址
* @returns IP地址
*/
function getLocalIPAddress(): string | null {
const interfaces = os.networkInterfaces();
@ -212,6 +232,11 @@ function getLocalIPAddress(): string | null {
return null; // 没有找到
}
/**
* Base64格式的图像
* @param win
* @returns Base64格式的图像
*/
async function captureWindowAsBase64(win: BrowserWindow): Promise<string> {
const image = await win.capturePage(); // 截图
const pngBuffer = image.toPNG(); // 转为 PNG Buffer
@ -221,9 +246,14 @@ async function captureWindowAsBase64(win: BrowserWindow): Promise<string> {
let menuData: ApiResponse<MenuItem[]> = null;
let menuDataReadyPromise: Promise<ApiResponse<MenuItem[]>>;
let configData: ApiResponse<TagResolutionConfig[]> = null;
let configDataReadyPromise: Promise<ApiResponse<TagResolutionConfig[]>>;
let tagResolutionData: ApiResponse<TagResolutionConfig[]> = null;
let tagResolutionDataReadyPromise: Promise<ApiResponse<TagResolutionConfig[]>>;
let helperDescriptionData: ApiResponse<HelperDescription[]> = null;
let helperDescriptionDataReadyPromise: Promise<ApiResponse<HelperDescription[]>>;
/**
*
*/
function getMenuAsync(): void {
if (!menuDataReadyPromise) {
menuDataReadyPromise = new Promise((resolve, reject) => {
@ -239,12 +269,15 @@ function getMenuAsync(): void {
}
}
function getConfigAsync(): void {
if (!configDataReadyPromise) {
configDataReadyPromise = new Promise((resolve, reject) => {
EIACDesktopApi.Menu.GetConfigAsync()
/**
*
*/
function getTagResolutionsAsync(): void {
if (!tagResolutionDataReadyPromise) {
tagResolutionDataReadyPromise = new Promise((resolve, reject) => {
EIACDesktopApi.Menu.GetTagResolutionsAsync()
.then(data => {
configData = data;
tagResolutionData = data;
resolve(data);
})
.catch(err => {
@ -254,7 +287,29 @@ function getConfigAsync(): void {
}
}
/**
*
*/
function getHelperDescriptionsAsync(): void {
if (!helperDescriptionDataReadyPromise) {
helperDescriptionDataReadyPromise = new Promise((resolve, reject) => {
EIACDesktopApi.Menu.GetHelperDescripsAsync()
.then(data => {
helperDescriptionData = data;
resolve(data);
})
.catch(err => {
reject(err);
});
});
}
}
/**
*
*/
export function preloadData(): void {
getMenuAsync();
getConfigAsync();
getTagResolutionsAsync();
getHelperDescriptionsAsync();
}

View File

@ -129,7 +129,9 @@ async function addTabAsync(tabGroup: TabGroup, menuItem: MenuItem): Promise<Tab
} else {
console.warn(`❌ URL ${url} 不可访问:`, result.message ?? `status ${result.status}`);
lastInvalidUrlResult = { url, message: result.message, status: result.status };
showErrorModal(`无法访问 ${url}\r\n异常原因${result.message ?? `status ${result.status}`}\r\n请联系10000技术支持。`);
const helpDescrip: string = await window.electronAPI.getHelperDescripAsync(result.status.toString()) ?? `无法访问 {URL}\r\n异常原因${result.message ?? `status ${result.status}`}\r\n${helpDescrip ?? ''}`;
showErrorModal(helpDescrip.replace('{URL}', url));
return null;
}
@ -362,8 +364,7 @@ async function initialize(): Promise<void> {
await addTabAsync(tabGroup, firstMenuItem);
// Bind logo click event
const lastMenuItem: MenuItem = menuList[menuList.length - 1];
const logoMenuItem: MenuItem = lastMenuItem.Children[lastMenuItem.Children.length - 1];
const logoMenuItem: MenuItem = menuList[menuList.length - 1];
bindLogoClickEvent(tabGroup, logoMenuItem);
// Bind logout event

View File

@ -24,10 +24,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
getMenuCacheAsync: () => ipcRenderer.invoke('get-menu-cache') as Promise<ApiResponse<MenuItem[]>>,
/**
*
* @returns
*
* @param code
* @returns
*/
getConfigCacheAsync: () => ipcRenderer.invoke('get-config-cache') as Promise<ApiResponse<TagResolutionConfig[]>>,
getHelperDescripAsync: (code: string) => ipcRenderer.invoke('get-helper-descrip', code) as Promise<string | null>,
/**
* URL的缩放比例

View File

@ -19,10 +19,11 @@ export interface ElectronAPI {
*/
getMenuCacheAsync: () => Promise<ApiResponse<MenuItem[]>>;
/**
*
* @returns
*
* @param code
* @returns
*/
getConfigCacheAsync: () => Promise<ApiResponse<TagResolutionConfig[]>>;
getHelperDescripAsync: (code: string) => Promise<string | null>;
/**
* URL的缩放比例
* @param url URL