229 lines
6.5 KiB
TypeScript
229 lines
6.5 KiB
TypeScript
import React, { useState, useEffect, useCallback } from 'react';
|
|
import { Modal, Form, Input, DatePicker, InputNumber, Select, Space, message } from 'antd';
|
|
import dayjs from 'dayjs';
|
|
import apiClient from '../../utils/request';
|
|
import useFormDraft from '../../hooks/useFormDraft';
|
|
|
|
interface ContractCreateModalProps {
|
|
visible: boolean;
|
|
projectId: number;
|
|
projectName: string;
|
|
onCancel: () => void;
|
|
onSuccess: () => void;
|
|
}
|
|
|
|
const ContractCreateModal: React.FC<ContractCreateModalProps> = ({
|
|
visible,
|
|
projectId,
|
|
projectName,
|
|
onCancel,
|
|
onSuccess
|
|
}) => {
|
|
const [form] = Form.useForm();
|
|
const [contractAmount, setContractAmount] = useState(0);
|
|
|
|
// 表单草稿保护
|
|
const { save: saveDraft, restore: restoreDraft, clear: clearDraft, hasDraft } = useFormDraft({
|
|
form,
|
|
storageKey: 'contract_create',
|
|
})
|
|
|
|
const handleFormChange = useCallback(() => {
|
|
saveDraft()
|
|
}, [saveDraft])
|
|
|
|
// 生成默认的合同编号(包含时间戳确保唯一性)
|
|
const today = dayjs();
|
|
const dateStr = today.format('YYYYMMDD');
|
|
const timeStr = today.format('HHmmss');
|
|
const defaultContractCode = `CONTRACT-${dateStr}-${timeStr}`;
|
|
|
|
useEffect(() => {
|
|
if (visible) {
|
|
form.setFieldsValue({
|
|
contract_code: defaultContractCode,
|
|
project_name: projectName,
|
|
contract_method: 'lump_sum',
|
|
currency: 'CNY',
|
|
contract_amount: 0,
|
|
contract_period: 180
|
|
});
|
|
setContractAmount(0);
|
|
}
|
|
}, [visible, form, projectName]);
|
|
|
|
// 处理工期变化
|
|
const handlePeriodChange = (value: number) => {
|
|
// 只需要设置工期天数,不需要计算开始和结束日期
|
|
};
|
|
|
|
// 提交表单
|
|
const handleSubmit = async (values: any) => {
|
|
// 构建提交数据(简化版)
|
|
const submitData = {
|
|
contract_code: values.contract_code,
|
|
project_name: values.project_name,
|
|
contract_method: values.contract_method || 'lump_sum',
|
|
currency: values.currency || 'CNY',
|
|
contract_amount: values.contract_amount || 0,
|
|
contract_period: values.contract_period || 180,
|
|
warranty_deposit_percentage: 5, // 默认5%
|
|
warranty_period: 12, // 默认12个月
|
|
// 其他字段留空,后续在项目管理中补充
|
|
project_overview: '',
|
|
other_requirements: '',
|
|
contract_file: null,
|
|
payment_nodes: [],
|
|
unit_price_items: []
|
|
};
|
|
|
|
|
|
try {
|
|
const res = await apiClient.put(`/budget-projects/${projectId}/sign`, submitData, {
|
|
headers: {
|
|
'x-user-role': 'admin' // 签约操作需要管理员权限
|
|
}
|
|
});
|
|
|
|
|
|
if (res.data.success) {
|
|
message.success('签约成功,项目已自动创建');
|
|
clearDraft()
|
|
onSuccess();
|
|
onCancel();
|
|
} else {
|
|
message.error(res.data.message || '操作失败');
|
|
}
|
|
} catch (error: any) {
|
|
console.error('签约失败:', error);
|
|
console.error('错误响应:', error.response);
|
|
const errorMessage = error.response?.data?.message || error.message || '操作失败';
|
|
message.error(errorMessage);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal
|
|
title="快速签约"
|
|
open={visible}
|
|
onOk={() => form.submit()}
|
|
onCancel={() => {
|
|
if (form.isFieldsTouched()) {
|
|
Modal.confirm({
|
|
title: '确认关闭',
|
|
content: '表单数据尚未保存,关闭后可通过草稿恢复。确定关闭吗?',
|
|
okText: '关闭',
|
|
cancelText: '继续编辑',
|
|
onOk: () => {
|
|
saveDraft()
|
|
onCancel()
|
|
},
|
|
})
|
|
} else {
|
|
onCancel()
|
|
}
|
|
}}
|
|
width={600}
|
|
okText="确认签约"
|
|
cancelText="取消"
|
|
maskClosable={false}
|
|
>
|
|
<Form
|
|
form={form}
|
|
layout="vertical"
|
|
onFinish={handleSubmit}
|
|
onValuesChange={handleFormChange}
|
|
>
|
|
{/* 基本信息 */}
|
|
<Form.Item
|
|
name="contract_code"
|
|
label="合同编号"
|
|
rules={[{ required: true, message: '请输入合同编号' }]}
|
|
>
|
|
<Input placeholder="请输入合同编号" />
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="project_name"
|
|
label="项目名称"
|
|
rules={[{ required: true, message: '请输入项目名称' }]}
|
|
>
|
|
<Input placeholder="请输入项目名称" />
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="contract_method"
|
|
label="承包方式"
|
|
rules={[{ required: true, message: '请选择承包方式' }]}
|
|
>
|
|
<Select
|
|
placeholder="请选择承包方式"
|
|
options={[
|
|
{ value: 'lump_sum', label: '总价包干' },
|
|
{ value: 'unit_price', label: '单价结算' }
|
|
]}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="currency"
|
|
label="币种"
|
|
rules={[{ required: true, message: '请选择币种' }]}
|
|
>
|
|
<Select
|
|
placeholder="请选择币种"
|
|
options={[
|
|
{ value: 'CNY', label: '人民币' },
|
|
{ value: 'USD', label: '美元' },
|
|
{ value: 'LAK', label: '老挝基普' },
|
|
{ value: 'THB', label: '泰铢' }
|
|
]}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
name="contract_amount"
|
|
label="总价"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: '请输入总价'
|
|
}
|
|
]}
|
|
>
|
|
<InputNumber
|
|
style={{ width: '100%' }}
|
|
min={0}
|
|
placeholder="请输入总价"
|
|
formatter={(value) => `¥ ${value}`}
|
|
parser={(value) => value.replace(/¥\s?|(,*)/g, '')}
|
|
onChange={(value) => setContractAmount(value || 0)}
|
|
/>
|
|
</Form.Item>
|
|
|
|
{/* 工期 */}
|
|
<Form.Item
|
|
name="contract_period"
|
|
label="工期(天)"
|
|
rules={[{ required: true, message: '请输入工期' }]}
|
|
>
|
|
<InputNumber
|
|
style={{ width: '100%' }}
|
|
min={1}
|
|
placeholder="请输入工期(天)"
|
|
onChange={handlePeriodChange}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<div style={{ marginTop: 16, padding: 16, background: '#f5f5f5', borderRadius: 8 }}>
|
|
<p style={{ margin: 0, fontSize: 14, color: '#666' }}>
|
|
注:此为快速签约流程,仅录入基本信息。详细的合同信息可在项目管理中补充。
|
|
</p>
|
|
</div>
|
|
</Form>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default ContractCreateModal;
|