mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
Compare commits
2 Commits
364d38ddc0
...
655b92081e
| Author | SHA1 | Date | |
|---|---|---|---|
| 655b92081e | |||
| 6687888c97 |
@@ -4,36 +4,39 @@ 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' },
|
||||||
@@ -45,8 +48,8 @@ const navOptions: MenuOption[] = [ // Explicitly typed
|
|||||||
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 ---
|
||||||
|
|
||||||
@@ -55,11 +58,9 @@ onMounted(async () => {
|
|||||||
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 = "无法获取开机启动状态,请稍后重试。";
|
||||||
// Keep default isStartOnBoot value (false)
|
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
@@ -68,27 +69,23 @@ onMounted(async () => {
|
|||||||
// --- Watchers for Side Effects ---
|
// --- Watchers for Side Effects ---
|
||||||
|
|
||||||
watch(isStartOnBoot, async (newValue, oldValue) => {
|
watch(isStartOnBoot, async (newValue, oldValue) => {
|
||||||
// Prevent running on initial load if oldValue is the initial default
|
if (isLoading.value || newValue === oldValue) return;
|
||||||
// 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
|
errorMsg.value = null;
|
||||||
try {
|
try {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
await enable();
|
await enable();
|
||||||
//window.$message.success('已启用开机启动');
|
|
||||||
} else {
|
} else {
|
||||||
await disable();
|
await disable();
|
||||||
//window.$message.success('已禁用开机启动'); // Provide feedback for disabling too
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to update autostart status:", err);
|
console.error("Failed to update autostart status:", err);
|
||||||
errorMsg.value = `设置开机启动失败: ${err instanceof Error ? err.message : '未知错误'}`;
|
errorMsg.value = `设置开机启动失败: ${err instanceof Error ? err.message : '未知错误'}`;
|
||||||
// Revert UI state on failure
|
|
||||||
isStartOnBoot.value = oldValue;
|
isStartOnBoot.value = oldValue;
|
||||||
window.$message.error('设置开机启动失败');
|
window.$message.error('设置开机启动失败');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderNotifidactionEnable = (name: NotificationType) => h(NCheckbox, {
|
const renderNotifidactionEnable = (name: NotificationType) => h(NCheckbox, {
|
||||||
checked: setting.settings.notificationSettings?.enableTypes.includes(name),
|
checked: setting.settings.notificationSettings?.enableTypes.includes(name),
|
||||||
onUpdateChecked: (value) => {
|
onUpdateChecked: (value) => {
|
||||||
@@ -101,15 +98,25 @@ const renderNotifidactionEnable = (name: NotificationType) => h(NCheckbox, {
|
|||||||
},
|
},
|
||||||
}, () => '启用');
|
}, () => '启用');
|
||||||
|
|
||||||
watch(minimizeOnStart, (newValue) => {
|
// --- 隐藏功能处理函数 ---
|
||||||
// TODO: Implement logic to save/apply minimizeOnStart setting
|
const handleTitleClick = () => {
|
||||||
// Example: saveToConfig('minimizeOnStart', newValue);
|
titleClickCount.value++;
|
||||||
console.log("Minimize on start:", newValue);
|
|
||||||
if (newValue) {
|
|
||||||
window.$message.info('启动后最小化功能待实现'); // Placeholder feedback
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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,21 +234,20 @@ 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="通知设置"
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
>
|
>
|
||||||
<NAlert type="warning">
|
<NAlert type="warning">
|
||||||
暂未完成
|
未完全完成
|
||||||
</NAlert>
|
</NAlert>
|
||||||
<NDivider />
|
<NDivider />
|
||||||
<NSpace vertical>
|
<NSpace vertical>
|
||||||
<NCheckbox
|
<NCheckbox
|
||||||
v-model:checked="setting.settings.enableNotification"
|
v-model:checked="setting.settings.enableNotification"
|
||||||
@update:checked="(value) => {
|
@update:checked="(value) => {
|
||||||
setting.save()
|
setting.save();
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
启用通知
|
启用通知
|
||||||
@@ -262,6 +262,14 @@ watch(minimizeOnStart, (newValue) => {
|
|||||||
<component :is="renderNotifidactionEnable('question-box')" />
|
<component :is="renderNotifidactionEnable('question-box')" />
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
|
<NCard
|
||||||
|
size="small"
|
||||||
|
title="积分兑换通知"
|
||||||
|
>
|
||||||
|
<template #header-extra>
|
||||||
|
<component :is="renderNotifidactionEnable('goods-buy')" />
|
||||||
|
</template>
|
||||||
|
</NCard>
|
||||||
<NCard
|
<NCard
|
||||||
size="small"
|
size="small"
|
||||||
title="弹幕相关"
|
title="弹幕相关"
|
||||||
@@ -275,7 +283,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 +292,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="关于"
|
||||||
@@ -336,7 +342,6 @@ watch(minimizeOnStart, (newValue) => {
|
|||||||
<p>
|
<p>
|
||||||
反馈: 🐧 873260337
|
反馈: 🐧 873260337
|
||||||
</p>
|
</p>
|
||||||
<!-- Add more about info -->
|
|
||||||
</NCard>
|
</NCard>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -352,7 +357,7 @@ watch(minimizeOnStart, (newValue) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* Scoped styles if needed, e.g., for the transition */
|
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
@@ -362,11 +367,8 @@ watch(minimizeOnStart, (newValue) => {
|
|||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-item {
|
.label-item {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
/* Optional: Adjust NFormItem label alignment if needed */
|
|
||||||
/* :deep(.n-form-item-label) { */
|
|
||||||
/* Add custom styles */
|
|
||||||
/* } */
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { isPermissionGranted, onAction, sendNotification } from '@tauri-apps/plugin-notification';
|
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() {
|
async function testNotification() {
|
||||||
let permissionGranted = await isPermissionGranted();
|
onReceivedQuestion({
|
||||||
if (permissionGranted) {
|
id: 1,
|
||||||
sendNotification({
|
question: {
|
||||||
title: "测试通知",
|
message: '这是一条测试问题',
|
||||||
body: "这是一个测试通知",
|
},
|
||||||
silent: false,
|
tag: '测试标签',
|
||||||
extra: { type: 'test' },
|
sender: { name: '测试用户', id: 1, isBiliAuthed: false },
|
||||||
});
|
isPublic: true,
|
||||||
onAction((event) => {
|
} as QAInfo);
|
||||||
console.log('Notification clicked:', event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -26,6 +28,12 @@ async function testNotification() {
|
|||||||
>
|
>
|
||||||
测试通知
|
测试通知
|
||||||
</NButton>
|
</NButton>
|
||||||
|
<LabelItem label="关闭弹幕客户端">
|
||||||
|
<NSwitch
|
||||||
|
v-model:value="setting.settings.dev_disableDanmakuClient"
|
||||||
|
@update:value="setting.save()"
|
||||||
|
/>
|
||||||
|
</LabelItem>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -29,14 +29,9 @@ export async function initAll(isOnBoot: boolean) {
|
|||||||
if (clientInited.value) {
|
if (clientInited.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isOnBoot) {
|
|
||||||
if (setting.settings.bootAsMinimized && !isDev) {
|
|
||||||
const appWindow = getCurrentWindow();
|
|
||||||
appWindow.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let permissionGranted = await isPermissionGranted();
|
|
||||||
checkUpdate();
|
checkUpdate();
|
||||||
|
const appWindow = getCurrentWindow();
|
||||||
|
let permissionGranted = await isPermissionGranted();
|
||||||
|
|
||||||
// If not we need to request it
|
// If not we need to request it
|
||||||
if (!permissionGranted) {
|
if (!permissionGranted) {
|
||||||
@@ -45,7 +40,16 @@ export async function initAll(isOnBoot: boolean) {
|
|||||||
if (permissionGranted) {
|
if (permissionGranted) {
|
||||||
info('Notification permission granted');
|
info('Notification permission granted');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOnBoot) {
|
||||||
|
if (setting.settings.bootAsMinimized && !isDev && await appWindow.isVisible()) {
|
||||||
|
appWindow.hide();
|
||||||
|
sendNotification({
|
||||||
|
title: "VTsuru.Client",
|
||||||
|
body: '已启动并最小化到托盘'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
initNotificationHandler();
|
initNotificationHandler();
|
||||||
const detach = await attachConsole();
|
const detach = await attachConsole();
|
||||||
@@ -58,7 +62,7 @@ export async function initAll(isOnBoot: boolean) {
|
|||||||
initInfo();
|
initInfo();
|
||||||
info('[init] 开始更新数据');
|
info('[init] 开始更新数据');
|
||||||
|
|
||||||
if (isLoggedIn && accountInfo.value.isBiliVerified) {
|
if (isLoggedIn && accountInfo.value.isBiliVerified && !setting.settings.dev_disableDanmakuClient) {
|
||||||
const danmakuInitNoticeRef = window.$notification.info({
|
const danmakuInitNoticeRef = window.$notification.info({
|
||||||
title: '正在初始化弹幕客户端...',
|
title: '正在初始化弹幕客户端...',
|
||||||
closable: false
|
closable: false
|
||||||
@@ -90,7 +94,6 @@ export async function initAll(isOnBoot: boolean) {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
const iconData = await (await fetch('https://oss.suki.club/vtsuru/icon.ico')).arrayBuffer();
|
const iconData = await (await fetch('https://oss.suki.club/vtsuru/icon.ico')).arrayBuffer();
|
||||||
const appWindow = getCurrentWindow();
|
|
||||||
const options: TrayIconOptions = {
|
const options: TrayIconOptions = {
|
||||||
// here you can add a tray menu, title, tooltip, event handler, etc
|
// here you can add a tray menu, title, tooltip, event handler, etc
|
||||||
menu: menu,
|
menu: menu,
|
||||||
@@ -113,6 +116,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() {
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
import { QAInfo } from "@/api/api-models";
|
import { QAInfo, ResponsePointGoodModel, ResponsePointOrder2OwnerModel } from "@/api/api-models";
|
||||||
import { useSettings } from "../store/useSettings";
|
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 { openUrl } from "@tauri-apps/plugin-opener";
|
||||||
import { CN_HOST } from "@/data/constants";
|
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) {
|
switch (type) {
|
||||||
case 'question-box':
|
case 'question-box':
|
||||||
|
|
||||||
onReceivedQuestion(data);
|
onReceivedQuestion(data);
|
||||||
break;
|
break;
|
||||||
|
case 'goods-buy':
|
||||||
|
onGoodsBuy(data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Unhandled notification type: ${type}`);
|
console.warn(`Unhandled notification type: ${type}`);
|
||||||
}
|
}
|
||||||
@@ -20,20 +32,57 @@ export async function onReceivedQuestion(question: QAInfo) {
|
|||||||
const setting = useSettings();
|
const setting = useSettings();
|
||||||
if (setting.settings.notificationSettings.enableTypes.includes("question-box")) {
|
if (setting.settings.notificationSettings.enableTypes.includes("question-box")) {
|
||||||
window.$notification.info({
|
window.$notification.info({
|
||||||
title: "收到提问",
|
title: "提问箱",
|
||||||
description: '收到来自 [' + question.sender.name || '匿名用户' + '] 的提问',
|
description: '收到来自 [' + (question.sender.name || '匿名用户') + '] 的提问',
|
||||||
duration: 5,
|
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 }),
|
||||||
});
|
});
|
||||||
let permissionGranted = await isPermissionGranted();
|
}
|
||||||
if (permissionGranted) {
|
}, () => '快速查看'),
|
||||||
sendNotification({
|
h(NButton, {
|
||||||
title: "收到提问",
|
text: true, type: 'primary', onClick: () => {
|
||||||
body: '来自 [' + question.sender.name || '匿名用户' + '] 的提问',
|
openUrl(`${CN_HOST}manage/question-box`);
|
||||||
silent: false,
|
}
|
||||||
|
}, () => '查看详情'),
|
||||||
|
])
|
||||||
|
});
|
||||||
|
trySendNotification({
|
||||||
|
title: "提问箱",
|
||||||
|
body: '收到来自 [' + (question.sender.name || '匿名用户') + '] 的提问',
|
||||||
extra: { type: 'question-box' },
|
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' },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useTauriStore } from './useTauriStore';
|
import { useTauriStore } from './useTauriStore';
|
||||||
|
|
||||||
export type NotificationType = 'question-box' | 'danmaku';
|
export type NotificationType = 'question-box' | 'danmaku' | 'goods-buy';
|
||||||
export type NotificationSettings = {
|
export type NotificationSettings = {
|
||||||
enableTypes: NotificationType[];
|
enableTypes: NotificationType[];
|
||||||
};
|
};
|
||||||
@@ -14,6 +14,8 @@ export type VTsuruClientSettings = {
|
|||||||
|
|
||||||
enableNotification: boolean;
|
enableNotification: boolean;
|
||||||
notificationSettings: NotificationSettings;
|
notificationSettings: NotificationSettings;
|
||||||
|
|
||||||
|
dev_disableDanmakuClient: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSettings = defineStore('settings', () => {
|
export const useSettings = defineStore('settings', () => {
|
||||||
@@ -29,6 +31,8 @@ export const useSettings = defineStore('settings', () => {
|
|||||||
notificationSettings: {
|
notificationSettings: {
|
||||||
enableTypes: ['question-box', 'danmaku'],
|
enableTypes: ['question-box', 'danmaku'],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
dev_disableDanmakuClient: false,
|
||||||
};
|
};
|
||||||
const settings = ref<VTsuruClientSettings>(Object.assign({}, defaultSettings));
|
const settings = ref<VTsuruClientSettings>(Object.assign({}, defaultSettings));
|
||||||
|
|
||||||
|
|||||||
@@ -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 进行反馈, 有功能需求也可以提出'
|
||||||
|
|||||||
Reference in New Issue
Block a user