Index.js 29 KB

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