feat: multi-module iteration

This commit is contained in:
2026-08-04 21:38:49 +08:00
parent 9d96c73246
commit 71f508e02b
1366 changed files with 202004 additions and 0 deletions
@@ -0,0 +1,95 @@
import { useState } from 'react';
import {
Button, Descriptions, Drawer, Form, Input, Space, Table, Typography, message,
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { request } from '../lib/api';
import { ORDER_STATUS_LABELS, fmtTime } from '../lib/constants';
import { useAdminList } from '../lib/useAdminList';
type Row = {
id: string; provider: string; trackingNo: string | null; providerOrderNo: string | null; updatedAt: string;
order?: { orderNo: string; status: string; receiverName: string; receiverPhone: string; deliveryType: string };
};
export default function DeliveriesPage() {
const [form] = Form.useForm();
const [editForm] = Form.useForm();
const [filters, setFilters] = useState<Record<string, string>>({});
const { data, loading, page, pageSize, setPage, setPageSize, reload } = useAdminList<Row>(
'/admin/deliveries',
() => {
const qs = new URLSearchParams();
if (filters.provider) qs.set('provider', filters.provider);
if (filters.trackingNo) qs.set('trackingNo', filters.trackingNo);
if (filters.orderNo) qs.set('orderNo', filters.orderNo);
return qs;
},
[filters],
);
const [detail, setDetail] = useState<Row | null>(null);
const [drawerOpen, setDrawerOpen] = useState(false);
const columns: ColumnsType<Row> = [
{ title: '订单号', dataIndex: ['order', 'orderNo'], width: 170 },
{ title: 'provider', dataIndex: 'provider', width: 90 },
{ title: '运单号', dataIndex: 'trackingNo', width: 140, render: (v) => v || '—' },
{ title: '第三方单号', dataIndex: 'providerOrderNo', width: 140, render: (v) => v || '—' },
{ title: '订单状态', dataIndex: ['order', 'status'], width: 100, render: (s) => ORDER_STATUS_LABELS[s] || s },
{ title: '收货人', dataIndex: ['order', 'receiverName'], width: 90 },
{ title: '更新', dataIndex: 'updatedAt', width: 160, render: fmtTime },
{
title: '操作', width: 80,
render: (_, row) => (
<Button type="link" size="small" onClick={async () => {
const d = await request<Row>(`/admin/deliveries/${row.id}`);
setDetail(d);
editForm.setFieldsValue({ provider: d.provider, trackingNo: d.trackingNo, providerOrderNo: d.providerOrderNo });
setDrawerOpen(true);
}}></Button>
),
},
];
return (
<div>
<Typography.Title level={4}>/</Typography.Title>
<Form form={form} layout="inline" style={{ marginBottom: 16 }} onFinish={(v) => { setFilters(v); setPage(1); }}>
<Form.Item name="orderNo" label="订单号"><Input allowClear /></Form.Item>
<Form.Item name="provider" label="provider"><Input allowClear placeholder="MOCK" /></Form.Item>
<Form.Item name="trackingNo" label="运单号"><Input allowClear /></Form.Item>
<Form.Item><Button type="primary" htmlType="submit"></Button></Form.Item>
</Form>
<Table rowKey="id" loading={loading} columns={columns} dataSource={data?.items ?? []} scroll={{ x: 1100 }}
pagination={{ current: page, pageSize, total: data?.total ?? 0, showSizeChanger: true, onChange: (p, ps) => { setPage(p); setPageSize(ps); } }} />
<Drawer title="配送单编辑" width={480} open={drawerOpen} onClose={() => setDrawerOpen(false)}
extra={
<Space>
<Button onClick={() => setDrawerOpen(false)}></Button>
<Button type="primary" onClick={async () => {
if (!detail) return;
const v = await editForm.validateFields();
await request(`/admin/deliveries/${detail.id}`, { method: 'PUT', body: JSON.stringify(v) });
message.success('已保存');
setDrawerOpen(false);
void reload();
}}></Button>
</Space>
}>
{detail && (
<>
<Descriptions column={1} bordered size="small" style={{ marginBottom: 16 }}>
<Descriptions.Item label="订单">{detail.order?.orderNo}</Descriptions.Item>
<Descriptions.Item label="收货">{detail.order?.receiverName} {detail.order?.receiverPhone}</Descriptions.Item>
</Descriptions>
<Form form={editForm} layout="vertical">
<Form.Item name="provider" label="provider" rules={[{ required: true }]}><Input /></Form.Item>
<Form.Item name="providerOrderNo" label="第三方单号"><Input /></Form.Item>
<Form.Item name="trackingNo" label="运单号"><Input /></Form.Item>
</Form>
</>
)}
</Drawer>
</div>
);
}