import React, { useState, useEffect } from 'react'; import { Modal, Form, Select, Button, Tree, message, DatePicker, Radio, Upload, Input } from 'antd'; import { UploadOutlined } from '@ant-design/icons'; import type { UploadFile } from 'antd/es/upload/interface'; //组件 import SupplierSelector from './SupplierSelector'; import ReviewerSelector from './ReviewerSelector'; import DivisionModal from './DivisionModal'; // 请求 import { categoryTree, add, uploadFile } from '../services'; import AccessDepartmentSelect from '@/components/AccessDepartmentSelect'; const { Option } = Select; const { RangePicker } = DatePicker; //selected 类型 interface Reviewer { userId: string; name: string; id: string; deptId: string; orgName: string; } // 传入的人接口 interface ReviewerSelectorData { selected: Reviewer[]; leader: Reviewer | null; } // 主体 const CreateModal: React.FC<{ visible: boolean; onCancel: () => void; }> = ({ visible, onCancel }) => { const [form] = Form.useForm(); //品类选择 const [checkedKeys, setCheckedKeys] = useState([]); //供应商 const [selectedSuppliers, setSelectedSuppliers] = useState([]); // 选择评审人员 const [selectedReviewers, setSelectedReviewers] = useState({ selected: [], leader: null, }); //评审分工 const [divisionData, setDivisionData] = useState([]); //准入方式 const [admissionMethod, setAdmissionMethod] = useState('online'); //供应商符合性审查 const [fileList, setFileList] = useState[]>([]); //供应商弹出 const [supplierModalVisible, setSupplierModalVisible] = useState(false); const [reviewerModalVisible, setReviewerModalVisible] = useState(false); const [divisionModalVisible, setDivisionModalVisible] = useState(false); //品类选择渲染数据 const [categoriesTreeData, setCategoriesTreeData] = useState([]); //品类选择数据中字段转换 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({ categoryIds: onlyLeafChecked }); // 只存叶子到表单 // setCheckedKeys(keys); // form.setFieldsValue({ categoryIds: keys }); }; // 选择准入方式 const onMethodChange = (e: any) => { setAdmissionMethod(e.target.value); form.setFieldsValue({ method: e.target.value }); // 如果切换到线上准入,清空下面相关字段 if (e.target.value === 'online') { form.setFieldsValue({ rangePicker: undefined, reviewers: undefined, division: undefined, supplierCompliance: undefined, }); setSelectedReviewers({ selected: [], leader: null, }); setDivisionData([]); } }; // 自定义上传 const handleCustomRequest = async (options: any) => { const { file, onSuccess, onError } = options; try { // 1. 调用你自己写的上传接口 const res = await uploadFile(file); // 2. 可根据后端返回结构,给 fileList 项增加 url 或其他字段 const uploadedFile: UploadFile = { ...file, status: 'done', url: res?.data?.url || res?.url, // 按后端返回实际字段 name: res?.data?.name || file.name, coscoAccessWorkAttachments: res }; setFileList([uploadedFile]); // 同步到 Form form.setFieldsValue({ supplierCompliance: [uploadedFile] }); onSuccess && onSuccess(res, file); message.success('上传成功'); } catch (e) { onError && onError(e); message.error('上传失败'); } }; // 提交 const onFinish = async (values: any) => { const finalPayload: { coscoAccessWork: { startTime: string; endTime: string; accessType: string; accessWorkName: string; deptId: string; accessDesc: string; }; categoryIds: string[]; supplierIds: string[]; coscoAccessUserls: { userId: string; deptId: string; isLeader: number }[]; coscoAccessItems: { itemName: string; reviewBy: string[] }[]; coscoAccessWorkAttachments: any; attachmentsType: any; } = { coscoAccessWork: { startTime: '', endTime: '', accessType: '', accessWorkName: '', deptId: '', accessDesc: '', }, categoryIds: [], supplierIds: [], coscoAccessUserls: [], coscoAccessItems: [], coscoAccessWorkAttachments: {}, attachmentsType: {}, }; //标题名称 finalPayload.coscoAccessWork.accessWorkName = values.accessWorkName; //准入方式 finalPayload.coscoAccessWork.accessType = values.accessType; //准入部门 finalPayload.coscoAccessWork.deptId = values.deptId; // 准入说明 finalPayload.coscoAccessWork.accessDesc = values.accessDesc; //品类选择 finalPayload.categoryIds = values.categoryIds; //选择供应商 values.supplier.forEach((item: { id: string }) => { finalPayload.supplierIds.push(item.id) }) if (values.accessType === 'online') { // 评审时间 if (values.rangePicker && values.rangePicker.length === 2) { const [start, end] = values.rangePicker; finalPayload.coscoAccessWork.startTime = start.format('YYYY-MM-DD HH:mm'); finalPayload.coscoAccessWork.endTime = end.format('YYYY-MM-DD HH:mm'); } //选择评审人员 finalPayload.coscoAccessUserls = values.reviewers.selected.map((item: { userId: string, deptId: string, isLeader: number }) => { return { userId: item.userId, deptId: item.deptId, isLeader: item.isLeader } }); //评审分工 values.division.forEach((item: any) => { const dataJson = { itemName: item.itemName, reviewBy: [] as string[], }; Object.entries(item.reviewerChecks || {}).forEach(([key, value]) => { dataJson.reviewBy.push(key); }); finalPayload.coscoAccessItems.push(dataJson); }); } else { // 供应商符合性审查 finalPayload.coscoAccessWorkAttachments = values.supplierCompliance[0].response; finalPayload.coscoAccessWorkAttachments.fileUrl = values.supplierCompliance[0].response.url; } const res = await add(finalPayload); if (res?.success) { message.success('创建成功'); form.resetFields(); setCheckedKeys([]); setSelectedSuppliers([]); setSelectedReviewers({ selected: [], leader: null, }); setDivisionData([]); setAdmissionMethod('online'); onCancel(); } else { message.error('创建失败'); } }; //初始化 useEffect(() => { if(visible) { categoryTree().then((res) => { const { code, data } = res; if (code == 200) { setCategoriesTreeData(data) } }) form.setFieldsValue({ method: 'online' }); } }, [visible, form]); return ( { form.resetFields(); setCheckedKeys([]); setSelectedSuppliers([]); setSelectedReviewers({ selected: [], leader: null, }); setDivisionData([]); setAdmissionMethod('online'); onCancel(); }} width="700px" destroyOnClose >
线上准入 线下准入 零星采购/应急采购/个人供应商 {admissionMethod === 'offline' && ( <> { if (admissionMethod === 'offline') { if (!value || value.length === 0) { return Promise.reject(new Error('请上传供应商符合性审查文件')); } } return Promise.resolve(); }, }, ]} valuePropName="fileList" getValueFromEvent={e => (Array.isArray(e) ? e : e && e.fileList)} > { if (fileList.length >= 1) { message.error('只能上传一个文件'); return Upload.LIST_IGNORE; } return true; // 允许进入 customRequest }} onChange={({ fileList: newFileList }) => { setFileList(newFileList); form.setFieldsValue({ supplierCompliance: newFileList }); }} onRemove={(file) => { const newList = fileList.filter(item => item.uid !== file.uid); setFileList(newList); form.setFieldsValue({ supplierCompliance: newList }); }} accept=".pdf,.doc,.docx" // 可选,限制文件类型 maxCount={1} // 只允许一个 > )} {admissionMethod === 'online' && ( <> { if (!value || !Array.isArray(value) || value.length === 0) { return Promise.reject(new Error('请设置评审分工')); } // 判断所有分工的checkbox数量总和是否≥1 let checkedCount = 0; for (const row of value) { checkedCount += Object.values(row.reviewerChecks || {}).filter(Boolean).length; } if (checkedCount < 1) { return Promise.reject(new Error('至少分配一名评审人')); } return Promise.resolve(); } } ]} > )} {admissionMethod === 'scattered' && ( <> (Array.isArray(e) ? e : e && e.fileList)} > { if (fileList.length >= 1) { message.error('只能上传一个文件'); return Upload.LIST_IGNORE; } return true; // 允许进入 customRequest }} onChange={({ fileList: newFileList }) => { setFileList(newFileList); form.setFieldsValue({ supplierCompliance: newFileList }); }} onRemove={(file) => { const newList = fileList.filter(item => item.uid !== file.uid); setFileList(newList); form.setFieldsValue({ supplierCompliance: newList }); }} accept=".pdf,.doc,.docx" // 可选,限制文件类型 maxCount={1} // 只允许一个 > )}
{/* 供应商选择 */} setSupplierModalVisible(false)} onSelect={(selected) => { setSelectedSuppliers(selected); form.setFieldsValue({ supplier: selected }); setSupplierModalVisible(false); const accessWorkName = form.getFieldValue('accessWorkName'); if(!accessWorkName) { if(selected.length > 0 ) { console.log(selected,'accessWorkName'); const suppliersName = `${selected[0].supplierType === 'ovs'? selected[0].nameEn:selected[0].name}${selected.length > 1? '等':'' }` form.setFieldsValue({ 'accessWorkName': suppliersName }); } } }} /> {/* 评审人员选择 */} setReviewerModalVisible(false)} selected={selectedReviewers.selected.map(i => i.userId)} leader={selectedReviewers.leader?.userId} onSelect={(result) => { setSelectedReviewers(result); form.setFieldsValue({ reviewers: result }); setReviewerModalVisible(false); }} /> {/* 评审分工选择 */} setDivisionModalVisible(false)} onSelect={(data) => { setDivisionData(data); form.setFieldsValue({ division: data }); setDivisionModalVisible(false); }} />
); }; export default CreateModal;