SimpleProcessDesigner.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <template>
  2. <div class="overflow-auto">
  3. <SimpleProcessModel
  4. ref="simpleProcessModelRef"
  5. v-if="processNodeTree"
  6. :flow-node="processNodeTree"
  7. :readonly="false"
  8. @save="saveSimpleFlowModel"
  9. />
  10. <Dialog v-model="errorDialogVisible" title="保存失败" width="400" :fullscreen="false">
  11. <div class="mb-2">以下节点内容不完善,请修改后保存</div>
  12. <div
  13. class="mb-3 b-rounded-1 bg-gray-100 p-2 line-height-normal"
  14. v-for="(item, index) in errorNodes"
  15. :key="index"
  16. >
  17. {{ item.name }} : {{ NODE_DEFAULT_TEXT.get(item.type) }}
  18. </div>
  19. <template #footer>
  20. <el-button type="primary" @click="errorDialogVisible = false">知道了</el-button>
  21. </template>
  22. </Dialog>
  23. </div>
  24. </template>
  25. <script setup lang="ts">
  26. import SimpleProcessModel from './SimpleProcessModel.vue'
  27. import { updateBpmSimpleModel, getBpmSimpleModel } from '@/api/bpm/simple'
  28. import { SimpleFlowNode, NodeType, NodeId, NODE_DEFAULT_TEXT } from './consts'
  29. import { getModel } from '@/api/bpm/model'
  30. import { getForm, FormVO } from '@/api/bpm/form'
  31. import { handleTree } from '@/utils/tree'
  32. import * as RoleApi from '@/api/system/role'
  33. import * as DeptApi from '@/api/system/dept'
  34. import * as PostApi from '@/api/system/post'
  35. import * as UserApi from '@/api/system/user'
  36. import * as UserGroupApi from '@/api/bpm/userGroup'
  37. defineOptions({
  38. name: 'SimpleProcessDesigner'
  39. })
  40. const emits = defineEmits(['success']) // 保存成功事件
  41. const props = defineProps({
  42. modelId: {
  43. type: String,
  44. required: false
  45. },
  46. modelKey: {
  47. type: String,
  48. required: false
  49. },
  50. modelName: {
  51. type: String,
  52. required: false
  53. },
  54. // 可发起流程的人员编号
  55. startUserIds: {
  56. type: Array,
  57. required: false
  58. }
  59. })
  60. const processData = inject('processData') as Ref
  61. const loading = ref(false)
  62. const formFields = ref<string[]>([])
  63. const formType = ref(20)
  64. const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
  65. const postOptions = ref<PostApi.PostVO[]>([]) // 岗位列表
  66. const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
  67. const deptOptions = ref<DeptApi.DeptVO[]>([]) // 部门列表
  68. const deptTreeOptions = ref()
  69. const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
  70. const isDataInitialized = ref(false) // 添加标记,用于判断数据是否已初始化
  71. provide('formFields', formFields)
  72. provide('formType', formType)
  73. provide('roleList', roleOptions)
  74. provide('postList', postOptions)
  75. provide('userList', userOptions)
  76. provide('deptList', deptOptions)
  77. provide('userGroupList', userGroupOptions)
  78. provide('deptTree', deptTreeOptions)
  79. provide('startUserIds', props.startUserIds)
  80. provide('tasks', [])
  81. provide('processInstance', {})
  82. const message = useMessage() // 国际化
  83. const processNodeTree = ref<SimpleFlowNode | undefined>()
  84. provide('processNodeTree', processNodeTree)
  85. const errorDialogVisible = ref(false)
  86. let errorNodes: SimpleFlowNode[] = []
  87. // 添加更新模型的方法
  88. const updateModel = () => {
  89. if (!processNodeTree.value) {
  90. processNodeTree.value = {
  91. name: '发起人',
  92. type: NodeType.START_USER_NODE,
  93. id: NodeId.START_USER_NODE_ID,
  94. childNode: {
  95. id: NodeId.END_EVENT_NODE_ID,
  96. name: '结束',
  97. type: NodeType.END_EVENT_NODE
  98. }
  99. }
  100. // 初始化时也触发一次保存
  101. saveSimpleFlowModel(processNodeTree.value)
  102. }
  103. }
  104. const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => {
  105. if (!simpleModelNode) {
  106. return
  107. }
  108. try {
  109. processData.value = simpleModelNode
  110. emits('success', simpleModelNode)
  111. } catch (error) {
  112. console.error('保存失败:', error)
  113. }
  114. }
  115. // 校验节点设置。 暂时以 showText 为空 未节点错误配置
  116. const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
  117. if (node) {
  118. const { type, showText, conditionNodes } = node
  119. if (type == NodeType.END_EVENT_NODE) {
  120. return
  121. }
  122. if (type == NodeType.START_USER_NODE) {
  123. // 发起人节点暂时不用校验,直接校验孩子节点
  124. validateNode(node.childNode, errorNodes)
  125. }
  126. if (
  127. type === NodeType.USER_TASK_NODE ||
  128. type === NodeType.COPY_TASK_NODE ||
  129. type === NodeType.CONDITION_NODE
  130. ) {
  131. if (!showText) {
  132. errorNodes.push(node)
  133. }
  134. validateNode(node.childNode, errorNodes)
  135. }
  136. if (
  137. type == NodeType.CONDITION_BRANCH_NODE ||
  138. type == NodeType.PARALLEL_BRANCH_NODE ||
  139. type == NodeType.INCLUSIVE_BRANCH_NODE
  140. ) {
  141. // 分支节点
  142. // 1. 先校验各个分支
  143. conditionNodes?.forEach((item) => {
  144. validateNode(item, errorNodes)
  145. })
  146. // 2. 校验孩子节点
  147. validateNode(node.childNode, errorNodes)
  148. }
  149. }
  150. }
  151. // 初始化数据的方法
  152. const initializeData = async () => {
  153. if (isDataInitialized.value) {
  154. return
  155. }
  156. try {
  157. loading.value = true
  158. // 并行加载所有数据
  159. const [roleList, postList, userList, deptList, userGroupList] = await Promise.all([
  160. RoleApi.getSimpleRoleList(),
  161. PostApi.getSimplePostList(),
  162. UserApi.getSimpleUserList(),
  163. DeptApi.getSimpleDeptList(),
  164. UserGroupApi.getUserGroupSimpleList()
  165. ])
  166. // 更新数据
  167. roleOptions.value = roleList
  168. postOptions.value = postList
  169. userOptions.value = userList
  170. deptOptions.value = deptList
  171. deptTreeOptions.value = handleTree(deptList as DeptApi.DeptVO[], 'id')
  172. userGroupOptions.value = userGroupList
  173. // 获取表单字段
  174. if (props.modelId) {
  175. const bpmnModel = await getModel(props.modelId)
  176. if (bpmnModel) {
  177. formType.value = bpmnModel.formType
  178. if (formType.value === 10) {
  179. const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
  180. formFields.value = bpmnForm?.fields
  181. }
  182. }
  183. }
  184. // 获得角色列表
  185. roleOptions.value = await RoleApi.getSimpleRoleList()
  186. // 获得岗位列表
  187. postOptions.value = await PostApi.getSimplePostList()
  188. // 获得用户列表
  189. userOptions.value = await UserApi.getSimpleUserList()
  190. // 获得部门列表
  191. deptOptions.value = await DeptApi.getSimpleDeptList()
  192. deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id')
  193. // 获取用户组列表
  194. userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
  195. // 加载流程数据
  196. if (processData.value) {
  197. processNodeTree.value = processData?.value
  198. } else {
  199. updateModel()
  200. }
  201. isDataInitialized.value = true
  202. } catch (error) {
  203. console.error('初始化数据失败:', error)
  204. } finally {
  205. loading.value = false
  206. }
  207. }
  208. onMounted(async () => {
  209. await initializeData()
  210. })
  211. // 添加 activated 生命周期钩子
  212. onActivated(() => {
  213. // 组件被激活时,只需要刷新视图
  214. if (isDataInitialized.value) {
  215. refresh()
  216. } else {
  217. initializeData()
  218. }
  219. })
  220. const simpleProcessModelRef = ref()
  221. defineExpose({})
  222. </script>