实现客户端的单点登录
This commit is contained in:
@@ -1,4 +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=https://bqw-120.ii999.live:20038
|
||||||
#VITE_h5_client_url=http://127.0.0.1:18901
|
#VITE_h5_client_url=http://127.0.0.1:18901
|
||||||
VITE_HsAppCode=1
|
VITE_HsAppCode=1
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
appId: com.huashiai.dify-market-manager-gui
|
appId: com.szgas.dify-market-manager-gui
|
||||||
compression: maximum
|
compression: maximum
|
||||||
productName: 深燃智能体平台
|
productName: 深燃智能体平台
|
||||||
directories:
|
directories:
|
||||||
@@ -12,7 +12,7 @@ files:
|
|||||||
asarUnpack:
|
asarUnpack:
|
||||||
- resources/**
|
- resources/**
|
||||||
win:
|
win:
|
||||||
executableName: 深燃智能体平台
|
executableName: 深圳燃气智能体平台
|
||||||
nsis:
|
nsis:
|
||||||
artifactName: ${name}-${version}-setup.${ext}
|
artifactName: ${name}-${version}-setup.${ext}
|
||||||
shortcutName: ${productName}
|
shortcutName: ${productName}
|
||||||
@@ -32,7 +32,7 @@ linux:
|
|||||||
target:
|
target:
|
||||||
- AppImage
|
- AppImage
|
||||||
- deb
|
- deb
|
||||||
maintainer: huashiai.org
|
maintainer: szgas.org
|
||||||
category: Utility
|
category: Utility
|
||||||
appImage:
|
appImage:
|
||||||
artifactName: ${name}-${version}.${ext}
|
artifactName: ${name}-${version}.${ext}
|
||||||
|
|||||||
27
package.json
27
package.json
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "dify-market-manager-gui",
|
"name": "SZGAS_AIAgent",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "百千万AI智能体共创平台",
|
"description": "深圳燃气 AI智能体",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "huashiai.com",
|
"author": "szgas.com",
|
||||||
"homepage": "https://huashiai.com",
|
"homepage": "https://szgas.com",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"lint": "eslint --cache .",
|
"lint": "eslint --cache .",
|
||||||
@@ -37,6 +37,24 @@
|
|||||||
"build:icon": "./node_modules/.bin/electron-icon-builder --input=./build/icon.png --output=./build/",
|
"build:icon": "./node_modules/.bin/electron-icon-builder --input=./build/icon.png --output=./build/",
|
||||||
"make": "electron-forge make"
|
"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": [
|
"permissions": [
|
||||||
"audioCapture",
|
"audioCapture",
|
||||||
"videoCapture"
|
"videoCapture"
|
||||||
@@ -51,6 +69,7 @@
|
|||||||
"electron-log": "^5.4.0",
|
"electron-log": "^5.4.0",
|
||||||
"electron-store": "^8.0.0",
|
"electron-store": "^8.0.0",
|
||||||
"electron-updater": "^6.3.9",
|
"electron-updater": "^6.3.9",
|
||||||
|
"jquery": "^3.7.1",
|
||||||
"ws": "^8.18.2",
|
"ws": "^8.18.2",
|
||||||
"xe-utils": "^3.7.4"
|
"xe-utils": "^3.7.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { app, shell, BrowserWindow, ipcMain, Menu, session, screen, dialog } from 'electron'
|
import { app, shell, BrowserWindow, ipcMain, Menu, session, screen, dialog } from 'electron'
|
||||||
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||||
import Store from 'electron-store'
|
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 { setupIPC } from './ipc.js'
|
||||||
import { createTray, destroyTray,clearBrowserCache } from './tray.js'
|
import { createTray, destroyTray,clearBrowserCache } from './tray.js'
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
@@ -15,6 +15,8 @@ import { setStoreValue, getStoreValue ,deleteStore} from './store.js'
|
|||||||
import AutoLaunch from 'auto-launch'
|
import AutoLaunch from 'auto-launch'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const PROTOCOL_NAME = 'aiAgent'
|
||||||
|
|
||||||
import WebSocketClient from './utils/WebSocketClient';
|
import WebSocketClient from './utils/WebSocketClient';
|
||||||
|
|
||||||
let wsClient=null
|
let wsClient=null
|
||||||
@@ -163,6 +165,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 +258,10 @@ if (!gotTheLock) {
|
|||||||
// 监听第二个实例被运行时
|
// 监听第二个实例被运行时
|
||||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||||
logger.info('检测到第二个实例启动,激活现有实例')
|
logger.info('检测到第二个实例启动,激活现有实例')
|
||||||
|
const deeplink = extractDeepLinkFromArgs(commandLine)
|
||||||
|
if (deeplink) {
|
||||||
|
handleDeepLink(deeplink)
|
||||||
|
}
|
||||||
// 当有第二个实例被运行时,激活之前的实例并将焦点置于其窗口
|
// 当有第二个实例被运行时,激活之前的实例并将焦点置于其窗口
|
||||||
const windows = BrowserWindow.getAllWindows()
|
const windows = BrowserWindow.getAllWindows()
|
||||||
if (windows.length > 0) {
|
if (windows.length > 0) {
|
||||||
@@ -196,6 +277,8 @@ if (!gotTheLock) {
|
|||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
logger.info('应用已准备就绪,开始初始化...');
|
logger.info('应用已准备就绪,开始初始化...');
|
||||||
|
|
||||||
|
registerDeepLinkProtocol()
|
||||||
|
|
||||||
// 清理缓存目录
|
// 清理缓存目录
|
||||||
cleanupCacheDirectories()
|
cleanupCacheDirectories()
|
||||||
|
|
||||||
@@ -213,6 +296,8 @@ if (!gotTheLock) {
|
|||||||
optimizer.watchWindowShortcuts(window)
|
optimizer.watchWindowShortcuts(window)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 根据存储的状态决定是否创建悬浮窗口
|
// 根据存储的状态决定是否创建悬浮窗口
|
||||||
if (getStoreValue('showDrageWindow')) {
|
if (getStoreValue('showDrageWindow')) {
|
||||||
createDrageWindow()
|
createDrageWindow()
|
||||||
@@ -247,8 +332,20 @@ if (!gotTheLock) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
logger.info('应用初始化完成');
|
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) => {
|
app.on('window-all-closed', async (event) => {
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export function createTray() {
|
|||||||
tray = new Tray(icon)
|
tray = new Tray(icon)
|
||||||
|
|
||||||
// 设置托盘图标的提示文本
|
// 设置托盘图标的提示文本
|
||||||
tray.setToolTip('Dify Market Manager')
|
tray.setToolTip('深圳燃气 AI智能体')
|
||||||
|
|
||||||
// 创建右键菜单
|
// 创建右键菜单
|
||||||
const contextMenu = Menu.buildFromTemplate([
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class WebSocketClient {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.lockReconnect = false;
|
this.lockReconnect = false;
|
||||||
this.createConnect(); // 重新获取本地缓存并创建连接
|
// this.createConnect(); // 重新获取本地缓存并创建连接
|
||||||
}, this.reconnectInterval);
|
}, this.reconnectInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {checkForUpdates} from "./utils/updateUtils"
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
let mainWindow = null
|
let mainWindow = null
|
||||||
|
let oauthWindow = null
|
||||||
let difyfullScreenWindow = null
|
let difyfullScreenWindow = null
|
||||||
let drageWindow = null
|
let drageWindow = null
|
||||||
let apiConfigWindow = 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() {
|
export async function createWindow() {
|
||||||
// 如果窗口已经存在,直接显示并返回
|
// 如果窗口已经存在,直接显示并返回
|
||||||
@@ -63,6 +107,9 @@ export async function createWindow() {
|
|||||||
|
|
||||||
Menu.setApplicationMenu(null)
|
Menu.setApplicationMenu(null)
|
||||||
|
|
||||||
|
// createOAuthWindow()
|
||||||
|
// return
|
||||||
|
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 1480,
|
width: 1480,
|
||||||
@@ -300,6 +347,9 @@ function registerShortcuts(window=null) {
|
|||||||
app.on('will-quit', () => {
|
app.on('will-quit', () => {
|
||||||
globalShortcut.unregisterAll() // 注销所有快捷键
|
globalShortcut.unregisterAll() // 注销所有快捷键
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createNewWindow(url, access_token, refresh_token,sandbox=false) {
|
export async function createNewWindow(url, access_token, refresh_token,sandbox=false) {
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
import { contextBridge , ipcRenderer} from 'electron'
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
import { electronAPI } from '@electron-toolkit/preload'
|
import { electronAPI } from '@electron-toolkit/preload'
|
||||||
|
|
||||||
// Custom APIs for renderer
|
// Custom APIs for renderer
|
||||||
const api = {}
|
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) {
|
if (process.contextIsolated) {
|
||||||
try {
|
try {
|
||||||
contextBridge.exposeInMainWorld('electron', electronAPI)
|
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||||
contextBridge.exposeInMainWorld('api', api)
|
contextBridge.exposeInMainWorld('api', api)
|
||||||
|
ipcRenderer.on('data-from-main', (event, key, value) => {
|
||||||
ipcRenderer.on('data-from-main', (event, key,value) => {
|
localStorage.setItem(key, value)
|
||||||
localStorage.setItem(key, value);
|
})
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
@@ -23,5 +18,26 @@ if (process.contextIsolated) {
|
|||||||
window.electron = electronAPI
|
window.electron = electronAPI
|
||||||
window.api = api
|
window.api = api
|
||||||
|
|
||||||
|
// ✅ 重点修复:覆盖 require('jquery') 让它返回 jQuery
|
||||||
|
try {
|
||||||
|
// 保存原始 require 避免循环
|
||||||
|
const originalRequire = require;
|
||||||
|
// 重写 require 函数,让 'jquery' 请求返回 jQuery
|
||||||
|
require = (request) => {
|
||||||
|
if (request === 'jquery') {
|
||||||
|
// 确保 jQuery 已加载
|
||||||
|
if (!window.jQuery) {
|
||||||
|
window.jQuery = originalRequire('jquery');
|
||||||
|
window.$ = window.jQuery;
|
||||||
|
}
|
||||||
|
return window.jQuery;
|
||||||
|
}
|
||||||
|
return originalRequire(request);
|
||||||
|
};
|
||||||
|
// 初始化 jQuery(触发上面的逻辑)
|
||||||
|
window.jQuery = require('jquery');
|
||||||
|
window.$ = window.jQuery;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load jQuery:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user