import { useEffect, useRef, useState } from "react"; import { RotateCcw, Trash2 } from "lucide-react"; import { Button, Dialog, Space, Table } from "tdesign-react"; import { api } from "../../services/api"; import AccessibleInput from "../../components/AccessibleInput"; import type { Notify } from "../expenses/types"; import type { Expense } from "../expenses/types"; import { dateText, money } from "../expenses/date"; import { AsyncState, BusyIcon, ErrorBanner, Page, StatusTag } from "../common"; export default function TrashPage({ timezone = "Asia/Shanghai", notify }: { timezone?: string; notify?: Notify }) { const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [busy, setBusy] = useState(false); const [purgeTarget, setPurgeTarget] = useState(null); const [password, setPassword] = useState(""); const [purgeError, setPurgeError] = useState(""); const loadSequence = useRef(0); const load = async () => { const sequence = ++loadSequence.current; setLoading(true); setError(""); try { const result = await api<{ items: Expense[] }>("/api/trash"); if (sequence === loadSequence.current) setItems(result.items); } catch (e) { if (sequence === loadSequence.current) setError((e as Error).message); } finally { if (sequence === loadSequence.current) setLoading(false); } }; useEffect(() => { void load(); }, []); const restore = async (item: Expense) => { setBusy(true); setError(""); try { await api(`/api/trash/${item.id}/restore`, { method: "POST", body: JSON.stringify({ version: item.version }) }); notify?.("账目已恢复", "success"); await load(); } catch (e) { setError((e as Error).message); } finally { setBusy(false); } }; const purge = async () => { if (!purgeTarget || !password) { setPurgeError("请输入当前管理员密码"); return; } setBusy(true); setPurgeError(""); try { await api(`/api/trash/${purgeTarget.id}`, { method: "DELETE", body: JSON.stringify({ version: purgeTarget.version, password }) }); setPurgeTarget(null); setPassword(""); notify?.("账目已永久删除,审计历史仍保留", "success"); await load(); } catch (e) { setPurgeError((e as Error).message); } finally { setBusy(false); } }; const columns = [ { colKey: "deletedAt", title: "删除时间", cell: ({ row }: any) => row.deletedAt ? dateText(row.deletedAt, timezone) : "-" }, { colKey: "paidAt", title: "支付时间", cell: ({ row }: any) => dateText(row.paidAt, timezone) }, { colKey: "amountCents", title: "金额", cell: ({ row }: any) => {money(row.amountCents)} }, { colKey: "note", title: "备注", cell: ({ row }: any) => {row.note || "无备注"} }, { colKey: "status", title: "原状态", cell: ({ row }: any) => }, { colKey: "actions", title: "操作", width: 190, cell: ({ row }: any) => }, ]; return void load()} disabled={loading || busy} icon={}>刷新}>

回收站为空

: undefined} onRetry={() => void load()}>
{ if (!busy) { setPurgeTarget(null); setPurgeError(""); } }} onConfirm={() => void purge()} onCancel={() => { if (!busy) { setPurgeTarget(null); setPurgeError(""); } }}>

此操作会移除账目和附件字节,完整审计内容仍会保留,且无法恢复。

请输入当前管理员密码确认。

{ setPassword(value); setPurgeError(""); }} placeholder="当前管理员密码" autocomplete="current-password" /> {purgeError && }
; }