import React, { useEffect, useState, useRef, useMemo } from 'react'; import { UnorderedListOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Modal, message, Alert, Avatar, Spin, Select, Menu, Dropdown } from 'antd'; import { connect } from 'dva'; import styles from './Index.less'; import LuckySheet from './LuckySheet'; import router from 'umi/router'; import AuditModal from './AuditModal'; // import CommentDrawer from './CommentDrawer'; import RightDrawer from './RightDrawer'; import CommitModal from './CommitModal'; import CompareModal from './CompareModal'; import ExportModal from './ExportModal'; import FlowModal from './FlowModal'; import HistoryModal from './HistoryModal'; import TimeNode from './TimeNode'; import FilesModal from './FilesModal'; import VersionModal from './VersionModal'; import CommitAuditModal from './CommitAuditModal'; import CommentContent from '@/components/CommentContent'; import MergeModal from './MergeModal'; import { GetTokenFromUrl, getToken } from '@/utils/utils'; import { queryDetail } from '@/services/boom'; import HistoryDrawer from './HistoryDrawer'; import AuditFlow from './AuditFlow'; import { getCurrentUser } from '@/utils/authority'; const LocalData = localStorage.luckysheet; const { Option } = Select; function Detail(props) { const { dispatch, comment, history, loading, currentUser, fileList, roleList, template, versionList, auditList, flowDetail, versionTree, match: { params }, instanceDetail, } = props; const [versionTreeVisible, setVersionTreeVisible] = useState(false); const [commentVisible, setCommentVisible] = useState(false); const [mergeVisible, setMergeVisible] = useState(false); const [compareVisible, setCompareVisible] = useState(false); const [exportVisible, setExportVisible] = useState(false); const [commitVisible, setCommitVisible] = useState(false); const [auditVisible, setAuditVisible] = useState(false); const [flowVisible, setFlowVisible] = useState(false); const [versionVisible, setVersionVisible] = useState(false); const [commitAuditVisible, setCommitAuditVisible] = useState(false); const [sheet, setSheet] = useState({}); const [compareList, setCompareList] = useState([]); const [edit, setEdit] = useState(false); const [isMerge, setIsMerge] = useState(false); const [version, setVersion] = useState({}); const [user, setUser] = useState([]); const [updateCount, setUpdateCount] = useState({ diff: 0, add: 0, }); const [fileVisible, setFileVisible] = useState(false); const [exportDate, setExportData] = useState([]); const sheetRef = useRef(); const sheetRef2 = useRef(); const sheetRef3 = useRef(); const fileRef = useRef(); const userRef = useRef(); const statusRef = useRef({ edit: false, compare: false, }); const cellPosition = useRef({}); const projectId = parseInt(params.projectId); const templateId = parseInt(params.templateId); const auditDetail = useMemo(() => { let data = { processCode: '', deptId: '14169890', // userId: '16569001414345099', // deptId: currentUser.DingDepId || getCurrentUser()?.DingDepId, userId: currentUser.DingUserId || getCurrentUser()?.DingUserId, formComponentValues: [], activityId: '', status: version.audit_status, }; if (version?.flow_id && instanceDetail?.tasks && instanceDetail.tasks?.length > 0) { let item = flowDetail.nodes.find(item => item.Id == version.template_node_id); if (!item) return data; const { tasks, form_component_values } = instanceDetail; data.processCode = item.process_code; data.activityId = tasks[tasks.length - 1]?.activity_id; data.formComponentValues = form_component_values?.filter(item => item.name); } return data; }, [instanceDetail, version]); const flow = useMemo(() => { let data = { active: 0, active_id: null, current: 0, currentNode: {}, list: { FlowNodes: [], }, }; if (version?.flow_id && auditList?.length > 0) { let item = auditList.find(item => item.list.id == version.flow_id); if (!item) return data; // 查询当前节点 let current = item.list.FlowNodes.findIndex(node => node.seq == item.active); item.current = current == -1 ? 0 : current; // 保存当前所处节点 item.currentNode = item.list.FlowNodes[item.current]; data = item; } return data; }, [auditList, version]); const active_audit = flow.active_audit; const isAuditor = useMemo(() => { const getUserRole = () => { let roleID = flow.currentNode?.AuditRoleInfo?.ID; let item = currentUser.roleList.find(role => role.ID == roleID); if (item) return true; return false; }; return active_audit == 1 && getUserRole(); }, [active_audit, flow, currentUser]); const onSave = () => { let sheet1 = compareList[0]; Modal.confirm({ title: '提示', content: `是否确认保存【${sheet1.version_name || sheet1.name}】`, okText: '确定', cancelText: '取消', onOk() { let sheetData = sheetRef3.current.getSheetJson().data; sheetData.forEach(sheet => { delete sheet.data; }); let params = { ...sheet1, data: JSON.stringify(sheetData), }; dispatch({ type: 'detail/commitSheet', payload: params, callback: () => { onCompare(false); }, }); }, }); }; const onCompare = async checkSheets => { if (checkSheets) { const [sheet1, sheet2] = checkSheets; sheet1.data = ( await queryDetail({ excel_id: sheet1.id, }) ).data; sheet2.data = ( await queryDetail({ excel_id: sheet2.id, }) ).data; setCompareList(checkSheets); statusRef.current.compare = true; } else { let index = compareList.findIndex(item => item.id == sheet.id); // 退出比对模式 if (index == 0) { sheetRef3.current.toggleCompare(false); } else if (index == 1) { sheetRef2.current.toggleCompare(false); } setIsMerge(false); setCompareList([]); setSheet({ ...sheet, }); setUpdateCount({ diff: 0, add: 0, }); statusRef.current.compare = false; } setCommentVisible(false); }; const renderSheetDom = (item, index) => { return (

{item.version_name || item?.name}

); }; const onClickCell = (cell, position, s) => { console.log(cell); if (cell?.cid && !statusRef.current.edit) { let payload = { sheet_id: s.order || '0', excel_id: version.id, cid: cell.cid, }; dispatch({ type: 'detail/queryComment', payload, }); cellPosition.current = { ...payload, sheet_index: (s.seq || 0) + '', }; // setCommentVisible(true); } // 比对模式下双excl同步选中 // if (statusRef.current.compare) { // sheetRef3.current.selectCell(position.r, position.c, s.order); // sheetRef2.current.selectCell(position.r, position.c, s.order); // } }; const onCommit = (values, id) => { let currentNode = flowDetail.nodes.find?.(item => item.Id == version.template_node_id); let currentData = sheetRef.current.getSheetJson().data; let sheets = JSON.parse(JSON.stringify(currentData)); if (!currentNode.muti_version) { // audit_status=4 表示为清单推进后留存的副本.不计入多清单计算 let serviceVersion = versionList.find( item => item.audit_status != 4 && item.template_node_id == currentNode.Id ); if (serviceVersion) { message.error(`新建清单失败!业务节点【${currentNode.label}】只能有一个清单!`); return; } } sheets.forEach(item => { delete item.data; }); console.log(sheets); let params = { ...values, id: id, project_id: version.project_id, name: version.name, guid: version.guid, template_id: version.template_id, template_node_id: version.template_node_id, flow_id: version.flow_id, node_id: version.node_id, new_version: '0', audit_status: 0, data: JSON.stringify(sheets), base_id: version.id, }; dispatch({ type: 'detail/commitSheet', payload: params, callback: newVersion => { onCompare(false); setCommitVisible(false); setVersionVisible(false); changeVersion(newVersion); // 更新flow流程图 dispatch({ type: 'xflow/queryBoomFlowDetail', payload: { id: templateId, }, }); }, }); }; const onUpdate = () => { if (flow.active != 0) return; let currentData = sheetRef.current.getSheetJson().data; let sheets = JSON.parse(JSON.stringify(currentData)); sheets.forEach(item => { delete item.data; }); console.log(sheets); let params = { ...version, data: JSON.stringify(sheets), }; dispatch({ type: 'detail/saveSheet', payload: params, }); }; const onAudit = ({ audit_comment }) => { const flowNode = flow.currentNode; dispatch({ type: 'detail/approve', payload: { id: flow.active_id, project_id: projectId, audit_status: 2, flow_id: flowNode.flow_id, node_id: flowNode.seq, audit_comment, }, callback: newVersion => { setAuditVisible(false); // 更新flow流程图 dispatch({ type: 'xflow/queryBoomFlowDetail', payload: { id: templateId, }, }); localStorage.excelId = newVersion.id; setVersion({ ...version, flow_id: newVersion.flow_id, id: newVersion.id, }); }, }); }; const onApprove = flag => { if (!flag) { setAuditVisible(true); return; } let isSingle = false; let serviceNode; const flowNode = flow.currentNode; const getLastTemplateNodeId = data => { let result; const getFun = item => { if (item.flow_path?.length > 0) { getFun(item.flow_path[0]); } else { result = item.template_node_id; } }; if (!data) return version.template_node_id; getFun(data[0]); return result; }; let lastTemplateNodeId = version.template_node_id; if (version.flow_path) { //如果多节点审批 获取当前是否审批流程的最后一个审批节点 let flowPathList = JSON.parse(version.flow_path); lastTemplateNodeId = getLastTemplateNodeId(flowPathList); } // 判断是否为最后一个审批节点 if ( lastTemplateNodeId == version.template_node_id && flow.current == flow.list.FlowNodes.length - 1 ) { serviceNode = flowDetail.nodes.find?.(item => item.Id == version.next_template_node_id); if (!serviceNode.muti_version) { //audit_status=4 表示为清单推进后留存的副本.不计入多清单计算 isSingle = versionList.find( item => item.audit_status != 4 && item.template_node_id == serviceNode.Id ); } } Modal.confirm({ title: '提示', content: isSingle ? `节点【${serviceNode.label}】只能拥有一个清单,是否覆盖?` : `是否通过审批。`, okText: '确定', cancelText: '取消', onOk: () => { dispatch({ type: 'detail/approve', payload: { id: flow.active_id, project_id: projectId, audit_status: 3, flow_id: flowNode.flow_id, node_id: flowNode.seq, }, callback: newVersion => { // 更新flow流程图 dispatch({ type: 'xflow/queryBoomFlowDetail', payload: { id: templateId, }, }); // 更新审批流 dispatch({ type: 'detail/queryAuditList', payload: { template_id: version.template_id, template_node_id: version.template_node_id, flow_id: version.flow_id, version_id: version.version_id, }, }); if (flow.current == flow.list.FlowNodes.length - 1) { // 最后一个审核节点通过后 需要更新version id 不更不更,留在原地 // localStorage.excelId = newVersion.id; // setVersion({ // ...version, // flow_id: newVersion.flow_id, // id: newVersion.id, // }); } }, }); }, }); }; const onMerge = () => { const [sheet1, sheet2] = compareList; Modal.confirm({ title: '提示', content: `是否确认将【${sheet2.version_name}】改动的内容同步至【${sheet1.version_name || sheet1.name}】`, okText: '确定', cancelText: '取消', onOk() { // let sheet2Data = sheetRef2.current.getSheetJson() sheetRef3.current.mergeExcl(sheetRef2.current.updateCell); // setCompareList([...compareList]); // let currentData = sheetRef3.current.getSheetJson() // // 更新后重新比对 // sheetRef2.current.toggleCompare(false); // sheetRef2.current.toggleCompare(true, currentData); }, }); }; const onMergeVersion = async sheet2 => { // const [sheet1, sheet2] = checkSheets; const sheet1 = version; if (!sheet1.data) { sheet1.data = ( await queryDetail({ excel_id: sheet1.id, }) ).data; } if (!sheet2.data) { sheet2.data = ( await queryDetail({ excel_id: sheet2.id, }) ).data; } setIsMerge(true); setCompareList([sheet1, sheet2]); // setTimeout(() => { // sheetRef3.current.mergeExcl(sheet.data); // }, 400); }; const handleClickFile = () => { fileRef.current.click(); }; const handleMenuClick = e => { console.log('click', e); switch (e.key) { case 'back': // 返回 router.push(`/home`); break; // case 'version': // // 清单 // queryHistory(); // setCommentVisible(false); // setHistoryVisible(true); // break; case 'bomDetail': // 清单 setCommentVisible(true); break; case 'export': // 导出 handleExportClick(); break; case 'commitAudit': // 提交流转 setCommitAuditVisible(true); break; case 'flow': // 查看流程 setFlowVisible(true); break; case 'compare': // 比对 setCompareVisible(true); break; case 'template': // 模板 handleClickFile(); break; // case 'auditSuccess': // // 审核通过 // onApprove(true); // break; // case 'auditFailed': // // 审核拒绝 // onApprove(false); // break; // case 'edit': // // 编辑 // handleEdit(true); case 'merge': // 同步清单 setMergeVisible(true); break; case 'commit': // 提交 // handleClickCommit(); setCommitVisible(true); setCommentVisible(false); break; case 'attachment': // 附件 setFileVisible(true); queryFiles(); break; } }; const renderBtns = () => { // 判断是否为比对模式 if (compareList.length == 2) { // 判断是否为同步最新清单的比对 if (isMerge) { return ( <> ); } else { return ; } } const menuList = [ 返回, 详情, 导出, 比对, 附件, ]; // version.audit_status:4 为副本。不可操作 if (version.audit_status != 4) { //判断权限配置,如果配置了,就指定权限的人可提交,没配置就全部人都可提交 const getIsSubmit = () => { const nodeId = version.template_node_id; if (!flowDetail?.nodes || !nodeId) return; const node = flowDetail.nodes.find(item => item.Id == nodeId); if (!node || node.name == 'custom-circle') return; if (node?.role_list) { return node.role_list .split(',') .some(id => currentUser.roleList?.find(role => role.ID == id)); } return true; }; // console.log('是否有权限提交流转 ', getIsSubmit()); if (getIsSubmit() && version.audit_status != 3) menuList.push(提交流转); if (!isAuditor && canEdit() && !version.flow_id) { // menuList.push(编辑); menuList.push(同步); // menuList.push(提交); // if (history.list.length > 0) { // menuList.push(申请审批); // } } } return ( <> {menuList}}> ); }; const canEdit = () => { if (flow.list.FlowNodes.length - 1 == flow.current && active_audit == 3) return false; return active_audit != 1; }; const renderAlert = () => { const audit_comment = history.list[0]?.audit_comment; let item = ''; switch (active_audit) { case 0: if (!flow.list || flow.list.FlowNodes?.length == 0) return; item = ; break; case 1: item = ; break; case 2: item = ( ); break; case 3: item = ; break; } return
{item}
; }; const exportExcl = files => { sheetRef.current.uploadExcel(files, () => { fileRef.current.value = null; }); }; const getRowOneList = () => { const obj = sheetRef.current.getSheetJson(); console.log(obj); const list = []; obj.data.forEach(item => { list.push(item.data[0]); }); return list; }; //点击导出弹出选择导出列弹框 const handleExportClick = () => { setExportData(sheetRef.current.getSheetJson()); setExportVisible(true); }; const downloadExcel = checkValue => { sheetRef.current.downloadExcel(checkValue); setExportVisible(false); }; const queryHistory = id => { return new Promise(reslove => { dispatch({ type: 'detail/queryHistory', payload: { // excel_id: id || excelId, project_id: projectId, }, callback: reslove, }); }); }; const queryFiles = () => { dispatch({ type: 'detail/queryFiles', payload: { // excel_id: id || excelId, excel_id: version.id, }, }); }; const getUploadProps = () => { const token = getToken() || GetTokenFromUrl(); const uploadProps = { name: 'file', showUploadList: false, action: `/api/v1/purchase/attachment/${version.id}`, headers: { 'JWT-TOKEN': token, }, onChange(info) { if (info.file.status !== 'uploading') { console.log(info.file, info.fileList); } if (info.file.status === 'done') { message.success(`${info.file.name} 文件上传成功`); queryFiles(); } else if (info.file.status === 'error') { message.error(`${info.file.name} 文件上传失败`); } }, }; return uploadProps; }; const deleteFile = id => { dispatch({ type: 'detail/deleteFiles', id: id, callback: () => { queryFiles(); }, }); }; const queryHistoryDetail = async item => { return new Promise(resolve => { dispatch({ type: 'detail/queryHistoryDetail', payload: { excel_id: item.excel_id, history_id: item.id, }, callback: sheet => { resolve(sheet); }, }); }); }; const getLoading = () => { let effects = loading.effects; return !loading.effects['detail/queryComment'] && loading.models.detail; }; const getFilesLoading = () => { let effects = loading.effects; return loading.effects['detail/queryFiles']; }; const downloadFile = record => { window.location.href = `${record.url}`; }; const changeVersion = id => { let version; if (typeof id == 'object') { version = id; localStorage.excelId = version.id; localStorage.excelItem = JSON.stringify(version); } else { version = versionList.find(item => item.id == id); if (!version) return; localStorage.excelId = id; } setVersion(version); //请求历史版本 dispatch({ type: 'detail/queryVersionsTree', payload: { excel_id: version.id || localStorage.excelId, }, }); // 判断是否审批节点 if (version.flow_id) { dispatch({ type: 'detail/queryAuditList', payload: { template_id: version.template_id, template_node_id: version.template_node_id, flow_id: version.flow_id, version_id: version.version_id, }, }); dispatch({ type: 'detail/queryDingInstanceDetail', payload: { process_instance_id: version.ding_instance_id, //创建表单成功返回的id }, }); } }; const onSubmitNextNode = values => { dispatch({ type: 'detail/submitNextNode', payload: values, callback: newVersion => { setCommitAuditVisible(false); // 更新version // localStorage.excelId = newVersion.id; // changeVersion({ // ...version, // ...newVersion, // version_id: version.id // }); // 更新flow流程图 dispatch({ type: 'xflow/queryBoomFlowDetail', payload: { id: templateId, }, }); }, }); }; const getUser = newUser => { try { if (JSON.stringify(newUser) != JSON.stringify(userRef.current)) { userRef.current = newUser; setUser(newUser); } } catch (error) {} }; const renderNode = () => { const nodeId = version.template_node_id; if (!flowDetail?.nodes || !nodeId) return; const node = flowDetail.nodes.find(item => item.Id == nodeId); // return `当前清单:${version.version_name || '-'}; 当前节点:${node?.label || '-'}`; return ( 当前清单: {version.version_name || '-'}当前节点:{' '} {node?.label || '-'} ); }; const handleSubmitCell = (value, callback) => { if (!value) return; dispatch({ type: 'detail/addComment', payload: { ...cellPosition.current, comment: value, }, callback, }); }; useEffect(() => { dispatch({ type: 'detail/queryProjectRecord', payload: { project_id: projectId, }, }); dispatch({ type: 'xflow/queryBoomFlowDetail', payload: { id: templateId, }, }); dispatch({ type: 'user/fetch', }); }, []); useEffect(() => { if (compareList.length == 2) { const callback = ({ diff, add }) => { setUpdateCount(updateCount => { return { diff: diff.length, add: updateCount.add + add.length, }; }); }; var update1 = sheetRef3.current.toggleCompare(true, compareList[1].data, callback); var update2 = sheetRef2.current.toggleCompare(true, compareList[0].data, callback); } }, [compareList]); useEffect(() => { if (versionList.length == 0) return; if (!version.id) { const excelId = localStorage.excelItem ? JSON.parse(localStorage.excelItem) : localStorage.excelId; changeVersion(excelId); } else { changeVersion(version.id); } }, [versionList]); return (
{/* 非审批节点可以创建清单 */} {flow?.active == 0 && ( )} {renderNode()}
{user.map((item, id) => ( {item.Name} ))} {renderBtns()}
exportExcl(e.target.files)} />
{/* */} {version.flow_id ? ( ) : null} {/* {renderAlert()} */} {/* 判断是否为比对模式 */} {compareList.length == 2 ? ( <>
{compareList.map(renderSheetDom)}
) : (
{version.id && ( )}
)} changeVersion(version)} onClose={() => setVersionTreeVisible(false)} /> setCommentVisible(false)} /> setCompareVisible(false)} onOk={onCompare} /> setMergeVisible(false)} onOk={onMergeVersion} /> setExportVisible(false)} onOk={downloadExcel} /> setFlowVisible(false)} version={version} onChangeVersion={version => changeVersion(version)} /> setAuditVisible(false)} onOk={onAudit} /> setFileVisible(false)} uploadProps={getUploadProps()} DeleteFile={deleteFile} downloadFile={downloadFile} data={fileList} /> setVersionVisible(false)} onOk={values => onCommit(values)} /> setCommitAuditVisible(false)} onOk={onSubmitNextNode} />
); } export default connect(({ detail, user, xflow, loading }) => ({ flowDetail: xflow.flowDetail, auditList: detail.auditList, fileList: detail.fileList, history: detail.history, comment: detail.comment, instanceDetail: detail.dingInstanceDetail, currentUser: user.currentUser, roleList: detail.roleList, versionList: detail.versionList, versionTree: detail.versionTree, loading, }))(Detail);