feat(p3.3): 应用内审批前端——flow-approval 组件族本地化 + /todo 我的审批页 + 详情审批卡片
build / build (push) Successful in 2m12s

- 从 Notice/front 复制 flow-approval 六件并本地修复(漂移登记组件 README,Notice 不回改):
  · P0-04:四个写调用点(List 通过/驳回 + Card 通过/驳回)全部实际携带本行 bizId,
    选中 bizId 随弹窗生命周期锁定/清理
  · P0-05:删 useElementHeight/yh-* 平台布局依赖,本地 fa-* 样式(theme-base.css --sh-* 令牌)
  · P0-06:types.ts 本地契约——增 my(行=ApplyVo 子集/FlowPage 完整元数据/状态 0=待提交
    禁止当全部,全部用 -1 哨兵)、删 instances(不代理全校视角)、approve/reject 增 bizId 参
  · P1-05:卡片轨迹不自取(详情页把 /progress 转换 TraceVo 经 props 传入);节点摘要取
    active steps 节点名;MULTI_TASK 逐条列出本人待办各带动作,不默认 tasks[0];
    未进流程(flowInstanceId 空)详情页不渲染卡片(显式决策)
  · P1-09:FlowTaskEmbed 消息四条件(打开中+严格 origin+本 iframe+taskId/bizId 上下文一致),
    换址重置高度;宿主换址请求带代际号,关闭/换件废弃在途响应并清上下文;
    open-biz 只用与当前办件一致的 bizId 构造 /apply-detail?id=,不透传任意 URL
- ApprovalApi 类挂 svc.ts(todo/my/byBiz/approve/reject/recordUrl/taskPageUrl,写面
  taskId/applyId 查询参数+opinion/edgeName JSON body 两形态区分)+ approvalAdapter.ts 唯一映射
- /todo 路由 + 顶部导航第三链接「我的审批」+ MyApprovals.vue(双页签+记录抽屉+完整办理)
- ApplyDetail 挂审批卡片(审批操作区)+ TraceVo 转换器
- 小屏基础响应式(drawer/modal 宽度自适应、列表横向滚动;1200px 全量适配不在本批)
- 门禁:vue-tsc(ts4.9 外挂兼容组合)错误数 HEAD=工作区=18 零新增(仓内 vue-tsc1.8+ts5.9
  崩溃系历史遗留);vite build 绿(MyApprovals/approvalAdapter chunk 产出);
  preview 冒烟:/todo 渲染完整(导航/页签/表格空态/API 失败优雅降级)、详情页无崩溃(Stage S4/P3.3)
This commit is contained in:
chenxing
2026-10-19 23:59:48 +08:00
parent f5b39b96c6
commit 351a513547
12 changed files with 1567 additions and 1 deletions
+28
View File
@@ -0,0 +1,28 @@
import type { FlowApprovalApi } from "@/components/flow-approval/types";
import { approvalApi, applyApi } from "@/api/module/svc";
/**
* svc-hall 应用内审批适配器(唯一映射位置;沿 Notice approvalAdapter 形态)。
*
* 纪律:
* - 身份三字段(operatorId/operatorName/schId)不出现——后端从 CAS 会话取;
* - 写面 bizId=applyId 是必需上下文(后端写面双闸),组件契约层已强制携带;
* - trace 复用既有 /api/apply/{id}/progress(卡片不自取轨迹,宿主转换后经 props 传入);
* - alova Method 是 thenable,组件 await 即发。
*/
export const svcFlowApprovalApi: FlowApprovalApi = {
todo: (p) => approvalApi.todo(p?.page ?? 1, p?.size ?? 10).send(),
my: (p) =>
approvalApi
.my(p?.page ?? 1, p?.size ?? 10, p?.flowStatus ?? null)
.send(),
byBiz: (bizId) => approvalApi.byBiz(Number(bizId)).send(),
trace: (bizId) => applyApi.progress(Number(bizId)).send(),
approve: (taskId, opinion, edgeName, bizId) =>
approvalApi.approve(taskId, Number(bizId), opinion, edgeName).send(),
reject: (taskId, opinion, bizId) => approvalApi.reject(taskId, Number(bizId), opinion).send(),
recordUrl: (bizId) => approvalApi.recordUrl(Number(bizId)).send(),
taskPageUrl: (bizId, taskId) => approvalApi.taskPageUrl(Number(bizId), taskId).send(),
};
export default svcFlowApprovalApi;
+36
View File
@@ -22,6 +22,7 @@ import type {
const HALL = "/api/hall";
const APPLY = "/api/apply";
const FILE = "/api/file";
const APPROVAL = "/api/apply/approval";
function get<T = any>(url: string, params?: Record<string, any>): Method<T> {
return new Method<T>("GET", alovaInstance, url, { params });
@@ -125,6 +126,41 @@ class FileApi {
}
}
class ApprovalApi {
/** 应用内审批代理(P3.1,/api/apply/approval/**;身份全部由后端从 CAS 会话取,前端不传) */
/** 待我审批(中心 todo;双值双查与合并都在后端) */
todo(page?: number, size?: number) {
return get(`${APPROVAL}/Todo`, { page, size });
}
/** 我提交的(本地办件;后端做 {total,list}→FlowPage 信封映射;flowStatus 空=全部) */
my(page?: number, size?: number, flowStatus?: number | null) {
return get(`${APPROVAL}/My`, { page, size, flowStatus: flowStatus ?? undefined });
}
/** 当前人在该办件上的待办(0/1/N 均 200;卡片/列表复核同源) */
byBiz(applyId: number) {
return get(`${APPROVAL}/ByBiz`, { applyId });
}
/** 通过:taskId/applyId 走查询参数(与中心端点同构),opinion/edgeName 走 JSON body */
approve(taskId: number, applyId: number, opinion?: string, edgeName?: string) {
return postJSON(`${APPROVAL}/Approve?taskId=${encodeURIComponent(taskId)}&applyId=${encodeURIComponent(applyId)}`,
{ opinion: opinion || undefined, edgeName: edgeName || undefined });
}
/** 拒绝:opinion 必填(后端前置校验) */
reject(taskId: number, applyId: number, opinion: string) {
return postJSON(`${APPROVAL}/Reject?taskId=${encodeURIComponent(taskId)}&applyId=${encodeURIComponent(applyId)}`,
{ opinion });
}
/** 审批记录抽屉地址(token 只读页,instanceId 形态换址) */
recordUrl(applyId: number) {
return get(`${APPROVAL}/RecordUrl`, { applyId });
}
/** 完整办理任务页地址(先 byBiz 归属预检再签发,在后端) */
taskPageUrl(applyId: number, taskId: number) {
return get(`${APPROVAL}/TaskPageUrl`, { applyId, taskId });
}
}
export const hallApi = new HallApi();
export const applyApi = new ApplyApi();
export const fileApi = new FileApi();
export const approvalApi = new ApprovalApi();