import { useState } from 'react'; import { Button, Descriptions, Drawer, Form, Input, Select, Table, Tag, Typography, Upload, message, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { INVOICE_KIND_LABELS, INVOICE_STATUS_LABELS, INVOICE_TITLE_TYPE_LABELS, type InvoiceKind, type InvoiceStatus, type InvoiceTitleType, } from '@dukang/shared-types'; import { request } from '../lib/api'; import { fmtTime } from '../lib/constants'; import { useAdminList } from '../lib/useAdminList'; import { uploadFileToOss } from '../lib/upload'; type Row = { id: string; invoiceNo: string; orderNo?: string; titleType: InvoiceTitleType; invoiceKind: InvoiceKind; titleName: string; status: InvoiceStatus; overdue?: boolean; createdAt: string; fileUrl?: string; email?: string; phone?: string; taxNo?: string; addressPhone?: string; bankAccount?: string; payAmount?: string; userPhone?: string; remark?: string; }; export default function InvoicesPage() { const [filters, setFilters] = useState>({}); const { data, loading, page, pageSize, setPage, setPageSize, reload } = useAdminList( '/admin/invoices', () => { const qs = new URLSearchParams(); if (filters.status) qs.set('status', filters.status); return qs; }, [filters], ); const [detail, setDetail] = useState(null); const [drawerOpen, setDrawerOpen] = useState(false); const [uploading, setUploading] = useState(false); async function openDetail(id: string) { setDetail(await request(`/admin/invoices/${id}`)); setDrawerOpen(true); } async function issueWithFile(file: File) { if (!detail) return false; setUploading(true); try { const uploaded = await uploadFileToOss(file, { bizType: 'invoice' }); await request(`/admin/invoices/${detail.id}/issue`, { method: 'POST', body: JSON.stringify({ fileUrl: uploaded.url }), }); message.success('已开票回传'); reload(); setDrawerOpen(false); } catch (e) { message.error(e instanceof Error ? e.message : '开票失败'); } finally { setUploading(false); } return false; } async function reject() { if (!detail) return; await request(`/admin/invoices/${detail.id}/reject`, { method: 'POST', body: JSON.stringify({ remark: '驳回' }), }); message.success('已驳回'); reload(); setDrawerOpen(false); } const columns: ColumnsType = [ { title: '申请单号', dataIndex: 'invoiceNo', width: 180 }, { title: '订单号', dataIndex: 'orderNo', width: 160 }, { title: '抬头', width: 100, render: (_, r) => INVOICE_TITLE_TYPE_LABELS[r.titleType] ?? r.titleType, }, { title: '票种', width: 120, render: (_, r) => INVOICE_KIND_LABELS[r.invoiceKind] ?? r.invoiceKind, }, { title: '名称', dataIndex: 'titleName', ellipsis: true }, { title: '状态', width: 110, render: (_, r) => ( <> {INVOICE_STATUS_LABELS[r.status] ?? r.status} {r.overdue ? 超时 : null} ), }, { title: '申请时间', dataIndex: 'createdAt', width: 160, render: fmtTime }, { title: '操作', width: 80, render: (_, row) => ( ), }, ]; return (
发票管理
{ setFilters(v); setPage(1); }} >