登录 个人 与 零星采购

This commit is contained in:
孙景学
2025-07-09 14:01:45 +08:00
parent 56da66ee21
commit b46b35cd4b
35 changed files with 1054 additions and 343 deletions

View File

@ -2,7 +2,9 @@ import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Upload, message, Row, Col, Descriptions } from 'antd';
import type { UploadProps } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { uploadFile, bankView, bankAdd, bankEdit } from '../services';
import { uploadFile, bankView, bankAdd, bankEdit, coscoSupplierBase } from '../services';
import { getRegionTree, getregionInternational } from '@/servers/api/register';
interface props {
visible: boolean;
onOk: () => void;
@ -56,6 +58,11 @@ const InvoiceFormModal: React.FC<props> = ({
setViewData(fields);
}
});
} else {
form.resetFields(); // ✅ 只有无 initialValues 才重置
}

View File

@ -1,5 +1,5 @@
/* 境外企业 表单项 */
import React from 'react';
import React, { useState, useEffect } from 'react';
import { Form, Input, Select, Row, Col } from 'antd';
import {
MailOutlined,
@ -8,7 +8,7 @@ import {
/**
* 引入通用表单组件
*/
import { getregionInternational } from '@/servers/api/register';
const { Option } = Select;
interface ForeignFormProps {
@ -23,7 +23,15 @@ interface ForeignFormProps {
* 其他部分使用通用表单组件
*/
const ForeignForm: React.FC<ForeignFormProps> = ({ form, countdown, handleGetCaptcha }) => {
// 全球
const [regionOptions, setRegionOptions] = useState<API.RegionOption[]>([]);
useEffect(() => {
getregionInternational().then(res => {
if (res.code === 200) {
setRegionOptions(res.data);
}
});
}, []);
return (
<>
{/* 境外企业特有的基本信息部分 */}
@ -56,16 +64,11 @@ const ForeignForm: React.FC<ForeignFormProps> = ({ form, countdown, handleGetCap
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>
{
regionOptions.map((item) => {
return <Option value={item.id}>{item.name}</Option>
})
}
</Select>
</Form.Item>
</Col>

View File

@ -0,0 +1,109 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, message, Input, Upload, Button } from 'antd';
import Person from './Person';
import { updateSupplierBase } from '../services'
interface Props {
visible: boolean;
onOk: () => void;
onCancel: () => void;
initialValues?: coscoSupplierBases;
}
// 基础信息
interface coscoSupplierBases {
id?: string;
supplierType?: string;
name?: string;
nameEn?: string;
range?: string;
workAddress?: string;
parentCompanyInvestor?: string;
legalPerson?: string;
capital?: string;
contactsName?: string;
contactsPhone?: string;
contactsEmail?: string;
nation?: string;
vat?: string;
currency?: string;
licenceAccessory?: string;
licenceDate?: string;
enterpriseType?: string;
socialCreditCode?: string;
regAddress?: string;
idCard?: string;
contactsType?: string;
telephone?: string;
coscoSupplierSurveyAttachments?: coscoSupplierSurveyAttachments[];
}
interface coscoSupplierSurveyAttachments {
attachmentsType: string;
fileName: string;
fileType: string;
fileSize: string;
filePath: string;
fileUrl: string;
}
const BaseInfoFormModal: React.FC<Props> = ({
visible,
onOk,
onCancel,
initialValues,
}) => {
const [form] = Form.useForm();
//数据初始化
useEffect(() => {
if (visible && initialValues) {
form.setFieldsValue({
coscoSupplierBase: {
...initialValues,
},
});
} else {
form.resetFields();
}
}, [visible, initialValues]);
//确认提交
const handleFinish = async () => {
const values = await form.validateFields();
const payload = {
...values,
};
payload.coscoSupplierBase.name = payload.coscoSupplierBase.personName;
payload.coscoSupplierBase.contactPhone = payload.coscoSupplierBase.personPhone;
payload.coscoSupplierBase.id = initialValues?.id;
const res = await updateSupplierBase(payload);
if (res.code === 200) {
message.success('修改成功');
onOk();
}
};
return (
<Modal
title="企业基本信息"
visible={visible}
onCancel={onCancel}
onOk={handleFinish}
destroyOnClose
width={800}
>
<Form form={form} labelCol={{ flex: '140px' }} wrapperCol={{ flex: 1 }} >
<Person form={form} />
</Form>
</Modal >
);
};
export default BaseInfoFormModal;

View File

@ -0,0 +1,107 @@
import React, { useEffect, useState } from 'react';
import { Descriptions, Button } from 'antd';
import { coscoSupplierBase } from '../services';
import { useIntl } from 'umi';
import PeBaseInfoFormModal from './PeBaseInfoFormModal'
export interface Request {
capital: string;
contactsEmail: string;
contactsName: string;
contactsPhone: string;
contactsType: string;
enterpriseType: string;
id: string;
idCard: string;
legalPerson: string;
licenceAccessory: string;
licenceDate: string;
name: string;
nameEn: string;
parentCompanyInvestor: string;
range: string;
regAddress: string;
socialCreditCode: string;
telephone: string;
workAddress: string;
[property: string]: any;
}
interface BaseInfoTabProps {
viewType?:boolean;
record?:string;
}
const BaseInfoTab: React.FC<BaseInfoTabProps> = (props) => {
const { viewType = false, record = '' } = props;
const intl = useIntl();
const [registerInfo, setRegisterInfo] = useState<Request>();
const fetchData = async () => {
const res = await coscoSupplierBase(record);
if (res.code === 200) {
setRegisterInfo(res.data);
}
};
//增改查
const [formVisible, setFormVisible] = useState(false);
const handleAdd = () => {
setFormVisible(true);
};
const handleFormSubmit = () => {
setFormVisible(false);
fetchData();
};
useEffect(() => {
//供应商信息
fetchData()
}, []);
if (!registerInfo?.coscoSupplierBase) return <div>{intl.formatMessage({ id: 'component.globalModal.loading' })}...</div>;
return (
<div style={{ padding: '0 30px 0 0' }}>
{ !viewType && (
<Button type="primary" onClick={handleAdd}></Button>
)}
<Descriptions
bordered
column={2}
size="middle"
style={{ background: '#fff', padding: '16px 0 0' }}
>
<Descriptions.Item label="姓名">
{registerInfo.coscoSupplierBase.personName}
</Descriptions.Item>
<Descriptions.Item label="身份证号">
{registerInfo.coscoSupplierBase.idCard}
</Descriptions.Item>
<Descriptions.Item label="联系电话">
{registerInfo.coscoSupplierBase.personPhone}
</Descriptions.Item>
<Descriptions.Item label="开户行">
{registerInfo.coscoSupplierBase.personBank}
</Descriptions.Item>
<Descriptions.Item label="银行账号">
{registerInfo.coscoSupplierBase.personAccount}
</Descriptions.Item>
{/* <Descriptions.Item label="相关证照">
{registerInfo.coscoSupplierBase.socialCreditCode}
</Descriptions.Item> */}
</Descriptions>
<PeBaseInfoFormModal
visible={formVisible}
onOk={handleFormSubmit}
onCancel={() => setFormVisible(false)}
initialValues={registerInfo.coscoSupplierBase || undefined}
/>
</div>
);
};
export default BaseInfoTab;

View File

@ -0,0 +1,99 @@
/* 境外企业 表单项 */
import React from 'react';
import { Form, Input, Row, Col } from 'antd';
import {
MobileOutlined,
} from '@ant-design/icons';
interface ForeignFormProps {
form: any;
}
/**
* 个人注册表单
* 基本信息部分为个人
*/
const ForeignForm: React.FC<ForeignFormProps> = ({ form }) => {
return (
<>
{/* 境外企业特有的基本信息部分 */}
<div className="form-section-title"></div>
<Row gutter={24}>
<Col span={13}>
<Form.Item
name={['coscoSupplierBase', 'personName']}
label="姓名"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input placeholder="请输入姓名" />
</Form.Item>
</Col>
<Col span={13}>
<Form.Item
name={['coscoSupplierBase', 'idCard']}
label="身份证号"
rules={[{ required: true, message: '请输入身份证号' }]}
>
<Input placeholder="请填写正确的身份证号" />
</Form.Item>
</Col>
<Col span={13}>
<Form.Item
name={['coscoSupplierBase', 'personPhone']}
label="联系电话"
rules={[
{ required: true, message: '请输入联系电话' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的联系电话' },
]}
>
<Input
placeholder="请输入11位联系电话"
prefix={<MobileOutlined />}
/>
</Form.Item>
</Col>
<Col span={13}>
<Form.Item
name={['coscoSupplierBase', 'personBank']}
label="开户行"
rules={[{ required: true, message: '请输入开户行' }]}
>
<Input placeholder="请输入开户行" />
</Form.Item>
</Col>
<Col span={13}>
<Form.Item
name={['coscoSupplierBase', 'personAccount']}
label="银行账号"
rules={[{ required: true, message: '请输入银行账号' }]}
>
<Input placeholder="请输入银行账号" />
</Form.Item>
</Col>
{/* <Col span={24}>
<Form.Item
name="attachments"
label="相关证照"
extra="pdf,jpg,jpeg,png类型的文件,大小不超过10MB"
rules={[{ required: true, message: '请上传相关证照' }]}
>
<Upload
name="file"
action="/api/fileConfig/files/upload"
listType="text"
maxCount={1}
beforeUpload={(file) => validateFileSize(file, 10, ['pdf', 'jpg', 'jpeg', 'png'])}
>
<Button icon={<UploadOutlined />}>上传文件</Button>
</Upload>
</Form.Item>
</Col> */}
</Row>
</>
);
};
export default ForeignForm;

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { Tabs } from 'antd';
import { useIntl } from 'umi';
import BaseInfoTab from './component/BaseInfoTab';
@ -7,6 +7,9 @@ import InvoiceTab from './component/InvoiceTab';
import AttachmentsTab from './component/AttachmentsTab';
import ContactsInfoTab from './component/ContactsInfoTab';
import BankInfoTab from './component/BankInfoTab';
import PeBaseInfoTab from './component/PeBaseInfoTab';
import { coscoSupplierBase } from './services'
interface CompanyInfoProps {
viewType?: boolean;
@ -16,31 +19,53 @@ interface CompanyInfoProps {
const { TabPane } = Tabs;
const CompanyInfo: React.FC<CompanyInfoProps> = (props) => {
const { viewType = false, record = '999698' } = props;
const { viewType = false, record = '' } = props;
const intl = useIntl();
// 切换tab
const [subTab, setSubTab] = useState<string>('base');
const [subTab, setSubTab] = useState<string>('');
useEffect(() => {
coscoSupplierBase(record).then((res) => {
if (res.code === 200) {
if (res.data.coscoSupplierBase.supplierType === 'pe') {
setSubTab('pe')
} else {
setSubTab('base')
}
}
})
}, [record])
return (
<Tabs activeKey={subTab} onChange={setSubTab}>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.base' })} key="base">
<BaseInfoTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.qualification' })} key="qualification">
<QualificationTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.invoice' })} key="invoice">
<InvoiceTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.bank' })} key="bank">
<BankInfoTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.attachments' })} key="attachments">
<AttachmentsTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.contacts' })} key="contacts">
<ContactsInfoTab viewType={viewType} record={record} />
</TabPane>
{subTab === 'pe' ? (
<TabPane tab={intl.formatMessage({ id: 'page.workbench.base' })} key="pe">
<PeBaseInfoTab viewType={viewType} record={record} />
</TabPane>
) : (
<>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.base' })} key="base">
<BaseInfoTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.qualification' })} key="qualification">
<QualificationTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.invoice' })} key="invoice">
<InvoiceTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.bank' })} key="bank">
<BankInfoTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.attachments' })} key="attachments">
<AttachmentsTab viewType={viewType} record={record} />
</TabPane>
<TabPane tab={intl.formatMessage({ id: 'page.workbench.contacts' })} key="contacts">
<ContactsInfoTab viewType={viewType} record={record} />
</TabPane>
</>
)}
</Tabs>
);
};

View File

@ -5,7 +5,7 @@ import request from '@/utils/request';
/**
* 供应商基本信息
*/
export const coscoSupplierBase = (id: string) => request.get(`/coscoSupplierBase/${id? id: '999698'}`);
export const coscoSupplierBase = (id: string) => request.get(`/coscoSupplierBase/${id? id: '1942784565717565440'}`);
/**
* 资质分页列表

View File

@ -254,7 +254,9 @@ const bankColumns:ColumnsType<BankInfo> = [
label={intl.formatMessage({ id: 'component.globalModal.otherAttachmentLabel' })}
labelStyle={{ width: '200px' }}
>
<a href={registerInfo.coscoSupplierSurveyAttachments[1].fileUrl} target="_blank" rel="noreferrer">{intl.formatMessage({id: 'component.globalModal.viewAttachment'})}</a>
{ registerInfo.coscoSupplierSurveyAttachments[0].fileUrl && (
<a href={registerInfo.coscoSupplierSurveyAttachments[0].fileUrl} target="_blank" rel="noreferrer">{intl.formatMessage({id: 'component.globalModal.viewAttachment'})}</a>
)}
</Descriptions.Item>
</Descriptions>
</>

View File

@ -1,11 +1,12 @@
import React, { useEffect, useState } from 'react';
import { connect, useIntl } from 'umi';
import { Modal, Button, Space, Tag } from 'antd';
import { coscoSupplierBase } from './services'
import { Modal, Button, Space, Descriptions } from 'antd';
import { coscoSupplierBase } from './services'
import SupplierRegisterInfo from './components/SupplierRegisterInfo';
import AccessCategoryTable from './components/AccessCategoryTable';
import TianyanchaInfo from './components/TianyanchaInfo';
import RiskList from './components/RiskList';
// 弹出主体
const GlobalModal = ({ visible, id, dispatch }: any) => {
const intl = useIntl();
@ -14,14 +15,10 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
const [modalType, setModalType] = useState<'register' | 'category' | 'tianyancha' | 'risk'>('register');
//供应商信息数据
const [registerInfo, setRegisterInfo] = useState<any>(null);
//黑名单显示状态
const isBlacklisted = true;
//灰名单显示状态
const isGreylisted = true;
//获取供应商信息
const fetchRegisterInfo = () => {
//供应商信息
coscoSupplierBase(id).then((res) => {
let { code, data } = res;
if (code == 200) {
@ -35,7 +32,7 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
};
// 渲染页面 供应商信息 准入品类/品类库 天眼查工商信息 合规风险列表 页面标签
const renderContent = () => {
if (modalType === 'register') {
if (modalType === 'register' && registerInfo?.coscoSupplierBase) {
//供应商页面
return <SupplierRegisterInfo registerInfo={registerInfo} />;
}
@ -55,11 +52,9 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
};
// 初始化
useEffect(() => {
if (visible) {
setModalType('register');
fetchRegisterInfo();
coscoSupplierBase(id)
}
}, [visible, id]);
return (
@ -67,29 +62,55 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
visible={visible}
zIndex={1100}
width="90%"
onCancel={() => dispatch({ type: 'globalModal/hide' })}
onCancel={() => {
setRegisterInfo(null); // ← 清空数据
dispatch({ type: 'globalModal/hide' });
}}
footer={null}
title={
<div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
<span>{intl.formatMessage({id: 'component.globalModal.title' })}</span>
{/* <span style={{ marginLeft: '10px' }}>
{isBlacklisted && <Tag color="red">{intl.formatMessage({id: 'component.globalModal.blacklist' })}</Tag>}
{isGreylisted && <Tag color="gray">{intl.formatMessage({id: 'component.globalModal.GreyList' })}</Tag>}
</span> */}
<span>{intl.formatMessage({ id: 'component.globalModal.title' })}</span>
</div>
}
>
<div>
<Space style={{ marginBottom: 16 }}>
<Button type={modalType === 'register' ? 'primary' : 'default'} onClick={() => handleSwitch('register')}>{intl.formatMessage({id: 'component.globalModal.register' })}</Button>
<Button type={modalType === 'category' ? 'primary' : 'default'} onClick={() => handleSwitch('category')}>{intl.formatMessage({id: 'component.globalModal.category' })}</Button>
<Button type={modalType === 'tianyancha' ? 'primary' : 'default'} onClick={() => handleSwitch('tianyancha')}>{intl.formatMessage({id: 'component.globalModal.tianyancha' })}</Button>
<Button type={modalType === 'risk' ? 'primary' : 'default'} onClick={() => handleSwitch('risk')}>{intl.formatMessage({id: 'component.globalModal.ComplianceRisk' })}</Button>
</Space>
<div style={{ height: '600px', overflowY: 'auto' }}>
{renderContent()}
</div>
</div>
{(registerInfo?.coscoSupplierBase.supplierType !== 'pe' && registerInfo ) ?
(
<div>
<Space style={{ marginBottom: 16 }}>
<Button type={modalType === 'register' ? 'primary' : 'default'} onClick={() => handleSwitch('register')}>{intl.formatMessage({ id: 'component.globalModal.register' })}</Button>
<Button type={modalType === 'category' ? 'primary' : 'default'} onClick={() => handleSwitch('category')}>{intl.formatMessage({ id: 'component.globalModal.category' })}</Button>
<Button type={modalType === 'tianyancha' ? 'primary' : 'default'} onClick={() => handleSwitch('tianyancha')}>{intl.formatMessage({ id: 'component.globalModal.tianyancha' })}</Button>
<Button type={modalType === 'risk' ? 'primary' : 'default'} onClick={() => handleSwitch('risk')}>{intl.formatMessage({ id: 'component.globalModal.ComplianceRisk' })}</Button>
</Space>
<div style={{ height: '600px', overflowY: 'auto' }}>
{renderContent()}
</div>
</div>
) : (
<Descriptions bordered column={3} style={{ marginBottom: 24 }} title={intl.formatMessage({ id: 'component.globalModal.supplierRegisterInfo' })}>
<Descriptions.Item label="姓名" labelStyle={{ width: '140px' }}>
<span>{registerInfo?.coscoSupplierBase.personName}</span>
</Descriptions.Item>
<Descriptions.Item label="身份证号" labelStyle={{ width: '140px' }}>
<span>{registerInfo?.coscoSupplierBase.idCard}</span>
</Descriptions.Item>
<Descriptions.Item label="联系电话" labelStyle={{ width: '140px' }}>
<span>{registerInfo?.coscoSupplierBase.personPhone}</span>
</Descriptions.Item>
<Descriptions.Item label="开户行">
<span>{registerInfo?.coscoSupplierBase.personBank}</span>
</Descriptions.Item>
<Descriptions.Item label="银行账号">
<span>{registerInfo?.coscoSupplierBase.personAccount}</span>
</Descriptions.Item>
{/* <Descriptions.Item label="相关证照">
<span>{registerInfo?.coscoSupplierBase.accessory}</span>
</Descriptions.Item> */}
</Descriptions>
)
}
</Modal>
);
};