Showing
5 changed files
with
265 additions
and
143 deletions
| ... | @@ -455,7 +455,7 @@ import type { FormInstance, FormRules } from 'element-plus' | ... | @@ -455,7 +455,7 @@ import type { FormInstance, FormRules } from 'element-plus' |
| 455 | import qs from 'qs' | 455 | import qs from 'qs' |
| 456 | import { after } from 'lodash-es'; | 456 | import { after } from 'lodash-es'; |
| 457 | // import { VueSpinner } from 'vue3-spinners'; | 457 | // import { VueSpinner } from 'vue3-spinners'; |
| 458 | -import { flowVersionAPI, saveFlowAPI, flowNodesAPI, enableFlowVersionAPI, flowNodePropertyAPI, saveFlowNodePropertyAPI } from "./api"; | 458 | +import { flowVersionAPI, saveFlowAPI, flowNodesAPI, enableFlowVersionAPI, flowNodePropertyAPI, saveFlowNodePropertyAPI, saveAllFlowNodePropertyAPI } from "./api"; |
| 459 | 459 | ||
| 460 | const G6 = (window as any).G6.default as any | 460 | const G6 = (window as any).G6.default as any |
| 461 | 461 | ||
| ... | @@ -519,12 +519,14 @@ export default { | ... | @@ -519,12 +519,14 @@ export default { |
| 519 | desc: '拖拽新增流程', | 519 | desc: '拖拽新增流程', |
| 520 | color: '#ed8383', | 520 | color: '#ed8383', |
| 521 | img: 'https://cdn.ipadbiz.cn/oa/flow/icons-flow.png', | 521 | img: 'https://cdn.ipadbiz.cn/oa/flow/icons-flow.png', |
| 522 | + error: '', | ||
| 522 | }, | 523 | }, |
| 523 | cc: { | 524 | cc: { |
| 524 | text: '抄送节点', | 525 | text: '抄送节点', |
| 525 | desc: '拖拽新增抄送', | 526 | desc: '拖拽新增抄送', |
| 526 | color: '#ed8383', | 527 | color: '#ed8383', |
| 527 | img: 'https://cdn.ipadbiz.cn/oa/flow/icon-cc.png', | 528 | img: 'https://cdn.ipadbiz.cn/oa/flow/icon-cc.png', |
| 529 | + error: '', | ||
| 528 | }, | 530 | }, |
| 529 | }, | 531 | }, |
| 530 | controlConfig: { | 532 | controlConfig: { |
| ... | @@ -540,12 +542,14 @@ export default { | ... | @@ -540,12 +542,14 @@ export default { |
| 540 | desc: '流程节点', | 542 | desc: '流程节点', |
| 541 | color: '#ed8383', | 543 | color: '#ed8383', |
| 542 | img: 'https://cdn.ipadbiz.cn/oa/flow/icons-flow.png', | 544 | img: 'https://cdn.ipadbiz.cn/oa/flow/icons-flow.png', |
| 545 | + error: '', | ||
| 543 | }, | 546 | }, |
| 544 | cc: { | 547 | cc: { |
| 545 | text: '抄送节点', | 548 | text: '抄送节点', |
| 546 | desc: '抄送节点', | 549 | desc: '抄送节点', |
| 547 | color: '#ed8383', | 550 | color: '#ed8383', |
| 548 | img: 'https://cdn.ipadbiz.cn/oa/flow/icon-cc.png', | 551 | img: 'https://cdn.ipadbiz.cn/oa/flow/icon-cc.png', |
| 552 | + error: '', | ||
| 549 | }, | 553 | }, |
| 550 | end: { | 554 | end: { |
| 551 | id: 'end-node', | 555 | id: 'end-node', |
| ... | @@ -751,7 +755,7 @@ export default { | ... | @@ -751,7 +755,7 @@ export default { |
| 751 | } | 755 | } |
| 752 | } | 756 | } |
| 753 | }, | 757 | }, |
| 754 | - { immediate: true } | 758 | + // { immediate: true } |
| 755 | ); | 759 | ); |
| 756 | watch( | 760 | watch( |
| 757 | () => state.more_attr, | 761 | () => state.more_attr, |
| ... | @@ -779,6 +783,7 @@ export default { | ... | @@ -779,6 +783,7 @@ export default { |
| 779 | * @param note | 783 | * @param note |
| 780 | */ | 784 | */ |
| 781 | const onSelectFlowVersion = (id: number, code: number, note: string) => { | 785 | const onSelectFlowVersion = (id: number, code: number, note: string) => { |
| 786 | + state.node_tree = {}; // 清空当前版本的节点树状态缓存 | ||
| 782 | state.reloadLoading = true; // 打开loading | 787 | state.reloadLoading = true; // 打开loading |
| 783 | state.select_flow_version = code; | 788 | state.select_flow_version = code; |
| 784 | updateFlowId(id); // 更新缓存flow_id | 789 | updateFlowId(id); // 更新缓存flow_id |
| ... | @@ -1115,8 +1120,7 @@ export default { | ... | @@ -1115,8 +1120,7 @@ export default { |
| 1115 | /******************* END *******************/ | 1120 | /******************* END *******************/ |
| 1116 | 1121 | ||
| 1117 | const handleNodeNameChange = (val) => { | 1122 | const handleNodeNameChange = (val) => { |
| 1118 | - state.detailModel.text = val; // 更新节点名称显示 | 1123 | + // state.detailModel.text = val; // 更新节点名称显示 |
| 1119 | - editor.updateModel(state.detailModel); // 更新流程图信息 | ||
| 1120 | } | 1124 | } |
| 1121 | 1125 | ||
| 1122 | /***************** 用户选择控件弹框 ****************/ | 1126 | /***************** 用户选择控件弹框 ****************/ |
| ... | @@ -1126,6 +1130,7 @@ export default { | ... | @@ -1126,6 +1130,7 @@ export default { |
| 1126 | */ | 1130 | */ |
| 1127 | const openUserForm = () => { | 1131 | const openUserForm = () => { |
| 1128 | state.dialogUserFormVisible = true; | 1132 | state.dialogUserFormVisible = true; |
| 1133 | + state.dialogUserTags = state.node_tree[state.detailModel.id].user; | ||
| 1129 | } | 1134 | } |
| 1130 | 1135 | ||
| 1131 | const onCloseUserView = (status: boolean) => { | 1136 | const onCloseUserView = (status: boolean) => { |
| ... | @@ -1322,16 +1327,25 @@ export default { | ... | @@ -1322,16 +1327,25 @@ export default { |
| 1322 | 1327 | ||
| 1323 | editor.openModel(); | 1328 | editor.openModel(); |
| 1324 | 1329 | ||
| 1325 | - // 储存原始节点属性 | 1330 | + // // 储存原始节点属性 |
| 1326 | - state.node_attr = { | 1331 | + // state.node_attr = { |
| 1327 | - name: _.cloneDeep(state.node_name), | 1332 | + // name: _.cloneDeep(state.node_name), |
| 1328 | - user: _.cloneDeep(state.userTags), | 1333 | + // user: _.cloneDeep(state.userTags), |
| 1329 | - field: _.cloneDeep(state.field_extend), | 1334 | + // field: _.cloneDeep(state.field_extend), |
| 1330 | - property: _.cloneDeep(state.more_attr) | 1335 | + // property: _.cloneDeep(state.more_attr) |
| 1331 | - } | 1336 | + // } |
| 1332 | 1337 | ||
| 1333 | // 临时保存树信息 | 1338 | // 临时保存树信息 |
| 1334 | - setNodeTree(model.id, { name: _.cloneDeep(state.node_name), user: _.cloneDeep(state.userTags), field: _.cloneDeep(state.field_auths), property: _.cloneDeep(state.more_attr) }); | 1339 | + setNodeTree(model.id, |
| 1340 | + { | ||
| 1341 | + name: _.cloneDeep(state.node_name), | ||
| 1342 | + user: model_id === 'start-node' ? '' : _.cloneDeep(state.userTags), // 开始节点没有负责人 | ||
| 1343 | + field: _.cloneDeep(state.field_auths), | ||
| 1344 | + field_extend: _.cloneDeep(state.field_extend), | ||
| 1345 | + property: _.cloneDeep(state.more_attr), | ||
| 1346 | + model | ||
| 1347 | + } | ||
| 1348 | + ); | ||
| 1335 | 1349 | ||
| 1336 | } else { | 1350 | } else { |
| 1337 | state.statusLoading = false; | 1351 | state.statusLoading = false; |
| ... | @@ -1424,68 +1438,194 @@ export default { | ... | @@ -1424,68 +1438,194 @@ export default { |
| 1424 | state.main_attr_set = true; | 1438 | state.main_attr_set = true; |
| 1425 | } | 1439 | } |
| 1426 | 1440 | ||
| 1427 | - /** | 1441 | + const checkSaveNodeTree = () => { // 检查需要保存的节点树属性 |
| 1428 | - * 保存表单信息 | 1442 | + let models = []; |
| 1429 | - * | 1443 | + for (const key in state.node_tree) { |
| 1430 | - */ | 1444 | + const element = state.node_tree[key]; |
| 1431 | - async function saveForm() { | 1445 | + let avail_visible_count = element.field.filter((ele) => { |
| 1432 | - if (state.node_name === '') { | 1446 | + if (ele.visible.checked && !ele.visible.disabled) { |
| 1433 | - ElMessage({ | 1447 | + return ele; |
| 1434 | - type: 'error', | 1448 | + } |
| 1435 | - message: '节点名称不能为空', | ||
| 1436 | }); | 1449 | }); |
| 1437 | - return; | 1450 | + let avail_editable_count = element.field.filter((ele) => { |
| 1451 | + if (ele.editable.checked && !ele.editable.disabled) { | ||
| 1452 | + return ele; | ||
| 1453 | + } | ||
| 1454 | + }); | ||
| 1455 | + | ||
| 1456 | + if ( | ||
| 1457 | + (element.name === '') || | ||
| 1458 | + (key !=='start-node' && !element.user.length) || // 开始节点不需要检查负责人 | ||
| 1459 | + (avail_visible_count.length === 0 && avail_editable_count.length === 0) | ||
| 1460 | + ) { // 节点名称为空, 节点负责人不能为空, 请至少选择一个字段权限 | ||
| 1461 | + models.push(element.model); | ||
| 1462 | + } | ||
| 1438 | } | 1463 | } |
| 1439 | - if (state.detailModel.id !== 'start-node' && state.userTags.length === 0) { | 1464 | + |
| 1465 | + if (models.length) { | ||
| 1440 | ElMessage({ | 1466 | ElMessage({ |
| 1441 | type: 'error', | 1467 | type: 'error', |
| 1442 | - message: '节点负责人不能为空', | 1468 | + message: '流程配置不完善,请点击节点红点完善。', |
| 1443 | }); | 1469 | }); |
| 1444 | - return; | ||
| 1445 | } | 1470 | } |
| 1446 | - let avail_visible_count = state.field_auths.filter((ele) => { | 1471 | + |
| 1447 | - if (ele.visible.checked && !ele.visible.disabled) { | 1472 | + // 批量新增节点提示 |
| 1448 | - return ele; | 1473 | + models.forEach(ele => { |
| 1449 | - } | 1474 | + ele.desc = 'https://cdn.ipadbiz.cn/oa/flow/icons-error1.png'; |
| 1450 | - }); | 1475 | + editor.updateModel(ele); // 更新流程图信息 |
| 1451 | - let avail_editable_count = state.field_auths.filter((ele) => { | ||
| 1452 | - if (ele.editable.checked && !ele.editable.disabled) { | ||
| 1453 | - return ele; | ||
| 1454 | - } | ||
| 1455 | }); | 1476 | }); |
| 1456 | - if (avail_visible_count.length === 0 && avail_editable_count.length === 0) { | 1477 | + |
| 1457 | - ElMessage({ | 1478 | + return models; |
| 1458 | - type: 'error', | 1479 | + } |
| 1459 | - message: '请至少选择一个字段权限', | 1480 | + |
| 1481 | + const batchSaveForm = async () => { // 批量保存节点信息 | ||
| 1482 | + for (const key in state.node_tree) { | ||
| 1483 | + const element = state.node_tree[key]; | ||
| 1484 | + // 调整数据结构 | ||
| 1485 | + element.field_extend.forEach(ele => { | ||
| 1486 | + element.field.forEach(auth => { | ||
| 1487 | + if (ele.field_id === auth.field_id) { | ||
| 1488 | + ele.field_extend.visibled = auth.visible.checked; | ||
| 1489 | + ele.field_extend.editabled = auth.editable.checked; | ||
| 1490 | + ele.field_extend.readonly = auth.editable.disabled; | ||
| 1491 | + } | ||
| 1492 | + }) | ||
| 1460 | }); | 1493 | }); |
| 1461 | - return; | 1494 | + // 没有错误,修改节点名称 |
| 1495 | + element.field = element.field_extend; // 字段权限保存需要的数据结构 | ||
| 1496 | + element.model.text = element.name; // 修改节点名称 | ||
| 1497 | + element.model.desc = ''; // 清空节点错误提示 | ||
| 1498 | + editor.updateModel(element.model); // 更新流程图信息 | ||
| 1462 | } | 1499 | } |
| 1463 | - // 调整数据结构 | ||
| 1464 | - state.field_extend.forEach(ele => { | ||
| 1465 | - state.field_auths.forEach(auth => { | ||
| 1466 | - if (ele.field_id === auth.field_id) { | ||
| 1467 | - ele.field_extend.visibled = auth.visible.checked; | ||
| 1468 | - ele.field_extend.editabled = auth.editable.checked; | ||
| 1469 | - ele.field_extend.readonly = auth.editable.disabled; | ||
| 1470 | - } | ||
| 1471 | - }) | ||
| 1472 | - }); | ||
| 1473 | 1500 | ||
| 1474 | let flow_id = getFlowId(); // 流程id | 1501 | let flow_id = getFlowId(); // 流程id |
| 1475 | 1502 | ||
| 1476 | // TAG: 保存表单信息 | 1503 | // TAG: 保存表单信息 |
| 1477 | - const { code, data } = await saveFlowNodePropertyAPI({ flow_id: +flow_id, node_code: state.detailModel.id, data: JSON.stringify({ name: state.node_name, user: state.userTags, field: state.field_extend, property: state.more_attr }) }) | 1504 | + const { code, data } = await saveAllFlowNodePropertyAPI({ flow_id: +flow_id, data: JSON.stringify(state.node_tree) }) |
| 1478 | if (code) { | 1505 | if (code) { |
| 1479 | - ElMessage({ | 1506 | + state.node_tree = {}; // 清空节点树缓存 |
| 1480 | - type:'success', | ||
| 1481 | - message: '保存成功', | ||
| 1482 | - }); | ||
| 1483 | - state.detailModel.text = state.node_name; // 更新节点名称显示 | ||
| 1484 | - editor.updateModel(state.detailModel); // 更新流程图信息 | ||
| 1485 | editor.closeModel(); | 1507 | editor.closeModel(); |
| 1486 | } | 1508 | } |
| 1487 | } | 1509 | } |
| 1488 | 1510 | ||
| 1511 | + const saveFlowData = async () => { // 保存流程图结构信息 | ||
| 1512 | + let { nodes, edges } = editor.editorState.graph.save(); | ||
| 1513 | + | ||
| 1514 | + // 使用时需要把自定义节点的类型带过去 activity/control | ||
| 1515 | + nodes.forEach((node: { [x: string]: string; shape: string }) => { | ||
| 1516 | + if (node.shape === 'control') { | ||
| 1517 | + node['control'] = node['control'] | ||
| 1518 | + } | ||
| 1519 | + }); | ||
| 1520 | + | ||
| 1521 | + nodes = nodes.map( | ||
| 1522 | + ({ data, id, label, shape, x, y, text, desc, img, control }) => ({ | ||
| 1523 | + data, | ||
| 1524 | + id, | ||
| 1525 | + label, | ||
| 1526 | + shape, | ||
| 1527 | + x, | ||
| 1528 | + y, | ||
| 1529 | + text, | ||
| 1530 | + desc, | ||
| 1531 | + img, | ||
| 1532 | + control, | ||
| 1533 | + }), | ||
| 1534 | + ); | ||
| 1535 | + edges = edges.map(({ shape, source, sourceAnchor, target, targetAnchor }) => ({ | ||
| 1536 | + shape, | ||
| 1537 | + source, | ||
| 1538 | + sourceAnchor, | ||
| 1539 | + target, | ||
| 1540 | + targetAnchor, | ||
| 1541 | + })); | ||
| 1542 | + | ||
| 1543 | + // 检查路径有效性 | ||
| 1544 | + const paths = []; | ||
| 1545 | + findPathsToEndNode(edges, 'start-node', [], paths); | ||
| 1546 | + | ||
| 1547 | + let flow_id = getFlowId(); // 流程id | ||
| 1548 | + | ||
| 1549 | + if (paths.length) { | ||
| 1550 | + const { code, data } = await saveFlowAPI({ form_id: +form_id, flow_id: +flow_id, data: JSON.stringify({ nodes, edges }) }); | ||
| 1551 | + if (code) { | ||
| 1552 | + ElMessage({ | ||
| 1553 | + type: 'success', | ||
| 1554 | + message: '保存流程图成功', | ||
| 1555 | + }); | ||
| 1556 | + updateFlowId(data); // 更新缓存flow_id | ||
| 1557 | + console.log(paths); // 输出满足条件的路径结果数组 | ||
| 1558 | + } | ||
| 1559 | + } else { | ||
| 1560 | + ElNotification.error('缺少一条从开始节点到结束节点的完整流程!'); | ||
| 1561 | + } | ||
| 1562 | + } | ||
| 1563 | + | ||
| 1564 | + /** | ||
| 1565 | + * 保存表单信息 | ||
| 1566 | + * | ||
| 1567 | + */ | ||
| 1568 | + // async function saveForm() { | ||
| 1569 | + // if (state.node_name === '') { | ||
| 1570 | + // ElMessage({ | ||
| 1571 | + // type: 'error', | ||
| 1572 | + // message: '节点名称不能为空', | ||
| 1573 | + // }); | ||
| 1574 | + // return; | ||
| 1575 | + // } | ||
| 1576 | + // if (state.detailModel.id !== 'start-node' && state.userTags.length === 0) { | ||
| 1577 | + // ElMessage({ | ||
| 1578 | + // type: 'error', | ||
| 1579 | + // message: '节点负责人不能为空', | ||
| 1580 | + // }); | ||
| 1581 | + // return; | ||
| 1582 | + // } | ||
| 1583 | + // let avail_visible_count = state.field_auths.filter((ele) => { | ||
| 1584 | + // if (ele.visible.checked && !ele.visible.disabled) { | ||
| 1585 | + // return ele; | ||
| 1586 | + // } | ||
| 1587 | + // }); | ||
| 1588 | + // let avail_editable_count = state.field_auths.filter((ele) => { | ||
| 1589 | + // if (ele.editable.checked && !ele.editable.disabled) { | ||
| 1590 | + // return ele; | ||
| 1591 | + // } | ||
| 1592 | + // }); | ||
| 1593 | + // if (avail_visible_count.length === 0 && avail_editable_count.length === 0) { | ||
| 1594 | + // ElMessage({ | ||
| 1595 | + // type: 'error', | ||
| 1596 | + // message: '请至少选择一个字段权限', | ||
| 1597 | + // }); | ||
| 1598 | + // return; | ||
| 1599 | + // } | ||
| 1600 | + // // 调整数据结构 | ||
| 1601 | + // state.field_extend.forEach(ele => { | ||
| 1602 | + // state.field_auths.forEach(auth => { | ||
| 1603 | + // if (ele.field_id === auth.field_id) { | ||
| 1604 | + // ele.field_extend.visibled = auth.visible.checked; | ||
| 1605 | + // ele.field_extend.editabled = auth.editable.checked; | ||
| 1606 | + // ele.field_extend.readonly = auth.editable.disabled; | ||
| 1607 | + // } | ||
| 1608 | + // }) | ||
| 1609 | + // }); | ||
| 1610 | + | ||
| 1611 | + // let flow_id = getFlowId(); // 流程id | ||
| 1612 | + | ||
| 1613 | + // // TODO: 需要一个可以保存多个表单的接口,field字段的结构要重新遍历state.field_extend | ||
| 1614 | + // // TODO:只要失焦的话就需要判断表单是否为空,为空需要用户继续填写不能走。 | ||
| 1615 | + // console.warn(state.node_tree); | ||
| 1616 | + // // TAG: 保存表单信息 | ||
| 1617 | + // const { code, data } = await saveFlowNodePropertyAPI({ flow_id: +flow_id, node_code: state.detailModel.id, data: JSON.stringify({ name: state.node_name, user: state.userTags, field: state.field_extend, property: state.more_attr }) }) | ||
| 1618 | + // if (code) { | ||
| 1619 | + // ElMessage({ | ||
| 1620 | + // type:'success', | ||
| 1621 | + // message: '保存成功', | ||
| 1622 | + // }); | ||
| 1623 | + // state.detailModel.text = state.node_name; // 更新节点名称显示 | ||
| 1624 | + // editor.updateModel(state.detailModel); // 更新流程图信息 | ||
| 1625 | + // editor.closeModel(); | ||
| 1626 | + // } | ||
| 1627 | + // } | ||
| 1628 | + | ||
| 1489 | /** | 1629 | /** |
| 1490 | * 删除前校验 | 1630 | * 删除前校验 |
| 1491 | * | 1631 | * |
| ... | @@ -1660,19 +1800,19 @@ export default { | ... | @@ -1660,19 +1800,19 @@ export default { |
| 1660 | editor.closeModel() | 1800 | editor.closeModel() |
| 1661 | } | 1801 | } |
| 1662 | 1802 | ||
| 1663 | - const checkFormEdited = () => { // 检查表单是否修改过内容 | 1803 | + // const checkFormEdited = () => { // 检查表单是否修改过内容 |
| 1664 | - state.field_extend.forEach(ele => { | 1804 | + // state.field_extend.forEach(ele => { |
| 1665 | - state.field_auths.forEach(auth => { | 1805 | + // state.field_auths.forEach(auth => { |
| 1666 | - if (ele.field_id === auth.field_id) { | 1806 | + // if (ele.field_id === auth.field_id) { |
| 1667 | - ele.field_extend.visibled = auth.visible.checked; | 1807 | + // ele.field_extend.visibled = auth.visible.checked; |
| 1668 | - ele.field_extend.editabled = auth.editable.checked; | 1808 | + // ele.field_extend.editabled = auth.editable.checked; |
| 1669 | - ele.field_extend.readonly = auth.editable.disabled; | 1809 | + // ele.field_extend.readonly = auth.editable.disabled; |
| 1670 | - } | 1810 | + // } |
| 1671 | - }) | 1811 | + // }) |
| 1672 | - }); | 1812 | + // }); |
| 1673 | 1813 | ||
| 1674 | - return _.isEqual(state.node_attr, {name: state.node_name, user: state.userTags, field: state.field_extend, property: state.more_attr}) | 1814 | + // return _.isEqual(state.node_attr, {name: state.node_name, user: state.userTags, field: state.field_extend, property: state.more_attr}) |
| 1675 | - } | 1815 | + // } |
| 1676 | 1816 | ||
| 1677 | /** | 1817 | /** |
| 1678 | * 拖动节点结束回调 | 1818 | * 拖动节点结束回调 |
| ... | @@ -1703,11 +1843,14 @@ export default { | ... | @@ -1703,11 +1843,14 @@ export default { |
| 1703 | * | 1843 | * |
| 1704 | * @return {void} No return value. | 1844 | * @return {void} No return value. |
| 1705 | */ | 1845 | */ |
| 1706 | - function saveData(): void { | 1846 | + const saveData = async () => { |
| 1707 | - // 如果表单打开状态,走表单保存逻辑 | 1847 | + if (checkSaveNodeTree().length) { |
| 1708 | - if (state.detailModel) { | 1848 | + return; |
| 1849 | + } | ||
| 1850 | + | ||
| 1851 | + if (_.isEmpty(state.node_tree)) { | ||
| 1709 | ElMessageBox.confirm( | 1852 | ElMessageBox.confirm( |
| 1710 | - '是否确定保存流程信息?', | 1853 | + '是否确定保存流程?', |
| 1711 | '温馨提示', | 1854 | '温馨提示', |
| 1712 | { | 1855 | { |
| 1713 | confirmButtonText: '确认', | 1856 | confirmButtonText: '确认', |
| ... | @@ -1716,76 +1859,27 @@ export default { | ... | @@ -1716,76 +1859,27 @@ export default { |
| 1716 | } | 1859 | } |
| 1717 | ) | 1860 | ) |
| 1718 | .then(async () => { | 1861 | .then(async () => { |
| 1719 | - saveForm(); | 1862 | + saveFlowData(); |
| 1720 | }) | 1863 | }) |
| 1721 | .catch(() => { | 1864 | .catch(() => { |
| 1722 | }); | 1865 | }); |
| 1723 | - return; | 1866 | + } else { |
| 1724 | - } | 1867 | + ElMessageBox.confirm( |
| 1725 | - | 1868 | + '是否确定保存流程?', |
| 1726 | - let { nodes, edges } = editor.editorState.graph.save(); | 1869 | + '温馨提示', |
| 1727 | - | 1870 | + { |
| 1728 | - // 使用时需要把自定义节点的类型带过去 activity/control | 1871 | + confirmButtonText: '确认', |
| 1729 | - nodes.forEach((node: { [x: string]: string; shape: string }) => { | 1872 | + cancelButtonText: '取消', |
| 1730 | - if (node.shape === 'control') { | 1873 | + type: 'warning', |
| 1731 | - node['control'] = node['control'] | ||
| 1732 | - } | ||
| 1733 | - }); | ||
| 1734 | - | ||
| 1735 | - nodes = nodes.map( | ||
| 1736 | - ({ data, id, label, shape, x, y, text, desc, img, control }) => ({ | ||
| 1737 | - data, | ||
| 1738 | - id, | ||
| 1739 | - label, | ||
| 1740 | - shape, | ||
| 1741 | - x, | ||
| 1742 | - y, | ||
| 1743 | - text, | ||
| 1744 | - desc, | ||
| 1745 | - img, | ||
| 1746 | - control, | ||
| 1747 | - }), | ||
| 1748 | - ); | ||
| 1749 | - edges = edges.map(({ shape, source, sourceAnchor, target, targetAnchor }) => ({ | ||
| 1750 | - shape, | ||
| 1751 | - source, | ||
| 1752 | - sourceAnchor, | ||
| 1753 | - target, | ||
| 1754 | - targetAnchor, | ||
| 1755 | - })); | ||
| 1756 | - | ||
| 1757 | - ElMessageBox.confirm( | ||
| 1758 | - '是否确定保存流程图?', | ||
| 1759 | - '温馨提示', | ||
| 1760 | - { | ||
| 1761 | - confirmButtonText: '确认', | ||
| 1762 | - cancelButtonText: '取消', | ||
| 1763 | - type: 'warning', | ||
| 1764 | - } | ||
| 1765 | - ) | ||
| 1766 | - .then(async () => { | ||
| 1767 | - // 检查路径有效性 | ||
| 1768 | - const paths = []; | ||
| 1769 | - findPathsToEndNode(edges, 'start-node', [], paths); | ||
| 1770 | - | ||
| 1771 | - let flow_id = getFlowId(); // 流程id | ||
| 1772 | - | ||
| 1773 | - if (paths.length) { | ||
| 1774 | - const { code, data } = await saveFlowAPI({ form_id: +form_id, flow_id: +flow_id, data: JSON.stringify({ nodes, edges }) }); | ||
| 1775 | - if (code) { | ||
| 1776 | - ElMessage({ | ||
| 1777 | - type: 'success', | ||
| 1778 | - message: '保存流程图成功', | ||
| 1779 | - }); | ||
| 1780 | - updateFlowId(data); // 更新缓存flow_id | ||
| 1781 | - console.log(paths); // 输出满足条件的路径结果数组 | ||
| 1782 | - } | ||
| 1783 | - } else { | ||
| 1784 | - ElNotification.error('缺少一条从开始节点到结束节点的完整流程!'); | ||
| 1785 | } | 1874 | } |
| 1786 | - }) | 1875 | + ) |
| 1787 | - .catch(() => { | 1876 | + .then(async () => { |
| 1788 | - }); | 1877 | + batchSaveForm(); |
| 1878 | + saveFlowData(); | ||
| 1879 | + }) | ||
| 1880 | + .catch(() => { | ||
| 1881 | + }); | ||
| 1882 | + } | ||
| 1789 | } | 1883 | } |
| 1790 | 1884 | ||
| 1791 | const startFlow = () => { // 启用流程图 | 1885 | const startFlow = () => { // 启用流程图 |
| ... | @@ -1856,7 +1950,7 @@ export default { | ... | @@ -1856,7 +1950,7 @@ export default { |
| 1856 | cancel, | 1950 | cancel, |
| 1857 | setMoreAttr, | 1951 | setMoreAttr, |
| 1858 | onConfirmMoreAttr, | 1952 | onConfirmMoreAttr, |
| 1859 | - saveForm, | 1953 | + // saveForm, |
| 1860 | handleBeforeDelete, | 1954 | handleBeforeDelete, |
| 1861 | handleAfterDelete, | 1955 | handleAfterDelete, |
| 1862 | handleBeforeAdd, | 1956 | handleBeforeAdd, | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-11-30 10:34:01 | 2 | * @Date: 2023-11-30 10:34:01 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2023-12-02 15:08:01 | 4 | + * @LastEditTime: 2023-12-06 11:36:04 |
| 5 | * @FilePath: /vue-flow-editor/doc/api/index.js | 5 | * @FilePath: /vue-flow-editor/doc/api/index.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -14,6 +14,7 @@ const Api = { | ... | @@ -14,6 +14,7 @@ const Api = { |
| 14 | ENABLE_FLOW_VERSION: '/admin/?a=enable_flow_version', | 14 | ENABLE_FLOW_VERSION: '/admin/?a=enable_flow_version', |
| 15 | FLOW_NODE_PROPERTY: '/admin/?a=flow_node_property', | 15 | FLOW_NODE_PROPERTY: '/admin/?a=flow_node_property', |
| 16 | SAVE_FLOW_NODE_PROPERTY: '/admin/?a=save_node_property', | 16 | SAVE_FLOW_NODE_PROPERTY: '/admin/?a=save_node_property', |
| 17 | + SAVE_ALL_FLOW_NODE_PROPERTY: '/admin/?a=save_all_node_property', | ||
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | /** | 20 | /** |
| ... | @@ -64,3 +65,11 @@ export const flowNodePropertyAPI = (params) => fn(fetch.get(Api.FLOW_NODE_PROPER | ... | @@ -64,3 +65,11 @@ export const flowNodePropertyAPI = (params) => fn(fetch.get(Api.FLOW_NODE_PROPER |
| 64 | * @returns | 65 | * @returns |
| 65 | */ | 66 | */ |
| 66 | export const saveFlowNodePropertyAPI = (params) => fn(fetch.stringifyPost(Api.SAVE_FLOW_NODE_PROPERTY, params)); | 67 | export const saveFlowNodePropertyAPI = (params) => fn(fetch.stringifyPost(Api.SAVE_FLOW_NODE_PROPERTY, params)); |
| 68 | + | ||
| 69 | +/** | ||
| 70 | + * @description: 保存所有节点属性 | ||
| 71 | + * @param {*} flow_id 流程 ID | ||
| 72 | + * @param {*} data 节点属性的数据,json格式字符串 | ||
| 73 | + * @returns | ||
| 74 | + */ | ||
| 75 | +export const saveAllFlowNodePropertyAPI = (params) => fn(fetch.stringifyPost(Api.SAVE_ALL_FLOW_NODE_PROPERTY, params)); | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2023-11-01 10:18:53 | 2 | * @Date: 2023-11-01 10:18:53 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2023-11-24 16:23:41 | 4 | + * @LastEditTime: 2023-12-06 12:52:57 |
| 5 | * @FilePath: /vue-flow-editor/doc/selectUserView.vue | 5 | * @FilePath: /vue-flow-editor/doc/selectUserView.vue |
| 6 | * @Description: 成员列表选择控件 | 6 | * @Description: 成员列表选择控件 |
| 7 | --> | 7 | --> |
| ... | @@ -411,6 +411,18 @@ watch( | ... | @@ -411,6 +411,18 @@ watch( |
| 411 | nextTick(() => { | 411 | nextTick(() => { |
| 412 | tabTextWidth.value = $("#" + activeTabId.value).width() + "px"; | 412 | tabTextWidth.value = $("#" + activeTabId.value).width() + "px"; |
| 413 | }); | 413 | }); |
| 414 | + userTags.value = _.cloneDeep(props.list); | ||
| 415 | + // 第一项目是组织结构树,默认展开第一个节点 | ||
| 416 | + if (userTabs.value[activeTabIdx.value]['type'] === 'corp-tree') { | ||
| 417 | + if (userTabs.value[activeTabIdx.value]['data'].length) { | ||
| 418 | + // 默认展开第一个节点 | ||
| 419 | + defaultExpandedKeys.value = [userTabs.value[activeTabIdx.value]['data'][0]['id']]; | ||
| 420 | + // 把用户选中的节点注入树结构显示选中状态 | ||
| 421 | + nextTick(() => { | ||
| 422 | + currentCheckedNodeKey.value = userTags.value.map(ele => ele.id); | ||
| 423 | + }); | ||
| 424 | + } | ||
| 425 | + } | ||
| 414 | } | 426 | } |
| 415 | } | 427 | } |
| 416 | ); | 428 | ); | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-10-27 09:29:59 | 2 | * @Date: 2023-10-27 09:29:59 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2023-11-14 15:31:33 | 4 | + * @LastEditTime: 2023-12-06 09:51:19 |
| 5 | * @FilePath: /vue-flow-editor/src/shape/control.ts | 5 | * @FilePath: /vue-flow-editor/src/shape/control.ts |
| 6 | * @Description: 自定义控制节点 | 6 | * @Description: 自定义控制节点 |
| 7 | */ | 7 | */ |
| ... | @@ -53,7 +53,8 @@ export function registerControl(G6) { | ... | @@ -53,7 +53,8 @@ export function registerControl(G6) { |
| 53 | }, | 53 | }, |
| 54 | drawShape(cfg, group) { // 继承了基类,可以使用drawShape,如果没有继承,必须要有draw | 54 | drawShape(cfg, group) { // 继承了基类,可以使用drawShape,如果没有继承,必须要有draw |
| 55 | 55 | ||
| 56 | - let {text, desc, img, color} = cfg | 56 | + let {text, desc, img, error, color} = cfg |
| 57 | + | ||
| 57 | color = color || BASE_COLOR | 58 | color = color || BASE_COLOR |
| 58 | desc = desc || '无描述' | 59 | desc = desc || '无描述' |
| 59 | 60 | ||
| ... | @@ -77,6 +78,10 @@ export function registerControl(G6) { | ... | @@ -77,6 +78,10 @@ export function registerControl(G6) { |
| 77 | type: 'image', | 78 | type: 'image', |
| 78 | attrs: {x: height / 4 - width / 2, y: height / 4 - height / 2, width: height / 2, height: height / 2, img}, | 79 | attrs: {x: height / 4 - width / 2, y: height / 4 - height / 2, width: height / 2, height: height / 2, img}, |
| 79 | }, | 80 | }, |
| 81 | + error: { | ||
| 82 | + type: 'image', | ||
| 83 | + attrs: {x: height / 4 + width / 4 + 5, y: height / 4 - height / 2, width: height / 2.1, height: height / 2.1, img: error}, | ||
| 84 | + }, | ||
| 80 | label: { | 85 | label: { |
| 81 | type: 'text', | 86 | type: 'text', |
| 82 | attrs: {text, x: height - width / 2, y: height * (4 / 8) - height / 2, fontSize: 14, textAlign: 'left', textBaseline: 'middle', fill: 'black'}, | 87 | attrs: {text, x: height - width / 2, y: height * (4 / 8) - height / 2, fontSize: 14, textAlign: 'left', textBaseline: 'middle', fill: 'black'}, |
| ... | @@ -111,6 +116,7 @@ export function registerControl(G6) { | ... | @@ -111,6 +116,7 @@ export function registerControl(G6) { |
| 111 | group = group.getContainer() | 116 | group = group.getContainer() |
| 112 | // group.shapes.sideRect.attr({fill: cfg.color}) | 117 | // group.shapes.sideRect.attr({fill: cfg.color}) |
| 113 | group.shapes.img.attr({img: cfg.img}) | 118 | group.shapes.img.attr({img: cfg.img}) |
| 119 | + group.shapes.error.attr({img: cfg.desc}) | ||
| 114 | group.shapes.label.attr({text: cfg.text}) | 120 | group.shapes.label.attr({text: cfg.text}) |
| 115 | // group.shapes.desc.attr({text: cfg.desc}) | 121 | // group.shapes.desc.attr({text: cfg.desc}) |
| 116 | }, | 122 | }, | ... | ... |
| ... | @@ -157,6 +157,7 @@ export function formatNodeModel_control(model: any, controlConfig: object) { | ... | @@ -157,6 +157,7 @@ export function formatNodeModel_control(model: any, controlConfig: object) { |
| 157 | // 把 control 的配置挂到model上 | 157 | // 把 control 的配置挂到model上 |
| 158 | model.shape = 'control' | 158 | model.shape = 'control' |
| 159 | model.img = controlConfig[control].img | 159 | model.img = controlConfig[control].img |
| 160 | + model.error = controlConfig[control].error | ||
| 160 | model.color = controlConfig[control].color | 161 | model.color = controlConfig[control].color |
| 161 | } | 162 | } |
| 162 | 163 | ... | ... |
-
Please register or login to post a comment