import React, { useState, useEffect, useCallback } from 'react' import { useNavigate } from 'react-router-dom' import { Table, Button, Modal, Form, Input, message, Space, Tag, Card, Row, Col, Statistic, Image } from 'antd' import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined, HomeOutlined, BankOutlined } from '@ant-design/icons' import type { ColumnsType } from 'antd/es/table' import FileUpload from '../components/FileUpload' import useFormDraft from '../hooks/useFormDraft' interface Contact { name: string position: string phone: string is_primary?: boolean } interface PaymentInfo { account_name: string bank_account: string bank_name: string qr_code?: string is_primary: boolean } interface Customer { id: number code: string name: string address: string contacts: Contact[] payment_infos: PaymentInfo[] remark: string total_contract_amount: number total_received: number total_receivable: number created_at: string } const CustomerPage: React.FC = () => { const navigate = useNavigate() const [customers, setCustomers] = useState([]) const [loading, setLoading] = useState(false) const [modalVisible, setModalVisible] = useState(false) const [editingCustomer, setEditingCustomer] = useState(null) const [searchText, setSearchText] = useState('') const [form] = Form.useForm() // 表单草稿保护 const { save: saveDraft, restore: restoreDraft, clear: clearDraft, hasDraft } = useFormDraft({ form, storageKey: 'customer_create', }) const handleFormChange = useCallback(() => { saveDraft() }, [saveDraft]) const fetchCustomers = async () => { setLoading(true) try { const response = await fetch('/api/customers') const data = await response.json() if (data.success) setCustomers(data.data || []) } catch (error) { message.error('获取客户列表失败') } finally { setLoading(false) } } useEffect(() => { fetchCustomers() }, []) const stats = { total: customers.length, totalContract: customers.reduce((sum, c) => sum + (c.total_contract_amount || 0), 0), totalReceivable: customers.reduce((sum, c) => sum + (c.total_receivable || 0), 0) } const getPrimaryContact = (contacts: Contact[]) => { const primary = contacts?.find(c => c.is_primary) return primary?.name || '-' } const getPrimaryPaymentInfo = (paymentInfos: PaymentInfo[]) => { const primary = paymentInfos?.find(p => p.is_primary) return primary } const columns: ColumnsType = [ { title: '名称', dataIndex: 'name', key: 'name', render: (text, record) => ( ) }, { title: '地址', dataIndex: 'address', key: 'address', width: 150, render: (t) => t || '-' }, { title: '主联系人', key: 'primary_contact', width: 100, render: (_, record) => getPrimaryContact(record.contacts || []) }, { title: '收款信息', key: 'payment_info', width: 200, render: (_, record) => { const primary = getPrimaryPaymentInfo(record.payment_infos || []) if (!primary) return 未设置 return (
{primary.bank_name || '-'}
户名: {primary.account_name || '-'}
账号: {primary.bank_account ? primary.bank_account.slice(-4).padStart(primary.bank_account.length, '*') : '-'}
) } }, { title: '合同金额', dataIndex: 'total_contract_amount', key: 'total_contract_amount', width: 100, render: (v) => `¥${(v || 0).toLocaleString()}` }, { title: '应收金额', dataIndex: 'total_receivable', key: 'total_receivable', width: 100, render: (v) => 0 ? '#ff4d4f' : '#52c41a' }}>¥{(v || 0).toLocaleString()} }, { title: '操作', key: 'actions', width: 100, render: (_, record) => ( `共 ${total} 条` }} scroll={{ x: 1100 }} /> { if (form.isFieldsTouched()) { Modal.confirm({ title: '确认关闭', content: '表单数据尚未保存,关闭后可通过草稿恢复。确定关闭吗?', okText: '关闭', cancelText: '继续编辑', onOk: () => { saveDraft() setModalVisible(false) form.resetFields() setEditingCustomer(null) }, }) } else { setModalVisible(false) form.resetFields() setEditingCustomer(null) } }} onOk={() => form.submit()} width={800} maskClosable={false} >

联系人

{(fields, { add, remove }) => (
{fields.map(({ key, name, ...restField }) => (
handleContactChange(name, 'is_primary', e.target.checked)} /> 主联系人
{fields.length > 1 && }
))}
)}

收款信息

{(fields, { add, remove }) => (
{fields.map(({ key, name, ...restField }) => (
handlePaymentInfoChange(name, 'is_primary', e.target.checked)} /> 主要收款账户
{fields.length > 0 && ( )}
))}
)}
) } export default CustomerPage