feat: 在 web 页面显示版本号和更新日志
This commit is contained in:
120
web/src/lib/components/ChangelogDrawer.svelte
Normal file
120
web/src/lib/components/ChangelogDrawer.svelte
Normal file
@@ -0,0 +1,120 @@
|
||||
<script lang="ts">
|
||||
import * as Drawer from '$lib/components/ui/drawer';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import X from '@lucide/svelte/icons/x';
|
||||
import Calendar from '@lucide/svelte/icons/calendar';
|
||||
import Tag from '@lucide/svelte/icons/tag';
|
||||
|
||||
let { open = $bindable(false) } = $props();
|
||||
|
||||
// Changelog 内容(从 CHANGELOG.md 解析或硬编码)
|
||||
const changelog = [
|
||||
{
|
||||
version: '1.3.0',
|
||||
date: '2026-01-26',
|
||||
changes: {
|
||||
新增: [
|
||||
'京东账单支持 - 支持京东白条账单上传和清洗',
|
||||
'自动识别京东账单类型(交易流水 ZIP)',
|
||||
'解析京东白条账单 CSV 格式(含还款日期信息)',
|
||||
'京东专属分类映射配置',
|
||||
'支持京东外卖、京东平台商户等商户识别',
|
||||
'上传页面和账单列表页面添加"京东"选项'
|
||||
],
|
||||
优化: [
|
||||
'京东订单智能去重 - 上传京东账单时自动软删除其他来源中的京东订单',
|
||||
'分类推断复核等级优化 - 京东账单引入 LOW 复核等级',
|
||||
'京东平台商户关键词扩展'
|
||||
],
|
||||
技术改进: [
|
||||
'新增京东账单清理器',
|
||||
'新增京东专属配置',
|
||||
'后端新增软删除接口',
|
||||
'新增单元测试(11 个测试用例)'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
version: '1.2.1',
|
||||
date: '2026-01-23',
|
||||
changes: {
|
||||
优化: [
|
||||
'智能复核快捷确认 - 在复核列表每行添加快捷确认按钮',
|
||||
'无需打开详情页面即可确认分类正确',
|
||||
'自动更新统计数据',
|
||||
'提升复核效率,支持快速批量确认'
|
||||
],
|
||||
文档: ['AGENTS.md 更新 - 精简为 150 行,专为 AI 编程助手设计']
|
||||
}
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
date: '2026-01-25',
|
||||
changes: {
|
||||
新增: [
|
||||
'账单删除功能 - 支持在账单详情抽屉中删除账单(软删除)',
|
||||
'删除按钮带二次确认,防止误操作',
|
||||
'已删除的账单在所有查询中自动过滤'
|
||||
],
|
||||
技术改进: [
|
||||
'后端 MongoDB 查询方法添加软删除过滤',
|
||||
'新增 DELETE /api/bills/:id 接口'
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<Drawer.Root bind:open>
|
||||
<Drawer.Content class="max-h-[90vh]">
|
||||
<Drawer.Header class="border-b">
|
||||
<div class="flex items-center justify-between">
|
||||
<Drawer.Title class="text-xl font-semibold">版本更新日志</Drawer.Title>
|
||||
<Button variant="ghost" size="icon" onclick={() => (open = false)}>
|
||||
<X class="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</Drawer.Header>
|
||||
|
||||
<div class="h-[calc(90vh-8rem)] overflow-y-auto p-6">
|
||||
<div class="space-y-8">
|
||||
{#each changelog as release}
|
||||
<div class="space-y-3">
|
||||
<!-- 版本号和日期 -->
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<Tag class="size-5 text-primary" />
|
||||
<h3 class="text-lg font-semibold">v{release.version}</h3>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 text-sm text-muted-foreground">
|
||||
<Calendar class="size-4" />
|
||||
<span>{release.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 变更内容 -->
|
||||
<div class="space-y-4 pl-7 border-l-2 border-muted">
|
||||
{#each Object.entries(release.changes) as [category, items]}
|
||||
<div class="space-y-2">
|
||||
<h4 class="text-sm font-semibold text-primary">{category}</h4>
|
||||
<ul class="space-y-1.5 text-sm text-muted-foreground">
|
||||
{#each items as item}
|
||||
<li class="flex gap-2 leading-relaxed">
|
||||
<span class="text-primary mt-1.5">•</span>
|
||||
<span>{item}</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Drawer.Footer class="border-t">
|
||||
<Button variant="outline" onclick={() => (open = false)} class="w-full">关闭</Button>
|
||||
</Drawer.Footer>
|
||||
</Drawer.Content>
|
||||
</Drawer.Root>
|
||||
@@ -10,6 +10,7 @@
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import * as Avatar from '$lib/components/ui/avatar';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import ChangelogDrawer from '$lib/components/ChangelogDrawer.svelte';
|
||||
|
||||
// Icons
|
||||
import Upload from '@lucide/svelte/icons/upload';
|
||||
@@ -24,6 +25,10 @@
|
||||
import User from '@lucide/svelte/icons/user';
|
||||
import Bell from '@lucide/svelte/icons/bell';
|
||||
import Sparkles from '@lucide/svelte/icons/sparkles';
|
||||
import Info from '@lucide/svelte/icons/info';
|
||||
|
||||
// 从 package.json 导入版本号
|
||||
import pkg from '../../package.json';
|
||||
|
||||
// Theme
|
||||
import {
|
||||
@@ -42,6 +47,7 @@
|
||||
let checkingHealth = $state(true);
|
||||
let isAuthenticated = $state(false);
|
||||
let currentUser = $state<AuthUser | null>(null);
|
||||
let changelogOpen = $state(false);
|
||||
|
||||
// 订阅认证状态
|
||||
$effect(() => {
|
||||
@@ -228,9 +234,27 @@
|
||||
</Sidebar.Group>
|
||||
</Sidebar.Content>
|
||||
|
||||
<!-- Footer: 用户信息 -->
|
||||
<!-- Footer: 用户信息 + 版本号 -->
|
||||
<Sidebar.Footer>
|
||||
<Sidebar.Menu>
|
||||
<!-- 版本号 -->
|
||||
<Sidebar.MenuItem>
|
||||
<Sidebar.MenuButton>
|
||||
{#snippet child({ props })}
|
||||
<button
|
||||
{...props}
|
||||
onclick={() => changelogOpen = true}
|
||||
class="w-full"
|
||||
title="查看更新日志"
|
||||
>
|
||||
<Info class="size-4" />
|
||||
<span class="text-xs">v{pkg.version}</span>
|
||||
</button>
|
||||
{/snippet}
|
||||
</Sidebar.MenuButton>
|
||||
</Sidebar.MenuItem>
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<Sidebar.MenuItem>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
@@ -344,4 +368,7 @@
|
||||
</main>
|
||||
</Sidebar.Inset>
|
||||
</Sidebar.Provider>
|
||||
|
||||
<!-- Changelog 抽屉 -->
|
||||
<ChangelogDrawer bind:open={changelogOpen} />
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user