feat: 添加托盘最小化通知;禁用 F12 键事件监听

This commit is contained in:
2025-04-09 11:24:00 +08:00
parent 364d38ddc0
commit 6687888c97
3 changed files with 143 additions and 134 deletions

View File

@@ -1,115 +1,122 @@
<script setup lang="ts"> <script setup lang="ts">
import { useColorMode } from '@vueuse/core'; import { useColorMode } from '@vueuse/core';
import { disable, enable, isEnabled } from "@tauri-apps/plugin-autostart"; import { disable, enable, isEnabled } from "@tauri-apps/plugin-autostart";
import { ref, watch, onMounted } from 'vue'; import { ref, watch, onMounted } from 'vue';
import { import {
NGrid, NGrid,
NGridItem, // Corrected import NGridItem NGridItem,
NMenu, NMenu,
NRadio, NRadio,
NRadioGroup, // Added NRadioGroup NRadioGroup,
NSwitch, NSwitch,
NSpace, NSpace,
NCard, NCard,
NSpin, // Added NSpin for loading state NSpin,
NFormItem, // Added NFormItem NFormItem,
NAlert, NAlert,
NCheckboxGroup, NCheckboxGroup,
NCheckbox, NCheckbox,
NDivider, // Added NAlert for error messages NDivider,
} from 'naive-ui'; } from 'naive-ui';
import type { MenuOption } from 'naive-ui'; // Import MenuOption type import type { MenuOption } from 'naive-ui';
import { ThemeType } from '@/api/api-models'; import { ThemeType } from '@/api/api-models';
import { NotificationType, useSettings } from './store/useSettings'; import { NotificationType, useSettings } from './store/useSettings';
import { getVersion } from '@tauri-apps/api/app'; import { getVersion } from '@tauri-apps/api/app';
import { invoke } from '@tauri-apps/api/core';
// --- State --- // --- State ---
const currentTab = ref('general'); const currentTab = ref('general');
const isLoading = ref(true); // Loading state for initial fetch const isLoading = ref(true);
const errorMsg = ref<string | null>(null); // Error message state const errorMsg = ref<string | null>(null);
const titleClickCount = ref(0); // 添加计数器状态变量
let resetTimeout: number | null = null; // 用于重置计数器的超时ID
const setting = useSettings(); const setting = useSettings();
const currentVersion = await getVersion(); // Fetch current version on mount const currentVersion = await getVersion();
// Navigation // Navigation
const navOptions: MenuOption[] = [ // Explicitly typed const navOptions: MenuOption[] = [
{ label: '常规', key: 'general' }, { label: '常规', key: 'general' },
{ label: '通知', key: 'notification' }, { label: '通知', key: 'notification' },
{ label: '其他', key: 'other' }, { label: '其他', key: 'other' },
{ label: '关于', key: 'about' }, { label: '关于', key: 'about' },
]; ];
// Theme // Theme
const themeType = useStorage('Settings.Theme', ThemeType.Auto); const themeType = useStorage('Settings.Theme', ThemeType.Auto);
// Autostart Settings // Autostart Settings
const isStartOnBoot = ref(false); // Initialize with default, fetch in onMounted const isStartOnBoot = ref(false);
const minimizeOnStart = ref(false); // Placeholder state for minimize setting const minimizeOnStart = ref(false);
// --- Lifecycle Hooks --- // --- Lifecycle Hooks ---
onMounted(async () => { onMounted(async () => {
isLoading.value = true; isLoading.value = true;
errorMsg.value = null; errorMsg.value = null;
try { try {
isStartOnBoot.value = await isEnabled(); isStartOnBoot.value = await isEnabled();
// TODO: Fetch initial state for minimizeOnStart if applicable } catch (err) {
} catch (err) { console.error("Failed to fetch autostart status:", err);
console.error("Failed to fetch autostart status:", err); errorMsg.value = "无法获取开机启动状态,请稍后重试。";
errorMsg.value = "无法获取开机启动状态,请稍后重试。"; } finally {
// Keep default isStartOnBoot value (false) isLoading.value = false;
} finally {
isLoading.value = false;
}
});
// --- Watchers for Side Effects ---
watch(isStartOnBoot, async (newValue, oldValue) => {
// Prevent running on initial load if oldValue is the initial default
// or during the initial fetch if needed (though onMounted handles initial state)
if (isLoading.value || newValue === oldValue) return; // Avoid unnecessary calls
errorMsg.value = null; // Clear previous errors
try {
if (newValue) {
await enable();
//window.$message.success('已启用开机启动');
} else {
await disable();
//window.$message.success('已禁用开机启动'); // Provide feedback for disabling too
} }
} catch (err) { });
console.error("Failed to update autostart status:", err);
errorMsg.value = `设置开机启动失败: ${err instanceof Error ? err.message : '未知错误'}`;
// Revert UI state on failure
isStartOnBoot.value = oldValue;
window.$message.error('设置开机启动失败');
}
});
const renderNotifidactionEnable = (name: NotificationType) => h(NCheckbox, {
checked: setting.settings.notificationSettings?.enableTypes.includes(name),
onUpdateChecked: (value) => {
setting.settings.notificationSettings.enableTypes ??= [];
if (value) {
setting.settings.notificationSettings.enableTypes.push(name);
} else {
setting.settings.notificationSettings.enableTypes = setting.settings.notificationSettings.enableTypes.filter(type => type !== name);
}
},
}, () => '启用');
watch(minimizeOnStart, (newValue) => { // --- Watchers for Side Effects ---
// TODO: Implement logic to save/apply minimizeOnStart setting
// Example: saveToConfig('minimizeOnStart', newValue); watch(isStartOnBoot, async (newValue, oldValue) => {
console.log("Minimize on start:", newValue); if (isLoading.value || newValue === oldValue) return;
if (newValue) {
window.$message.info('启动后最小化功能待实现'); // Placeholder feedback errorMsg.value = null;
try {
if (newValue) {
await enable();
} else {
await disable();
}
} catch (err) {
console.error("Failed to update autostart status:", err);
errorMsg.value = `设置开机启动失败: ${err instanceof Error ? err.message : '未知错误'}`;
isStartOnBoot.value = oldValue;
window.$message.error('设置开机启动失败');
} }
}); });
const renderNotifidactionEnable = (name: NotificationType) => h(NCheckbox, {
checked: setting.settings.notificationSettings?.enableTypes.includes(name),
onUpdateChecked: (value) => {
setting.settings.notificationSettings.enableTypes ??= [];
if (value) {
setting.settings.notificationSettings.enableTypes.push(name);
} else {
setting.settings.notificationSettings.enableTypes = setting.settings.notificationSettings.enableTypes.filter(type => type !== name);
}
},
}, () => '启用');
// --- 隐藏功能处理函数 ---
const handleTitleClick = () => {
titleClickCount.value++;
if (resetTimeout !== null) {
clearTimeout(resetTimeout);
}
resetTimeout = setTimeout(() => {
titleClickCount.value = 0;
}, 3000) as unknown as number;
if (titleClickCount.value === 10) {
invoke('open_dev_tools')
.then(() => {
window.$message.success('已打开 Dev Tools');
})
}
};
</script> </script>
<template> <template>
@@ -121,7 +128,10 @@ watch(minimizeOnStart, (newValue) => {
<!-- 标题区域 --> <!-- 标题区域 -->
<div style="max-width: 72rem; margin: 0 auto; padding: 0 1rem;"> <div style="max-width: 72rem; margin: 0 auto; padding: 0 1rem;">
<!-- Added padding --> <!-- Added padding -->
<h1 style="font-size: 1.875rem; font-weight: 600; margin-bottom: 1rem;"> <h1
style="font-size: 1.875rem; font-weight: 600; margin-bottom: 1rem;"
@click="handleTitleClick"
>
<!-- Added margin --> <!-- Added margin -->
设置 设置
</h1> </h1>
@@ -135,7 +145,6 @@ watch(minimizeOnStart, (newValue) => {
> >
<!-- Left Navigation --> <!-- Left Navigation -->
<NGridItem span="6"> <NGridItem span="6">
<!-- Responsive spans -->
<NMenu <NMenu
v-model:value="currentTab" v-model:value="currentTab"
:options="navOptions" :options="navOptions"
@@ -145,13 +154,11 @@ watch(minimizeOnStart, (newValue) => {
<!-- Right Content Area --> <!-- Right Content Area -->
<NGridItem span="18"> <NGridItem span="18">
<!-- Responsive spans -->
<NSpin :show="isLoading"> <NSpin :show="isLoading">
<NSpace <NSpace
vertical vertical
size="large" size="large"
> >
<!-- Global Error Display -->
<NAlert <NAlert
v-if="errorMsg" v-if="errorMsg"
title="操作错误" title="操作错误"
@@ -162,18 +169,13 @@ watch(minimizeOnStart, (newValue) => {
{{ errorMsg }} {{ errorMsg }}
</NAlert> </NAlert>
<!-- Content Transition -->
<Transition <Transition
name="fade" name="fade"
mode="out-in" mode="out-in"
> >
<div :key="currentTab"> <div :key="currentTab">
<!-- Key needed for transition on content change -->
<!-- General Settings -->
<template v-if="currentTab === 'general'"> <template v-if="currentTab === 'general'">
<NSpace <NSpace vertical>
vertical
>
<NCard <NCard
title="启动" title="启动"
:bordered="false" :bordered="false"
@@ -200,7 +202,6 @@ watch(minimizeOnStart, (newValue) => {
v-model:value="setting.settings.bootAsMinimized" v-model:value="setting.settings.bootAsMinimized"
@update:value="setting.save()" @update:value="setting.save()"
/> />
<!-- Add appropriate logic/state for this -->
</LabelItem> </LabelItem>
</NFlex> </NFlex>
</NCard> </NCard>
@@ -233,7 +234,6 @@ watch(minimizeOnStart, (newValue) => {
</NSpace> </NSpace>
</template> </template>
<!-- Notification Settings -->
<template v-else-if="currentTab === 'notification'"> <template v-else-if="currentTab === 'notification'">
<NCard <NCard
title="通知设置" title="通知设置"
@@ -247,7 +247,7 @@ watch(minimizeOnStart, (newValue) => {
<NCheckbox <NCheckbox
v-model:checked="setting.settings.enableNotification" v-model:checked="setting.settings.enableNotification"
@update:checked="(value) => { @update:checked="(value) => {
setting.save() setting.save();
}" }"
> >
启用通知 启用通知
@@ -275,7 +275,6 @@ watch(minimizeOnStart, (newValue) => {
</NCard> </NCard>
</template> </template>
<!-- Other Settings -->
<template v-else-if="currentTab === 'other'"> <template v-else-if="currentTab === 'other'">
<NCard <NCard
title="其他设置" title="其他设置"
@@ -285,7 +284,6 @@ watch(minimizeOnStart, (newValue) => {
</NCard> </NCard>
</template> </template>
<!-- About Section -->
<template v-else-if="currentTab === 'about'"> <template v-else-if="currentTab === 'about'">
<NCard <NCard
title="关于" title="关于"
@@ -294,7 +292,7 @@ watch(minimizeOnStart, (newValue) => {
<template #header-extra> <template #header-extra>
<div <div
style="width: 10px; height: 10px;" style="width: 10px; height: 10px;"
@click="$router.push({name: 'client-test'})" @click="$router.push({ name: 'client-test' })"
/> />
</template> </template>
<p>VTsuruEventFetcher Tauri</p> <p>VTsuruEventFetcher Tauri</p>
@@ -336,7 +334,6 @@ watch(minimizeOnStart, (newValue) => {
<p> <p>
反馈: 🐧 873260337 反馈: 🐧 873260337
</p> </p>
<!-- Add more about info -->
</NCard> </NCard>
</template> </template>
</div> </div>
@@ -352,21 +349,18 @@ watch(minimizeOnStart, (newValue) => {
</template> </template>
<style scoped> <style scoped>
/* Scoped styles if needed, e.g., for the transition */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from, .fade-enter-active,
.fade-leave-to { .fade-leave-active {
opacity: 0; transition: opacity 0.2s ease;
} }
.label-item {
height: 20px; .fade-enter-from,
} .fade-leave-to {
/* Optional: Adjust NFormItem label alignment if needed */ opacity: 0;
/* :deep(.n-form-item-label) { */ }
/* Add custom styles */
/* } */ .label-item {
height: 20px;
}
</style> </style>

View File

@@ -33,6 +33,12 @@ export async function initAll(isOnBoot: boolean) {
if (setting.settings.bootAsMinimized && !isDev) { if (setting.settings.bootAsMinimized && !isDev) {
const appWindow = getCurrentWindow(); const appWindow = getCurrentWindow();
appWindow.hide(); appWindow.hide();
sendNotification({
title: "VTsuru.Client",
body: '已启动并最小化到托盘',
silent: false,
extra: { type: 'question-box' },
});
} }
} }
let permissionGranted = await isPermissionGranted(); let permissionGranted = await isPermissionGranted();
@@ -113,6 +119,16 @@ export async function initAll(isOnBoot: boolean) {
appWindow.setMinSize(new PhysicalSize(720, 480)); appWindow.setMinSize(new PhysicalSize(720, 480));
// 监听f12事件
if (!isDev) {
window.addEventListener('keydown', (event) => {
if (event.key === 'F12') {
event.preventDefault();
event.stopPropagation();
}
});
}
clientInited.value = true; clientInited.value = true;
} }
export function OnClientUnmounted() { export function OnClientUnmounted() {

View File

@@ -14,11 +14,10 @@ export const updateNotes: updateNoteType[] = [
content: [ content: [
['比当前所有 EventFetcher 部署方法都更要简单且支持扫码登录的客户端开始测试力, 支持Windows, Linux, MacOS (后两个没测试过'], ['比当前所有 EventFetcher 部署方法都更要简单且支持扫码登录的客户端开始测试力, 支持Windows, Linux, MacOS (后两个没测试过'],
[ [
'如果对此感兴趣的话可以使用 ', '安装方式: ',
() => h(NButton, { () => h(NButton, {
text: true, tag: 'a', href: FETCH_API + 'https://github.com/Megghy/vtsuru-fetcher-client/releases/download/app-v0.1.0/vtsuru-fetcher-client_0.1.0_x64-setup.exe', target: '_blank', type: 'info' text: true, tag: 'a', href: 'https://www.wolai.com/carN6qvUm3FErze9Xo53ii', target: '_blank', type: 'info'
}, () => '这个链接'), }, () => '查看介绍'),
' 下载Windows客户端, 其他平台请在下面的客户端 Repo 中的 Release 下载',
], ],
[ [
'当前可能存在一些问题, 可以加入秋秋群 873260337 进行反馈, 有功能需求也可以提出' '当前可能存在一些问题, 可以加入秋秋群 873260337 进行反馈, 有功能需求也可以提出'