import React, { useEffect, useRef, useState } from 'react'; import { Button, Descriptions, Drawer, Form, Image, Input, message, Modal, Radio, Space, Table, Tag, Typography, } from 'antd'; import type { TableProps } from 'antd'; import { UnorderedListOutlined } from '@ant-design/icons'; import XinTable from '@/components/XinTable'; import type { XinTableColumn, XinTableInstance, XinTableProps, } from '@/components/XinTable/typings.ts'; import type IPayment from '@/domain/iPayment.ts'; import type { IPaymentBill, IPaymentDetail } from '@/domain/iPayment.ts'; import { PAY_METHOD_MAP, PAYMENT_STATUS_MAP } from '@/domain/iPayment.ts'; import { BILL_STATUS_MAP } from '@/domain/iPurchaseOrder.ts'; import { getPaymentDetail, auditPayment } from '@/api/recon/payment.ts'; import { getStoreOptions } from '@/api/customer/store.ts'; import type IStore from '@/domain/iStore.ts'; import AuthButton from '@/components/AuthButton'; const { Title, Text } = Typography; /** 审核表单 */ interface AuditFormValues { result: 'pass' | 'reject'; audit_remark?: string; } /** * 支付记录(小程序合并付款提交汇款凭证;审核通过后关联账单全部置已支付,拒绝则释放账单) */ const PaymentPage: React.FC = () => { const tableRef = useRef>(null); const [stores, setStores] = useState([]); const [detailOpen, setDetailOpen] = useState(false); const [detail, setDetail] = useState(null); const [detailLoading, setDetailLoading] = useState(false); // 审核弹窗 const [auditTarget, setAuditTarget] = useState(null); const [auditSaving, setAuditSaving] = useState(false); const [auditForm] = Form.useForm(); const watchAuditResult = Form.useWatch('result', auditForm); useEffect(() => { getStoreOptions().then((res) => setStores(res.data.data ?? [])); }, []); const openDetail = async (id: number) => { setDetailOpen(true); setDetailLoading(true); try { const res = await getPaymentDetail(id); setDetail(res.data.data ?? null); } finally { setDetailLoading(false); } }; /** 打开审核弹窗 */ const openAudit = (record: IPayment) => { setAuditTarget(record); auditForm.setFieldsValue({ result: 'pass', audit_remark: '' }); }; /** 提交审核:通过 → 账单批量置已支付;拒绝 → 释放账单 */ const handleAuditSave = async (values: AuditFormValues) => { if (!auditTarget?.id) { return; } setAuditSaving(true); try { const res = await auditPayment(auditTarget.id, values); message.success(res.data.msg ?? '审核完成'); setAuditTarget(null); await tableRef.current?.reload(); if (detail && detail.payment.id === auditTarget.id) { await openDetail(auditTarget.id); } } finally { setAuditSaving(false); } }; /** 合并账单列 */ const billColumns: TableProps['columns'] = [ { title: '账单号', dataIndex: 'bill_no', align: 'center', render: (v) => {v}, }, { title: '账单日期', dataIndex: 'bill_date', align: 'center' }, { title: '商品金额', dataIndex: 'product_amount', align: 'center', render: (v) => `¥${Number(v).toFixed(2)}`, }, { title: '配送费', dataIndex: 'delivery_fee', align: 'center', render: (v) => `¥${Number(v).toFixed(2)}`, }, { title: '附加金额', dataIndex: 'added_amount', align: 'center', render: (v) => `¥${Number(v).toFixed(2)}`, }, { title: '账单总金额', dataIndex: 'total_amount', align: 'center', render: (v) => ¥{Number(v).toFixed(2)}, }, { title: '支付状态', dataIndex: 'status', align: 'center', render: (v) => { const item = BILL_STATUS_MAP[Number(v ?? 0)]; return {item?.text}; }, }, ]; const columns: XinTableColumn[] = [ { title: '支付单号', dataIndex: 'payment_no', valueType: 'text', hideInForm: true, width: 210, render: (_, record) => {record.payment_no}, }, { title: '门店', dataIndex: 'store_id', valueType: 'select', hideInForm: true, fieldProps: { options: stores.map((s) => ({ label: s.name, value: s.id })), showSearch: true, optionFilterProp: 'label', }, render: (_, record) => record.store?.name ?? `门店#${record.store_id}`, }, { title: '支付金额', dataIndex: 'amount', hideInForm: true, hideInSearch: true, align: 'center', render: (_, record) => ¥{record.amount}, }, { title: '支付方式', dataIndex: 'pay_method', valueType: 'select', hideInForm: true, align: 'center', fieldProps: { options: Object.entries(PAY_METHOD_MAP).map(([value, item]) => ({ value: Number(value), label: item.text, })), }, render: (_, record) => { const item = PAY_METHOD_MAP[record.pay_method ?? 0]; return {item?.text ?? '-'}; }, }, { title: '合并账单', dataIndex: 'bills_count', hideInForm: true, hideInSearch: true, align: 'center', render: (_, record) => `${record.bills_count ?? 0} 张`, }, { title: '状态', dataIndex: 'status', valueType: 'select', hideInForm: true, align: 'center', fieldProps: { options: Object.entries(PAYMENT_STATUS_MAP).map(([value, item]) => ({ value: Number(value), label: item.text, })), }, render: (_, record) => { const item = PAYMENT_STATUS_MAP[record.status ?? 0]; return {item?.text}; }, }, { title: '提交时间', dataIndex: 'created_at', hideInForm: true, hideInSearch: true, align: 'center', }, { title: '审核人', dataIndex: 'auditor', hideInForm: true, hideInSearch: true, align: 'center', render: (_, record) => record.auditor?.nickname ?? '-', }, ]; const operateRender: XinTableProps['operateRender'] = (record) => [ ) : null, ]; const tableProps: XinTableProps = { api: '/recon/payment', columns, rowKey: 'id', accessName: 'recon.payment', tableRef, operateRender, formProps: false, actionBarRender: (dom) => [dom.search, dom.keywordSearch], }; return ( <>
支付记录 门店在小程序端选择账单合并付款并上传汇款凭证;审核通过后关联账单全部置为已支付,拒绝则释放账单可重新付款。
{...tableProps} /> {/* 支付详情:支付信息 + 凭证 + 合并账单 */} setDetailOpen(false)} size={1000} loading={detailLoading} footer={ detail && detail.payment.status === 0 ? ( ) : null } > {detail ? ( <> {detail.payment.store?.name ?? `门店#${detail.payment.store_id}`} ¥{detail.payment.amount} {PAY_METHOD_MAP[detail.payment.pay_method ?? 0]?.text ?? '-'} {PAYMENT_STATUS_MAP[detail.payment.status ?? 0]?.text} {detail.payment.created_at} {detail.payment.auditor?.nickname ?? '-'} {detail.payment.audited_at ?? '-'} {detail.payment.audit_remark || '-'} {detail.payment.remark ? ( {detail.payment.remark} ) : null} 汇款凭证 {(detail.payment.voucher_urls ?? []).length > 0 ? ( {(detail.payment.voucher_urls ?? []).map((url, index) => ( ))} ) : ( 无凭证 )} 合并付款账单({detail.bills.length} 张) rowKey="id" size="small" bordered columns={billColumns} dataSource={detail.bills} pagination={false} /> ) : null} {/* 审核弹窗 */} setAuditTarget(null)} onOk={() => auditForm.submit()} confirmLoading={auditSaving} okText="提交审核" destroyOnHidden >
支付金额 ¥{auditTarget?.amount ?? '0.00'}({auditTarget?.bills_count ?? 0} 张账单); 通过后关联账单全部置为「已支付」,拒绝则释放账单,门店可重新发起付款。
); }; export default PaymentPage;