CommitAuditModal.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. import React, { useEffect, useState, useRef, useMemo } from 'react';
  2. import '@ant-design/compatible/assets/index.css';
  3. import { Modal, Input, Select, message, Cascader, Form, Tabs } from 'antd';
  4. import { connect } from 'dva';
  5. import { isArray, result } from 'lodash';
  6. import { useForm } from 'rc-field-form';
  7. import { async } from '@antv/x6/lib/registry/marker/async';
  8. import AuditDetailed from './AuditDetailed';
  9. import AuditFlow from './AuditFlow';
  10. import { queryDingSchema } from '@/services/boom';
  11. import { Form as Form3x } from '@ant-design/compatible';
  12. const { TextArea } = Input;
  13. const { Option } = Select;
  14. const { TabPane } = Tabs;
  15. // 提交
  16. function CommitAuditModal(props) {
  17. const { visible, onClose, onOk, loading, version, versionList, flowDetail } = props;
  18. const [auditId, setAuditId] = useState();
  19. const [data, setData] = useState([]);
  20. const [length, setLength] = useState(1);
  21. const [formData, setFromData] = useState({});
  22. const [auditList, setAuditList] = useState([]); //用于创建Tabs表单
  23. const [formComponentValues, setFormComponentValues] = useState({}); //用于创建Tabs表单
  24. const [form] = Form.useForm();
  25. useEffect(() => {
  26. if (!visible) return;
  27. const { edges, nodes } = flowDetail;
  28. let Id = version.template_node_id;
  29. const currentId = flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
  30. const data = treeData(currentId);
  31. if (data.length <= 0) setAuditId(currentId);
  32. setData(data);
  33. }, [auditId, version.template_node_id, visible]);
  34. useEffect(() => {
  35. form.resetFields();
  36. setAuditList([]);
  37. }, [visible]);
  38. const treeData = currentId => {
  39. const list = getNextNodes(currentId, 'custom-circle');
  40. const fun = nodes => {
  41. const re = nodes?.forEach((item, idx) => {
  42. const data = getNextNodes(item.Id, 'custom-circle');
  43. if (data || data.length > 0) list.push(...data);
  44. fun(data);
  45. });
  46. };
  47. fun(list);
  48. const fun2 = list => {
  49. const parents = list.filter(item => list.findIndex(node => node.Id == item.parentId) == -1);
  50. let translator = (parents, children) => {
  51. setLength(length + 1);
  52. parents.forEach(parent => {
  53. children.forEach((current, index) => {
  54. if (current.parentId === parent.Id) {
  55. let temp = JSON.parse(JSON.stringify(children));
  56. temp.splice(index, 1);
  57. translator([current], temp);
  58. if (!parent.children.find(item => item.Id == current.Id))
  59. parent.children.push(current);
  60. }
  61. });
  62. });
  63. };
  64. translator(parents, list);
  65. return parents;
  66. };
  67. return fun2(list);
  68. };
  69. const currentNodeId = useMemo(() => {
  70. let Id = version.template_node_id;
  71. setAuditId(currentNodeId);
  72. return flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
  73. }, [flowDetail, version]);
  74. /**
  75. *
  76. * @param {*} currentId 当前节点
  77. * @param {*} type 下一个节点的类型 custom-circle: 审批节点 custom-rect: 业务节点
  78. * @returns
  79. */
  80. const getNextNodes = (currentId, type) => {
  81. const { edges, nodes } = flowDetail;
  82. if (!currentId) return [];
  83. //删除虚线通向的节点
  84. // let targetIds = edges
  85. // .filter(edge => {
  86. // let line = edge.attrs?.line?.strokeDasharray?.split(' ');
  87. // return edge.source.cell == currentId && line && line[0] == '0';
  88. // })
  89. // .map(item => item.target.cell);
  90. let targetIds = edges
  91. .filter(edge => edge.source.cell == currentId)
  92. .map(item => item.target.cell);
  93. edges.filter(edge => edge.source.cell == currentId);
  94. let auditNodes = nodes.filter(node => {
  95. if (type && node.name != type) {
  96. return false;
  97. }
  98. return targetIds.indexOf(node.id) != -1;
  99. });
  100. const result = auditNodes.map(item => {
  101. return {
  102. label: item.label,
  103. value: item.Id,
  104. Id: item.node_id,
  105. parentId: currentId,
  106. children: [],
  107. };
  108. });
  109. return result || [];
  110. };
  111. const changeAudit = id => {
  112. let node = flowDetail.nodes.find?.(item => item.Id == id);
  113. setAuditId(node.node_id);
  114. };
  115. const onChange = value => {
  116. changeAudit(value[value.length - 1]);
  117. setAuditListFun();
  118. };
  119. //处理tabs页
  120. const setAuditListFun = async () => {
  121. var fieldsValue = await form.validateFields();
  122. let addAuditList = [];
  123. let result = Object.values(fieldsValue)
  124. .map(item => {
  125. if (item && Array.isArray(item)) return item;
  126. })
  127. .filter(item => item)
  128. .flat(Infinity);
  129. let codeList = [...new Set(result)]
  130. .map(Id => {
  131. return flowDetail.nodes.find?.(item => item.Id == Id);
  132. })
  133. .filter(item => item.process_code);
  134. for (let i = 0; i < codeList.length; i++) {
  135. let res = await queryDingSchema({ process_code: codeList[i].process_code });
  136. if (res) {
  137. res.data.result.nodeId = codeList[i].Id;
  138. addAuditList.push(res.data.result);
  139. }
  140. }
  141. console.log(addAuditList);
  142. addAuditList.forEach((item, index) => {
  143. let Components = Form3x.create({
  144. onValuesChange: (props, changedValues, allValues) => {
  145. const { items } = props;
  146. console.log(item);
  147. formComponentValues[item.nodeId] = items
  148. .map(item => {
  149. const itemProps = item.props;
  150. if (!itemProps.label) return;
  151. let val = allValues[itemProps.id];
  152. if (val instanceof Object) {
  153. return {
  154. name: itemProps.label,
  155. id: itemProps.id,
  156. ...val,
  157. };
  158. }
  159. return {
  160. name: itemProps.label,
  161. // id: itemProps.id,
  162. value: allValues[itemProps.id] || '',
  163. };
  164. })
  165. .filter(item => item);
  166. setFormComponentValues({ ...formComponentValues });
  167. },
  168. })(AuditDetailed);
  169. item.FormComponents = <Components items={item.schemaContent.items} />;
  170. });
  171. setAuditList(addAuditList);
  172. };
  173. const getFromData = idList => {
  174. const data = formComponentValues;
  175. const result = [];
  176. //获取流转节点的层级关系
  177. let len = 0;
  178. let list = [];
  179. idList.forEach(item => {
  180. if (len < item.length) len = item.length;
  181. });
  182. for (let i = 0; i < len; i++) {
  183. idList.forEach(item => {
  184. if (item && item[i]) list.push(item[i]);
  185. });
  186. }
  187. let firstList = [...new Set(list)];
  188. // let firstList = idList[0];
  189. // for (let i = 1; i < idList.length; i++) {
  190. // let item = idList[i];
  191. // item.forEach(itemId => {
  192. // let idx = firstList.findIndex(id => id == itemId);
  193. // if (idx > 0 && !firstList.find(cur => cur == item[idx - 1])) {
  194. // firstList.splice(idx, 0, item[i - 1]);
  195. // }
  196. // });
  197. // }
  198. firstList.forEach(id => {
  199. let approvalNode = flowDetail.nodes.find?.(item => item.Id == id);
  200. const formItem = {
  201. processCode: approvalNode.process_code,
  202. originatorUserId: '16569001414345099',
  203. deptId: '14169890',
  204. template_node_id: `${approvalNode.Id}`,
  205. formComponentValues: data[approvalNode.Id],
  206. };
  207. result.push(JSON.stringify(formItem));
  208. });
  209. return result;
  210. };
  211. const onFinish = async () => {
  212. var fieldsValue = await form.validateFields();
  213. console.log(formComponentValues);
  214. let hasFlowId = true; //是否都绑定审批节点
  215. const getFlowPath = node => {
  216. //[134, 135]
  217. let itemData = {};
  218. const Function = (curId, index) => {
  219. if (!curId) return;
  220. let data = {};
  221. let approvalNode = flowDetail.nodes.find?.(item => item.Id == curId);
  222. data.template_id = version.template_id;
  223. data.flow_id = approvalNode?.flow_id || 0;
  224. data.node_level_id = approvalNode?.flow_id ? 1 : 0;
  225. data.template_node_id = approvalNode?.Id;
  226. index++;
  227. if (approvalNode?.Id) {
  228. if (!approvalNode?.flow_id) {
  229. hasFlowId = false;
  230. }
  231. }
  232. const res = Function(node[index], index);
  233. if (res) {
  234. data.flow_path = [res];
  235. }
  236. return data;
  237. };
  238. itemData = Function(node[0], 0);
  239. return itemData;
  240. };
  241. let result = Object.values(fieldsValue)
  242. .map(item => {
  243. if (item && Array.isArray(item)) return item;
  244. })
  245. .filter(item => item);
  246. let serviceNode = flowDetail.nodes.find?.(item => item.Id == fieldsValue.next_template_node_id);
  247. if (!serviceNode) {
  248. message.error('请选择需要流转的业务节点。');
  249. return;
  250. }
  251. const flowPath = result.map(item => getFlowPath(item));
  252. const formList = getFromData(result);
  253. let params = {
  254. desc: fieldsValue.desc,
  255. // 审核流程id
  256. // flow_id: approvalNode?.flow_id || 0,
  257. // node_level_id: approvalNode?.flow_id ? 1 : 0,
  258. id: version.id,
  259. project_id: version.project_id,
  260. cur_template_node_id: version.template_node_id * 1, // 当前节点
  261. next_template_node_id: serviceNode.Id * 1, // 审核完成后的业务节点
  262. // template_node_id: result[0][0], // 将要流转的节点审批节点
  263. // flow_path:flow_path, //审批节点数组
  264. // 模板id.一致就行
  265. template_id: version.template_id,
  266. cur_template_id: version.template_id,
  267. next_template_id: version.template_id,
  268. };
  269. if (result.length <= 0) {
  270. //直接走业务节点
  271. } else if (result.length <= 1 && result[0]?.length <= 1) {
  272. //单个审批节点
  273. let approvalNode = flowDetail.nodes.find?.(item => item.Id == result[0][0]);
  274. params.flow_id = approvalNode?.flow_id || 0;
  275. params.node_level_id = approvalNode?.flow_id ? 1 : 0;
  276. params.template_node_id = result[0][0]; // 将要流转的节点审批节点
  277. params.form_list = formList; //创建钉钉表单所需数据
  278. if (approvalNode?.Id) {
  279. if (!approvalNode?.flow_id) {
  280. hasFlowId = false;
  281. }
  282. }
  283. } else {
  284. //多节点审批
  285. params.template_node_id = result[0][0]; // 将要流转的节点审批节点
  286. params.flow_path = flowPath;
  287. params.form_list = formList; //创建钉钉表单所需数据
  288. }
  289. if (!hasFlowId) {
  290. message.error('当前存在审批节点未绑定审批流程!请联系管理员。');
  291. return;
  292. }
  293. console.log(JSON.stringify(params));
  294. console.log(params);
  295. onOk(params);
  296. };
  297. const onTabChange = key => {
  298. console.log('=====================', key);
  299. };
  300. const CascaderNode = index => {
  301. return (
  302. <Form.Item
  303. labelCol={{ span: 7 }}
  304. wrapperCol={{ span: 15 }}
  305. label={`审批节点${index + 1}`}
  306. name={`circle${index}`}
  307. key={`circle${index}`}
  308. >
  309. <Cascader style={{ width: '100%' }} options={data} onChange={onChange} />
  310. </Form.Item>
  311. );
  312. };
  313. return (
  314. <Modal
  315. confirmLoading={loading}
  316. destroyOnClose
  317. title="提交流转目标"
  318. visible={visible}
  319. onCancel={() => {
  320. setAuditId();
  321. onClose();
  322. }}
  323. onOk={onFinish}
  324. >
  325. <Form form={form}>
  326. {data.map((item, idx) => (data.length == 1 ? CascaderNode('') : CascaderNode(idx)))}
  327. <Form.Item
  328. labelCol={{ span: 7 }}
  329. wrapperCol={{ span: 15 }}
  330. label="业务节点"
  331. name="next_template_node_id"
  332. >
  333. <Select style={{ width: '100%' }}>
  334. {getNextNodes(data.length < 0 ? currentNodeId : auditId, 'custom-rect').map(item => (
  335. <Option key={item.value}>{item.label}</Option>
  336. ))}
  337. </Select>
  338. </Form.Item>
  339. <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="备注信息" name="desc">
  340. <Input.TextArea />
  341. </Form.Item>
  342. </Form>
  343. <Tabs defaultActiveKey="1" onChange={onTabChange}>
  344. {auditList.map((item, idx) => (
  345. // <TabPane tab={item.label} key={`${item.Id}_${item.label}`}>
  346. // <AuditDetailed />
  347. // </TabPane>
  348. <TabPane tab={item.name} key={`${idx}_${item.title}`}>
  349. {item.FormComponents}
  350. <AuditFlow
  351. processCode={item.formCode}
  352. formComponentValues={formComponentValues[item.nodeId]}
  353. />
  354. </TabPane>
  355. ))}
  356. </Tabs>
  357. </Modal>
  358. );
  359. }
  360. export default connect(({ xflow, detail }) => ({
  361. flowDetail: xflow.flowDetail,
  362. versionList: detail.versionList,
  363. }))(CommitAuditModal);