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 { isArray, result, set } from 'lodash'; import { useForm } from 'rc-field-form'; import { async } from '@antv/x6/lib/registry/marker/async'; 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'; 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, OSSData, } = props; // console.log(loading); 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 [approvalProcess, setApprovalProcess] = useState({}); const [selectUserList, setSelectUserList] = useState([]); const [curNodeIdx, setCurNodeIdx] = useState(-1); const [dataSource, setDataSource] = useState([]); const [loading, setLoading] = useState(false); const uploadList = useRef([]); useEffect(() => { if (!visible) return; const { edges, nodes } = flowDetail; // initFormList().then(approvalProcess => { let Id = version.template_node_id; const currentId = flowDetail.nodes.find?.(item => item.Id == Id)?.node_id; const data = treeData(currentId); console.log('===============审批节点======', data); const nextNodes = getNextNodes(currentId, 'custom-rect'); if (data.length <= 0 || nextNodes.length > 0) { setAuditId(currentId); } else { let defaultValues = {}; if (data.length == 1) { let value = getDataValue(data[0]); defaultValues[`circle`] = value; } else { data.forEach((item, index) => { let value = getDataValue(item); defaultValues[`circle${index}`] = value; }); } // 设置延迟,等待组件渲染 setTimeout(async () => { form.setFieldsValue(defaultValues); const approvalProcess = await initFormList(); Object.values(defaultValues).forEach(value => onChange(value, approvalProcess || {})); }, 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]); // 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 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 || {}); return formList.approvalProcess; // setFormComponentValues(defaultFormData); } }; const treeData = currentId => { const list = getNextNodes(currentId, 'custom-circle'); const fun = nodes => { const re = nodes?.forEach((item, idx) => { const data = getNextNodes(item.Id, 'custom-circle'); if (data || data.length > 0) list.push(...data); fun(data); }); }; fun(list); const fun2 = list => { const parents = list.filter(item => list.findIndex(node => node.Id == item.parentId) == -1); let translator = (parents, children) => { setLength(length + 1); parents.forEach(parent => { children.forEach((current, index) => { if (current.parentId === parent.Id) { let 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, list); return parents; }; return fun2(list); }; const currentNodeId = useMemo(() => { let Id = version.template_node_id; setAuditId(currentNodeId); return flowDetail.nodes.find?.(item => item.Id == Id)?.node_id; }, [flowDetail, version]); /** * * @param {*} currentId 当前节点 * @param {*} type 下一个节点的类型 custom-circle: 审批节点 custom-rect: 业务节点 * @returns */ const getNextNodes = (currentId, type) => { 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) ); let targetIds = edges .filter(edge => edge.source.cell == currentId) .map(item => item.target.cell); edges.filter(edge => edge.source.cell == currentId); let auditNodes = nodes.filter(node => { if (type && node.name != type) { return false; } return targetIds.indexOf(node.id) != -1; }); const result = auditNodes.map(item => { return { label: item.label, value: item.Id, Id: item.node_id, parentId: currentId, children: [], }; }); return result || []; }; const nextNodesList = useMemo(() => { if (!auditId && !currentNodeId) return []; return getNextNodes(auditId || currentNodeId, 'custom-rect'); }, [auditId, currentNodeId, flowDetail]); const changeAudit = id => { let node = flowDetail.nodes.find?.(item => item.Id == id); setAuditId(node?.node_id); }; const onChange = (value) => { if (value) { changeAudit(value[value.length - 1]); setAuditListFun(approvalProcess); } else { changeAudit(''); setAuditList([]); setApprovalProcess({}); } form.setFieldValue('next_template_node_id', ''); }; 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 advanceSubmit = async () => { console.log('重重新计算审批流程'); var fieldsValue = await form.validateFields(); let hasFlowId = true; //是否都绑定审批节点 let result = Object.values(fieldsValue) .map(item => { if (item && Array.isArray(item)) return item; }) .filter(item => item); const formList = await getFromData(result); 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 = {}) => { var fieldsValue = await form.validateFields(); let addAuditList = []; let result = Object.values(fieldsValue) .map(item => { if (item && Array.isArray(item)) return item; }) .filter(item => item) .flat(Infinity); let nodeList = [...new Set(result)] .map(Id => { return flowDetail.nodes.find?.(item => item.Id == Id); }) .filter(item => item); let flowIds = [...new Set(nodeList.map(item => item.flow_id))].join(','); let data = await queryProcessFlows({ ids: flowIds }); if (data && data?.length > 0) { let newlist = nodeList.map(node => { let curData = data.find(item => item.id == node.flow_id); let newItem = { name: curData?.name, nodeId: node.Id, items: JSON.parse(curData.form_json || '[]'), }; return newItem; }); addAuditList = [...addAuditList, ...newlist]; } addAuditList.forEach((item, index) => { let Components = Form3x.create({ onValuesChange: (props, changedValues, allValues) => { const { items } = props; formComponentValues[item.nodeId] = items .map(item => { const itemProps = item.props; let val = allValues[itemProps.id]; if (!itemProps.label || val === '') return; if (val instanceof Object) { return { name: itemProps.label, id: itemProps.id, value: [...val], }; } else if (allValues[itemProps.id]) { return { name: itemProps.label, id: itemProps.id, value: [allValues[itemProps.id]] || undefined, }; } }) .filter(item => item); if (getReComputeAudit(items, changedValues)) advanceSubmit(); setFormComponentValues({ ...formComponentValues }); }, })(AuditDetailed); item.FormComponents = ; }); setAuditList(addAuditList); if (Object.keys(approvalProcess).length == 0) advanceSubmit(); }; const getFromData = async idList => { const data = formComponentValues; 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; let values = data[approvalNode.Id] || []; 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 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 () => { 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 { const formList = await getFromData(result); 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) { params.data = await uploadExcelByUrl(serviceNode.node_type_psr, version.id); } // 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 }), }); params.audit_series = uuidv4(); params.files = uploadList.current.join(','); onSubmitNextNode(params); } catch (error) { console.error(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 ( ); }; const upload = async () => { let blob = await luckysheet.current.getExcelBolb(); let formData = new FormData(); formData.append('userid', currentUser.DingUserId); formData.append('file', new File([blob], `${version.version_name}_${version.version_no}.xlsx`)); try { let res = await uploadFile(formData); let data = JSON.parse(res.dentry); return [ { spaceId: String(data.spaceId), fileName: data.name, fileSize: String(data.spaceId), fileType: data.extension, fileId: data.id, }, ]; } catch (error) { message.error('附件上传失败'); } }; const columns = [ { title: '文件名称', dataIndex: 'name', key: 'name', }, { title: '操作', render: record => 删除, }, ]; useEffect(() => { if (!visible) { // 清空数据 uploadList.current = []; } }, [visible]); return ( { setAuditId(); onClose(); }} onOk={onFinish} >
{data.map((item, idx) => (data.length == 1 ? CascaderNode('') : CascaderNode(idx)))} {OSSData.host && }
{auditList.map((item, idx) => ( {item.FormComponents} {!approvalProcess[item.nodeId] ? ( //!formComponentValues[item.nodeId] || ) : ( )} ))}
); } function getDataValue(item) { let arr = []; arr.push(item.value); if (item.children?.length > 0) { let res = getDataValue(item.children[0]); arr = arr.concat(res); } return arr; } const uploadExcelByUrl = (nodeType, versionId) => { const TEMPLATE_URL = 'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/doc/contract/2023-06-29/ed0d5dcd-6ce0-40df-9d17-a1f69245dbb9.xlsx'; const TEMPLATE_URL2 = 'https://water-service-test.oss-cn-hangzhou.aliyuncs.com/doc/contract/2023-06-29/431733cd-0abc-4a68-a439-d24c466e9845.xlsx'; return new Promise((reslove, reject) => { LuckyExcel.transformExcelToLuckyByUrl( nodeType == 3 ? TEMPLATE_URL : TEMPLATE_URL2, '模板.xlsx', async (exportJson, luckysheetfile) => { let [record] = await getExcel(versionId); let len = exportJson.sheets.length; const excelData = exportJson.sheets?.map(item => { return { ...item, order: Number(item.order) }; }); delete record.id; record.order = len; record.index = String(len); record.status = '0'; record.name = '投标成本'; var res = [...excelData, record]; console.log(res); reslove(JSON.stringify(res)); } ); }); }; async function getExcel(gridKey) { var formData = new FormData(); formData.append('gridKey', gridKey); let res = await fetch( `/api/v1/purchase/record/sheet?gridKey=${gridKey}&JWT-TOKEN=${getToken()}`, { method: 'POST', body: formData, } ).then(response => response.text()); return JSON.parse(JSON.parse(res)); } export default connect(({ xflow, detail, user }) => ({ flowDetail: xflow.flowDetail, versionList: detail.versionList, currentUser: user.currentUser, userList: user.list, OSSData: detail.OSSData, }))(CommitAuditModal);