+
{
+
+
+
+
启动后不打开主界面,静默驻留托盘(托盘左键可呼出)
+
+
appStore.toggleSilentAutoStart(checked)"
+ />
+
@@ -675,8 +874,42 @@ const onDragEnd = () => {
{{ progress.message }}
{{ progress.percent }}%
-
+
+
+
+
+
+
+ 停止监控内核后继续
+
+ {{
+ thinghkConfirmState.wasRunning
+ ? '内核更新包已下载。安装新内核前需要停止监控内核,点击「停止并继续」将自动停止监控并完成安装。'
+ : '内核更新包已下载。即将安装新内核,点击「继续」完成安装。'
+ }}
+
+
+
+ 取消
+
+ {{ thinghkConfirmState.busy ? '正在停止...' : (thinghkConfirmState.wasRunning ? '停止并继续' : '继续') }}
+
+
+
+
diff --git a/src/stores/appStore.ts b/src/stores/appStore.ts
index 376cf7d..8c0137f 100644
--- a/src/stores/appStore.ts
+++ b/src/stores/appStore.ts
@@ -57,6 +57,7 @@ export const useAppStore = defineStore('app', () => {
const theme = ref
('system')
const effect = ref('mica')
const isAutoStart = ref(false)
+ const silentAutoStart = ref(false)
const isInitialized = ref(false)
const modules = ref(initModulesFromRegistry())
const moduleOrder = ref(initModuleOrder())
@@ -88,6 +89,8 @@ export const useAppStore = defineStore('app', () => {
if (settings.theme) theme.value = settings.theme
if (settings.effect) effect.value = settings.effect
+ if (typeof settings.isAutoStart === 'boolean') isAutoStart.value = settings.isAutoStart
+ if (typeof settings.silentAutoStart === 'boolean') silentAutoStart.value = settings.silentAutoStart
if (settings.modules) {
const savedModules = settings.modules as Array<{ id: string; enabled: boolean }>
savedModules.forEach(sm => {
@@ -127,6 +130,7 @@ export const useAppStore = defineStore('app', () => {
theme: theme.value,
effect: effect.value,
isAutoStart: isAutoStart.value,
+ silentAutoStart: silentAutoStart.value,
modules: modulesData,
moduleOrder: moduleOrder.value
}))
@@ -323,6 +327,11 @@ export const useAppStore = defineStore('app', () => {
}
}
+ const toggleSilentAutoStart = (checked?: boolean) => {
+ silentAutoStart.value = checked !== undefined ? checked : !silentAutoStart.value
+ saveSettings()
+ }
+
const applyTheme = async () => {
const root = document.documentElement
root.classList.remove('dark')
@@ -472,6 +481,8 @@ export const useAppStore = defineStore('app', () => {
isInitialized.value = true
} finally {
+ // 静默启动:仅当未开启时才显示主窗口(开启后启动静默驻留托盘,托盘左键可呼出)
+ if (silentAutoStart.value) return
try {
const tauriWindow = getCurrentWindow()
await tauriWindow.show()
@@ -486,6 +497,7 @@ export const useAppStore = defineStore('app', () => {
effect,
systemDark,
isAutoStart,
+ silentAutoStart,
isInitialized,
modules,
moduleOrder,
@@ -497,6 +509,7 @@ export const useAppStore = defineStore('app', () => {
setTheme,
setEffect,
toggleAutoStart,
+ toggleSilentAutoStart,
applyTheme,
applyEffect,
init,
diff --git a/src/stores/monitorStore.ts b/src/stores/monitorStore.ts
index 43b3959..a7b1ed5 100644
--- a/src/stores/monitorStore.ts
+++ b/src/stores/monitorStore.ts
@@ -185,6 +185,8 @@ export interface OsdConfig {
/** 悬浮窗窗口保存位置(null=使用百分比计算默认位置) */
overlayX?: number | null
overlayY?: number | null
+ /** 游戏全屏时自动隐藏悬浮窗(前台全屏应用会因置顶透明窗口掉帧,默认开启) */
+ gameAutoHide: boolean
}
/** OSD 悬浮窗窗口 label(与 Tauri 窗口创建对应,见 constants::WINDOWS) */
@@ -274,6 +276,7 @@ function defaultOsdConfig(): OsdConfig {
alert: { ...DEFAULT_ALERT_CONFIG, maxValues: { ...DEFAULT_ALERT_CONFIG.maxValues } },
overlayX: null,
overlayY: null,
+ gameAutoHide: true,
}
}
@@ -340,6 +343,10 @@ export const useMonitorStore = defineStore('monitor', () => {
*/
const osdConfig = ref(loadOsdConfig())
+ /** 前台是否为全屏应用(游戏)。由 Rust 侧 osd-game-active/inactive 事件驱动,
+ * 用于游戏时隐藏 OSD(透明置顶窗口会占用 DWM 合成路径导致游戏掉帧) */
+ const gameFullscreen = ref(false)
+
/** OSD 配置防抖保存:滑块/输入连续变化时合并为一次 localStorage 写入(避免每帧全量序列化) */
let osdSaveTimer: ReturnType | null = null
/** OSD 配置防抖推送定时器(initOsd 内注册的 deep watch 使用,dispose 时需清理) */
@@ -367,6 +374,8 @@ export const useMonitorStore = defineStore('monitor', () => {
/** 推送 OSD 数据到所有 OSD 窗口(高频通道:仅显示项 key→value 映射 + 网速,每秒一次) */
async function pushOsdState() {
if (!osdConfig.value.overlayEnabled) return
+ // 游戏全屏自动隐藏期间停止推送:OSD 窗口已隐藏,推送只会白白消耗 IPC 和 WebView JS 时间片
+ if (gameFullscreen.value && osdConfig.value.gameAutoHide) return
try {
const map = sensorKeyMap.value
const data: Record = {}
@@ -1190,12 +1199,24 @@ export const useMonitorStore = defineStore('monitor', () => {
if (enabled) {
// 开启时若显示项为空则不创建窗口
if (osdConfig.value.overlayItems.length === 0) return
+ // 游戏全屏自动隐藏期间不创建窗口(退出全屏时由 osd-game-inactive 统一恢复)
+ if (gameFullscreen.value && osdConfig.value.gameAutoHide) return
ensureOverlayWindow().catch(e => logger.error('[OSD] 创建悬浮窗失败: ' + e))
} else {
hideOverlayWindow().catch(e => logger.error('[OSD] 隐藏悬浮窗失败: ' + e))
}
}))
+ // 游戏中切换"自动隐藏"开关:立即生效(关闭时恢复显示,开启时立即隐藏)
+ osdWatchStops.push(watch(() => osdConfig.value.gameAutoHide, (enabled) => {
+ if (!osdConfig.value.overlayEnabled || !gameFullscreen.value) return
+ if (enabled) {
+ hideOverlayWindow().catch(e => logger.error('[OSD] 游戏全屏隐藏悬浮窗失败: ' + e))
+ } else {
+ ensureOverlayWindow().catch(e => logger.error('[OSD] 恢复悬浮窗失败: ' + e))
+ }
+ }))
+
// 显示项变化时:无项则隐藏窗口,有项且开关开则确保窗口存在
osdWatchStops.push(watch(() => osdConfig.value.overlayItems.length, (len) => {
if (!osdConfig.value.overlayEnabled) return
diff --git a/vite.config.ts b/vite.config.ts
index 645350f..bdba4e2 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -54,14 +54,16 @@ export default defineConfig(async () => ({
clearScreen: false,
// 2. tauri expects a fixed port, fail if that port is not available
server: {
- port: 1420,
+ // 1420/1421 落在 Windows 保留端口段 1333-1432 内(Hyper-V/WinNAT 动态保留),
+ // 绑定时报 EACCES,故改用 14210/14211(netsh excludedportrange 确认可用)
+ port: 14210,
strictPort: true,
host: host || false,
hmr: host
? {
protocol: "ws",
host,
- port: 1421,
+ port: 14211,
}
: undefined,
watch: {