From 4f7819afd69311546999d290907fed791e3dcb07 Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Fri, 30 Oct 2026 21:03:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(approval):=20PC=20=E5=BE=85=E5=8A=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E9=A1=B5=E9=9D=A2=E4=B8=8E=E6=94=B9=E6=B4=BE?= =?UTF-8?q?=20(#22)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 views/approval/todo:ele-pro-table 待办列表(单号/单据类型/标题/发起人/ 报送部门/状态/提交时间/当前节点,状态与关键词筛选) - 详情抽屉:只读字段、附件、处理记录时间线、当前节点;通过/驳回/存档/归档/ 改派动作按 permissions 与 v-permission 显隐,驳回意见必填,改派需选人并填原因 - 新增 api/approval/{model,instance,task},统一走 THINK_API_URL --- src/api/approval/instance/index.ts | 37 ++ src/api/approval/model/index.ts | 188 ++++++ src/api/approval/task/index.ts | 95 +++ .../todo/components/detail-drawer.vue | 559 ++++++++++++++++++ src/views/approval/todo/format.ts | 46 ++ src/views/approval/todo/index.vue | 215 +++++++ 6 files changed, 1140 insertions(+) create mode 100644 src/api/approval/instance/index.ts create mode 100644 src/api/approval/model/index.ts create mode 100644 src/api/approval/task/index.ts create mode 100644 src/views/approval/todo/components/detail-drawer.vue create mode 100644 src/views/approval/todo/format.ts create mode 100644 src/views/approval/todo/index.vue diff --git a/src/api/approval/instance/index.ts b/src/api/approval/instance/index.ts new file mode 100644 index 0000000..53cad4c --- /dev/null +++ b/src/api/approval/instance/index.ts @@ -0,0 +1,37 @@ +import request from '@/utils/request'; +import type { ApiResult, PageResult } from '@/api'; +import { THINK_API_URL } from '@/config/setting'; +import type { + ApprovalInstance, + ApprovalItem, + ApprovalItemParam +} from '../model'; + +/** + * 我的待办分页 + */ +export async function pageApprovalTodo(params: ApprovalItemParam) { + const res = await request.get>>( + THINK_API_URL + '/approval/todo/page', + { + params + } + ); + if (res.data.code === 0 && res.data.data) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 审批单据详情 + */ +export async function getApprovalInstance(id: number) { + const res = await request.get>( + THINK_API_URL + '/approval/instance/' + id + ); + if (res.data.code === 0 && res.data.data) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} diff --git a/src/api/approval/model/index.ts b/src/api/approval/model/index.ts new file mode 100644 index 0000000..06ee4c3 --- /dev/null +++ b/src/api/approval/model/index.ts @@ -0,0 +1,188 @@ +import type { PageParam } from '@/api'; + +/** + * 审批单据列表项 + */ +export interface ApprovalItem { + id?: number; + // 单号 + bizNo?: string; + // 单据类型:completion / coordination + docType?: string; + // 单据类型名称 + docTypeName?: string; + // 状态 + status?: string; + // 状态名称 + statusName?: string; + // 标题或名称 + title?: string; + // 提交时间 + submitTime?: string; + // 当前节点名称 + currentNodeName?: string; + // 发起人 + reporterId?: number; + reporterName?: string; + // 报送部门 + reportOrgName?: string; + // 受理部门 + acceptOrgName?: string; + // 归档时间 + archiveTime?: string; +} + +/** + * 待办/已办查询条件 + */ +export interface ApprovalItemParam extends PageParam { + status?: string; + docType?: string; + keywords?: string; +} + +/** + * 审批附件 + */ +export interface ApprovalAttachment { + id?: number; + fileId?: number; + name?: string; + url?: string; + length?: number; + category?: string; + categoryName?: string; + uploaderId?: number; + uploaderName?: string; + createTime?: string; +} + +/** + * 处理记录 + */ +export interface ApprovalRecord { + id?: number; + taskId?: number; + nodeKey?: string; + nodeName?: string; + operatorId?: number; + operatorName?: string; + action?: string; + actionName?: string; + opinion?: string; + round?: number; + createTime?: string; +} + +/** + * 当前轮存档确认人 + */ +export interface ApprovalConfirm { + userId?: number; + userName?: string; + status?: string; + statusName?: string; + handleTime?: string; +} + +/** + * 当前用户的待办任务 + */ +export interface ApprovalMyTask { + id?: number; + nodeKey?: string; + nodeType?: string; + status?: string; +} + +/** + * 详情动作权限 + */ +export interface ApprovalPermissions { + canEdit?: boolean; + canSubmit?: boolean; + canWithdraw?: boolean; + canApprove?: boolean; + canReject?: boolean; + canConfirm?: boolean; + canArchive?: boolean; + canDispatch?: boolean; + canAssign?: boolean; +} + +/** + * 审批单据详情 + */ +export interface ApprovalInstance { + id?: number; + bizNo?: string; + docType?: string; + docTypeName?: string; + flowCode?: string; + status?: string; + statusName?: string; + round?: number; + reporterId?: number; + reporterName?: string; + reportOrgId?: number; + reportOrgName?: string; + acceptOrgId?: number; + acceptOrgName?: string; + currentNodeKey?: string; + currentNodeType?: string; + currentNodeName?: string; + submitTime?: string; + approveTime?: string; + archiveTime?: string; + archivistId?: number; + archivistName?: string; + // 业务完成确认单字段 + name?: string; + implementOrg?: string; + fee?: number; + serviceContent?: string; + // 内部协调单字段 + title?: string; + content?: string; + remark?: string; + dispatchTargetId?: number; + dispatchTargetName?: string; + attachments?: ApprovalAttachment[]; + records?: ApprovalRecord[]; + confirms?: ApprovalConfirm[]; + myTask?: ApprovalMyTask | null; + permissions?: ApprovalPermissions; +} + +/** + * 改派候选用户 + */ +export interface ApprovalUser { + userId?: number; + username?: string; + nickname?: string; + realName?: string; + organizationId?: number; + organizationName?: string; +} + +/** + * 改派参数 + */ +export interface ApprovalAssignParam { + targetUserId: number; + reason: string; +} + +/** + * 改派结果 + */ +export interface ApprovalAssignResult { + instanceId?: number; + taskId?: number; + originalAssigneeId?: number; + originalAssigneeName?: string; + assigneeId?: number; + assigneeName?: string; + reason?: string; +} diff --git a/src/api/approval/task/index.ts b/src/api/approval/task/index.ts new file mode 100644 index 0000000..2a6b4d3 --- /dev/null +++ b/src/api/approval/task/index.ts @@ -0,0 +1,95 @@ +import request from '@/utils/request'; +import type { ApiResult } from '@/api'; +import { THINK_API_URL } from '@/config/setting'; +import type { + ApprovalAssignParam, + ApprovalAssignResult, + ApprovalUser +} from '../model'; + +/** + * 通过任务 + */ +export async function approveApprovalTask(id: number, opinion?: string) { + const res = await request.post>( + THINK_API_URL + '/approval/task/' + id + '/approve', + { opinion } + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 驳回任务(意见必填) + */ +export async function rejectApprovalTask(id: number, opinion: string) { + const res = await request.post>( + THINK_API_URL + '/approval/task/' + id + '/reject', + { opinion } + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 存档确认 + */ +export async function confirmApprovalTask(id: number) { + const res = await request.post>( + THINK_API_URL + '/approval/task/' + id + '/confirm' + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 归档 + */ +export async function archiveApprovalTask(id: number) { + const res = await request.post>( + THINK_API_URL + '/approval/task/' + id + '/archive' + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 改派待办 + */ +export async function assignApprovalTask( + id: number, + data: ApprovalAssignParam +) { + const res = await request.post>( + THINK_API_URL + '/approval/task/' + id + '/assign', + data + ); + if (res.data.code === 0) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 改派候选用户:同租户启用用户,最多 50 条 + */ +export async function searchApprovalUsers(keywords?: string) { + const res = await request.get>( + THINK_API_URL + '/approval/directory/users', + { + params: { keywords } + } + ); + if (res.data.code === 0 && res.data.data) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} diff --git a/src/views/approval/todo/components/detail-drawer.vue b/src/views/approval/todo/components/detail-drawer.vue new file mode 100644 index 0000000..b095ee7 --- /dev/null +++ b/src/views/approval/todo/components/detail-drawer.vue @@ -0,0 +1,559 @@ + + + + + + + + diff --git a/src/views/approval/todo/format.ts b/src/views/approval/todo/format.ts new file mode 100644 index 0000000..f1e8936 --- /dev/null +++ b/src/views/approval/todo/format.ts @@ -0,0 +1,46 @@ +import { toDateString } from 'ele-admin-pro'; + +/** + * 审批时间统一展示:兼容 ISO 字符串与时间戳 + */ +export function formatApprovalTime(value?: string | number | null): string { + if (value === undefined || value === null || value === '') { + return ''; + } + if (typeof value === 'number') { + return toDateString(value, 'yyyy-MM-dd HH:mm:ss'); + } + return String(value).replace('T', ' ').slice(0, 19); +} + +/** + * 附件大小展示 + */ +export function formatFileSize(length?: number): string { + if (!length || length <= 0) { + return '0 KB'; + } + if (length < 1024 * 1024) { + return (length / 1024).toFixed(1) + ' KB'; + } + return (length / 1024 / 1024).toFixed(1) + ' MB'; +} + +/** + * 单据状态标签颜色 + */ +export function approvalStatusColor(status?: string): string { + if (status === 'PENDING' || status === 'DRAFT') { + return 'blue'; + } + if (status === 'REJECTED') { + return 'red'; + } + if (status === 'WITHDRAWN') { + return 'orange'; + } + if (status === 'APPROVED') { + return 'green'; + } + return 'default'; +} diff --git a/src/views/approval/todo/index.vue b/src/views/approval/todo/index.vue new file mode 100644 index 0000000..947be00 --- /dev/null +++ b/src/views/approval/todo/index.vue @@ -0,0 +1,215 @@ + + + + + + + +