ElementMultiInstance.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <template>
  2. <div class="panel-tab__content">
  3. <el-radio-group
  4. v-if="type === 'UserTask'"
  5. v-model="approveMethod"
  6. @change="onApproveMethodChange"
  7. >
  8. <div class="flex-col">
  9. <div v-for="(item, index) in APPROVE_METHODS" :key="index">
  10. <el-radio :value="item.value" :label="item.value">
  11. {{ item.label }}
  12. </el-radio>
  13. <el-form-item prop="approveRatio">
  14. <el-input-number
  15. v-model="approveRatio"
  16. :min="10"
  17. :max="100"
  18. :step="10"
  19. size="small"
  20. v-if="
  21. item.value === ApproveMethodType.APPROVE_BY_RATIO &&
  22. approveMethod === ApproveMethodType.APPROVE_BY_RATIO
  23. "
  24. @change="onApproveRatioChange"
  25. />
  26. </el-form-item>
  27. </div>
  28. </div>
  29. </el-radio-group>
  30. <div v-else>
  31. 除了UserTask以外节点的多实例待实现
  32. </div>
  33. <!-- 与Simple设计器配置合并,保留以前的代码 -->
  34. <el-form label-width="90px" style="display: none">
  35. <el-form-item label="快捷配置">
  36. <el-button size="small" @click="changeConfig('依次审批')">依次审批</el-button>
  37. <el-button size="small" @click="changeConfig('会签')">会签</el-button>
  38. <el-button size="small" @click="changeConfig('或签')">或签</el-button>
  39. </el-form-item>
  40. <el-form-item label="会签类型">
  41. <el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType">
  42. <el-option label="并行多重事件" value="ParallelMultiInstance" />
  43. <el-option label="时序多重事件" value="SequentialMultiInstance" />
  44. <el-option label="无" value="Null" />
  45. </el-select>
  46. </el-form-item>
  47. <template
  48. v-if="
  49. loopCharacteristics === 'ParallelMultiInstance' ||
  50. loopCharacteristics === 'SequentialMultiInstance'
  51. "
  52. >
  53. <el-form-item label="循环数量" key="loopCardinality">
  54. <el-input
  55. v-model="loopInstanceForm.loopCardinality"
  56. clearable
  57. @change="updateLoopCardinality"
  58. />
  59. </el-form-item>
  60. <el-form-item label="集合" key="collection" v-show="false">
  61. <el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" />
  62. </el-form-item>
  63. <!-- add by 芋艿:由于「元素变量」暂时用不到,所以这里 display 为 none -->
  64. <el-form-item label="元素变量" key="elementVariable" style="display: none">
  65. <el-input v-model="loopInstanceForm.elementVariable" clearable @change="updateLoopBase" />
  66. </el-form-item>
  67. <el-form-item label="完成条件" key="completionCondition">
  68. <el-input
  69. v-model="loopInstanceForm.completionCondition"
  70. clearable
  71. @change="updateLoopCondition"
  72. />
  73. </el-form-item>
  74. <!-- add by 芋艿:由于「异步状态」暂时用不到,所以这里 display 为 none -->
  75. <el-form-item label="异步状态" key="async" style="display: none">
  76. <el-checkbox
  77. v-model="loopInstanceForm.asyncBefore"
  78. label="异步前"
  79. value="异步前"
  80. @change="updateLoopAsync('asyncBefore')"
  81. />
  82. <el-checkbox
  83. v-model="loopInstanceForm.asyncAfter"
  84. label="异步后"
  85. value="异步后"
  86. @change="updateLoopAsync('asyncAfter')"
  87. />
  88. <el-checkbox
  89. v-model="loopInstanceForm.exclusive"
  90. v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
  91. label="排除"
  92. value="排除"
  93. @change="updateLoopAsync('exclusive')"
  94. />
  95. </el-form-item>
  96. <el-form-item
  97. label="重试周期"
  98. prop="timeCycle"
  99. v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
  100. key="timeCycle"
  101. >
  102. <el-input v-model="loopInstanceForm.timeCycle" clearable @change="updateLoopTimeCycle" />
  103. </el-form-item>
  104. </template>
  105. </el-form>
  106. </div>
  107. </template>
  108. <script lang="ts" setup>
  109. import { ApproveMethodType, APPROVE_METHODS } from '@/components/SimpleProcessDesignerV2/src/consts'
  110. defineOptions({ name: 'ElementMultiInstance' })
  111. const props = defineProps({
  112. businessObject: Object,
  113. type: String,
  114. id: String
  115. })
  116. const prefix = inject('prefix')
  117. const loopCharacteristics = ref('')
  118. //默认配置,用来覆盖原始不存在的选项,避免报错
  119. const defaultLoopInstanceForm = ref({
  120. completionCondition: '',
  121. loopCardinality: '',
  122. extensionElements: [],
  123. asyncAfter: false,
  124. asyncBefore: false,
  125. exclusive: false
  126. })
  127. const loopInstanceForm = ref<any>({})
  128. const bpmnElement = ref(null)
  129. const multiLoopInstance = ref(null)
  130. const bpmnInstances = () => (window as any)?.bpmnInstances
  131. const getElementLoop = (businessObject) => {
  132. if (!businessObject.loopCharacteristics) {
  133. loopCharacteristics.value = 'Null'
  134. loopInstanceForm.value = {}
  135. return
  136. }
  137. if (businessObject.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics') {
  138. loopCharacteristics.value = 'StandardLoop'
  139. loopInstanceForm.value = {}
  140. return
  141. }
  142. if (businessObject.loopCharacteristics.isSequential) {
  143. loopCharacteristics.value = 'SequentialMultiInstance'
  144. } else {
  145. loopCharacteristics.value = 'ParallelMultiInstance'
  146. }
  147. // 合并配置
  148. loopInstanceForm.value = {
  149. ...defaultLoopInstanceForm.value,
  150. ...businessObject.loopCharacteristics,
  151. completionCondition: businessObject.loopCharacteristics?.completionCondition?.body ?? '',
  152. loopCardinality: businessObject.loopCharacteristics?.loopCardinality?.body ?? ''
  153. }
  154. // 保留当前元素 businessObject 上的 loopCharacteristics 实例
  155. multiLoopInstance.value = bpmnInstances().bpmnElement.businessObject.loopCharacteristics
  156. // 更新表单
  157. if (
  158. businessObject.loopCharacteristics.extensionElements &&
  159. businessObject.loopCharacteristics.extensionElements.values &&
  160. businessObject.loopCharacteristics.extensionElements.values.length
  161. ) {
  162. loopInstanceForm.value['timeCycle'] =
  163. businessObject.loopCharacteristics.extensionElements.values[0].body
  164. }
  165. }
  166. const changeLoopCharacteristicsType = (type) => {
  167. // this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // 切换类型取消原表单配置
  168. // 取消多实例配置
  169. if (type === 'Null') {
  170. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  171. loopCharacteristics: null
  172. })
  173. return
  174. }
  175. // 配置循环
  176. if (type === 'StandardLoop') {
  177. const loopCharacteristicsObject = bpmnInstances().moddle.create(
  178. 'bpmn:StandardLoopCharacteristics'
  179. )
  180. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  181. loopCharacteristics: loopCharacteristicsObject
  182. })
  183. multiLoopInstance.value = null
  184. return
  185. }
  186. // 时序
  187. if (type === 'SequentialMultiInstance') {
  188. multiLoopInstance.value = bpmnInstances().moddle.create(
  189. 'bpmn:MultiInstanceLoopCharacteristics',
  190. { isSequential: true }
  191. )
  192. } else {
  193. multiLoopInstance.value = bpmnInstances().moddle.create(
  194. 'bpmn:MultiInstanceLoopCharacteristics',
  195. { collection: '${coll_userList}' }
  196. )
  197. }
  198. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  199. loopCharacteristics: toRaw(multiLoopInstance.value)
  200. })
  201. }
  202. // 循环基数
  203. const updateLoopCardinality = (cardinality) => {
  204. let loopCardinality = null
  205. if (cardinality && cardinality.length) {
  206. loopCardinality = bpmnInstances().moddle.create('bpmn:FormalExpression', {
  207. body: cardinality
  208. })
  209. }
  210. bpmnInstances().modeling.updateModdleProperties(
  211. toRaw(bpmnElement.value),
  212. multiLoopInstance.value,
  213. {
  214. loopCardinality
  215. }
  216. )
  217. }
  218. // 完成条件
  219. const updateLoopCondition = (condition) => {
  220. let completionCondition = null
  221. if (condition && condition.length) {
  222. completionCondition = bpmnInstances().moddle.create('bpmn:FormalExpression', {
  223. body: condition
  224. })
  225. }
  226. bpmnInstances().modeling.updateModdleProperties(
  227. toRaw(bpmnElement.value),
  228. multiLoopInstance.value,
  229. {
  230. completionCondition
  231. }
  232. )
  233. }
  234. // 重试周期
  235. const updateLoopTimeCycle = (timeCycle) => {
  236. const extensionElements = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
  237. values: [
  238. bpmnInstances().moddle.create(`${prefix}:FailedJobRetryTimeCycle`, {
  239. body: timeCycle
  240. })
  241. ]
  242. })
  243. bpmnInstances().modeling.updateModdleProperties(
  244. toRaw(bpmnElement.value),
  245. multiLoopInstance.value,
  246. {
  247. extensionElements
  248. }
  249. )
  250. }
  251. // 直接更新的基础信息
  252. const updateLoopBase = () => {
  253. bpmnInstances().modeling.updateModdleProperties(
  254. toRaw(bpmnElement.value),
  255. multiLoopInstance.value,
  256. {
  257. collection: loopInstanceForm.value.collection || null,
  258. elementVariable: loopInstanceForm.value.elementVariable || null
  259. }
  260. )
  261. }
  262. // 各异步状态
  263. const updateLoopAsync = (key) => {
  264. const { asyncBefore, asyncAfter } = loopInstanceForm.value
  265. let asyncAttr = Object.create(null)
  266. if (!asyncBefore && !asyncAfter) {
  267. // this.$set(this.loopInstanceForm, "exclusive", false);
  268. loopInstanceForm.value['exclusive'] = false
  269. asyncAttr = { asyncBefore: false, asyncAfter: false, exclusive: false, extensionElements: null }
  270. } else {
  271. asyncAttr[key] = loopInstanceForm.value[key]
  272. }
  273. bpmnInstances().modeling.updateModdleProperties(
  274. toRaw(bpmnElement.value),
  275. multiLoopInstance.value,
  276. asyncAttr
  277. )
  278. }
  279. const changeConfig = (config) => {
  280. if (config === '依次审批') {
  281. changeLoopCharacteristicsType('SequentialMultiInstance')
  282. updateLoopCardinality('1')
  283. updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
  284. } else if (config === '会签') {
  285. changeLoopCharacteristicsType('ParallelMultiInstance')
  286. updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
  287. } else if (config === '或签') {
  288. changeLoopCharacteristicsType('ParallelMultiInstance')
  289. updateLoopCondition('${ nrOfCompletedInstances > 0 }')
  290. }
  291. }
  292. /**
  293. * -----新版本多实例-----
  294. */
  295. const approveMethod = ref()
  296. const approveRatio = ref(100)
  297. const otherExtensions = ref()
  298. const getElementLoopNew = () => {
  299. if (props.type === 'UserTask') {
  300. const extensionElements =
  301. bpmnElement.value.businessObject?.extensionElements ??
  302. bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
  303. approveMethod.value = extensionElements.values.filter(
  304. (ex) => ex.$type === `${prefix}:ApproveMethod`
  305. )?.[0]?.value
  306. otherExtensions.value =
  307. extensionElements.values.filter((ex) => ex.$type !== `${prefix}:ApproveMethod`) ?? []
  308. if (!approveMethod.value) {
  309. approveMethod.value = ApproveMethodType.SEQUENTIAL_APPROVE
  310. updateLoopCharacteristics()
  311. }
  312. }
  313. }
  314. const onApproveMethodChange = () => {
  315. approveRatio.value = 100
  316. updateLoopCharacteristics()
  317. }
  318. const onApproveRatioChange = () => {
  319. updateLoopCharacteristics()
  320. }
  321. const updateLoopCharacteristics = () => {
  322. // 根据ApproveMethod生成multiInstanceLoopCharacteristics节点
  323. if (approveMethod.value === ApproveMethodType.RANDOM_SELECT_ONE_APPROVE) {
  324. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  325. loopCharacteristics: null
  326. })
  327. } else {
  328. if (approveMethod.value === ApproveMethodType.APPROVE_BY_RATIO) {
  329. multiLoopInstance.value = bpmnInstances().moddle.create(
  330. 'bpmn:MultiInstanceLoopCharacteristics',
  331. { isSequential: false, collection: '${coll_userList}' }
  332. )
  333. multiLoopInstance.value.completionCondition = bpmnInstances().moddle.create(
  334. 'bpmn:FormalExpression',
  335. {
  336. body: '${ nrOfCompletedInstances/nrOfInstances >= ' + approveRatio.value / 100 + '}'
  337. }
  338. )
  339. }
  340. if (approveMethod.value === ApproveMethodType.ANY_APPROVE) {
  341. multiLoopInstance.value = bpmnInstances().moddle.create(
  342. 'bpmn:MultiInstanceLoopCharacteristics',
  343. { isSequential: false, collection: '${coll_userList}' }
  344. )
  345. multiLoopInstance.value.completionCondition = bpmnInstances().moddle.create(
  346. 'bpmn:FormalExpression',
  347. {
  348. body: '${ nrOfCompletedInstances > 0 }'
  349. }
  350. )
  351. }
  352. if (approveMethod.value === ApproveMethodType.SEQUENTIAL_APPROVE) {
  353. multiLoopInstance.value = bpmnInstances().moddle.create(
  354. 'bpmn:MultiInstanceLoopCharacteristics',
  355. { isSequential: true, collection: '${coll_userList}' }
  356. )
  357. multiLoopInstance.value.loopCardinality = bpmnInstances().moddle.create(
  358. 'bpmn:FormalExpression',
  359. {
  360. body: '1'
  361. }
  362. )
  363. multiLoopInstance.value.completionCondition = bpmnInstances().moddle.create(
  364. 'bpmn:FormalExpression',
  365. {
  366. body: '${ nrOfCompletedInstances >= nrOfInstances }'
  367. }
  368. )
  369. }
  370. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  371. loopCharacteristics: toRaw(multiLoopInstance.value)
  372. })
  373. }
  374. // 添加ApproveMethod到ExtensionElements
  375. const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
  376. values: [
  377. ...otherExtensions.value,
  378. bpmnInstances().moddle.create(`${prefix}:ApproveMethod`, {
  379. value: approveMethod.value
  380. })
  381. ]
  382. })
  383. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  384. extensionElements: extensions
  385. })
  386. }
  387. onBeforeUnmount(() => {
  388. multiLoopInstance.value = null
  389. bpmnElement.value = null
  390. })
  391. watch(
  392. () => props.id,
  393. (val) => {
  394. if (val) {
  395. nextTick(() => {
  396. bpmnElement.value = bpmnInstances().bpmnElement
  397. // getElementLoop(val)
  398. getElementLoopNew()
  399. })
  400. }
  401. },
  402. { immediate: true }
  403. )
  404. </script>