Index.js 33 KB

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