Initial clean project import

This commit is contained in:
cat-shark
2026-06-19 18:41:41 +08:00
commit a13b804c7a
1306 changed files with 220568 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
import {BrowserWindow} from "electron";
import {preloadDefault} from "../lib/env-main";
import {t} from "../config/lang";
import {Page} from "./index";
import {WindowConfig} from "../config/window";
export const PageAbout = {
NAME: "about",
open: async (option: any) => {
const win = new BrowserWindow({
title: t("关于"),
parent: null,
minWidth: WindowConfig.aboutWidth,
minHeight: WindowConfig.aboutHeight,
width: WindowConfig.aboutWidth,
height: WindowConfig.aboutHeight,
webPreferences: {
preload: preloadDefault,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
contextIsolation: false,
},
show: true,
frame: false,
transparent: false,
});
return Page.openWindow(PageAbout.NAME, win, "page/about.html");
},
};
+111
View File
@@ -0,0 +1,111 @@
import {BrowserWindow, ipcMain} from "electron";
import {preloadDefault, rendererLoadPath} from "../lib/env-main";
import {Page} from "./index";
import {AppConfig} from "../../src/config";
import {icnsLogoPath, icoLogoPath, logoPath} from "../config/icon";
import {isPackaged} from "../lib/env";
import {WindowConfig} from "../config/window";
import * as remoteMain from "@electron/remote/main";
import {DevToolsManager} from "../lib/devtools";
export const PageAgentLogin = {
NAME: "agentLogin",
event: {
onGetQRCode: null,
onCheckStatus: null,
onClose: null,
},
open: async (option: {
region: string;
onGetQRCode: (region: string) => Promise<{
loginUrl: string;
expireSeconds: number;
}>;
onCheckStatus: (region: string) => Promise<{
status: "WaitScan" | "Scanned" | "LoggedIn" | "Expired" | "Error";
userInfo?: any;
}>;
onClose: () => void;
parent?: BrowserWindow;
}): Promise<{
close: () => void;
}> => {
PageAgentLogin.event.onGetQRCode = option.onGetQRCode;
PageAgentLogin.event.onCheckStatus = option.onCheckStatus;
PageAgentLogin.event.onClose = option.onClose;
let icon = logoPath;
if (process.platform === "win32") {
icon = icoLogoPath;
} else if (process.platform === "darwin") {
icon = icnsLogoPath;
}
let parent = option.parent || null;
let alwaysOnTop = !parent;
const win = new BrowserWindow({
show: true,
title: `${AppConfig.title} - 智能体登录`,
...(!isPackaged ? {icon} : {}),
frame: false,
transparent: false,
hasShadow: true,
center: true,
useContentSize: true,
minWidth: 500,
minHeight: 650,
width: 500,
height: 650,
skipTaskbar: true,
resizable: false,
maximizable: false,
backgroundColor: "#f1f5f9",
focusable: true,
parent,
alwaysOnTop,
webPreferences: {
preload: preloadDefault,
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
contextIsolation: false,
},
});
win.on("closed", () => {
Page.unregisterWindow(PageAgentLogin.NAME);
PageAgentLogin.event.onClose();
});
let currentRegion = option.region;
// 传递region参数到渲染进程
win.webContents.once("did-finish-load", () => {
win.webContents.send("AgentLogin.Init", { region: currentRegion });
Page.ready("agentLogin");
DevToolsManager.autoShow(win);
win.focus();
});
rendererLoadPath(win, "page/agentLogin.html");
remoteMain.enable(win.webContents);
DevToolsManager.register("AgentLogin", win);
Page.registerWindow(PageAgentLogin.NAME, win);
return {
close: () => {
win.close();
},
};
},
};
ipcMain.handle("AgentLogin.Event", async (event, type: "getQRCode" | "checkStatus", param: any) => {
switch (type) {
case "getQRCode":
return await PageAgentLogin.event.onGetQRCode(param.region);
case "checkStatus":
return await PageAgentLogin.event.onCheckStatus(param.region);
}
});
+34
View File
@@ -0,0 +1,34 @@
import {BrowserWindow} from "electron";
import {preloadDefault} from "../lib/env-main";
import {AppRuntime} from "../mapi/env";
import {t} from "../config/lang";
import {Page} from "./index";
import {WindowConfig} from "../config/window";
export const PageFeedback = {
NAME: "feedback",
open: async (option: any) => {
const win = new BrowserWindow({
title: t("工单反馈"),
parent: null,
minWidth: WindowConfig.feedbackWidth,
minHeight: WindowConfig.feedbackHeight,
width: WindowConfig.feedbackWidth,
height: WindowConfig.feedbackHeight,
webPreferences: {
preload: preloadDefault,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
contextIsolation: false,
},
show: true,
frame: false,
transparent: false,
});
return Page.openWindow(PageFeedback.NAME, win, "page/feedback.html");
},
};
+69
View File
@@ -0,0 +1,69 @@
import {BrowserWindow} from "electron";
import {preloadDefault, rendererLoadPath} from "../lib/env-main";
import {Page} from "./index";
import {AppConfig} from "../../src/config";
import {icnsLogoPath, icoLogoPath, logoPath} from "../config/icon";
import {isPackaged} from "../lib/env";
import {WindowConfig} from "../config/window";
import * as remoteMain from "@electron/remote/main";
import {DevToolsManager} from "../lib/devtools";
export const PageGuide = {
NAME: "guide",
open: async (option: any) => {
let icon = logoPath;
if (process.platform === "win32") {
icon = icoLogoPath;
} else if (process.platform === "darwin") {
icon = icnsLogoPath;
}
const win = new BrowserWindow({
show: true,
title: AppConfig.title,
...(!isPackaged ? {icon} : {}),
frame: false,
transparent: false,
hasShadow: true,
center: true,
useContentSize: true,
minWidth: WindowConfig.guideWidth,
minHeight: WindowConfig.guideHeight,
width: WindowConfig.guideWidth,
height: WindowConfig.guideHeight,
skipTaskbar: true,
resizable: false,
maximizable: false,
backgroundColor: "#f1f5f9",
alwaysOnTop: false,
webPreferences: {
preload: preloadDefault,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
contextIsolation: false,
},
});
win.on("closed", () => {
Page.unregisterWindow(PageGuide.NAME);
});
rendererLoadPath(win, "page/guide.html");
remoteMain.enable(win.webContents);
win.webContents.on("did-finish-load", () => {
Page.ready("guide");
DevToolsManager.autoShow(win);
});
DevToolsManager.register("Guide", win);
// win.webContents.setWindowOpenHandler(({url}) => {
// if (url.startsWith('https:')) shell.openExternal(url)
// return {action: 'deny'}
// })
Page.registerWindow(PageGuide.NAME, win);
},
};
+94
View File
@@ -0,0 +1,94 @@
import {Events} from "../mapi/event/main";
import {AppEnv, AppRuntime} from "../mapi/env";
import {PageUser} from "./user";
import {BrowserWindow, shell} from "electron";
import {rendererLoadPath} from "../lib/env-main";
import {PageGuide} from "./guide";
import {PageSetup} from "./setup";
import {DevToolsManager} from "../lib/devtools";
import {PageFeedback} from "./feedback";
import {PagePayment} from "./payment";
import {PageMonitor} from "./monitor";
import {PageLog} from "./log";
import {PageAgentLogin} from "./agentLogin";
const Pages = {
user: PageUser,
guide: PageGuide,
setup: PageSetup,
payment: PagePayment,
feedback: PageFeedback,
monitor: PageMonitor,
log: PageLog,
agentLogin: PageAgentLogin,
};
export const Page = {
ready(name: string) {
Events.send(name, "APP_READY", {
name,
AppEnv,
});
},
openWindow: (name: string, win: BrowserWindow, fileName: string) => {
win.webContents.on("will-navigate", event => {
event.preventDefault();
});
win.webContents.setWindowOpenHandler(() => {
return {action: "deny"};
});
win.webContents.setWindowOpenHandler(({url}) => {
if (url.startsWith("https:") || url.startsWith("http:")) {
shell.openExternal(url).then();
}
return {action: "deny"};
});
win.on("close", () => {
delete AppRuntime.windows[name];
});
const promise = new Promise((resolve, reject) => {
win.webContents.on("did-finish-load", () => {
win.focus();
Page.ready(name);
DevToolsManager.autoShow(win);
resolve(undefined);
});
});
rendererLoadPath(win, fileName);
DevToolsManager.register(`Page.${name}`, win);
AppRuntime.windows[name] = win;
return promise;
},
open: async (
name: string,
option?: {
singleton?: boolean;
parent?: BrowserWindow;
[key: string]: any;
}
) => {
option = Object.assign(
{
singleton: true,
parent: null,
},
option
);
if (!option.parent) {
option.parent = AppRuntime.mainWindow;
}
if (option.singleton && AppRuntime.windows[name]) {
AppRuntime.windows[name].show();
AppRuntime.windows[name].focus();
AppRuntime.windows[name].setParentWindow(option.parent);
return;
}
return Pages[name].open(option);
},
registerWindow(name: string, win: BrowserWindow) {
AppRuntime.windows[name] = win;
},
unregisterWindow(name: string) {
delete AppRuntime.windows[name];
},
};
+51
View File
@@ -0,0 +1,51 @@
import {BrowserWindow} from "electron";
import {preloadDefault} from "../lib/env-main";
import {t} from "../config/lang";
import {Page} from "./index";
import {WindowConfig} from "../config/window";
import {AppRuntime} from "../mapi/env";
export const PageLog = {
NAME: "log",
open: async (option: {
log: string,
}) => {
if (AppRuntime.windows[PageLog.NAME]) {
AppRuntime.windows[PageLog.NAME].close();
}
const win = new BrowserWindow({
title: t("日志"),
parent: null,
minWidth: WindowConfig.logWidth,
minHeight: WindowConfig.logHeight,
width: WindowConfig.logWidth,
height: WindowConfig.logHeight,
webPreferences: {
preload: preloadDefault,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
contextIsolation: false,
},
show: true,
frame: false,
transparent: false,
});
await Page.openWindow(PageLog.NAME, win, "page/log.html");
const logInit = {
log: option.log,
}
win.webContents.executeJavaScript(`
const logInit = ()=>{
if(!window.__logInit){
setTimeout(logInit, 100);
return;
}
window.__logInit(${JSON.stringify(logInit)});
};logInit();
`);
},
};
+69
View File
@@ -0,0 +1,69 @@
import {BrowserWindow} from "electron";
import {preloadDefault} from "../lib/env-main";
import {Page} from "./index";
import {Events} from "../mapi/event/main";
import {t} from "../config/lang";
export const PageMonitor = {
NAME: "monitor",
open: async (option: {title?: string; width?: number; height?: number; [key: string]: any}) => {
option = Object.assign(
{
title: t("加载中"),
width: 700,
height: 500,
url: "",
script: null,
openDevTools: false,
broadcastPages: [],
},
option
);
const win = new BrowserWindow({
title: option.title,
width: option.width,
height: option.height,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webSecurity: false,
preload: preloadDefault,
webviewTag: true,
},
show: true,
frame: false,
center: true,
transparent: false,
focusable: true,
parent: null,
alwaysOnTop: false,
});
const sendMonitorData = async (type: string, data: any) => {
return Events.callPage(PageMonitor.NAME, "MonitorData", {type, data});
};
win.webContents.on("did-finish-load", () => {
sendMonitorData("SetTitle", {title: option.title});
sendMonitorData("LoadUrl", {
url: option.url,
script: option.script,
openDevTools: option.openDevTools,
});
});
win.webContents.on("ipc-message", (event, channel, ...args) => {
if (channel === "MonitorEvent") {
const {type, data} = args[0];
// console.log('MonitorEvent', type, data)
if (option.broadcastPages.length > 0) {
Events.broadcast(
"MonitorEvent",
{type, data},
{
pages: option.broadcastPages,
}
);
}
}
});
await Page.openWindow(PageMonitor.NAME, win, "page/monitor.html");
},
};
+113
View File
@@ -0,0 +1,113 @@
import {BrowserWindow, ipcMain} from "electron";
import {preloadDefault, rendererLoadPath} from "../lib/env-main";
import {Page} from "./index";
import {AppConfig} from "../../src/config";
import {icnsLogoPath, icoLogoPath, logoPath} from "../config/icon";
import {isPackaged} from "../lib/env";
import {WindowConfig} from "../config/window";
import * as remoteMain from "@electron/remote/main";
import {DevToolsManager} from "../lib/devtools";
export const PagePayment = {
NAME: "payment",
event: {
onRefresh: null,
onWatch: null,
onClose: null,
},
open: async (option: {
onRefresh: () => Promise<{
payUrl: string;
watchUrl: string;
payExpireSeconds: number;
body: string;
}>;
onWatch: () => Promise<{
status: "WaitPay" | "Scanned" | "Payed" | "Expired" | "Error";
}>;
onClose: () => void;
parent?: BrowserWindow;
}): Promise<{
close: () => void;
}> => {
PagePayment.event.onRefresh = option.onRefresh;
PagePayment.event.onWatch = option.onWatch;
PagePayment.event.onClose = option.onClose;
let icon = logoPath;
if (process.platform === "win32") {
icon = icoLogoPath;
} else if (process.platform === "darwin") {
icon = icnsLogoPath;
}
let parent = option.parent || null;
let alwaysOnTop = !parent;
const win = new BrowserWindow({
show: true,
title: AppConfig.title,
...(!isPackaged ? {icon} : {}),
frame: false,
transparent: false,
hasShadow: true,
center: true,
useContentSize: true,
minWidth: WindowConfig.paymentWidth,
minHeight: WindowConfig.paymentHeight,
width: WindowConfig.paymentWidth,
height: WindowConfig.paymentHeight,
skipTaskbar: true,
resizable: false,
maximizable: false,
backgroundColor: "#f1f5f9",
focusable: true,
parent,
alwaysOnTop,
webPreferences: {
preload: preloadDefault,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
contextIsolation: false,
// sandbox: false,
},
});
win.on("closed", () => {
Page.unregisterWindow(PagePayment.NAME);
PagePayment.event.onClose();
});
rendererLoadPath(win, "page/payment.html");
remoteMain.enable(win.webContents);
win.webContents.on("did-finish-load", () => {
Page.ready("payment");
DevToolsManager.autoShow(win);
win.focus();
});
DevToolsManager.register("Payment", win);
// win.webContents.setWindowOpenHandler(({url}) => {
// if (url.startsWith('https:')) shell.openExternal(url)
// return {action: 'deny'}
// })
Page.registerWindow(PagePayment.NAME, win);
return {
close: () => {
win.close();
},
};
},
};
ipcMain.handle("Payment.Event", async (event, type: "refresh" | "watch", param: any) => {
switch (type) {
case "refresh":
return await PagePayment.event.onRefresh();
case "watch":
return await PagePayment.event.onWatch();
}
});
+70
View File
@@ -0,0 +1,70 @@
import {BrowserWindow} from "electron";
import {preloadDefault, rendererLoadPath} from "../lib/env-main";
import {Page} from "./index";
import {AppConfig} from "../../src/config";
import {icnsLogoPath, icoLogoPath, logoPath} from "../config/icon";
import {isPackaged} from "../lib/env";
import {WindowConfig} from "../config/window";
import * as remoteMain from "@electron/remote/main";
import {DevToolsManager} from "../lib/devtools";
export const PageSetup = {
NAME: "setup",
open: async (option: any) => {
let icon = logoPath;
if (process.platform === "win32") {
icon = icoLogoPath;
} else if (process.platform === "darwin") {
icon = icnsLogoPath;
}
const win = new BrowserWindow({
show: true,
title: AppConfig.title,
...(!isPackaged ? {icon} : {}),
frame: false,
transparent: false,
hasShadow: true,
center: true,
useContentSize: true,
minWidth: WindowConfig.guideWidth,
minHeight: WindowConfig.guideHeight,
width: WindowConfig.guideWidth,
height: WindowConfig.guideHeight,
skipTaskbar: true,
resizable: false,
maximizable: false,
backgroundColor: "#f1f5f9",
alwaysOnTop: false,
webPreferences: {
preload: preloadDefault,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
nodeIntegration: true,
webSecurity: false,
webviewTag: true,
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
contextIsolation: false,
// sandbox: false,
},
});
win.on("closed", () => {
Page.unregisterWindow(PageSetup.NAME);
});
rendererLoadPath(win, "page/setup.html");
remoteMain.enable(win.webContents);
win.webContents.on("did-finish-load", () => {
Page.ready("setup");
DevToolsManager.autoShow(win);
});
DevToolsManager.register("Setup", win);
// win.webContents.setWindowOpenHandler(({url}) => {
// if (url.startsWith('https:')) shell.openExternal(url)
// return {action: 'deny'}
// })
Page.registerWindow(PageSetup.NAME, win);
},
};
+37
View File
@@ -0,0 +1,37 @@
import {BrowserWindow} from "electron";
import {preloadDefault} from "../lib/env-main";
import {AppRuntime} from "../mapi/env";
import {t} from "../config/lang";
import {Page} from "./index";
export const PageUser = {
NAME: "user",
open: async (option: { parent?: BrowserWindow }) => {
option = Object.assign({
parent: null
}, option)
let alwaysOnTop = !option.parent;
const win = new BrowserWindow({
title: t("用户中心"),
minWidth: 700,
minHeight: 500,
width: 700,
height: 500,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webSecurity: false,
preload: preloadDefault,
webviewTag: true,
},
show: true,
frame: false,
center: true,
transparent: false,
focusable: true,
parent: option.parent,
alwaysOnTop,
});
return Page.openWindow(PageUser.NAME, win, "page/user.html");
},
};