Index.js 28 KB

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