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 75843bc6ddf913e9ca3260f000a23cbd9cb4312c800e2cb96cb89516b4116e12:


import { useEffect, useState } from 'react'
import { api, qty, type Warehouse } from '../api'
import { useSession } from '../session'
import { Banner, Empty, Field, Page } from '../ui'

type Batch = {
  location_code: string
  goods_code: string
  batch_no: string
  produced_on: string
  expires_on: string
  qty: number
}

export function Inventory() {
  const { user } = useSession()
  const [warehouses, setWarehouses] = useState<Warehouse[]>([])
  const [warehouseId, setWarehouseId] = useState(0)
  const [rows, setRows] = useState<Batch[]>([])
  const [error, setError] = useState('')

  useEffect(() => {
    api<{ warehouses: Warehouse[] }>('/api/warehouses')
      .then((data) => {
        const operational = data.warehouses.filter((row) => row.operational)
        setWarehouses(operational)
        const current = operational.find((row) => row.id === user?.current_warehouse_id)
        setWarehouseId((current ?? operational[0])?.id ?? 0)
      })
      .catch((err: unknown) => setError(err instanceof Error ? err.message : '加载失败'))
  }, [user?.current_warehouse_id])

  useEffect(() => {
    if (!warehouseId) return
    api<{ batches: Batch[] }>(`/api/inventory?warehouse_id=${warehouseId}`)
      .then((data) => setRows(data.batches))
      .catch((err: unknown) => setError(err instanceof Error ? err.message : '库存加载失败'))
  }, [warehouseId])

  return (
    <Page title="库存">
      <Banner kind="error" text={error} />
      <Field label="作业仓库">
        <select value={warehouseId || ''} onChange={(event) => setWarehouseId(Number(event.target.value))}>
          {warehouses.map((row) => (
            <option key={row.id} value={row.id}>
              {row.name}({row.code})
            </option>
          ))}
        </select>
      </Field>
      {warehouseId === 0 ? (
        <Empty text="没有可查看库存的作业仓库" />
      ) : 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.location_code}-${row.batch_no}-${row.produced_on}`}>
                  <td className="mono">{row.location_code}</td>
                  <td className="mono">{row.goods_code}</td>
                  <td className="mono">{row.batch_no}</td>
                  <td>{row.produced_on}</td>
                  <td>{row.expires_on}</td>
                  <td>{qty(row.qty)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </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.