258 lines
7.2 KiB
TypeScript
258 lines
7.2 KiB
TypeScript
![]() |
import React, { useEffect, useState } from 'react';
|
||
|
import { Modal, Table, Button, Radio, Input, Upload, message, Spin } from 'antd';
|
||
|
import { reviewInfo, uploadFile } from '../services'; // 你的接口
|
||
|
|
||
|
interface ResultModalProps {
|
||
|
visible: boolean;
|
||
|
record?: { id?: string; [key: string]: any } | null;
|
||
|
onCancel: () => void;
|
||
|
onSubmit: (payload: any) => void;
|
||
|
}
|
||
|
|
||
|
// 单元格内容
|
||
|
type CellValue = {
|
||
|
reviewResult?: 0 | 1; // 0合格 1不合格
|
||
|
remark?: string;
|
||
|
file?: any;
|
||
|
};
|
||
|
|
||
|
const ResultModal: React.FC<ResultModalProps> = ({
|
||
|
visible,
|
||
|
record,
|
||
|
onCancel,
|
||
|
onSubmit
|
||
|
}) => {
|
||
|
const [suppliers, setSuppliers] = useState<any[]>([]);
|
||
|
const [items, setItems] = useState<any[]>([]);
|
||
|
const [cellData, setCellData] = useState<{
|
||
|
[itemId: string]: { [supplierId: string]: CellValue }
|
||
|
}>({});
|
||
|
const [loading, setLoading] = useState(false);
|
||
|
|
||
|
// 备注弹窗
|
||
|
const [remarksModalVisible, setRemarksModalVisible] = useState(false);
|
||
|
const [remarks, setRemarks] = useState('');
|
||
|
const [fileList, setFileList] = useState<any[]>([]);
|
||
|
const [currentCell, setCurrentCell] = useState<{ itemId: string, supplierId: string } | null>(null);
|
||
|
|
||
|
// 拉取评审数据
|
||
|
useEffect(() => {
|
||
|
if (visible && record?.id) {
|
||
|
setLoading(true);
|
||
|
reviewInfo({ id: record.id, userId: 'E0001' })
|
||
|
.then((res: any) => {
|
||
|
const data = res?.data || [];
|
||
|
setSuppliers(data);
|
||
|
|
||
|
// 用第一家供应商的coscoAccessItemList生成所有评审项
|
||
|
const firstSupplier = data[0] || {};
|
||
|
const itemList = (firstSupplier.coscoAccessItemList || []).filter((i: { itemType:string } ) => i.itemType !== 'summary');
|
||
|
setItems(itemList);
|
||
|
|
||
|
// 初始化 cellData
|
||
|
const newCellData: any = {};
|
||
|
itemList.forEach((item: any) => {
|
||
|
newCellData[item.id] = {};
|
||
|
data.forEach((sup: any) => {
|
||
|
newCellData[item.id][sup.supplierId] = {};
|
||
|
});
|
||
|
});
|
||
|
setCellData(newCellData);
|
||
|
})
|
||
|
.finally(() => setLoading(false));
|
||
|
}
|
||
|
}, [visible, record]);
|
||
|
|
||
|
// 单选
|
||
|
const handleRadioChange = (itemId: string, supplierId: string, value: string) => {
|
||
|
setCellData(prev => ({
|
||
|
...prev,
|
||
|
[itemId]: {
|
||
|
...prev[itemId],
|
||
|
[supplierId]: {
|
||
|
...prev[itemId]?.[supplierId],
|
||
|
reviewResult: value === '合格' ? 0 : 1
|
||
|
}
|
||
|
}
|
||
|
}));
|
||
|
};
|
||
|
|
||
|
// 打开备注弹窗
|
||
|
const openRemarksModal = (itemId: string, supplierId: string) => {
|
||
|
setCurrentCell({ itemId, supplierId });
|
||
|
const cell = cellData[itemId]?.[supplierId] || {};
|
||
|
setRemarks(cell.remark || '');
|
||
|
setFileList(cell.file
|
||
|
? [{
|
||
|
uid: '-1',
|
||
|
name: cell.file.fileName,
|
||
|
status: 'done',
|
||
|
url: cell.file.fileUrl,
|
||
|
response: cell.file
|
||
|
}]
|
||
|
: []);
|
||
|
setRemarksModalVisible(true);
|
||
|
};
|
||
|
|
||
|
// 上传
|
||
|
const uploadProps = {
|
||
|
fileList,
|
||
|
maxCount: 1,
|
||
|
onRemove: () => setFileList([]),
|
||
|
customRequest: async (options: any) => {
|
||
|
|
||
|
const res = await uploadFile(options.file);
|
||
|
const fileObj = res;
|
||
|
setFileList([{
|
||
|
uid: options.file.uid,
|
||
|
name: fileObj.fileName,
|
||
|
status: 'done',
|
||
|
url: fileObj.url,
|
||
|
response: fileObj
|
||
|
}]);
|
||
|
message.success('文件上传成功');
|
||
|
options.onSuccess && options.onSuccess(res, options.file);
|
||
|
|
||
|
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 备注提交
|
||
|
const handleSubmitRemarks = () => {
|
||
|
if (!currentCell) return;
|
||
|
setCellData(prev => ({
|
||
|
...prev,
|
||
|
[currentCell.itemId]: {
|
||
|
...prev[currentCell.itemId],
|
||
|
[currentCell.supplierId]: {
|
||
|
...prev[currentCell.itemId]?.[currentCell.supplierId],
|
||
|
remark: remarks,
|
||
|
file: fileList[0]?.response || undefined
|
||
|
}
|
||
|
}
|
||
|
}));
|
||
|
setRemarksModalVisible(false);
|
||
|
};
|
||
|
|
||
|
// 提交
|
||
|
const handleSubmit = () => {
|
||
|
// 组装参数
|
||
|
let result: any[] = [];
|
||
|
items.forEach(item => {
|
||
|
suppliers.forEach(sup => {
|
||
|
const cell = cellData?.[item.id]?.[sup.supplierId];
|
||
|
if (cell && cell.reviewResult !== undefined) {
|
||
|
result.push({
|
||
|
id: item.id,
|
||
|
reviewResult: cell.reviewResult,
|
||
|
remark: cell.remark || '',
|
||
|
coscoAccessTtemAttachments: cell.file || undefined
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
console.log(items,'items');
|
||
|
console.log(result,'result');
|
||
|
|
||
|
|
||
|
onSubmit && onSubmit({ coscoAccessUserItemList: result });
|
||
|
};
|
||
|
|
||
|
// 组装表头
|
||
|
const columns = [
|
||
|
{
|
||
|
title: '评审项',
|
||
|
dataIndex: 'itemName',
|
||
|
key: 'itemName',
|
||
|
width: 200,
|
||
|
fixed: 'left'
|
||
|
},
|
||
|
...suppliers.map(sup => ({
|
||
|
title: sup.supplierName,
|
||
|
dataIndex: sup.supplierId,
|
||
|
key: sup.supplierId,
|
||
|
width: 300,
|
||
|
render: (_: any, row: any) => {
|
||
|
const v = cellData?.[row.key]?.[sup.supplierId] || {};
|
||
|
console.log(sup,'sup');
|
||
|
|
||
|
return (
|
||
|
<div>
|
||
|
<Radio.Group
|
||
|
value={
|
||
|
v.reviewResult === 0
|
||
|
? '合格'
|
||
|
: v.reviewResult === 1
|
||
|
? '不合格'
|
||
|
: undefined
|
||
|
}
|
||
|
onChange={e => handleRadioChange(row.key, sup.supplierId, e.target.value)}
|
||
|
>
|
||
|
<Radio value="合格">合格</Radio>
|
||
|
<Radio value="不合格">不合格</Radio>
|
||
|
</Radio.Group>
|
||
|
<Button type="link" onClick={() => openRemarksModal(row.key, sup.supplierId)}>备注</Button>
|
||
|
{v.remark && <span style={{ color: '#aaa', fontSize: 12 }}>已备注</span>}
|
||
|
{v.file && <span style={{ color: '#52c41a', fontSize: 12, marginLeft: 8 }}>已上传</span>}
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
}))
|
||
|
];
|
||
|
|
||
|
// 行数据
|
||
|
const tableData = items.map(item => ({
|
||
|
key: item.id,
|
||
|
itemName: item.itemName
|
||
|
}));
|
||
|
|
||
|
return (
|
||
|
<Modal
|
||
|
title="评审结果"
|
||
|
visible={visible}
|
||
|
onCancel={onCancel}
|
||
|
footer={[
|
||
|
<Button key="cancel" onClick={onCancel}>取消</Button>,
|
||
|
<Button key="submit" type="primary" onClick={handleSubmit}>提交评审结果</Button>
|
||
|
]}
|
||
|
width={1000}
|
||
|
bodyStyle={{ maxHeight: '60vh', overflowY: 'auto' }}
|
||
|
centered
|
||
|
destroyOnClose
|
||
|
>
|
||
|
<Spin spinning={loading}>
|
||
|
<Table
|
||
|
dataSource={tableData}
|
||
|
columns={columns}
|
||
|
pagination={false}
|
||
|
bordered
|
||
|
scroll={{ x: 300 * suppliers.length + 200 }}
|
||
|
/>
|
||
|
</Spin>
|
||
|
<Modal
|
||
|
title="备注/上传附件"
|
||
|
visible={remarksModalVisible}
|
||
|
onCancel={() => setRemarksModalVisible(false)}
|
||
|
footer={[
|
||
|
<Button key="cancel" onClick={() => setRemarksModalVisible(false)}>取消</Button>,
|
||
|
<Button key="submit" type="primary" onClick={handleSubmitRemarks}>提交</Button>
|
||
|
]}
|
||
|
destroyOnClose
|
||
|
>
|
||
|
<Input.TextArea
|
||
|
rows={4}
|
||
|
placeholder="请输入备注"
|
||
|
value={remarks}
|
||
|
onChange={e => setRemarks(e.target.value)}
|
||
|
/>
|
||
|
<Upload {...uploadProps}>
|
||
|
<Button style={{ marginTop: 12 }}>点击上传</Button>
|
||
|
</Upload>
|
||
|
</Modal>
|
||
|
</Modal>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export default ResultModal;
|