diff --git a/src/client/ClientSettings.vue b/src/client/ClientSettings.vue index 367b80c..3014c81 100644 --- a/src/client/ClientSettings.vue +++ b/src/client/ClientSettings.vue @@ -240,7 +240,7 @@ import { invoke } from '@tauri-apps/api/core'; :bordered="false" > - 暂未完成 + 未完全完成 @@ -262,6 +262,14 @@ import { invoke } from '@tauri-apps/api/core'; + + + import { isPermissionGranted, onAction, sendNotification } from '@tauri-apps/plugin-notification'; + import { NSwitch } from 'naive-ui'; +import { useSettings } from './store/useSettings'; +import { onReceivedQuestion } from './data/notification'; +import { QAInfo } from '@/api/api-models'; + const setting = useSettings() async function testNotification() { - let permissionGranted = await isPermissionGranted(); - if (permissionGranted) { - sendNotification({ - title: "测试通知", - body: "这是一个测试通知", - silent: false, - extra: { type: 'test' }, - }); - onAction((event) => { - console.log('Notification clicked:', event); - }); - } + onReceivedQuestion({ + id: 1, + question: { + message: '这是一条测试问题', + }, + tag: '测试标签', + sender: { name: '测试用户', id: 1, isBiliAuthed: false }, + isPublic: true, + } as QAInfo); } @@ -26,6 +28,12 @@ async function testNotification() { > 测试通知 + + + \ No newline at end of file diff --git a/src/client/data/initialize.ts b/src/client/data/initialize.ts index b43ecd1..2f44092 100644 --- a/src/client/data/initialize.ts +++ b/src/client/data/initialize.ts @@ -29,20 +29,9 @@ export async function initAll(isOnBoot: boolean) { if (clientInited.value) { return; } - if (isOnBoot) { - if (setting.settings.bootAsMinimized && !isDev) { - const appWindow = getCurrentWindow(); - appWindow.hide(); - sendNotification({ - title: "VTsuru.Client", - body: '已启动并最小化到托盘', - silent: false, - extra: { type: 'question-box' }, - }); - } - } - let permissionGranted = await isPermissionGranted(); checkUpdate(); + const appWindow = getCurrentWindow(); + let permissionGranted = await isPermissionGranted(); // If not we need to request it if (!permissionGranted) { @@ -51,7 +40,16 @@ export async function initAll(isOnBoot: boolean) { if (permissionGranted) { info('Notification permission granted'); } + } + if (isOnBoot) { + if (setting.settings.bootAsMinimized && !isDev && await appWindow.isVisible()) { + appWindow.hide(); + sendNotification({ + title: "VTsuru.Client", + body: '已启动并最小化到托盘' + }); + } } initNotificationHandler(); const detach = await attachConsole(); @@ -64,7 +62,7 @@ export async function initAll(isOnBoot: boolean) { initInfo(); info('[init] 开始更新数据'); - if (isLoggedIn && accountInfo.value.isBiliVerified) { + if (isLoggedIn && accountInfo.value.isBiliVerified && !setting.settings.dev_disableDanmakuClient) { const danmakuInitNoticeRef = window.$notification.info({ title: '正在初始化弹幕客户端...', closable: false @@ -96,7 +94,6 @@ export async function initAll(isOnBoot: boolean) { ], }); const iconData = await (await fetch('https://oss.suki.club/vtsuru/icon.ico')).arrayBuffer(); - const appWindow = getCurrentWindow(); const options: TrayIconOptions = { // here you can add a tray menu, title, tooltip, event handler, etc menu: menu, diff --git a/src/client/data/notification.ts b/src/client/data/notification.ts index 5e54ae6..3a5b909 100644 --- a/src/client/data/notification.ts +++ b/src/client/data/notification.ts @@ -1,16 +1,28 @@ -import { QAInfo } from "@/api/api-models"; +import { QAInfo, ResponsePointGoodModel, ResponsePointOrder2OwnerModel } from "@/api/api-models"; import { useSettings } from "../store/useSettings"; -import { isPermissionGranted, onAction, sendNotification } from "@tauri-apps/plugin-notification"; +import { isPermissionGranted, onAction, Options, sendNotification } from "@tauri-apps/plugin-notification"; import { openUrl } from "@tauri-apps/plugin-opener"; import { CN_HOST } from "@/data/constants"; +import { NButton, NFlex } from "naive-ui"; +import QuestionItem from "@/components/QuestionItem.vue"; -export function onReceivedNotification(type: string, data: any) { +export async function trySendNotification(option: Options) { + let permissionGranted = await isPermissionGranted(); + if (permissionGranted) { + sendNotification(option); + } +} + +export function onReceivedNotification(type: string, json: string) { + console.log(`接收到通知: ${type}`, json); + const data = JSON.parse(json); switch (type) { case 'question-box': - onReceivedQuestion(data); break; - + case 'goods-buy': + onGoodsBuy(data); + break; default: console.warn(`Unhandled notification type: ${type}`); } @@ -20,20 +32,57 @@ export async function onReceivedQuestion(question: QAInfo) { const setting = useSettings(); if (setting.settings.notificationSettings.enableTypes.includes("question-box")) { window.$notification.info({ - title: "收到提问", - description: '收到来自 [' + question.sender.name || '匿名用户' + '] 的提问', - duration: 5, + title: "提问箱", + description: '收到来自 [' + (question.sender.name || '匿名用户') + '] 的提问', + duration: 0, + action: () => h(NFlex, {}, () => [ + h(NButton, { + text: true, type: 'info', onClick: () => { + window.$modal.create({ + title: '快速查看', + preset: 'card', + style: { maxWidth: '80vw' }, + content: () => h(QuestionItem, { item: question }), + }); + } + }, () => '快速查看'), + h(NButton, { + text: true, type: 'primary', onClick: () => { + openUrl(`${CN_HOST}manage/question-box`); + } + }, () => '查看详情'), + ]) + }); + trySendNotification({ + title: "提问箱", + body: '收到来自 [' + (question.sender.name || '匿名用户') + '] 的提问', + extra: { type: 'question-box' }, }); - let permissionGranted = await isPermissionGranted(); - if (permissionGranted) { - sendNotification({ - title: "收到提问", - body: '来自 [' + question.sender.name || '匿名用户' + '] 的提问', - silent: false, - extra: { type: 'question-box' }, - }); - - } } +} +export function onGoodsBuy(info: { + data: ResponsePointOrder2OwnerModel, + goods: ResponsePointGoodModel +}) { + const setting = useSettings(); + const order = info.data; + const goods = info.goods; + if (setting.settings.notificationSettings.enableTypes.includes("goods-buy")) { + window.$notification.info({ + title: "礼物兑换", + description: `${order.customer.name} 兑换了你的 [${goods.name}],数量: ${order.count},总价: ${order.point} 元`, + duration: 0, + action: () => h(NButton, { + text: true, type: 'primary', onClick: () => { + openUrl(`${CN_HOST}manage/goods-buy`); + } + }, () => '查看详情'), + }); + trySendNotification({ + title: "礼物兑换", + body: `${order.customer.name} 兑换了你的 [${goods.name}],数量: ${order.count},总价: ${order.point} 元`, + extra: { type: 'goods-buy' }, + }); + } } \ No newline at end of file diff --git a/src/client/store/useSettings.ts b/src/client/store/useSettings.ts index 3a0065d..26a5c7d 100644 --- a/src/client/store/useSettings.ts +++ b/src/client/store/useSettings.ts @@ -1,6 +1,6 @@ import { useTauriStore } from './useTauriStore'; -export type NotificationType = 'question-box' | 'danmaku'; +export type NotificationType = 'question-box' | 'danmaku' | 'goods-buy'; export type NotificationSettings = { enableTypes: NotificationType[]; }; @@ -14,6 +14,8 @@ export type VTsuruClientSettings = { enableNotification: boolean; notificationSettings: NotificationSettings; + + dev_disableDanmakuClient: boolean; }; export const useSettings = defineStore('settings', () => { @@ -29,6 +31,8 @@ export const useSettings = defineStore('settings', () => { notificationSettings: { enableTypes: ['question-box', 'danmaku'], }, + + dev_disableDanmakuClient: false, }; const settings = ref(Object.assign({}, defaultSettings));