Fosi Fossil Service
Small teams. Open source. Built on Fossil.

IaC / SwiftFlow

High-performance WMS with wave picking, smart routing, and real-time inventory visibility.

Public | Owner: IaC | Default branch: trunk | Last update: 2026-10-23 14:37

Artifact 982f230187ec4dc7923277d0b68321e7ab19fefbafefd39b3c49c25b34e55a7f:


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>
  )
}

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/IaC/SwiftFlow

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.