Compare commits
10 Commits
7ad962d2d0
...
shenranqi
| Author | SHA1 | Date | |
|---|---|---|---|
| ee950e00a1 | |||
| abe131fedc | |||
| d50c049dfc | |||
|
|
efd387e24c | ||
|
|
e256d69d89 | ||
| 26750c3c2a | |||
| 57c40d0b3a | |||
| cc2494d3a1 | |||
|
|
dce1e04398 | ||
| 56171be0bf |
@@ -1,2 +1,2 @@
|
||||
VITE_h5_client_url=http://192.168.11.200:19080
|
||||
VITE_h5_client_url=http://192.168.11.200:18900
|
||||
VITE_HsAppCode=1
|
||||
|
||||
2
.env.pinshan
Normal file
@@ -0,0 +1,2 @@
|
||||
VITE_h5_client_url=http://172.22.33.66:18900
|
||||
VITE_HsAppCode=1
|
||||
@@ -1,2 +1,4 @@
|
||||
VITE_h5_client_url=http://10.9.18.138:18900
|
||||
VITE_h5_client_url=https://aiagent.szgas.com.cn
|
||||
### VITE_h5_client_url=https://bqw-120.ii999.live:20038
|
||||
#VITE_h5_client_url=http://127.0.0.1:18901
|
||||
VITE_HsAppCode=1
|
||||
|
||||
3
.gitignore
vendored
@@ -6,3 +6,6 @@ out
|
||||
*.log*
|
||||
package-lock.json
|
||||
.cursor
|
||||
./.idea
|
||||
./.idea/**
|
||||
.idea/
|
||||
|
||||
@@ -32,3 +32,11 @@ $ npm run build:mac
|
||||
# For Linux
|
||||
$ npm run build:linux
|
||||
```
|
||||
|
||||
npm install -g electron-icon-builder
|
||||
|
||||
electron-icon-builder --input=./build/icon.png --output=./build/icons
|
||||
|
||||
```shell
|
||||
npm install -g electron-icon-builder
|
||||
```
|
||||
|
||||
BIN
build/icon - 副本.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
build/icon.ico
|
Before Width: | Height: | Size: 281 KiB After Width: | Height: | Size: 353 KiB |
BIN
build/icon.png
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 1.4 MiB |
BIN
build/icon_pinshan.ico
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
build/icon_pinshan.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 352 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 628 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
BIN
build/icons/icons/mac/icon.icns
Normal file
BIN
build/icons/icons/png/1024x1024.png
Normal file
|
After Width: | Height: | Size: 239 KiB |
BIN
build/icons/icons/png/128x128.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
build/icons/icons/png/16x16.png
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
build/icons/icons/png/24x24.png
Normal file
|
After Width: | Height: | Size: 817 B |
BIN
build/icons/icons/png/256x256.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
build/icons/icons/png/32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
build/icons/icons/png/48x48.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
build/icons/icons/png/512x512.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
build/icons/icons/png/64x64.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
build/icons/icons/win/icon.ico
Normal file
|
After Width: | Height: | Size: 353 KiB |
|
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 239 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 628 B After Width: | Height: | Size: 479 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 817 B |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 353 KiB |
44
electron-builder-pinshan.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
appId: com.huashiai.dify-market-manager-gui
|
||||
compression: maximum
|
||||
productName: 智能体平台
|
||||
directories:
|
||||
buildResources: build
|
||||
files:
|
||||
- '!**/.vscode/*'
|
||||
- '!src/*'
|
||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
win:
|
||||
executableName: 智能体平台
|
||||
nsis:
|
||||
artifactName: ${name}-${version}-setup.${ext}
|
||||
shortcutName: ${productName}
|
||||
uninstallDisplayName: ${productName}
|
||||
createDesktopShortcut: always
|
||||
mac:
|
||||
entitlementsInherit: build/entitlements.mac.plist
|
||||
extendInfo:
|
||||
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||
notarize: false
|
||||
dmg:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
- deb
|
||||
maintainer: huashiai.org
|
||||
category: Utility
|
||||
appImage:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
npmRebuild: false
|
||||
publish:
|
||||
provider: generic
|
||||
url: ""
|
||||
electronDownload:
|
||||
mirror: http://172.22.33.66:18900/update_files
|
||||
@@ -1,6 +1,6 @@
|
||||
appId: com.huashiai.dify-market-manager-gui
|
||||
appId: com.szgas.dify-market-manager-gui
|
||||
compression: maximum
|
||||
productName: 龙岗区百千万AI智能体共创平台
|
||||
productName: 深燃智能体平台
|
||||
directories:
|
||||
buildResources: build
|
||||
files:
|
||||
@@ -12,7 +12,7 @@ files:
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
win:
|
||||
executableName: 龙岗区百千万AI智能体共创平台
|
||||
executableName: 深圳燃气智能体平台
|
||||
nsis:
|
||||
artifactName: ${name}-${version}-setup.${ext}
|
||||
shortcutName: ${productName}
|
||||
@@ -32,7 +32,7 @@ linux:
|
||||
target:
|
||||
- AppImage
|
||||
- deb
|
||||
maintainer: huashiai.org
|
||||
maintainer: szgas.org
|
||||
category: Utility
|
||||
appImage:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
|
||||
23
electron.vite.config.1761015624809.mjs
Normal file
@@ -0,0 +1,23 @@
|
||||
// electron.vite.config.mjs
|
||||
import { resolve } from "path";
|
||||
import { defineConfig, externalizeDepsPlugin } from "electron-vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
var electron_vite_config_default = defineConfig({
|
||||
main: {
|
||||
plugins: [externalizeDepsPlugin()]
|
||||
},
|
||||
preload: {
|
||||
plugins: [externalizeDepsPlugin()]
|
||||
},
|
||||
renderer: {
|
||||
resolve: {
|
||||
alias: {
|
||||
"@renderer": resolve("src/renderer/src")
|
||||
}
|
||||
},
|
||||
plugins: [vue()]
|
||||
}
|
||||
});
|
||||
export {
|
||||
electron_vite_config_default as default
|
||||
};
|
||||
27
package.json
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "dify-market-manager-gui",
|
||||
"name": "SZGAS_AIAgent",
|
||||
"version": "1.0.0",
|
||||
"description": "百千万AI智能体共创平台",
|
||||
"description": "深圳燃气 AI智能体",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "huashiai.com",
|
||||
"homepage": "https://huashiai.com",
|
||||
"author": "szgas.com",
|
||||
"homepage": "https://szgas.com",
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint --cache .",
|
||||
@@ -28,6 +28,7 @@
|
||||
"build:win_lgzs": "electron-vite build --mode lgzs && electron-builder --win ",
|
||||
"build:win_jiangsu": "electron-vite build --mode jiangsu && electron-builder --win ",
|
||||
"build:win_nanshan": "electron-vite build --mode nanshan && electron-builder --win",
|
||||
"build:win_pinshan": "electron-vite build --mode pinshan && electron-builder --win",
|
||||
"build:win_huashiai": "electron-vite build --mode huashiai && electron-builder --win",
|
||||
"build:win_internet": "npm run build --mode internet && electron-builder --win",
|
||||
"build:mac": "npm run build && electron-builder --mac",
|
||||
@@ -36,6 +37,24 @@
|
||||
"build:icon": "./node_modules/.bin/electron-icon-builder --input=./build/icon.png --output=./build/",
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
"build": {
|
||||
"protocols": [{
|
||||
"name": "aiAgent Protocol",
|
||||
"schemes": ["aiAgent"]
|
||||
}],
|
||||
"win": {
|
||||
"target": "nsis",
|
||||
"signingHashAlgorithms": ["sha256"]
|
||||
},
|
||||
"mac": {
|
||||
"extendInfo": {
|
||||
"CFBundleURLTypes": [{
|
||||
"CFBundleURLName": "MyApp Protocol",
|
||||
"CFBundleURLSchemes": ["myapp"]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"permissions": [
|
||||
"audioCapture",
|
||||
"videoCapture"
|
||||
|
||||
|
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 628 B After Width: | Height: | Size: 611 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 4.6 KiB |
BIN
resources/pinshan/1024x1024.png
Normal file
|
After Width: | Height: | Size: 239 KiB |
BIN
resources/pinshan/128x128.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
resources/pinshan/16x16.png
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
resources/pinshan/24x24.png
Normal file
|
After Width: | Height: | Size: 817 B |
BIN
resources/pinshan/256x256.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
resources/pinshan/32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
resources/pinshan/48x48.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/pinshan/512x512.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
resources/pinshan/64x64.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/shenranqi/1024x1024.png
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
resources/shenranqi/128x128.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
resources/shenranqi/16x16.png
Normal file
|
After Width: | Height: | Size: 611 B |
BIN
resources/shenranqi/24x24.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/shenranqi/256x256.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
resources/shenranqi/32x32.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/shenranqi/48x48.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/shenranqi/512x512.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
resources/shenranqi/64x64.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
resources/shenranqi/icon.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
resources/shenranqi/img.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
@@ -1,7 +1,7 @@
|
||||
import { app, shell, BrowserWindow, ipcMain, Menu, session, screen, dialog } from 'electron'
|
||||
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||
import Store from 'electron-store'
|
||||
import { createWindow, createDrageWindow, unregisterAllShortcuts, getMainWindow } from './window.js'
|
||||
import { createWindow, createDrageWindow, unregisterAllShortcuts, getMainWindow,createOAuthWindow } from './window.js'
|
||||
import { setupIPC } from './ipc.js'
|
||||
import { createTray, destroyTray,clearBrowserCache } from './tray.js'
|
||||
import XEUtils from 'xe-utils'
|
||||
@@ -15,10 +15,17 @@ import { setStoreValue, getStoreValue ,deleteStore} from './store.js'
|
||||
import AutoLaunch from 'auto-launch'
|
||||
import axios from 'axios'
|
||||
|
||||
const PROTOCOL_NAME = 'aiAgent'
|
||||
|
||||
import WebSocketClient from './utils/WebSocketClient';
|
||||
|
||||
let wsClient=null
|
||||
|
||||
const isDebugger=getStoreValue("isDebugger");
|
||||
if (isDebugger==null||isDebugger==''){
|
||||
setStoreValue("isDebugger",0)
|
||||
}
|
||||
|
||||
// 延迟创建WebSocket连接,等待应用完全启动后再连接
|
||||
function createWebSocketClient() {
|
||||
try {
|
||||
@@ -150,7 +157,7 @@ function cleanupCacheDirectories() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
deleteRecursive(cachePath)
|
||||
logger.info(`缓存目录清理完成: ${cachePath}`)
|
||||
} catch (error) {
|
||||
@@ -163,6 +170,81 @@ function cleanupCacheDirectories() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册自定义协议为系统默认处理程序
|
||||
*/
|
||||
function registerDeepLinkProtocol() {
|
||||
try {
|
||||
if (process.platform === 'win32') {
|
||||
if (process.defaultApp) {
|
||||
app.setAsDefaultProtocolClient(PROTOCOL_NAME, process.execPath, [path.resolve(process.argv[1])])
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient(PROTOCOL_NAME)
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient(PROTOCOL_NAME)
|
||||
}
|
||||
logger.info(`已注册自定义协议: ${PROTOCOL_NAME}`)
|
||||
} catch (error) {
|
||||
logger.error('注册自定义协议失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从命令行参数提取深链地址与 code 参数
|
||||
* 返回对象 { url, code };未找到返回 null
|
||||
*/
|
||||
function extractDeepLinkFromArgs(args = []) {
|
||||
try {
|
||||
const protoPrefix = `${PROTOCOL_NAME.toLowerCase()}://`
|
||||
const found = (args || []).find(
|
||||
(arg) => typeof arg === 'string' && arg.toLowerCase().startsWith(protoPrefix)
|
||||
)
|
||||
if (!found) return null
|
||||
|
||||
let code = null
|
||||
try {
|
||||
const u = new URL(found)
|
||||
const params = new URLSearchParams(u.search || '')
|
||||
code = params.get('code')
|
||||
} catch (e) {
|
||||
const m = found.match(/[?&]code=([^&]+)/i)
|
||||
code = m ? decodeURIComponent(m[1]) : null
|
||||
}
|
||||
|
||||
return { url: found, code }
|
||||
} catch (error) {
|
||||
logger.error('提取深链地址失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理深链地址
|
||||
*/
|
||||
function handleDeepLink(payload) {
|
||||
try {
|
||||
const url = typeof payload === 'string' ? payload : payload?.url
|
||||
const code = typeof payload === 'object' ? payload?.code : null
|
||||
logger.info('Deep link URL:', url)
|
||||
if (code) {
|
||||
logger.info('Deep link code:', code)
|
||||
}
|
||||
const mainWindow = BrowserWindow.getAllWindows()[0] || getMainWindow()
|
||||
if (mainWindow) {
|
||||
const h5_client_url=getStoreValue("h5_client_url")+"/pc_client/autologin?code="+code
|
||||
|
||||
logger.info("==================================== mainWindow.loadURL:"+h5_client_url)
|
||||
// 加载存储的 URL
|
||||
mainWindow.loadURL(h5_client_url)
|
||||
mainWindow.show()
|
||||
mainWindow.focus()
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('处理深链地址失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单应用启动实现
|
||||
* 请求单一实例锁,
|
||||
@@ -181,6 +263,10 @@ if (!gotTheLock) {
|
||||
// 监听第二个实例被运行时
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
logger.info('检测到第二个实例启动,激活现有实例')
|
||||
const deeplink = extractDeepLinkFromArgs(commandLine)
|
||||
if (deeplink) {
|
||||
handleDeepLink(deeplink)
|
||||
}
|
||||
// 当有第二个实例被运行时,激活之前的实例并将焦点置于其窗口
|
||||
const windows = BrowserWindow.getAllWindows()
|
||||
if (windows.length > 0) {
|
||||
@@ -196,6 +282,8 @@ if (!gotTheLock) {
|
||||
app.whenReady().then(() => {
|
||||
logger.info('应用已准备就绪,开始初始化...');
|
||||
|
||||
registerDeepLinkProtocol()
|
||||
|
||||
// 清理缓存目录
|
||||
cleanupCacheDirectories()
|
||||
|
||||
@@ -213,6 +301,8 @@ if (!gotTheLock) {
|
||||
optimizer.watchWindowShortcuts(window)
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 根据存储的状态决定是否创建悬浮窗口
|
||||
if (getStoreValue('showDrageWindow')) {
|
||||
createDrageWindow()
|
||||
@@ -247,8 +337,20 @@ if (!gotTheLock) {
|
||||
})
|
||||
|
||||
logger.info('应用初始化完成');
|
||||
|
||||
const initialDeeplink = extractDeepLinkFromArgs(process.argv)
|
||||
if (initialDeeplink) {
|
||||
handleDeepLink(initialDeeplink)
|
||||
}
|
||||
})
|
||||
|
||||
app.on('open-url', (event, url) => {
|
||||
logger.info('Opened with URL:', url)
|
||||
event.preventDefault()
|
||||
// 处理url,例如解析参数并打开相应窗口
|
||||
logger.info('Opened with URL:', url)
|
||||
})
|
||||
|
||||
// 修改窗口关闭行为
|
||||
app.on('window-all-closed', async (event) => {
|
||||
if (process.platform !== 'darwin') {
|
||||
@@ -258,7 +360,7 @@ if (!gotTheLock) {
|
||||
logger.info('检测到重启过程,跳过窗口关闭处理')
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!app.isQuiting) {
|
||||
logger.info('用户关闭窗口,隐藏应用')
|
||||
// 如果不是主动退出,则隐藏所有窗口
|
||||
@@ -272,7 +374,7 @@ if (!gotTheLock) {
|
||||
} catch (error) {
|
||||
logger.error('窗口关闭时清理缓存失败:', error);
|
||||
}
|
||||
|
||||
|
||||
// 销毁托盘并退出应用
|
||||
destroyTray()
|
||||
app.quit();
|
||||
@@ -293,7 +395,7 @@ if (!gotTheLock) {
|
||||
logger.info('检测到重启过程,跳过before-quit处理')
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
logger.info('应用即将退出,开始清理资源')
|
||||
// 在应用程序即将退出时执行操作,例如保存数据
|
||||
event.preventDefault();
|
||||
@@ -304,7 +406,7 @@ if (!gotTheLock) {
|
||||
} catch (error) {
|
||||
logger.error('应用退出时清理缓存失败:', error);
|
||||
}
|
||||
|
||||
|
||||
// 销毁托盘并退出应用
|
||||
destroyTray()
|
||||
// 使用 exit 确保完全退出
|
||||
@@ -331,7 +433,7 @@ if (!gotTheLock) {
|
||||
|
||||
unregisterAllShortcuts()
|
||||
destroyTray()
|
||||
|
||||
|
||||
// 清理完成后退出应用,使用 exit 确保完全退出
|
||||
app.exit(0);
|
||||
})
|
||||
@@ -394,7 +496,7 @@ export function checkIsKeepAlive(){
|
||||
setStoreValue("lastAliveTime",dayjs())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, 1000 * 2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export function setupIPC() {
|
||||
setStoreValue("token", data.token);
|
||||
setStoreValue("dify_access_token:", data.dify_access_token);
|
||||
setStoreValue("dify_refresh_token", data.dify_refresh_token);
|
||||
setStoreValue("dify_csrf_token", data.dify_csrf_token);
|
||||
setStoreValue("userInfo", data.userInfo);
|
||||
|
||||
setStoreValue("apiUrl", data.apiUrl);
|
||||
@@ -207,7 +208,7 @@ export function setupIPC() {
|
||||
newWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
|
||||
console.error('页面加载失败:', errorDescription);
|
||||
failLoadCount++;
|
||||
|
||||
|
||||
if (failLoadCount <= maxRetries) {
|
||||
console.log(`页面加载失败,${retryDelay}ms后进行第${failLoadCount}次重试...`);
|
||||
setTimeout(() => {
|
||||
@@ -252,7 +253,7 @@ export function setupIPC() {
|
||||
newWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
|
||||
console.error('页面加载失败:', errorDescription);
|
||||
failLoadCount2++;
|
||||
|
||||
|
||||
if (failLoadCount2 <= maxRetries2) {
|
||||
console.log(`页面加载失败,${retryDelay2}ms后进行第${failLoadCount2}次重试...`);
|
||||
setTimeout(() => {
|
||||
@@ -307,7 +308,7 @@ export function setupIPC() {
|
||||
const urlParts = fileUrl.split('/');
|
||||
fileName = urlParts[urlParts.length - 1] || '';
|
||||
}
|
||||
|
||||
|
||||
// 解码文件名,解决中文乱码问题
|
||||
try {
|
||||
fileName = decodeURIComponent(fileName);
|
||||
@@ -315,7 +316,7 @@ export function setupIPC() {
|
||||
// 如果解码失败,保持原文件名
|
||||
logger.warn(`文件名解码失败: ${fileName}`);
|
||||
}
|
||||
|
||||
|
||||
// 如果提取的文件名为空,使用时间戳生成默认名称
|
||||
if (!fileName || fileName === '') {
|
||||
fileName = `downloaded_file_${Date.now()}`;
|
||||
@@ -323,12 +324,12 @@ export function setupIPC() {
|
||||
|
||||
// 获取用户下载目录
|
||||
const downloadDir = path.join(os.homedir(), 'Downloads');
|
||||
|
||||
|
||||
// 确保下载目录存在
|
||||
if (!fs.existsSync(downloadDir)) {
|
||||
fs.mkdirSync(downloadDir, { recursive: true });
|
||||
}
|
||||
|
||||
|
||||
const outputLocationPath = path.join(downloadDir, fileName);
|
||||
const writer = fs.createWriteStream(outputLocationPath);
|
||||
let receivedBytes = 0;
|
||||
@@ -385,11 +386,11 @@ export function setupIPC() {
|
||||
try {
|
||||
// 标记为正在重启,避免其他退出逻辑干扰
|
||||
app.isRestarting = true;
|
||||
|
||||
|
||||
// 确保所有窗口都被正确关闭
|
||||
const windows = BrowserWindow.getAllWindows();
|
||||
logger.info(`准备关闭 ${windows.length} 个窗口`);
|
||||
|
||||
|
||||
windows.forEach(window => {
|
||||
if (!window.isDestroyed()) {
|
||||
try {
|
||||
@@ -400,7 +401,7 @@ export function setupIPC() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 延迟执行重启,确保窗口关闭完成
|
||||
setTimeout(() => {
|
||||
try {
|
||||
@@ -417,7 +418,7 @@ export function setupIPC() {
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
logger.error(`重启软件失败: ${error.message}`);
|
||||
|
||||
@@ -90,7 +90,7 @@ export function createTray() {
|
||||
tray = new Tray(icon)
|
||||
|
||||
// 设置托盘图标的提示文本
|
||||
tray.setToolTip('Dify Market Manager')
|
||||
tray.setToolTip('深圳燃气 AI智能体')
|
||||
|
||||
// 创建右键菜单
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
@@ -124,7 +124,19 @@ export function createTray() {
|
||||
click: () => {
|
||||
createConfigWindow()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '打开日志目录',
|
||||
click: () => {
|
||||
try {
|
||||
const configDir = app.getPath('userData')
|
||||
logger.info('打开配置文件目录:', configDir)
|
||||
shell.openPath(configDir)
|
||||
} catch (error) {
|
||||
logger.error('打开配置文件目录失败:', error)
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{ type: 'separator' },
|
||||
@@ -144,8 +156,6 @@ export function createTray() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
|
||||
@@ -81,7 +81,7 @@ class WebSocketClient {
|
||||
|
||||
setTimeout(() => {
|
||||
this.lockReconnect = false;
|
||||
this.createConnect(); // 重新获取本地缓存并创建连接
|
||||
// this.createConnect(); // 重新获取本地缓存并创建连接
|
||||
}, this.reconnectInterval);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class WebSocketClient {
|
||||
try {
|
||||
const messageStr = data.toString();
|
||||
const message = JSON.parse(messageStr);
|
||||
|
||||
|
||||
// 减少心跳消息的日志打印
|
||||
if (message.cmd === 'heartcheck') {
|
||||
// 心跳消息不打印日志,或者只在调试模式下打印
|
||||
@@ -118,7 +118,7 @@ class WebSocketClient {
|
||||
} else {
|
||||
logger.info('收到消息:', messageStr);
|
||||
}
|
||||
|
||||
|
||||
this.handleMessage(message);
|
||||
} catch (error) {
|
||||
logger.error('消息解析错误:', error);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {checkForUpdates} from "./utils/updateUtils"
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
let mainWindow = null
|
||||
let oauthWindow = null
|
||||
let difyfullScreenWindow = null
|
||||
let drageWindow = null
|
||||
let apiConfigWindow = null
|
||||
@@ -51,6 +52,49 @@ async function checkAndApplyDeviceAccessPrivilege() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function createOAuthWindow(){
|
||||
logger.info('创建授权窗口')
|
||||
|
||||
Menu.setApplicationMenu(null)
|
||||
|
||||
// Create the browser window.
|
||||
oauthWindow = new BrowserWindow({
|
||||
width: 1480,
|
||||
height: 980,
|
||||
minWidth: 1480,
|
||||
minHeight: 980,
|
||||
show: false,
|
||||
media: {
|
||||
audio: true,
|
||||
video: true
|
||||
},
|
||||
icon: icon,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
nodeIntegrationInWorker: true,
|
||||
preload: join(__dirname, '../preload/index.js'),
|
||||
// sandbox: false
|
||||
}
|
||||
})
|
||||
|
||||
// 检查本地存储中是否已有 h5_client_url
|
||||
const existingH5ClientUrl = getStoreValue("h5_client_url")
|
||||
if (!existingH5ClientUrl || existingH5ClientUrl.trim() === '') {
|
||||
// 只有当值不存在或为空时,才设置默认值
|
||||
// setStoreValue("h5_client_url", "http://work.ii999.live:20040")
|
||||
// setStoreValue("h5_client_url", "http://10.102.8.56:18900")
|
||||
// setStoreValue("h5_client_url", "http://68.66.24.160:18900")
|
||||
setStoreValue("h5_client_url", import.meta.env.VITE_h5_client_url)
|
||||
}
|
||||
|
||||
const h5_client_url=getStoreValue("h5_client_url")+"/pc_client/autologin"
|
||||
|
||||
logger.info("==================================== mainWindow.loadURL:"+h5_client_url)
|
||||
// 加载存储的 URL
|
||||
oauthWindow.loadURL(h5_client_url)
|
||||
|
||||
|
||||
}
|
||||
|
||||
export async function createWindow() {
|
||||
// 如果窗口已经存在,直接显示并返回
|
||||
@@ -63,10 +107,15 @@ export async function createWindow() {
|
||||
|
||||
Menu.setApplicationMenu(null)
|
||||
|
||||
// createOAuthWindow()
|
||||
// return
|
||||
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 420,
|
||||
height: 900,
|
||||
width: 1480,
|
||||
height: 980,
|
||||
minWidth: 1480,
|
||||
minHeight: 980,
|
||||
show: false,
|
||||
media: {
|
||||
audio: true,
|
||||
@@ -85,7 +134,18 @@ export async function createWindow() {
|
||||
// 创建菜单
|
||||
createMenu(mainWindow, difyfullScreenWindow)
|
||||
|
||||
let code = `localStorage.setItem("IsHsAiApp","IsHsAiApp");localStorage.setItem("HsAppCode",${import.meta.env.VITE_HsAppCode});`
|
||||
|
||||
|
||||
const isDebugger=getStoreValue("isDebugger");
|
||||
|
||||
|
||||
const localStorageStatements = [
|
||||
`localStorage.setItem("IsHsAiApp","IsHsAiApp");`,
|
||||
`localStorage.setItem("HsAppCode",${import.meta.env.VITE_HsAppCode});`,
|
||||
`localStorage.setItem("isDebugger",${isDebugger});`
|
||||
].join('\n');
|
||||
|
||||
let code = `${localStorageStatements};`;
|
||||
|
||||
|
||||
const isAdmin = getStoreValue("isAdmin")
|
||||
@@ -107,12 +167,17 @@ export async function createWindow() {
|
||||
|
||||
// 监听快捷键 F12 来打开/关闭 DevTools
|
||||
mainWindow.webContents.on('before-input-event', (event, input) => {
|
||||
if (input.key === 'F12') {
|
||||
mainWindow.webContents.toggleDevTools()
|
||||
} else if (input.key === 'F5') {
|
||||
logger.info('主窗口 F5 快捷键触发')
|
||||
mainWindow.reload()
|
||||
|
||||
const isDebugger=getStoreValue("isDebugger");
|
||||
if (isDebugger==1){
|
||||
if (input.key === 'F12') {
|
||||
mainWindow.webContents.toggleDevTools()
|
||||
} else if (input.key === 'F5') {
|
||||
logger.info('全屏窗口 F5 快捷键触发')
|
||||
mainWindow.reload()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
@@ -161,7 +226,7 @@ export async function createWindow() {
|
||||
setStoreValue("h5_client_url", import.meta.env.VITE_h5_client_url)
|
||||
}
|
||||
|
||||
const h5_client_url=getStoreValue("h5_client_url")+"/h5_client/"
|
||||
const h5_client_url=getStoreValue("h5_client_url")+"/pc_client/"
|
||||
|
||||
logger.info("==================================== mainWindow.loadURL:"+h5_client_url)
|
||||
// 加载存储的 URL
|
||||
@@ -174,10 +239,10 @@ export async function createWindow() {
|
||||
|
||||
mainWindow.webContents.on('did-fail-load', async (event, errorCode, errorDescription, validatedURL) => {
|
||||
logger.error(`主窗口页面加载失败: code=${errorCode}, desc=${errorDescription}, url=${validatedURL}, 失败次数: ${failLoadCount + 1}`)
|
||||
|
||||
|
||||
// 增加失败计数
|
||||
failLoadCount++;
|
||||
|
||||
|
||||
if (failLoadCount <= maxRetries) {
|
||||
logger.info(`页面加载失败,${retryDelay}ms后进行第${failLoadCount}次重试...`);
|
||||
setTimeout(async () => {
|
||||
@@ -291,19 +356,30 @@ function registerShortcuts(window=null) {
|
||||
|
||||
logger.info(`F5快捷键注册${success ? '成功' : '失败'}`)
|
||||
|
||||
const isRegistered_F12 = globalShortcut.isRegistered('F12');
|
||||
logger.info(`Is F12 registered: ${isRegistered_F12}`);
|
||||
|
||||
|
||||
const isDebugger=getStoreValue("isDebugger");
|
||||
if (isDebugger==1){
|
||||
const isRegistered_F12 = globalShortcut.isRegistered('F12');
|
||||
logger.info(`Is F12 registered: ${isRegistered_F12}`);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 桌面端快要退出的时候,注销快捷键
|
||||
app.on('will-quit', () => {
|
||||
globalShortcut.unregisterAll() // 注销所有快捷键
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
export async function createNewWindow(url, access_token, refresh_token,sandbox=false) {
|
||||
const origin_url = url
|
||||
logger.info('==========createNewWindow')
|
||||
logger.info('==========createNewWindow sandbox',sandbox)
|
||||
const csrf_token=getStoreValue("dify_csrf_token")
|
||||
|
||||
await checkAndApplyDeviceAccessPrivilege()
|
||||
|
||||
@@ -329,9 +405,24 @@ export async function createNewWindow(url, access_token, refresh_token,sandbox=f
|
||||
registerShortcuts(difyfullScreenWindow)
|
||||
})
|
||||
|
||||
let code = `localStorage.setItem("IsHsAiApp","IsHsAiApp");localStorage.setItem("console_token","${access_token}");localStorage.setItem("refresh_token","12");`
|
||||
const isAdmin = getStoreValue("isAdmin")
|
||||
const hs_version = getStoreValue("hs_version")
|
||||
|
||||
const cookieStatements = [
|
||||
`document.cookie = "access_token=${access_token}";`,
|
||||
`document.cookie = "refresh_token=${refresh_token}";`,
|
||||
`document.cookie = "csrf_token=${csrf_token}";`,
|
||||
`document.cookie = "hs_version=${hs_version}";`
|
||||
].join('\n');
|
||||
|
||||
const localStorageStatements = [
|
||||
`localStorage.setItem("IsHsAiApp", "IsHsAiApp");`,
|
||||
`localStorage.setItem("console_token", "${access_token}");`,
|
||||
`localStorage.setItem("refresh_token", "12");`
|
||||
].join('\n');
|
||||
|
||||
let code = `${localStorageStatements}\n${cookieStatements};`;
|
||||
|
||||
const isAdmin = getStoreValue("isAdmin")
|
||||
let display='';
|
||||
|
||||
if (isAdmin==true){
|
||||
@@ -354,7 +445,7 @@ export async function createNewWindow(url, access_token, refresh_token,sandbox=f
|
||||
`
|
||||
}
|
||||
|
||||
code=code+`document.cookie="hs_version=${hs_version}";`
|
||||
code=code+`;document.cookie="hs_version=${hs_version}";`
|
||||
|
||||
difyfullScreenWindow.webContents.on('did-finish-load', () => {
|
||||
difyfullScreenWindow.webContents
|
||||
@@ -387,12 +478,16 @@ export async function createNewWindow(url, access_token, refresh_token,sandbox=f
|
||||
|
||||
// 监听快捷键 F12 来打开/关闭 DevTools
|
||||
difyfullScreenWindow.webContents.on('before-input-event', (event, input) => {
|
||||
if (input.key === 'F12') {
|
||||
difyfullScreenWindow.webContents.toggleDevTools()
|
||||
} else if (input.key === 'F5') {
|
||||
logger.info('全屏窗口 F5 快捷键触发')
|
||||
difyfullScreenWindow.reload()
|
||||
const isDebugger=getStoreValue("isDebugger");
|
||||
if (isDebugger==1){
|
||||
if (input.key === 'F12') {
|
||||
difyfullScreenWindow.webContents.toggleDevTools()
|
||||
} else if (input.key === 'F5') {
|
||||
logger.info('全屏窗口 F5 快捷键触发')
|
||||
difyfullScreenWindow.reload()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
difyfullScreenWindow.webContents.setWindowOpenHandler((details) => {
|
||||
@@ -503,18 +598,18 @@ export async function createNewWindow(url, access_token, refresh_token,sandbox=f
|
||||
|
||||
difyfullScreenWindow.webContents.on('did-fail-load', async (event, errorCode, errorDescription, validatedURL) => {
|
||||
logger.error(`全屏窗口页面加载失败: code=${errorCode}, desc=${errorDescription}, url=${validatedURL}, 失败次数: ${failLoadCount + 1}`)
|
||||
|
||||
|
||||
failLoadCount++;
|
||||
|
||||
|
||||
if (failLoadCount <= maxRetries) {
|
||||
logger.info(`全屏窗口页面加载失败,${retryDelay}ms后进行第${failLoadCount}次重试...`);
|
||||
|
||||
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
// 在重试前先检查网络连接
|
||||
const { checkDefaultClientConnection } = await import('./utils/networkUtils.js');
|
||||
const isNetworkConnected = await checkDefaultClientConnection(3000);
|
||||
|
||||
|
||||
if (isNetworkConnected) {
|
||||
logger.info('网络连接正常,重新加载全屏窗口页面');
|
||||
difyfullScreenWindow.reload();
|
||||
@@ -606,18 +701,18 @@ export function createDrageWindow() {
|
||||
|
||||
drageWindow.webContents.on('did-fail-load', async (event, errorCode, errorDescription, validatedURL) => {
|
||||
logger.error(`悬浮窗口页面加载失败: code=${errorCode}, desc=${errorDescription}, url=${validatedURL}, 失败次数: ${drageFailLoadCount + 1}`)
|
||||
|
||||
|
||||
drageFailLoadCount++;
|
||||
|
||||
|
||||
if (drageFailLoadCount <= drageMaxRetries) {
|
||||
logger.info(`悬浮窗口页面加载失败,${drageRetryDelay}ms后进行第${drageFailLoadCount}次重试...`);
|
||||
|
||||
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
// 在重试前先检查网络连接
|
||||
const { checkDefaultClientConnection } = await import('./utils/networkUtils.js');
|
||||
const isNetworkConnected = await checkDefaultClientConnection(3000);
|
||||
|
||||
|
||||
if (isNetworkConnected) {
|
||||
logger.info('网络连接正常,重新加载悬浮窗口页面');
|
||||
drageWindow.reload();
|
||||
@@ -653,6 +748,8 @@ export async function tokenExpireTimer(){
|
||||
const LOG_INTERVAL = 60000; // 日志打印间隔,60秒打印一次
|
||||
|
||||
const tokenExpireTimer = setInterval(async () => {
|
||||
return false;
|
||||
|
||||
const currentTime = Date.now();
|
||||
const lastActiveTime = getStoreValue("lastActiveTime")||null
|
||||
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import { contextBridge , ipcRenderer} from 'electron'
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
import { electronAPI } from '@electron-toolkit/preload'
|
||||
|
||||
// Custom APIs for renderer
|
||||
const api = {}
|
||||
|
||||
// Use `contextBridge` APIs to expose Electron APIs to
|
||||
// renderer only if context isolation is enabled, otherwise
|
||||
// just add to the DOM global.
|
||||
if (process.contextIsolated) {
|
||||
try {
|
||||
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||
contextBridge.exposeInMainWorld('api', api)
|
||||
|
||||
ipcRenderer.on('data-from-main', (event, key,value) => {
|
||||
localStorage.setItem(key, value);
|
||||
});
|
||||
|
||||
ipcRenderer.on('data-from-main', (event, key, value) => {
|
||||
localStorage.setItem(key, value)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||