CommitAuditModal.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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 { queryDingSchema } from '@/services/boom';
  10. const { TextArea } = Input;
  11. const { Option } = Select;
  12. const { TabPane } = Tabs;
  13. // 提交
  14. function CommitAuditModal(props) {
  15. const { visible, onClose, onOk, loading, version, versionList, flowDetail } = props;
  16. const [auditId, setAuditId] = useState();
  17. const [data, setData] = useState([]);
  18. const [length, setLength] = useState(1);
  19. const [formData, setFromData] = useState({});
  20. const [auditList, setAuditList] = useState([]); //用于创建Tabs表单
  21. const [form] = Form.useForm();
  22. const res = {
  23. result: {
  24. creatorUserId: '1649060463062661',
  25. gmtModified: '2022-08-10T15:24Z',
  26. formUuid: 'FORM-50442153-A9E8-4247-903C-AAF68B4C6219',
  27. bizType: '',
  28. ownerIdType: 'orgId',
  29. formCode: 'PROC-F2AD61A8-25CF-47AB-96EA-E0D0850BBE35',
  30. memo: '',
  31. engineType: 0,
  32. ownerId: '8642326',
  33. gmtCreate: '2022-08-09T11:53Z',
  34. schemaContent: {
  35. icon: 'promotion',
  36. title: '测试2',
  37. items: [
  38. {
  39. children: [
  40. {
  41. componentName: 'NumberField',
  42. props: {
  43. id: 'NumberField_S1TT9HEIZGG0',
  44. label: '数字输入框',
  45. required: false,
  46. },
  47. },
  48. {
  49. componentName: 'DDSelectField',
  50. props: {
  51. id: 'DDSelectField_1UAHP7C7C3NK0',
  52. label: '单选框',
  53. required: false,
  54. },
  55. },
  56. {
  57. props: {
  58. id: 'PhoneField_SEIS8H2KAQO0',
  59. label: '电话',
  60. required: false,
  61. },
  62. },
  63. ],
  64. componentName: 'TableField',
  65. props: {
  66. staffStatusEnabled: false,
  67. holidayOptions: [],
  68. id: 'TableField_1NFDDN09KZQ80',
  69. label: '表格',
  70. push: {},
  71. actionName: '添加',
  72. },
  73. },
  74. {
  75. componentName: 'DepartmentField',
  76. props: {
  77. staffStatusEnabled: false,
  78. holidayOptions: [],
  79. id: 'DepartmentField_23VD81FG2G5C0',
  80. label: '部门',
  81. placeholder: '请选择',
  82. required: false,
  83. push: {},
  84. },
  85. },
  86. {
  87. componentName: 'DDAttachment',
  88. props: {
  89. staffStatusEnabled: false,
  90. holidayOptions: [],
  91. id: 'DDAttachment_YP8901BICJ4',
  92. label: '附件',
  93. required: false,
  94. push: {},
  95. },
  96. },
  97. {
  98. componentName: 'TextareaField',
  99. props: {
  100. staffStatusEnabled: false,
  101. holidayOptions: [],
  102. id: '请假事由',
  103. label: '请假事由',
  104. placeholder: '请输入请假事由',
  105. required: false,
  106. push: {},
  107. },
  108. },
  109. {
  110. componentName: 'DDPhotoField',
  111. props: {
  112. staffStatusEnabled: false,
  113. holidayOptions: [],
  114. id: '图片',
  115. label: '上传病假单(如病假)',
  116. push: {},
  117. },
  118. },
  119. ],
  120. },
  121. appUuid: 'ding0cdce2d5dbf986d9',
  122. appType: 0,
  123. visibleRange: 'PRIVATE',
  124. listOrder: 1084,
  125. name: '测试2',
  126. status: 'PUBLISHED',
  127. procType: '',
  128. },
  129. };
  130. const [schemaContent, setSchemaContent] = useState(res.result.schemaContent);
  131. useEffect(() => {
  132. const { edges, nodes } = flowDetail;
  133. let Id = version.template_node_id;
  134. const currentId = flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
  135. const data = treeData(currentId);
  136. if (data.length <= 0) setAuditId(currentId);
  137. console.log('================data', data, currentId, version);
  138. setData(data);
  139. }, [auditId, version]);
  140. useEffect(() => {
  141. form.resetFields();
  142. setAuditList([]);
  143. }, [visible]);
  144. const treeData = currentId => {
  145. const list = getNextNodes(currentId, 'custom-circle');
  146. const fun = nodes => {
  147. const re = nodes?.forEach((item, idx) => {
  148. const data = getNextNodes(item.Id, 'custom-circle');
  149. if (data || data.length > 0) list.push(...data);
  150. fun(data);
  151. });
  152. };
  153. fun(list);
  154. const fun2 = list => {
  155. const parents = list.filter(item => list.findIndex(node => node.Id == item.parentId) == -1);
  156. let translator = (parents, children) => {
  157. setLength(length + 1);
  158. parents.forEach(parent => {
  159. children.forEach((current, index) => {
  160. if (current.parentId === parent.Id) {
  161. let temp = JSON.parse(JSON.stringify(children));
  162. temp.splice(index, 1);
  163. translator([current], temp);
  164. if (!parent.children.find(item => item.Id == current.Id))
  165. parent.children.push(current);
  166. }
  167. });
  168. });
  169. };
  170. translator(parents, list);
  171. return parents;
  172. };
  173. return fun2(list);
  174. };
  175. const currentNodeId = useMemo(() => {
  176. let Id = version.template_node_id;
  177. setAuditId(currentNodeId);
  178. return flowDetail.nodes.find?.(item => item.Id == Id)?.node_id;
  179. }, [flowDetail, version]);
  180. /**
  181. *
  182. * @param {*} currentId 当前节点
  183. * @param {*} type 下一个节点的类型 custom-circle: 审批节点 custom-rect: 业务节点
  184. * @returns
  185. */
  186. const getNextNodes = (currentId, type) => {
  187. const { edges, nodes } = flowDetail;
  188. if (!currentId) return [];
  189. //删除虚线通向的节点
  190. // let targetIds = edges
  191. // .filter(edge => {
  192. // let line = edge.attrs?.line?.strokeDasharray?.split(' ');
  193. // return edge.source.cell == currentId && line && line[0] == '0';
  194. // })
  195. // .map(item => item.target.cell);
  196. let targetIds = edges
  197. .filter(edge => edge.source.cell == currentId)
  198. .map(item => item.target.cell);
  199. edges.filter(edge => edge.source.cell == currentId);
  200. let auditNodes = nodes.filter(node => {
  201. if (type && node.name != type) {
  202. return false;
  203. }
  204. return targetIds.indexOf(node.id) != -1;
  205. });
  206. const result = auditNodes.map(item => {
  207. return {
  208. label: item.label,
  209. value: item.Id,
  210. Id: item.node_id,
  211. parentId: currentId,
  212. children: [],
  213. };
  214. });
  215. return result || [];
  216. };
  217. const changeAudit = id => {
  218. let node = flowDetail.nodes.find?.(item => item.Id == id);
  219. setAuditId(node.node_id);
  220. };
  221. const onChange = value => {
  222. changeAudit(value[value.length - 1]);
  223. setAuditListFun();
  224. };
  225. //处理tabs页
  226. const setAuditListFun = async () => {
  227. var fieldsValue = await form.validateFields();
  228. let addAuditList = [];
  229. let result = Object.values(fieldsValue)
  230. .map(item => {
  231. if (item && Array.isArray(item)) return item;
  232. })
  233. .filter(item => item)
  234. .flat(Infinity);
  235. let codeList = [...new Set(result)]
  236. .map(Id => {
  237. return flowDetail.nodes.find?.(item => item.Id == Id).process_code;
  238. })
  239. .filter(item => item); // && !auditList.find(node => node.formCode == item)
  240. console.log('=========================auditfvsfs', codeList, auditList);
  241. codeList.map(async process_code => {
  242. let res = await queryDingSchema({ process_code });
  243. if (res) {
  244. addAuditList.push(res.data.result);
  245. }
  246. });
  247. setAuditList(addAuditList);
  248. };
  249. useEffect(() => {
  250. console.log(auditList);
  251. }, [auditList]);
  252. const onFinish = async () => {
  253. var fieldsValue = await form.validateFields();
  254. let hasFlowId = true; //是否都绑定审批节点
  255. const getFlowPath = node => {
  256. //[134, 135]
  257. let itemData = {};
  258. const Function = (curId, index) => {
  259. if (!curId) return;
  260. let data = {};
  261. let approvalNode = flowDetail.nodes.find?.(item => item.Id == curId);
  262. data.template_id = version.template_id;
  263. data.flow_id = approvalNode?.flow_id || 0;
  264. data.node_level_id = approvalNode?.flow_id ? 1 : 0;
  265. data.template_node_id = approvalNode?.Id;
  266. index++;
  267. if (approvalNode?.Id) {
  268. if (!approvalNode?.flow_id) {
  269. hasFlowId = false;
  270. }
  271. }
  272. const res = Function(node[index], index);
  273. if (res) {
  274. data.flow_path = [res];
  275. }
  276. return data;
  277. };
  278. itemData = Function(node[0], 0);
  279. return itemData;
  280. };
  281. let result = Object.values(fieldsValue)
  282. .map(item => {
  283. if (item && Array.isArray(item)) return item;
  284. })
  285. .filter(item => item);
  286. let serviceNode = flowDetail.nodes.find?.(item => item.Id == fieldsValue.next_template_node_id);
  287. if (!serviceNode) {
  288. message.error('请选择需要流转的业务节点。');
  289. return;
  290. }
  291. let params = {
  292. desc: fieldsValue.desc,
  293. // 审核流程id
  294. // flow_id: approvalNode?.flow_id || 0,
  295. // node_level_id: approvalNode?.flow_id ? 1 : 0,
  296. id: version.id,
  297. project_id: version.project_id,
  298. cur_template_node_id: version.template_node_id * 1, // 当前节点
  299. next_template_node_id: serviceNode.Id * 1, // 审核完成后的业务节点
  300. // template_node_id: result[0][0], // 将要流转的节点审批节点
  301. // flow_path:flow_path, //审批节点数组
  302. // 模板id.一致就行
  303. template_id: version.template_id,
  304. cur_template_id: version.template_id,
  305. next_template_id: version.template_id,
  306. };
  307. if (result.length <= 0) {
  308. //直接走业务节点
  309. } else if (result.length <= 1 && result[0]?.length <= 1) {
  310. //单个审批节点
  311. let approvalNode = flowDetail.nodes.find?.(item => item.Id == result[0][0]);
  312. params.flow_id = approvalNode?.flow_id || 0;
  313. params.node_level_id = approvalNode?.flow_id ? 1 : 0;
  314. params.template_node_id = result[0][0]; // 将要流转的节点审批节点
  315. if (approvalNode?.Id) {
  316. if (!approvalNode?.flow_id) {
  317. hasFlowId = false;
  318. }
  319. }
  320. } else {
  321. //多节点审批
  322. params.template_node_id = result[0][0]; // 将要流转的节点审批节点
  323. params.flow_path = result.map(item => getFlowPath(item));
  324. }
  325. // if (!hasFlowId) {
  326. // message.error('当前存在审批节点未绑定审批流程!请联系管理员。');
  327. // return;
  328. // }
  329. onOk(params);
  330. };
  331. const onTabChange = key => {
  332. console.log('=====================', key);
  333. };
  334. const CascaderNode = index => {
  335. return (
  336. <Form.Item
  337. labelCol={{ span: 7 }}
  338. wrapperCol={{ span: 15 }}
  339. label={`审批节点${index + 1}`}
  340. name={`circle${index}`}
  341. key={`circle${index}`}
  342. >
  343. <Cascader style={{ width: '100%' }} options={data} onChange={onChange} />
  344. </Form.Item>
  345. );
  346. };
  347. return (
  348. <Modal
  349. confirmLoading={loading}
  350. destroyOnClose
  351. title="提交流转目标"
  352. visible={visible}
  353. onCancel={() => {
  354. setAuditId();
  355. onClose();
  356. }}
  357. onOk={onFinish}
  358. >
  359. <Form form={form}>
  360. {data.map((item, idx) => (data.length == 1 ? CascaderNode('') : CascaderNode(idx)))}
  361. <Form.Item
  362. labelCol={{ span: 7 }}
  363. wrapperCol={{ span: 15 }}
  364. label="业务节点"
  365. name="next_template_node_id"
  366. >
  367. <Select style={{ width: '100%' }}>
  368. {getNextNodes(data.length < 0 ? currentNodeId : auditId, 'custom-rect').map(item => (
  369. <Option key={item.value}>{item.label}</Option>
  370. ))}
  371. </Select>
  372. </Form.Item>
  373. <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label="备注信息" name="desc">
  374. <Input.TextArea />
  375. </Form.Item>
  376. </Form>
  377. <Tabs defaultActiveKey="1" onChange={onTabChange}>
  378. {auditList.map((item, idx) => (
  379. <TabPane tab={item.name} key={`${idx}_${item.name}`}>
  380. <AuditDetailed items={item.schemaContent.items} />
  381. </TabPane>
  382. ))}
  383. </Tabs>
  384. </Modal>
  385. );
  386. }
  387. export default connect(({ xflow, detail }) => ({
  388. flowDetail: xflow.flowDetail,
  389. versionList: detail.versionList,
  390. }))(CommitAuditModal);