operation-button.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <!-- 操作按钮 -->
  2. <template>
  3. <!-- 有待审批的任务 -->
  4. <view v-if="runningTask" class="yd-detail-footer">
  5. <view class="w-full flex items-center">
  6. <!-- 左侧操作按钮 -->
  7. <view v-for="(action, idx) in leftOperations" :key="idx" class="mr-32rpx w-60rpx flex flex-col items-center" @click="handleOperation(action.operationType)">
  8. <wd-icon :name="action.iconName" size="40rpx" color="#1890ff" />
  9. <text class="mt-4rpx text-22rpx text-[#333]">{{ action.displayName }}</text>
  10. </view>
  11. <!-- 更多操作按钮 -->
  12. <view v-if="moreOperations.length > 0" class="mr-32rpx w-60rpx flex flex-col items-center" @click="handleShowMore">
  13. <wd-icon name="ellipsis" size="40rpx" color="#1890ff" />
  14. <text class="mt-4rpx text-22rpx text-[#333]">更多</text>
  15. </view>
  16. <!-- 更多操作 ActionSheet -->
  17. <wd-action-sheet v-if="moreOperations.length > 0" v-model="showMoreActions" :actions="moreOperations" title="请选择操作" @select="handleMoreAction" />
  18. <!-- 右侧按钮,TODO 是否一定要保留两个按钮 -->
  19. <view class="flex flex-1 gap-16rpx">
  20. <wd-button
  21. v-for="(action, idx) in rightOperations"
  22. :key="idx"
  23. :plain="action.plain"
  24. :type="action.btnType"
  25. :round="false"
  26. class="flex-1"
  27. custom-style="min-width: 200rpx; width: 200rpx;"
  28. @click="handleOperation(action.operationType)"
  29. >
  30. {{ action.displayName }}
  31. </wd-button>
  32. </view>
  33. </view>
  34. </view>
  35. <!-- 无待审批的任务 仅显示取消按钮。TODO 看看还需要显示 -->
  36. <view v-if="!runningTask && isShowProcessStartCancel()" class="yd-detail-footer">
  37. <wd-button
  38. plain
  39. type="primary"
  40. :round="false"
  41. block
  42. @click="handleOperation(BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL)"
  43. >
  44. 取消
  45. </wd-button>
  46. </view>
  47. </template>
  48. <script lang="ts" setup>
  49. import type { Action } from 'wot-design-uni/components/wd-action-sheet/types'
  50. import type { ButtonType } from 'wot-design-uni/components/wd-button/types'
  51. import type { ProcessInstance } from '@/api/bpm/processInstance'
  52. import type { Task } from '@/api/bpm/task'
  53. import { useToast } from 'wot-design-uni'
  54. import { useUserStore } from '@/store'
  55. import {
  56. BpmProcessInstanceStatus,
  57. BpmTaskOperationButtonTypeEnum,
  58. BpmTaskStatusEnum,
  59. OPERATION_BUTTON_NAME,
  60. } from '@/utils/constants'
  61. const showMoreActions = ref(false)
  62. type MoreOperationType = Action & {
  63. operationType: number
  64. }
  65. interface LeftOperationType {
  66. operationType: number
  67. iconName: string
  68. displayName: string
  69. }
  70. interface RightOperationType {
  71. operationType: number
  72. btnType: ButtonType
  73. displayName: string
  74. plain: boolean
  75. }
  76. const operationIconsMap: Record<number, string> = {
  77. [BpmTaskOperationButtonTypeEnum.TRANSFER]: 'transfer',
  78. [BpmTaskOperationButtonTypeEnum.ADD_SIGN]: 'add',
  79. [BpmTaskOperationButtonTypeEnum.DELEGATE]: 'share',
  80. [BpmTaskOperationButtonTypeEnum.RETURN]: 'arrow-left',
  81. [BpmTaskOperationButtonTypeEnum.COPY]: 'copy',
  82. [BpmTaskOperationButtonTypeEnum.DELETE_SIGN]: 'remove',
  83. [BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL]: 'stop-circle',
  84. }
  85. const userStore = useUserStore()
  86. /** 左侧操作按钮 【最多两个】{转办, 委派, 退回, 加签, 抄送等} */
  87. const leftOperations = ref<LeftOperationType[]>([])
  88. /** 右侧操作按钮【最多两个】{通过,拒绝, 取消} */
  89. const rightOperationTypes = []
  90. const rightOperations = ref<RightOperationType[]>([])
  91. /** 更多操作 */
  92. const moreOperations = ref<MoreOperationType[]>([])
  93. const toast = useToast()
  94. const runningTask = ref<Task>()
  95. const processInstance = ref<ProcessInstance>()
  96. const reasonRequire = ref<boolean>(false)
  97. /** 初始化 */
  98. function init(theProcessInstance: ProcessInstance, task: Task) {
  99. processInstance.value = theProcessInstance
  100. runningTask.value = task
  101. if (task) {
  102. reasonRequire.value = task.reasonRequire ?? false
  103. // 右侧按钮
  104. if (isHandleTaskStatus() && isShowButton(BpmTaskOperationButtonTypeEnum.REJECT)) {
  105. rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.REJECT)
  106. rightOperations.value.push({
  107. operationType: BpmTaskOperationButtonTypeEnum.REJECT,
  108. displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.REJECT),
  109. btnType: 'error',
  110. plain: true,
  111. })
  112. }
  113. if (isHandleTaskStatus() && isShowButton(BpmTaskOperationButtonTypeEnum.APPROVE)) {
  114. rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.APPROVE)
  115. rightOperations.value.push({
  116. operationType: BpmTaskOperationButtonTypeEnum.APPROVE,
  117. displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.APPROVE),
  118. btnType: 'primary',
  119. plain: false,
  120. })
  121. }
  122. // 左侧操作,和更多操作
  123. Object.keys(task.buttonsSetting || {}).forEach((key) => {
  124. const operationType = Number(key)
  125. if (task.buttonsSetting[key].enable && isHandleTaskStatus()
  126. && !rightOperationTypes.includes(operationType)) {
  127. if (leftOperations.value.length >= 2) {
  128. moreOperations.value.push({
  129. name: getButtonDisplayName(operationType),
  130. operationType,
  131. })
  132. } else {
  133. leftOperations.value.push({
  134. operationType,
  135. iconName: operationIconsMap[operationType],
  136. displayName: getButtonDisplayName(operationType),
  137. })
  138. }
  139. }
  140. })
  141. /** 减签操作的显示 */
  142. if (isShowDeleteSign()) {
  143. if (leftOperations.value.length >= 2) {
  144. moreOperations.value.push({
  145. name: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.DELETE_SIGN),
  146. operationType: BpmTaskOperationButtonTypeEnum.DELETE_SIGN,
  147. })
  148. } else {
  149. leftOperations.value.push({
  150. operationType: BpmTaskOperationButtonTypeEnum.DELETE_SIGN,
  151. iconName: operationIconsMap[BpmTaskOperationButtonTypeEnum.DELETE_SIGN],
  152. displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.DELETE_SIGN),
  153. })
  154. }
  155. }
  156. }
  157. // 是否显示流程取消
  158. if (isShowProcessStartCancel()) {
  159. if (rightOperationTypes.length < 2) {
  160. rightOperationTypes.push(BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL)
  161. rightOperations.value.push({
  162. operationType: BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL,
  163. displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL),
  164. btnType: 'primary',
  165. plain: true,
  166. })
  167. } else {
  168. if (leftOperations.value.length >= 2) {
  169. moreOperations.value.push({
  170. name: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL),
  171. operationType: BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL,
  172. })
  173. } else {
  174. leftOperations.value.push({
  175. operationType: BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL,
  176. iconName: operationIconsMap[BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL],
  177. displayName: getButtonDisplayName(BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL),
  178. })
  179. }
  180. }
  181. }
  182. }
  183. /** 跳转到相应的操作页面 */
  184. function handleOperation(operationType: number) {
  185. switch (operationType) {
  186. case BpmTaskOperationButtonTypeEnum.APPROVE:
  187. uni.navigateTo({ url: `/pages-bpm/processInstance/detail/audit/index?id=${runningTask.value.id}&pass=true` })
  188. break
  189. case BpmTaskOperationButtonTypeEnum.REJECT:
  190. uni.navigateTo({ url: `/pages-bpm/processInstance/detail/audit/index?id=${runningTask.value.id}&pass=false` })
  191. break
  192. case BpmTaskOperationButtonTypeEnum.DELEGATE:
  193. uni.navigateTo({
  194. url: `/pages-bpm/processInstance/detail/reassign/index?processInstanceId=${runningTask.value.processInstanceId}&taskId=${runningTask.value.id}&type=delegate`,
  195. })
  196. break
  197. case BpmTaskOperationButtonTypeEnum.TRANSFER:
  198. uni.navigateTo({
  199. url: `/pages-bpm/processInstance/detail/reassign/index?processInstanceId=${runningTask.value.processInstanceId}&taskId=${runningTask.value.id}&type=transfer`,
  200. })
  201. break
  202. case BpmTaskOperationButtonTypeEnum.ADD_SIGN:
  203. uni.navigateTo({
  204. url: `/pages-bpm/processInstance/detail/add-sign/index?processInstanceId=${runningTask.value.processInstanceId}&taskId=${runningTask.value.id}`,
  205. })
  206. break
  207. case BpmTaskOperationButtonTypeEnum.RETURN:
  208. uni.navigateTo({
  209. url: `/pages-bpm/processInstance/detail/return/index?processInstanceId=${runningTask.value.processInstanceId}&taskId=${runningTask.value.id}`,
  210. })
  211. break
  212. case BpmTaskOperationButtonTypeEnum.DELETE_SIGN:
  213. uni.navigateTo({
  214. url: `/pages-bpm/processInstance/detail/delete-sign/index?processInstanceId=${runningTask.value.processInstanceId}&taskId=${runningTask.value.id}&children=${encodeURIComponent(JSON.stringify(runningTask.value.children || []))}`,
  215. })
  216. break
  217. case BpmTaskOperationButtonTypeEnum.PROCESS_START_CANCEL:
  218. uni.navigateTo({
  219. url: `/pages-bpm/processInstance/detail/process-cancel/index?processInstanceId=${processInstance.value.id}&taskId=${runningTask.value?.id}`,
  220. })
  221. break
  222. }
  223. }
  224. /** 显示更多操作 */
  225. function handleShowMore() {
  226. showMoreActions.value = true
  227. }
  228. /** 处理更多操作选择 */
  229. function handleMoreAction(action: { item: MoreOperationType }) {
  230. handleOperation(action.item.operationType)
  231. showMoreActions.value = false
  232. }
  233. /** 获取按钮的显示名称 */
  234. function getButtonDisplayName(btnType: BpmTaskOperationButtonTypeEnum) {
  235. let displayName = OPERATION_BUTTON_NAME.get(btnType)
  236. if (
  237. runningTask.value?.buttonsSetting
  238. && runningTask.value?.buttonsSetting[btnType]
  239. ) {
  240. displayName = runningTask.value.buttonsSetting[btnType].displayName
  241. }
  242. return displayName
  243. }
  244. /** 是否显示按钮 */
  245. function isShowButton(btnType: BpmTaskOperationButtonTypeEnum): boolean {
  246. let isShow = true
  247. if (
  248. runningTask.value?.buttonsSetting
  249. && runningTask.value?.buttonsSetting[btnType]
  250. ) {
  251. isShow = runningTask.value.buttonsSetting[btnType].enable
  252. }
  253. return isShow
  254. }
  255. /** 任务是否为处理中状态 */
  256. function isHandleTaskStatus() {
  257. let canHandle = false
  258. if (BpmTaskStatusEnum.RUNNING === runningTask.value?.status) {
  259. canHandle = true
  260. }
  261. return canHandle
  262. }
  263. /** 流程状态是否为结束状态 */
  264. function isEndProcessStatus(status: number) {
  265. let isEndStatus = false
  266. if (
  267. BpmProcessInstanceStatus.APPROVE === status
  268. || BpmProcessInstanceStatus.REJECT === status
  269. || BpmProcessInstanceStatus.CANCEL === status
  270. ) {
  271. isEndStatus = true
  272. }
  273. return isEndStatus
  274. }
  275. /** 流程发起人是否为当前用户 */
  276. function isProcessStartUser() {
  277. let isStartUser = false
  278. if (userStore.userInfo?.userId === processInstance.value?.startUser?.id) {
  279. isStartUser = true
  280. }
  281. return isStartUser
  282. }
  283. /** 是否显示减签 */
  284. function isShowDeleteSign() {
  285. return runningTask.value?.children?.length > 0
  286. }
  287. /** 是否显示流程发起人取消 */
  288. function isShowProcessStartCancel() {
  289. return isProcessStartUser() && !isEndProcessStatus(processInstance.value?.status)
  290. }
  291. /** 暴露方法 */
  292. defineExpose({ init })
  293. </script>