联系人

This commit is contained in:
孙景学
2025-07-18 10:37:13 +08:00
parent 90b8628eb8
commit 0d3088b8f8
13 changed files with 328 additions and 47 deletions

View File

@ -168,7 +168,7 @@ const InvoiceFormModal: React.FC<props> = ({
<Row gutter={24}>
<Col span={24}>
<Form.Item name="attachmentsType" label="附件类型" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入附件类型' />
</Form.Item>
</Col>
<Col span={24}>

View File

@ -161,22 +161,22 @@ const InvoiceFormModal: React.FC<props> = ({
<Row gutter={24}>
<Col span={24}>
<Form.Item name="account" label="开户账号" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开户账号' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="accountName" label="账户名称" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入账户名称' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="bank" label="开户银行" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开户银行' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="interbankNumber" label="联行号" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入联行号' />
</Form.Item>
</Col>

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, message, Row, Col, Descriptions } from 'antd';
import { coscoSupplierUserView, coscoSupplierUserAdd, coscoSupplierUserEdit } from '../services';
import { Modal, Form, Input, message, Row, Col, Descriptions, Tree } from 'antd';
//接口
import { coscoSupplierUserView, coscoSupplierUserAdd, coscoSupplierUserEdit, categoryTree } from '../services';
interface props {
visible: boolean;
@ -15,7 +15,10 @@ interface viewDataData {
contactsName?: string;
contactsPhone?: string;
contactsEmail?: string;
categoryName?: string;
categoryNameList?: string[];
}
const InvoiceFormModal: React.FC<props> = ({
visible,
onOk,
@ -28,7 +31,10 @@ const InvoiceFormModal: React.FC<props> = ({
const [form] = Form.useForm();
//查看
const [viewData, setViewData] = useState<viewDataData>({});
//品类选择
const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
//品类选择渲染数据
const [categoriesTreeData, setCategoriesTreeData] = useState([]);
useEffect(() => {
if (visible) {
if (initialValues) {
@ -38,11 +44,6 @@ const InvoiceFormModal: React.FC<props> = ({
const fields = {
...data,
id: data.id ? data.id : null,
address: [
Number(data.nation),
Number(data.province),
Number(data.city),
]
};
console.log(fields);
@ -53,9 +54,55 @@ const InvoiceFormModal: React.FC<props> = ({
} else {
form.resetFields();
}
categoryTree().then((res) => {
const { code, data } = res;
if (code == 200) {
setCategoriesTreeData(data)
}
})
}
}, [visible, initialValues]);
//品类选择数据中字段转换
const convertTreeData = (data: any) => {
return data.map((item: any) => ({
...item,
title: item.categoryName,
key: item.id,
children: item.children ? convertTreeData(item.children) : undefined,
}));
}
function findLeafKeys(treeData: any[]): string[] {
let leafKeys: string[] = [];
function dfs(nodes: any[]) {
nodes.forEach(node => {
if (!node.children || node.children.length === 0) {
leafKeys.push(node.key);
} else {
dfs(node.children);
}
});
}
dfs(treeData);
return leafKeys;
}
//品类选择
const onCheck = (
checkedKeysValue:
| React.Key[]
| { checked: React.Key[]; halfChecked: React.Key[] }
) => {
const keys = Array.isArray(checkedKeysValue)
? checkedKeysValue
: checkedKeysValue.checked;
// 只取叶子节点 key
const leafKeys = findLeafKeys(convertTreeData(categoriesTreeData));
const onlyLeafChecked = keys.filter(key => leafKeys.includes(String(key)));
setCheckedKeys(keys); // UI 显示用,还是全量
form.setFieldsValue({ categoryIdList: onlyLeafChecked }); // 只存叶子到表单
};
// 提交
const handleFinish = async () => {
try {
@ -64,6 +111,7 @@ const InvoiceFormModal: React.FC<props> = ({
...values,
supplierId: userId,
};
console.log(payload);
if (!values.id) {
coscoSupplierUserAdd(payload).then((res) => {
@ -106,13 +154,18 @@ const InvoiceFormModal: React.FC<props> = ({
<Descriptions.Item label="联系人姓名">{viewData.contactsName}</Descriptions.Item>
<Descriptions.Item label="联系人手机号">{viewData.contactsPhone}</Descriptions.Item>
<Descriptions.Item label="联系人邮箱">{viewData.contactsEmail}</Descriptions.Item>
<Descriptions.Item label="负责品类">
{viewData.categoryNameList && viewData.categoryNameList.map((item) => {
return <div>{item}</div>
})}
</Descriptions.Item>
</Descriptions>
) : (
<Form form={form} labelCol={{ flex: '120px' }} wrapperCol={{ flex: 1 }}>
<Row gutter={24}>
<Col span={24}>
<Form.Item name="contactsName" label="联系人姓名" rules={[{ required: true }]}>
<Input />
<Input placeholder="请输入联系人姓名" />
</Form.Item>
</Col>
<Col span={24}>
@ -121,7 +174,7 @@ const InvoiceFormModal: React.FC<props> = ({
{ required: true, message: '请输入联系人手机号码' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' },
]}>
<Input />
<Input placeholder="请输入联系人手机号" />
</Form.Item>
</Col>
<Col span={24}>
@ -130,7 +183,27 @@ const InvoiceFormModal: React.FC<props> = ({
{ type: 'email', message: '请输入有效的电子邮箱' },
{ required: true, message: '请输入电子邮箱' },
]}>
<Input />
<Input placeholder="请输入联系人邮箱" />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="categoryIdList" label="负责品类"
rules={[{ required: true }]}>
<Tree
checkable
selectable={false}
treeData={convertTreeData(categoriesTreeData)}
checkedKeys={checkedKeys}
onCheck={onCheck}
defaultExpandAll
style={{
maxHeight: 200,
overflowY: 'auto',
border: '1px solid #d9d9d9',
padding: 8,
borderRadius: 4,
}}
/>
</Form.Item>
</Col>

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Table, Button, message, Switch, Popconfirm } from 'antd';
import { Table, Button, message, Switch, Popconfirm, Tooltip } from 'antd';
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
import { getCoscoSupplierUserPage, editType, coscoSupplierUserDel } from '../services';
import { useIntl } from 'umi';
@ -17,6 +17,12 @@ interface getCoscoSupplierUser {
certificateUrl?: string;
delFlag: string;
type: string;
coscoSupplierUserCategoryList?: CoscoSupplierUserCategory[];
}
interface CoscoSupplierUserCategory {
categoryId:string;
categoryName:string;
supplierUserId:string;
}
interface Props {
@ -86,6 +92,7 @@ const OtherAttachmentsTab: React.FC<Props> = (props) => {
};
//是否为主联系人
const handleObsoleteChange = async (checked: boolean, id: string) => {
if(!checked) return
// 调用你的作废接口
const res = await editType({ id, supplierId: record });
if (res.code === 200) {
@ -124,6 +131,29 @@ const OtherAttachmentsTab: React.FC<Props> = (props) => {
dataIndex: 'contactsEmail',
key: 'contactsEmail',
},
{
title: '负责品类',
dataIndex: 'coscoSupplierUserCategoryList',
key: 'coscoSupplierUserCategoryList',
ellipsis: true,
width: 160,
render: (value: { categoryName: string }[] = []) => {
if (!value || value.length === 0) return '-';
if (value.length === 1) {
return <span>{value[0].categoryName}</span>;
}
// 多于1条
const allNames = value.map(item => item.categoryName).join('、');
return (
<Tooltip title={allNames} overlayStyle={{ zIndex: 1200 }}>
<span>
{value[0].categoryName}
<span></span>
</span>
</Tooltip>
);
},
},
{
title: '是否为主联系人',
@ -181,7 +211,7 @@ const OtherAttachmentsTab: React.FC<Props> = (props) => {
rowKey="id"
columns={columns.map(column => ({
...column,
title: intl.formatMessage({ id: column.title as string })
title: column.title
}))}
dataSource={data}
pagination={pagination}

View File

@ -201,35 +201,35 @@ const InvoiceFormModal: React.FC<props> = ({
</Col>
<Col span={24}>
<Form.Item name="taxpayerCode" label="纳税人识别号" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入纳税人识别号' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="phone" label="开票电话" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开票电话' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="account" label="开户行账号" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开户行账号' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="head" label="开票抬头" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开票抬头' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="address" label="开票地址" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开票地址' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="bank" label="开票开户行" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入开票开户行' />
</Form.Item>
</Col>

View File

@ -176,27 +176,27 @@ const QualificationFormModal: React.FC<QualificationFormModalProps> = ({
<Row gutter={24}>
<Col span={24}>
<Form.Item name="certificateType" label="资质证书类型" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入资质证书类型' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="name" label="资质名称" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入资质名称' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="code" label="资质证书编号" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入资质证书编号' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="typeLevel" label="资质类别和等级" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入资质类别和等级' />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="authority" label="发证机构" rules={[{ required: true }]}>
<Input />
<Input placeholder='请输入发证机构' />
</Form.Item>
</Col>
<Col span={24}>

View File

@ -276,7 +276,10 @@ export const editType = (data: editType) => request.post('/coscoSupplierUser/edi
export const coscoSupplierUserDel = (id: string) => request.delete(`/coscoSupplierUser/${id}`);
/**
* 品类选择查询树
*/
export const categoryTree = () => request.get('/cosco/category/categoryTree');

View File

@ -0,0 +1,122 @@
import React, { useEffect, useState } from 'react';
import { Table, Tooltip } from 'antd';
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
import { getCoscoSupplierUserPage } from '../services';
import { useIntl } from 'umi';
interface getCoscoSupplierUser {
id: string;
attachmentsType?: string;
fileName?: string;
filePath?: string;
fileSize?: string;
fileType?: string;
fileUrl?: string;
supplierId?: string;
certificateUrl?: string;
delFlag: string;
type: string;
}
interface Props {
id?: string;
}
const OtherAttachmentsTab: React.FC<Props> = ({id}) => {
//语言切换
const intl = useIntl();
//列表渲染数据
const [data, setData] = useState<getCoscoSupplierUser[]>([]);
//列表加载
const [loading, setLoading] = useState(false);
//列表分页
const [pagination, setPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 10, total: 0 });
//列表方法
const getList = async (pageNo = 1, pageSize = 10) => {
setLoading(true);
try {
const { code, data } = await getCoscoSupplierUserPage({ pageNo, pageSize, supplierId: id });
if (code === 200) {
setData(data.records);
setPagination({ current: pageNo, pageSize, total: data.total });
}
} finally {
setLoading(false);
}
};
//初始化
useEffect(() => {
if (id) {
getList();
}
}, [id]);
const columns: ColumnsType<getCoscoSupplierUser> = [
{
title: intl.formatMessage({ id: 'page.workbench.attachments.index' }),
render: (_: any, __: any, index: number) => index + 1,
width: 60,
},
{
title: '联系人',
dataIndex: 'contactsName',
key: 'contactsName',
},
{
title: '手机号',
dataIndex: 'contactsPhone',
key: 'contactsPhone',
},
{
title: '邮箱',
dataIndex: 'contactsEmail',
key: 'contactsEmail',
},
{
title: '负责品类',
dataIndex: 'coscoSupplierUserCategoryList',
key: 'coscoSupplierUserCategoryList',
ellipsis: true,
width: 160,
render: (value: { categoryName: string }[] = []) => {
if (!value || value.length === 0) return '-';
if (value.length === 1) {
return <span>{value[0].categoryName}</span>;
}
// 多于1条
const allNames = value.map(item => item.categoryName).join('、');
return (
<Tooltip title={allNames} overlayStyle={{ zIndex: 1200 }}>
<span>
{value[0].categoryName}
<span></span>
</span>
</Tooltip>
);
},
},
];
return (
<div style={{ padding: '0 30px 0 0' }}>
<Table
className="custom-table"
rowKey="id"
columns={columns.map(column => ({
...column,
title: intl.formatMessage({ id: column.title as string })
}))}
dataSource={data}
pagination={pagination}
loading={loading}
onChange={(pagination) => getList(pagination.current!, pagination.pageSize!)}
/>
</div>
);
};
export default OtherAttachmentsTab;

View File

@ -261,7 +261,12 @@ const SupplierRegisterInfo = ({ registerInfo }: { registerInfo: any }) => {
label={intl.formatMessage({ id: 'component.globalModal.antiBriberyLabel' })}
labelStyle={{ width: '200px' }}
>
<a href={registerInfo.coscoSupplierSurveyAttachments[0].fileUrl} target="_blank" rel="noreferrer">{intl.formatMessage({ id: 'component.globalModal.viewAttachment' })}</a>
{ registerInfo.coscoSupplierSurveyAttachments.map((item:any) => {
const { attachmentsType, fileUrl , fileName } = item;
return attachmentsType === 'commitment'? (
<a href={fileUrl} target="_blank" rel="noreferrer">{fileName}</a>
) :null
})}
</Descriptions.Item>
</Descriptions>
@ -276,9 +281,12 @@ const SupplierRegisterInfo = ({ registerInfo }: { registerInfo: any }) => {
label={intl.formatMessage({ id: 'component.globalModal.otherAttachmentLabel' })}
labelStyle={{ width: '200px' }}
>
{registerInfo.coscoSupplierSurveyAttachments[0].fileUrl && (
<a href={registerInfo.coscoSupplierSurveyAttachments[0].fileUrl} target="_blank" rel="noreferrer">{intl.formatMessage({ id: 'component.globalModal.viewAttachment' })}</a>
)}
{ registerInfo.coscoSupplierSurveyAttachments.map((item:any) => {
const { attachmentsType, fileUrl , fileName } = item;
return attachmentsType === 'accessory'? (
<a href={fileUrl} target="_blank" rel="noreferrer">{fileName}</a>
) :null
})}
</Descriptions.Item>
</Descriptions>
</>

View File

@ -2,13 +2,13 @@ import React, { useState, useEffect } from 'react';
import { Descriptions, Button, message } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import type { IntlShape } from 'react-intl';
import { getQuery } from '../services';
import { getQuery, getQueryAndUpdate } from '../services';
import { useIntl } from 'umi';
interface TianyanchaInfoProps {
base?: string; // 省份简称
name: string; // 企业名称
name?: string; // 企业名称
legalPersonName?: string; // 法人
legalPersonType?: string; // 法人类型 1 人 2 公司
regNumber?: string; // 注册号
@ -40,14 +40,31 @@ const TianyanchaInfo = ({ id }: { id: string }) => {
const intl = useIntl();
const [loading, setLoading] = useState(false);
const [dataList, setDataList] = useState<TianyanchaInfoProps[]>([]);
const [updateTime, setUpdateTime] = useState<string>(new Date().toLocaleDateString());
const [updateTime, setUpdateTime] = useState<string>('');
//列表
const getList = async () => {
setLoading(true);
try {
const { code, data } = await getQuery({ supplierId: id });
if (code === 200) {
if(data) {
setDataList(data);
setUpdateTime(new Date(Number(data.updateTimes)).toLocaleDateString());
}
}
} finally {
setLoading(false);
}
};
//更新
const getUpdateList = async () => {
setLoading(true);
try {
const { code, data } = await getQueryAndUpdate({ supplierId: id });
if (code === 200) {
setDataList(data);
setUpdateTime(new Date(Number(data.updateTimes)).toLocaleDateString());
}
} finally {
setLoading(false);
@ -56,12 +73,11 @@ const TianyanchaInfo = ({ id }: { id: string }) => {
const onUpdateTime = () => {
setUpdateTime(new Date().toLocaleDateString());
getList();
getUpdateList();
message.success(intl.formatMessage({ id: 'component.tianyancha.updateSuccess'}));
};
useEffect(() => {
if (id) {
setUpdateTime(new Date().toLocaleDateString());
getList();
}
}, [id]);

View File

@ -5,6 +5,7 @@ import { coscoSupplierBase } from './services'
import SupplierRegisterInfo from './components/SupplierRegisterInfo';
import AccessCategoryTable from './components/AccessCategoryTable';
import TianyanchaInfo from './components/TianyanchaInfo';
import ContactsInfo from './components/ContactsInfo';
import RiskList from './components/RiskList';
// 弹出主体
@ -12,7 +13,7 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
const intl = useIntl();
// 页面显示具体tab类型
const [modalType, setModalType] = useState<'register' | 'category' | 'tianyancha' | 'risk'>('register');
const [modalType, setModalType] = useState<'register' | 'category' | 'tianyancha' | 'risk' | 'ContactsInfo'>('register');
//供应商信息数据
const [registerInfo, setRegisterInfo] = useState<any>(null);
//获取供应商信息
@ -48,6 +49,10 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
//合规风险列表
return <RiskList id={id} />;
}
if (modalType === 'ContactsInfo') {
//合规风险列表
return <ContactsInfo id={id} />;
}
return null;
};
// 初始化
@ -81,6 +86,7 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
<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>
<Button type={modalType === 'ContactsInfo' ? 'primary' : 'default'} onClick={() => handleSwitch('ContactsInfo')}>{ '联系人' }</Button>
</Space>
<div style={{ height: '600px', overflowY: 'auto' }}>
{renderContent()}

View File

@ -2,12 +2,19 @@ import request from '@/utils/request';
/**
* 天眼查查询
* 天眼查查询
*/
interface getQuery {
supplierId: string;
}
export const getQuery = (params: getQuery) => request.get('/tycAndFxSupplierBase/queryAndUpdate', { params});
export const getQuery = (params: getQuery) => request.get('/tycAndFxSupplierBase/query', { params});
/**
* 天眼查更新
*/
interface getQuery {
supplierId: string;
}
export const getQueryAndUpdate = (params: getQuery) => request.get('/tycAndFxSupplierBase/queryAndUpdate', { params});
/**
@ -46,4 +53,15 @@ interface basePageRequests {
pageNo: number;
pageSize: number;
}
export const supplierIdPage = (data: supplierIdPage) => request.post('/cosco/library/supplierIdPage', { data });
export const supplierIdPage = (data: supplierIdPage) => request.post('/cosco/library/supplierIdPage', { data });
/**
* 联系人分页列表
*/
interface getCoscoSupplierUserPage {
pageNo: number;
pageSize: number;
supplierId?: string;
}
export const getCoscoSupplierUserPage = (data: getCoscoSupplierUserPage) => request.post('/coscoSupplierUser/getPage', { data });

View File

@ -146,9 +146,14 @@ const SupplierAddModal: React.FC<{
}
}
apply({ categoryLibraryId: storeId, supplierIds: selectedIds, ...values })
setSelectedIds([]);
onSuccess && onSuccess();
apply({ categoryLibraryId: storeId, supplierIds: selectedIds, ...values }).then((res) => {
if(res.code == 200) {
message.success('操作成功');
setSelectedIds([]);
onSuccess && onSuccess();
}
})
};
// 自定义上传