Index.js 31 KB

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