InstanceDetails.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <script setup lang="ts" name="InstanceDetails">
  2. import StatusTag from '@/views/workbench/StatusTag'
  3. import ActivityTimeline from '@/views/workbench/activityTimeline/index.vue'
  4. import FormParser from '@/components/FormParser'
  5. import type { FormInfo } from '@/api/modules/flow/define'
  6. import { buildRecords, type FlowActivity, records } from '@/api/modules/flow/activity'
  7. import { showConfirmDialog, showFailToast, showSuccessToast } from 'vant'
  8. import {
  9. cancel,
  10. type FlowInstance,
  11. getForm,
  12. getInstance,
  13. ProcessStatus
  14. } from '@/api/modules/flow/instance'
  15. import { useCachedViewStore } from '@/stores/modules/cachedView'
  16. const router = useRouter()
  17. const cachedViewStore = useCachedViewStore()
  18. const route = router.currentRoute
  19. const formInfo = ref<FormInfo>({
  20. formName: '',
  21. instanceId: '',
  22. taskId: '',
  23. flowDefine: {
  24. id: '',
  25. defineId: '',
  26. key: '',
  27. name: '',
  28. version: 0,
  29. groupId: '',
  30. icon: {
  31. name: '',
  32. color: '',
  33. bgColor: ''
  34. },
  35. process: {
  36. id: '',
  37. pid: '',
  38. name: '',
  39. type: 'start',
  40. next: undefined
  41. },
  42. form: {
  43. labelPosition: 'right',
  44. labelWidth: 100,
  45. gutter: 15,
  46. disabled: false,
  47. fields: [],
  48. rules: [],
  49. dataSource: []
  50. },
  51. deploymentId: '',
  52. description: '',
  53. suspend: 0
  54. },
  55. status: 0,
  56. startUserId: '',
  57. startTime: '',
  58. endTime: '',
  59. operations: {
  60. complete: false,
  61. refuse: false,
  62. back: false,
  63. transfer: false,
  64. delegate: false,
  65. addMulti: false,
  66. minusMulti: false
  67. }
  68. })
  69. const formData = ref<Recordable>({})
  70. const formKey = ref(0)
  71. const instanceLoading = ref(true)
  72. const activities = ref<FlowActivity[]>([])
  73. const timelineActivities = ref<FlowActivity[]>([])
  74. const activityKey = ref(0)
  75. const activitiesLoading = ref(true)
  76. const instance = ref<FlowInstance>()
  77. const onBack = () => {
  78. router.back()
  79. }
  80. const isCancel = () => {
  81. if (instance.value) {
  82. if (instance.value.status !== ProcessStatus.RUNNING) {
  83. return false
  84. }
  85. const { cancelDays, startTime } = instance.value
  86. if (cancelDays === 0) {
  87. return false
  88. }
  89. const start = new Date(startTime)
  90. start.setDate(start.getDate() + cancelDays)
  91. return start.getTime() > new Date().getTime()
  92. }
  93. return false
  94. }
  95. onMounted(() => {
  96. const { id } = route.value.query
  97. if (!id) {
  98. showFailToast('流程id不能为空')
  99. router.back()
  100. }
  101. getInstance(id as string).then((res) => {
  102. if (res.success) {
  103. instance.value = res.data
  104. }
  105. })
  106. getForm(id as string).then((res) => {
  107. if (res.success) {
  108. formInfo.value = res.data
  109. formKey.value = Date.now()
  110. instanceLoading.value = false
  111. }
  112. })
  113. // 获取流程活动
  114. activitiesLoading.value = true
  115. records(id as string).then((res) => {
  116. if (res.success) {
  117. activities.value = res.data
  118. timelineActivities.value = buildRecords(res.data)
  119. activityKey.value = Date.now()
  120. activitiesLoading.value = false
  121. }
  122. })
  123. })
  124. const handleAgain = () => {
  125. cachedViewStore.delCachedView('StartProcess')
  126. router.push({
  127. name: 'StartProcess',
  128. query: {
  129. id: formInfo.value.flowDefine.defineId,
  130. instanceId: formInfo.value.instanceId
  131. }
  132. })
  133. }
  134. const handleCancel = () => {
  135. showConfirmDialog({
  136. title: '提示',
  137. message: '您确认要撤回该流程吗?'
  138. }).then(() => {
  139. if (formInfo.value.instanceId) {
  140. cancel([formInfo.value.instanceId]).then((res) => {
  141. if (res.success) {
  142. showSuccessToast('撤回成功')
  143. router.back()
  144. }
  145. })
  146. }
  147. })
  148. }
  149. </script>
  150. <template>
  151. <van-nav-bar placeholder clickable fixed left-arrow title="流程详情" @click-left="onBack" />
  152. <van-cell-group inset mt-2>
  153. <van-cell>
  154. <template #title>
  155. <van-skeleton title :row="1" :loading="instanceLoading">
  156. {{ formInfo.formName }}
  157. <StatusTag :status="formInfo.status" />
  158. </van-skeleton>
  159. </template>
  160. <template #label>
  161. <van-skeleton title avatar :row="2" :loading="instanceLoading">
  162. <div flex-items-center gap2>
  163. <UserName :username="formInfo.startUserId" />
  164. 提交于 {{ formInfo.startTime }}
  165. </div>
  166. </van-skeleton>
  167. </template>
  168. </van-cell>
  169. </van-cell-group>
  170. <van-cell-group inset mt-2>
  171. <van-skeleton title :row="4" :loading="instanceLoading">
  172. <form-parser
  173. ref="formParserRef"
  174. :key="formKey"
  175. :form-data="formData"
  176. :form-conf="formInfo.flowDefine.form"
  177. />
  178. </van-skeleton>
  179. </van-cell-group>
  180. <van-cell-group inset mt-2 mb-15>
  181. <div class="flow-activity-timeline">
  182. <van-skeleton title :row="6" :loading="activitiesLoading">
  183. <ActivityTimeline :activities="timelineActivities"></ActivityTimeline>
  184. </van-skeleton>
  185. </div>
  186. </van-cell-group>
  187. <van-action-bar>
  188. <van-action-bar-icon icon="revoke" text="撤回" @click="handleCancel" v-show="isCancel()" />
  189. <van-action-bar-icon icon-class="i-ph-repeat" text="再次发起" @click="handleAgain" />
  190. </van-action-bar>
  191. </template>
  192. <style scoped lang="less">
  193. .flow-activity-timeline {
  194. padding: 20px 20px;
  195. }
  196. </style>