2025-06-27 10:41:33 +08:00
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
import { Modal, Table, Button, Select, Spin, message } from 'antd';
|
2025-07-02 16:18:03 +08:00
|
|
|
|
import { reviewInfoData } from '../services';
|
|
|
|
|
import { connect } from 'umi';
|
2025-06-27 10:41:33 +08:00
|
|
|
|
interface ResultModalProps {
|
|
|
|
|
visible: boolean;
|
2025-07-02 16:18:03 +08:00
|
|
|
|
record?: { id?: string;[key: string]: any } | null;
|
2025-06-27 10:41:33 +08:00
|
|
|
|
onCancel: () => void;
|
2025-07-02 16:18:03 +08:00
|
|
|
|
dispatch: any;
|
2025-06-27 10:41:33 +08:00
|
|
|
|
}
|
2025-06-24 10:52:30 +08:00
|
|
|
|
|
2025-06-27 10:41:33 +08:00
|
|
|
|
// 只读备注弹窗
|
|
|
|
|
const RemarkViewModal: React.FC<{
|
|
|
|
|
visible: boolean;
|
|
|
|
|
onCancel: () => void;
|
|
|
|
|
remark: string;
|
|
|
|
|
file?: any;
|
2025-07-02 16:18:03 +08:00
|
|
|
|
}> = ({ visible, onCancel, remark, file, }) => (
|
2025-06-27 10:41:33 +08:00
|
|
|
|
<Modal
|
|
|
|
|
visible={visible}
|
|
|
|
|
title="备注信息"
|
|
|
|
|
footer={null}
|
|
|
|
|
onCancel={onCancel}
|
|
|
|
|
destroyOnClose
|
|
|
|
|
>
|
2025-06-24 10:52:30 +08:00
|
|
|
|
<div>
|
2025-06-27 10:41:33 +08:00
|
|
|
|
<div style={{ marginBottom: 12 }}>
|
|
|
|
|
<b>备注:</b>{remark || '无'}
|
|
|
|
|
</div>
|
|
|
|
|
{file && file.fileUrl && (
|
|
|
|
|
<div>
|
|
|
|
|
<b>附件:</b>
|
|
|
|
|
<a href={file.fileUrl} target="_blank" rel="noopener noreferrer">
|
|
|
|
|
{file.fileName}
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
2025-06-24 10:52:30 +08:00
|
|
|
|
)}
|
|
|
|
|
</div>
|
2025-06-27 10:41:33 +08:00
|
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const ResultModal: React.FC<ResultModalProps> = ({
|
|
|
|
|
visible,
|
|
|
|
|
record,
|
|
|
|
|
onCancel,
|
2025-07-02 16:18:03 +08:00
|
|
|
|
dispatch
|
2025-06-27 10:41:33 +08:00
|
|
|
|
}) => {
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [suppliers, setSuppliers] = useState<any[]>([]);
|
|
|
|
|
const [items, setItems] = useState<any[]>([]);
|
|
|
|
|
const [groupSummaryResult, setGroupSummaryResult] = useState<{ [k: string]: '0' | '1' | undefined }>({});
|
|
|
|
|
// 查看备注弹窗
|
|
|
|
|
const [remarkModal, setRemarkModal] = useState({ open: false, remark: '', file: undefined as any });
|
|
|
|
|
// 拉取数据
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (visible && record?.id) {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
reviewInfoData({ id: record.id })
|
|
|
|
|
.then((res: any) => {
|
|
|
|
|
const supplierList = res?.data || [];
|
|
|
|
|
setSuppliers(supplierList);
|
|
|
|
|
// 所有项,取第一家公司
|
|
|
|
|
const allItems = (supplierList[0]?.coscoAccessItemList || []);
|
|
|
|
|
// 非summary项
|
|
|
|
|
setItems(allItems.filter((item: any) => item.itemType !== 'summary'));
|
|
|
|
|
// summary 行初始化
|
|
|
|
|
const summaryMap: { [k: string]: '0' | '1' | undefined } = {};
|
|
|
|
|
supplierList.forEach((sup: any) => {
|
|
|
|
|
// summary 行
|
|
|
|
|
const summaryItem = (sup.coscoAccessItemList || []).find((i: any) => i.itemType === 'summary');
|
2025-07-02 16:18:03 +08:00
|
|
|
|
console.log(summaryItem, 'summaryItem');
|
2025-06-27 10:41:33 +08:00
|
|
|
|
summaryMap[sup.supplierId] = summaryItem.coscoAccessUserItemList[0]?.reviewResult;
|
|
|
|
|
});
|
|
|
|
|
setGroupSummaryResult(summaryMap);
|
|
|
|
|
})
|
|
|
|
|
.finally(() => setLoading(false));
|
|
|
|
|
} else if (!visible) {
|
|
|
|
|
setSuppliers([]);
|
|
|
|
|
setItems([]);
|
|
|
|
|
setGroupSummaryResult({});
|
|
|
|
|
}
|
|
|
|
|
}, [visible, record]);
|
2025-07-02 16:18:03 +08:00
|
|
|
|
|
|
|
|
|
|
2025-06-27 10:41:33 +08:00
|
|
|
|
|
|
|
|
|
// 构造二级表头
|
|
|
|
|
const columns: any[] = [
|
|
|
|
|
{
|
|
|
|
|
title: '评审项',
|
|
|
|
|
dataIndex: 'itemName',
|
|
|
|
|
key: 'itemName',
|
|
|
|
|
width: 180,
|
|
|
|
|
fixed: 'left',
|
|
|
|
|
},
|
|
|
|
|
...suppliers.map(sup => {
|
|
|
|
|
// 当前公司所有人员(所有非summary项,取 coscoAccessUserItemList 多个)
|
|
|
|
|
const reviewerSet = new Set<string>();
|
|
|
|
|
(sup.coscoAccessItemList || []).forEach((item: any) => {
|
|
|
|
|
if (item.itemType !== 'summary' && Array.isArray(item.coscoAccessUserItemList)) {
|
|
|
|
|
item.coscoAccessUserItemList.forEach((u: any) => {
|
|
|
|
|
reviewerSet.add(u.reviewBy);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
const reviewers = Array.from(reviewerSet);
|
2025-07-02 16:18:03 +08:00
|
|
|
|
console.log(sup, 'sup');
|
|
|
|
|
|
2025-06-27 10:41:33 +08:00
|
|
|
|
return {
|
|
|
|
|
title: (
|
|
|
|
|
<div>
|
2025-07-02 16:18:03 +08:00
|
|
|
|
<a
|
|
|
|
|
onClick={() => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'globalModal/show',
|
|
|
|
|
payload: {
|
|
|
|
|
id: sup.supplierId,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{sup.supplierName}
|
|
|
|
|
</a>
|
2025-06-27 10:41:33 +08:00
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
children: reviewers.map((reviewBy: string) => ({
|
|
|
|
|
title: reviewBy,
|
|
|
|
|
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 (
|
|
|
|
|
<div>
|
|
|
|
|
{userItem.reviewResult === '0'
|
|
|
|
|
? <span style={{ color: '#52c41a' }}>合格</span>
|
|
|
|
|
: userItem.reviewResult === '1'
|
2025-07-02 16:18:03 +08:00
|
|
|
|
? <span style={{ color: '#f5222d' }}>不合格</span>
|
|
|
|
|
: ''}
|
2025-06-27 10:41:33 +08:00
|
|
|
|
{userItem.remark && (
|
|
|
|
|
<Button type="link" size="small" onClick={() =>
|
|
|
|
|
setRemarkModal({ open: true, remark: userItem.remark, file: userItem.coscoAccessTtemAttachments })
|
|
|
|
|
}>查看备注</Button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 组装表格行数据
|
|
|
|
|
const tableData = items.map(item => {
|
|
|
|
|
const row: any = {
|
|
|
|
|
key: item.id,
|
|
|
|
|
itemName: item.itemName
|
|
|
|
|
};
|
|
|
|
|
suppliers.forEach(sup => {
|
|
|
|
|
// 每个人员一格
|
|
|
|
|
const reviewerSet = new Set<string>();
|
|
|
|
|
(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 = (
|
|
|
|
|
<Table.Summary.Row>
|
|
|
|
|
<Table.Summary.Cell index={-1}>结果汇总</Table.Summary.Cell>
|
|
|
|
|
{suppliers.map((sup, index) => {
|
|
|
|
|
// 统计reviewer个数
|
|
|
|
|
const reviewerSet = new Set<string>();
|
|
|
|
|
(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;
|
2025-07-02 16:18:03 +08:00
|
|
|
|
|
2025-06-27 10:41:33 +08:00
|
|
|
|
return (
|
|
|
|
|
<Table.Summary.Cell index={index} key={sup.supplierId} colSpan={colSpan} align="center">
|
2025-07-02 16:18:03 +08:00
|
|
|
|
<span style={{ color: groupSummaryResult[sup.supplierId] === '0' ? '#52c41a' : '#f5222d' }}> {groupSummaryResult[sup.supplierId] === '0' ? '合格' : '不合格'}</span>
|
2025-06-27 10:41:33 +08:00
|
|
|
|
</Table.Summary.Cell>
|
|
|
|
|
)
|
|
|
|
|
})}
|
|
|
|
|
</Table.Summary.Row>
|
2025-06-24 10:52:30 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Modal
|
2025-06-27 10:41:33 +08:00
|
|
|
|
title="查看评审结果"
|
2025-06-24 10:52:30 +08:00
|
|
|
|
visible={visible}
|
|
|
|
|
onCancel={onCancel}
|
2025-06-27 10:41:33 +08:00
|
|
|
|
footer={[
|
|
|
|
|
<Button key="cancel" onClick={onCancel}>关 闭</Button>,
|
|
|
|
|
]}
|
2025-06-24 10:52:30 +08:00
|
|
|
|
width={1000}
|
|
|
|
|
bodyStyle={{ maxHeight: '60vh', overflowY: 'auto' }}
|
|
|
|
|
centered
|
2025-06-27 10:41:33 +08:00
|
|
|
|
destroyOnClose
|
2025-06-24 10:52:30 +08:00
|
|
|
|
>
|
2025-06-27 10:41:33 +08:00
|
|
|
|
<Spin spinning={loading}>
|
|
|
|
|
<Table
|
|
|
|
|
columns={columns}
|
|
|
|
|
dataSource={tableData}
|
|
|
|
|
pagination={false}
|
|
|
|
|
bordered
|
|
|
|
|
summary={() => summaryRow}
|
|
|
|
|
scroll={{ x: 300 * suppliers.length + 200 }}
|
|
|
|
|
/>
|
|
|
|
|
</Spin>
|
|
|
|
|
<RemarkViewModal
|
|
|
|
|
visible={remarkModal.open}
|
|
|
|
|
onCancel={() => setRemarkModal({ open: false, remark: '', file: undefined })}
|
|
|
|
|
remark={remarkModal.remark}
|
|
|
|
|
file={remarkModal.file}
|
2025-06-24 10:52:30 +08:00
|
|
|
|
/>
|
|
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-02 16:18:03 +08:00
|
|
|
|
export default connect()(ResultModal);
|