diff --git a/src/api/approval/instance/model/index.ts b/src/api/approval/instance/model/index.ts index e9610ae..30686c9 100644 --- a/src/api/approval/instance/model/index.ts +++ b/src/api/approval/instance/model/index.ts @@ -6,6 +6,8 @@ import type { PageParam } from '@/api'; export interface ApprovalQueryParam extends PageParam { // 单据类型 completion/coordination docType?: string; + // 流程编码,如 coordination_external(按流程类型筛选) + flowCode?: string; // 单号 bizNo?: string; // 关键词:单号、名称或标题、实施单位 @@ -36,6 +38,8 @@ export interface ApprovalItem { bizNo?: string; docType?: string; docTypeName?: string; + // 流程编码 + flowCode?: string; status?: string; statusName?: string; // 名称或标题 @@ -157,7 +161,11 @@ export interface ApprovalInstance { confirms?: ApprovalConfirm[]; myTask?: ApprovalMyTask | null; pendingTasks?: ApprovalPendingTask[]; - permissions?: Record; + // 业务内容(业务字段、明细、会签进度) + document?: ApprovalDocument | null; + // 字段改值历史 + fieldChanges?: ApprovalFieldChange[]; + permissions?: ApprovalPermissions; } /** @@ -204,6 +212,8 @@ export interface ApprovalTodoParam extends PageParam { status?: string; // 单据类型 docType?: string; + // 流程编码,如 settlement(按流程类型筛选) + flowCode?: string; // 查询范围:mine(默认本人待办)/all(全租户待办,需 assign 权限) scope?: 'mine' | 'all'; // 关键词:单号、名称或标题、实施单位 @@ -232,3 +242,126 @@ export interface ApprovalAssignResult { assigneeName?: string; reason?: string; } + +/** + * 业务字段(有序,后端已格式化展示值) + */ +export interface ApprovalField { + key?: string; + label?: string; + value?: string | null; +} + +/** + * 明细列元数据(类型 TEXT/DECIMAL/INT/DATE/BOOL/ENUM) + */ +export interface ApprovalLineColumn { + key?: string; + label?: string; + type?: string; + required?: boolean; + // 数值列小数位 + scale?: number; + // 文本列最大长度 + maxLength?: number; + // 是否金额列(服务端按数量 × 单价重算) + money?: boolean; + // ENUM 列可选值 + options?: { value?: string; label?: string }[]; +} + +/** + * 明细行:以列 key 为键 + */ +export type ApprovalLine = Record; + +/** + * 明细汇总 + */ +export interface ApprovalLineSummary { + lineCount?: number; + amountTotal?: number | null; +} + +/** + * 会签组成员 + */ +export interface ApprovalGroupMember { + userId?: number; + userName?: string; + status?: string; + statusName?: string; +} + +/** + * 会签节点进度(按组已签 N/M) + */ +export interface ApprovalGroupProgress { + nodeKey?: string; + nodeName?: string; + groupKey?: string; + groupName?: string; + groupSeq?: number; + signed?: number; + total?: number; + members?: ApprovalGroupMember[]; +} + +/** + * 单据业务内容 + */ +export interface ApprovalDocument { + // 业务字段(有序) + fields?: ApprovalField[]; + // 明细行 + lines?: ApprovalLine[]; + // 明细列元数据;无明细为空 + lineColumns?: ApprovalLineColumn[]; + // 明细汇总;无明细为 null + lineSummary?: ApprovalLineSummary | null; + // 会签节点进度,非会签单据为空 + groupProgress?: ApprovalGroupProgress[]; +} + +/** + * 字段改值历史 + */ +export interface ApprovalFieldChange { + id?: number; + nodeKey?: string; + nodeName?: string; + fieldKey?: string; + fieldLabel?: string; + oldValue?: string | null; + newValue?: string | null; + operatorName?: string; + round?: number; + createTime?: string; +} + +/** + * 当前用户可回填字段 + */ +export interface ApprovalWritableField { + field?: string; + label?: string; + required?: boolean; + value?: string | null; +} + +/** + * 详情动作权限 + */ +export interface ApprovalPermissions { + canEdit?: boolean; + canSubmit?: boolean; + canWithdraw?: boolean; + canApprove?: boolean; + canReject?: boolean; + canConfirm?: boolean; + canArchive?: boolean; + canDispatch?: boolean; + canAssign?: boolean; + // 当前用户在该节点可回填的字段;非节点处理人为空 + writableFields?: ApprovalWritableField[]; +} diff --git a/src/api/approval/price/index.ts b/src/api/approval/price/index.ts new file mode 100644 index 0000000..a9fe007 --- /dev/null +++ b/src/api/approval/price/index.ts @@ -0,0 +1,17 @@ +import request from '@/utils/request'; +import type { ApiResult } from '@/api'; +import { THINK_API_URL } from '@/config/setting'; +import type { ApprovalPriceView } from './model'; + +/** + * 设施价格表:当前生效版本 + 历史版本(只读,权限点 approval:price:view) + */ +export async function getApprovalPrice() { + const res = await request.get>( + THINK_API_URL + '/approval/price' + ); + 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/price/model/index.ts b/src/api/approval/price/model/index.ts new file mode 100644 index 0000000..9cea347 --- /dev/null +++ b/src/api/approval/price/model/index.ts @@ -0,0 +1,36 @@ +import type { + ApprovalField, + ApprovalLine, + ApprovalLineColumn +} from '../../instance/model'; + +/** + * 价格表版本:审批实例即版本(ADR 0012) + */ +export interface ApprovalPriceVersion { + instanceId?: number; + // 单号 + bizNo?: string; + // 生效日期(yyyy-MM-dd) + effectiveDate?: string; + // 归档时间 + archiveTime?: string; + // 报送部门名 + reportOrgName?: string; + // 业务字段(含生效日期等) + fields?: ApprovalField[]; + // 明细行 + lines?: ApprovalLine[]; + // 明细列元数据 + lineColumns?: ApprovalLineColumn[]; + // 合计金额 + amountTotal?: number | null; +} + +/** + * 价格表查看页数据:current 为当前生效版本,history 为历史版本(按生效日期倒序) + */ +export interface ApprovalPriceView { + current?: ApprovalPriceVersion | null; + history?: ApprovalPriceVersion[]; +} diff --git a/src/api/approval/task/index.ts b/src/api/approval/task/index.ts index 7633baf..3e15c46 100644 --- a/src/api/approval/task/index.ts +++ b/src/api/approval/task/index.ts @@ -8,12 +8,33 @@ import type { } from '../instance/model'; /** - * 通过任务 + * 通过任务(fields 为当前节点可回填字段,无回填时省略) */ -export async function approveApprovalTask(id: number, opinion?: string) { +export async function approveApprovalTask( + id: number, + opinion?: string, + fields?: Record +) { const res = await request.post>( THINK_API_URL + '/approval/task/' + id + '/approve', - { opinion } + { opinion, fields } + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 回填(只写字段,不推进节点) + */ +export async function backfillApprovalTask( + id: number, + fields: Record +) { + const res = await request.post>( + THINK_API_URL + '/approval/task/' + id + '/backfill', + { fields } ); if (res.data.code === 0) { return res.data.message; diff --git a/src/views/approval/components/document-view.vue b/src/views/approval/components/document-view.vue new file mode 100644 index 0000000..0e3934a --- /dev/null +++ b/src/views/approval/components/document-view.vue @@ -0,0 +1,319 @@ + + + + + + + + diff --git a/src/views/approval/format.ts b/src/views/approval/format.ts new file mode 100644 index 0000000..7c31c68 --- /dev/null +++ b/src/views/approval/format.ts @@ -0,0 +1,105 @@ +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); +} + +/** + * 日期统一展示(yyyy-MM-dd) + */ +export function formatApprovalDate(value?: string | number | null): string { + if (value === undefined || value === null || value === '') { + return ''; + } + if (typeof value === 'number') { + return toDateString(value, 'yyyy-MM-dd'); + } + return String(value).replace('T', ' ').slice(0, 10); +} + +/** + * 附件大小展示 + */ +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 formatMoney(value?: number | string | null): string { + if (value === undefined || value === null || value === '') { + return '-'; + } + const num = Number(value); + return isNaN(num) ? '-' : num.toFixed(2); +} + +/** + * 单据状态标签颜色 + */ +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'; +} + +/** + * 流程类型(flowCode)显示名。 + * + * 后端目前没有暴露 flowCode 字典接口,选项在此静态维护; + * 新增单据类型时需同步本文件,后端提供字典接口后可改为远程加载。 + */ +export const APPROVAL_FLOW_NAMES: Record = { + completion: '业务完成确认单', + coordination_internal: '内部协调单', + coordination_external: '外部协调单', + settlement: '结算单', + receipt: '收据申请单', + vehicle: '车辆免收费登记表', + venue: '场地使用申请表', + coupon: '体验券领用申请单', + facility: '设施损坏修复与租用价格表' +}; + +/** + * 流程类型下拉选项 + */ +export const APPROVAL_FLOW_OPTIONS = Object.keys(APPROVAL_FLOW_NAMES).map( + (value) => ({ label: APPROVAL_FLOW_NAMES[value], value }) +); + +/** + * 按 flowCode 取流程显示名;未知编码原样返回(降级为 docTypeName) + */ +export function approvalFlowName(flowCode?: string): string { + if (!flowCode) { + return ''; + } + return APPROVAL_FLOW_NAMES[flowCode] || flowCode; +} diff --git a/src/views/approval/instance/components/detail.vue b/src/views/approval/instance/components/detail.vue index 4fa3feb..4b85835 100644 --- a/src/views/approval/instance/components/detail.vue +++ b/src/views/approval/instance/components/detail.vue @@ -55,7 +55,7 @@
{{ data.serviceContent || '-' }}
-