import { useState } from 'react'; import { Button, Descriptions, Drawer, Form, Input, Modal, Select, Space, 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; }; type CreateFormValues = { orderNo: string; titleType: InvoiceTitleType; invoiceKind: InvoiceKind; titleName: string; taxNo?: string; addressPhone?: string; bankAccount?: string; email: string; phone: 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); const [createOpen, setCreateOpen] = useState(false); const [creating, setCreating] = useState(false); const [createForm] = Form.useForm(); const invoiceKind = Form.useWatch('invoiceKind', createForm); const titleType = Form.useWatch('titleType', createForm); 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); } async function submitCreate() { const values = await createForm.validateFields(); setCreating(true); try { await request('/admin/invoices', { method: 'POST', body: JSON.stringify({ orderNo: values.orderNo.trim(), titleType: values.titleType, invoiceKind: values.invoiceKind, titleName: values.titleName.trim(), taxNo: values.taxNo?.trim() || undefined, addressPhone: values.addressPhone?.trim() || undefined, bankAccount: values.bankAccount?.trim() || undefined, email: values.email.trim(), phone: values.phone.trim(), remark: values.remark?.trim() || undefined, }), }); message.success('发票申请已创建'); setCreateOpen(false); createForm.resetFields(); reload(); } catch (e) { message.error(e instanceof Error ? e.message : '创建失败'); } finally { setCreating(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); }} > ({ value: t, label: INVOICE_TITLE_TYPE_LABELS[t], disabled: invoiceKind === 'SPECIAL' && t === 'PERSONAL', }))} /> {(titleType === 'ENTERPRISE' || invoiceKind === 'SPECIAL') && ( )} {invoiceKind === 'SPECIAL' && ( <> )}
); }