SimpleProcessModel.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <template>
  2. <div class="simple-process-model-container position-relative">
  3. <div class="position-absolute top-0px right-0px bg-#fff">
  4. <el-row type="flex" justify="end">
  5. <el-button-group key="scale-control" size="default">
  6. <el-button size="default" :icon="ScaleToOriginal" @click="processReZoom()" />
  7. <el-button size="default" :plain="true" :icon="ZoomOut" @click="zoomOut()" />
  8. <el-button size="default" class="w-80px"> {{ scaleValue }}% </el-button>
  9. <el-button size="default" :plain="true" :icon="ZoomIn" @click="zoomIn()" />
  10. </el-button-group>
  11. </el-row>
  12. </div>
  13. <div class="simple-process-model" :style="`transform: scale(${scaleValue / 100});`">
  14. <ProcessNodeTree v-if="processNodeTree" v-model:flow-node="processNodeTree" />
  15. </div>
  16. </div>
  17. <Dialog v-model="errorDialogVisible" title="保存失败" width="400" :fullscreen="false">
  18. <div class="mb-2">以下节点内容不完善,请修改后保存</div>
  19. <div
  20. class="mb-3 b-rounded-1 bg-gray-100 p-2 line-height-normal"
  21. v-for="(item, index) in errorNodes"
  22. :key="index"
  23. >
  24. {{ item.name }} : {{ NODE_DEFAULT_TEXT.get(item.type) }}
  25. </div>
  26. <template #footer>
  27. <el-button type="primary" @click="errorDialogVisible = false">知道了</el-button>
  28. </template>
  29. </Dialog>
  30. </template>
  31. <script setup lang="ts">
  32. import ProcessNodeTree from './ProcessNodeTree.vue'
  33. import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from './consts'
  34. import { useWatchNode } from './node'
  35. import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue'
  36. defineOptions({
  37. name: 'SimpleProcessModel'
  38. })
  39. const props = defineProps({
  40. flowNode: {
  41. type: Object as () => SimpleFlowNode,
  42. required: true
  43. },
  44. readonly: {
  45. type: Boolean,
  46. required: false,
  47. default: true
  48. }
  49. })
  50. const emits = defineEmits<{
  51. 'save': [node: SimpleFlowNode | undefined]
  52. }>()
  53. const processNodeTree = useWatchNode(props)
  54. provide('readonly', props.readonly)
  55. let scaleValue = ref(100)
  56. const MAX_SCALE_VALUE = 200
  57. const MIN_SCALE_VALUE = 50
  58. // 放大
  59. const zoomIn = () => {
  60. if (scaleValue.value == MAX_SCALE_VALUE) {
  61. return
  62. }
  63. scaleValue.value += 10
  64. }
  65. // 缩小
  66. const zoomOut = () => {
  67. if (scaleValue.value == MIN_SCALE_VALUE) {
  68. return
  69. }
  70. scaleValue.value -= 10
  71. }
  72. const processReZoom = () => {
  73. scaleValue.value = 100
  74. }
  75. const errorDialogVisible = ref(false)
  76. let errorNodes: SimpleFlowNode[] = []
  77. // 校验节点设置。 暂时以 showText 为空 未节点错误配置
  78. const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
  79. if (node) {
  80. const { type, showText, conditionNodes } = node
  81. if (type == NodeType.END_EVENT_NODE) {
  82. return
  83. }
  84. if (type == NodeType.START_USER_NODE) {
  85. // 发起人节点暂时不用校验,直接校验孩子节点
  86. validateNode(node.childNode, errorNodes)
  87. }
  88. if (
  89. type === NodeType.USER_TASK_NODE ||
  90. type === NodeType.COPY_TASK_NODE ||
  91. type === NodeType.CONDITION_NODE
  92. ) {
  93. if (!showText) {
  94. errorNodes.push(node)
  95. }
  96. validateNode(node.childNode, errorNodes)
  97. }
  98. if (
  99. type == NodeType.CONDITION_BRANCH_NODE ||
  100. type == NodeType.PARALLEL_BRANCH_NODE ||
  101. type == NodeType.INCLUSIVE_BRANCH_NODE
  102. ) {
  103. // 分支节点
  104. // 1. 先校验各个分支
  105. conditionNodes?.forEach((item) => {
  106. validateNode(item, errorNodes)
  107. })
  108. // 2. 校验孩子节点
  109. validateNode(node.childNode, errorNodes)
  110. }
  111. }
  112. }
  113. /** 获取当前流程数据 */
  114. const getCurrentFlowData = async () => {
  115. try {
  116. errorNodes = []
  117. validateNode(processNodeTree.value, errorNodes)
  118. if (errorNodes.length > 0) {
  119. errorDialogVisible.value = true
  120. return undefined
  121. }
  122. return processNodeTree.value
  123. } catch (error) {
  124. console.error('获取流程数据失败:', error)
  125. return undefined
  126. }
  127. }
  128. defineExpose({
  129. getCurrentFlowData
  130. })
  131. </script>
  132. <style lang="scss" scoped></style>