From 634e1c12af39f2d552bc977d51f3bdaa82275944 Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Fri, 30 Oct 2026 19:59:48 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E8=A7=92=E8=89=B2=E9=A1=B5?= =?UTF-8?q?=E6=88=90=E5=91=98=E7=BB=B4=E6=8A=A4=E5=BC=B9=E7=AA=97=E4=B8=8E?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=A7=92=E8=89=B2=E6=B8=85=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 角色页新增「成员」动作,弹窗展示姓名/账号/所属组织/状态,支持搜索添加启用用户与移除 - api/system/role 增加 pageRoleMembers/addRoleMember/removeRoleMember,走 THINK_API_URL - api/system/user 的 updateUser 改走 THINK_API_URL,空角色由后端清空 - 用户编辑表单允许角色为空,保存后可删除该用户全部角色关联 --- src/api/system/role/index.ts | 46 +++- src/api/system/role/model/index.ts | 28 +++ src/api/system/user/index.ts | 4 +- .../system/role/components/role-member.vue | 230 ++++++++++++++++++ src/views/system/role/index.vue | 16 +- .../system/user/components/user-edit.vue | 10 +- 6 files changed, 321 insertions(+), 13 deletions(-) create mode 100644 src/views/system/role/components/role-member.vue diff --git a/src/api/system/role/index.ts b/src/api/system/role/index.ts index 352e352..1dcb9c1 100644 --- a/src/api/system/role/index.ts +++ b/src/api/system/role/index.ts @@ -1,8 +1,8 @@ import request from '@/utils/request'; import type { ApiResult, PageResult } from '@/api'; -import type { Role, RoleParam } from './model'; +import type { Role, RoleMember, RoleMemberParam, RoleParam } from './model'; import type { Menu } from '../menu/model'; -import { SERVER_API_URL } from '@/config/setting'; +import { SERVER_API_URL, THINK_API_URL } from '@/config/setting'; /** * 分页查询角色 @@ -117,3 +117,45 @@ export async function updateRoleMenus(roleId?: number, data?: number[]) { } return Promise.reject(new Error(res.data.message)); } + +/** + * 分页查询角色成员 + */ +export async function pageRoleMembers(params: RoleMemberParam) { + const res = await request.get>>( + THINK_API_URL + '/system/role-member/page', + { params } + ); + if (res.data.code === 0) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 添加角色成员 + */ +export async function addRoleMember(data: RoleMemberParam) { + const res = await request.post>( + THINK_API_URL + '/system/role-member', + data + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 移除角色成员 + */ +export async function removeRoleMember(roleId?: number, userId?: number) { + const res = await request.delete>( + THINK_API_URL + '/system/role-member', + { params: { roleId, userId } } + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} diff --git a/src/api/system/role/model/index.ts b/src/api/system/role/model/index.ts index d4c9a50..4a02264 100644 --- a/src/api/system/role/model/index.ts +++ b/src/api/system/role/model/index.ts @@ -25,3 +25,31 @@ export interface RoleParam extends PageParam { roleCode?: string; comments?: string; } + +/** + * 角色成员 + */ +export interface RoleMember { + // 用户id + userId?: number; + // 账号 + username?: string; + // 真实姓名 + realName?: string; + // 昵称 + nickname?: string; + // 所属组织id + organizationId?: number; + // 所属组织名称 + organizationName?: string; + // 状态, 0启用, 1停用 + status?: number; +} + +/** + * 角色成员查询/操作参数 + */ +export interface RoleMemberParam extends PageParam { + roleId?: number; + userId?: number; +} diff --git a/src/api/system/user/index.ts b/src/api/system/user/index.ts index 2ac2612..f0b4411 100644 --- a/src/api/system/user/index.ts +++ b/src/api/system/user/index.ts @@ -1,7 +1,7 @@ import request from '@/utils/request'; import type { ApiResult, PageResult } from '@/api'; import type { User, UserParam } from './model'; -import { SERVER_API_URL } from '@/config/setting'; +import { SERVER_API_URL, THINK_API_URL } from '@/config/setting'; /** * 分页查询用户 @@ -97,7 +97,7 @@ export async function addUser(data: User) { */ export async function updateUser(data: User) { const res = await request.put>( - SERVER_API_URL + '/system/user', + THINK_API_URL + '/system/user', data ); if (res.data.code === 0) { diff --git a/src/views/system/role/components/role-member.vue b/src/views/system/role/components/role-member.vue new file mode 100644 index 0000000..8228a11 --- /dev/null +++ b/src/views/system/role/components/role-member.vue @@ -0,0 +1,230 @@ + + + + diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue index ab6ebca..4462465 100644 --- a/src/views/system/role/index.vue +++ b/src/views/system/role/index.vue @@ -39,6 +39,8 @@ 修改 + 成员 + 分配权限 + + @@ -77,6 +81,7 @@ import RoleSearch from './components/role-search.vue'; import RoleEdit from './components/role-edit.vue'; import RoleAuth from './components/role-auth.vue'; + import RoleMember from './components/role-member.vue'; import { pageRoles, removeRole, removeRoles } from '@/api/system/role'; import type { Role, RoleParam } from '@/api/system/role/model'; @@ -120,7 +125,7 @@ { title: '操作', key: 'action', - width: 200, + width: 260, align: 'center' } ]); @@ -137,6 +142,9 @@ // 是否显示权限分配弹窗 const showAuth = ref(false); + // 是否显示成员维护弹窗 + const showMember = ref(false); + // 表格数据源 const datasource: DatasourceFunction = ({ page, limit, where, orders }) => { return pageRoles({ ...where, ...orders, page, limit }); @@ -160,6 +168,12 @@ showAuth.value = true; }; + /* 打开成员维护弹窗 */ + const openMember = (row?: Role) => { + current.value = row ?? null; + showMember.value = true; + }; + /* 删除单个 */ const remove = (row: Role) => { const hide = messageLoading('请求中..', 0); diff --git a/src/views/system/user/components/user-edit.vue b/src/views/system/user/components/user-edit.vue index 13f807d..59649d2 100644 --- a/src/views/system/user/components/user-edit.vue +++ b/src/views/system/user/components/user-edit.vue @@ -255,14 +255,8 @@ // trigger: 'blur' // } // ], - roles: [ - { - required: true, - message: '请选择角色', - type: 'array', - trigger: 'blur' - } - ], + // 角色可以为空:清空并保存表示删除该用户的全部角色关联 + roles: [], email: [ { pattern: emailReg, From b7b347554b4103751116cacd7cd1896b1a9f243c Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Fri, 30 Oct 2026 20:50:53 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat(approval):=20=E5=8D=95=E6=8D=AE?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E9=A1=B5=E9=9D=A2=E4=B8=8E=E5=8F=AA=E8=AF=BB?= =?UTF-8?q?=E8=AF=A6=E6=83=85=20(#25)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/approval/directory/index.ts | 34 +++ src/api/approval/instance/index.ts | 35 +++ src/api/approval/instance/model/index.ts | 172 +++++++++++ .../approval/instance/components/detail.vue | 280 ++++++++++++++++++ .../approval/instance/components/search.vue | 254 ++++++++++++++++ src/views/approval/instance/index.vue | 188 ++++++++++++ 6 files changed, 963 insertions(+) create mode 100644 src/api/approval/directory/index.ts create mode 100644 src/api/approval/instance/index.ts create mode 100644 src/api/approval/instance/model/index.ts create mode 100644 src/views/approval/instance/components/detail.vue create mode 100644 src/views/approval/instance/components/search.vue create mode 100644 src/views/approval/instance/index.vue diff --git a/src/api/approval/directory/index.ts b/src/api/approval/directory/index.ts new file mode 100644 index 0000000..b7a2e8a --- /dev/null +++ b/src/api/approval/directory/index.ts @@ -0,0 +1,34 @@ +import request from '@/utils/request'; +import type { ApiResult } from '@/api'; +import type { ApprovalOrganization, ApprovalUser } from '../instance/model'; +import { THINK_API_URL } from '@/config/setting'; + +/** + * 启用组织(审批管理下拉) + */ +export async function listApprovalOrganizations() { + const res = await request.get>( + THINK_API_URL + '/approval/directory/organizations' + ); + if (res.data.code === 0 && res.data.data) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 启用用户远程搜索(审批管理下拉) + */ +export async function searchApprovalUsers(params?: { + keywords?: string; + organizationId?: number; +}) { + const res = await request.get>( + THINK_API_URL + '/approval/directory/users', + { params } + ); + 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/instance/index.ts b/src/api/approval/instance/index.ts new file mode 100644 index 0000000..79ae7e9 --- /dev/null +++ b/src/api/approval/instance/index.ts @@ -0,0 +1,35 @@ +import request from '@/utils/request'; +import type { ApiResult, PageResult } from '@/api'; +import type { + ApprovalInstance, + ApprovalItem, + ApprovalQueryParam +} from './model'; +import { THINK_API_URL } from '@/config/setting'; + +/** + * 单据查询分页 + */ +export async function pageInstances(params: ApprovalQueryParam) { + const res = await request.get>>( + THINK_API_URL + '/approval/instance/page', + { params } + ); + if (res.data.code === 0) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 单据详情(只读) + */ +export async function getInstance(id: number) { + const res = await request.get>( + THINK_API_URL + '/approval/instance/' + id + ); + if (res.data.code === 0) { + return res.data.data; + } + return Promise.reject(new Error(res.data.message)); +} diff --git a/src/api/approval/instance/model/index.ts b/src/api/approval/instance/model/index.ts new file mode 100644 index 0000000..bae51da --- /dev/null +++ b/src/api/approval/instance/model/index.ts @@ -0,0 +1,172 @@ +import type { PageParam } from '@/api'; + +/** + * 单据查询条件 + */ +export interface ApprovalQueryParam extends PageParam { + // 单据类型 completion/coordination + docType?: string; + // 单号 + bizNo?: string; + // 关键词:单号、名称或标题、实施单位 + keyword?: string; + // 报送部门id + reportOrgId?: number; + // 受理部门id + acceptOrgId?: number; + // 发起人id + reporterId?: number; + // 单据状态 + status?: string; + // 提交时间起 + submitTimeStart?: string; + // 提交时间止 + submitTimeEnd?: string; + // 归档时间起 + archiveTimeStart?: string; + // 归档时间止 + archiveTimeEnd?: string; +} + +/** + * 单据列表行 + */ +export interface ApprovalItem { + id?: number; + bizNo?: string; + 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 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 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?: Record; +} + +/** + * 审批目录组织 + */ +export interface ApprovalOrganization { + organizationId?: number; + parentId?: number; + organizationName?: string; + organizationFullName?: string; + organizationCode?: string; + leaderId?: number; +} + +/** + * 审批目录用户 + */ +export interface ApprovalUser { + userId?: number; + username?: string; + nickname?: string; + realName?: string; + organizationId?: number; + organizationName?: string; +} diff --git a/src/views/approval/instance/components/detail.vue b/src/views/approval/instance/components/detail.vue new file mode 100644 index 0000000..d8a3da3 --- /dev/null +++ b/src/views/approval/instance/components/detail.vue @@ -0,0 +1,280 @@ + + + + + + diff --git a/src/views/approval/instance/components/search.vue b/src/views/approval/instance/components/search.vue new file mode 100644 index 0000000..17b4fd2 --- /dev/null +++ b/src/views/approval/instance/components/search.vue @@ -0,0 +1,254 @@ + + + + diff --git a/src/views/approval/instance/index.vue b/src/views/approval/instance/index.vue new file mode 100644 index 0000000..b392c7d --- /dev/null +++ b/src/views/approval/instance/index.vue @@ -0,0 +1,188 @@ + + + + + + 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 3/6] =?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 @@ + + + + + + + + From 90cfc4e7c7f659b7b6b6c48b99610e983ec21100 Mon Sep 17 00:00:00 2001 From: weicw <594098497@qq.com> Date: Fri, 30 Oct 2026 21:21:10 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat(approval):=20=E5=8D=95=E6=8D=AE?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=AF=BC=E5=87=BA=E6=8C=89=E9=92=AE=20(#26)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/approval/instance/index.ts | 15 ++++++++ src/api/approval/instance/model/index.ts | 12 ++++++ src/views/approval/instance/index.vue | 47 +++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/api/approval/instance/index.ts b/src/api/approval/instance/index.ts index 79ae7e9..7f20ac8 100644 --- a/src/api/approval/instance/index.ts +++ b/src/api/approval/instance/index.ts @@ -1,6 +1,7 @@ import request from '@/utils/request'; import type { ApiResult, PageResult } from '@/api'; import type { + ApprovalExportFile, ApprovalInstance, ApprovalItem, ApprovalQueryParam @@ -33,3 +34,17 @@ export async function getInstance(id: number) { } return Promise.reject(new Error(res.data.message)); } + +/** + * 导出单据(返回完整结果,含文件下载地址) + */ +export async function exportInstances(data: ApprovalQueryParam) { + const res = await request.post>( + THINK_API_URL + '/approval/export', + data + ); + if (res.data.code === 0) { + return res.data; + } + return Promise.reject(new Error(res.data.message)); +} diff --git a/src/api/approval/instance/model/index.ts b/src/api/approval/instance/model/index.ts index bae51da..a0397e8 100644 --- a/src/api/approval/instance/model/index.ts +++ b/src/api/approval/instance/model/index.ts @@ -170,3 +170,15 @@ export interface ApprovalUser { organizationId?: number; organizationName?: string; } + +/** + * 导出文件 + */ +export interface ApprovalExportFile { + id?: number; + name?: string; + path?: string; + length?: number; + contentType?: string; + url?: string; +} diff --git a/src/views/approval/instance/index.vue b/src/views/approval/instance/index.vue index b392c7d..5a3dc31 100644 --- a/src/views/approval/instance/index.vue +++ b/src/views/approval/instance/index.vue @@ -13,6 +13,22 @@ :scroll="{ x: 1500 }" cache-key="proApprovalInstanceTable" > +