From 4acff1e030f932430126759611cbb982fde425ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AD=99=E6=99=AF=E5=AD=A6?=
<5412262+sun_jing_xue@user.noreply.gitee.com>
Date: Thu, 7 Aug 2025 09:22:49 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A4=A9=E7=9C=BC=E6=9F=A5=E4=B8=8E=E5=87=86?=
=?UTF-8?q?=E5=85=A5=E5=AE=A1=E6=A0=B8=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
config/router.config.ts | 4 +
src/app.ts | 2 +-
src/components/GlobalModal/index.tsx | 54 ++-
.../SupplierDetail.tsx | 50 ++-
.../ViewReviewPage/GlobalModal/_mock.ts | 277 +++++++++++++
.../components/AccessCategoryTable.tsx | 210 ++++++++++
.../GlobalModal/components/ContactsInfo.tsx | 122 ++++++
.../GlobalModal/components/RiskList.tsx | 87 ++++
.../components/SupplierRegisterInfo.tsx | 384 ++++++++++++++++++
.../GlobalModal/components/TianyanchaInfo.tsx | 136 +++++++
.../ViewReviewPage/GlobalModal/index.tsx | 142 +++++++
.../ViewReviewPage/GlobalModal/services.ts | 67 +++
.../ViewReviewPage/components/ResultModal.tsx | 263 ++++++++++++
.../ViewReviewPage/components/ViewModal.tsx | 161 ++++++++
src/pages/supplier/ViewReviewPage/index.tsx | 41 ++
src/pages/supplier/ViewReviewPage/services.ts | 126 ++++++
16 files changed, 2085 insertions(+), 41 deletions(-)
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/_mock.ts
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/components/AccessCategoryTable.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/components/ContactsInfo.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/components/RiskList.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/components/SupplierRegisterInfo.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/components/TianyanchaInfo.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/index.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/GlobalModal/services.ts
create mode 100644 src/pages/supplier/ViewReviewPage/components/ResultModal.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/components/ViewModal.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/index.tsx
create mode 100644 src/pages/supplier/ViewReviewPage/services.ts
diff --git a/config/router.config.ts b/config/router.config.ts
index 613fdf2..c2e577a 100644
--- a/config/router.config.ts
+++ b/config/router.config.ts
@@ -3,6 +3,10 @@ export default [
path: '/login',
component: '@/pages/login/login',
},
+ {
+ path: '/ViewReviewPage',
+ component: '@/pages/supplier/ViewReviewPage/index',
+ },
{
path: '/register',
routes: [
diff --git a/src/app.ts b/src/app.ts
index b2f304e..81ea0d6 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -2,7 +2,7 @@ import { history } from 'umi';
export function onRouteChange({ location }: any) {
const token = sessionStorage.getItem('token');
- const whiteList = ['/login', '/forgot', '/register/supplier', '/register/expert', '/403', '/404'];
+ const whiteList = ['/login', '/forgot', '/register/supplier', '/register/expert', '/403', '/404', '/ViewReviewPage'];
if (!token && !whiteList.includes(location.pathname)) {
history.replace('/login');
}
diff --git a/src/components/GlobalModal/index.tsx b/src/components/GlobalModal/index.tsx
index a074840..9aec395 100644
--- a/src/components/GlobalModal/index.tsx
+++ b/src/components/GlobalModal/index.tsx
@@ -78,7 +78,7 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
}
>
- {(registerInfo?.coscoSupplierBase.supplierType !== 'pe' && registerInfo ) ?
+ {(registerInfo?.coscoSupplierBase.supplierType !== 'pe' && registerInfo) ?
(
@@ -86,33 +86,43 @@ const GlobalModal = ({ visible, id, dispatch }: any) => {
-
+
{renderContent()}
) : (
-
-
- {registerInfo?.coscoSupplierBase.personName}
-
-
- {registerInfo?.coscoSupplierBase.idCard}
-
-
- {registerInfo?.coscoSupplierBase.personPhone}
-
-
- {registerInfo?.coscoSupplierBase.personBank}
-
-
- {registerInfo?.coscoSupplierBase.personAccount}
-
- {/*
- {registerInfo?.coscoSupplierBase.accessory}
- */}
-
+
+
+
+
+
+
+ {modalType === 'category' && (
+
+ )}
+ {modalType === 'register' && (
+
+
+ {registerInfo?.coscoSupplierBase?.personName}
+
+
+ {registerInfo?.coscoSupplierBase?.idCard}
+
+
+ {registerInfo?.coscoSupplierBase?.personPhone}
+
+
+ {registerInfo?.coscoSupplierBase?.personBank}
+
+
+ {registerInfo?.coscoSupplierBase?.personAccount}
+
+
+ )}
+
+
)
}
diff --git a/src/components/SupplierDetailModalContext/SupplierDetail.tsx b/src/components/SupplierDetailModalContext/SupplierDetail.tsx
index 6c4b8ec..aa0e1bf 100644
--- a/src/components/SupplierDetailModalContext/SupplierDetail.tsx
+++ b/src/components/SupplierDetailModalContext/SupplierDetail.tsx
@@ -73,30 +73,44 @@ const SupplierDetail: React.FC = ({ supplierId }) => {
-
+
{renderContent()}
) : (
-
-
- {registerInfo?.coscoSupplierBase?.personName}
-
-
- {registerInfo?.coscoSupplierBase?.idCard}
-
-
- {registerInfo?.coscoSupplierBase?.personPhone}
-
-
- {registerInfo?.coscoSupplierBase?.personBank}
-
-
- {registerInfo?.coscoSupplierBase?.personAccount}
-
-
+
+
+
+
+
+
+ { modalType === 'category' && (
+
+ ) }
+ {modalType === 'register' && (
+
+
+ {registerInfo?.coscoSupplierBase?.personName}
+
+
+ {registerInfo?.coscoSupplierBase?.idCard}
+
+
+ {registerInfo?.coscoSupplierBase?.personPhone}
+
+
+ {registerInfo?.coscoSupplierBase?.personBank}
+
+
+ {registerInfo?.coscoSupplierBase?.personAccount}
+
+
+ )}
+
+
+
)
);
};
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/_mock.ts b/src/pages/supplier/ViewReviewPage/GlobalModal/_mock.ts
new file mode 100644
index 0000000..2d67325
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/_mock.ts
@@ -0,0 +1,277 @@
+import { Request, Response } from 'express';
+
+// const data = [
+// {
+// title: 'Name',
+// dataIndex: '评审项',
+// key: '评审项',
+// },
+// {
+// title: 'Other',
+// children: [
+// {
+// title: 'Age',
+// key: '人员A',
+// },
+// {
+// title: 'Address',
+// key: '人员B',
+// },
+// ]
+// },
+// ]
+
+
+export const mockData = {
+ base: {
+ "id": "123456",
+ "supplierType": "dvs",
+ "licenceAccessory": "https://example.com/license.pdf",
+ "licenceDate": "2025-12-31",
+ "enterpriseType": "company",
+ "name": "深圳供应商有限公司",
+ "nameEn": "Shenzhen Supplier Co., Ltd.",
+ "socialCreditCode": "91440300MA5F3XXXXQ",
+ "range": "电子元器件、金属材料销售",
+ "regAddress": "广东省深圳市南山区科技园",
+ "workAddress": "广东省深圳市南山区软件产业基地",
+ "parentCompanyInvestor": "深圳控股集团有限公司",
+ "legalPerson": "李四",
+ "idCard": "440301199001015678",
+ "capital": 5000,
+ "contactsName": "王五",
+ "contactsPhone": "13800138000",
+ "contactsType": "法人代表",
+ "contactsEmail": "contact@supplier.com",
+ "telephone": "0755-12345678",
+ "nation": "新加坡",
+ "vat": "SG12345678VAT",
+ "taxpayerId": "SG-TAX-998877",
+ "currency": "SGD",
+ "personName": "张三",
+ "personPhone": "13812345678",
+ "personBank": "中国银行深圳分行",
+ "personAccount": "6222020200123456789",
+ "remark": "该供应商已完成初步审核",
+ "accessStatus": 1,
+ "blacklistStatus": 0,
+ "greylistStatus": 1,
+ "fillinStatus": 0,
+ "fillinBy": "",
+ "sapCode": "SAP998877",
+ "delFlag": "normal",
+ "createBy": "admin",
+ "createTime": "2024-06-01 10:00:00",
+ "updateBy": "admin",
+ "updateTime": "2025-06-01 11:00:00",
+ "lastUpdateTime": "2025-06-17 09:30:00"
+ },
+ qualifications: [{
+ "id": "cert-001",
+ "supplierId": "supplier-123456",
+ "certificateType": "安全生产许可证",
+ "name": "建筑施工总承包一级资质",
+ "code": "ZJ20230605001",
+ "typeLevel": "一级",
+ "authority": "住房和城乡建设部",
+ "dateTime": "2023-06-05",
+ "termOfValidity": "2026-06-05",
+ "accessory": "https://example.com/certificate.pdf",
+ "delFlag": "normal",
+ "createBy": "admin",
+ "createTime": "2023-06-01 10:00:00",
+ "updateBy": "admin",
+ "updateTime": "2024-06-01 11:00:00",
+ "lastUpdateTime": "2025-06-17 09:30:00"
+ }],
+ invoice: {
+ "id": "invoice-001",
+ "supplierId": "supplier-123456",
+ "taxpayerType": "general",
+ "taxpayerCode": "91440300MA5F3XXXXQ",
+ "phone": "0755-12345678",
+ "account": "6222020200123456789",
+ "head": "深圳供应商有限公司",
+ "address": "深圳市南山区科技园开票楼101号",
+ "bank": "中国银行深圳分行",
+ "qualificationCertificate": "https://example.com/tax-cert.pdf",
+ "delFlag": "normal",
+ "createBy": "admin",
+ "createTime": "2024-06-01 09:00:00",
+ "updateBy": "admin",
+ "updateTime": "2025-06-01 10:00:00",
+ "lastUpdateTime": "2025-06-17 08:30:00"
+ },
+ bank: [{
+ "id": "bank-001",
+ "supplierId": "supplier-123456",
+ "interbankNumber": "123456789012",
+ "bank": "中国银行深圳分行",
+ "swiftCode": "BKCHCNBJ45A",
+ "accountName": "Shenzhen Supplier Co., Ltd.",
+ "account": "6222020200123456789",
+ "currency": "CNY",
+ "nation": "中国",
+ "province": "广东省",
+ "city": "深圳市",
+ "delFlag": "normal",
+ "createBy": "admin",
+ "createTime": "2024-06-01 09:00:00",
+ "updateBy": "admin",
+ "updateTime": "2025-06-01 10:00:00",
+ "lastUpdateTime": "2025-06-17 08:30:00"
+ }],
+ survey: {
+ "supplierName": "深圳供应商有限公司",
+ "name": "李四",
+ "position": "采购经理",
+ "phone": "13800138000",
+ "email": "lisi@supplier.com",
+ "dateTime": "2025-06-17",
+ },
+ questionReply: [
+ {
+ "surveyQuestion": "法律法规:\n我们确保经营和提供的产品服务遵守国家及 各业务所在地的所有使用法律、法规",
+ "replyValue": "是",
+ },{
+ "surveyQuestion": "健康和安全:\n我们为员工提供符合法律法规的安全且健康 的工作场所。我们建立安全管理体系,并向 员工传达工作场所或生活设施的健康和安全 标准,致力于减少工作对员工造成的伤害和 疾病。",
+ "replyValue": "符合",
+ },{
+ "surveyQuestion": "环境:\n我们能够以环境友好的方式经营。我们遵守 适用的环境法律、法规和标准;并建立有效 的环境管理体系。\n我们遵守贵集团对相关产品或服务的部分附 加环境要求,这些要求和规定体现在设计与 产品规范的合同文档中。",
+ "replyValue": "符合",
+ },{
+ "surveyQuestion": "监督和记录:\n我们保留记录遵守相关法律和此行为准则的必要文件,并根据要求为贵集团提供对文件的查看权。我们会允许贵集团在适当的时候,以验证行为准则执行为目的的现场勘查",
+ "replyValue": "符合",
+ }
+ ],
+ attachments: {
+ "attachmentsType": "commitment",
+ "fileName": "anti-bribery-commitment.pdf",
+ "fileType": "pdf",
+ "fileSize": "204800",
+ "filePath": "/data/files/anti-bribery-commitment.pdf",
+ "fileUrl": "http://example.com/files/anti-bribery-commitment.pdf",
+ }
+};
+// 代码中会兼容本地 service mock 以及部署站点的静态数据
+export default {
+ // 供应商信息
+ 'GET /api/system/coscoSupplier': (req: Request, res: Response) => {
+ res.json({ code: 200, data: mockData, msg: '操作成功' });
+ },
+
+ //品类库
+ 'GET /api/system/library': (req: Request, res: Response) => {
+ res.json({ code: 200,
+ data: [
+ {
+ "name": "电子元器件类",
+ "termOfValidity": "2026-12-31T00:00:00",
+ "deptId": "dept_001",
+ "area": "华东区域",
+ "approveStatus": 1,
+ "workFlowId": "wf_20250601",
+ "delFlag": "normal",
+ "createBy": "admin",
+ "createTime": "2025-06-17T09:00:00",
+ "updateBy": "admin",
+ "updateTime": "2025-06-17T10:30:00",
+ "lastUpdateTime": "2025-06-17T10:30:00"
+ },
+ {
+ "name": "建筑材料类",
+ "termOfValidity": "2025-09-30T00:00:00",
+ "deptId": "dept_002",
+ "area": "华南区域",
+ "approveStatus": 0,
+ "workFlowId": "wf_20250602",
+ "delFlag": "normal",
+ "createBy": "system",
+ "createTime": "2025-06-10T08:20:00",
+ "updateBy": "reviewer",
+ "updateTime": "2025-06-15T15:45:00",
+ "lastUpdateTime": "2025-06-15T15:45:00"
+ }
+ ],
+ total: 2,
+ msg: '操作成功' });
+ },
+ //
+ 'GET /api/system/tianyancha': (req: Request, res: Response) => {
+ res.json({ code: 200,
+ data: [
+ {
+ key: '1',
+ base: '京',
+ name: '北京科技有限公司',
+ legalPersonName: '张三',
+ legalPersonType: '1',
+ regNumber: '110108123456789',
+ industry: '信息技术',
+ companyOrgType: '有限责任公司',
+ regLocation: '北京市海淀区中关村',
+ estiblishTime: '2010-06-15',
+ fromTime: '2010-06-16',
+ toTime: '2025-06-15',
+ businessScope: '软件开发、技术咨询',
+ approvedTime: '2010-06-10',
+ regStatus: '存续',
+ regCapital: '5000万元',
+ regInstitute: '北京市工商局',
+ orgNumber: '1234567890',
+ creditCode: '91110108MA01A12345',
+ property3: 'Beijing Tech Co., Ltd.',
+ updatetime: '2025-06-15',
+ companyId: '1001',
+ taxNumber: '110108123456789',
+ email: 'contact@bjtech.com',
+ website: 'http://www.bjtech.com',
+ phoneNumber: '010-12345678',
+ lastUpdateTime: '2025-06-15 10:00:00',
+ },
+ {
+ key: '2',
+ base: '沪',
+ name: '上海电子商务有限公司',
+ legalPersonName: '李四',
+ legalPersonType: '1',
+ regNumber: '310101987654321',
+ industry: '电子商务',
+ companyOrgType: '股份有限公司',
+ regLocation: '上海市浦东新区',
+ estiblishTime: '2015-03-20',
+ fromTime: '2015-03-21',
+ toTime: '2030-03-20',
+ businessScope: '电子商务平台运营、广告设计',
+ approvedTime: '2015-03-15',
+ regStatus: '存续',
+ regCapital: '1亿元',
+ regInstitute: '上海市工商局',
+ orgNumber: '0987654321',
+ creditCode: '91310101MA1AB23456',
+ property3: 'Shanghai E-commerce Co., Ltd.',
+ updatetime: '2025-06-15',
+ companyId: '1002',
+ taxNumber: '310101987654321',
+ email: 'info@shcommerce.com',
+ website: 'http://www.shcommerce.com',
+ phoneNumber: '021-87654321',
+ lastUpdateTime: '2025-06-15 09:30:00',
+ },
+ ],
+ total: 2,
+ msg: '操作成功' });
+ },
+
+ 'GET /api/500': (req: Request, res: Response) => {
+ res.status(500).send({
+ timestamp: 1513932555104,
+ status: 500,
+ error: 'error',
+ message: 'error',
+ path: '/base/category/list',
+ });
+ },
+
+
+};
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/components/AccessCategoryTable.tsx b/src/pages/supplier/ViewReviewPage/GlobalModal/components/AccessCategoryTable.tsx
new file mode 100644
index 0000000..5da0bd8
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/components/AccessCategoryTable.tsx
@@ -0,0 +1,210 @@
+import React, { useEffect, useState } from 'react';
+import { Table, Tabs, message } from 'antd';
+import { useIntl } from 'umi';
+import { getCategoryPage, supplierIdPage } from '../services';
+// 类型定义
+import type { ColumnsType } from 'antd/es/table';
+
+//统一列表分页
+import tableProps from '@/utils/tableProps'
+const { TabPane } = Tabs;
+interface Data {
+ id: number;
+ storeName: string;
+ category: string;
+ region: string;
+ unit: string;
+ owner: string;
+ validTo: string;
+ supplierCount: number;
+}
+const AccessCategoryTable = ({id}:{id:string}) => {
+ const intl = useIntl();
+ const columns = [
+ {
+ title: '准入单位',
+ dataIndex: 'orgName',
+ key: 'orgName',
+ ellipsis: true
+ },
+ {
+ title: '准入部门',
+ dataIndex: 'deptName',
+ key: 'deptName',
+ ellipsis: true
+ },
+ {
+ title: '准入品类',
+ dataIndex: 'categoryName',
+ key: 'categoryName',
+ },
+ {
+ title: '准入时间',
+ dataIndex: 'updateTime',
+ key: 'updateTime',
+ },
+ {
+ title: '退出时间',
+ dataIndex: 'exitTime',
+ key: 'exitTime',
+ },
+ {
+ title: '退出原因',
+ dataIndex: 'exitReason',
+ key: 'exitReason',
+ ellipsis: true,
+ width: 120,
+ }
+ ]
+ //品类
+ const categoryColumns: ColumnsType = [
+ {
+ title: '品类库名称',
+ dataIndex: 'name',
+ key: 'name',
+ align: 'center',
+ ellipsis: true,
+ },
+ {
+ title: '品类',
+ dataIndex: 'categoryNames',
+ key: 'categoryNames',
+ align: 'center',
+ width: 100,
+ ellipsis: true,
+ },
+ {
+ title: '区域',
+ dataIndex: 'area',
+ key: 'area',
+ align: 'center',
+ ellipsis: true,
+ },
+ {
+ title: '创建单位',
+ dataIndex: 'deptName',
+ key: 'deptName',
+ align: 'center',
+ ellipsis: true,
+ },
+ {
+ title: '负责人',
+ dataIndex: 'createName',
+ key: 'createName',
+ align: 'center',
+ },
+ {
+ title: '有效期至',
+ dataIndex: 'termOfValidity',
+ key: 'termOfValidity',
+ align: 'center',
+ ellipsis: true,
+ },
+ ]
+
+ //Tabs切换key
+ const [activeKey, setActiveKey] = useState<'access' | 'category'>('access');
+
+ //准入品类
+ const [accessData, setAccessData] = useState([]);
+ //分页
+ const [accessPagination, setAccessPagination] = useState({ current: 1, pageSize: 10, total: 0 });
+ //加载
+ const [accessLoading, setAccessLoading] = useState(false);
+
+ //品类库
+ const [categoryData, setCategoryData] = useState([]);
+ //分页
+ const [categoryPagination, setCategoryPagination] = useState({ current: 1, pageSize: 10, total: 0 });
+ //加载
+ const [categoryLoading, setCategoryLoading] = useState(false);
+ // 准入品类
+ const fetchAccessData = async (current: number, pageSize: number) => {
+ setAccessLoading(true);
+ try {
+ const { code, data } = await getCategoryPage({ pageNo: current, pageSize, supplierId:id });
+ if (code === 200) {
+ setAccessData(data.records);
+ setAccessPagination({ current, pageSize, total: data.total });
+ }
+ } catch {
+ message.error(intl.formatMessage({id:'component.globalModal.FailedToObtainAdmissionCategory'}));
+
+ } finally {
+ setAccessLoading(false);
+ }
+ };
+ //品类库
+ const fetchCategoryData = async (current: number, pageSize: number) => {
+ setCategoryLoading(true);
+ try {
+ const { code, data } = await supplierIdPage({ basePageRequest: { pageNo: current, pageSize } , supplierId: id });
+ if (code === 200) {
+ setCategoryData(data.records);
+ setCategoryPagination({ current, pageSize, total: data.total });
+ }
+ } catch {
+ message.error(intl.formatMessage({id:'component.globalModal.FailedToObtainCategoryLibrary'}));
+ } finally {
+ setCategoryLoading(false);
+ }
+ };
+ //初始化
+ useEffect(() => {
+ if (activeKey === 'access') {
+ fetchAccessData(accessPagination.current, accessPagination.pageSize);
+ } else {
+ fetchCategoryData(categoryPagination.current, categoryPagination.pageSize);
+ }
+ }, [activeKey, id])
+ return (
+ setActiveKey(key as 'access' | 'category')} >
+
+ fetchAccessData(page, pageSize),
+ // }}
+ pagination={{...tableProps.pagination, total: accessPagination.total }}
+ onChange={(pagination) => {
+ fetchCategoryData( pagination.current!, pagination.pageSize!)
+ }}
+ style={{ flex: 1, minHeight: 0 }}
+ scroll={{ y: 'calc(100vh - 350px)' }}
+ />
+
+
+
+ fetchCategoryData(page, pageSize),
+ // }}
+
+ pagination={{...tableProps.pagination, total: categoryPagination.total }}
+ onChange={(pagination) => {
+ fetchCategoryData( pagination.current!, pagination.pageSize!)
+ }}
+ style={{ flex: 1, minHeight: 0 }}
+ scroll={{ y: 'calc(100vh - 350px)' }}
+ />
+
+
+ );
+};
+
+export default AccessCategoryTable;
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/components/ContactsInfo.tsx b/src/pages/supplier/ViewReviewPage/GlobalModal/components/ContactsInfo.tsx
new file mode 100644
index 0000000..d758b82
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/components/ContactsInfo.tsx
@@ -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 = ({ id }) => {
+ //语言切换
+ const intl = useIntl();
+ //列表渲染数据
+ const [data, setData] = useState([]);
+ //列表加载
+ const [loading, setLoading] = useState(false);
+ //列表分页
+ const [pagination, setPagination] = useState({ 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 = [
+ {
+ 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; categoryPathName: string }[] = []) => {
+ if (!value || value.length === 0) return '-';
+
+ // 多于1条
+ const allNames = value.map(item => item.categoryPathName).join('\n');
+ return (
+ {allNames}} overlayStyle={{ zIndex: 1200 }}>
+
+ {value[0].categoryName}
+ {value.length !== 1 && (
+ 等
+ )}
+
+
+ );
+ },
+ },
+
+ ];
+ return (
+
+
({
+ ...column,
+ title: column.title
+ }))}
+ dataSource={data}
+ pagination={pagination}
+ loading={loading}
+ onChange={(pagination) => getList(pagination.current!, pagination.pageSize!)}
+ />
+
+
+ );
+};
+
+export default OtherAttachmentsTab;
\ No newline at end of file
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/components/RiskList.tsx b/src/pages/supplier/ViewReviewPage/GlobalModal/components/RiskList.tsx
new file mode 100644
index 0000000..f3897be
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/components/RiskList.tsx
@@ -0,0 +1,87 @@
+import React, { useEffect, useState } from 'react';
+import { Descriptions, message } from 'antd';
+import { queryRiskInfo } from '../services'
+import { useIntl } from 'umi';
+import type { ColumnsType } from 'antd/es/table';
+
+interface data {
+ hit: string;
+ countries: string;
+ d1: string;
+ d2: string;
+ [key: string]: any;
+}
+
+
+const RiskList = ({ id }: { id: string }) => {
+ const intl = useIntl();
+ const columns: ColumnsType = [
+ {
+ title: intl.formatMessage({ id: 'component.globalModal.hit', defaultMessage: '命中对象' }),
+ dataIndex: 'hit',
+ key: 'hit',
+ },
+ {
+ title: intl.formatMessage({ id: 'component.globalModal.countries', defaultMessage: '涉及国家/地区' }),
+ dataIndex: 'countries', // 推荐拼写为 countries
+ key: 'countries',
+ },
+ {
+ title: intl.formatMessage({ id: 'component.globalModal.riskD1', defaultMessage: '风险主类' }),
+ dataIndex: 'd1',
+ key: 'd1',
+ },
+ {
+ title: intl.formatMessage({ id: 'component.globalModal.riskD2', defaultMessage: '风险分类' }),
+ dataIndex: 'd2',
+ key: 'd2',
+ },
+ ]
+ //合规风险
+ const [dataList, setDataList] = useState([])
+ //加载 const [loading, setLoading] = useState(false);
+
+ //分页
+
+ //数据渲染
+ const getList = async () => {
+ // setLoading(true);
+ try {
+ const { code, data } = await queryRiskInfo({ supplierId: id });
+ if (code === 200) {
+ setDataList(data);
+ } else {
+ message.error(intl.formatMessage({ id: 'component.globalModal.fetchRiskFail' }));
+ }
+ } catch (error) {
+ message.error(intl.formatMessage({ id: 'component.globalModal.apiError' }));
+ } finally {
+ // setLoading(false);
+ }
+ };
+ //初始化
+ useEffect(() => {
+ if (id) {
+ getList();
+ }
+ }, [id]);
+
+ return (
+ <>
+ {
+ dataList.map((item, idx) => (
+
+ {columns.map(col => (
+
+ {item[(col as any).dataIndex] ?? '-'}
+
+ ))}
+
+ ))
+ }
+
+ >
+ );
+};
+
+export default RiskList;
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/components/SupplierRegisterInfo.tsx b/src/pages/supplier/ViewReviewPage/GlobalModal/components/SupplierRegisterInfo.tsx
new file mode 100644
index 0000000..6c0f13b
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/components/SupplierRegisterInfo.tsx
@@ -0,0 +1,384 @@
+import React, { useEffect, useState } from 'react';
+import { Descriptions, Table, Spin } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+import { useIntl } from 'umi';
+import { getDictList } from '@/servers/api/dicts';
+import { dictRegion } from '@/servers/api/user'
+interface qualifications {
+ id: string; // 主键ID(如后续用于 rowKey)
+ certificateType: string; // 资质证书类型
+ name: string; // 资质名称
+ code: string; // 资质证书编号
+ typeLevel: string; // 资质类别和等级
+ authority: string; // 发证机构
+ dateTime: string; // 发证日期(如用 Date 类型可改成 Date)
+ termOfValidity: string; // 资质有效期至
+ accessory?: string; // 附件文件url,可能为空
+}
+interface BankInfo {
+ interbankNumber: string;
+ bank: string;
+ accountName: string;
+ account: string;
+ currency: string;
+ nation: string;
+ province: string;
+ city: string;
+}
+const codeNameCache = new Map();
+const fetchRegionNames = async (codes: string[]) => {
+ const waitCodes = codes.filter(code => code && !codeNameCache.has(code));
+ if (waitCodes.length === 0) return;
+ // 批量接口推荐你后端支持,单个请求也兼容如下
+ await Promise.all(waitCodes.map(async (code) => {
+ try {
+ const { code: status, data } = await dictRegion(code);
+ if (status === 200 && data && data.name) {
+ codeNameCache.set(code, data.name);
+ }
+ } catch { /* ignore */ }
+ }));
+};
+
+const SupplierRegisterInfo = ({ registerInfo }: { registerInfo: any }) => {
+ //币种
+ const [currencyMap, setCurrencyMap] = useState<{ [code: string]: string }>({});
+ const [enterpriseTypeMap, setEnterpriseTypeMap] = useState<{ [code: string]: string }>({});
+
+ const [contactsTypeMap, setContactsTypeMap] = useState<{ [code: string]: string }>({});
+ const [taxpayerTypeMap, setTaxpayerTypeMap] = useState<{ [code: string]: string }>({});
+ const [regionLoading, setRegionLoading] = useState(false);
+ const [, forceUpdate] = useState({}); // 用于触发重新渲染
+
+ useEffect(() => {
+ getDictList('currency').then((res) => {
+ if (res.code === 200) {
+ const map: { [code: string]: string } = {};
+ res.data.forEach((item: { code: string, dicName: string }) => {
+ map[item.code] = item.dicName;
+ });
+ setCurrencyMap(map);
+ }
+ });
+ getDictList('taxpayer_type').then((res) => {
+ if (res.code == 200) {
+ const map: { [code: string]: string } = {};
+ res.data.forEach((item: { code: string, dicName: string }) => {
+ map[item.code] = item.dicName;
+ });
+ setTaxpayerTypeMap(map);
+ }
+ })
+ getDictList('contacts_type').then((res) => {
+ if (res.code === 200) {
+ const map: { [code: string]: string } = {};
+ res.data.forEach((item: { code: string, dicName: string }) => {
+ map[item.code] = item.dicName;
+ });
+ setContactsTypeMap(map);
+ }
+ });
+
+ getDictList('enterprise_type').then((res) => {
+ if (res.code === 200) {
+ const map: { [code: string]: string } = {};
+ res.data.forEach((item: { code: string, dicName: string }) => {
+ map[item.code] = item.dicName;
+ });
+ setEnterpriseTypeMap(map);
+ }
+ });
+
+ }, []);
+ useEffect(() => {
+ if (!Array.isArray(registerInfo?.coscoSupplierBank)) return;
+ // 收集所有 code
+ const codes: string[] = [];
+ registerInfo.coscoSupplierBank.forEach((item: BankInfo) => {
+ if (item.nation) codes.push(item.nation);
+ if (item.province) codes.push(item.province);
+ if (item.city) codes.push(item.city);
+ });
+ setRegionLoading(true);
+ fetchRegionNames(codes).then(() => {
+ setRegionLoading(false);
+ forceUpdate({});
+ });
+ }, [registerInfo?.coscoSupplierBank]);
+ // 通用渲染
+ const renderRegionName = (code: string) => {
+ if (!code) return '';
+ if (codeNameCache.has(code)) {
+ return codeNameCache.get(code);
+ }
+ return ;
+ };
+
+ const intl = useIntl();
+ const qualificationsColumns: ColumnsType = [
+ { title: intl.formatMessage({ id: 'component.globalModal.serialNumber' }), dataIndex: 'index', key: 'index', width: 60, align: 'center', render: (_: any, __: any, index: number) => index + 1 },
+ { title: intl.formatMessage({ id: 'component.globalModal.certificateType' }), dataIndex: 'certificateType', key: 'certificateType' },
+ { title: intl.formatMessage({ id: 'component.globalModal.certificateName' }), dataIndex: 'name', key: 'name' },
+ { title: intl.formatMessage({ id: 'component.globalModal.certificateNumber' }), dataIndex: 'code', key: 'code' },
+ { title: intl.formatMessage({ id: 'component.globalModal.certificateCategoryLevel' }), dataIndex: 'typeLevel', key: 'typeLevel' },
+ { title: intl.formatMessage({ id: 'component.globalModal.issuingAuthority' }), dataIndex: 'authority', key: 'authority' },
+ { title: intl.formatMessage({ id: 'component.globalModal.issueDate' }), dataIndex: 'dateTime', key: 'dateTime' },
+ { title: intl.formatMessage({ id: 'component.globalModal.validUntil' }), dataIndex: 'termOfValidity', key: 'termOfValidity' },
+ { title: intl.formatMessage({ id: 'component.globalModal.attachment' }), dataIndex: 'accessory', key: 'accessory', render: (text: any) => text ? 查看附件 : '-' },
+ ];
+ const bankColumns: ColumnsType = [
+ { title: intl.formatMessage({ id: 'component.globalModal.serialNumber' }), dataIndex: 'index', key: 'index', width: 60, align: 'center', render: (_: any, __: any, index: number) => index + 1 },
+ { title: intl.formatMessage({ id: 'component.globalModal.bankCode' }), dataIndex: 'interbankNumber', key: 'interbankNumber' },
+ { title: intl.formatMessage({ id: 'component.globalModal.openingBank' }), dataIndex: 'bank', key: 'bank' },
+ { title: intl.formatMessage({ id: 'component.globalModal.accountName' }), dataIndex: 'accountName', key: 'accountName' },
+ { title: intl.formatMessage({ id: 'component.globalModal.accountNumber' }), dataIndex: 'account', key: 'account' },
+ { title: intl.formatMessage({ id: 'component.globalModal.currency' }), dataIndex: 'currency', key: 'currency', render: (code: string) => currencyMap[code] || code },
+ { title: intl.formatMessage({ id: 'component.globalModal.country' }), dataIndex: 'nation', key: 'nation', render: renderRegionName },
+ { title: intl.formatMessage({ id: 'component.globalModal.province' }), dataIndex: 'province', key: 'province', render: renderRegionName },
+ { title: intl.formatMessage({ id: 'component.globalModal.city' }), dataIndex: 'city', key: 'city', render: renderRegionName },
+ ];
+ if (!registerInfo) return {intl.formatMessage({ id: 'component.globalModal.loading' })}...
;
+
+ return (
+ <>
+
+ {registerInfo.coscoSupplierBase.supplierType === 'dvs' && (
+ <>
+
+ {intl.formatMessage({ id: 'component.globalModal.domesticEnterprise' })}
+
+
+ {registerInfo.coscoSupplierBase.licenceAccessory ? (
+
+
+
+ ) : (
+ 无附件
+ )}
+
+ >
+ )}
+
+ {registerInfo.coscoSupplierBase.name}
+
+
+ {registerInfo.coscoSupplierBase.nameEn}
+
+ {registerInfo.coscoSupplierBase.supplierType !== 'dvs' && (
+ <>
+
+ {registerInfo.coscoSupplierBase.nation}
+
+
+ {registerInfo.coscoSupplierBase.vat}
+
+
+ {registerInfo.coscoSupplierBase.taxpayerId}
+
+
+ {registerInfo.coscoSupplierBase.currency}
+
+ >
+ )}
+
+ {registerInfo.coscoSupplierBase.range}
+
+
+ {registerInfo.coscoSupplierBase.workAddress}
+
+
+ {registerInfo.coscoSupplierBase.parentCompanyInvestor}
+
+
+ {registerInfo.coscoSupplierBase.legalPerson}
+
+
+ {registerInfo.coscoSupplierBase.capital}
+
+ {registerInfo.coscoSupplierBase.supplierType === 'dvs' && (
+ <>
+
+ {registerInfo.coscoSupplierBase.socialCreditCode}
+
+
+ {registerInfo.coscoSupplierBase.regAddress}
+
+
+ {contactsTypeMap[registerInfo.coscoSupplierBase.contactsType] || registerInfo.coscoSupplierBase.contactsType}
+
+
+ {registerInfo.coscoSupplierBase.idCard}
+
+
+ {enterpriseTypeMap[registerInfo.coscoSupplierBase.enterpriseType] || registerInfo.coscoSupplierBase.enterpriseType}
+
+
+ {registerInfo.coscoSupplierBase.contactsPhone}
+
+ >
+ )}
+
+ {registerInfo.coscoSupplierBase.contactsName}
+
+
+ {registerInfo.coscoSupplierBase.contactsEmail}
+
+
+ {registerInfo.coscoSupplierBase.telephone}
+
+
+
+ {intl.formatMessage({ id: 'component.globalModal.qualificationInfo' })}
}
+ />
+
+ {registerInfo.coscoSupplierBase.supplierType === 'dvs' && (
+
+
+ { taxpayerTypeMap[registerInfo.coscoSupplierInvoice.taxpayerType] || registerInfo.coscoSupplierInvoice.taxpayerType }
+
+
+ {registerInfo.coscoSupplierInvoice.head}
+
+
+ {registerInfo.coscoSupplierInvoice.taxpayerCode}
+
+
+ {registerInfo.coscoSupplierInvoice.address}
+
+
+ {registerInfo.coscoSupplierInvoice.phone}
+
+
+ {registerInfo.coscoSupplierInvoice.bank}
+
+
+ {registerInfo.coscoSupplierInvoice.account}
+
+
+
+ {intl.formatMessage({ id: 'component.globalModal.viewAttachment' })}
+
+
+
+ )}
+
+ {intl.formatMessage({ id: 'component.globalModal.bankAccount' })}
}
+ />
+ {intl.formatMessage({ id: 'component.globalModal.ethicsQuestionnaireTitle' })}
+
+
+
+ {registerInfo.coscoSupplierSurvey.supplierName}
+
+
+ {registerInfo.coscoSupplierSurvey.name}
+
+
+ {registerInfo.coscoSupplierSurvey.position}
+
+
+ {registerInfo.coscoSupplierSurvey.phone}
+
+
+ {registerInfo.coscoSupplierSurvey.email}
+
+
+ {registerInfo.coscoSupplierSurvey.dateTime}
+
+
+
+
+
index + 1 },
+ { title: intl.formatMessage({ id: 'component.globalModal.question' }), dataIndex: 'questionName', key: 'questionName' },
+ { title: intl.formatMessage({ id: 'component.globalModal.answer' }), dataIndex: 'replyValue', key: 'replyValue', width: 120 },
+ ]}
+ pagination={false}
+ title={() => {intl.formatMessage({ id: 'component.globalModal.questionnaire' })}
}
+ />
+
+
+
+
+ {registerInfo.coscoSupplierSurveyAttachments.map((item: any) => {
+ const { attachmentsType, fileUrl, fileName } = item;
+ return attachmentsType === 'commitment' ? (
+ {fileName}
+ ) : null
+ })}
+
+
+
+
+
+ {registerInfo.coscoSupplierSurveyAttachments.map((item: any) => {
+ const { attachmentsType, fileUrl, fileName } = item;
+ return attachmentsType === 'accessory' ? (
+ {fileName}
+ ) : null
+ })}
+
+
+ >
+ );
+};
+
+export default SupplierRegisterInfo;
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/components/TianyanchaInfo.tsx b/src/pages/supplier/ViewReviewPage/GlobalModal/components/TianyanchaInfo.tsx
new file mode 100644
index 0000000..338ddf3
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/components/TianyanchaInfo.tsx
@@ -0,0 +1,136 @@
+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, getQueryAndUpdate } from '../services';
+import { useIntl } from 'umi';
+
+
+interface TianyanchaInfoProps {
+ base?: string; // 省份简称
+ name?: string; // 企业名称
+ legalPersonName?: string; // 法人
+ legalPersonType?: string; // 法人类型 ,1 人 2 公司
+ regNumber?: string; // 注册号
+ industry?: string; // 行业
+ companyOrgType?: string; // 企业类型
+ regLocation?: string; // 注册地址
+ estiblishTime?: string; // 成立时间
+ fromTime?: string; // 经营开始时间
+ toTime?: string; // 经营结束时间
+ businessScope?: string; // 经营范围
+ approvedTime?: string; // 核准时间
+ regStatus?: string; // 企业状态
+ regCapital?: string; // 注册资本
+ regInstitute?: string; // 登记机关
+ orgNumber?: string; // 组织机构代码
+ creditCode?: string; // 统一社会信用代码
+ property3?: string; // 英文名
+ updatetime?: string; // 更新时间
+ companyId?: string; // 表对应id
+ taxNumber?: string; // 纳税人识别号
+ email?: string; // 邮箱
+ website?: string; // 网址
+ phoneNumber?: string; // 电话号
+ lastUpdateTime?: string; // 最后更新时间
+}
+
+
+const TianyanchaInfo = ({ id }: { id: string }) => {
+ const intl = useIntl();
+ const [loading, setLoading] = useState(false);
+ const [dataList, setDataList] = useState([]);
+ const [updateTime, setUpdateTime] = useState('');
+
+ //列表
+ 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);
+ }
+ };
+
+ const onUpdateTime = () => {
+ setUpdateTime(new Date().toLocaleDateString());
+ getUpdateList();
+ message.success(intl.formatMessage({ id: 'component.tianyancha.updateSuccess'}));
+ };
+ useEffect(() => {
+ if (id) {
+ getList();
+ }
+ }, [id]);
+ // 渲染
+ const getColumns: ColumnsType = [
+ { title: intl.formatMessage({ id: 'component.tianyancha.base' }), dataIndex: 'base', key: 'base' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.name' }), dataIndex: 'name', key: 'name' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.legalPersonName' }), dataIndex: 'legalPersonName', key: 'legalPersonName' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.legalPersonType' }), dataIndex: 'legalPersonType', key: 'legalPersonType' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.regNumber' }), dataIndex: 'regNumber', key: 'regNumber' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.industry' }), dataIndex: 'industry', key: 'industry' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.companyOrgType' }), dataIndex: 'companyOrgType', key: 'companyOrgType' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.regLocation' }), dataIndex: 'regLocation', key: 'regLocation' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.estiblishTime' }), dataIndex: 'estiblishTime', key: 'estiblishTime' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.fromTime' }), dataIndex: 'fromTime', key: 'fromTime' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.toTime' }), dataIndex: 'toTime', key: 'toTime' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.businessScope' }), dataIndex: 'businessScope', key: 'businessScope' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.approvedTime' }), dataIndex: 'approvedTime', key: 'approvedTime' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.regStatus' }), dataIndex: 'regStatus', key: 'regStatus' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.regCapital' }), dataIndex: 'regCapital', key: 'regCapital' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.regInstitute' }), dataIndex: 'regInstitute', key: 'regInstitute' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.orgNumber' }), dataIndex: 'orgNumber', key: 'orgNumber' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.creditCode' }), dataIndex: 'creditCode', key: 'creditCode' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.property3' }), dataIndex: 'property3', key: 'property3' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.updatetime' }), dataIndex: 'updatetime', key: 'updatetime' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.companyId' }), dataIndex: 'companyId', key: 'companyId' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.taxNumber' }), dataIndex: 'taxNumber', key: 'taxNumber' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.email' }), dataIndex: 'email', key: 'email' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.website' }), dataIndex: 'website', key: 'website' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.phoneNumber' }), dataIndex: 'phoneNumber', key: 'phoneNumber' },
+ { title: intl.formatMessage({ id: 'component.tianyancha.lastUpdateTime' }), dataIndex: 'lastUpdateTime', key: 'lastUpdateTime' },
+ ];
+ return (
+ <>
+
+
+ {intl.formatMessage({ id: 'component.tianyancha.title' })}
+
+ ({intl.formatMessage({ id: 'component.tianyancha.updateTime' })}:{updateTime}){' '}
+
+
+ } bordered column={3}>
+ {getColumns.map(col => (
+
+ {dataList[(col as any).dataIndex] ?? '-'}
+
+ ))}
+
+ >
+ );
+};
+
+export default TianyanchaInfo;
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/index.tsx b/src/pages/supplier/ViewReviewPage/GlobalModal/index.tsx
new file mode 100644
index 0000000..95995d6
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/index.tsx
@@ -0,0 +1,142 @@
+import React, { useEffect, useState } from 'react';
+import { Modal, Button, Space, Descriptions } from 'antd';
+import { useIntl } from 'umi';
+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';
+
+// 推荐只接收外部传入的 props
+interface ViewGlobalModalModalProps {
+ visible: boolean;
+ id?: string;
+ onCancel: () => void;
+}
+
+const ViewGlobalModalModal: React.FC = ({
+ visible,
+ id,
+ onCancel,
+}) => {
+ const intl = useIntl();
+
+ // 页面显示具体tab类型
+ const [modalType, setModalType] = useState<'register' | 'category' | 'tianyancha' | 'risk' | 'ContactsInfo'>('register');
+ //供应商信息数据
+ const [registerInfo, setRegisterInfo] = useState(null);
+
+ //获取供应商信息
+ const fetchRegisterInfo = () => {
+ if (!id) return;
+ coscoSupplierBase(id).then((res) => {
+ let { code, data } = res;
+ if (code === 200) {
+ setRegisterInfo(data);
+ }
+ })
+ };
+
+ // 初始化
+ useEffect(() => {
+ if (visible && id) {
+ setModalType('register');
+ fetchRegisterInfo();
+ } else {
+ setRegisterInfo(null);
+ }
+ // eslint-disable-next-line
+ }, [visible, id]);
+
+ // 切换tab
+ const handleSwitch = (type: typeof modalType) => setModalType(type);
+
+ // 渲染tab内容
+ const renderContent = () => {
+ if (modalType === 'register' && registerInfo?.coscoSupplierBase) {
+ return ;
+ }
+ if (modalType === 'category') {
+ return ;
+ }
+ if (modalType === 'tianyancha') {
+ return ;
+ }
+ if (modalType === 'risk') {
+ return ;
+ }
+ if (modalType === 'ContactsInfo') {
+ return ;
+ }
+ return null;
+ };
+
+ return (
+ {
+ setRegisterInfo(null);
+ onCancel && onCancel(); // 只调外部传入的onCancel
+ }}
+ footer={null}
+ title={
+
+ {intl.formatMessage({ id: 'component.globalModal.title' })}
+
+ }
+ >
+ {(registerInfo?.coscoSupplierBase?.supplierType !== 'pe' && registerInfo) ?
+ (
+
+
+
+
+
+
+
+
+
+ {renderContent()}
+
+
+ ) : (
+
+
+
+
+
+
+ {modalType === 'category' && (
+
+ )}
+ {modalType === 'register' && (
+
+
+ {registerInfo?.coscoSupplierBase?.personName}
+
+
+ {registerInfo?.coscoSupplierBase?.idCard}
+
+
+ {registerInfo?.coscoSupplierBase?.personPhone}
+
+
+ {registerInfo?.coscoSupplierBase?.personBank}
+
+
+ {registerInfo?.coscoSupplierBase?.personAccount}
+
+
+ )}
+
+
+ )
+ }
+
+ );
+};
+
+export default ViewGlobalModalModal;
diff --git a/src/pages/supplier/ViewReviewPage/GlobalModal/services.ts b/src/pages/supplier/ViewReviewPage/GlobalModal/services.ts
new file mode 100644
index 0000000..ce4726a
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/GlobalModal/services.ts
@@ -0,0 +1,67 @@
+import request from '@/utils/request';
+
+
+/**
+ * 天眼查查询
+ */
+interface getQuery {
+ supplierId: string;
+}
+export const getQuery = (params: getQuery) => request.get('/tycAndFxSupplierBase/query', { params});
+/**
+ * 天眼查更新
+ */
+interface getQuery {
+ supplierId: string;
+}
+export const getQueryAndUpdate = (params: getQuery) => request.get('/tycAndFxSupplierBase/queryAndUpdate', { params});
+
+
+/**
+ * 合规风险查询
+ */
+interface queryRiskInfo {
+ supplierId: string;
+}
+export const queryRiskInfo = (params: queryRiskInfo) => request.get('/tycAndFxSupplierBase/queryRiskInfo', { params});
+
+
+/**
+ * 供应商注册信息
+ */
+export const coscoSupplierBase = (id: string) => request.get(`/coscoSupplierBase/${id}` );
+
+/**
+ * 准入品类
+ */
+interface getCategoryPage {
+ pageNo: number;
+ pageSize: number;
+ supplierId?: string;
+}
+export const getCategoryPage = (data: getCategoryPage) => request.post('/coscoSupplierBase/getCategoryPage', { data });
+
+
+/**
+ * 准入品类
+ */
+interface supplierIdPage {
+ basePageRequest: basePageRequests;
+ supplierId?: string;
+}
+interface basePageRequests {
+ pageNo: number;
+ pageSize: number;
+}
+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 });
diff --git a/src/pages/supplier/ViewReviewPage/components/ResultModal.tsx b/src/pages/supplier/ViewReviewPage/components/ResultModal.tsx
new file mode 100644
index 0000000..e7018e1
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/components/ResultModal.tsx
@@ -0,0 +1,263 @@
+import React, { useEffect, useState } from 'react';
+import { Modal, Table, Button, Spin } from 'antd';
+import { reviewInfoData, groupByList } from '../services';
+import { connect } from 'umi';
+import GlobalModal from '../GlobalModal/index'
+
+interface ResultModalProps {
+ visible: boolean;
+ record?: { id?: string;[key: string]: any } | null;
+ onCancel: () => void;
+ dispatch: any;
+}
+
+// 只读备注弹窗
+const RemarkViewModal: React.FC<{
+ visible: boolean;
+ onCancel: () => void;
+ remark: string;
+ file?: any;
+}> = ({ visible, onCancel, remark, file }) => (
+
+
+
+ 备注:{remark || '无'}
+
+ {file && file.fileUrl && (
+
+ )}
+
+
+);
+
+const ResultModal: React.FC = ({
+ visible,
+ record,
+ onCancel,
+ dispatch
+}) => {
+ const [loading, setLoading] = useState(false);
+ const [suppliers, setSuppliers] = useState([]);
+ const [items, setItems] = useState([]);
+ const [groupSummaryResult, setGroupSummaryResult] = useState<{ [k: string]: '0' | '1' | undefined }>({});
+ const [remarkModal, setRemarkModal] = useState({ open: false, remark: '', file: undefined as any });
+ const [visibleGlobalModal, setVisibleGlobalModal] = useState(false);
+ const [id, setId] = useState('');
+ // 拉取数据
+ useEffect(() => {
+ if (visible && record?.id) {
+ setLoading(true);
+ // 拉取评审项(groupByList)+供应商+评审数据(reviewInfoData)
+ Promise.all([
+ groupByList({ accessWorkId: record.id }),
+ reviewInfoData({ id: record.id })
+ ]).then(([groupRes, reviewRes]: any) => {
+ // 评审项(按接口数据确定字段,兼容你的接口:itemType !== 'summary')
+ const allItems = (groupRes?.data || []).filter((it: any) => it.itemType !== 'summary');
+ setItems(allItems);
+
+ // 供应商及评审数据
+ const supplierList = reviewRes?.data || [];
+ // 为每个 supplier 构造 coscoAccessItemList(根据 groupByList 的 items + supplier.coscoAccessUserItemList 拼装),这样 columns 渲染就不依赖接口中的 coscoAccessItemList
+ supplierList.forEach((sup: any) => {
+ // 按 itemName+itemType 拆分(兼容后续render逻辑)
+ const itemList = allItems.map((item: any) => {
+ // 找所有该供应商的userItem(同一itemName, itemType)
+ const userItems = (sup.coscoAccessUserItemList || []).filter(
+ (u: any) => u.itemName === item.itemName && u.itemType === item.itemType
+ );
+ return {
+ ...item,
+ coscoAccessUserItemList: userItems
+ }
+ });
+ // summary 行
+ const summaryItems = (sup.coscoAccessUserItemList || []).filter(
+ (u: any) => u.itemType === 'summary'
+ );
+ if (summaryItems.length) {
+ itemList.push({
+ itemName: summaryItems[0].itemName,
+ itemType: 'summary',
+ coscoAccessUserItemList: summaryItems
+ });
+ }
+ sup.coscoAccessItemList = itemList;
+ });
+ setSuppliers(supplierList);
+
+ // 汇总行初始化
+ const summaryMap: { [k: string]: '0' | '1' | undefined } = {};
+ supplierList.forEach((sup: any) => {
+ const summaryItem = (sup.coscoAccessItemList || []).find((i: any) => i.itemType === 'summary');
+ summaryMap[sup.supplierId] = summaryItem?.coscoAccessUserItemList?.[0]?.reviewResult;
+ });
+ setGroupSummaryResult(summaryMap);
+ }).finally(() => setLoading(false));
+ } else if (!visible) {
+ setSuppliers([]);
+ setItems([]);
+ setGroupSummaryResult({});
+ }
+ }, [visible, record]);
+
+ // 构造二级表头
+ const columns: any[] = [
+ {
+ title: '评审项',
+ dataIndex: 'itemName',
+ key: 'itemName',
+ width: 180,
+ fixed: 'left',
+ },
+ ...suppliers.map(sup => {
+ // 当前公司所有人员(所有非summary项,取 coscoAccessUserItemList 多个)
+ const reviewerMap = new Map();
+ (sup.coscoAccessItemList || []).forEach((item: any) => {
+ if (item.itemType !== 'summary' && Array.isArray(item.coscoAccessUserItemList)) {
+ item.coscoAccessUserItemList.forEach((u: any) => {
+ reviewerMap.set(u.reviewBy, u.reviewName); // 工号 -> 姓名
+ });
+ }
+ });
+ const reviewers = Array.from(reviewerMap.entries()).map(([reviewBy, reviewName]) => ({ reviewBy, reviewName }));
+
+ return {
+ title: (
+
+ ),
+ children: reviewers.map(({ reviewName, reviewBy }) => ({
+ title: reviewName,
+ dataIndex: `${sup.supplierId}_${reviewBy}`,
+ key: `${sup.supplierId}_${reviewBy}`,
+ width: 100,
+ align: 'center',
+ render: (_: any, row: any) => {
+ // 在sup.coscoAccessItemList里找该itemName下该人员
+ const item = (sup.coscoAccessItemList || []).find(
+ (it: any) => it.itemName === row.itemName && it.itemType !== 'summary'
+ );
+ if (!item) return null;
+ const userItem = (item.coscoAccessUserItemList || []).find((u: any) => u.reviewBy === reviewBy);
+ if (!userItem) return null;
+ return (
+
+ {userItem.reviewResult === '0'
+ ? 合格
+ : userItem.reviewResult === '1'
+ ? 不合格
+ : ''}
+ {userItem.remark && (
+
+ )}
+
+ );
+ }
+ }))
+ }
+ })
+ ];
+
+ // 组装表格行数据
+ const tableData = items.map(item => {
+ const row: any = {
+ key: item.id,
+ itemName: item.itemName
+ };
+ suppliers.forEach(sup => {
+ // 每个人员一格
+ const reviewerSet = new Set();
+ (sup.coscoAccessItemList || []).forEach((it: any) => {
+ if (it.itemType !== 'summary' && Array.isArray(it.coscoAccessUserItemList)) {
+ it.coscoAccessUserItemList.forEach((u: any) => {
+ reviewerSet.add(u.reviewBy);
+ });
+ }
+ });
+ const reviewers = Array.from(reviewerSet);
+ reviewers.forEach((reviewBy: string) => {
+ row[`${sup.supplierId}_${reviewBy}`] = null; // 具体显示用render
+ });
+ });
+ return row;
+ });
+
+ // summary 行
+ const summaryRow = (
+
+
+ 结果汇总
+
+ {suppliers.map((sup, index) => {
+ // 统计reviewer个数
+ const reviewerSet = new Set();
+ (sup.coscoAccessItemList || []).forEach((item: any) => {
+ if (item.itemType !== 'summary' && Array.isArray(item.coscoAccessUserItemList)) {
+ item.coscoAccessUserItemList.forEach((u: any) => {
+ reviewerSet.add(u.reviewBy);
+ });
+ }
+ });
+ const colSpan = reviewerSet.size || 1;
+ return (
+
+
+ {groupSummaryResult[sup.supplierId] === '0' ? '合格' : '不合格'}
+
+
+ )
+ })}
+
+ );
+
+ return (
+
+
查看评审结果
+
+ summaryRow}
+ scroll={{ x: 300 * suppliers.length + 200 }}
+ />
+
+ setRemarkModal({ open: false, remark: '', file: undefined })}
+ remark={remarkModal.remark}
+ file={remarkModal.file}
+ />
+
+ setVisibleGlobalModal(false)} />
+
+ );
+};
+
+export default connect()(ResultModal);
diff --git a/src/pages/supplier/ViewReviewPage/components/ViewModal.tsx b/src/pages/supplier/ViewReviewPage/components/ViewModal.tsx
new file mode 100644
index 0000000..5c3e97e
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/components/ViewModal.tsx
@@ -0,0 +1,161 @@
+import React, { useState, useEffect } from 'react';
+import { Modal, Descriptions, Spin } from 'antd';
+import { useSupplierDetailModal } from '@/components/SupplierDetailModalContext/SupplierDetailModalContext';
+import GlobalModal from '../GlobalModal/index'
+import { coscoAccessWork } from '../services'
+
+//数据接口
+interface Data {
+ coscoAccessWork: coscoAccessWorks;
+ coscoAccessSupplierList: coscoAccessSupplierLists[];
+ coscoAccessCategoryList: coscoAccessCategoryLists[];
+ coscoAccessUserls: coscoAccessUserl[];
+ coscoAccessWorkAttachments: coscoAccessWorkAttachments;
+}
+
+interface coscoAccessWorkAttachments {
+ fileName: string;
+ fileUrl: string;
+}
+interface coscoAccessUserl {
+ deptName: string;
+ deptId: string;
+ userName: string;
+ userId: string;
+}
+interface coscoAccessCategoryLists {
+ categoryName: string;
+ [property: string]: any;
+}
+interface coscoAccessSupplierLists {
+ supplierName: string;
+ [property: string]: any;
+}
+interface coscoAccessWorks {
+ deptId: string;
+ deptName: string;
+ startTime: string;
+ endTime: string;
+ reviewStatusText: string;
+ accessType: string;
+ accessDesc: string;
+ approveStatusText: string;
+}
+
+const ViewModal: React.FC<{
+ visible: boolean;
+ record?: any;
+ onCancel: () => void;
+}> = ({ visible, record = {}, onCancel }) => {
+ //渲染数据
+ const [data, setData] = useState < Data | null > (null);
+ const supplierDetailModal = useSupplierDetailModal();
+ const [loading, setLoading] = useState(false);
+ const [visibleGlobalModal, setVisibleGlobalModal] = useState(false);
+ const [id, setId] = useState('');
+
+ //初始化
+ useEffect(() => {
+ console.log(record,visible);
+
+ if (visible && record?.id) {
+ setLoading(true);
+ coscoAccessWork(record.id)
+ .then((res) => {
+ const { code, data } = res;
+ if (code == 200) {
+ setData(data);
+ }
+ })
+ .finally(() => setLoading(false));
+ } else {
+ setData(null);
+ }
+ }, [visible, record]);
+
+ return (
+
+
查看详情
+
+ {data && (
+
+ {data.coscoAccessWork.deptName}
+
+ {data.coscoAccessSupplierList.map((item) => {
+ return (
+ {
+ setId(item.supplierId)
+ setVisibleGlobalModal(true)
+ }}
+ >
+ {item.supplierName}
+
+ // supplierDetailModal?.(item.supplierId)} >{item.supplierName}
+
+ )
+ })}
+
+
+ {data.coscoAccessWork.accessType === 'scattered' && (
+ <>
+
+ {data.coscoAccessCategoryList.map((item) => {
+ return (
+ {item.categoryPathName}
+ )
+ })}
+
+ {data.coscoAccessWork.accessDesc}
+
+ {data.coscoAccessWorkAttachments.fileName}
+
+ >
+ )}
+ {data.coscoAccessWork.accessType === 'offline' && (
+ <>
+
+ {data.coscoAccessCategoryList.map((item) => {
+ return (
+ {item.categoryPathName}
+ )
+ })}
+
+
+ {data.coscoAccessWorkAttachments.fileName}
+
+ >
+ )}
+
+
+ {data.coscoAccessWork.accessType === 'online' && (
+ <>
+
+ {data.coscoAccessCategoryList.map((item) => {
+ return (
+ {item.categoryPathName}
+ )
+ })}
+
+ {data.coscoAccessWork.startTime}
+ {data.coscoAccessWork.endTime}
+
+ {data.coscoAccessUserls.map((item) => {
+ return (
+ {item.deptName} - {item.userName}
+ )
+ })}
+
+ {data.coscoAccessWork.approveStatusText}
+ >
+ )}
+
+
+ )}
+
+
setVisibleGlobalModal(false)} />
+
+ );
+};
+
+export default ViewModal;
\ No newline at end of file
diff --git a/src/pages/supplier/ViewReviewPage/index.tsx b/src/pages/supplier/ViewReviewPage/index.tsx
new file mode 100644
index 0000000..f5edb31
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/index.tsx
@@ -0,0 +1,41 @@
+// ViewReviewPage.tsx
+import React, { useState, useEffect } from 'react';
+import { useLocation } from 'umi'; // 或者 'react-router-dom'
+import ResultModal from './components/ResultModal';
+import ViewModal from './components/ViewModal';
+
+const ViewReviewPage: React.FC = () => {
+ const [modalVisible, setModalVisible] = useState(false); // 控制弹窗
+ const [modalRecord, setModalRecord] = useState(null);
+
+ // 解析url参数 ?id=xxx
+ const location = useLocation();
+ useEffect(() => {
+ // 获取id参数
+ const params = new URLSearchParams(location.search);
+ const id = params.get('id');
+ if (id) {
+ setModalRecord({ id }); // 只传id也可以,后面可以根据id扩展更多参数
+
+ setModalVisible(true);
+ }
+ }, [location.search]);
+
+ return (
+
+ {/* 其他页面内容 */}
+ setModalVisible(false)}
+ />
+ setModalVisible(false)}
+ />
+
+ );
+};
+
+export default ViewReviewPage;
diff --git a/src/pages/supplier/ViewReviewPage/services.ts b/src/pages/supplier/ViewReviewPage/services.ts
new file mode 100644
index 0000000..a9d1dd3
--- /dev/null
+++ b/src/pages/supplier/ViewReviewPage/services.ts
@@ -0,0 +1,126 @@
+import request from '@/utils/request';
+
+/**
+ * 准入列表
+ */
+interface getPageData {
+ pageNo: number;
+ pageSize: number;
+ deptId?: string;
+ accessType?: string;
+ reviewStatus?: string;
+ approveStatus?: string;
+ categoryId?: string;
+}
+export const getPage = (data: getPageData) => request.post('/coscoAccessWork/getPage', { data });
+
+/**
+ * 未准入的供应商分页列表查询
+ */
+interface coscoSupplierBaseData {
+ pageNo: number;
+ pageSize: number;
+ accessStatus?: number;
+ name?: string;
+ supplierType?: string;
+}
+export const coscoSupplierBase = (data: coscoSupplierBaseData) => request.post('/coscoSupplierBase/getPage', { data });
+/**
+ * 评审项
+ */
+ interface groupByListoData {
+ accessWorkId: string;
+ }
+ export const groupByList = (params: groupByListoData) => request.get(`/coscoAccessItem/groupByList`, { params });
+
+/**
+ * 未准入的供应商分页列表查询
+ */
+interface addInterface {
+ categoryIds: string[];
+ coscoAccessItems: CoscoAccessItem[];
+ coscoAccessUserls: CoscoAccessUserl[];
+ coscoAccessWork: CoscoAccessWork;
+ supplierIds: string[];
+ [property: string]: any;
+}
+
+interface CoscoAccessItem {
+ itemName: string;
+ reviewBy: string[];
+ [property: string]: any;
+}
+
+interface CoscoAccessUserl {
+ deptId: string;
+ isLeader: number;
+ userId: string;
+ [property: string]: any;
+}
+
+interface CoscoAccessWork {
+ accessType: string;
+ accessWorkName: string;
+ deptId: string;
+ endTime: string;
+ startTime: string;
+ [property: string]: any;
+}
+export const add = (data: addInterface) => request.post('/coscoAccessWork/add', { data });
+
+
+
+
+
+
+interface getUserPage {
+ basePageRequest: basePageRequest;
+ userId: string;
+}
+interface basePageRequest {
+ pageNo: number;
+ pageSize: number;
+}
+
+
+export const getUserPage = (data: getUserPage) => request.post('/v1/sysuser/getPageByUserCompany', { data });
+
+/**
+ * 品类选择查询树
+ */
+export const categoryTree = () => request.get('/cosco/category/categoryTree');
+/**
+ * 供应商准入管理详情
+ */
+export const coscoAccessWork = (id: string) => request.get(`/coscoAccessWork/${id}`);
+
+/**
+ * 上传文件
+ * @param file 上传的文件对象
+ * @returns 上传结果
+ */
+export const uploadFile = async (file: File) => {
+ const formData = new FormData();
+ formData.append('file', file);
+
+ return request('/fileConfig/files/upload', {
+ method: 'POST',
+ data: formData,
+
+ });
+};
+
+/**
+ * 发起审批
+ */
+interface startApproveData {
+ id: string;
+}
+export const startApprove = (params: startApproveData) => request.get(`/coscoAccessWork/startApprove`, { params });
+
+/**
+ * 查看评审结果
+ */
+export const reviewInfoData = (params: startApproveData) => request.get(`/coscoAccessWork/reviewInfoData`, { params });
+
+export const supplierChangeApprove = (data: { id:string; approveStatus:string }) => request.post('/synchronous/receiveApprove', { data });
\ No newline at end of file