feat: 添加更新日志功能;优化组件和状态管理;修复部分逻辑错误

This commit is contained in:
2025-04-08 16:11:00 +08:00
parent 0195e7b01a
commit 364d38ddc0
19 changed files with 536 additions and 312 deletions

View File

@@ -992,7 +992,7 @@
<NIcon :component="BarChartOutline" /> {{ webfetcher.sessionEventCount?.toLocaleString() ?? 0 }}
</NStatistic>
<NStatistic label="已发送">
{{ ((webfetcher.bytesSentSession ?? 0) / 1024).toFixed(2) }} KB <!-- Assuming exposed -->
{{ ((webfetcher.bytesSentSession ?? 0) / 1024 / 1024).toFixed(2) }} Mb <!-- Assuming exposed -->
</NStatistic>
</NFlex>
</NCard>

View File

@@ -10,6 +10,10 @@
const webfetcher = useWebFetcher();
const coverRef = ref();
const isHover = ref(false);
const roomCover = computed(() => {
return isHover.value ? roomInfo.value?.keyframe : roomInfo.value?.user_cover;
});
const { width, height } = useElementSize(coverRef);
function logout() {
@@ -90,8 +94,8 @@
<template #header>
<NSpace align="center">
直播状态
<NTag :type="!accountInfo.streamerInfo?.isStreaming ? 'error' : 'success'">
{{ !accountInfo.streamerInfo?.isStreaming ? '直播' : '直播' }}
<NTag :type="roomInfo?.live_status === 1 ? 'success' : 'error'">
{{ roomInfo?.live_status === 1 ? '直播' : '直播' }}
</NTag>
</NSpace>
<NText
@@ -102,13 +106,13 @@
</NText>
</template>
<div
v-if="roomInfo?.user_cover"
v-if="roomCover"
style="position: relative"
>
<div style="position: relative; width: 100%; max-width: 500px;">
<NImage
ref="coverRef"
:src="roomInfo?.user_cover"
:src="roomCover"
style="width: 100%; opacity: 0.5; border-radius: 8px;"
referrerpolicy="no-referrer"
:img-props="{ referrerpolicy: 'no-referrer', style: { width: '100%' } }"
@@ -118,6 +122,8 @@
style="position: absolute; z-index: 1; top: 0; width: 100%; background: linear-gradient(to top, rgba(0,0,0,0.8), rgba(0,0,0,0.2), transparent)"
:style="{ height: `${height}px`, maxWidth: '500px', cursor: 'pointer' }"
@click="openUrl(`https://live.bilibili.com/${accountInfo.biliRoomId}`)"
@mouseenter="isHover = true"
@mouseleave="isHover = false"
/>
<NText style="position: absolute; bottom: 12px; left: 16px; z-index: 2; color: white; font-size: 18px">
{{ roomInfo?.title }}

View File

@@ -117,169 +117,160 @@ import { isTauri } from '@/data/constants';
</script>
<template>
<NAlert
v-if="!isTauri"
type="error"
title="错误"
<WindowBar />
<div
v-if="!isLoggedIn"
class="login-container"
>
此应用在 Tauri 环境外运行无法使用
</NAlert>
<template v-else>
<WindowBar />
<div
v-if="!isLoggedIn"
class="login-container"
<NCard
v-if="!isLoadingAccount"
:bordered="false"
size="large"
class="login-card"
>
<NCard
v-if="!isLoadingAccount"
:bordered="false"
size="large"
class="login-card"
>
<template #header>
<div class="login-header">
<div class="login-title">
登陆
</div>
<div class="login-subtitle">
输入你的 VTsuru Token
</div>
</div>
</template>
<NSpace
vertical
size="large"
>
<NSpace vertical>
<div class="token-label-container">
<span class="token-label">Token</span>
<NTooltip placement="top">
<template #trigger>
<NA
class="token-get-link"
@click="openUrl('https://vtsuru.suki.club/manage')"
>
前往获取
</NA>
</template>
登录后在管理面板主页的个人信息下方
</NTooltip>
</div>
<NInput
v-model:value="token"
type="password"
show-password-on="click"
placeholder="请输入Token"
@keyup.enter="login"
/>
</NSpace>
<NButton
block
type="primary"
:loading="isLoadingAccount"
:disabled="isLoadingAccount"
@click="login"
>
<template #header>
<div class="login-header">
<div class="login-title">
登陆
</NButton>
</NSpace>
</NCard>
</div>
<div class="login-subtitle">
输入你的 VTsuru Token
</div>
</div>
</template>
<NSpin
v-else
<NSpace
vertical
size="large"
/>
</div>
<NLayout
v-else
has-sider
class="main-layout"
@vue:mounted="initAll(true)"
>
<NLayoutSider
width="200"
bordered
class="main-layout-sider"
>
<div class="sider-content">
<div class="sider-header">
<NText
tag="div"
class="app-title"
>
<span>VTsuru.Client</span>
</NText>
<NTooltip trigger="hover">
<NSpace vertical>
<div class="token-label-container">
<span class="token-label">Token</span>
<NTooltip placement="top">
<template #trigger>
<NButton
quaternary
class="fetcher-status-button"
:type="webfetcher.state === 'connected' ? 'success' : 'error'"
<NA
class="token-get-link"
@click="openUrl('https://vtsuru.suki.club/manage')"
>
<CheckmarkCircle
v-if="webfetcher.state === 'connected'"
class="fetcher-status-icon connected"
/>
<CloseCircle
v-else
class="fetcher-status-icon disconnected"
/>
</NButton>
前往获取
</NA>
</template>
<div>
<div>EventFetcher 状态</div>
<div v-if="webfetcher.state === 'connected'">
运行中
</div>
<div v-else>
未运行 / 连接断开
</div>
</div>
登录后在管理面板主页的个人信息下方
</NTooltip>
</div>
<NMenu
:options="menuOptions"
:default-value="'go-back-home'"
class="sider-menu"
<NInput
v-model:value="token"
type="password"
show-password-on="click"
placeholder="请输入Token"
@keyup.enter="login"
/>
</div>
</NLayoutSider>
</NSpace>
<NLayoutContent
class="main-layout-content"
:native-scrollbar="false"
:scrollbar-props="{
trigger: 'none'
}"
>
<div style="padding: 12px; padding-right: 15px;">
<RouterView v-slot="{ Component }">
<Transition
name="fade-slide"
mode="out-in"
:appear="true"
>
<KeepAlive>
<Suspense>
<component :is="Component" />
<template #fallback>
<div class="suspense-fallback">
加载中...
</div>
</template>
</Suspense>
</KeepAlive>
</Transition>
</RouterView>
<NButton
block
type="primary"
:loading="isLoadingAccount"
:disabled="isLoadingAccount"
@click="login"
>
登陆
</NButton>
</NSpace>
</NCard>
<NSpin
v-else
size="large"
/>
</div>
<NLayout
v-else
has-sider
class="main-layout"
@vue:mounted="initAll(true)"
>
<NLayoutSider
width="200"
bordered
class="main-layout-sider"
>
<div class="sider-content">
<div class="sider-header">
<NText
tag="div"
class="app-title"
>
<span>VTsuru.Client</span>
</NText>
<NTooltip trigger="hover">
<template #trigger>
<NButton
quaternary
class="fetcher-status-button"
:type="webfetcher.state === 'connected' ? 'success' : 'error'"
>
<CheckmarkCircle
v-if="webfetcher.state === 'connected'"
class="fetcher-status-icon connected"
/>
<CloseCircle
v-else
class="fetcher-status-icon disconnected"
/>
</NButton>
</template>
<div>
<div>EventFetcher 状态</div>
<div v-if="webfetcher.state === 'connected'">
运行中
</div>
<div v-else>
未运行 / 连接断开
</div>
</div>
</NTooltip>
</div>
</NLayoutContent>
</NLayout>
</template>
<NMenu
:options="menuOptions"
:default-value="'go-back-home'"
class="sider-menu"
/>
</div>
</NLayoutSider>
<NLayoutContent
class="main-layout-content"
:native-scrollbar="false"
:scrollbar-props="{
trigger: 'none'
}"
>
<div style="padding: 12px; padding-right: 15px;">
<RouterView v-slot="{ Component }">
<Transition
name="fade-slide"
mode="out-in"
:appear="true"
>
<KeepAlive>
<Suspense>
<component :is="Component" />
<template #fallback>
<div class="suspense-fallback">
加载中...
</div>
</template>
</Suspense>
</KeepAlive>
</Transition>
</RouterView>
</div>
</NLayoutContent>
</NLayout>
</template>
<style scoped>

View File

@@ -333,6 +333,9 @@ watch(minimizeOnStart, (newValue) => {
Tauri 客户端
</NButton>
</p>
<p>
反馈: 🐧 873260337
</p>
<!-- Add more about info -->
</NCard>
</template>

View File

@@ -4,6 +4,7 @@ import { info, error } from '@tauri-apps/plugin-log';
import { QueryBiliAPI } from './utils'; // 假设 Bili API 工具路径
import { BiliRoomInfo, BiliStreamingInfo, FetcherStatisticData } from './models'; // 假设模型路径
import { useTauriStore } from '../store/useTauriStore';
import { useAccount } from '@/api/account';
// import { useAccount } from '@/api/account'; // 如果需要账户信息
// const accountInfo = useAccount(); // 如果需要
@@ -185,10 +186,8 @@ export async function getHistoricalStatistics(days: number = 7): Promise<Fetcher
* 更新房间和直播流信息
*/
async function updateRoomAndStreamingInfo() {
// 需要一个房间ID来查询这个ID可能来自设置、登录信息或固定配置
// const roomId = accountInfo.value?.roomid ?? settings.value.roomId; // 示例获取房间ID
const roomId = 21484828; // !!! 示例这里需要替换成实际获取房间ID的逻辑 !!!
if (!roomId) {
const account = useAccount();
if (!account.value.biliRoomId) {
// error("无法获取房间ID以更新直播信息");
return;
}
@@ -196,7 +195,7 @@ async function updateRoomAndStreamingInfo() {
try {
// 查询房间基本信息
const roomRes = await QueryBiliAPI(
`https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${roomId}`
`https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${account.value.biliRoomId}`
);
const json = await roomRes.json();
if (json.code === 0) {

View File

@@ -4,6 +4,18 @@ import { isPermissionGranted, onAction, sendNotification } from "@tauri-apps/plu
import { openUrl } from "@tauri-apps/plugin-opener";
import { CN_HOST } from "@/data/constants";
export function onReceivedNotification(type: string, data: any) {
switch (type) {
case 'question-box':
onReceivedQuestion(data);
break;
default:
console.warn(`Unhandled notification type: ${type}`);
}
}
export async function onReceivedQuestion(question: QAInfo) {
const setting = useSettings();
if (setting.settings.notificationSettings.enableTypes.includes("question-box")) {
@@ -20,7 +32,7 @@ export async function onReceivedQuestion(question: QAInfo) {
silent: false,
extra: { type: 'question-box' },
});
}
}