ProcessInstanceSimpleViewer.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <div v-loading="loading" class="process-viewer-container">
  3. <div
  4. ref="wrapperRef"
  5. class="process-viewer-wrapper"
  6. @mousedown="startDrag"
  7. @mousemove="onDrag"
  8. @mouseup="stopDrag"
  9. @mouseleave="stopDrag"
  10. >
  11. <SimpleProcessViewer
  12. :flow-node="simpleModel"
  13. :tasks="tasks"
  14. :process-instance="processInstance"
  15. />
  16. </div>
  17. </div>
  18. </template>
  19. <script lang="ts" setup>
  20. import { propTypes } from '@/utils/propTypes'
  21. import { TaskStatusEnum } from '@/api/bpm/task'
  22. import { SimpleFlowNode, NodeType } from '@/components/SimpleProcessDesignerV2/src/consts'
  23. import { SimpleProcessViewer } from '@/components/SimpleProcessDesignerV2/src/'
  24. defineOptions({ name: 'BpmProcessInstanceSimpleViewer' })
  25. const props = defineProps({
  26. loading: propTypes.bool.def(false), // 是否加载中
  27. modelView: propTypes.object,
  28. simpleJson: propTypes.string // Simple 模型结构数据 (json 格式)
  29. })
  30. const simpleModel = ref<any>({})
  31. // 用户任务
  32. const tasks = ref([])
  33. // 流程实例
  34. const processInstance = ref()
  35. const wrapperRef = ref<HTMLElement>()
  36. const isDragging = ref(false)
  37. const startX = ref(0)
  38. const startY = ref(0)
  39. const currentX = ref(0)
  40. const currentY = ref(0)
  41. const startDrag = (e: MouseEvent) => {
  42. if (!wrapperRef.value) return
  43. isDragging.value = true
  44. startX.value = e.clientX - currentX.value
  45. startY.value = e.clientY - currentY.value
  46. }
  47. const onDrag = (e: MouseEvent) => {
  48. if (!isDragging.value || !wrapperRef.value) return
  49. e.preventDefault()
  50. currentX.value = e.clientX - startX.value
  51. currentY.value = e.clientY - startY.value
  52. wrapperRef.value.style.transform = `translate(${currentX.value}px, ${currentY.value}px)`
  53. }
  54. const stopDrag = () => {
  55. isDragging.value = false
  56. }
  57. /** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
  58. watch(
  59. () => props.modelView,
  60. async (newModelView) => {
  61. if (newModelView) {
  62. tasks.value = newModelView.tasks
  63. processInstance.value = newModelView.processInstance
  64. // 已经拒绝的活动节点编号集合,只包括 UserTask
  65. const rejectedTaskActivityIds: string[] = newModelView.rejectedTaskActivityIds
  66. // 进行中的活动节点编号集合, 只包括 UserTask
  67. const unfinishedTaskActivityIds: string[] = newModelView.unfinishedTaskActivityIds
  68. // 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
  69. const finishedActivityIds: string[] = newModelView.finishedTaskActivityIds
  70. // 已经完成的连线节点编号集合,只包括 SequenceFlow
  71. const finishedSequenceFlowActivityIds: string[] = newModelView.finishedSequenceFlowActivityIds
  72. setSimpleModelNodeTaskStatus(
  73. newModelView.simpleModel,
  74. newModelView.processInstance.status,
  75. rejectedTaskActivityIds,
  76. unfinishedTaskActivityIds,
  77. finishedActivityIds,
  78. finishedSequenceFlowActivityIds
  79. )
  80. simpleModel.value = newModelView.simpleModel
  81. }
  82. }
  83. )
  84. /** 监控模型结构数据 */
  85. watch(
  86. () => props.simpleJson,
  87. async (value) => {
  88. if (value) {
  89. simpleModel.value = JSON.parse(value)
  90. }
  91. }
  92. )
  93. const setSimpleModelNodeTaskStatus = (
  94. simpleModel: SimpleFlowNode | undefined,
  95. processStatus: number,
  96. rejectedTaskActivityIds: string[],
  97. unfinishedTaskActivityIds: string[],
  98. finishedActivityIds: string[],
  99. finishedSequenceFlowActivityIds: string[]
  100. ) => {
  101. if (!simpleModel) {
  102. return
  103. }
  104. // 结束节点
  105. if (simpleModel.type === NodeType.END_EVENT_NODE) {
  106. if (finishedActivityIds.includes(simpleModel.id)) {
  107. simpleModel.activityStatus = processStatus
  108. } else {
  109. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  110. }
  111. return
  112. }
  113. // 审批节点
  114. if (
  115. simpleModel.type === NodeType.START_USER_NODE ||
  116. simpleModel.type === NodeType.USER_TASK_NODE
  117. ) {
  118. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  119. if (rejectedTaskActivityIds.includes(simpleModel.id)) {
  120. simpleModel.activityStatus = TaskStatusEnum.REJECT
  121. } else if (unfinishedTaskActivityIds.includes(simpleModel.id)) {
  122. simpleModel.activityStatus = TaskStatusEnum.RUNNING
  123. } else if (finishedActivityIds.includes(simpleModel.id)) {
  124. simpleModel.activityStatus = TaskStatusEnum.APPROVE
  125. }
  126. // TODO 是不是还缺一个 cancel 的状态
  127. }
  128. // 抄送节点
  129. if (simpleModel.type === NodeType.COPY_TASK_NODE) {
  130. // 抄送节点,只有通过和未执行状态
  131. if (finishedActivityIds.includes(simpleModel.id)) {
  132. simpleModel.activityStatus = TaskStatusEnum.APPROVE
  133. } else {
  134. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  135. }
  136. }
  137. // 延迟器节点
  138. if (simpleModel.type === NodeType.DELAY_TIMER_NODE) {
  139. // 延迟器节点,只有通过和未执行状态
  140. if (finishedActivityIds.includes(simpleModel.id)) {
  141. simpleModel.activityStatus = TaskStatusEnum.APPROVE
  142. } else {
  143. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  144. }
  145. }
  146. // 触发器节点
  147. if (simpleModel.type === NodeType.TRIGGER_NODE) {
  148. // 触发器节点,只有通过和未执行状态
  149. if (finishedActivityIds.includes(simpleModel.id)) {
  150. simpleModel.activityStatus = TaskStatusEnum.APPROVE
  151. } else {
  152. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  153. }
  154. }
  155. // 条件节点对应 SequenceFlow
  156. if (simpleModel.type === NodeType.CONDITION_NODE) {
  157. // 条件节点,只有通过和未执行状态
  158. if (finishedSequenceFlowActivityIds.includes(simpleModel.id)) {
  159. simpleModel.activityStatus = TaskStatusEnum.APPROVE
  160. } else {
  161. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  162. }
  163. }
  164. // 网关节点
  165. if (
  166. simpleModel.type === NodeType.CONDITION_BRANCH_NODE ||
  167. simpleModel.type === NodeType.PARALLEL_BRANCH_NODE ||
  168. simpleModel.type === NodeType.INCLUSIVE_BRANCH_NODE ||
  169. simpleModel.type === NodeType.ROUTER_BRANCH_NODE
  170. ) {
  171. // 网关节点。只有通过和未执行状态
  172. if (finishedActivityIds.includes(simpleModel.id)) {
  173. simpleModel.activityStatus = TaskStatusEnum.APPROVE
  174. } else {
  175. simpleModel.activityStatus = TaskStatusEnum.NOT_START
  176. }
  177. simpleModel.conditionNodes?.forEach((node) => {
  178. setSimpleModelNodeTaskStatus(
  179. node,
  180. processStatus,
  181. rejectedTaskActivityIds,
  182. unfinishedTaskActivityIds,
  183. finishedActivityIds,
  184. finishedSequenceFlowActivityIds
  185. )
  186. })
  187. }
  188. setSimpleModelNodeTaskStatus(
  189. simpleModel.childNode,
  190. processStatus,
  191. rejectedTaskActivityIds,
  192. unfinishedTaskActivityIds,
  193. finishedActivityIds,
  194. finishedSequenceFlowActivityIds
  195. )
  196. }
  197. </script>
  198. <style lang="scss" scoped>
  199. .process-viewer-container {
  200. width: 100%;
  201. height: 100%;
  202. position: relative;
  203. overflow: hidden;
  204. .process-viewer-wrapper {
  205. position: absolute;
  206. top: 0;
  207. left: 0;
  208. min-width: 100%;
  209. min-height: 100%;
  210. cursor: grab;
  211. user-select: none;
  212. &:active {
  213. cursor: grabbing;
  214. }
  215. }
  216. }
  217. </style>