供应商退出、准入、 工作台
This commit is contained in:
@ -3,7 +3,6 @@ import { Modal, Form, Select, Button, Tree, message, DatePicker, Radio, Upload,
|
||||
//
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import type { UploadFile } from 'antd/es/upload/interface';
|
||||
import moment from 'moment';
|
||||
//组件
|
||||
import SupplierSelector from './SupplierSelector';
|
||||
import ReviewerSelector from './ReviewerSelector';
|
||||
@ -14,10 +13,10 @@ const { Option } = Select;
|
||||
const { RangePicker } = DatePicker;
|
||||
//selected 类型
|
||||
interface Reviewer {
|
||||
key: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
id: string;
|
||||
dept: string;
|
||||
deptId: string;
|
||||
}
|
||||
// 传入的人接口
|
||||
interface ReviewerSelectorData {
|
||||
@ -85,7 +84,7 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
|
||||
|
||||
// 只取叶子节点 key
|
||||
const leafKeys = findLeafKeys(convertTreeData(categoriesTreeData));
|
||||
const onlyLeafChecked = keys.filter(key => leafKeys.includes(key));
|
||||
const onlyLeafChecked = keys.filter(key => leafKeys.includes(String(key)));
|
||||
|
||||
setCheckedKeys(keys); // UI 显示用,还是全量
|
||||
form.setFieldsValue({ categoryIds: onlyLeafChecked }); // 只存叶子到表单
|
||||
@ -138,7 +137,20 @@ const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ vi
|
||||
};
|
||||
// 提交
|
||||
const onFinish = async (values: any) => {
|
||||
const finalPayload = {
|
||||
const finalPayload: {
|
||||
coscoAccessWork: {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
accessType: string;
|
||||
accessWorkName: string;
|
||||
deptId: string;
|
||||
};
|
||||
categoryIds: string[];
|
||||
supplierIds: string[];
|
||||
coscoAccessUserls: { userId: string; deptId: string; isLeader: number }[];
|
||||
coscoAccessItems: { itemName: string; reviewBy: string[] }[];
|
||||
coscoAccessWorkAttachments: any;
|
||||
} = {
|
||||
coscoAccessWork: {
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
|
@ -1,201 +1,223 @@
|
||||
import React from 'react';
|
||||
import { Modal, Table, Tag, Typography, Button } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, Table, Button, Select, Spin, message } from 'antd';
|
||||
import { reviewInfoData } from '../services';
|
||||
|
||||
const { Link } = Typography;
|
||||
|
||||
const dataSource = [
|
||||
{
|
||||
key: '1',
|
||||
item: '供应商信息登记表',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '合格',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
item: '供应商反商业贿赂承诺书',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '合格',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
item: '供应商社会准则符合性自审问卷',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '合格',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
item: '是否为禁止使用供应商',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '合格',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
item: '3年内经营活动中没有重大违法记录的书面声明',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '合格',
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
item: '企业存续状态审核(营业执照等)',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '不合格',
|
||||
companyB_lisiRemark: '查看备注',
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
item: '行业资质、认证情况(按需)',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_lisi: '合格',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_lisi: '合格',
|
||||
},
|
||||
{
|
||||
key: '8',
|
||||
item: '现场考察、产品试用情况(按需)',
|
||||
companyA_zhangsan: '合格',
|
||||
companyA_zhangsanRemark: '查看备注',
|
||||
companyA_lisi: '合格',
|
||||
companyA_lisiRemark: '查看备注',
|
||||
companyB_zhangsan: '合格',
|
||||
companyB_zhangsanRemark: '查看备注',
|
||||
companyB_lisi: '合格',
|
||||
companyB_lisiRemark: '查看备注',
|
||||
},
|
||||
];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'key',
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '评审项',
|
||||
dataIndex: 'item',
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<div>
|
||||
<div>中山市合创展包装材料有限公司</div>
|
||||
</div>
|
||||
),
|
||||
children: [
|
||||
{
|
||||
title: '张三',
|
||||
dataIndex: 'companyA_zhangsan',
|
||||
width: 100,
|
||||
render: (text: string, record: any) => renderStatus(text, record.companyA_zhangsanRemark),
|
||||
},
|
||||
{
|
||||
title: '李四',
|
||||
dataIndex: 'companyA_lisi',
|
||||
width: 100,
|
||||
render: (text: string, record: any) => renderStatus(text, record.companyA_lisiRemark),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<div>
|
||||
<div>广东振兴塑胶机械有限公司</div>
|
||||
</div>
|
||||
),
|
||||
children: [
|
||||
{
|
||||
title: '张三',
|
||||
dataIndex: 'companyB_zhangsan',
|
||||
width: 100,
|
||||
render: (text: string, record: any) => renderStatus(text, record.companyB_zhangsanRemark),
|
||||
},
|
||||
{
|
||||
title: '李四',
|
||||
dataIndex: 'companyB_lisi',
|
||||
width: 100,
|
||||
render: (text: string, record: any) => renderStatus(text, record.companyB_lisiRemark),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function renderStatus(text: string, remark?: string) {
|
||||
const color = text === '合格' ? 'green' : text === '不合格' ? 'red' : undefined;
|
||||
return (
|
||||
<div>
|
||||
<Tag color={color} style={{ marginRight: 6 }}>
|
||||
{text}
|
||||
</Tag>
|
||||
{remark && (
|
||||
<Link style={{ fontSize: 12 }} onClick={() => alert('备注内容')}>
|
||||
{remark}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
interface ResultModalProps {
|
||||
visible: boolean;
|
||||
record?: { id?: string; [key: string]: any } | null;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const ResultModal: React.FC<{
|
||||
// 只读备注弹窗
|
||||
const RemarkViewModal: React.FC<{
|
||||
visible: boolean;
|
||||
record?: any;
|
||||
onCancel: () => void;
|
||||
}> = ({ visible, onCancel }) => {
|
||||
remark: string;
|
||||
file?: any;
|
||||
}> = ({ visible, onCancel, remark, file }) => (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title="备注信息"
|
||||
footer={null}
|
||||
onCancel={onCancel}
|
||||
destroyOnClose
|
||||
>
|
||||
<div>
|
||||
<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>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
const ResultModal: React.FC<ResultModalProps> = ({
|
||||
visible,
|
||||
record,
|
||||
onCancel,
|
||||
}) => {
|
||||
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');
|
||||
console.log(summaryItem,'summaryItem');
|
||||
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 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);
|
||||
return {
|
||||
title: (
|
||||
<div>
|
||||
<div style={{ fontWeight: 600 }}>{sup.supplierName}</div>
|
||||
</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'
|
||||
? <span style={{ color: '#f5222d' }}>不合格</span>
|
||||
: ''}
|
||||
{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;
|
||||
|
||||
return (
|
||||
<Table.Summary.Cell index={index} key={sup.supplierId} colSpan={colSpan} align="center">
|
||||
<span style={{color: groupSummaryResult[sup.supplierId] === '0'? '#52c41a': '#f5222d' }}> {groupSummaryResult[sup.supplierId] === '0'? '合格': '不合格'}</span>
|
||||
</Table.Summary.Cell>
|
||||
)
|
||||
})}
|
||||
</Table.Summary.Row>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="评审结果"
|
||||
title="查看评审结果"
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
footer={null}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={onCancel}>关 闭</Button>,
|
||||
]}
|
||||
width={1000}
|
||||
bodyStyle={{ maxHeight: '60vh', overflowY: 'auto' }}
|
||||
centered
|
||||
destroyOnClose
|
||||
>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
bordered
|
||||
scroll={{ x: 900 }}
|
||||
summary={() => {
|
||||
// 汇总结果示例,模拟图片底部汇总
|
||||
return (
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={0} colSpan={2} align="right">
|
||||
结果汇总
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} align="center" colSpan={2}>
|
||||
<Tag color="green">合格</Tag>
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={4} align="center" colSpan={2}>
|
||||
<Tag color="red">不合格</Tag>
|
||||
</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
);
|
||||
}}
|
||||
<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}
|
||||
/>
|
||||
<div style={{ textAlign: 'right' }}>
|
||||
|
||||
<Button type="primary" >
|
||||
发起结果审批
|
||||
</Button>
|
||||
<Button type="primary" >
|
||||
结束流程
|
||||
</Button>
|
||||
<Button onClick={onCancel} style={{ marginRight: 8 }}>
|
||||
返回
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user