Index.js 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. import React, { useEffect, useState, useRef, useMemo } from 'react';
  2. import { UnorderedListOutlined, PlusOutlined } from '@ant-design/icons';
  3. import { Button, Modal, message, Alert, Avatar, Spin, Select, Menu, Dropdown } from 'antd';
  4. import { connect } from 'dva';
  5. import styles from './Index.less';
  6. import LuckySheet from './LuckySheet';
  7. import router from 'umi/router';
  8. import AuditModal from './AuditModal';
  9. // import CommentDrawer from './CommentDrawer';
  10. import RightDrawer from './RightDrawer';
  11. import CommitModal from './CommitModal';
  12. import CompareModal from './CompareModal';
  13. import ExportModal from './ExportModal';
  14. import FlowModal from './FlowModal';
  15. import HistoryModal from './HistoryModal';
  16. import TimeNode from './TimeNode';
  17. import FilesModal from './FilesModal';
  18. import VersionModal from './VersionModal';
  19. import CommitAuditModal from './CommitAuditModal';
  20. import CommentContent from '@/components/CommentContent';
  21. import MergeModal from './MergeModal';
  22. import { GetTokenFromUrl, getToken } from '@/utils/utils';
  23. import { queryDetail } from '@/services/boom';
  24. import HistoryDrawer from './HistoryDrawer';
  25. const LocalData = localStorage.luckysheet;
  26. const { Option } = Select;
  27. function Detail(props) {
  28. const {
  29. dispatch,
  30. comment,
  31. history,
  32. loading,
  33. currentUser,
  34. fileList,
  35. roleList,
  36. template,
  37. versionList,
  38. auditList,
  39. flowDetail,
  40. versionTree,
  41. match: { params },
  42. } = props;
  43. const [versionTreeVisible, setVersionTreeVisible] = useState(false);
  44. const [commentVisible, setCommentVisible] = useState(false);
  45. const [mergeVisible, setMergeVisible] = useState(false);
  46. const [compareVisible, setCompareVisible] = useState(false);
  47. const [exportVisible, setExportVisible] = useState(false);
  48. const [commitVisible, setCommitVisible] = useState(false);
  49. const [auditVisible, setAuditVisible] = useState(false);
  50. const [flowVisible, setFlowVisible] = useState(false);
  51. const [versionVisible, setVersionVisible] = useState(false);
  52. const [commitAuditVisible, setCommitAuditVisible] = useState(false);
  53. const [sheet, setSheet] = useState({});
  54. const [compareList, setCompareList] = useState([]);
  55. const [edit, setEdit] = useState(false);
  56. const [isMerge, setIsMerge] = useState(false);
  57. const [version, setVersion] = useState({});
  58. const [user, setUser] = useState([]);
  59. const [updateCount, setUpdateCount] = useState({
  60. diff: 0,
  61. add: 0,
  62. });
  63. const [fileVisible, setFileVisible] = useState(false);
  64. const [exportDate, setExportData] = useState([]);
  65. const sheetRef = useRef();
  66. const sheetRef2 = useRef();
  67. const sheetRef3 = useRef();
  68. const fileRef = useRef();
  69. const statusRef = useRef({
  70. edit: false,
  71. compare: false,
  72. });
  73. const cellPosition = useRef({});
  74. const projectId = parseInt(params.projectId);
  75. const templateId = parseInt(params.templateId);
  76. const flow = useMemo(() => {
  77. let data = {
  78. active: 0,
  79. active_id: null,
  80. current: 0,
  81. currentNode: {},
  82. list: {
  83. FlowNodes: [],
  84. },
  85. };
  86. if (version?.flow_id && auditList?.length > 0) {
  87. let item = auditList.find(item => item.list.id == version.flow_id);
  88. if (!item) return data;
  89. // 查询当前节点
  90. let current = item.list.FlowNodes.findIndex(node => node.seq == item.active);
  91. item.current = current == -1 ? 0 : current;
  92. // 保存当前所处节点
  93. item.currentNode = item.list.FlowNodes[item.current];
  94. data = item;
  95. }
  96. return data;
  97. }, [auditList, version]);
  98. const active_audit = flow.active_audit;
  99. const isAuditor = useMemo(() => {
  100. const getUserRole = () => {
  101. let roleID = flow.currentNode?.AuditRoleInfo?.ID;
  102. let item = currentUser.roleList.find(role => role.ID == roleID);
  103. if (item) return true;
  104. return false;
  105. };
  106. return active_audit == 1 && getUserRole();
  107. }, [active_audit, flow, currentUser]);
  108. const onSave = () => {
  109. let sheet1 = compareList[0];
  110. Modal.confirm({
  111. title: '提示',
  112. content: `是否确认保存【${sheet1.version_name || sheet1.name}】`,
  113. okText: '确定',
  114. cancelText: '取消',
  115. onOk() {
  116. let sheetData = sheetRef3.current.getSheetJson().data;
  117. sheetData.forEach(sheet => {
  118. delete sheet.data;
  119. });
  120. let params = {
  121. ...sheet1,
  122. data: JSON.stringify(sheetData),
  123. };
  124. dispatch({
  125. type: 'detail/commitSheet',
  126. payload: params,
  127. callback: () => {
  128. onCompare(false);
  129. },
  130. });
  131. },
  132. });
  133. };
  134. const onCompare = async checkSheets => {
  135. if (checkSheets) {
  136. const [sheet1, sheet2] = checkSheets;
  137. sheet1.data = (
  138. await queryDetail({
  139. excel_id: sheet1.id,
  140. })
  141. ).data;
  142. sheet2.data = (
  143. await queryDetail({
  144. excel_id: sheet2.id,
  145. })
  146. ).data;
  147. setCompareList(checkSheets);
  148. statusRef.current.compare = true;
  149. } else {
  150. let index = compareList.findIndex(item => item.id == sheet.id);
  151. // 退出比对模式
  152. if (index == 0) {
  153. sheetRef3.current.toggleCompare(false);
  154. } else if (index == 1) {
  155. sheetRef2.current.toggleCompare(false);
  156. }
  157. setIsMerge(false);
  158. setCompareList([]);
  159. setSheet({
  160. ...sheet,
  161. });
  162. setUpdateCount({
  163. diff: 0,
  164. add: 0,
  165. });
  166. statusRef.current.compare = false;
  167. }
  168. setCommentVisible(false);
  169. };
  170. const renderSheetDom = (item, index) => {
  171. return (
  172. <div key={item?.id || 'temp'} className={styles.sheetItem}>
  173. <h3>{item.version_name || item?.name}</h3>
  174. <LuckySheet
  175. className={styles.sheet}
  176. ref={!index ? sheetRef3 : sheetRef2}
  177. data={item.data || null}
  178. // onClickCell={onClickCell}
  179. />
  180. </div>
  181. );
  182. };
  183. const onClickCell = (cell, position, s) => {
  184. console.log(cell);
  185. if (cell?.cid && !statusRef.current.edit) {
  186. let payload = {
  187. sheet_id: s.order || '0',
  188. excel_id: version.id,
  189. cid: cell.cid,
  190. };
  191. dispatch({
  192. type: 'detail/queryComment',
  193. payload,
  194. });
  195. cellPosition.current = {
  196. ...payload,
  197. sheet_index: (s.seq || 0) + '',
  198. };
  199. // setCommentVisible(true);
  200. }
  201. // 比对模式下双excl同步选中
  202. // if (statusRef.current.compare) {
  203. // sheetRef3.current.selectCell(position.r, position.c, s.order);
  204. // sheetRef2.current.selectCell(position.r, position.c, s.order);
  205. // }
  206. };
  207. const onCommit = (values, id) => {
  208. let currentNode = flowDetail.nodes.find?.(item => item.Id == version.template_node_id);
  209. let currentData = sheetRef.current.getSheetJson().data;
  210. let sheets = JSON.parse(JSON.stringify(currentData));
  211. if (!currentNode.muti_version) {
  212. // audit_status=4 表示为清单推进后留存的副本.不计入多清单计算
  213. let serviceVersion = versionList.find(
  214. item => item.audit_status != 4 && item.template_node_id == currentNode.Id
  215. );
  216. if (serviceVersion) {
  217. message.error(
  218. `新建清单失败!业务节点【${currentNode.label}】只能有一个清单!`
  219. );
  220. return;
  221. }
  222. }
  223. sheets.forEach(item => {
  224. delete item.data;
  225. });
  226. console.log(sheets);
  227. let params = {
  228. ...values,
  229. id: id,
  230. project_id: version.project_id,
  231. name: version.name,
  232. guid: version.guid,
  233. template_id: version.template_id,
  234. template_node_id: version.template_node_id,
  235. flow_id: version.flow_id,
  236. node_id: version.node_id,
  237. new_version: '0',
  238. audit_status: 0,
  239. data: JSON.stringify(sheets),
  240. base_id: version.id,
  241. };
  242. dispatch({
  243. type: 'detail/commitSheet',
  244. payload: params,
  245. callback: newVersion => {
  246. onCompare(false);
  247. setCommitVisible(false);
  248. setVersionVisible(false);
  249. changeVersion(newVersion);
  250. // 更新flow流程图
  251. dispatch({
  252. type: 'xflow/queryBoomFlowDetail',
  253. payload: {
  254. id: templateId,
  255. },
  256. });
  257. },
  258. });
  259. };
  260. const onUpdate = () => {
  261. if (flow.active != 0) return;
  262. let currentData = sheetRef.current.getSheetJson().data;
  263. let sheets = JSON.parse(JSON.stringify(currentData));
  264. sheets.forEach(item => {
  265. delete item.data;
  266. });
  267. console.log(sheets);
  268. let params = {
  269. ...version,
  270. data: JSON.stringify(sheets),
  271. };
  272. dispatch({
  273. type: 'detail/saveSheet',
  274. payload: params,
  275. });
  276. };
  277. const onAudit = ({ audit_comment }) => {
  278. const flowNode = flow.currentNode;
  279. dispatch({
  280. type: 'detail/approve',
  281. payload: {
  282. id: flow.active_id,
  283. project_id: projectId,
  284. audit_status: 2,
  285. flow_id: flowNode.flow_id,
  286. node_id: flowNode.seq,
  287. audit_comment,
  288. },
  289. callback: newVersion => {
  290. setAuditVisible(false);
  291. // 更新flow流程图
  292. dispatch({
  293. type: 'xflow/queryBoomFlowDetail',
  294. payload: {
  295. id: templateId,
  296. },
  297. });
  298. localStorage.excelId = newVersion.id;
  299. setVersion({
  300. ...version,
  301. flow_id: newVersion.flow_id,
  302. id: newVersion.id,
  303. });
  304. },
  305. });
  306. };
  307. const onApprove = flag => {
  308. if (!flag) {
  309. setAuditVisible(true);
  310. return;
  311. }
  312. let isSingle = false;
  313. let serviceNode;
  314. const flowNode = flow.currentNode;
  315. const getLastTemplateNodeId = (data) => {
  316. let result;
  317. const getFun = (item) => {
  318. if(item.flow_path?.length > 0){
  319. getFun(item.flow_path[0])
  320. }else{
  321. result = item.template_node_id;
  322. }
  323. }
  324. if(!data) return version.template_node_id
  325. getFun(data[0])
  326. return result;
  327. }
  328. let lastTemplateNodeId = version.template_node_id;
  329. if(version.flow_path){
  330. //如果多节点审批 获取当前是否审批流程的最后一个审批节点
  331. let flowPathList = JSON.parse(version.flow_path)
  332. lastTemplateNodeId = getLastTemplateNodeId(flowPathList)
  333. }
  334. // 判断是否为最后一个审批节点
  335. if (lastTemplateNodeId == version.template_node_id && flow.current == flow.list.FlowNodes.length - 1) {
  336. serviceNode = flowDetail.nodes.find?.(item => item.Id == version.next_template_node_id);
  337. if (!serviceNode.muti_version) {
  338. //audit_status=4 表示为清单推进后留存的副本.不计入多清单计算
  339. isSingle = versionList.find(
  340. item => item.audit_status != 4 && item.template_node_id == serviceNode.Id
  341. );
  342. }
  343. }
  344. Modal.confirm({
  345. title: '提示',
  346. content: isSingle
  347. ? `节点【${serviceNode.label}】只能拥有一个清单,是否覆盖?`
  348. : `是否通过审批。`,
  349. okText: '确定',
  350. cancelText: '取消',
  351. onOk: () => {
  352. dispatch({
  353. type: 'detail/approve',
  354. payload: {
  355. id: flow.active_id,
  356. project_id: projectId,
  357. audit_status: 3,
  358. flow_id: flowNode.flow_id,
  359. node_id: flowNode.seq,
  360. },
  361. callback: newVersion => {
  362. // 更新flow流程图
  363. dispatch({
  364. type: 'xflow/queryBoomFlowDetail',
  365. payload: {
  366. id: templateId,
  367. },
  368. });
  369. // 更新审批流
  370. dispatch({
  371. type: 'detail/queryAuditList',
  372. payload: {
  373. template_id: version.template_id,
  374. template_node_id: version.template_node_id,
  375. flow_id: version.flow_id,
  376. version_id: version.version_id,
  377. },
  378. });
  379. if (flow.current == flow.list.FlowNodes.length - 1) {
  380. // 最后一个审核节点通过后 需要更新version id 不更不更,留在原地
  381. // localStorage.excelId = newVersion.id;
  382. // setVersion({
  383. // ...version,
  384. // flow_id: newVersion.flow_id,
  385. // id: newVersion.id,
  386. // });
  387. }
  388. },
  389. });
  390. },
  391. });
  392. };
  393. const onMerge = () => {
  394. const [sheet1, sheet2] = compareList;
  395. Modal.confirm({
  396. title: '提示',
  397. content: `是否确认将【${sheet2.version_name}】改动的内容同步至【${sheet1.version_name ||
  398. sheet1.name}】`,
  399. okText: '确定',
  400. cancelText: '取消',
  401. onOk() {
  402. // let sheet2Data = sheetRef2.current.getSheetJson()
  403. sheetRef3.current.mergeExcl(sheetRef2.current.updateCell);
  404. // setCompareList([...compareList]);
  405. // let currentData = sheetRef3.current.getSheetJson()
  406. // // 更新后重新比对
  407. // sheetRef2.current.toggleCompare(false);
  408. // sheetRef2.current.toggleCompare(true, currentData);
  409. },
  410. });
  411. };
  412. const onMergeVersion = async sheet2 => {
  413. // const [sheet1, sheet2] = checkSheets;
  414. const sheet1 = version;
  415. if (!sheet1.data) {
  416. sheet1.data = (
  417. await queryDetail({
  418. excel_id: sheet1.id,
  419. })
  420. ).data;
  421. }
  422. if (!sheet2.data) {
  423. sheet2.data = (
  424. await queryDetail({
  425. excel_id: sheet2.id,
  426. })
  427. ).data;
  428. }
  429. setIsMerge(true);
  430. setCompareList([sheet1, sheet2]);
  431. // setTimeout(() => {
  432. // sheetRef3.current.mergeExcl(sheet.data);
  433. // }, 400);
  434. };
  435. const handleClickFile = () => {
  436. fileRef.current.click();
  437. };
  438. const handleMenuClick = e => {
  439. console.log('click', e);
  440. switch (e.key) {
  441. case 'back':
  442. // 返回
  443. router.push(`/home`);
  444. break;
  445. // case 'version':
  446. // // 清单
  447. // queryHistory();
  448. // setCommentVisible(false);
  449. // setHistoryVisible(true);
  450. // break;
  451. case 'bomDetail':
  452. // 清单
  453. setCommentVisible(true);
  454. break;
  455. case 'export':
  456. // 导出
  457. handleExportClick();
  458. break;
  459. case 'commitAudit':
  460. // 提交流转
  461. setCommitAuditVisible(true);
  462. break;
  463. case 'flow':
  464. // 查看流程
  465. setFlowVisible(true);
  466. break;
  467. case 'compare':
  468. // 比对
  469. setCompareVisible(true);
  470. break;
  471. case 'template':
  472. // 模板
  473. handleClickFile();
  474. break;
  475. // case 'auditSuccess':
  476. // // 审核通过
  477. // onApprove(true);
  478. // break;
  479. // case 'auditFailed':
  480. // // 审核拒绝
  481. // onApprove(false);
  482. // break;
  483. // case 'edit':
  484. // // 编辑
  485. // handleEdit(true);
  486. case 'merge':
  487. // 同步清单
  488. setMergeVisible(true);
  489. break;
  490. case 'commit':
  491. // 提交
  492. // handleClickCommit();
  493. setCommitVisible(true);
  494. setCommentVisible(false);
  495. break;
  496. case 'attachment':
  497. // 附件
  498. setFileVisible(true);
  499. queryFiles();
  500. break;
  501. }
  502. };
  503. const renderBtns = () => {
  504. // 判断是否为比对模式
  505. if (compareList.length == 2) {
  506. // 判断是否为同步最新清单的比对
  507. if (isMerge) {
  508. return (
  509. <>
  510. <Button type="primary" onClick={() => onSave()}>
  511. 保存
  512. </Button>
  513. <Button onClick={() => onMerge()}>同步新增内容</Button>
  514. <Button onClick={() => onCompare(false)}>取消同步</Button>
  515. </>
  516. );
  517. } else {
  518. return <Button onClick={() => onCompare(false)}>取消比对</Button>;
  519. }
  520. }
  521. const menuList = [
  522. <Menu.Item key="back">返回</Menu.Item>,
  523. <Menu.Item key="bomDetail">详情</Menu.Item>,
  524. <Menu.Item key="export">导出</Menu.Item>,
  525. <Menu.Item key="compare">比对</Menu.Item>,
  526. <Menu.Item key="attachment">附件</Menu.Item>,
  527. ];
  528. // version.audit_status:4 为副本。不可操作
  529. if (version.audit_status != 4) {
  530. //判断权限配置,如果配置了,就指定权限的人可提交,没配置就全部人都可提交
  531. const getIsSubmit = () => {
  532. const nodeId = version.template_node_id;
  533. if (!flowDetail?.nodes || !nodeId) return;
  534. const node = flowDetail.nodes.find(item => item.Id == nodeId);
  535. if(node.name=='custom-circle') return ;
  536. if( node?.role_list ){
  537. return node.role_list.split(",").some(id=> currentUser.roleList?.find(role=>role.ID == id))
  538. }
  539. return true;
  540. }
  541. console.log("是否有权限提交流转 ", getIsSubmit())
  542. if(getIsSubmit()) menuList.push(<Menu.Item key="commitAudit">提交流转</Menu.Item>);
  543. if (!isAuditor && canEdit() && !version.flow_id) {
  544. // menuList.push(<Menu.Item key="edit">编辑</Menu.Item>);
  545. menuList.push(<Menu.Item key="merge">同步</Menu.Item>);
  546. // menuList.push(<Menu.Item key="commit">提交</Menu.Item>);
  547. // if (history.list.length > 0) {
  548. // menuList.push(<Menu.Item key="approval">申请审批</Menu.Item>);
  549. // }
  550. }
  551. }
  552. return (
  553. <>
  554. <Dropdown overlay={<Menu onClick={handleMenuClick}>{menuList}</Menu>}>
  555. <UnorderedListOutlined style={{ fontSize: 30, cursor: 'pointer' }} />
  556. </Dropdown>
  557. </>
  558. );
  559. };
  560. const canEdit = () => {
  561. if (flow.list.FlowNodes.length - 1 == flow.current && active_audit == 3) return false;
  562. return active_audit != 1;
  563. };
  564. const renderAlert = () => {
  565. const audit_comment = history.list[0]?.audit_comment;
  566. let item = '';
  567. switch (active_audit) {
  568. case 0:
  569. if (!flow.list || flow.list.FlowNodes?.length == 0) return
  570. item = <Alert message="审批拒绝" type="error" />;
  571. break;
  572. case 1:
  573. item = <Alert message="等待审核中" type="info" />;
  574. break;
  575. case 2:
  576. item = (
  577. <Alert
  578. message={`审批被拒绝${
  579. audit_comment ? `,拒绝原因:${audit_comment}` : ''
  580. }。请修改后重新提交`}
  581. type="error"
  582. />
  583. );
  584. break;
  585. case 3:
  586. item = <Alert message="审批通过" type="success" />;
  587. break;
  588. }
  589. return <div style={{ marginTop: 20 }}>{item}</div>;
  590. };
  591. const exportExcl = files => {
  592. sheetRef.current.uploadExcel(files, () => {
  593. fileRef.current.value = null;
  594. });
  595. };
  596. const getRowOneList = () => {
  597. const obj = sheetRef.current.getSheetJson();
  598. console.log(obj);
  599. const list = [];
  600. obj.data.forEach(item => {
  601. list.push(item.data[0]);
  602. });
  603. return list;
  604. };
  605. //点击导出弹出选择导出列弹框
  606. const handleExportClick = () => {
  607. setExportData(sheetRef.current.getSheetJson());
  608. setExportVisible(true);
  609. };
  610. const downloadExcel = checkValue => {
  611. sheetRef.current.downloadExcel(checkValue);
  612. setExportVisible(false);
  613. };
  614. const queryHistory = id => {
  615. return new Promise(reslove => {
  616. dispatch({
  617. type: 'detail/queryHistory',
  618. payload: {
  619. // excel_id: id || excelId,
  620. project_id: projectId,
  621. },
  622. callback: reslove,
  623. });
  624. });
  625. };
  626. const queryFiles = () => {
  627. dispatch({
  628. type: 'detail/queryFiles',
  629. payload: {
  630. // excel_id: id || excelId,
  631. excel_id: version.id,
  632. },
  633. });
  634. };
  635. const getUploadProps = () => {
  636. const token = getToken() || GetTokenFromUrl();
  637. const uploadProps = {
  638. name: 'file',
  639. showUploadList: false,
  640. action: `/api/v1/purchase/attachment/${version.id}`,
  641. headers: {
  642. 'JWT-TOKEN': token,
  643. },
  644. onChange(info) {
  645. if (info.file.status !== 'uploading') {
  646. console.log(info.file, info.fileList);
  647. }
  648. if (info.file.status === 'done') {
  649. message.success(`${info.file.name} 文件上传成功`);
  650. queryFiles();
  651. } else if (info.file.status === 'error') {
  652. message.error(`${info.file.name} 文件上传失败`);
  653. }
  654. },
  655. };
  656. return uploadProps;
  657. };
  658. const deleteFile = id => {
  659. dispatch({
  660. type: 'detail/deleteFiles',
  661. id: id,
  662. callback: () => {
  663. queryFiles();
  664. },
  665. });
  666. };
  667. const queryHistoryDetail = async item => {
  668. return new Promise(resolve => {
  669. dispatch({
  670. type: 'detail/queryHistoryDetail',
  671. payload: {
  672. excel_id: item.excel_id,
  673. history_id: item.id,
  674. },
  675. callback: sheet => {
  676. resolve(sheet);
  677. },
  678. });
  679. });
  680. };
  681. const getLoading = () => {
  682. let effects = loading.effects;
  683. return !loading.effects['detail/queryComment'] && loading.models.detail;
  684. };
  685. const getFilesLoading = () => {
  686. let effects = loading.effects;
  687. return loading.effects['detail/queryFiles'];
  688. };
  689. const downloadFile = record => {
  690. window.location.href = `${record.url}`;
  691. };
  692. const changeVersion = id => {
  693. let version;
  694. if (typeof id == 'object') {
  695. version = id;
  696. localStorage.excelId = version.id;
  697. } else {
  698. version = versionList.find(item => item.id == id);
  699. if (!version) return;
  700. localStorage.excelId = id;
  701. }
  702. setVersion(version);
  703. //请求历史版本
  704. dispatch({
  705. type:'detail/queryVersionsTree',
  706. payload: {
  707. excel_id: version.id || localStorage.excelId,
  708. },
  709. })
  710. // 判断是否审批节点
  711. if (version.flow_id) {
  712. dispatch({
  713. type: 'detail/queryAuditList',
  714. payload: {
  715. template_id: version.template_id,
  716. template_node_id: version.template_node_id,
  717. flow_id: version.flow_id,
  718. version_id: version.version_id,
  719. },
  720. });
  721. }
  722. };
  723. const onSubmitNextNode = values => {
  724. dispatch({
  725. type: 'detail/submitNextNode',
  726. payload: values,
  727. callback: newVersion => {
  728. setCommitAuditVisible(false);
  729. // 更新version
  730. // localStorage.excelId = newVersion.id;
  731. // changeVersion({
  732. // ...version,
  733. // ...newVersion,
  734. // version_id: version.id
  735. // });
  736. // 更新flow流程图
  737. dispatch({
  738. type: 'xflow/queryBoomFlowDetail',
  739. payload: {
  740. id: templateId,
  741. },
  742. });
  743. },
  744. });
  745. };
  746. const getUser = user => {
  747. setUser(user);
  748. };
  749. const renderNode = () => {
  750. const nodeId = version.template_node_id;
  751. if (!flowDetail?.nodes || !nodeId) return;
  752. const node = flowDetail.nodes.find(item => item.Id == nodeId);
  753. // return `当前清单:${version.version_name || '-'}; 当前节点:${node?.label || '-'}`;
  754. return(
  755. <span className={styles.curTitle}>
  756. 当前清单: <span>{version.version_name || '-'}</span>当前节点: <span>{node?.label || '-'}</span>
  757. </span>
  758. )
  759. };
  760. const handleSubmitCell = (value, callback) => {
  761. if (!value) return;
  762. dispatch({
  763. type: 'detail/addComment',
  764. payload: {
  765. ...cellPosition.current,
  766. comment: value,
  767. },
  768. callback,
  769. });
  770. };
  771. useEffect(() => {
  772. dispatch({
  773. type: 'detail/queryProjectRecord',
  774. payload: {
  775. project_id: projectId,
  776. },
  777. });
  778. dispatch({
  779. type: 'xflow/queryBoomFlowDetail',
  780. payload: {
  781. id: templateId,
  782. },
  783. });
  784. dispatch({
  785. type: 'user/fetch',
  786. });
  787. }, []);
  788. useEffect(() => {
  789. if (compareList.length == 2) {
  790. const callback = ({ diff, add }) => {
  791. setUpdateCount(updateCount => {
  792. return {
  793. diff: diff.length,
  794. add: updateCount.add + add.length,
  795. };
  796. });
  797. };
  798. var update1 = sheetRef3.current.toggleCompare(true, compareList[1].data, callback);
  799. var update2 = sheetRef2.current.toggleCompare(true, compareList[0].data, callback);
  800. }
  801. }, [compareList]);
  802. useEffect(() => {
  803. if (versionList.length == 0) return;
  804. if (!version.id) {
  805. const excelId = localStorage.excelId;
  806. changeVersion(excelId);
  807. } else {
  808. changeVersion(version.id);
  809. }
  810. }, [versionList]);
  811. return (
  812. <Spin spinning={false}>
  813. <div className={styles.top}>
  814. <div>
  815. <Button type="primary" style={{ marginRight: 20 }} onClick={() => setFlowVisible(true)}>
  816. 查看流程
  817. </Button>
  818. {/* 非审批节点可以创建清单 */}
  819. {flow?.active == 0 && (
  820. <Button type="primary" onClick={() => setVersionVisible(true)}>
  821. 新建清单
  822. </Button>
  823. )}
  824. {renderNode()}
  825. </div>
  826. <div className={styles.btns}>
  827. <Button type="primary" style={{ marginRight: 20 }} onClick={() => setVersionTreeVisible(true)}>
  828. 历史版本
  829. </Button>
  830. <Avatar.Group style={{ marginRight: 20 }}>
  831. {user.map((item, id) => (
  832. <Avatar key={`${id}-${item.name}`} style={{ backgroundColor: '#008dff' }} size="large">
  833. {item.Name}
  834. </Avatar>
  835. ))}
  836. </Avatar.Group>
  837. {renderBtns()}
  838. </div>
  839. <input
  840. type="file"
  841. ref={fileRef}
  842. style={{ display: 'none' }}
  843. onChange={e => exportExcl(e.target.files)}
  844. />
  845. </div>
  846. <TimeNode flow={flow} isAuditor={isAuditor} onApprove={onApprove}></TimeNode>
  847. {renderAlert()}
  848. {/* 判断是否为比对模式 */}
  849. {compareList.length == 2 ? (
  850. <>
  851. <Alert
  852. message={`比对结果:${updateCount.diff}项差异。${updateCount.add}项新增`}
  853. type="info"
  854. />
  855. <div className={styles.sheetBox}>{compareList.map(renderSheetDom)}</div>
  856. </>
  857. ) : (
  858. <div className={styles.sheetBox}>
  859. {version.id && (
  860. <LuckySheet
  861. className={styles.sheet}
  862. ref={sheetRef}
  863. onClickCell={onClickCell}
  864. version={version}
  865. templateId={templateId}
  866. getUser={getUser}
  867. onUpdate={onUpdate}
  868. />
  869. )}
  870. </div>
  871. )}
  872. <HistoryDrawer
  873. versionTree={versionTree}
  874. version={version}
  875. visible={versionTreeVisible}
  876. onChangeVersion={version => changeVersion(version)}
  877. onClose={() => setVersionTreeVisible(false)}
  878. />
  879. <CommentContent
  880. title="单元格沟通记录"
  881. comment={comment}
  882. onSubmit={handleSubmitCell}
  883. loading={loading.effects['detail/queryComment'] || loading.effects['detail/addComment']}
  884. />
  885. <RightDrawer
  886. version={version}
  887. visible={commentVisible}
  888. onClose={() => setCommentVisible(false)}
  889. />
  890. <CompareModal
  891. visible={compareVisible}
  892. version={version}
  893. onClose={() => setCompareVisible(false)}
  894. onOk={onCompare}
  895. />
  896. <MergeModal
  897. visible={mergeVisible}
  898. version={version}
  899. onClose={() => setMergeVisible(false)}
  900. onOk={onMergeVersion}
  901. />
  902. <ExportModal
  903. visible={exportVisible}
  904. sheet={exportDate.data}
  905. onClose={() => setExportVisible(false)}
  906. onOk={downloadExcel}
  907. />
  908. <FlowModal
  909. visible={flowVisible}
  910. onClose={() => setFlowVisible(false)}
  911. version={version}
  912. onChangeVersion={version => changeVersion(version)}
  913. />
  914. <AuditModal
  915. loading={getLoading()}
  916. visible={auditVisible}
  917. onClose={() => setAuditVisible(false)}
  918. onOk={onAudit}
  919. />
  920. <FilesModal
  921. loading={getFilesLoading()}
  922. visible={fileVisible}
  923. onClose={() => setFileVisible(false)}
  924. uploadProps={getUploadProps()}
  925. DeleteFile={deleteFile}
  926. downloadFile={downloadFile}
  927. data={fileList}
  928. />
  929. <VersionModal
  930. loading={getLoading()}
  931. visible={versionVisible}
  932. onClose={() => setVersionVisible(false)}
  933. onOk={values => onCommit(values)}
  934. />
  935. <CommitAuditModal
  936. loading={getLoading()}
  937. visible={commitAuditVisible}
  938. version={version}
  939. onClose={() => setCommitAuditVisible(false)}
  940. onOk={onSubmitNextNode}
  941. />
  942. </Spin>
  943. );
  944. }
  945. export default connect(({ detail, user, xflow, loading }) => ({
  946. flowDetail: xflow.flowDetail,
  947. auditList: detail.auditList,
  948. fileList: detail.fileList,
  949. history: detail.history,
  950. comment: detail.comment,
  951. currentUser: user.currentUser,
  952. roleList: detail.roleList,
  953. versionList: detail.versionList,
  954. versionTree: detail.versionTree,
  955. loading,
  956. }))(Detail);