备份:大改造前的完整版本 - 修复合同细节/付款节点/文件上传/施工管理/项目保存等BUG

This commit is contained in:
root
2026-05-15 12:02:24 +08:00
parent 1cad1e438d
commit fad28741bd
6157 changed files with 5147 additions and 877912 deletions
+58 -20
View File
@@ -1,9 +1,10 @@
import React, { useState, useEffect } from 'react'
import React, { useState, useEffect, useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
import { Table, Button, Modal, Form, Input, Select, message, Space, Tag, Card, Row, Col, Statistic } from 'antd'
import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined, SolutionOutlined, 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
@@ -45,6 +46,16 @@ const SubcontractorPage: React.FC = () => {
const [searchText, setSearchText] = useState('')
const [form] = Form.useForm()
// 表单草稿保护
const { save: saveDraft, restore: restoreDraft, clear: clearDraft, hasDraft } = useFormDraft({
form,
storageKey: 'subcontractor_create',
})
const handleFormChange = useCallback(() => {
saveDraft()
}, [saveDraft])
const fetchSubcontractors = async () => {
setLoading(true)
try {
@@ -84,23 +95,6 @@ const SubcontractorPage: React.FC = () => {
)
},
{ title: '承包范围', dataIndex: 'scope', key: 'scope', width: 120 },
{ 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 <Tag></Tag>
return (
<div style={{ fontSize: 12 }}>
<div><BankOutlined /> {primary.bank_name || '-'}</div>
<div>: {primary.account_name || '-'}</div>
<div>: {primary.bank_account ? primary.bank_account.slice(-4).padStart(primary.bank_account.length, '*') : '-'}</div>
</div>
)
}
},
{ title: '国家', dataIndex: 'country', key: 'country', width: 80, render: (c) => <Tag>{c || '-'}</Tag> },
{ title: '合同金额', dataIndex: 'total_contract_amount', key: 'total_contract_amount', width: 100, render: (v) => `¥${(v || 0).toLocaleString()}` },
{ title: '应付金额', dataIndex: 'total_payable', key: 'total_payable', width: 100, render: (v) => <span style={{ color: v > 0 ? '#ff4d4f' : '#52c41a' }}>¥{(v || 0).toLocaleString()}</span> },
@@ -163,6 +157,7 @@ const SubcontractorPage: React.FC = () => {
const data = await response.json()
if (data.success) {
message.success(editingSubcontractor ? '更新成功' : '创建成功')
clearDraft()
setModalVisible(false)
form.resetFields()
setEditingSubcontractor(null)
@@ -212,6 +207,29 @@ const SubcontractorPage: React.FC = () => {
payment_infos: []
})
setModalVisible(true)
// 检查是否有草稿,提示用户是否恢复
setTimeout(() => {
if (hasDraft()) {
Modal.confirm({
title: '发现未完成的草稿',
content: '检测到上次未提交的分包商信息,是否恢复?',
okText: '恢复草稿',
cancelText: '重新填写',
onOk: () => {
restoreDraft()
},
onCancel: () => {
clearDraft()
form.resetFields()
form.setFieldsValue({
country: 'Laos',
contacts: [{ name: '', position: '', phone: '', is_primary: true }],
payment_infos: []
})
},
})
}
}, 0)
}
return (
@@ -236,11 +254,31 @@ const SubcontractorPage: React.FC = () => {
<Modal
title={editingSubcontractor ? '编辑分包商' : '新增分包商'}
open={modalVisible}
onCancel={() => { setModalVisible(false); form.resetFields(); setEditingSubcontractor(null) }}
onCancel={() => {
if (form.isFieldsTouched()) {
Modal.confirm({
title: '确认关闭',
content: '表单数据尚未保存,关闭后可通过草稿恢复。确定关闭吗?',
okText: '关闭',
cancelText: '继续编辑',
onOk: () => {
saveDraft()
setModalVisible(false)
form.resetFields()
setEditingSubcontractor(null)
},
})
} else {
setModalVisible(false)
form.resetFields()
setEditingSubcontractor(null)
}
}}
onOk={() => form.submit()}
width={800}
maskClosable={false}
>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form form={form} layout="vertical" onFinish={handleSubmit} onValuesChange={handleFormChange}>
<Form.Item name="name" label="名称" rules={[{ required: true, message: '请输入名称' }]}>
<Input placeholder="分包商名称" />
</Form.Item>