Ei kuvausta

approval-panel.vue 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <!--
  2. TODO: 优化项
  3. 会先加载流程信息 再加载业务表单信息
  4. -->
  5. <script setup lang="ts">
  6. import type { ApprovalType } from './type';
  7. import type { FlowInfoResponse } from '#/api/workflow/instance/model';
  8. import type { TaskInfo } from '#/api/workflow/task/model';
  9. import { computed, ref, watch } from 'vue';
  10. import { Fallback, VbenAvatar } from '@vben/common-ui';
  11. import { DictEnum } from '@vben/constants';
  12. import { cn } from '@vben/utils';
  13. // import { Copy } from '@element-plus/icons-vue';
  14. import { CopyDocument } from '@element-plus/icons-vue';
  15. import { useClipboard } from '@vueuse/core';
  16. import { ElCard, ElMessage, ElTabPane, ElTabs } from 'element-plus';
  17. import { renderDict } from '#/utils/render';
  18. import { FlowActions } from './actions';
  19. import ApprovalDetails from './approval-details.vue';
  20. defineOptions({
  21. name: 'ApprovalPanel',
  22. inheritAttrs: false,
  23. });
  24. const props = defineProps<Props>();
  25. /**
  26. * 下面按钮点击后会触发的事件
  27. */
  28. defineEmits<{ reload: [] }>();
  29. interface Props {
  30. /**
  31. * 行数据(list)的info
  32. */
  33. task?: TaskInfo;
  34. /**
  35. * 工单详情
  36. */
  37. workOrderDetail?: any;
  38. /**
  39. * 审批类型
  40. */
  41. type: ApprovalType;
  42. /**
  43. * 按钮权限(可选,外部传入覆盖内部计算)
  44. */
  45. buttonPermissions?: Record<string, boolean>;
  46. }
  47. /**
  48. * 目前的作用只为了获取按钮权限 因为list接口(行数据)获取为空
  49. */
  50. const onlyForBtnPermissionTask = ref<TaskInfo>();
  51. /**
  52. * 按钮权限
  53. */
  54. const buttonPermissions = computed(() => {
  55. // 如果外部传入了buttonPermissions,优先使用
  56. if (props.buttonPermissions) {
  57. return props.buttonPermissions;
  58. }
  59. const record: Record<string, boolean> = {};
  60. if (!onlyForBtnPermissionTask.value) {
  61. return record;
  62. }
  63. onlyForBtnPermissionTask.value.buttonList.forEach((item) => {
  64. record[item.code] = item.show;
  65. });
  66. return record;
  67. });
  68. const showFooter = computed(() => {
  69. if (props.type === 'readonly') {
  70. return false;
  71. }
  72. // 我发起的 && [已完成, 已作废] 不显示
  73. if (
  74. props.type === 'myself' &&
  75. ['finish', 'invalid'].includes(props.task?.flowStatus ?? '')
  76. ) {
  77. return false;
  78. }
  79. return true;
  80. });
  81. const currentFlowInfo = ref<FlowInfoResponse>();
  82. /**
  83. * card的loading状态
  84. */
  85. const loading = ref(false);
  86. async function handleLoadInfo(task: TaskInfo | undefined) {
  87. if (!task) {
  88. return null;
  89. }
  90. try {
  91. loading.value = true;
  92. /**
  93. * 不为审批不需要调用`getTaskByTaskId`接口
  94. */
  95. // if (props.type !== 'approve') {
  96. // const flowResp = await flowInfo(task.businessId);
  97. // currentFlowInfo.value = flowResp;
  98. // return;
  99. // }
  100. /**
  101. * getTaskByTaskId主要为了获取按钮权限 目前没有其他功能
  102. * 行数据(即props.task)获取的是没有按钮权限的
  103. */
  104. // const [flowResp, taskResp] = await Promise.all([
  105. // flowInfo(task.businessId),
  106. // getTaskByTaskId(task.id),
  107. // ]);
  108. // currentFlowInfo.value = flowResp;
  109. // onlyForBtnPermissionTask.value = taskResp;
  110. } catch (error) {
  111. console.error(error);
  112. } finally {
  113. loading.value = false;
  114. }
  115. }
  116. watch(() => props.task, handleLoadInfo);
  117. /**
  118. * 不加legacy在本地开发没有问题
  119. * 打包后在一些设备会无法复制 使用legacy来保证兼容性
  120. */
  121. const { copy } = useClipboard({ legacy: true });
  122. async function handleCopy(text: string) {
  123. await copy(text);
  124. ElMessage.success('复制成功');
  125. }
  126. </script>
  127. <template>
  128. <div :class="cn('thin-scrollbar', 'flex flex-1 overflow-y-hidden')">
  129. <ElCard
  130. v-if="workOrderDetail"
  131. :body-style="{ overflowY: 'auto', height: '100%' }"
  132. :loading="loading"
  133. class="thin-scrollbar flex-1 overflow-y-hidden"
  134. size="small"
  135. >
  136. <template #extra>
  137. <el-button size="small" @click="() => handleLoadInfo(workOrderDetail)">
  138. <div class="flex items-center justify-center">
  139. <span class="icon-[material-symbols--refresh] size-24px"></span>
  140. </div>
  141. </el-button>
  142. </template>
  143. <div class="flex flex-col gap-5 p-4">
  144. <div class="flex flex-col gap-3">
  145. <div class="flex items-center gap-2">
  146. <div class="text-2xl font-bold">
  147. {{ workOrderDetail.orderNo }}
  148. </div>
  149. <el-icon @click="() => handleCopy(workOrderDetail.orderNo)">
  150. <CopyDocument />
  151. </el-icon>
  152. <div>
  153. <component
  154. :is="renderDict(workOrderDetail.status, DictEnum.TICKET_STATUS)"
  155. />
  156. </div>
  157. </div>
  158. <div class="flex items-center gap-2">
  159. <VbenAvatar
  160. :alt="workOrderDetail?.createBy ?? ''"
  161. class="bg-primary size-[28px] rounded-full text-white"
  162. src=""
  163. />
  164. <span>{{ workOrderDetail.createBy }}</span>
  165. <div class="flex items-center opacity-50">
  166. <div class="flex items-center gap-1">
  167. <span class="icon-[bxs--category-alt] size-[16px]"></span>
  168. 流程分类: {{ workOrderDetail.ticketTypeName }}
  169. </div>
  170. <div class="flex items-center gap-1">
  171. <span class="icon-[mdi--clock-outline] size-[16px]"></span>
  172. 提交时间: {{ workOrderDetail.createTime }}
  173. </div>
  174. </div>
  175. </div>
  176. </div>
  177. <ElTabs class="flex-1">
  178. <ElTabPane key="1" label="工单详情">
  179. <ApprovalDetails
  180. :current-flow-info="currentFlowInfo"
  181. :work-order-detail="workOrderDetail"
  182. />
  183. </ElTabPane>
  184. <!-- <ElTabPane key="2" label="审批流程图">
  185. <FlowPreview :instance-id="currentFlowInfo.instanceId" />
  186. </ElTabPane> -->
  187. </ElTabs>
  188. </div>
  189. <!-- 固定底部 占位高度 -->
  190. <div class="h-[58px]"></div>
  191. <FlowActions
  192. v-if="showFooter"
  193. :type="type"
  194. :task="task"
  195. :work-order-detail="workOrderDetail"
  196. :button-permissions="buttonPermissions"
  197. @reload="$emit('reload')"
  198. />
  199. </ElCard>
  200. <slot v-else name="empty">
  201. <Fallback title="点击左侧选择" />
  202. </slot>
  203. </div>
  204. </template>