ProcessInstanceOperationButton.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. <template>
  2. <div
  3. class="h-50px bottom-10 text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container"
  4. >
  5. <!-- 【通过】按钮 -->
  6. <el-popover
  7. :visible="popOverVisible.approve"
  8. placement="top-end"
  9. :width="420"
  10. trigger="click"
  11. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.APPROVE)"
  12. >
  13. <template #reference>
  14. <el-button plain type="success" @click="openPopover('approve')">
  15. <Icon icon="ep:select" />&nbsp; {{ getButtonDisplayName(OperationButtonType.APPROVE) }}
  16. </el-button>
  17. </template>
  18. <!-- 审批表单 -->
  19. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  20. <el-form
  21. label-position="top"
  22. class="mb-auto"
  23. ref="formRef"
  24. :model="genericForm"
  25. :rules="genericRule"
  26. label-width="100px"
  27. >
  28. <el-card v-if="runningTask?.formId > 0" class="mb-15px !-mt-10px">
  29. <template #header>
  30. <span class="el-icon-picture-outline"> 填写表单【{{ runningTask?.formName }}】 </span>
  31. </template>
  32. <form-create
  33. v-model="approveForm.value"
  34. v-model:api="approveFormFApi"
  35. :option="approveForm.option"
  36. :rule="approveForm.rule"
  37. />
  38. </el-card>
  39. <el-form-item label="审批意见" prop="reason">
  40. <el-input
  41. v-model="genericForm.reason"
  42. placeholder="请输入审批意见"
  43. type="textarea"
  44. :rows="4"
  45. />
  46. </el-form-item>
  47. <el-form-item>
  48. <el-button :disabled="formLoading" type="success" @click="handleAudit(true)">
  49. {{ getButtonDisplayName(OperationButtonType.APPROVE) }}
  50. </el-button>
  51. <el-button @click="popOverVisible.approve = false"> 取消 </el-button>
  52. </el-form-item>
  53. </el-form>
  54. </div>
  55. </el-popover>
  56. <!-- 【拒绝】按钮 -->
  57. <el-popover
  58. :visible="popOverVisible.reject"
  59. placement="top-end"
  60. :width="420"
  61. trigger="click"
  62. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.REJECT)"
  63. >
  64. <template #reference>
  65. <el-button class="mr-20px" plain type="danger" @click="openPopover('reject')">
  66. <Icon icon="ep:close" />&nbsp; {{ getButtonDisplayName(OperationButtonType.REJECT) }}
  67. </el-button>
  68. </template>
  69. <!-- 审批表单 -->
  70. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  71. <el-form
  72. label-position="top"
  73. class="mb-auto"
  74. ref="formRef"
  75. :model="genericForm"
  76. :rules="genericRule"
  77. label-width="100px"
  78. >
  79. <el-card v-if="runningTask?.formId > 0" class="mb-15px !-mt-10px">
  80. <template #header>
  81. <span class="el-icon-picture-outline"> 填写表单【{{ runningTask?.formName }}】 </span>
  82. </template>
  83. <form-create
  84. v-model="approveForm.value"
  85. v-model:api="approveFormFApi"
  86. :option="approveForm.option"
  87. :rule="approveForm.rule"
  88. />
  89. </el-card>
  90. <el-form-item label="审批意见" prop="reason">
  91. <el-input
  92. v-model="genericForm.reason"
  93. placeholder="请输入审批意见"
  94. type="textarea"
  95. :rows="4"
  96. />
  97. </el-form-item>
  98. <el-form-item>
  99. <el-button :disabled="formLoading" type="danger" @click="handleAudit(false)">
  100. {{ getButtonDisplayName(OperationButtonType.REJECT) }}
  101. </el-button>
  102. <el-button @click="popOverVisible.reject = false"> 取消 </el-button>
  103. </el-form-item>
  104. </el-form>
  105. </div>
  106. </el-popover>
  107. <!-- 【抄送】按钮 -->
  108. <el-popover
  109. :visible="popOverVisible.copy"
  110. placement="top-start"
  111. :width="420"
  112. trigger="click"
  113. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.COPY)"
  114. >
  115. <template #reference>
  116. <div @click="openPopover('copy')" class="hover-bg-gray-100 rounded-xl p-6px">
  117. <Icon :size="14" icon="svg-icon:send" />&nbsp;
  118. {{ getButtonDisplayName(OperationButtonType.COPY) }}
  119. </div>
  120. </template>
  121. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  122. <el-form
  123. label-position="top"
  124. class="mb-auto"
  125. ref="formRef"
  126. :model="genericForm"
  127. :rules="genericRule"
  128. label-width="100px"
  129. >
  130. <el-form-item label="抄送人" prop="copyUserIds">
  131. <el-select
  132. v-model="genericForm.copyUserIds"
  133. clearable
  134. style="width: 100%"
  135. multiple
  136. placeholder="请选择抄送人"
  137. >
  138. <el-option
  139. v-for="item in userOptions"
  140. :key="item.id"
  141. :label="item.nickname"
  142. :value="item.id"
  143. />
  144. </el-select>
  145. </el-form-item>
  146. <el-form-item label="抄送意见" prop="copyReason">
  147. <el-input
  148. v-model="genericForm.copyReason"
  149. clearable
  150. placeholder="请输入抄送意见"
  151. type="textarea"
  152. :rows="3"
  153. />
  154. </el-form-item>
  155. <el-form-item>
  156. <el-button :disabled="formLoading" type="primary" @click="handleCopy">
  157. {{ getButtonDisplayName(OperationButtonType.COPY) }}
  158. </el-button>
  159. <el-button @click="popOverVisible.copy = false"> 取消 </el-button>
  160. </el-form-item>
  161. </el-form>
  162. </div>
  163. </el-popover>
  164. <!-- 【转交】按钮 -->
  165. <el-popover
  166. :visible="popOverVisible.transfer"
  167. placement="top-start"
  168. :width="420"
  169. trigger="click"
  170. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.TRANSFER)"
  171. >
  172. <template #reference>
  173. <div @click="openPopover('transfer')" class="hover-bg-gray-100 rounded-xl p-6px">
  174. <Icon :size="14" icon="fa:share-square-o" />&nbsp;
  175. {{ getButtonDisplayName(OperationButtonType.TRANSFER) }}
  176. </div>
  177. </template>
  178. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  179. <el-form
  180. label-position="top"
  181. class="mb-auto"
  182. ref="formRef"
  183. :model="genericForm"
  184. :rules="genericRule"
  185. label-width="100px"
  186. >
  187. <el-form-item label="新审批人" prop="assigneeUserId">
  188. <el-select v-model="genericForm.assigneeUserId" clearable style="width: 100%">
  189. <el-option
  190. v-for="item in userOptions"
  191. :key="item.id"
  192. :label="item.nickname"
  193. :value="item.id"
  194. />
  195. </el-select>
  196. </el-form-item>
  197. <el-form-item label="审批意见" prop="reason">
  198. <el-input
  199. v-model="genericForm.reason"
  200. clearable
  201. placeholder="请输入审批意见"
  202. type="textarea"
  203. :rows="3"
  204. />
  205. </el-form-item>
  206. <el-form-item>
  207. <el-button :disabled="formLoading" type="primary" @click="handleTransfer()">
  208. {{ getButtonDisplayName(OperationButtonType.TRANSFER) }}
  209. </el-button>
  210. <el-button @click="popOverVisible.transfer = false"> 取消 </el-button>
  211. </el-form-item>
  212. </el-form>
  213. </div>
  214. </el-popover>
  215. <!-- 【委派】按钮 -->
  216. <el-popover
  217. :visible="popOverVisible.delegate"
  218. placement="top-start"
  219. :width="420"
  220. trigger="click"
  221. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.DELEGATE)"
  222. >
  223. <template #reference>
  224. <div @click="openPopover('delegate')" class="hover-bg-gray-100 rounded-xl p-6px">
  225. <Icon :size="14" icon="ep:position" />&nbsp;
  226. {{ getButtonDisplayName(OperationButtonType.DELEGATE) }}
  227. </div>
  228. </template>
  229. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  230. <el-form
  231. label-position="top"
  232. class="mb-auto"
  233. ref="formRef"
  234. :model="genericForm"
  235. :rules="genericRule"
  236. label-width="100px"
  237. >
  238. <el-form-item label="接收人" prop="delegateUserId">
  239. <el-select v-model="genericForm.delegateUserId" clearable style="width: 100%">
  240. <el-option
  241. v-for="item in userOptions"
  242. :key="item.id"
  243. :label="item.nickname"
  244. :value="item.id"
  245. />
  246. </el-select>
  247. </el-form-item>
  248. <el-form-item label="审批意见" prop="reason">
  249. <el-input
  250. v-model="genericForm.reason"
  251. clearable
  252. placeholder="请输入审批意见"
  253. type="textarea"
  254. :rows="3"
  255. />
  256. </el-form-item>
  257. <el-form-item>
  258. <el-button :disabled="formLoading" type="primary" @click="handleDelegate()">
  259. {{ getButtonDisplayName(OperationButtonType.DELEGATE) }}
  260. </el-button>
  261. <el-button @click="popOverVisible.delegate = false"> 取消 </el-button>
  262. </el-form-item>
  263. </el-form>
  264. </div>
  265. </el-popover>
  266. <!-- 【加签】按钮 当前任务审批人为A,向前加签选了一个C,则需要C先审批,然后再是A审批,向后加签B,A审批完,需要B再审批完,才算完成这个任务节点 -->
  267. <el-popover
  268. :visible="popOverVisible.addSign"
  269. placement="top-start"
  270. :width="420"
  271. trigger="click"
  272. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.ADD_SIGN)"
  273. >
  274. <template #reference>
  275. <div @click="openPopover('addSign')" class="hover-bg-gray-100 rounded-xl p-6px">
  276. <Icon :size="14" icon="ep:plus" />&nbsp;
  277. {{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }}
  278. </div>
  279. </template>
  280. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  281. <el-form
  282. label-position="top"
  283. class="mb-auto"
  284. ref="formRef"
  285. :model="genericForm"
  286. :rules="genericRule"
  287. label-width="100px"
  288. >
  289. <el-form-item label="加签处理人" prop="addSignUserIds">
  290. <el-select v-model="genericForm.addSignUserIds" multiple clearable style="width: 100%">
  291. <el-option
  292. v-for="item in userOptions"
  293. :key="item.id"
  294. :label="item.nickname"
  295. :value="item.id"
  296. />
  297. </el-select>
  298. </el-form-item>
  299. <el-form-item label="审批意见" prop="reason">
  300. <el-input
  301. v-model="genericForm.reason"
  302. clearable
  303. placeholder="请输入审批意见"
  304. type="textarea"
  305. :rows="3"
  306. />
  307. </el-form-item>
  308. <el-form-item>
  309. <el-button :disabled="formLoading" type="primary" @click="handlerAddSign('before')">
  310. 向前{{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }}
  311. </el-button>
  312. <el-button :disabled="formLoading" type="primary" @click="handlerAddSign('after')">
  313. 向后{{ getButtonDisplayName(OperationButtonType.ADD_SIGN) }}
  314. </el-button>
  315. <el-button @click="popOverVisible.addSign = false"> 取消 </el-button>
  316. </el-form-item>
  317. </el-form>
  318. </div>
  319. </el-popover>
  320. <!-- 【减签】按钮 -->
  321. <div
  322. @click="openChildrenTask()"
  323. class="hover-bg-gray-100 rounded-xl p-6px"
  324. v-if="runningTask?.children"
  325. >
  326. <Icon :size="14" icon="ep:semi-select" />&nbsp; 减签
  327. </div>
  328. <!-- 【退回】按钮 -->
  329. <el-popover
  330. :visible="popOverVisible.return"
  331. placement="top-start"
  332. :width="420"
  333. trigger="click"
  334. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.RETURN)"
  335. >
  336. <template #reference>
  337. <div @click="openReturnPopover" class="hover-bg-gray-100 rounded-xl p-6px">
  338. <Icon :size="14" icon="ep:back" />&nbsp;
  339. {{ getButtonDisplayName(OperationButtonType.RETURN) }}
  340. </div>
  341. </template>
  342. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  343. <el-form
  344. label-position="top"
  345. class="mb-auto"
  346. ref="formRef"
  347. :model="genericForm"
  348. :rules="genericRule"
  349. label-width="100px"
  350. >
  351. <el-form-item label="退回节点" prop="targetTaskDefinitionKey">
  352. <el-select v-model="genericForm.targetTaskDefinitionKey" clearable style="width: 100%">
  353. <el-option
  354. v-for="item in returnList"
  355. :key="item.taskDefinitionKey"
  356. :label="item.name"
  357. :value="item.taskDefinitionKey"
  358. />
  359. </el-select>
  360. </el-form-item>
  361. <el-form-item label="退回理由" prop="returnReason">
  362. <el-input
  363. v-model="genericForm.returnReason"
  364. clearable
  365. placeholder="请输入退回理由"
  366. type="textarea"
  367. :rows="3"
  368. />
  369. </el-form-item>
  370. <el-form-item>
  371. <el-button :disabled="formLoading" type="primary" @click="handleReturn()">
  372. {{ getButtonDisplayName(OperationButtonType.RETURN) }}
  373. </el-button>
  374. <el-button @click="popOverVisible.return = false"> 取消 </el-button>
  375. </el-form-item>
  376. </el-form>
  377. </div>
  378. </el-popover>
  379. <!--【取消】按钮 这个对应发起人的取消, 只有发起人可以取消 -->
  380. <el-popover
  381. :visible="popOverVisible.cancel"
  382. placement="top-start"
  383. :width="420"
  384. trigger="click"
  385. v-if="
  386. userId === processInstance?.startUser?.id && !isEndProcessStatus(processInstance?.status)
  387. "
  388. >
  389. <template #reference>
  390. <div @click="openPopover('cancel')" class="hover-bg-gray-100 rounded-xl p-6px">
  391. <Icon :size="14" icon="fa:mail-reply" />&nbsp; 取消
  392. </div>
  393. </template>
  394. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  395. <el-form
  396. label-position="top"
  397. class="mb-auto"
  398. ref="formRef"
  399. :model="genericForm"
  400. :rules="genericRule"
  401. label-width="100px"
  402. >
  403. <el-form-item label="取消理由" prop="cancelReason">
  404. <span class="text-#878c93 text-12px">&nbsp; 取消后,该审批流程将自动结束</span>
  405. <el-input
  406. v-model="genericForm.cancelReason"
  407. clearable
  408. placeholder="请输入取消理由"
  409. type="textarea"
  410. :rows="3"
  411. />
  412. </el-form-item>
  413. <el-form-item>
  414. <el-button :disabled="formLoading" type="primary" @click="handleCancel()">
  415. 取消
  416. </el-button>
  417. <el-button @click="popOverVisible.cancel = false"> 取消 </el-button>
  418. </el-form-item>
  419. </el-form>
  420. </div>
  421. </el-popover>
  422. <!-- 【再次提交】 按钮-->
  423. <div
  424. @click="handleReCreate()"
  425. class="hover-bg-gray-100 rounded-xl p-6px"
  426. v-if="
  427. userId === processInstance?.startUser?.id &&
  428. isEndProcessStatus(processInstance?.status) &&
  429. processDefinition?.formType === 10
  430. "
  431. >
  432. <Icon :size="14" icon="ep:refresh" />&nbsp; 再次提交
  433. </div>
  434. <!-- 弹窗:子任务 -->
  435. <TaskSignList ref="taskSignListRef" @success="reload" />
  436. </div>
  437. </template>
  438. <script lang="ts" setup>
  439. import { useUserStoreWithOut } from '@/store/modules/user'
  440. import TaskSignList from './dialog/TaskSignList.vue'
  441. import { setConfAndFields2 } from '@/utils/formCreate'
  442. import * as TaskApi from '@/api/bpm/task'
  443. import * as ProcessInstanceApi from '@/api/bpm/processInstance'
  444. import { propTypes } from '@/utils/propTypes'
  445. import {
  446. OperationButtonType,
  447. OPERATION_BUTTON_NAME
  448. } from '@/components/SimpleProcessDesignerV2/src/consts'
  449. import { BpmProcessInstanceStatus } from '@/utils/constants'
  450. defineOptions({ name: 'ProcessInstanceBtnContainer' })
  451. const router = useRouter() // 路由
  452. const message = useMessage() // 消息弹窗
  453. const { proxy } = getCurrentInstance() as any
  454. const userId = useUserStoreWithOut().getUser.id // 当前登录的编号
  455. const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  456. const props = defineProps({
  457. processInstance: propTypes.object, // 流程实例信息
  458. processDefinition: propTypes.object, // 流程定义信息
  459. userOptions: propTypes.any
  460. })
  461. const formLoading = ref(false) // 表单加载中
  462. const popOverVisible = ref({
  463. approve: false,
  464. reject: false,
  465. transfer: false,
  466. delegate: false,
  467. addSign: false,
  468. return: false,
  469. copy: false,
  470. cancel: false
  471. }) // 气泡卡是否展示
  472. const returnList = ref([] as any) // 退回节点
  473. // ========== 审批信息 ==========
  474. const runningTask = ref<any>() // 运行中的任务
  475. const genericForm = ref<any>({}) // 通用表单
  476. const approveForm = ref<any>({}) // 审批通过时,额外的补充信息
  477. const approveFormFApi = ref<any>({}) // approveForms 的 fAPi
  478. const formRef = ref()
  479. const genericRule = reactive({
  480. reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
  481. returnReason: [{ required: true, message: '退回理由不能为空', trigger: 'blur' }],
  482. cancelReason: [{ required: true, message: '取消理由不能为空', trigger: 'blur' }],
  483. copyUserIds: [{ required: true, message: '抄送人不能为空', trigger: 'change' }],
  484. assigneeUserId: [{ required: true, message: '新审批人不能为空', trigger: 'change' }],
  485. delegateUserId: [{ required: true, message: '接收人不能为空', trigger: 'change' }],
  486. addSignUserIds: [{ required: true, message: '加签处理人不能为空', trigger: 'change' }],
  487. targetTaskDefinitionKey: [{ required: true, message: '退回节点不能为空', trigger: 'change' }]
  488. }) // 表单校验规则
  489. /** 监听 approveFormFApis,实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */
  490. watch(
  491. () => approveFormFApi.value,
  492. (val) => {
  493. val?.btn?.show(false)
  494. val?.resetBtn?.show(false)
  495. },
  496. {
  497. deep: true
  498. }
  499. )
  500. /** 弹出退回气泡卡 */
  501. const openReturnPopover = async () => {
  502. returnList.value = await TaskApi.getTaskListByReturn(runningTask.value.id)
  503. if (returnList.value.length === 0) {
  504. message.warning('当前没有可退回的节点')
  505. return
  506. }
  507. await openPopover('return')
  508. }
  509. /** 弹出气泡卡 */
  510. const openPopover = async (type: string) => {
  511. Object.keys(popOverVisible.value).forEach((item) => {
  512. popOverVisible.value[item] = item === type
  513. })
  514. await nextTick()
  515. formRef.value.resetFields()
  516. }
  517. /** 处理审批通过和不通过的操作 */
  518. const handleAudit = async (pass: boolean) => {
  519. formLoading.value = true
  520. try {
  521. const genericFormRef = proxy.$refs['formRef']
  522. // 1.2 校验表单
  523. const elForm = unref(genericFormRef)
  524. if (!elForm) return
  525. const valid = await elForm.validate()
  526. if (!valid) return
  527. // 2.1 提交审批
  528. const data = {
  529. id: runningTask.value.id,
  530. reason: genericForm.value.reason
  531. }
  532. if (pass) {
  533. // 审批通过,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
  534. const formCreateApi = approveFormFApi.value
  535. if (Object.keys(formCreateApi)?.length > 0) {
  536. await formCreateApi.validate()
  537. // @ts-ignore
  538. data.variables = approveForm.value.value
  539. }
  540. await TaskApi.approveTask(data)
  541. popOverVisible.value.approve = false
  542. message.success('审批通过成功')
  543. } else {
  544. await TaskApi.rejectTask(data)
  545. popOverVisible.value.reject = false
  546. message.success('审批不通过成功')
  547. }
  548. // 2.2 加载最新数据
  549. reload()
  550. } finally {
  551. formLoading.value = false
  552. }
  553. }
  554. /** 处理抄送 */
  555. const handleCopy = async () => {
  556. formLoading.value = true
  557. try {
  558. const copyFormRef = proxy.$refs['formRef']
  559. // 1. 校验表单
  560. const elForm = unref(copyFormRef)
  561. if (!elForm) return
  562. const valid = await elForm.validate()
  563. if (!valid) return
  564. // 2. 提交抄送
  565. const data = {
  566. id: runningTask.value.id,
  567. reason: genericForm.value.copyReason,
  568. copyUserIds: genericForm.value.copyUserIds
  569. }
  570. await TaskApi.copyTask(data)
  571. popOverVisible.value.copy = false
  572. message.success('操作成功')
  573. } finally {
  574. formLoading.value = false
  575. }
  576. }
  577. /** 处理转交 */
  578. const handleTransfer = async () => {
  579. formLoading.value = true
  580. try {
  581. const transferFormRef = proxy.$refs['formRef']
  582. // 1.1 校验表单
  583. const elForm = unref(transferFormRef)
  584. if (!elForm) return
  585. const valid = await elForm.validate()
  586. if (!valid) return
  587. // 1.2 提交转交
  588. const data = {
  589. id: runningTask.value.id,
  590. reason: genericForm.value.reason,
  591. assigneeUserId: genericForm.value.assigneeUserId
  592. }
  593. await TaskApi.transferTask(data)
  594. popOverVisible.value.transfer = false
  595. message.success('操作成功')
  596. // 2. 加载最新数据
  597. reload()
  598. } finally {
  599. formLoading.value = false
  600. }
  601. }
  602. /** 处理委派 */
  603. const handleDelegate = async () => {
  604. formLoading.value = true
  605. try {
  606. const deletegateFormRef = proxy.$refs['formRef']
  607. // 1.1 校验表单
  608. const elForm = unref(deletegateFormRef)
  609. if (!elForm) return
  610. const valid = await elForm.validate()
  611. if (!valid) return
  612. // 1.2 处理委派
  613. const data = {
  614. id: runningTask.value.id,
  615. reason: genericForm.value.reason,
  616. delegateUserId: genericForm.value.delegateUserId
  617. }
  618. await TaskApi.delegateTask(data)
  619. popOverVisible.value.delegate = false
  620. message.success('操作成功')
  621. // 2. 加载最新数据
  622. reload()
  623. } finally {
  624. formLoading.value = false
  625. }
  626. }
  627. /** 处理加签 */
  628. const handlerAddSign = async (type: string) => {
  629. formLoading.value = true
  630. try {
  631. const transferFormRef = proxy.$refs['formRef']
  632. // 1.1 校验表单
  633. const elForm = unref(transferFormRef)
  634. if (!elForm) return
  635. const valid = await elForm.validate()
  636. if (!valid) return
  637. // 1.2 提交加签
  638. const data = {
  639. id: runningTask.value.id,
  640. type,
  641. reason: genericForm.value.reason,
  642. userIds: genericForm.value.addSignUserIds
  643. }
  644. await TaskApi.signCreateTask(data)
  645. message.success('操作成功')
  646. popOverVisible.value.addSign = false
  647. // 2 加载最新数据
  648. reload()
  649. } finally {
  650. formLoading.value = false
  651. }
  652. }
  653. /** 处理退回 */
  654. const handleReturn = async () => {
  655. formLoading.value = true
  656. try {
  657. const returnFormRef = proxy.$refs['formRef']
  658. // 1.1 校验表单
  659. const elForm = unref(returnFormRef)
  660. if (!elForm) return
  661. const valid = await elForm.validate()
  662. if (!valid) return
  663. // 1.2 提交退回
  664. const data = {
  665. id: runningTask.value.id,
  666. reason: genericForm.value.returnReason,
  667. targetTaskDefinitionKey: genericForm.value.targetTaskDefinitionKey
  668. }
  669. await TaskApi.returnTask(data)
  670. popOverVisible.value.return = false
  671. message.success('操作成功')
  672. // 2 重新加载数据
  673. reload()
  674. } finally {
  675. formLoading.value = false
  676. }
  677. }
  678. /** 处理取消 */
  679. const handleCancel = async () => {
  680. formLoading.value = true
  681. try {
  682. const cancelFormRef = proxy.$refs['formRef']
  683. // 1.1 校验表单
  684. const elForm = unref(cancelFormRef)
  685. if (!elForm) return
  686. const valid = await elForm.validate()
  687. if (!valid) return
  688. // 1.2 提交取消
  689. await ProcessInstanceApi.cancelProcessInstanceByStartUser(
  690. props.processInstance.id,
  691. genericForm.value.cancelReason
  692. )
  693. popOverVisible.value.return = false
  694. message.success('操作成功')
  695. // 2 重新加载数据
  696. reload()
  697. } finally {
  698. formLoading.value = false
  699. }
  700. }
  701. /** 处理再次提交 */
  702. const handleReCreate = async () => {
  703. // 跳转发起流程界面
  704. await router.push({
  705. name: 'BpmProcessInstanceCreate',
  706. query: { processInstanceId: props.processInstance?.id }
  707. })
  708. }
  709. /** 子任务 */
  710. const taskSignListRef = ref()
  711. const openChildrenTask = () => {
  712. taskSignListRef.value.open(runningTask.value)
  713. }
  714. /** 重新加载数据 */
  715. const reload = () => {
  716. emit('success')
  717. }
  718. /** 任务是否为处理中状态 */
  719. const isHandleTaskStatus = () => {
  720. let canHandle = false
  721. if (
  722. TaskApi.TaskStatusEnum.RUNNING === runningTask.value?.status ||
  723. TaskApi.TaskStatusEnum.DELEGATE === runningTask.value?.status
  724. ) {
  725. canHandle = true
  726. }
  727. return canHandle
  728. }
  729. /** 流程状态是否为结束状态 */
  730. const isEndProcessStatus = (status: number) => {
  731. let isEndStatus = false
  732. if (
  733. BpmProcessInstanceStatus.APPROVE === status ||
  734. BpmProcessInstanceStatus.REJECT === status ||
  735. BpmProcessInstanceStatus.CANCEL === status
  736. ) {
  737. isEndStatus = true
  738. }
  739. return isEndStatus
  740. }
  741. /** 是否显示按钮 */
  742. const isShowButton = (btnType: OperationButtonType): boolean => {
  743. let isShow = true
  744. if (runningTask.value?.buttonsSetting && runningTask.value?.buttonsSetting[btnType]) {
  745. isShow = runningTask.value.buttonsSetting[btnType].enable
  746. }
  747. return isShow
  748. }
  749. /** 获取按钮的显示名称 */
  750. const getButtonDisplayName = (btnType: OperationButtonType) => {
  751. let displayName = OPERATION_BUTTON_NAME.get(btnType)
  752. if (runningTask.value?.buttonsSetting && runningTask.value?.buttonsSetting[btnType]) {
  753. displayName = runningTask.value.buttonsSetting[btnType].displayName
  754. }
  755. return displayName
  756. }
  757. const loadTodoTask = (task: any) => {
  758. genericForm.value = {}
  759. approveForm.value = {}
  760. approveFormFApi.value = {}
  761. runningTask.value = task
  762. // 处理 approve 表单.
  763. if (task && task.formId && task.formConf) {
  764. const tempApproveForm = {}
  765. setConfAndFields2(tempApproveForm, task.formConf, task.formFields, task.formVariables)
  766. approveForm.value = tempApproveForm
  767. } else {
  768. approveForm.value = {} // 占位,避免为空
  769. }
  770. }
  771. defineExpose({ loadTodoTask })
  772. </script>
  773. <style lang="scss" scoped>
  774. :deep(.el-affix--fixed) {
  775. background-color: var(--el-bg-color);
  776. }
  777. .btn-container {
  778. > div {
  779. display: flex;
  780. margin: 0 8px;
  781. cursor: pointer;
  782. align-items: center;
  783. &:hover {
  784. color: #6db5ff;
  785. }
  786. }
  787. }
  788. </style>