CommitAuditModal.js 31 KB

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