feat: implement dynamic changelog loading from API
- Add GET /api/changelog endpoint to fetch changelog from CHANGELOG.md - Create service/changelog.go to parse CHANGELOG.md markdown file - Add handler/changelog.go to handle changelog requests - Update ChangelogDrawer component to fetch from API instead of hardcoded data - Export apiFetch from lib/api.ts for public use - Add changelog parser tests with 14 version entries verified
This commit is contained in:
@@ -5,7 +5,7 @@ import type { UIBill } from '$lib/models/bill';
|
||||
// API 配置 - 使用相对路径,由 SvelteKit 代理到后端
|
||||
const API_BASE = '';
|
||||
|
||||
async function apiFetch(input: RequestInfo | URL, init: RequestInit = {}) {
|
||||
export async function apiFetch(input: RequestInfo | URL, init: RequestInit = {}) {
|
||||
const headers = new Headers(init.headers);
|
||||
|
||||
if (browser) {
|
||||
|
||||
@@ -3,77 +3,48 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import Calendar from '@lucide/svelte/icons/calendar';
|
||||
import Tag from '@lucide/svelte/icons/tag';
|
||||
import { onMount } from 'svelte';
|
||||
import { apiFetch } from '$lib/api';
|
||||
|
||||
let { open = $bindable(false) } = $props();
|
||||
|
||||
// Changelog 内容(从 CHANGELOG.md 解析或硬编码)
|
||||
const changelog = [
|
||||
{
|
||||
version: '1.3.1',
|
||||
date: '2026-01-26',
|
||||
changes: {
|
||||
优化: [
|
||||
'版本号显示优化 - 侧边栏版本号按钮样式改进',
|
||||
'移至次级导航区域,与其他菜单项样式一致',
|
||||
'更新日志改用 Sheet 组件(右侧滑出),替代底部 Drawer',
|
||||
'统一暗色主题下的视觉效果'
|
||||
]
|
||||
interface ChangelogEntry {
|
||||
version: string;
|
||||
date: string;
|
||||
changes: Record<string, string[]>;
|
||||
}
|
||||
|
||||
let changelog = $state<ChangelogEntry[]>([]);
|
||||
let isLoading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
// 获取更新日志
|
||||
async function fetchChangelog() {
|
||||
isLoading = true;
|
||||
error = null;
|
||||
try {
|
||||
const response = await apiFetch('/api/changelog');
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
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 接口'
|
||||
]
|
||||
const data = await response.json();
|
||||
if (data.result && Array.isArray(data.data)) {
|
||||
changelog = data.data;
|
||||
} else {
|
||||
throw new Error('Invalid response format');
|
||||
}
|
||||
} catch (err) {
|
||||
error = err instanceof Error ? err.message : 'Failed to fetch changelog';
|
||||
console.error('Failed to fetch changelog:', err);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMount(() => {
|
||||
fetchChangelog();
|
||||
});
|
||||
</script>
|
||||
|
||||
<Sheet.Root bind:open>
|
||||
@@ -85,7 +56,20 @@
|
||||
</Sheet.Description>
|
||||
</Sheet.Header>
|
||||
|
||||
<div class="flex-1 overflow-y-auto py-6">
|
||||
<div class="flex-1 overflow-y-auto py-6">
|
||||
{#if isLoading}
|
||||
<div class="flex items-center justify-center py-8">
|
||||
<div class="text-muted-foreground">加载中...</div>
|
||||
</div>
|
||||
{:else if error}
|
||||
<div class="flex items-center justify-center py-8">
|
||||
<div class="text-destructive text-sm">{error}</div>
|
||||
</div>
|
||||
{:else if changelog.length === 0}
|
||||
<div class="flex items-center justify-center py-8">
|
||||
<div class="text-muted-foreground">暂无更新日志</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="space-y-8">
|
||||
{#each changelog as release}
|
||||
<div class="space-y-3">
|
||||
@@ -120,7 +104,8 @@
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Sheet.Footer class="border-t pt-4">
|
||||
<Button variant="outline" onclick={() => (open = false)} class="w-full">关闭</Button>
|
||||
|
||||
Reference in New Issue
Block a user