Initial commit

This commit is contained in:
linxd
2025-06-17 14:20:06 +08:00
commit 08424ecdb8
112 changed files with 26341 additions and 0 deletions

View File

@ -0,0 +1,770 @@
/**
* 供应商注册表单通用部分
* 封装了国内企业和境外企业注册表单相同的部分
*/
import React from 'react';
import {
Form,
Input,
Button,
Select,
Upload,
DatePicker,
Row,
Col,
Table,
Radio,
Cascader,
Empty,
} from 'antd';
import { UploadOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import { message } from 'antd';
import { validateFileSize } from '@/utils/utils';
const { Option } = Select;
// 中国省市区级联数据
export const addressOptions = [
{
value: '330000',
label: '浙江省',
children: [
{
value: '330100',
label: '杭州市',
children: [
{ value: '330102', label: '上城区' },
{ value: '330103', label: '下城区' },
{ value: '330104', label: '江干区' },
{ value: '330105', label: '拱墅区' },
{ value: '330106', label: '西湖区' },
{ value: '330108', label: '滨江区' },
],
},
],
},
{
value: '310000',
label: '上海市',
children: [
{
value: '310100',
label: '上海市',
children: [
{ value: '310101', label: '黄浦区' },
{ value: '310104', label: '徐汇区' },
{ value: '310105', label: '长宁区' },
],
},
],
},
];
interface CommonFormSectionsProps {
form: any;
}
// 扩展问卷部分的属性接口
interface SurveySectionProps extends CommonFormSectionsProps {
surveyQuestions?: API.SurveyQuestionResponse;
}
/**
* 资质信息表单部分
* 包含资质证书类型、名称、编号、等级、发证机构、发证日期、有效期等
*/
export const QualificationSection: React.FC<CommonFormSectionsProps> = ({ form }) => {
return (
<>
<div className="form-section-title"></div>
<Form.List name="coscoSupplierQualifications">
{(fields, { add, remove }) => (
<>
<Table
dataSource={fields.map((field) => ({
...field,
key: field.key,
fieldKey: field.name,
}))}
pagination={false}
bordered
size="middle"
rowKey="key"
columns={[
{
title: '序号',
dataIndex: 'name',
width: 60,
render: (_, __, index) => index + 1,
},
{
title: '资质证书类型',
dataIndex: 'certType',
render: (_, record) => (
<Form.Item
name={[record.name, 'certType']}
noStyle
rules={[{ required: true, message: '请选择资质证书类型' }]}
>
<Select placeholder="请选择类型" style={{ width: '100%' }}>
<Option value="机构资质"></Option>
<Option value="CMMI资质等级">CMMI资质等级</Option>
<Option value="质量体系认证"></Option>
<Option value="环境管理体系认证"></Option>
<Option value="行业资质"></Option>
</Select>
</Form.Item>
),
},
{
title: '资质名称',
dataIndex: 'certName',
render: (_, record) => (
<Form.Item
name={[record.name, 'certName']}
noStyle
rules={[{ required: true, message: '请输入资质名称' }]}
>
<Input placeholder="请输入资质名称" />
</Form.Item>
),
},
{
title: '资质证书编号',
dataIndex: 'certNumber',
render: (_, record) => (
<Form.Item
name={[record.name, 'certNumber']}
noStyle
rules={[{ required: true, message: '请输入资质证书编号' }]}
>
<Input placeholder="请输入证书编号" />
</Form.Item>
),
},
{
title: '资质类别和等级',
dataIndex: 'certLevel',
render: (_, record) => (
<Form.Item name={[record.name, 'certLevel']} noStyle>
<Input placeholder="请输入资质类别和等级" />
</Form.Item>
),
},
{
title: '发证机构',
dataIndex: 'issuingAuthority',
render: (_, record) => (
<Form.Item
name={[record.name, 'issuingAuthority']}
noStyle
rules={[{ required: true, message: '请输入发证机构' }]}
>
<Input placeholder="请输入发证机构" />
</Form.Item>
),
},
{
title: '发证日期',
dataIndex: 'issueDate',
render: (_, record) => (
<Form.Item
name={[record.name, 'dateTime']}
noStyle
rules={[{ required: true, message: '请选择发证日期' }]}
>
<DatePicker
placeholder="年/月/日"
style={{ width: '100%' }}
format="YYYY-MM-DD"
/>
</Form.Item>
),
},
{
title: '资质有效期至',
dataIndex: 'expiryDate',
render: (_, record) => (
<Form.Item
name={[record.name, 'termOfValidity']}
noStyle
rules={[{ required: true, message: '请选择资质有效期' }]}
>
<DatePicker
placeholder="年/月/日"
style={{ width: '100%' }}
format="YYYY-MM-DD"
/>
</Form.Item>
),
},
{
title: '附件',
dataIndex: 'certFile',
render: (_, record) => (
<Form.Item
name={[record.name, 'certFile']}
noStyle
rules={[{ required: true, message: '请上传资质证书附件' }]}
>
<Upload name="certFile" action="/api/upload" listType="text" maxCount={1}>
<Button type="link" size="small">
</Button>
</Upload>
</Form.Item>
),
},
{
title: '操作',
width: 70,
render: (_, record) => (
<Button
type="link"
danger
icon={<DeleteOutlined />}
onClick={() => remove(record.name)}
>
</Button>
),
},
]}
/>
<Form.Item style={{ marginTop: 16 }} wrapperCol={{ span: 24 }}>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
</Button>
</Form.Item>
</>
)}
</Form.List>
</>
);
};
/**
* 开票信息表单部分
* 包含纳税人类型、开票抬头、纳税人识别号、开票地址等
*/
export const InvoiceSection: React.FC<CommonFormSectionsProps> = ({ form }) => {
return (
<>
<div className="form-section-title"></div>
<Row gutter={24}>
<Col span={8}>
<Form.Item
name={['coscoSupplierInvoice', 'taxpayerType']}
label="纳税人类型"
rules={[{ required: true, message: '请选择纳税人类型' }]}
>
<Select placeholder="请选择纳税人类型">
<Option value="general"></Option>
<Option value="small"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="invoiceTitle"
label="开票抬头"
rules={[{ required: true, message: '请输入开票抬头' }]}
>
<Input placeholder="请输入开票抬头" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="taxpayerNumber"
label="纳税人识别号"
rules={[{ required: true, message: '请输入纳税人识别号' }]}
>
<Input placeholder="请输入纳税人识别号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="invoiceAddress" label="开票地址">
<Input placeholder="请输入开票地址" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="invoicePhone" label="开票电话">
<Input placeholder="请输入开票电话" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="invoiceBank" label="开票户行">
<Input placeholder="请输入开票银行" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="bankAccountNumber" label="开票户行账号">
<Input placeholder="请输入开票户行账号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="generalTaxpayerCert" label="一般纳税人资格证明">
<Upload
name="generalTaxpayerCert"
action="/api/upload"
listType="text"
maxCount={1}
beforeUpload={(file) => validateFileSize(file, 10, ['pdf', 'jpg', 'jpeg', 'png'])}
>
<Button icon={<UploadOutlined />}></Button>
</Upload>
</Form.Item>
</Col>
</Row>
</>
);
};
/**
* 银行账户表单部分
* 包含开户银行、账户名称、账号、所在地区等
*/
export const BankAccountSection: React.FC<CommonFormSectionsProps> = ({ form }) => {
return (
<>
<div className="form-section-title"></div>
<Form.List name="coscoSupplierBank">
{(fields, { add, remove }) => (
<>
<Table
dataSource={fields.map((field) => ({
...field,
key: field.key,
fieldKey: field.name,
}))}
pagination={false}
bordered
size="middle"
rowKey="key"
columns={[
{
title: '序号',
dataIndex: 'name',
width: 60,
render: (_, __, index) => index + 1,
},
{
title: '开户银行',
dataIndex: 'bankName',
render: (_, record) => (
<Form.Item
name={[record.name, 'bankName']}
noStyle
rules={[{ required: true, message: '请输入开户银行' }]}
>
<Input placeholder="请输入开户银行" />
</Form.Item>
),
},
{
title: '账户名称',
dataIndex: 'accountName',
render: (_, record) => (
<Form.Item
name={[record.name, 'accountName']}
noStyle
rules={[{ required: true, message: '请输入账户名称' }]}
>
<Input placeholder="请输入账户名称" />
</Form.Item>
),
},
{
title: '账号',
dataIndex: 'accountNumber',
render: (_, record) => (
<Form.Item
name={[record.name, 'accountNumber']}
noStyle
rules={[{ required: true, message: '请输入账号' }]}
>
<Input placeholder="请输入账号" />
</Form.Item>
),
},
{
title: '国家、省、市',
dataIndex: 'location',
render: (_, record) => (
<Form.Item
name={[record.name, 'address']}
noStyle
rules={[{ required: true, message: '请选择地址' }]}
>
<Cascader
options={addressOptions}
placeholder="请选择省市区"
showSearch={{
filter: (inputValue, path) => {
return path.some((option) => {
if (typeof option.label === 'string') {
return (
option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
);
}
return false;
});
},
}}
/>
</Form.Item>
),
},
{
title: '操作',
width: 70,
render: (_, record) => (
<Button
type="link"
danger
icon={<DeleteOutlined />}
onClick={() => remove(record.name)}
>
</Button>
),
},
]}
/>
<Form.Item style={{ marginTop: 16 }} wrapperCol={{ span: 24 }}>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
</Button>
</Form.Item>
</>
)}
</Form.List>
</>
);
};
/**
* 社会准则符合性自查问卷部分
* 包含填写人信息和问卷内容
*/
export const SurveySection: React.FC<SurveySectionProps> = ({ form, surveyQuestions }) => {
// 使用API获取的问卷数据如果没有则显示无数据状态
const hasQuestions = surveyQuestions && surveyQuestions.length > 0;
return (
<>
<div className="form-section-title"></div>
<div className="questionnaire-header"></div>
<Row gutter={24}>
<Col span={8}>
<Form.Item
name={['coscoSupplierSurvey', 'supplierName']}
label="供应商名称"
rules={[{ required: true, message: '请输入供应商名称' }]}
>
<Input placeholder="请输入供应商名称" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierSurvey', 'name']}
label="姓名"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input placeholder="请输入姓名" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierSurvey', 'position']}
label="职位"
rules={[{ required: true, message: '请输入职位' }]}
>
<Input placeholder="请输入职位" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierSurvey', 'phone']}
label="电话号"
rules={[{ required: true, message: '请输入电话号' }]}
>
<Input placeholder="请输入电话号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierSurvey', 'email']}
label="邮箱"
rules={[
{ type: 'email', message: '请输入有效的电子邮箱' },
{ required: true, message: '请输入电子邮箱' },
]}
>
<Input placeholder="请输入电子邮箱" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierSurvey', 'dateTime']}
label="日期"
rules={[{ required: true, message: '请选择日期' }]}
>
<DatePicker placeholder="请选择日期" style={{ width: '100%' }} format="YYYY-MM-DD" />
</Form.Item>
</Col>
</Row>
<div className="questionnaire-header" style={{ marginTop: '20px' }}>
</div>
{hasQuestions ? (
<Form.List name="coscoSupplierSurveyQuestionReply">
{(fields, { add, remove }) => {
// 确保有足够的表单项对应每个问题
if (fields.length < surveyQuestions.length) {
const diff = surveyQuestions.length - fields.length;
for (let i = 0; i < diff; i++) {
add();
}
}
return (
<Table
pagination={false}
bordered
size="middle"
rowKey="id"
dataSource={surveyQuestions}
columns={[
{
title: '序号',
dataIndex: 'id',
width: 60,
align: 'center',
render: (text, record, index) => index + 1,
},
{
title: '问题',
dataIndex: 'questionName',
render: (text) => <div style={{ whiteSpace: 'pre-line' }}>{text}</div>,
},
{
title: '回复',
width: 650,
render: (_, record, index) => (
<>
<Form.Item
name={[index, 'surveyQuestionId']}
initialValue={record.id}
hidden
>
<Input />
</Form.Item>
<Form.Item
name={[index, 'replyValue']}
rules={[{ required: true, message: '请选择答案' }]}
wrapperCol={{ span: 24 }}
>
<Radio.Group>
{record.coscoSurveyQuestionOptionList?.map((option: any) => (
<Radio key={option.id} value={option.opentionValue}>
{option.optionName}
</Radio>
))}
</Radio.Group>
</Form.Item>
</>
),
},
]}
/>
);
}}
</Form.List>
) : (
<div style={{ padding: '30px 0' }}>
<Empty description="暂无问卷数据" image={Empty.PRESENTED_IMAGE_SIMPLE} />
</div>
)}
</>
);
};
/**
* 供应商反商业贿赂承诺书和其他附件部分
*/
export const AttachmentSection: React.FC<CommonFormSectionsProps> = ({ form }) => {
return (
<>
<div className="form-section-title">贿</div>
<Row gutter={24}>
<Col span={12}>
<div className="upload-label">
<Button
type="link"
href="/templates/anti-bribery-template.docx"
download="供应商反商业贿赂承诺书模板.docx"
>
</Button>
</div>
<Form.List name="coscoSupplierSurveyAttachments">
{(fields, { add, remove }) => {
// 确保至少有一项用于反商业贿赂承诺书
if (fields.length === 0) {
add({ attachmentsType: 'commitment' });
}
return (
<div>
{fields.map((field, index) => (
<div key={field.key} style={{ display: field.name === 0 ? 'block' : 'none' }}>
<Form.Item
name={[field.name, 'attachmentsType']}
initialValue="commitment"
hidden
>
<Input />
</Form.Item>
<Form.Item
name={[field.name, 'fileUrl']}
rules={[{ required: true, message: '请上传已盖章的反商业贿赂承诺书' }]}
>
<Upload
name="file"
action="/api/upload"
listType="text"
maxCount={1}
beforeUpload={(file) =>
validateFileSize(file, 10, ['pdf', 'doc', 'docx'])
}
onChange={(info) => {
if (info.file.status === 'done') {
const response = info.file.response;
if (response && response.success) {
// 填充文件信息
form.setFieldsValue({
coscoSupplierSurveyAttachments: [
{
...form.getFieldValue([
'coscoSupplierSurveyAttachments',
field.name,
]),
fileName: info.file.name,
fileType: info.file.type,
fileSize: info.file.size.toString(),
filePath: response.filePath || response.url,
},
],
});
message.success(`${info.file.name} 上传成功`);
} else {
message.error(`${info.file.name} 上传失败`);
}
}
}}
>
<Button icon={<UploadOutlined />}></Button>
</Upload>
</Form.Item>
</div>
))}
</div>
);
}}
</Form.List>
</Col>
</Row>
<div className="form-section-title"></div>
<Row gutter={24}>
<Col span={24}>
<Form.List name="coscoSupplierSurveyAttachments">
{(fields, { add, remove }) => (
<>
<div className="upload-label"></div>
{fields.map((field, index) => (
<div
key={field.key}
style={{
display: index > 0 || fields.length === 1 ? 'block' : 'none',
marginBottom: 8,
}}
>
{index > 0 && (
<Form.Item
name={[field.name, 'attachmentsType']}
initialValue="accessory"
hidden
>
<Input />
</Form.Item>
)}
{index > 0 && (
<Form.Item name={[field.name, 'fileUrl']}>
<Upload
name="file"
action="/api/upload"
listType="text"
maxCount={1}
beforeUpload={(file) => validateFileSize(file, 20, ['*'])}
onChange={(info) => {
if (info.file.status === 'done') {
const response = info.file.response;
if (response && response.success) {
// 填充文件信息
const fieldValue = form.getFieldValue([
'coscoSupplierSurveyAttachments',
field.name,
]);
form.setFieldsValue({
coscoSupplierSurveyAttachments: [
{
...fieldValue,
fileName: info.file.name,
fileType: info.file.type,
fileSize: info.file.size.toString(),
filePath: response.filePath || response.url,
},
],
});
message.success(`${info.file.name} 上传成功`);
} else {
message.error(`${info.file.name} 上传失败`);
}
}
}}
>
<Button icon={<UploadOutlined />}></Button>
</Upload>
</Form.Item>
)}
</div>
))}
<Button
type="dashed"
onClick={() => add({ attachmentsType: 'accessory' })}
icon={<PlusOutlined />}
style={{ marginTop: 8 }}
>
</Button>
</>
)}
</Form.List>
</Col>
</Row>
</>
);
};

View File

@ -0,0 +1,281 @@
/* 境内企业/机构 表单项 */
import React from 'react';
import { Form, Input, Button, Select, Upload, DatePicker, Row, Col, message } from 'antd';
import {
MobileOutlined,
MailOutlined,
EnvironmentOutlined,
UploadOutlined,
} from '@ant-design/icons';
/**
* 引入通用表单组件
*/
import {
QualificationSection,
InvoiceSection,
BankAccountSection,
SurveySection,
AttachmentSection,
} from './CommonFormSections';
import { validateFileSize } from '@/utils/utils';
const { Option } = Select;
const { TextArea } = Input;
// 移除不再需要的addressOptions
interface DomesticFormProps {
form: any;
countdown: number;
handleGetCaptcha: () => void;
surveyQuestions?: API.SurveyQuestionResponse; // 本身就是数组类型
}
/**
* 境内企业注册表单
* 基本信息部分为境内企业特有
* 其他部分使用通用表单组件
*/
const DomesticForm: React.FC<DomesticFormProps> = ({
form,
countdown,
handleGetCaptcha,
surveyQuestions,
}) => {
return (
<>
<div className="form-section-title"></div>
{/* 营业执照附件和有效期 */}
<Row gutter={24}>
<Col span={8}>
<Form.Item
name={['coscoSupplierBase', 'licenceAccessory']}
label="营业执照附件"
extra="pdf,jpg,jpeg,png类型的文件,大小不超过10MB"
rules={[{ required: true, message: '请上传营业执照附件' }]}
>
<Upload
name="businessLicense"
action="/api/upload"
listType="text"
maxCount={1}
beforeUpload={(file) => validateFileSize(file, 10, ['pdf', 'jpg', 'jpeg', 'png'])}
>
<Button icon={<UploadOutlined />}></Button>
</Upload>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierBase', 'licenceDate']}
label="营业执照有效期"
rules={[{ required: false, message: '请选择营业执照有效期' }]}
>
<DatePicker
placeholder="请选择日期"
style={{ width: '100%' }}
format="YYYY-MM-DD"
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={['coscoSupplierBase', 'name']}
label="企业名称"
rules={[{ required: true, message: '请输入企业名称' }]}
>
<Input placeholder="请输入企业名称" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="socialCreditCode"
label="统一社会信用代码"
rules={[
{ required: true, message: '请输入统一社会信用代码' },
{ pattern: /^[0-9A-HJ-NPQRTUWXY]{18}$/, message: '请输入正确的统一社会信用代码' },
]}
>
<Input placeholder="请输入正确的统一社会信用代码" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="legalPerson"
label="企业法定代表人"
rules={[{ required: true, message: '请输入企业法定代表人/负责人' }]}
>
<Input placeholder="张三" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="registeredCapital"
label="注册资本"
rules={[{ required: true, message: '请输入注册资本' }]}
>
<Input
type="number"
placeholder="请输入金额"
addonBefore="人民币"
addonAfter="万元"
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="companyType"
label="企业性质"
rules={[{ required: true, message: '请选择企业性质' }]}
>
<Select placeholder="请选择企业性质">
<Option value="limited"></Option>
<Option value="joint"></Option>
<Option value="individual"></Option>
<Option value="other"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="supplierType"
label="供应商类型"
rules={[{ required: true, message: '请选择供应商类型' }]}
>
<Select placeholder="请选择类型">
<Option value="manufacturer"></Option>
<Option value="agent"></Option>
<Option value="service"></Option>
<Option value="other"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="parentCompanyInfo" label="母公司/出资人">
<Input placeholder="请输入母公司或出资人信息" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="registeredAddress"
label="注册地址"
rules={[{ required: true, message: '请输入注册地址' }]}
>
<Input prefix={<EnvironmentOutlined />} placeholder="上海市普陀区XX路1888号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="officeAddress" label="办公地址">
<Input
prefix={<EnvironmentOutlined />}
placeholder="请具体注明省、市、区、路、门牌号"
/>
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
name="businessScope"
label="经营范围"
rules={[{ required: true, message: '请输入经营范围' }]}
labelCol={{ span: 2 }}
wrapperCol={{ span: 22 }}
>
<TextArea
placeholder="金融专用产品、广告传媒"
rows={2}
maxLength={200}
showCount
style={{ resize: 'none' }}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactPerson"
label="联系人姓名"
rules={[{ required: true, message: '请输入联系人姓名' }]}
>
<Input placeholder="请输入联系人姓名" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactPhone"
label="联系人手机"
rules={[
{ required: true, message: '请输入联系人手机号' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入有效的手机号' },
]}
>
<Input prefix={<MobileOutlined />} placeholder="请输入11位手机号码" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="captcha"
label="验证码"
rules={[{ required: true, message: '请输入验证码' }]}
>
<Row gutter={8}>
<Col span={14}>
<Input placeholder="请输入短信验证码" />
</Col>
<Col span={10}>
<Button
type="primary"
style={{ marginTop: 0 }}
disabled={countdown > 0}
onClick={handleGetCaptcha}
>
{countdown > 0 ? `${countdown}s` : '获取验证码'}
</Button>
</Col>
</Row>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="contactIdType" label="联系人身份类别">
<Select placeholder="请选择类型">
<Option value="idcard"></Option>
<Option value="passport"></Option>
<Option value="other"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="contactIdNumber" label="联系人证件号码">
<Input placeholder="请填写联系人正确的身份证号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactEmail"
label="联系人邮箱"
rules={[
{ type: 'email', message: '请输入有效的电子邮箱' },
{ required: true, message: '请输入电子邮箱' },
]}
>
<Input prefix={<MailOutlined />} placeholder="请输入企业联系电话" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="telephone" label="固定电话">
<Input placeholder="XXX@XXX.com" />
</Form.Item>
</Col>
</Row>
{/* 使用通用表单组件 */}
<QualificationSection form={form} />
<InvoiceSection form={form} />
<BankAccountSection form={form} />
<SurveySection form={form} surveyQuestions={surveyQuestions} />
<AttachmentSection form={form} />
</>
);
};
export default DomesticForm;

View File

@ -0,0 +1,319 @@
/* 境外企业 表单项 */
import React from 'react';
import { Form, Input, Button, Select, Row, Col } from 'antd';
import {
MobileOutlined,
MailOutlined,
EnvironmentOutlined,
} from '@ant-design/icons';
/**
* 引入通用表单组件
*/
import {
QualificationSection,
InvoiceSection,
BankAccountSection,
SurveySection,
AttachmentSection,
} from './CommonFormSections';
const { Option } = Select;
const { TextArea } = Input;
interface ForeignFormProps {
form: any;
countdown: number;
handleGetCaptcha: () => void;
surveyQuestions?: API.SurveyQuestionResponse; // 本身就是数组类型
}
/**
* 境外企业注册表单
* 基本信息部分为境外企业特有
* 其他部分使用通用表单组件
*/
const ForeignForm: React.FC<ForeignFormProps> = ({ form, countdown, handleGetCaptcha, surveyQuestions }) => {
return (
<>
{/* 境外企业特有的基本信息部分 */}
<div className="form-section-title"></div>
<Row gutter={24}>
<Col span={8}>
<Form.Item
name="companyName"
label="企业名称"
rules={[{ required: true, message: '请输入企业名称' }]}
>
<Input placeholder="请输入企业名称" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="companyEnglishName"
label="企业英文名称"
rules={[{ required: true, message: '请输入企业英文名称' }]}
>
<Input placeholder="请输入企业英文名称" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="companyRegNumber"
label="公司注册号"
rules={[{ required: true, message: '请输入公司注册号' }]}
>
<Input placeholder="请输入公司注册号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="country"
label="国家/地区"
rules={[{ required: true, message: '请选择国家/地区' }]}
>
<Select placeholder="请选择国家/地区">
<Option value="US"></Option>
<Option value="UK"></Option>
<Option value="JP"></Option>
<Option value="DE"></Option>
<Option value="FR"></Option>
<Option value="AU"></Option>
<Option value="CA"></Option>
<Option value="SG"></Option>
<Option value="HK"></Option>
<Option value="OTHER"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="registrationPassword"
label="登录密码"
rules={[
{ required: true, message: '请输入登录密码' },
{ min: 8, message: '密码长度为8-20位' },
{
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,20}$/,
message: '需要同时包含字母、数字、大小写',
},
]}
>
<Input.Password placeholder="长度为8-20位需要同时包含字母、数字、大小写" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="confirmPassword"
label="确认密码"
rules={[
{ required: true, message: '请再次输入密码' },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('registrationPassword') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次输入的密码不一致'));
},
}),
]}
>
<Input.Password placeholder="请再次输入密码" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="registeredAddress"
label="注册地址"
rules={[{ required: true, message: '请输入注册地址' }]}
>
<Input prefix={<EnvironmentOutlined />} placeholder="请具体注明" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="officeAddress" label="办公地址">
<Input prefix={<EnvironmentOutlined />} placeholder="请具体注明" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="parentCompanyInfo" label="母公司/出资人">
<Input placeholder="请输入母公司或出资人信息" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="legalPerson"
label="企业法定代表人"
rules={[{ required: true, message: '请输入企业法定代表人' }]}
>
<Input placeholder="请输入企业法定代表人" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="companyType"
label="企业性质"
rules={[{ required: true, message: '请选择企业性质' }]}
>
<Select placeholder="请选择企业性质">
<Option value="corporation"></Option>
<Option value="partnership"></Option>
<Option value="joint"></Option>
<Option value="sole"></Option>
<Option value="other"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="supplierType"
label="供应商类型"
rules={[{ required: true, message: '请选择供应商类型' }]}
>
<Select placeholder="请选择供应商类型">
<Option value="manufacturer"></Option>
<Option value="agent"></Option>
<Option value="service"></Option>
<Option value="other"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label="注册资本"
required
style={{ marginBottom: 0 }}
>
<Input.Group compact style={{ display: 'flex' }}>
<Form.Item name="capitalCurrency" noStyle initialValue="USD">
<Select style={{ width: 100, borderRadius: '2px 0 0 2px' }}>
<Option value="USD"></Option>
<Option value="EUR"></Option>
<Option value="GBP"></Option>
<Option value="JPY"></Option>
<Option value="HKD"></Option>
</Select>
</Form.Item>
<Form.Item
name="capitalAmount"
noStyle
rules={[{ required: true, message: '请输入注册资本金额' }]}
>
<Input
type="number"
placeholder="请输入金额"
style={{ flex: 1, borderRadius: '0 2px 2px 0', marginLeft: -1 }}
/>
</Form.Item>
</Input.Group>
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
name="businessScope"
label="经营范围"
labelCol={{ span: 2 }}
wrapperCol={{ span: 22 }}
rules={[{ required: true, message: '请输入经营范围' }]}
>
<TextArea placeholder="请输入经营范围" rows={2} maxLength={200} showCount />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactName"
label="联系人姓名"
rules={[{ required: true, message: '请输入联系人姓名' }]}
>
<Input placeholder="请输入联系人姓名" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactPhone"
label="联系人手机"
rules={[
{ required: true, message: '请输入联系人手机号码' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' },
]}
>
<Input
placeholder="请输入11位手机号码"
prefix={<MobileOutlined />}
addonAfter={
<Button
type="link"
size="small"
disabled={countdown > 0}
onClick={handleGetCaptcha}
>
{countdown ? `${countdown}秒后重新获取` : '获取验证码'}
</Button>
}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="verificationCode"
label="验证码"
rules={[
{ required: true, message: '请输入验证码' },
{ pattern: /^\d{6}$/, message: '请输入6位数字验证码' },
]}
extra="该手机号用于后续联系和找回密码"
>
<Input placeholder="请输入验证码" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactIdType"
label="联系人身份类别"
rules={[{ required: true, message: '请选择联系人身份类别' }]}
>
<Select placeholder="请选择类型">
<Option value="internal"></Option>
<Option value="external"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactIdNumber"
label="联系人证件号码"
rules={[{ required: true, message: '请输入联系人证件号码' }]}
>
<Input placeholder="请填写联系人正确的身份证号" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="contactEmail"
label="联系人邮箱"
rules={[
{ type: 'email', message: '请输入有效的电子邮箱' },
{ required: true, message: '请输入电子邮箱' },
]}
>
<Input prefix={<MailOutlined />} placeholder="XXX@XXX.com" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="telephone" label="固定电话">
<Input placeholder="请输入企业联系电话" />
</Form.Item>
</Col>
</Row>
{/* 使用通用表单组件 */}
<QualificationSection form={form} />
<InvoiceSection form={form} />
<BankAccountSection form={form} />
<SurveySection form={form} surveyQuestions={surveyQuestions} />
<AttachmentSection form={form} />
</>
);
};
export default ForeignForm;