import React, { useEffect, useState, useRef, useMemo, useCallback } from 'react'; import '@ant-design/compatible/assets/index.css'; import { Modal, Input, Select, message, Cascader, Form, Tabs, Row, Col, Empty, Button, Steps, Popover, Upload, Table, Divider, Collapse, } from 'antd'; import { PlusOutlined, UploadOutlined } from '@ant-design/icons'; import { connect } from 'dva'; import { useForm } from 'rc-field-form'; import AuditDetailed from './AuditDetailed'; import AuditFlow from './AuditFlow'; import { queryDingSchema, queryGetBomForm, queryProcessFlows, querySaveBomForm, } from '@/services/boom'; import { Form as Form3x } from '@ant-design/compatible'; import { getCurrentUser } from '@/utils/authority'; import DDCode from '@/components/DDComponents/DDCode'; import { uploadFile, queryUserListByRoleID } from '@/services/boom'; import ApprovalProcess from './ApprovalProcess'; import { uuidv4 } from '@antv/xflow'; import AliyunOSSUpload from '@/components/OssUpload/AliyunOssUploader'; import AttachmentTable from '@/components/AttachmentTable'; import { getToken } from '@/utils/utils'; import LuckyExcel from 'luckyexcel'; import DDComponents from '@/components/DDComponents'; import uploadExcelByUrl from '@/utils/uploadExcelByUrl'; const { TextArea } = Input; const { Option } = Select; const { TabPane } = Tabs; const { Step } = Steps; // 提交 function CommitAuditModal(props) { const { dispatch, visible, onClose, // loading, version, versionList, flowDetail, currentUser, luckysheet, userList, templateId, projectList, OSSData, } = props; const [auditId, setAuditId] = useState(); const [data, setData] = useState([]); const [length, setLength] = useState(1); const [formData, setFromData] = useState({}); const [auditList, setAuditList] = useState([]); //用于创建Tabs表单 const [formComponentValues, setFormComponentValues] = useState({}); //用于创建Tabs表单 const [form] = Form.useForm(); const [aduitDetailForm] = Form.useForm(); const [approvalProcess, setApprovalProcess] = useState({}); const [selectUserList, setSelectUserList] = useState([]); const [curNodeIdx, setCurNodeIdx] = useState(-1); const [currentTab, setCurrentTab] = useState(0); const [dataSource, setDataSource] = useState([]); const [loading, setLoading] = useState(false); const uploadList = useRef([]); const formValueRef = useRef({ form: [], }); function getDataValue(item) { let arr = []; arr.push(item.value); if (item.children?.length > 0) { const res = getDataValue(item.children[0]); arr = arr.concat(res); } return arr; } const initFormList = async () => { const res = await queryGetBomForm({ project_id: version.project_id, node_id: version.template_node_id, }); if (res.data) { const formList = JSON.parse(res.data.json); setApprovalProcess(formList.approvalProcess || {}); const prevFormData = JSON.parse(formList.formList?.[0] || '{}'); setFormComponentValues(prevFormData); return formList; } return []; }; /** * * @param {*} currentId 当前节点 * @param {*} type 下一个节点的类型 custom-circle: 审批节点 custom-rect: 业务节点 * @returns */ const getNextNodes = (currentId, type, flag) => { const { edges, nodes } = flowDetail; if (!currentId) return []; // 删除虚线通向的节点 // let targetIds = edges // .filter(edge => { // let line = edge.attrs?.line?.strokeDasharray?.split(' '); // return edge.source.cell == currentId && line && line[0] == '0'; // }) // .map(item => item.target.cell); // console.log( // '---------', // edges.filter(edge => edge.source.cell == currentId) // ); const targetIds = edges .filter(edge => edge.source.cell === currentId) .map(item => item.target.cell); edges.filter(edge => edge.source.cell === currentId); const auditNodes = nodes.filter(node => { // ========为旧清单提供生成PSR的能力,后期舍弃========= if (flag && (node.node_type_psr == 3 || node.node_type_psr == 4)) return true; if (type && node.name !== type) { return false; } return targetIds.indexOf(node.id) !== -1; }); const auditNode = auditNodes.map(item => { return { label: item.label, value: item.Id, Id: item.node_id, parentId: currentId, children: [], }; }); return auditNode || []; }; const treeData = currentId => { const list = getNextNodes(currentId, 'custom-circle'); const fun = nodes => { const re = nodes?.forEach(item => { const nextNodes = getNextNodes(item.Id, 'custom-circle'); if (nextNodes || nextNodes.length > 0) list.push(...nextNodes); fun(nextNodes); }); }; fun(list); const fun2 = listParams => { const parents = listParams.filter( item => listParams.findIndex(node => node.Id == item.parentId) == -1 ); const translator = (p, children) => { setLength(length + 1); p.forEach(parent => { children.forEach((current, index) => { if (current.parentId === parent.Id) { const temp = JSON.parse(JSON.stringify(children)); temp.splice(index, 1); translator([current], temp); if (!parent.children.find(item => item.Id === current.Id)) parent.children.push(current); } }); }); }; translator(parents, listParams); return parents; }; return fun2(list); }; const changeAudit = id => { const node = flowDetail.nodes.find?.(item => item.Id === id); setAuditId(node?.node_id); }; const getFromData = (idList, newFormValues) => { let data = []; if (newFormValues) { try { data = JSON.parse(JSON.stringify(newFormValues)); } catch (error) { console.log(error); } } const result = []; // 获取流转节点的层级关系 let len = 0; let list = []; idList.forEach(item => { if (len < item.length) len = item.length; }); for (let i = 0; i < len; i++) { idList.forEach(item => { if (item && item[i]) list.push(item[i]); }); } let firstList = [...new Set(list)]; // let attachment = await upload(); firstList.forEach(id => { let approvalNode = flowDetail.nodes.find?.(item => item.Id == id); if (!approvalNode) return; const prevValues = data.length ? data.find(item => item.template_node_id === approvalNode.Id).formComponentValues : []; let values = data[approvalNode.Id] || prevValues || []; values.forEach(tempValue => { if (tempValue.type === 'DIYTable') { tempValue.value = tempValue.value.map(item => JSON.stringify(item)); } }); let audit_list = [], cc_list = []; approvalProcess[approvalNode.Id]?.forEach(item => { let arr = item[0].is_cc == 1 ? cc_list : audit_list; if (item[0].type == 'role') return arr.push(item[0].nowValue); return arr.push(item[0].value); }); const formItem = { flow_id: approvalNode.flow_id, template_node_id: approvalNode.Id, formComponentValues: [...values], // { name: '附件', value: JSON.stringify(attachment) } audit_list, cc_list, }; result.push(JSON.stringify(formItem)); }); return result; }; // 填写表单实时计算审批流程 const advanceSubmit = async newFormValues => { // console.log('重重新计算审批流程'); const fieldsValue = await form.validateFields(); let hasFlowId = true; //是否都绑定审批节点 const result = Object.values(fieldsValue) .map(item => { if (item && Array.isArray(item)) return item; }) .filter(item => item); const formList = await getFromData(result, newFormValues); let params = { desc: fieldsValue.desc, // 审核流程id flow_id: 0, node_level_id: 0, id: version.id, project_id: version.project_id, cur_template_node_id: version.template_node_id * 1, // 当前节点 next_template_node_id: 0, // 审核完成后的业务节点 template_node_id: null, // 将要流转的节点审批节点 flow_path: null, // 审批节点数组 // 模板id.一致就行 template_id: version.template_id, cur_template_id: version.template_id, next_template_id: version.template_id, form_list: formList, }; dispatch({ type: 'detail/advanceSubmitNextNode', payload: params, // values, callback: data => { if (data) { setApprovalProcess(data); } }, }); }; // 处理tabs页 const setAuditListFun = async (approvalProcess = {}, prevFormData = []) => { const fieldsValue = await form.validateFields(); let addAuditList = []; const result = Object.values(fieldsValue) .map(item => { if (item && Array.isArray(item)) return item; }) .filter(item => item) .flat(Infinity); const nodeList = [...new Set(result)] .map(Id => { return flowDetail.nodes.find?.(item => item.Id == Id); }) .filter(item => item); const flowIds = [...new Set(nodeList.map(item => item.flow_id))].join(','); const processFlows = await queryProcessFlows({ ids: flowIds }); if (processFlows && processFlows?.length > 0) { const newlist = nodeList.map(node => { const curData = processFlows.find(item => item.id === node.flow_id); const newItem = { name: curData?.name, nodeId: node.Id, items: JSON.parse(curData?.form_json || '[]'), }; return newItem; }); addAuditList = [...addAuditList, ...newlist]; } addAuditList.forEach(addAuditItem => { // 回填部分组件的历史数据 if (prevFormData.length) { const currentForm = prevFormData.find( pItem => pItem.template_node_id === addAuditItem.nodeId ); addAuditItem.items.forEach(DDComponent => { const prevValue = currentForm?.formComponentValues?.find( cItem => cItem.id === DDComponent.props.id ); DDComponent.props.defaultValue = prevValue?.value || prevValue?.defaultValue; }); } // 回填之前的值结束后需要把formComponentValues清空 防止提交之前的值 setFormComponentValues([]); }); setAuditList(addAuditList); // advanceSubmit(); }; const onChange = async (value, approvalProcess) => { // 加载之前提交的form数据 const resFormData = await initFormList(); const resData = resFormData?.formList; const prevFormData = resData && resData.length ? resData.map(resItem => JSON.parse(resItem)) : null; if (prevFormData && prevFormData.length) { const formValues = {}; prevFormData.forEach(pItem => { pItem.formComponentValues?.map(item => { if (item.id.includes('ProjectField')) { item.value = [version.project_id]; } }); formValues[pItem.template_node_id] = [...pItem.formComponentValues]; }); setFormComponentValues(formValues); } if (value) { changeAudit(value[value.length - 1]); if (prevFormData !== null) { setAuditListFun(approvalProcess, prevFormData); } else { setAuditListFun(approvalProcess); } } else { changeAudit(''); setAuditList([]); setApprovalProcess({}); } form.setFieldValue('next_template_node_id', ''); }; useEffect(() => { if (!visible) return; const { edges, nodes } = flowDetail; const Id = version.template_node_id; const currentId = flowDetail.nodes.find?.(item => item.Id == Id)?.node_id; const data = treeData(currentId); const nextNodes = getNextNodes(currentId, 'custom-rect'); if (data.length <= 0 || nextNodes.length > 0) { setAuditId(currentId); } else { const defaultValues = {}; if (data.length === 1) { const value = getDataValue(data[0]); defaultValues.circle = value; } else { data.forEach((item, index) => { const value = getDataValue(item); defaultValues[`circle${index}`] = value; }); } // 设置延迟,等待组件渲染 setTimeout(async () => { form.setFieldsValue(defaultValues); const initForm = await initFormList(); const tempAP = initForm?.approvalProcess ? initForm.approvalProcess : {}; Object.values(defaultValues).forEach(value => onChange(value, tempAP)); }, 200); } setData(data); // }); }, [version.template_node_id, visible]); useEffect(() => { if (!visible) return; dispatch({ type: 'detail/getChartOSSData', payload: { projectId: version.project_id, }, }); }, [visible]); useEffect(() => { form.resetFields(); setAuditList([]); }, [visible]); useEffect(() => { if (!visible) { // 清空数据 uploadList.current = []; } }, [visible]); // const OnModelFileDone = file => { // var path = OSSData.host + '/' + file.url; // uploadList.current = [...uploadList.current, path]; // console.log(uploadList.current); // }; const setUploadList = files => { uploadList.current = files.map(file => OSSData.host + '/' + file.url); // console.log(uploadList.current); }; const OnUploading = file => {}; const uploadProps = { OSSData: OSSData, // onDone: OnModelFileDone, onUploading: OnUploading, noStyle: false, onChange: setUploadList, // showUploadList: false, }; const currentNodeId = useMemo(() => { let Id = version.template_node_id; setAuditId(currentNodeId); return flowDetail.nodes.find?.(item => item.Id == Id)?.node_id; }, [flowDetail, version]); const nextNodesList = useMemo(() => { if (!auditId && !currentNodeId) return []; return getNextNodes(auditId || currentNodeId, 'custom-rect', true); }, [auditId, currentNodeId, flowDetail]); const getReComputeAudit = (items, changedValues) => { const id = Object.keys(changedValues)[0]; const formItem = items?.find(item => item.props.id == id); if (formItem && formItem.props?.required) return true; return false; }; const handleTabChange = key => { const index = Number(key.split('_')[0]); setCurrentTab(index); }; const onFormValueChange = (changedFields, allValues) => { const currentNodeID = auditList[currentTab]?.nodeId; if (!currentNodeID) return; const allFormItem = auditList[currentTab].items; const componentValue = formComponentValues[currentNodeID] || []; const currentFieldID = Object.keys(changedFields)[0]; const formItem = allFormItem.find(item => item.props.id === currentFieldID); // 记录TextNote 以及其他未填写的值 for (let index = 0; index < allFormItem.length; index++) { const tempFormItem = allFormItem[index]; // 跳过DIYTable控件 if (tempFormItem.componentName === 'DIYTable') { continue; } // 没找到就给默认值 if (!componentValue.find(item => item.id === tempFormItem.props.id)) { if (tempFormItem.componentName === 'TextNote') { // 记录TextNote componentValue.push({ name: tempFormItem.props.label, id: tempFormItem.props.id, value: [tempFormItem.props.placeholder], }); } else { const prevValue = allValues[tempFormItem.props.id]; // 从allValue中找到该值 componentValue.push({ name: tempFormItem.props.label, id: tempFormItem.props.id, value: Array.isArray(prevValue) ? [...prevValue] : [], }); } } } // 记录变更的formItem值 if (componentValue.length) { for (let index = 0; index < componentValue.length; index++) { const item = componentValue[index]; if (item.id === currentFieldID) { componentValue[index] = { name: formItem.props.label, id: currentFieldID, value: Array.isArray(changedFields[currentFieldID]) ? changedFields[currentFieldID] : [changedFields[currentFieldID]], }; break; } else if (index === componentValue.length - 1) { componentValue.push({ name: formItem.props.label, id: currentFieldID, value: Array.isArray(changedFields[currentFieldID]) ? changedFields[currentFieldID] : [changedFields[currentFieldID]], }); } } } else { componentValue.push({ name: formItem.props.label, id: currentFieldID, value: [changedFields[currentFieldID]], }); } let newFormValues = { ...formComponentValues, [currentNodeID]: componentValue, }; setFormComponentValues(newFormValues); console.log(formComponentValues); formValueRef.current.form[currentNodeID] = [...componentValue]; advanceSubmit(newFormValues); }; // const getFlowPath = node => { // //[134, 135] // let itemData = {}; // const Function = (curId, index) => { // if (!curId) return; // let data = {}; // let approvalNode = flowDetail.nodes.find?.(item => item.Id == curId); // data.template_id = version.template_id; // data.flow_id = approvalNode?.flow_id || 0; // data.node_level_id = approvalNode?.flow_id ? 1 : 0; // data.template_node_id = approvalNode?.Id; // index++; // if (approvalNode?.Id) { // if (!approvalNode?.flow_id) { // hasFlowId = false; // } // } // const res = Function(node[index], index); // if (res) { // data.flow_path = [res]; // } // return data; // }; // itemData = Function(node[0], 0); // return itemData; // }; const onFinish = async () => { if (loading) return; const isOk = Object.values(approvalProcess).every(item => { return item.every(cur => { if (cur[0].type == 'role') return cur[0].nowValue; return true; }); }); if (!isOk) { message.error('请选择审批人。'); return; } var fieldsValue = await form.validateFields(); let hasFlowId = true; //是否都绑定审批节点 const getFlowPath = node => { //[134, 135] let itemData = {}; const Function = (curId, index) => { if (!curId) return; let data = {}; let approvalNode = flowDetail.nodes.find?.(item => item.Id == curId); data.template_id = version.template_id; data.flow_id = approvalNode?.flow_id || 0; data.node_level_id = approvalNode?.flow_id ? 1 : 0; data.template_node_id = approvalNode?.Id; index++; if (approvalNode?.Id) { if (!approvalNode?.flow_id) { hasFlowId = false; } } const res = Function(node[index], index); if (res) { data.flow_path = [res]; } return data; }; itemData = Function(node[0], 0); return itemData; }; let result = Object.values(fieldsValue) .map(item => { if (item && Array.isArray(item)) return item; }) .filter(item => item); let serviceNode = flowDetail.nodes.find?.(item => item.Id == fieldsValue.next_template_node_id); if (!serviceNode) { message.error('请选择需要流转的业务节点。'); return; } const flowPath = result.map(item => getFlowPath(item)); setLoading(true); try { // 检查Audit form是否为空 const tempFormData = await aduitDetailForm.validateFields().catch(err => { message.error(err.errorFields[0].errors); setLoading(false); return false; }); if (tempFormData === undefined || tempFormData === false) { return; } // 检查之后调用一次,防止什么都没改导致获取不到值 onFormValueChange(tempFormData, tempFormData); const formList = getFromData(result, formComponentValues); let params = { desc: fieldsValue.desc, // 审核流程id // flow_id: approvalNode?.flow_id || 0, // node_level_id: approvalNode?.flow_id ? 1 : 0, id: version.id, project_id: version.project_id, cur_template_node_id: version.template_node_id * 1, // 当前节点 next_template_node_id: serviceNode.Id * 1, // 审核完成后的业务节点 // template_node_id: result[0][0], // 将要流转的节点审批节点 // flow_path:flow_path, //审批节点数组 // 模板id.一致就行 template_id: version.template_id, cur_template_id: version.template_id, next_template_id: version.template_id, }; if (serviceNode.node_type_psr == 3 || serviceNode.node_type_psr == 4) { let project = projectList.find(item => item.id == version?.project_id) || {}; let sheetData = await uploadExcelByUrl(serviceNode.node_type_psr, version.id, project); params.data = JSON.stringify(sheetData); } // params.data = await uploadExcelByUrl(3, version.id); // console.log(params); if (result.length <= 0) { //直接走业务节点 } else if (result.length <= 1 && result[0]?.length <= 1) { //单个审批节点 let approvalNode = flowDetail.nodes.find?.(item => item.Id == result[0][0]); params.flow_id = approvalNode?.flow_id || 0; params.node_level_id = approvalNode?.flow_id ? 1 : 0; params.template_node_id = result[0][0]; // 将要流转的节点审批节点 params.form_list = formList; //创建钉钉表单所需数据 if (approvalNode?.Id) { if (!approvalNode?.flow_id) { hasFlowId = false; } } } else { //多节点审批 params.template_node_id = result[0][0]; // 将要流转的节点审批节点 params.flow_path = flowPath; params.form_list = formList; //创建钉钉表单所需数据 } if (!hasFlowId) { message.error('当前存在审批节点未绑定审批流程!请联系管理员。'); return; } await querySaveBomForm({ project_id: version.project_id, node_id: version.template_node_id, json: JSON.stringify({ approvalProcess, formList }), }); params.audit_series = uuidv4(); if (version.audit_status == 5) { params.audit_status = version.audit_status; } params.files = uploadList.current.join(','); // console.log(params); onSubmitNextNode(params); } catch (error) { console.error(error); setLoading(false); message.error('请求失败'); } }; const onSubmitNextNode = values => { dispatch({ type: 'detail/submitNextNode', payload: values, callback: newVersion => { setLoading(false); onClose(); // 更新flow流程图 dispatch({ type: 'xflow/queryBoomFlowDetail', payload: { id: templateId, }, }); }, }); }; const CascaderNode = index => { return (