- 引入 ApprovalType 类型替代内联联合类型,提升代码可维护性 - 使用 computed 计算属性 showFooter 控制底部操作栏显隐逻辑 - 移除原先通过 drawerApi 动态设置 footer 的方式,改用条件渲染 - 修复 footer 插槽在只读模式下仍渲染内容的问题 - 添加 TODO 注释说明当前 footer 插槽存在的设计问题
170 lines
4.9 KiB
Vue
170 lines
4.9 KiB
Vue
<script setup lang="ts">
|
|
import type { ApprovalType } from './type';
|
|
|
|
import type { FlowInfoResponse } from '#/api/workflow/instance/model';
|
|
import type { TaskInfo } from '#/api/workflow/task/model';
|
|
|
|
import { computed, ref } from 'vue';
|
|
|
|
import { useVbenDrawer, VbenAvatar } from '@vben/common-ui';
|
|
import { DictEnum } from '@vben/constants';
|
|
import { cloneDeep, cn } from '@vben/utils';
|
|
|
|
import { Divider, Skeleton, TabPane, Tabs } from 'ant-design-vue';
|
|
|
|
import { flowInfo } from '#/api/workflow/instance';
|
|
import { getTaskByTaskId } from '#/api/workflow/task';
|
|
import { renderDict } from '#/utils/render';
|
|
|
|
import { FlowActions } from './actions';
|
|
import ApprovalDetails from './approval-details.vue';
|
|
import FlowPreview from './flow-preview.vue';
|
|
|
|
const emit = defineEmits<{ reload: [] }>();
|
|
|
|
interface DrawerProps {
|
|
task: TaskInfo;
|
|
type: ApprovalType;
|
|
}
|
|
|
|
const currentTask = ref<null | TaskInfo>(null);
|
|
const currentFlowInfo = ref<FlowInfoResponse | null>(null);
|
|
const currentType = ref<DrawerProps['type'] | null>(null);
|
|
|
|
const [BasicDrawer, drawerApi] = useVbenDrawer({
|
|
title: '流程',
|
|
onOpenChange: async (isOpen) => {
|
|
if (!isOpen) {
|
|
return null;
|
|
}
|
|
try {
|
|
loading.value = true;
|
|
|
|
const { task, type } = drawerApi.getData() as DrawerProps;
|
|
const { businessId, id: taskId } = task;
|
|
|
|
const flowResp = await flowInfo(businessId);
|
|
currentFlowInfo.value = flowResp;
|
|
|
|
/**
|
|
* 审批需要查询按钮权限 通过drawer传递的task是空的
|
|
* TODO: promise.all
|
|
*/
|
|
if (type === 'approve') {
|
|
const taskResp = await getTaskByTaskId(taskId);
|
|
const cloneTask = cloneDeep(task);
|
|
// 赋值 按钮权限
|
|
cloneTask.buttonList = taskResp.buttonList;
|
|
currentTask.value = cloneTask;
|
|
} else {
|
|
// default逻辑
|
|
currentTask.value = task;
|
|
}
|
|
// 最后赋值type
|
|
currentType.value = type;
|
|
// // 设置是否显示footer
|
|
// drawerApi.setState({
|
|
// footer: type !== 'readonly',
|
|
// });
|
|
} catch (error) {
|
|
console.error(error);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
},
|
|
onClosed() {
|
|
currentTask.value = null;
|
|
currentType.value = null;
|
|
currentFlowInfo.value = null;
|
|
},
|
|
});
|
|
|
|
const loading = ref(false);
|
|
|
|
/**
|
|
* 底部按钮操作后
|
|
*/
|
|
async function handleAfterAction() {
|
|
emit('reload');
|
|
drawerApi.close();
|
|
}
|
|
|
|
const showFooter = computed(() => {
|
|
return ![null, 'readonly'].includes(currentType.value);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<BasicDrawer class="w-[900px]" content-class="flex w-full">
|
|
<div :class="cn('flex-1 text-[#323639E0]')">
|
|
<Skeleton active :loading="loading">
|
|
<div v-if="currentTask" class="flex flex-col gap-5 p-4">
|
|
<div class="flex flex-col gap-3">
|
|
<div class="flex items-center gap-2">
|
|
<div class="text-2xl font-bold">
|
|
{{ currentTask.businessTitle ?? currentTask.flowName }}
|
|
</div>
|
|
<div>
|
|
<component
|
|
:is="
|
|
renderDict(
|
|
currentTask.flowStatus,
|
|
DictEnum.WF_BUSINESS_STATUS,
|
|
)
|
|
"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2 text-sm">
|
|
<VbenAvatar
|
|
:alt="currentTask.createByName ?? ''"
|
|
class="bg-primary size-[28px] rounded-full text-white"
|
|
src=""
|
|
/>
|
|
<span>{{ currentTask.createByName }}</span>
|
|
|
|
<div class="flex items-center opacity-50">
|
|
<div class="flex items-center gap-1">
|
|
<span class="icon-[bxs--category-alt] size-[16px]"></span>
|
|
流程分类: {{ currentTask.categoryName }}
|
|
</div>
|
|
|
|
<Divider type="vertical" />
|
|
|
|
<div class="flex items-center gap-1">
|
|
<span class="icon-[mdi--clock-outline] size-[16px]"></span>
|
|
提交时间: {{ currentTask.createTime }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<Tabs v-if="currentFlowInfo" class="flex-1">
|
|
<TabPane key="1" tab="审批详情">
|
|
<ApprovalDetails
|
|
:current-flow-info="currentFlowInfo"
|
|
:task="currentTask"
|
|
/>
|
|
</TabPane>
|
|
|
|
<TabPane key="2" tab="审批流程图">
|
|
<FlowPreview :instance-id="currentFlowInfo.instanceId" />
|
|
</TabPane>
|
|
</Tabs>
|
|
</div>
|
|
</Skeleton>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<!-- TODO: 暂时只能这样处理 footer常驻但不显示内容 这个插槽有点迷 -->
|
|
<FlowActions
|
|
v-if="showFooter && currentTask && currentType"
|
|
:task="currentTask"
|
|
:type="currentType"
|
|
@reload="handleAfterAction"
|
|
/>
|
|
<div v-else></div>
|
|
</template>
|
|
</BasicDrawer>
|
|
</template>
|