ProcessInstanceOperationButton.vue 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  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. <el-popover
  322. :visible="popOverVisible.deleteSign"
  323. placement="top-start"
  324. :width="420"
  325. trigger="click"
  326. v-if="runningTask?.children.length > 0"
  327. >
  328. <template #reference>
  329. <div @click="openPopover('deleteSign')" class="hover-bg-gray-100 rounded-xl p-6px">
  330. <Icon :size="14" icon="ep:semi-select" />&nbsp; 减签
  331. </div>
  332. </template>
  333. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  334. <el-form
  335. label-position="top"
  336. class="mb-auto"
  337. ref="formRef"
  338. :model="genericForm"
  339. :rules="genericRule"
  340. label-width="100px"
  341. >
  342. <el-form-item label="减签人员" prop="deleteSignTaskId">
  343. <el-select v-model="genericForm.deleteSignTaskId" clearable style="width: 100%">
  344. <el-option
  345. v-for="item in runningTask.children"
  346. :key="item.id"
  347. :label="getDeleteSignUserLabel(item)"
  348. :value="item.id"
  349. />
  350. </el-select>
  351. </el-form-item>
  352. <el-form-item label="审批意见" prop="reason">
  353. <el-input
  354. v-model="genericForm.reason"
  355. clearable
  356. placeholder="请输入审批意见"
  357. type="textarea"
  358. :rows="3"
  359. />
  360. </el-form-item>
  361. <el-form-item>
  362. <el-button :disabled="formLoading" type="primary" @click="handlerDeleteSign()">
  363. 减签
  364. </el-button>
  365. <el-button @click="popOverVisible.deleteSign = false"> 取消 </el-button>
  366. </el-form-item>
  367. </el-form>
  368. </div>
  369. </el-popover>
  370. <!-- 【退回】按钮 -->
  371. <el-popover
  372. :visible="popOverVisible.return"
  373. placement="top-start"
  374. :width="420"
  375. trigger="click"
  376. v-if="runningTask && isHandleTaskStatus() && isShowButton(OperationButtonType.RETURN)"
  377. >
  378. <template #reference>
  379. <div @click="openReturnPopover" class="hover-bg-gray-100 rounded-xl p-6px">
  380. <Icon :size="14" icon="ep:back" />&nbsp;
  381. {{ getButtonDisplayName(OperationButtonType.RETURN) }}
  382. </div>
  383. </template>
  384. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  385. <el-form
  386. label-position="top"
  387. class="mb-auto"
  388. ref="formRef"
  389. :model="genericForm"
  390. :rules="genericRule"
  391. label-width="100px"
  392. >
  393. <el-form-item label="退回节点" prop="targetTaskDefinitionKey">
  394. <el-select v-model="genericForm.targetTaskDefinitionKey" clearable style="width: 100%">
  395. <el-option
  396. v-for="item in returnList"
  397. :key="item.taskDefinitionKey"
  398. :label="item.name"
  399. :value="item.taskDefinitionKey"
  400. />
  401. </el-select>
  402. </el-form-item>
  403. <el-form-item label="退回理由" prop="returnReason">
  404. <el-input
  405. v-model="genericForm.returnReason"
  406. clearable
  407. placeholder="请输入退回理由"
  408. type="textarea"
  409. :rows="3"
  410. />
  411. </el-form-item>
  412. <el-form-item>
  413. <el-button :disabled="formLoading" type="primary" @click="handleReturn()">
  414. {{ getButtonDisplayName(OperationButtonType.RETURN) }}
  415. </el-button>
  416. <el-button @click="popOverVisible.return = false"> 取消 </el-button>
  417. </el-form-item>
  418. </el-form>
  419. </div>
  420. </el-popover>
  421. <!--【取消】按钮 这个对应发起人的取消, 只有发起人可以取消 -->
  422. <el-popover
  423. :visible="popOverVisible.cancel"
  424. placement="top-start"
  425. :width="420"
  426. trigger="click"
  427. v-if="
  428. userId === processInstance?.startUser?.id && !isEndProcessStatus(processInstance?.status)
  429. "
  430. >
  431. <template #reference>
  432. <div @click="openPopover('cancel')" class="hover-bg-gray-100 rounded-xl p-6px">
  433. <Icon :size="14" icon="fa:mail-reply" />&nbsp; 取消
  434. </div>
  435. </template>
  436. <div class="flex flex-col flex-1 pt-20px px-20px" v-loading="formLoading">
  437. <el-form
  438. label-position="top"
  439. class="mb-auto"
  440. ref="formRef"
  441. :model="genericForm"
  442. :rules="genericRule"
  443. label-width="100px"
  444. >
  445. <el-form-item label="取消理由" prop="cancelReason">
  446. <span class="text-#878c93 text-12px">&nbsp; 取消后,该审批流程将自动结束</span>
  447. <el-input
  448. v-model="genericForm.cancelReason"
  449. clearable
  450. placeholder="请输入取消理由"
  451. type="textarea"
  452. :rows="3"
  453. />
  454. </el-form-item>
  455. <el-form-item>
  456. <el-button :disabled="formLoading" type="primary" @click="handleCancel()">
  457. 取消
  458. </el-button>
  459. <el-button @click="popOverVisible.cancel = false"> 取消 </el-button>
  460. </el-form-item>
  461. </el-form>
  462. </div>
  463. </el-popover>
  464. <!-- 【再次提交】 按钮-->
  465. <div
  466. @click="handleReCreate()"
  467. class="hover-bg-gray-100 rounded-xl p-6px"
  468. v-if="
  469. userId === processInstance?.startUser?.id &&
  470. isEndProcessStatus(processInstance?.status) &&
  471. processDefinition?.formType === 10
  472. "
  473. >
  474. <Icon :size="14" icon="ep:refresh" />&nbsp; 再次提交
  475. </div>
  476. </div>
  477. </template>
  478. <script lang="ts" setup>
  479. import { useUserStoreWithOut } from '@/store/modules/user'
  480. import { setConfAndFields2 } from '@/utils/formCreate'
  481. import * as TaskApi from '@/api/bpm/task'
  482. import * as ProcessInstanceApi from '@/api/bpm/processInstance'
  483. import { propTypes } from '@/utils/propTypes'
  484. import {
  485. OperationButtonType,
  486. OPERATION_BUTTON_NAME
  487. } from '@/components/SimpleProcessDesignerV2/src/consts'
  488. import { BpmProcessInstanceStatus } from '@/utils/constants'
  489. defineOptions({ name: 'ProcessInstanceBtnContainer' })
  490. const router = useRouter() // 路由
  491. const message = useMessage() // 消息弹窗
  492. const { proxy } = getCurrentInstance() as any
  493. const userId = useUserStoreWithOut().getUser.id // 当前登录的编号
  494. const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  495. const props = defineProps({
  496. processInstance: propTypes.object, // 流程实例信息
  497. processDefinition: propTypes.object, // 流程定义信息
  498. userOptions: propTypes.any
  499. })
  500. const formLoading = ref(false) // 表单加载中
  501. const popOverVisible = ref({
  502. approve: false,
  503. reject: false,
  504. transfer: false,
  505. delegate: false,
  506. addSign: false,
  507. return: false,
  508. copy: false,
  509. cancel: false,
  510. deleteSign: false
  511. }) // 气泡卡是否展示
  512. const returnList = ref([] as any) // 退回节点
  513. // ========== 审批信息 ==========
  514. const runningTask = ref<any>() // 运行中的任务
  515. const genericForm = ref<any>({}) // 通用表单
  516. const approveForm = ref<any>({}) // 审批通过时,额外的补充信息
  517. const approveFormFApi = ref<any>({}) // approveForms 的 fAPi
  518. const formRef = ref()
  519. const genericRule = reactive({
  520. reason: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
  521. returnReason: [{ required: true, message: '退回理由不能为空', trigger: 'blur' }],
  522. cancelReason: [{ required: true, message: '取消理由不能为空', trigger: 'blur' }],
  523. copyUserIds: [{ required: true, message: '抄送人不能为空', trigger: 'change' }],
  524. assigneeUserId: [{ required: true, message: '新审批人不能为空', trigger: 'change' }],
  525. delegateUserId: [{ required: true, message: '接收人不能为空', trigger: 'change' }],
  526. addSignUserIds: [{ required: true, message: '加签处理人不能为空', trigger: 'change' }],
  527. deleteSignTaskId: [{ required: true, message: '减签人员不能为空', trigger: 'change' }],
  528. targetTaskDefinitionKey: [{ required: true, message: '退回节点不能为空', trigger: 'change' }]
  529. }) // 表单校验规则
  530. /** 监听 approveFormFApis,实现它对应的 form-create 初始化后,隐藏掉对应的表单提交按钮 */
  531. watch(
  532. () => approveFormFApi.value,
  533. (val) => {
  534. val?.btn?.show(false)
  535. val?.resetBtn?.show(false)
  536. },
  537. {
  538. deep: true
  539. }
  540. )
  541. /** 弹出退回气泡卡 */
  542. const openReturnPopover = async () => {
  543. returnList.value = await TaskApi.getTaskListByReturn(runningTask.value.id)
  544. if (returnList.value.length === 0) {
  545. message.warning('当前没有可退回的节点')
  546. return
  547. }
  548. await openPopover('return')
  549. }
  550. /** 弹出气泡卡 */
  551. const openPopover = async (type: string) => {
  552. Object.keys(popOverVisible.value).forEach((item) => {
  553. popOverVisible.value[item] = item === type
  554. })
  555. await nextTick()
  556. formRef.value.resetFields()
  557. }
  558. /** 处理审批通过和不通过的操作 */
  559. const handleAudit = async (pass: boolean) => {
  560. formLoading.value = true
  561. try {
  562. const genericFormRef = proxy.$refs['formRef']
  563. // 1.2 校验表单
  564. const elForm = unref(genericFormRef)
  565. if (!elForm) return
  566. const valid = await elForm.validate()
  567. if (!valid) return
  568. // 2.1 提交审批
  569. const data = {
  570. id: runningTask.value.id,
  571. reason: genericForm.value.reason
  572. }
  573. if (pass) {
  574. // 审批通过,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
  575. const formCreateApi = approveFormFApi.value
  576. if (Object.keys(formCreateApi)?.length > 0) {
  577. await formCreateApi.validate()
  578. // @ts-ignore
  579. data.variables = approveForm.value.value
  580. }
  581. await TaskApi.approveTask(data)
  582. popOverVisible.value.approve = false
  583. message.success('审批通过成功')
  584. } else {
  585. await TaskApi.rejectTask(data)
  586. popOverVisible.value.reject = false
  587. message.success('审批不通过成功')
  588. }
  589. // 2.2 加载最新数据
  590. reload()
  591. } finally {
  592. formLoading.value = false
  593. }
  594. }
  595. /** 处理抄送 */
  596. const handleCopy = async () => {
  597. formLoading.value = true
  598. try {
  599. const copyFormRef = proxy.$refs['formRef']
  600. // 1. 校验表单
  601. const elForm = unref(copyFormRef)
  602. if (!elForm) return
  603. const valid = await elForm.validate()
  604. if (!valid) return
  605. // 2. 提交抄送
  606. const data = {
  607. id: runningTask.value.id,
  608. reason: genericForm.value.copyReason,
  609. copyUserIds: genericForm.value.copyUserIds
  610. }
  611. await TaskApi.copyTask(data)
  612. popOverVisible.value.copy = false
  613. message.success('操作成功')
  614. } finally {
  615. formLoading.value = false
  616. }
  617. }
  618. /** 处理转交 */
  619. const handleTransfer = async () => {
  620. formLoading.value = true
  621. try {
  622. const transferFormRef = proxy.$refs['formRef']
  623. // 1.1 校验表单
  624. const elForm = unref(transferFormRef)
  625. if (!elForm) return
  626. const valid = await elForm.validate()
  627. if (!valid) return
  628. // 1.2 提交转交
  629. const data = {
  630. id: runningTask.value.id,
  631. reason: genericForm.value.reason,
  632. assigneeUserId: genericForm.value.assigneeUserId
  633. }
  634. await TaskApi.transferTask(data)
  635. popOverVisible.value.transfer = false
  636. message.success('操作成功')
  637. // 2. 加载最新数据
  638. reload()
  639. } finally {
  640. formLoading.value = false
  641. }
  642. }
  643. /** 处理委派 */
  644. const handleDelegate = async () => {
  645. formLoading.value = true
  646. try {
  647. const deletegateFormRef = proxy.$refs['formRef']
  648. // 1.1 校验表单
  649. const elForm = unref(deletegateFormRef)
  650. if (!elForm) return
  651. const valid = await elForm.validate()
  652. if (!valid) return
  653. // 1.2 处理委派
  654. const data = {
  655. id: runningTask.value.id,
  656. reason: genericForm.value.reason,
  657. delegateUserId: genericForm.value.delegateUserId
  658. }
  659. await TaskApi.delegateTask(data)
  660. popOverVisible.value.delegate = false
  661. message.success('操作成功')
  662. // 2. 加载最新数据
  663. reload()
  664. } finally {
  665. formLoading.value = false
  666. }
  667. }
  668. /** 处理加签 */
  669. const handlerAddSign = async (type: string) => {
  670. formLoading.value = true
  671. try {
  672. const transferFormRef = proxy.$refs['formRef']
  673. // 1.1 校验表单
  674. const elForm = unref(transferFormRef)
  675. if (!elForm) return
  676. const valid = await elForm.validate()
  677. if (!valid) return
  678. // 1.2 提交加签
  679. const data = {
  680. id: runningTask.value.id,
  681. type,
  682. reason: genericForm.value.reason,
  683. userIds: genericForm.value.addSignUserIds
  684. }
  685. await TaskApi.signCreateTask(data)
  686. message.success('操作成功')
  687. popOverVisible.value.addSign = false
  688. // 2 加载最新数据
  689. reload()
  690. } finally {
  691. formLoading.value = false
  692. }
  693. }
  694. /** 处理退回 */
  695. const handleReturn = async () => {
  696. formLoading.value = true
  697. try {
  698. const returnFormRef = proxy.$refs['formRef']
  699. // 1.1 校验表单
  700. const elForm = unref(returnFormRef)
  701. if (!elForm) return
  702. const valid = await elForm.validate()
  703. if (!valid) return
  704. // 1.2 提交退回
  705. const data = {
  706. id: runningTask.value.id,
  707. reason: genericForm.value.returnReason,
  708. targetTaskDefinitionKey: genericForm.value.targetTaskDefinitionKey
  709. }
  710. await TaskApi.returnTask(data)
  711. popOverVisible.value.return = false
  712. message.success('操作成功')
  713. // 2 重新加载数据
  714. reload()
  715. } finally {
  716. formLoading.value = false
  717. }
  718. }
  719. /** 处理取消 */
  720. const handleCancel = async () => {
  721. formLoading.value = true
  722. try {
  723. const cancelFormRef = proxy.$refs['formRef']
  724. // 1.1 校验表单
  725. const elForm = unref(cancelFormRef)
  726. if (!elForm) return
  727. const valid = await elForm.validate()
  728. if (!valid) return
  729. // 1.2 提交取消
  730. await ProcessInstanceApi.cancelProcessInstanceByStartUser(
  731. props.processInstance.id,
  732. genericForm.value.cancelReason
  733. )
  734. popOverVisible.value.return = false
  735. message.success('操作成功')
  736. // 2 重新加载数据
  737. reload()
  738. } finally {
  739. formLoading.value = false
  740. }
  741. }
  742. /** 处理再次提交 */
  743. const handleReCreate = async () => {
  744. // 跳转发起流程界面
  745. await router.push({
  746. name: 'BpmProcessInstanceCreate',
  747. query: { processInstanceId: props.processInstance?.id }
  748. })
  749. }
  750. /** 获取减签人员标签 */
  751. const getDeleteSignUserLabel = (task:any) : string => {
  752. const deptName = task?.assigneeUser?.deptName || task?.ownerUser?.deptName
  753. const nickname = task?.assigneeUser?.nickname || task?.ownerUser?.nickname
  754. return `${nickname} ( 所属部门:${deptName} )`;
  755. }
  756. /** 处理减签 */
  757. const handlerDeleteSign = async () => {
  758. formLoading.value = true
  759. try {
  760. const deleteFormRef = proxy.$refs['formRef']
  761. // 1.1 校验表单
  762. const elForm = unref(deleteFormRef)
  763. if (!elForm) return
  764. const valid = await elForm.validate()
  765. if (!valid) return
  766. // 1.2 提交减签
  767. const data = {
  768. id: genericForm.value.deleteSignTaskId,
  769. reason: genericForm.value.reason,
  770. }
  771. await TaskApi.signDeleteTask(data)
  772. message.success('减签成功')
  773. popOverVisible.value.deleteSign = false
  774. // 2 加载最新数据
  775. reload()
  776. } finally {
  777. formLoading.value = false
  778. }
  779. }
  780. /** 重新加载数据 */
  781. const reload = () => {
  782. emit('success')
  783. }
  784. /** 任务是否为处理中状态 */
  785. const isHandleTaskStatus = () => {
  786. let canHandle = false
  787. if (TaskApi.TaskStatusEnum.RUNNING === runningTask.value?.status) {
  788. canHandle = true
  789. }
  790. return canHandle
  791. }
  792. /** 流程状态是否为结束状态 */
  793. const isEndProcessStatus = (status: number) => {
  794. let isEndStatus = false
  795. if (
  796. BpmProcessInstanceStatus.APPROVE === status ||
  797. BpmProcessInstanceStatus.REJECT === status ||
  798. BpmProcessInstanceStatus.CANCEL === status
  799. ) {
  800. isEndStatus = true
  801. }
  802. return isEndStatus
  803. }
  804. /** 是否显示按钮 */
  805. const isShowButton = (btnType: OperationButtonType): boolean => {
  806. let isShow = true
  807. if (runningTask.value?.buttonsSetting && runningTask.value?.buttonsSetting[btnType]) {
  808. isShow = runningTask.value.buttonsSetting[btnType].enable
  809. }
  810. return isShow
  811. }
  812. /** 获取按钮的显示名称 */
  813. const getButtonDisplayName = (btnType: OperationButtonType) => {
  814. let displayName = OPERATION_BUTTON_NAME.get(btnType)
  815. if (runningTask.value?.buttonsSetting && runningTask.value?.buttonsSetting[btnType]) {
  816. displayName = runningTask.value.buttonsSetting[btnType].displayName
  817. }
  818. return displayName
  819. }
  820. const loadTodoTask = (task: any) => {
  821. genericForm.value = {}
  822. approveForm.value = {}
  823. approveFormFApi.value = {}
  824. runningTask.value = task
  825. // 处理 approve 表单.
  826. if (task && task.formId && task.formConf) {
  827. const tempApproveForm = {}
  828. setConfAndFields2(tempApproveForm, task.formConf, task.formFields, task.formVariables)
  829. approveForm.value = tempApproveForm
  830. } else {
  831. approveForm.value = {} // 占位,避免为空
  832. }
  833. }
  834. defineExpose({ loadTodoTask })
  835. </script>
  836. <style lang="scss" scoped>
  837. :deep(.el-affix--fixed) {
  838. background-color: var(--el-bg-color);
  839. }
  840. .btn-container {
  841. > div {
  842. display: flex;
  843. margin: 0 8px;
  844. cursor: pointer;
  845. align-items: center;
  846. &:hover {
  847. color: #6db5ff;
  848. }
  849. }
  850. }
  851. </style>