diff --git a/docs/examples/provider-example/README.md b/docs/examples/provider-example/README.md index bfa4e6b6..e55027b7 100644 --- a/docs/examples/provider-example/README.md +++ b/docs/examples/provider-example/README.md @@ -21,8 +21,12 @@ ``` ```js -ztools.registerProvider('baidu', async (input) => { /* ... */ }) -ztools.registerProvider('google', async (input) => { /* ... */ }) +ztools.registerProvider('baidu', async (input) => { + /* ... */ +}) +ztools.registerProvider('google', async (input) => { + /* ... */ +}) ``` 详见主程序 `docs/provider-development-guide.md`。 diff --git a/docs/provider-development-guide.md b/docs/provider-development-guide.md index d1508d36..65edfa4c 100644 --- a/docs/provider-development-guide.md +++ b/docs/provider-development-guide.md @@ -50,7 +50,7 @@ ZTools 把「翻译」「OCR」等能力抽象为 **Provider(提供商)**。 ```json { "providers": { - "baidu": { "type": "translation", "label": "百度翻译" }, + "baidu": { "type": "translation", "label": "百度翻译" }, "google": { "type": "translation", "label": "谷歌翻译" } } } @@ -58,8 +58,12 @@ ZTools 把「翻译」「OCR」等能力抽象为 **Provider(提供商)**。 ```js // preload.js -ztools.registerProvider('baidu', async (input) => { /* 调用百度 */ }) -ztools.registerProvider('google', async (input) => { /* 调用谷歌 */ }) +ztools.registerProvider('baidu', async (input) => { + /* 调用百度 */ +}) +ztools.registerProvider('google', async (input) => { + /* 调用谷歌 */ +}) ``` 两条都会出现在「设置 → 提供商 → 翻译」,用户可分别启用并选其中一个为默认。 diff --git a/internal-plugins/setting/src/views/GeneralSetting/GeneralSetting.vue b/internal-plugins/setting/src/views/GeneralSetting/GeneralSetting.vue index 99ecef61..8306ee2b 100644 --- a/internal-plugins/setting/src/views/GeneralSetting/GeneralSetting.vue +++ b/internal-plugins/setting/src/views/GeneralSetting/GeneralSetting.vue @@ -253,6 +253,8 @@ const windowDefaultHeight = ref(541) // 托盘图标显示设置 const showTrayIcon = ref(true) +// 静默启动(默认开启) +const silentStart = ref(true) // 悬浮球设置 const floatingBallEnabled = ref(false) @@ -975,6 +977,18 @@ async function handleTrayIconChange(): Promise { } } +// 处理静默启动变化 +async function handleSilentStartChange(): Promise { + const ok = await saveSettings() + if (!ok) { + // v-model 已切换,保存失败时回滚 UI + silentStart.value = !silentStart.value + console.error('更新静默启动设置失败') + return + } + console.log('静默启动设置已更新:', silentStart.value) +} + // 处理悬浮球开关变化 async function handleFloatingBallChange(): Promise { try { @@ -1192,6 +1206,7 @@ async function loadSettings(): Promise { windowDefaultHeight.value = data.windowDefaultHeight ?? 541 hotkey.value = data.hotkey ?? defaultHotkey.value showTrayIcon.value = data.showTrayIcon ?? true + silentStart.value = data.silentStart ?? true placeholder.value = data.placeholder ?? DEFAULT_PLACEHOLDER avatar.value = data.avatar ?? DEFAULT_AVATAR autoPaste.value = data.autoPaste ?? '3s' @@ -1269,8 +1284,8 @@ async function loadSettings(): Promise { } } -// 保存设置 -async function saveSettings(): Promise { +// 保存设置(返回是否成功,便于调用方在失败时回滚 UI) +async function saveSettings(): Promise { try { // 只有自定义头像才保存到数据库,默认头像不保存 const avatarToSave = avatar.value === defaultAvatar ? undefined : avatar.value @@ -1311,6 +1326,7 @@ async function saveSettings(): Promise { primaryColor: primaryColor.value, customColor: customColor.value, showTrayIcon: showTrayIcon.value, + silentStart: silentStart.value, windowMaterial: windowMaterial.value, acrylicLightOpacity: acrylicLightOpacity.value, acrylicDarkOpacity: acrylicDarkOpacity.value, @@ -1324,8 +1340,10 @@ async function saveSettings(): Promise { terminal: terminal.value, terminalCustomCommand: terminalCustomCommand.value }) + return true } catch (error) { console.error('保存设置失败:', error) + return false } } @@ -1432,6 +1450,19 @@ onUnmounted(() => { +
+
+ 静默启动 + 启动时不显示主窗口,仅托盘运行 +
+
+ +
+
+
diff --git a/src/main/appMain.ts b/src/main/appMain.ts index 05719d1d..0329fb42 100644 --- a/src/main/appMain.ts +++ b/src/main/appMain.ts @@ -1,6 +1,6 @@ import './core/appData/configureAppDataRoot' import { platform } from '@electron-toolkit/utils' -import { app, BrowserWindow, session, webContents } from 'electron' +import { app, BrowserWindow, ipcMain, session, webContents } from 'electron' import log from 'electron-log' import path from 'path' import lmdbInstance from './core/lmdb/lmdbInstance' @@ -125,6 +125,20 @@ export function getCurrentShortcut(): string { } app.whenReady().then(async () => { + // 启动时仅处理一次:关闭静默启动则在渲染就绪后显示主窗口(需在创建窗口前注册,避免竞态) + ipcMain.once('renderer-ready', () => { + try { + const settingsDoc = lmdbInstance.get('ZTOOLS/settings-general') + const silentStart = settingsDoc?.data?.silentStart ?? true + if (!silentStart) { + windowManager.showWindow() + console.log('[Main] 静默启动已关闭,渲染进程就绪后自动显示搜索窗口') + } + } catch { + console.log('[Main] 读取静默启动设置失败,按默认行为启动') + } + }) + // macOS 辅助功能权限检查和请求(如果未授权则弹窗提示) await ensureMacAccessibilityPermission() diff --git a/src/preload/index.ts b/src/preload/index.ts index 61860a1a..65dec235 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -27,6 +27,7 @@ const api = { launchAsAdmin: (appPath: string, name?: string) => ipcRenderer.invoke('launch-as-admin', appPath, name), hideWindow: () => ipcRenderer.send('hide-window'), + rendererReady: () => ipcRenderer.send('renderer-ready'), resizeWindow: (height: number) => ipcRenderer.send('resize-window', height), updateLaunchContext: (context: { searchQuery: string @@ -475,6 +476,7 @@ declare global { confirmDialog?: any }) => Promise hideWindow: () => void + rendererReady: () => void resizeWindow: (height: number) => void updateLaunchContext: (context: { searchQuery: string diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index 140109b0..d922d615 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -524,6 +524,9 @@ onMounted(async () => { // 初始调整窗口高度 updateWindowHeight() + // 通知主进程渲染进程已就绪(用于静默启动控制) + window.ztools.rendererReady() + console.log('监听聚焦事件') // 监听窗口显示事件,聚焦搜索框,并接收窗口信息 diff --git a/src/renderer/src/env.d.ts b/src/renderer/src/env.d.ts index 935930a9..d770d805 100644 --- a/src/renderer/src/env.d.ts +++ b/src/renderer/src/env.d.ts @@ -58,6 +58,7 @@ declare global { }) => Promise launchAsAdmin: (appPath: string, name?: string) => Promise hideWindow: () => void + rendererReady: () => void resizeWindow: (height: number) => void updateLaunchContext: (context: { searchQuery: string