diff --git a/frontend/electron/main.ts b/frontend/electron/main.ts index 9360e27..f313a6f 100644 --- a/frontend/electron/main.ts +++ b/frontend/electron/main.ts @@ -5,6 +5,7 @@ import { ipcMain, Menu, nativeImage, + nativeTheme, screen, shell, Tray, @@ -749,6 +750,108 @@ ipcMain.handle('stop-backend', async () => { return stopBackend() }) +// 获取当前主题信息 +ipcMain.handle('get-theme-info', async () => { + try { + const appRoot = getAppRoot() + const configPath = path.join(appRoot, 'config', 'frontend_config.json') + + let themeMode = 'system' + let themeColor = 'blue' + + // 尝试从配置文件读取主题设置 + if (fs.existsSync(configPath)) { + try { + const configData = fs.readFileSync(configPath, 'utf8') + const config = JSON.parse(configData) + themeMode = config.themeMode || 'system' + themeColor = config.themeColor || 'blue' + } catch (error) { + log.warn('读取主题配置失败,使用默认值:', error) + } + } + + // 检测系统主题 + const systemTheme = nativeTheme.shouldUseDarkColors ? 'dark' : 'light' + + // 确定实际使用的主题 + let actualTheme = themeMode + if (themeMode === 'system') { + actualTheme = systemTheme + } + + const themeColors: Record = { + blue: '#1677ff', + purple: '#722ed1', + cyan: '#13c2c2', + green: '#52c41a', + magenta: '#eb2f96', + pink: '#eb2f96', + red: '#ff4d4f', + orange: '#fa8c16', + yellow: '#fadb14', + volcano: '#fa541c', + geekblue: '#2f54eb', + lime: '#a0d911', + gold: '#faad14', + } + + return { + themeMode, + themeColor, + actualTheme, + systemTheme, + isDark: actualTheme === 'dark', + primaryColor: themeColors[themeColor] || themeColors.blue + } + } catch (error) { + log.error('获取主题信息失败:', error) + return { + themeMode: 'system', + themeColor: 'blue', + actualTheme: 'light', + systemTheme: 'light', + isDark: false, + primaryColor: '#1677ff' + } + } +}) + +// 获取对话框专用的主题信息 +ipcMain.handle('get-theme', async () => { + try { + const appRoot = getAppRoot() + const configPath = path.join(appRoot, 'config', 'frontend_config.json') + + let themeMode = 'system' + + // 尝试从配置文件读取主题设置 + if (fs.existsSync(configPath)) { + try { + const configData = fs.readFileSync(configPath, 'utf8') + const config = JSON.parse(configData) + themeMode = config.themeMode || 'system' + } catch (error) { + log.warn('读取主题配置失败,使用默认值:', error) + } + } + + // 检测系统主题 + const systemTheme = nativeTheme.shouldUseDarkColors ? 'dark' : 'light' + + // 确定实际使用的主题 + let actualTheme = themeMode + if (themeMode === 'system') { + actualTheme = systemTheme + } + + return actualTheme + } catch (error) { + log.error('获取对话框主题失败:', error) + return nativeTheme.shouldUseDarkColors ? 'dark' : 'light' + } +}) + // 全局存储对话框窗口引用和回调 let dialogWindows = new Map() let dialogCallbacks = new Map void>() @@ -769,15 +872,19 @@ function createQuestionDialog(questionData: any): Promise { messageId: messageId } - // 创建对话框窗口 + // 获取主窗口的尺寸用于全屏显示 + let windowBounds = { width: 800, height: 600, x: 100, y: 100 } + if (mainWindow && !mainWindow.isDestroyed()) { + windowBounds = mainWindow.getBounds() + } + + // 创建对话框窗口 - 小尺寸可拖动窗口 const dialogWindow = new BrowserWindow({ - width: 450, - height: 200, - minWidth: 350, - minHeight: 150, - maxWidth: 600, - maxHeight: 400, - resizable: true, + width: 400, + height: 140, + x: windowBounds.x + (windowBounds.width - 400) / 2, // 居中显示 + y: windowBounds.y + (windowBounds.height - 200) / 2, + resizable: false, // 不允许改变大小 minimizable: false, maximizable: false, alwaysOnTop: true, @@ -803,19 +910,8 @@ function createQuestionDialog(questionData: any): Promise { const dialogUrl = `file://${path.join(__dirname, '../public/dialog.html')}?data=${encodedData}` dialogWindow.loadURL(dialogUrl) - // 窗口准备好后显示并居中 + // 窗口准备好后显示 dialogWindow.once('ready-to-show', () => { - // 计算居中位置 - if (mainWindow && !mainWindow.isDestroyed()) { - const mainBounds = mainWindow.getBounds() - const dialogBounds = dialogWindow.getBounds() - const x = Math.round(mainBounds.x + (mainBounds.width - dialogBounds.width) / 2) - const y = Math.round(mainBounds.y + (mainBounds.height - dialogBounds.height) / 2) - dialogWindow.setPosition(x, y) - } else { - dialogWindow.center() - } - dialogWindow.show() dialogWindow.focus() }) @@ -830,7 +926,7 @@ function createQuestionDialog(questionData: any): Promise { } }) - log.info(`对话框窗口已创建: ${messageId}`) + log.info(`全屏对话框窗口已创建: ${messageId}`) }) } @@ -867,16 +963,16 @@ ipcMain.handle('dialog-response', async (_event, messageId: string, choice: bool return true }) -// 调整对话框窗口大小 -ipcMain.handle('resize-dialog-window', async (_event, height: number) => { +// 移动对话框窗口 +ipcMain.handle('move-window', async (_event, deltaX: number, deltaY: number) => { // 获取当前活动的对话框窗口(最后创建的) const dialogWindow = Array.from(dialogWindows.values()).pop() if (dialogWindow && !dialogWindow.isDestroyed()) { - const bounds = dialogWindow.getBounds() - dialogWindow.setBounds({ - ...bounds, - height: Math.max(150, Math.min(400, height)) - }) + const currentBounds = dialogWindow.getBounds() + dialogWindow.setPosition( + currentBounds.x + deltaX, + currentBounds.y + deltaY + ) } }) diff --git a/frontend/electron/preload.ts b/frontend/electron/preload.ts index 0a31b5c..e2137e7 100644 --- a/frontend/electron/preload.ts +++ b/frontend/electron/preload.ts @@ -67,6 +67,11 @@ contextBridge.exposeInMainWorld('electronAPI', { showQuestionDialog: (questionData: any) => ipcRenderer.invoke('show-question-dialog', questionData), dialogResponse: (messageId: string, choice: boolean) => ipcRenderer.invoke('dialog-response', messageId, choice), resizeDialogWindow: (height: number) => ipcRenderer.invoke('resize-dialog-window', height), + moveWindow: (deltaX: number, deltaY: number) => ipcRenderer.invoke('move-window', deltaX, deltaY), + + // 主题信息获取 + getThemeInfo: () => ipcRenderer.invoke('get-theme-info'), + getTheme: () => ipcRenderer.invoke('get-theme'), // 监听下载进度 onDownloadProgress: (callback: (progress: any) => void) => { diff --git a/frontend/public/dialog.html b/frontend/public/dialog.html index 6a451a5..ce87aae 100644 --- a/frontend/public/dialog.html +++ b/frontend/public/dialog.html @@ -5,6 +5,70 @@ 操作确认 -
+