Artifact 982f230187ec4dc7923277d0b68321e7ab19fefbafefd39b3c49c25b34e55a7f:
- File
web/src/pages/Products.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: 2550)
import { useEffect, useState } from 'react' import { api } from '../api' import { Empty, Field, Page, Pager } from '../ui' type Product = { id: number code: string name: string barcode: string spec: string unit: string shelf_life: string disabled: boolean } export function Products() { const [keyword, setKeyword] = useState('') const [query, setQuery] = useState('') const [offset, setOffset] = useState(0) const [total, setTotal] = useState(0) const [rows, setRows] = useState<Product[]>([]) const [error, setError] = useState('') const limit = 50 useEffect(() => { const params = new URLSearchParams({ keyword: query, limit: String(limit), offset: String(offset) }) api<{ total: number; products: Product[] }>(`/api/products?${params}`) .then((data) => { setTotal(data.total) setRows(data.products) }) .catch((err: unknown) => setError(err instanceof Error ? err.message : '加载失败')) }, [query, offset]) return ( <Page title="商品"> {error && <p className="banner error">{error}</p>} <form className="filters" onSubmit={(event) => { event.preventDefault() setOffset(0) setQuery(keyword.trim()) }} > <Field label="编码、名称或条码"> <input value={keyword} onChange={(event) => setKeyword(event.target.value)} /> </Field> <button type="submit">查询</button> </form> {rows.length === 0 ? ( <Empty text="没有商品" /> ) : ( <div className="table-wrap"> <table> <thead> <tr> <th>编码</th> <th>名称</th> <th>条码</th> <th>规格</th> <th>单位</th> <th>保质期</th> <th>状态</th> </tr> </thead> <tbody> {rows.map((row) => ( <tr key={row.id}> <td className="mono">{row.code}</td> <td>{row.name}</td> <td className="mono">{row.barcode}</td> <td>{row.spec}</td> <td>{row.unit}</td> <td>{row.shelf_life}</td> <td>{row.disabled ? '停用' : '启用'}</td> </tr> ))} </tbody> </table> </div> )} <Pager total={total} limit={limit} offset={offset} onPage={setOffset} /> </Page> ) }