diff --git a/apps/web-antd/src/api/bpm/definition/index.ts b/apps/web-antd/src/api/bpm/definition/index.ts new file mode 100644 index 000000000..3a59b9875 --- /dev/null +++ b/apps/web-antd/src/api/bpm/definition/index.ts @@ -0,0 +1,49 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +/** 流程定义 */ +export namespace BpmProcessDefinitionApi { + export interface ProcessDefinitionVO { + id: string; + version: number; + deploymentTime: number; + suspensionState: number; + formType?: number; + bpmnXml?: string; + simpleModel?: string; + } +} + +/** 查询流程定义 */ +export async function getProcessDefinition(id?: string, key?: string) { + return requestClient.get( + '/bpm/process-definition/get', + { + params: { id, key }, + }, + ); +} + +/** 分页查询流程定义 */ +export async function getProcessDefinitionPage(params: PageParam) { + return requestClient.get< + PageResult + >('/bpm/process-definition/page', { params }); +} + +/** 查询流程定义列表 */ +export async function getProcessDefinitionList(params: any) { + return requestClient.get< + PageResult + >('/bpm/process-definition/list', { + params, + }); +} + +/** 查询流程定义列表(简单列表) */ +export async function getSimpleProcessDefinitionList() { + return requestClient.get< + PageResult + >('/bpm/process-definition/simple-list'); +} diff --git a/apps/web-antd/src/api/bpm/oa/leave/index.ts b/apps/web-antd/src/api/bpm/oa/leave/index.ts new file mode 100644 index 000000000..4172ffbd0 --- /dev/null +++ b/apps/web-antd/src/api/bpm/oa/leave/index.ts @@ -0,0 +1,40 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace BpmOALeaveApi { + export interface LeaveVO { + id: number; + status: number; + type: number; + reason: string; + processInstanceId: string; + startTime: number; + endTime: number; + createTime: Date; + startUserSelectAssignees?: Record; + } +} + +/** 创建请假申请 */ +export async function createLeave(data: BpmOALeaveApi.LeaveVO) { + return requestClient.post('/bpm/oa/leave/create', data); +} + +/** 更新请假申请 */ +export async function updateLeave(data: BpmOALeaveApi.LeaveVO) { + return requestClient.post('/bpm/oa/leave/update', data); +} + +/** 获得请假申请 */ +export async function getLeave(id: number) { + return requestClient.get(`/bpm/oa/leave/get?id=${id}`); +} + +/** 获得请假申请分页 */ +export async function getLeavePage(params: PageParam) { + return requestClient.get>( + '/bpm/oa/leave/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/bpm/processInstance/index.ts b/apps/web-antd/src/api/bpm/processInstance/index.ts index f287ee0be..23afa8c30 100644 --- a/apps/web-antd/src/api/bpm/processInstance/index.ts +++ b/apps/web-antd/src/api/bpm/processInstance/index.ts @@ -1,7 +1,7 @@ import type { PageParam, PageResult } from '@vben/request'; import type { BpmModelApi } from '#/api/bpm/model'; -import type { CandidateStrategyEnum, NodeTypeEnum } from '#/utils'; +import type { BpmCandidateStrategyEnum, BpmNodeTypeEnum } from '#/utils'; import { requestClient } from '#/api/request'; @@ -29,12 +29,12 @@ export namespace BpmProcessInstanceApi { // 审批节点信息 export type ApprovalNodeInfo = { - candidateStrategy?: CandidateStrategyEnum; + candidateStrategy?: BpmCandidateStrategyEnum; candidateUsers?: User[]; endTime?: Date; id: number; name: string; - nodeType: NodeTypeEnum; + nodeType: BpmNodeTypeEnum; startTime?: Date; status: number; tasks: ApprovalTaskInfo[]; diff --git a/apps/web-antd/src/api/bpm/task/index.ts b/apps/web-antd/src/api/bpm/task/index.ts new file mode 100644 index 000000000..4054b8f6a --- /dev/null +++ b/apps/web-antd/src/api/bpm/task/index.ts @@ -0,0 +1,108 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace BpmTaskApi { + /** BPM 流程监听器 VO */ + export interface TaskVO { + id: number; // 编号 + name: string; // 监听器名字 + type: string; // 监听器类型 + status: number; // 监听器状态 + event: string; // 监听事件 + valueType: string; // 监听器值类型 + value: string; // 监听器值 + } +} + +/** 查询待办任务分页 */ +export async function getTaskTodoPage(params: PageParam) { + return requestClient.get>( + '/bpm/task/todo-page', + { + params, + }, + ); +} + +/** 查询已办任务分页 */ +export async function getTaskDonePage(params: PageParam) { + return requestClient.get>( + '/bpm/task/done-page', + { + params, + }, + ); +} + +/** 查询任务管理分页 */ +export async function getTaskManagerPage(params: PageParam) { + return requestClient.get>( + '/bpm/task/manager-page', + { params }, + ); +} + +/** 审批任务 */ +export const approveTask = async (data: any) => { + return await requestClient.put('/bpm/task/approve', data); +}; + +/** 驳回任务 */ +export const rejectTask = async (data: any) => { + return await requestClient.put('/bpm/task/reject', data); +}; + +/** 根据流程实例 ID 查询任务列表 */ +export const getTaskListByProcessInstanceId = async (data: any) => { + return await requestClient.get('/bpm/task/list-by-process-instance-id', data); +}; + +/** 获取所有可退回的节点 */ +export const getTaskListByReturn = async (data: any) => { + return await requestClient.get('/bpm/task/list-by-return', data); +}; + +/** 退回 */ +export const returnTask = async (data: any) => { + return await requestClient.put('/bpm/task/return', data); +}; + +// 委派 +export const delegateTask = async (data: any) => { + return await requestClient.put('/bpm/task/delegate', data); +}; + +// 转派 +export const transferTask = async (data: any) => { + return await requestClient.put('/bpm/task/transfer', data); +}; + +// 加签 +export const signCreateTask = async (data: any) => { + return await requestClient.put('/bpm/task/create-sign', data); +}; + +// 减签 +export const signDeleteTask = async (data: any) => { + return await requestClient.delete('/bpm/task/delete-sign', data); +}; + +// 抄送 +export const copyTask = async (data: any) => { + return await requestClient.put('/bpm/task/copy', data); +}; + +// 获取我的待办任务 +export const myTodoTask = async (processInstanceId: string) => { + return await requestClient.get( + `/bpm/task/my-todo?processInstanceId=${processInstanceId}`, + ); +}; + +// 获取加签任务列表 +export const getChildrenTaskList = async (id: string) => { + return await requestClient.get( + `/bpm/task/list-by-parent-task-id?parentTaskId=${id}`, + ); +}; diff --git a/apps/web-antd/src/components/user-select-modal/user-select-modal.vue b/apps/web-antd/src/components/user-select-modal/user-select-modal.vue index 7437a8b28..6b03d3086 100644 --- a/apps/web-antd/src/components/user-select-modal/user-select-modal.vue +++ b/apps/web-antd/src/components/user-select-modal/user-select-modal.vue @@ -52,7 +52,8 @@ const props = withDefaults( const emit = defineEmits<{ cancel: []; - confirm: [value: number[]]; + closed: []; + confirm: [value: SystemUserApi.User[]]; 'update:value': [value: number[]]; }>(); @@ -167,9 +168,12 @@ const loadUserData = async (pageNo: number, pageSize: number) => { // 更新右侧列表数据 const updateRightListData = () => { - // 获取选中的用户 + // 使用 Set 来去重选中的用户ID + const uniqueSelectedIds = new Set(selectedUserIds.value); + + // 获取选中的用户,确保不重复 const selectedUsers = userList.value.filter((user) => - selectedUserIds.value.includes(String(user.id)), + uniqueSelectedIds.has(String(user.id)), ); // 应用搜索过滤 @@ -181,8 +185,10 @@ const updateRightListData = () => { ) : selectedUsers; - // 更新总数 - rightListState.value.pagination.total = filteredUsers.length; + // 更新总数(使用 Set 确保唯一性) + rightListState.value.pagination.total = new Set( + filteredUsers.map((user) => user.id), + ).size; // 应用分页 const { current, pageSize } = rightListState.value.pagination; @@ -219,8 +225,9 @@ const handleUserSearch = async (direction: string, value: string) => { // 处理用户选择变化 const handleUserChange = (targetKeys: string[]) => { - selectedUserIds.value = targetKeys; - emit('update:value', targetKeys.map(Number)); + // 使用 Set 来去重选中的用户ID + selectedUserIds.value = [...new Set(targetKeys)]; + emit('update:value', selectedUserIds.value.map(Number)); updateRightListData(); }; @@ -258,7 +265,7 @@ const resetData = () => { }; // 打开弹窗 -const open = async () => { +const open = async (userIds: string[]) => { resetData(); loading.value = true; try { @@ -273,15 +280,22 @@ const open = async () => { await loadUserData(1, leftListState.value.pagination.pageSize); // 设置已选用户 - if (props.value?.length) { - selectedUserIds.value = props.value.map(String); - // 加载已选用户的完整信息 + if (userIds?.length) { + selectedUserIds.value = userIds.map(String); + // 加载已选用户的完整信息 TODO 目前接口暂不支持 多个用户ID 查询, 需要后端支持 const { list } = await getUserPage({ pageNo: 1, - pageSize: props.value.length, - userIds: props.value, + pageSize: 100, // 临时使用固定值确保能加载所有已选用户 + userIds, }); - userList.value.push(...list); + // 使用 Map 来去重,以用户 ID 为 key + const userMap = new Map(userList.value.map((user) => [user.id, user])); + list.forEach((user) => { + if (!userMap.has(user.id)) { + userMap.set(user.id, user); + } + }); + userList.value = [...userMap.values()]; updateRightListData(); } @@ -344,7 +358,12 @@ const handleConfirm = () => { message.warning('请选择用户'); return; } - emit('confirm', selectedUserIds.value.map(Number)); + emit( + 'confirm', + userList.value.filter((user) => + selectedUserIds.value.includes(String(user.id)), + ), + ); modalApi.close(); }; @@ -360,6 +379,7 @@ const handleCancel = () => { // 关闭弹窗 const handleClosed = () => { + emit('closed'); resetData(); }; @@ -421,7 +441,7 @@ defineExpose({ @search="handleUserSearch" >