Artifact 7d839dda0bc13549f7abe3dc6917323eae04e696f3c39446af5ef805c9730831:
- File
web/src/pages/Audit.tsx
— part of check-in
[dfa747c1ad]
at
2026-10-23 06:08:28
on branch trunk
— Web 管理控制台
- 用 Vite 和 React 做完整的 Web 端:登录、按权限显示菜单、切换当前作业仓库 - 覆盖来肯同步、仓库、库位规划、商品、销售订单、采购入库与批次码、采购订单、库存、用户授权和审计日志 - 开发时由 Vite 把 /api 代理到本机后端 - SQLite 写入和页面读取冲突时自动重试,避免请求进程因数据库忙碌直接崩溃 (user: pluto size: 1871)
import { useEffect, useState } from 'react' import { api } from '../api' import { Empty, Page, Pager } from '../ui' type Entry = { id: string username: string action: string target: string warehouse_id: number detail: string created_at: string } export function Audit() { const [offset, setOffset] = useState(0) const [total, setTotal] = useState(0) const [rows, setRows] = useState<Entry[]>([]) const [error, setError] = useState('') const limit = 50 useEffect(() => { api<{ total: number; logs: Entry[] }>(`/api/audit-logs?limit=${limit}&offset=${offset}`) .then((data) => { setTotal(data.total) setRows(data.logs) }) .catch((err: unknown) => setError(err instanceof Error ? err.message : '加载失败')) }, [offset]) return ( <Page title="审计日志"> {error && <p className="banner error">{error}</p>} {rows.length === 0 ? ( <Empty text="还没有审计记录" /> ) : ( <div className="table-wrap"> <table> <thead> <tr> <th>时间</th> <th>账号</th> <th>动作</th> <th>对象</th> <th>仓库</th> <th>说明</th> </tr> </thead> <tbody> {rows.map((row) => ( <tr key={row.id}> <td>{row.created_at}</td> <td>{row.username}</td> <td className="mono">{row.action}</td> <td>{row.target}</td> <td>{row.warehouse_id || ''}</td> <td>{row.detail}</td> </tr> ))} </tbody> </table> </div> )} <Pager total={total} limit={limit} offset={offset} onPage={setOffset} /> </Page> ) }