CommitAuditModal.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. import React, { useEffect, useState, useRef, useMemo, useCallback } from 'react';
  2. import '@ant-design/compatible/assets/index.css';
  3. import {
  4. Modal,
  5. Input,
  6. Select,
  7. message,
  8. Cascader,
  9. Form,
  10. Tabs,
  11. Row,
  12. Col,
  13. Empty,
  14. Button,
  15. Steps,
  16. Popover,
  17. Upload,
  18. Table,
  19. Divider,
  20. Collapse,
  21. } from 'antd';
  22. import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
  23. import { connect } from 'dva';
  24. import { useForm } from 'rc-field-form';
  25. import AuditDetailed from './AuditDetailed';
  26. import AuditFlow from './AuditFlow';
  27. import {
  28. queryDingSchema,
  29. queryGetBomForm,
  30. queryProcessFlows,
  31. querySaveBomForm,
  32. } from '@/services/boom';
  33. import { Form as Form3x } from '@ant-design/compatible';
  34. import { getCurrentUser } from '@/utils/authority';
  35. import DDCode from '@/components/DDComponents/DDCode';
  36. import { uploadFile, queryUserListByRoleID } from '@/services/boom';
  37. import ApprovalProcess from './ApprovalProcess';
  38. import { uuidv4 } from '@antv/xflow';
  39. import AliyunOSSUpload from '@/components/OssUpload/AliyunOssUploader';
  40. import AttachmentTable from '@/components/AttachmentTable';
  41. import { getToken } from '@/utils/utils';
  42. import LuckyExcel from 'luckyexcel';
  43. import DDComponents from '@/components/DDComponents';
  44. import uploadExcelByUrl from '@/utils/uploadExcelByUrl';
  45. const { TextArea } = Input;
  46. const { Option } = Select;
  47. const { TabPane } = Tabs;
  48. const { Step } = Steps;
  49. // 提交
  50. function CommitAuditModal(props) {
  51. const {
  52. dispatch,
  53. visible,
  54. onClose,
  55. // loading,
  56. version,
  57. versionList,
  58. flowDetail,
  59. currentUser,
  60. luckysheet,
  61. userList,
  62. templateId,
  63. projectList,
  64. OSSData,
  65. } = props;
  66. const [auditId, setAuditId] = useState();
  67. const [data, setData] = useState([]);
  68. const [length, setLength] = useState(1);
  69. const [formData, setFromData] = useState({});
  70. const [auditList, setAuditList] = useState([]); //用于创建Tabs表单
  71. const [formComponentValues, setFormComponentValues] = useState({}); //用于创建Tabs表单
  72. const [form] = Form.useForm();
  73. const [aduitDetailForm] = Form.useForm();
  74. const [approvalProcess, setApprovalProcess] = useState({});
  75. const [selectUserList, setSelectUserList] = useState([]);
  76. const [curNodeIdx, setCurNodeIdx] = useState(-1);
  77. const [currentTab, setCurrentTab] = useState(0);
  78. const [dataSource, setDataSource] = useState([]);
  79. const [loading, setLoading] = useState(false);
  80. const uploadList = useRef([]);
  81. const formValueRef = useRef({
  82. form: [],
  83. });
  84. function getDataValue(item) {
  85. let arr = [];
  86. arr.push(item.value);
  87. if (item.children?.length > 0) {
  88. const res = getDataValue(item.children[0]);
  89. arr = arr.concat(res);
  90. }
  91. return arr;
  92. }
  93. const initFormList = async () => {
  94. const res = await queryGetBomForm({
  95. project_id: version.project_id,
  96. node_id: version.template_node_id,
  97. });
  98. if (res.data) {
  99. const formList = JSON.parse(res.data.json);
  100. setApprovalProcess(formList.approvalProcess || {});
  101. const prevFormData = JSON.parse(formList.formList?.[0] || '{}');
  102. setFormComponentValues(prevFormData);
  103. return formList;
  104. }
  105. return [];
  106. };
  107. /**
  108. *
  109. * @param {*} currentId 当前节点
  110. * @param {*} type 下一个节点的类型 custom-circle: 审批节点 custom-rect: 业务节点
  111. * @returns
  112. */
  113. const getNextNodes = (currentId, type, flag) => {
  114. const { edges, nodes } = flowDetail;
  115. if (!currentId) return [];
  116. // 删除虚线通向的节点
  117. // let targetIds = edges
  118. // .filter(edge => {
  119. // let line = edge.attrs?.line?.strokeDasharray?.split(' ');
  120. // return edge.source.cell == currentId && line && line[0] == '0';
  121. // })
  122. // .map(item => item.target.cell);
  123. // console.log(
  124. // '---------',
  125. // edges.filter(edge => edge.source.cell == currentId)
  126. // );
  127. const targetIds = edges
  128. .filter(edge => edge.source.cell === currentId)
  129. .map(item => item.target.cell);
  130. edges.filter(edge => edge.source.cell === currentId);
  131. const auditNodes = nodes.filter(node => {
  132. // ========为旧清单提供生成PSR的能力,后期舍弃=========
  133. if (flag && (node.node_type_psr == 3 || node.node_type_psr == 4)) return true;
  134. if (type && node.name !== type) {
  135. return false;
  136. }
  137. return targetIds.indexOf(node.id) !== -1;
  138. });
  139. const auditNode = auditNodes.map(item => {
  140. return {
  141. label: item.label,
  142. value: item.Id,
  143. Id: item.node_id,
  144. parentId: currentId,
  145. children: [],
  146. };
  147. });
  148. return auditNode || [];
  149. };
  150. const treeData = currentId => {
  151. const list = getNextNodes(currentId, 'custom-circle');
  152. const fun = nodes => {
  153. const re = nodes?.forEach(item => {
  154. const nextNodes = getNextNodes(item.Id, 'custom-circle');
  155. if (nextNodes || nextNodes.length > 0) list.push(...nextNodes);
  156. fun(nextNodes);
  157. });
  158. };
  159. fun(list);
  160. const fun2 = listParams => {
  161. const parents = listParams.filter(
  162. item => listParams.findIndex(node => node.Id == item.parentId) == -1
  163. );
  164. const translator = (p, children) => {
  165. setLength(length + 1);
  166. p.forEach(parent => {
  167. children.forEach((current, index) => {
  168. if (current.parentId === parent.Id) {
  169. const temp = JSON.parse(JSON.stringify(children));
  170. temp.splice(index, 1);
  171. translator([current], temp);
  172. if (!parent.children.find(item => item.Id === current.Id))
  173. parent.children.push(current);
  174. }
  175. });
  176. });
  177. };
  178. translator(parents, listParams);
  179. return parents;
  180. };
  181. return fun2(list);
  182. };
  183. const changeAudit = id => {
  184. const node = flowDetail.nodes.find?.(item => item.Id === id);
  185. setAuditId(node?.node_id);
  186. };
  187. const getFromData = (idList, newFormValues) => {
  188. let data = [];
  189. if (newFormValues) {
  190. try {
  191. data = JSON.parse(JSON.stringify(newFormValues));
  192. } catch (error) {
  193. console.log(error);
  194. }
  195. }
  196. const result = [];
  197. // 获取流转节点的层级关系
  198. let len = 0;
  199. let list = [];
  200. idList.forEach(item => {
  201. if (len < item.length) len = item.length;
  202. });
  203. for (let i = 0; i < len; i++) {
  204. idList.forEach(item => {
  205. if (item && item[i]) list.push(item[i]);
  206. });
  207. }
  208. let firstList = [...new Set(list)];
  209. // let attachment = await upload();
  210. firstList.forEach(id => {
  211. let approvalNode = flowDetail.nodes.find?.(item => item.Id == id);
  212. if (!approvalNode) return;
  213. const prevValues = data.length
  214. ? data.find(item => item.template_node_id === approvalNode.Id).formComponentValues
  215. : [];
  216. let values = data[approvalNode.Id] || prevValues || [];
  217. values.forEach(tempValue => {
  218. if (tempValue.type === 'DIYTable') {
  219. tempValue.value = tempValue.value.map(item => JSON.stringify(item));
  220. }
  221. });
  222. let audit_list = [],
  223. cc_list = [];
  224. approvalProcess[approvalNode.Id]?.forEach(item => {
  225. let arr = item[0].is_cc == 1 ? cc_list : audit_list;
  226. if (item[0].type == 'role') return arr.push(item[0].nowValue);
  227. return arr.push(item[0].value);
  228. });
  229. const formItem = {
  230. flow_id: approvalNode.flow_id,
  231. template_node_id: approvalNode.Id,
  232. formComponentValues: [...values], // { name: '附件', value: JSON.stringify(attachment) }
  233. audit_list,
  234. cc_list,
  235. };
  236. result.push(JSON.stringify(formItem));
  237. });
  238. return result;
  239. };
  240. // 填写表单实时计算审批流程
  241. const advanceSubmit = async newFormValues => {
  242. // console.log('重重新计算审批流程');
  243. const fieldsValue = await form.validateFields();
  244. let hasFlowId = true; //是否都绑定审批节点
  245. const result = Object.values(fieldsValue)
  246. .map(item => {
  247. if (item && Array.isArray(item)) return item;
  248. })
  249. .filter(item => item);
  250. const formList = await getFromData(result, newFormValues);
  251. let params = {
  252. desc: fieldsValue.desc,
  253. // 审核流程id
  254. flow_id: 0,
  255. node_level_id: 0,
  256. id: version.id,
  257. project_id: version.project_id,
  258. cur_template_node_id: version.template_node_id * 1, // 当前节点
  259. next_template_node_id: 0, // 审核完成后的业务节点
  260. template_node_id: null, // 将要流转的节点审批节点
  261. flow_path: null, // 审批节点数组
  262. // 模板id.一致就行
  263. template_id: version.template_id,
  264. cur_template_id: version.template_id,
  265. next_template_id: version.template_id,
  266. form_list: formList,
  267. };
  268. dispatch({
  269. type: 'detail/advanceSubmitNextNode',
  270. payload: params, // values,
  271. callback: data => {
  272. if (data) {
  273. setApprovalProcess(data);
  274. }
  275. },
  276. });
  277. };
  278. // 处理tabs页
  279. const setAuditListFun = async (approvalProcess = {}, prevFormData = []) => {
  280. const fieldsValue = await form.validateFields();
  281. let addAuditList = [];
  282. const result = Object.values(fieldsValue)
  283. .map(item => {
  284. if (item && Array.isArray(item)) return item;
  285. })
  286. .filter(item => item)
  287. .flat(Infinity);
  288. const nodeList = [...new Set(result)]
  289. .map(Id => {
  290. return flowDetail.nodes.find?.(item => item.Id == Id);
  291. })
  292. .filter(item => item);
  293. const flowIds = [...new Set(nodeList.map(item => item.flow_id))].join(',');
  294. const processFlows = await queryProcessFlows({ ids: flowIds });
  295. if (processFlows && processFlows?.length > 0) {
  296. const newlist = nodeList.map(node => {
  297. const curData = processFlows.find(item => item.id === node.flow_id);
  298. const newItem = {
  299. name: curData?.name,
  300. nodeId: node.Id,
  301. items: JSON.parse(curData?.form_json || '[]'),
  302. };
  303. return newItem;
  304. });
  305. addAuditList = [...addAuditList, ...newlist];
  306. }
  307. addAuditList.forEach(addAuditItem => {
  308. // 回填部分组件的历史数据
  309. if (prevFormData.length) {
  310. const currentForm = prevFormData.find(
  311. pItem => pItem.template_node_id === addAuditItem.nodeId
  312. );
  313. addAuditItem.items.forEach(DDComponent => {
  314. const prevValue = currentForm?.formComponentValues?.find(
  315. cItem => cItem.id === DDComponent.props.id
  316. );
  317. DDComponent.props.defaultValue = prevValue?.value || prevValue?.defaultValue;
  318. });
  319. }
  320. // 回填之前的值结束后需要把formComponentValues清空 防止提交之前的值
  321. setFormComponentValues([]);
  322. });
  323. setAuditList(addAuditList);
  324. // advanceSubmit();
  325. };
  326. const onChange = async (value, approvalProcess) => {
  327. // 加载之前提交的form数据
  328. const resFormData = await initFormList();
  329. const resData = resFormData?.formList;
  330. const prevFormData =
  331. resData && resData.length ? resData.map(resItem => JSON.parse(resItem)) : null;
  332. if (prevFormData && prevFormData.length) {
  333. const formValues = {};
  334. prevFormData.forEach(pItem => {
  335. pItem.formComponentValues?.map(item => {
  336. if (item.id.includes('ProjectField')) {
  337. item.value = [version.project_id];
  338. }
  339. });
  340. formValues[pItem.template_node_id] = [...pItem.formComponentValues];
  341. });
  342. setFormComponentValues(formValues);
  343. }
  344. if (value) {
  345. changeAudit(value[value.length - 1]);
  346. if (prevFormData !== null) {
  347. setAuditListFun(approvalProcess, prevFormData);
  348. } else {
  349. setAuditListFun(approvalProcess);
  350. }
  351. } else {
  352. changeAudit('');
  353. setAuditList([]);
  354. setApprovalProcess({});
  355. }
  356. form.setFieldValue('next_template_node_id', '');
  357. };
  358. useEffect(() => {
  359. if (!visible) return;
  360. const { edges, nodes } = flowDetail;
  361. const Id = version.template_node_id;
  362. const currentId = flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
  363. const data = treeData(currentId);
  364. const nextNodes = getNextNodes(currentId, 'custom-rect');
  365. if (data.length <= 0 || nextNodes.length > 0) {
  366. setAuditId(currentId);
  367. } else {
  368. const defaultValues = {};
  369. if (data.length === 1) {
  370. const value = getDataValue(data[0]);
  371. defaultValues.circle = value;
  372. } else {
  373. data.forEach((item, index) => {
  374. const value = getDataValue(item);
  375. defaultValues[`circle${index}`] = value;
  376. });
  377. }
  378. // 设置延迟,等待组件渲染
  379. setTimeout(async () => {
  380. form.setFieldsValue(defaultValues);
  381. const initForm = await initFormList();
  382. const tempAP = initForm?.approvalProcess ? initForm.approvalProcess : {};
  383. Object.values(defaultValues).forEach(value => onChange(value, tempAP));
  384. }, 200);
  385. }
  386. setData(data);
  387. // });
  388. }, [version.template_node_id, visible]);
  389. useEffect(() => {
  390. if (!visible) return;
  391. dispatch({
  392. type: 'detail/getChartOSSData',
  393. payload: {
  394. projectId: version.project_id,
  395. },
  396. });
  397. }, [visible]);
  398. useEffect(() => {
  399. form.resetFields();
  400. setAuditList([]);
  401. }, [visible]);
  402. useEffect(() => {
  403. if (!visible) {
  404. // 清空数据
  405. uploadList.current = [];
  406. }
  407. }, [visible]);
  408. // const OnModelFileDone = file => {
  409. // var path = OSSData.host + '/' + file.url;
  410. // uploadList.current = [...uploadList.current, path];
  411. // console.log(uploadList.current);
  412. // };
  413. const setUploadList = files => {
  414. uploadList.current = files.map(file => OSSData.host + '/' + file.url);
  415. // console.log(uploadList.current);
  416. };
  417. const OnUploading = file => {};
  418. const uploadProps = {
  419. OSSData: OSSData,
  420. // onDone: OnModelFileDone,
  421. onUploading: OnUploading,
  422. noStyle: false,
  423. onChange: setUploadList,
  424. // showUploadList: false,
  425. };
  426. const currentNodeId = useMemo(() => {
  427. let Id = version.template_node_id;
  428. setAuditId(currentNodeId);
  429. return flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
  430. }, [flowDetail, version]);
  431. const nextNodesList = useMemo(() => {
  432. if (!auditId && !currentNodeId) return [];
  433. return getNextNodes(auditId || currentNodeId, 'custom-rect', true);
  434. }, [auditId, currentNodeId, flowDetail]);
  435. const getReComputeAudit = (items, changedValues) => {
  436. const id = Object.keys(changedValues)[0];
  437. const formItem = items?.find(item => item.props.id == id);
  438. if (formItem && formItem.props?.required) return true;
  439. return false;
  440. };
  441. const handleTabChange = key => {
  442. const index = Number(key.split('_')[0]);
  443. setCurrentTab(index);
  444. };
  445. const onFormValueChange = (changedFields, allValues) => {
  446. const currentNodeID = auditList[currentTab]?.nodeId;
  447. if (!currentNodeID) return;
  448. const allFormItem = auditList[currentTab].items;
  449. const componentValue = formComponentValues[currentNodeID] || [];
  450. const currentFieldID = Object.keys(changedFields)[0];
  451. const formItem = allFormItem.find(item => item.props.id === currentFieldID);
  452. // 记录TextNote 以及其他未填写的值
  453. for (let index = 0; index < allFormItem.length; index++) {
  454. const tempFormItem = allFormItem[index];
  455. // 跳过DIYTable控件
  456. if (tempFormItem.componentName === 'DIYTable') {
  457. continue;
  458. }
  459. // 没找到就给默认值
  460. if (!componentValue.find(item => item.id === tempFormItem.props.id)) {
  461. if (tempFormItem.componentName === 'TextNote') {
  462. // 记录TextNote
  463. componentValue.push({
  464. name: tempFormItem.props.label,
  465. id: tempFormItem.props.id,
  466. value: [tempFormItem.props.placeholder],
  467. });
  468. } else {
  469. const prevValue = allValues[tempFormItem.props.id];
  470. // 从allValue中找到该值
  471. componentValue.push({
  472. name: tempFormItem.props.label,
  473. id: tempFormItem.props.id,
  474. value: Array.isArray(prevValue) ? [...prevValue] : [],
  475. });
  476. }
  477. }
  478. }
  479. // 记录变更的formItem值
  480. if (componentValue.length) {
  481. for (let index = 0; index < componentValue.length; index++) {
  482. const item = componentValue[index];
  483. if (item.id === currentFieldID) {
  484. componentValue[index] = {
  485. name: formItem.props.label,
  486. id: currentFieldID,
  487. value: Array.isArray(changedFields[currentFieldID])
  488. ? changedFields[currentFieldID]
  489. : [changedFields[currentFieldID]],
  490. };
  491. break;
  492. } else if (index === componentValue.length - 1) {
  493. componentValue.push({
  494. name: formItem.props.label,
  495. id: currentFieldID,
  496. value: Array.isArray(changedFields[currentFieldID])
  497. ? changedFields[currentFieldID]
  498. : [changedFields[currentFieldID]],
  499. });
  500. }
  501. }
  502. } else {
  503. componentValue.push({
  504. name: formItem.props.label,
  505. id: currentFieldID,
  506. value: [changedFields[currentFieldID]],
  507. });
  508. }
  509. let newFormValues = {
  510. ...formComponentValues,
  511. [currentNodeID]: componentValue,
  512. };
  513. setFormComponentValues(newFormValues);
  514. console.log(formComponentValues);
  515. formValueRef.current.form[currentNodeID] = [...componentValue];
  516. advanceSubmit(newFormValues);
  517. };
  518. // const getFlowPath = node => {
  519. // //[134, 135]
  520. // let itemData = {};
  521. // const Function = (curId, index) => {
  522. // if (!curId) return;
  523. // let data = {};
  524. // let approvalNode = flowDetail.nodes.find?.(item => item.Id == curId);
  525. // data.template_id = version.template_id;
  526. // data.flow_id = approvalNode?.flow_id || 0;
  527. // data.node_level_id = approvalNode?.flow_id ? 1 : 0;
  528. // data.template_node_id = approvalNode?.Id;
  529. // index++;
  530. // if (approvalNode?.Id) {
  531. // if (!approvalNode?.flow_id) {
  532. // hasFlowId = false;
  533. // }
  534. // }
  535. // const res = Function(node[index], index);
  536. // if (res) {
  537. // data.flow_path = [res];
  538. // }
  539. // return data;
  540. // };
  541. // itemData = Function(node[0], 0);
  542. // return itemData;
  543. // };
  544. const onFinish = async () => {
  545. if (loading) return;
  546. const isOk = Object.values(approvalProcess).every(item => {
  547. return item.every(cur => {
  548. if (cur[0].type == 'role') return cur[0].nowValue;
  549. return true;
  550. });
  551. });
  552. if (!isOk) {
  553. message.error('请选择审批人。');
  554. return;
  555. }
  556. var fieldsValue = await form.validateFields();
  557. let hasFlowId = true; //是否都绑定审批节点
  558. const getFlowPath = node => {
  559. //[134, 135]
  560. let itemData = {};
  561. const Function = (curId, index) => {
  562. if (!curId) return;
  563. let data = {};
  564. let approvalNode = flowDetail.nodes.find?.(item => item.Id == curId);
  565. data.template_id = version.template_id;
  566. data.flow_id = approvalNode?.flow_id || 0;
  567. data.node_level_id = approvalNode?.flow_id ? 1 : 0;
  568. data.template_node_id = approvalNode?.Id;
  569. index++;
  570. if (approvalNode?.Id) {
  571. if (!approvalNode?.flow_id) {
  572. hasFlowId = false;
  573. }
  574. }
  575. const res = Function(node[index], index);
  576. if (res) {
  577. data.flow_path = [res];
  578. }
  579. return data;
  580. };
  581. itemData = Function(node[0], 0);
  582. return itemData;
  583. };
  584. let result = Object.values(fieldsValue)
  585. .map(item => {
  586. if (item && Array.isArray(item)) return item;
  587. })
  588. .filter(item => item);
  589. let serviceNode = flowDetail.nodes.find?.(item => item.Id == fieldsValue.next_template_node_id);
  590. if (!serviceNode) {
  591. message.error('请选择需要流转的业务节点。');
  592. return;
  593. }
  594. const flowPath = result.map(item => getFlowPath(item));
  595. setLoading(true);
  596. try {
  597. // 检查Audit form是否为空
  598. const tempFormData = await aduitDetailForm.validateFields().catch(err => {
  599. message.error(err.errorFields[0].errors);
  600. setLoading(false);
  601. return false;
  602. });
  603. if (tempFormData === undefined || tempFormData === false) {
  604. return;
  605. }
  606. // 检查之后调用一次,防止什么都没改导致获取不到值
  607. onFormValueChange(tempFormData, tempFormData);
  608. const formList = getFromData(result, formComponentValues);
  609. let params = {
  610. desc: fieldsValue.desc,
  611. // 审核流程id
  612. // flow_id: approvalNode?.flow_id || 0,
  613. // node_level_id: approvalNode?.flow_id ? 1 : 0,
  614. id: version.id,
  615. project_id: version.project_id,
  616. cur_template_node_id: version.template_node_id * 1, // 当前节点
  617. next_template_node_id: serviceNode.Id * 1, // 审核完成后的业务节点
  618. // template_node_id: result[0][0], // 将要流转的节点审批节点
  619. // flow_path:flow_path, //审批节点数组
  620. // 模板id.一致就行
  621. template_id: version.template_id,
  622. cur_template_id: version.template_id,
  623. next_template_id: version.template_id,
  624. };
  625. if (serviceNode.node_type_psr == 3 || serviceNode.node_type_psr == 4) {
  626. let project = projectList.find(item => item.id == version?.project_id) || {};
  627. let sheetData = await uploadExcelByUrl(serviceNode.node_type_psr, version.id, project);
  628. params.data = JSON.stringify(sheetData);
  629. }
  630. // params.data = await uploadExcelByUrl(3, version.id);
  631. // console.log(params);
  632. if (result.length <= 0) {
  633. //直接走业务节点
  634. } else if (result.length <= 1 && result[0]?.length <= 1) {
  635. //单个审批节点
  636. let approvalNode = flowDetail.nodes.find?.(item => item.Id == result[0][0]);
  637. params.flow_id = approvalNode?.flow_id || 0;
  638. params.node_level_id = approvalNode?.flow_id ? 1 : 0;
  639. params.template_node_id = result[0][0]; // 将要流转的节点审批节点
  640. params.form_list = formList; //创建钉钉表单所需数据
  641. if (approvalNode?.Id) {
  642. if (!approvalNode?.flow_id) {
  643. hasFlowId = false;
  644. }
  645. }
  646. } else {
  647. //多节点审批
  648. params.template_node_id = result[0][0]; // 将要流转的节点审批节点
  649. params.flow_path = flowPath;
  650. params.form_list = formList; //创建钉钉表单所需数据
  651. }
  652. if (!hasFlowId) {
  653. message.error('当前存在审批节点未绑定审批流程!请联系管理员。');
  654. return;
  655. }
  656. await querySaveBomForm({
  657. project_id: version.project_id,
  658. node_id: version.template_node_id,
  659. json: JSON.stringify({ approvalProcess, formList }),
  660. });
  661. params.audit_series = uuidv4();
  662. if (version.audit_status == 5) {
  663. params.audit_status = version.audit_status;
  664. }
  665. params.files = uploadList.current.join(',');
  666. // console.log(params);
  667. onSubmitNextNode(params);
  668. } catch (error) {
  669. console.error(error);
  670. setLoading(false);
  671. message.error('请求失败');
  672. }
  673. };
  674. const onSubmitNextNode = values => {
  675. dispatch({
  676. type: 'detail/submitNextNode',
  677. payload: values,
  678. callback: newVersion => {
  679. setLoading(false);
  680. onClose();
  681. // 更新flow流程图
  682. dispatch({
  683. type: 'xflow/queryBoomFlowDetail',
  684. payload: {
  685. id: templateId,
  686. },
  687. });
  688. },
  689. });
  690. };
  691. const CascaderNode = index => {
  692. return (
  693. <Form.Item
  694. labelCol={{ span: 7 }}
  695. wrapperCol={{ span: 15 }}
  696. label={`审批节点${index + 1}`}
  697. name={`circle${index}`}
  698. key={`circle${index}`}
  699. >
  700. <Cascader style={{ width: '100%' }} options={data} onChange={onChange} />
  701. </Form.Item>
  702. );
  703. };
  704. // const upload = async () => {
  705. // let blob = await luckysheet.current.getExcelBolb();
  706. // let formData = new FormData();
  707. // formData.append('userid', currentUser.DingUserId);
  708. // formData.append('file', new File([blob], `${version.version_name}_${version.version_no}.xlsx`));
  709. //
  710. // try {
  711. // let res = await uploadFile(formData);
  712. // let data = JSON.parse(res.dentry);
  713. // return [
  714. // {
  715. // spaceId: String(data.spaceId),
  716. // fileName: data.name,
  717. // fileSize: String(data.spaceId),
  718. // fileType: data.extension,
  719. // fileId: data.id,
  720. // },
  721. // ];
  722. // } catch (error) {
  723. // message.error('附件上传失败');
  724. // }
  725. // };
  726. //
  727. // const columns = [
  728. // {
  729. // title: '文件名称',
  730. // dataIndex: 'name',
  731. // key: 'name',
  732. // },
  733. // {
  734. // title: '操作',
  735. // render: record => <a>删除</a>,
  736. // },
  737. // ];
  738. return (
  739. <Modal
  740. confirmLoading={loading}
  741. destroyOnClose
  742. title="提交流转目标"
  743. width={1000}
  744. visible={visible}
  745. onCancel={() => {
  746. setAuditId();
  747. onClose();
  748. }}
  749. onOk={onFinish}
  750. >
  751. <Form form={form}>
  752. {data.map((item, idx) => (data.length == 1 ? CascaderNode('') : CascaderNode(idx)))}
  753. <Form.Item
  754. labelCol={{ span: 7 }}
  755. wrapperCol={{ span: 15 }}
  756. label="业务节点"
  757. name="next_template_node_id"
  758. // rules={[{ required: true, message: '请选择业务节点' }]}
  759. >
  760. <Select style={{ width: '100%' }}>
  761. {nextNodesList.map(item => (
  762. <Option key={item.value}>{item.label}</Option>
  763. ))}
  764. </Select>
  765. </Form.Item>
  766. <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="备注信息" name="desc">
  767. <Input.TextArea />
  768. </Form.Item>
  769. <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="附件">
  770. {OSSData.host && <AliyunOSSUpload {...uploadProps} directory={false} label="上传文件" />}
  771. </Form.Item>
  772. </Form>
  773. <Collapse style={{ marginTop: 20 }}>
  774. <Collapse.Panel header="已上传附件" key="1">
  775. <AttachmentTable version={version} canDelete={version.last_version == 0} />
  776. </Collapse.Panel>
  777. </Collapse>
  778. <Tabs defaultActiveKey="1" onChange={handleTabChange}>
  779. {auditList.map((item, idx) => (
  780. <TabPane tab={item.name} key={`${idx}_${item.name}`}>
  781. <Row>
  782. <Col span={17}>
  783. <AuditDetailed
  784. allValues={formValueRef.current.form[item.nodeId]}
  785. items={item.items}
  786. form={aduitDetailForm}
  787. onValuesChange={onFormValueChange}
  788. />
  789. </Col>
  790. <Col offset={1} span={6}>
  791. {!approvalProcess[item.nodeId] ? ( // !formComponentValues[item.nodeId] ||
  792. <Empty description="请先填写表单" />
  793. ) : (
  794. <ApprovalProcess
  795. id={item.nodeId}
  796. approvalProcess={approvalProcess}
  797. onChange={setApprovalProcess}
  798. />
  799. )}
  800. </Col>
  801. </Row>
  802. </TabPane>
  803. ))}
  804. </Tabs>
  805. </Modal>
  806. );
  807. }
  808. export default connect(({ xflow, detail, user }) => ({
  809. flowDetail: xflow.flowDetail,
  810. versionList: detail.versionList,
  811. currentUser: user.currentUser,
  812. userList: user.list,
  813. OSSData: detail.OSSData,
  814. projectList: detail.project.list,
  815. }))(CommitAuditModal);