import { Button, DatePicker, Form, Input, Popconfirm, Select, Space, Table, Tag, message } from 'antd'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import dayjs from 'dayjs'; import { api } from '../api/client'; import { FormDrawer } from './FormDrawer'; import { PageHeader, unwrapList } from './ResourcePage'; import { ApplyBucketBar } from './ApplyBucketBar'; export const QUAL_BUCKET_META: Record = { valid: { color: 'success', text: '有效' }, expiring: { color: 'gold', text: '即将到期' }, expired: { color: 'error', text: '已过期' }, }; export const BORROW_BUCKET_META: Record = { borrowed: { color: 'blue', text: '外带中' }, due: { color: 'gold', text: '应还' }, overdue: { color: 'error', text: '未还逾期' }, returned: { color: 'success', text: '已归还' }, }; export const SEAL_BUCKET_META: Record = { pending: { color: 'processing', text: '待审批' }, approved: { color: 'success', text: '已通过' }, rejected: { color: 'error', text: '已驳回' }, out: { color: 'blue', text: '外带中' }, overdue: { color: 'error', text: '外带未还' }, returned: { color: 'success', text: '已归还' }, }; export default function QualificationListPage() { const [params] = useSearchParams(); const bucket = params.get('bucket') || ''; const endpoint = bucket ? `/qualifications?bucket=${bucket}` : '/qualifications'; const qc = useQueryClient(); const [form] = Form.useForm(); const [drawer, setDrawer] = useState(null); const q = useQuery({ queryKey: [endpoint], queryFn: () => api.get(endpoint), }); const { items } = unwrapList(q.data); const mut = useMutation({ mutationFn: (body: Record) => api.post('/qualifications', body), onSuccess: () => { message.success('已登记'); qc.invalidateQueries(); }, onError: (e: Error) => message.error(e.message), }); const openCreate = () => { form.resetFields(); setDrawer('create'); }; return ( <> 登记 } /> } /> setDrawer(null)} okText="提交保存" okLoading={mut.isPending} onOk={async () => { const v = await form.validateFields(); const body = { ...v, expiresAt: v.expiresAt ? dayjs(v.expiresAt).format('YYYY-MM-DD') : undefined, }; if (drawer === 'create') await mut.mutateAsync(body); else if (drawer && typeof drawer === 'object') { await api.patch(`/qualifications/${drawer.id}`, body); message.success('已保存'); qc.invalidateQueries(); } setDrawer(null); }} >
String(r.id)} loading={q.isLoading} dataSource={items} scroll={{ x: 'max-content' }} tableLayout="fixed" columns={[ { title: '资质', dataIndex: 'name', width: 220, ellipsis: true }, { title: '编码', dataIndex: 'code', width: 140 }, { title: '保管人', dataIndex: 'keeper', width: 100 }, { title: '到期日', dataIndex: 'expiresAt', width: 120, render: (v: string) => (v ? dayjs(v).format('YYYY-MM-DD') : '—'), }, { title: '创建时间', dataIndex: 'createdAt', width: 170, render: (v: string) => (v ? dayjs(v).format('YYYY-MM-DD HH:mm:ss') : '—'), }, { title: '预警', dataIndex: 'bucket', width: 110, render: (v: string) => { const s = QUAL_BUCKET_META[v] || { color: 'default', text: v || '—' }; return {s.text}; }, }, { title: '操作', width: 140, render: (_: unknown, r: Record) => ( { await api.delete(`/qualifications/${r.id}`); message.success('已删除'); qc.invalidateQueries(); }} > ), }, ]} /> ); } export function BorrowListPage() { const [params] = useSearchParams(); const bucket = params.get('bucket') || ''; const endpoint = bucket ? `/credential-borrows?bucket=${bucket}` : '/credential-borrows'; const qc = useQueryClient(); const [form] = Form.useForm(); const [creating, setCreating] = useState(false); const q = useQuery({ queryKey: [endpoint], queryFn: () => api.get(endpoint) }); const quals = useQuery({ queryKey: ['/qualifications'], queryFn: () => api.get('/qualifications') }); const staff = useQuery({ queryKey: ['/staff'], queryFn: () => api.get('/staff') }); const bids = useQuery({ queryKey: ['/bid-cases'], queryFn: () => api.get('/bid-cases') }); const { items } = unwrapList(q.data); const createMut = useMutation({ mutationFn: (body: Record) => api.post('/credential-borrows', body), onSuccess: () => { message.success('已登记外带'); qc.invalidateQueries(); }, onError: (e: Error) => message.error(e.message), }); const retMut = useMutation({ mutationFn: (id: string) => api.post(`/credential-borrows/${id}/return`), onSuccess: () => { message.success('已归还'); qc.invalidateQueries(); }, onError: (e: Error) => message.error(e.message), }); const openCreate = () => { form.resetFields(); setCreating(true); }; return ( <> 外带登记 } /> } /> setCreating(false)} okText="提交保存" okLoading={createMut.isPending} onOk={async () => { const v = await form.validateFields(); await createMut.mutateAsync({ ...v, dueAt: v.dueAt ? dayjs(v.dueAt).format('YYYY-MM-DD') : undefined }); setCreating(false); }} >
({ value: s.id, label: s.name, }))} />
String(r.id)} loading={q.isLoading} dataSource={items} columns={[ { title: '物品', dataIndex: 'itemName' }, { title: '借用人', dataIndex: 'borrower', width: 110 }, { title: '资质', width: 180, render: (_: unknown, row: Record) => (row.qualification as { name?: string } | null)?.name || '—', }, { title: '应还', dataIndex: 'dueAt', width: 120, render: (v: string) => (v ? dayjs(v).format('YYYY-MM-DD') : '—'), }, { title: '状态', dataIndex: 'bucket', width: 110, render: (v: string) => { const s = BORROW_BUCKET_META[v] || { color: 'default', text: v }; return {s.text}; }, }, { title: '操作', width: 140, render: (_: unknown, row: Record) => ( {row.status !== 'RETURNED' ? ( ) : null} { await api.delete(`/credential-borrows/${row.id}`); message.success('已删除'); qc.invalidateQueries(); }} > ), }, ]} /> ); }