chore: 我的已办

This commit is contained in:
dap 2024-12-20 10:02:31 +08:00
parent fc43527cf1
commit 4db697e714
2 changed files with 187 additions and 26 deletions

View File

@ -6,7 +6,6 @@ import type { TaskInfo } from '#/api/workflow/task/model';
import { computed, onMounted, ref, useTemplateRef } from 'vue';
import { Page } from '@vben/common-ui';
import { useTabs } from '@vben/hooks';
import { addFullName, getPopupContainer } from '@vben/utils';
import { FilterOutlined, RedoOutlined } from '@ant-design/icons-vue';
@ -134,8 +133,6 @@ async function handleCardClick(item: TaskInfo) {
lastSelectId.value = id;
}
const { refreshTab } = useTabs();
// 使v-model
const popoverOpen = ref(false);
const selectedUserList = ref<User[]>([]);
@ -283,7 +280,7 @@ onMounted(async () => {
</div>
</div>
</div>
<ApprovalPanel :task="currentTask" type="readonly" @reload="refreshTab" />
<ApprovalPanel :task="currentTask" type="readonly" />
</div>
</Page>
</template>

View File

@ -1,24 +1,47 @@
<!-- eslint-disable no-use-before-define -->
<script setup lang="ts">
import type { FlowInfoResponse } from '#/api/workflow/instance/model';
import type { User } from '#/api/system/user/model';
import type { TaskInfo } from '#/api/workflow/task/model';
import { computed, onMounted, ref } from 'vue';
import { computed, onMounted, ref, useTemplateRef } from 'vue';
import { Page } from '@vben/common-ui';
import { addFullName, getPopupContainer } from '@vben/utils';
import { Empty, InputSearch } from 'ant-design-vue';
import { debounce } from 'lodash-es';
import { FilterOutlined, RedoOutlined } from '@ant-design/icons-vue';
import {
Empty,
Form,
FormItem,
Input,
InputSearch,
Popover,
Spin,
Tooltip,
TreeSelect,
} from 'ant-design-vue';
import { cloneDeep, debounce } from 'lodash-es';
import { flowInfo } from '#/api/workflow/instance';
import { categoryTree } from '#/api/workflow/category';
import { pageByTaskFinish } from '#/api/workflow/task';
import { ApprovalCard, ApprovalPanel } from '../components';
import { ApprovalCard, ApprovalPanel, CopyComponent } from '../components';
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
const taskList = ref<({ active: boolean } & TaskInfo)[]>([]);
const taskTotal = ref(0);
const page = ref(1);
const loading = ref(false);
const defaultFormData = {
flowName: '', //
nodeName: '', //
flowCode: '', //
createByIds: [] as string[], //
category: null as null | number, //
};
const formData = ref(cloneDeep(defaultFormData));
/**
* 是否已经加载全部数据 taskList.length === taskTotal
@ -27,15 +50,45 @@ const isLoadComplete = computed(
() => taskList.value.length === taskTotal.value,
);
onMounted(async () => {
/**
* 获取待办任务列表
*/
const resp = await pageByTaskFinish({ pageSize: 10, pageNum: page.value });
console.log(resp);
// ref
const cardContainerRef = useTemplateRef('cardContainerRef');
/**
* @param resetFields 是否清空查询参数
*/
async function reload(resetFields: boolean = false) {
//
cardContainerRef.value?.scroll({ top: 0, behavior: 'auto' });
page.value = 1;
currentTask.value = undefined;
taskTotal.value = 0;
lastSelectId.value = '';
if (resetFields) {
formData.value = cloneDeep(defaultFormData);
selectedUserList.value = [];
}
loading.value = true;
const resp = await pageByTaskFinish({
pageSize: 10,
pageNum: page.value,
...formData.value,
});
taskList.value = resp.rows.map((item) => ({ ...item, active: false }));
taskTotal.value = resp.total;
});
loading.value = false;
//
if (taskList.value.length > 0) {
const firstTask = taskList.value[0]!;
currentTask.value = firstTask;
handleCardClick(firstTask);
}
}
onMounted(reload);
const handleScroll = debounce(async (e: Event) => {
if (!e.target) {
@ -50,20 +103,24 @@ const handleScroll = debounce(async (e: Event) => {
//
if (isBottom && !isLoadComplete.value) {
loading.value = true;
page.value += 1;
const resp = await pageByTaskFinish({ pageSize: 10, pageNum: page.value });
const resp = await pageByTaskFinish({
pageSize: 10,
pageNum: page.value,
...formData.value,
});
taskList.value.push(
...resp.rows.map((item) => ({ ...item, active: false })),
);
loading.value = false;
}
}, 200);
const currentInstance = ref<FlowInfoResponse>();
const lastSelectId = ref('');
const currentTask = ref<TaskInfo>();
async function handleCardClick(item: TaskInfo) {
const { id, businessId } = item;
const { id } = item;
//
if (lastSelectId.value === id) {
return;
@ -74,25 +131,119 @@ async function handleCardClick(item: TaskInfo) {
item.active = item.id === id;
});
lastSelectId.value = id;
const resp = await flowInfo(businessId);
currentInstance.value = resp;
}
// 使v-model
const popoverOpen = ref(false);
const selectedUserList = ref<User[]>([]);
function handleFinish(userList: User[]) {
popoverOpen.value = true;
selectedUserList.value = userList;
formData.value.createByIds = userList.map((item) => item.userId);
}
const treeData = ref<any[]>([]);
onMounted(async () => {
// menu
const tree = await categoryTree();
addFullName(tree, 'label', ' / ');
treeData.value = tree;
});
</script>
<template>
<Page :auto-content-height="true">
<div class="flex h-full gap-2">
<div
class="bg-background flex h-full min-w-[320px] max-w-[320px] flex-col rounded-lg"
class="bg-background relative flex h-full min-w-[320px] max-w-[320px] flex-col rounded-lg"
>
<!-- 搜索条件 -->
<div
class="bg-background z-100 sticky left-0 top-0 w-full rounded-t-lg border-b-[1px] border-solid p-2"
>
<InputSearch placeholder="搜索还没做" />
<div class="flex items-center gap-1">
<InputSearch
v-model:value="formData.flowName"
placeholder="流程名称搜索"
@search="reload(false)"
/>
<Tooltip placement="top" title="重置">
<a-button @click="reload(true)">
<RedoOutlined />
</a-button>
</Tooltip>
<Popover
v-model:open="popoverOpen"
:get-popup-container="getPopupContainer"
placement="rightTop"
trigger="click"
>
<template #title>
<div class="w-full border-b pb-[12px] text-[16px]">搜索</div>
</template>
<template #content>
<Form
:colon="false"
:label-col="{ span: 6 }"
:model="formData"
autocomplete="off"
class="w-[300px]"
@finish="() => reload(false)"
>
<FormItem label="申请人">
<!-- 弹窗关闭后仍然显示表单浮层 -->
<CopyComponent
v-model:user-list="selectedUserList"
@cancel="() => (popoverOpen = true)"
@finish="handleFinish"
/>
</FormItem>
<FormItem label="流程分类">
<TreeSelect
v-model:value="formData.category"
:allow-clear="true"
:field-names="{ label: 'label', value: 'id' }"
:get-popup-container="getPopupContainer"
:tree-data="treeData"
:tree-default-expand-all="true"
:tree-line="{ showLeafIcon: false }"
placeholder="请选择"
tree-node-filter-prop="label"
tree-node-label-prop="fullName"
/>
</FormItem>
<FormItem label="任务名称">
<Input
v-model:value="formData.nodeName"
placeholder="请输入"
/>
</FormItem>
<FormItem label="流程编码">
<Input
v-model:value="formData.flowCode"
placeholder="请输入"
/>
</FormItem>
<FormItem>
<div class="flex">
<a-button block html-type="submit" type="primary">
搜索
</a-button>
<a-button block class="ml-2" @click="reload(true)">
重置
</a-button>
</div>
</FormItem>
</Form>
</template>
<a-button>
<FilterOutlined />
</a-button>
</Popover>
</div>
</div>
<div
ref="cardContainerRef"
class="thin-scrollbar flex flex-1 flex-col gap-2 overflow-y-auto py-3"
@scroll="handleScroll"
>
@ -106,6 +257,19 @@ async function handleCardClick(item: TaskInfo) {
/>
</template>
<Empty v-else :image="emptyImage" />
<div
v-if="isLoadComplete && taskList.length > 0"
class="flex items-center justify-center text-[14px] opacity-50"
>
没有更多数据了
</div>
<!-- 遮罩loading层 -->
<div
v-if="loading"
class="absolute left-0 top-0 flex h-full w-full items-center justify-center bg-[rgba(0,0,0,0.1)]"
>
<Spin tip="加载中..." />
</div>
</div>
<!-- total显示 -->
<div