收敛审批动作面板并清理层叠遗留 [approval-action-panel-kiss-layering]
这个提交包含在:
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { buildReimbursementApprovalEvidence } from "../../src/lib/reimbursementApprovalProjection";
|
||||
import { resolveReimbursementApprovalBlockReason } from "../../src/lib/reimbursementApprovalReadiness";
|
||||
import {
|
||||
buildReimbursementAmountSummary,
|
||||
parseMoneyToMinorUnits,
|
||||
@@ -42,6 +43,53 @@ test("报销金额使用整数分判断完整性且不产生展示用第二总
|
||||
});
|
||||
});
|
||||
|
||||
test("报销审批五类阻断原因由同一投影给出且正常态保持安静", () => {
|
||||
const base = {
|
||||
amountIntegrity: "ready" as const,
|
||||
detailState: "ready" as const,
|
||||
online: true,
|
||||
snapshotParseStatus: "ready",
|
||||
};
|
||||
|
||||
expect(resolveReimbursementApprovalBlockReason(base)).toBeNull();
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, online: false })).toBe("报销审批需联网核对完整报销内容;当前不能通过、退回、驳回或转审。");
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, detailState: "loading" })).toBe("正在加载完整报销内容和票据;加载完成前不能作出审批决定。");
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, detailState: "error" })).toBe("报销内容未加载完整,暂不能审批,请刷新后重试");
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, snapshotParseStatus: "invalid" })).toBe("提交时检查记录无法解析,暂时不能审批;请联系系统管理员核对。");
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, snapshotParseStatus: undefined })).toBe("提交时检查记录无法解析,暂时不能审批;请联系系统管理员核对。");
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, amountIntegrity: "mismatch" })).toBe("报销总额与明细汇总不一致,请联系管理员");
|
||||
expect(resolveReimbursementApprovalBlockReason({ ...base, amountIntegrity: "unavailable" })).toBe("明细金额无法完整核对,请联系管理员");
|
||||
});
|
||||
|
||||
test("动作面板复用唯一阻断投影且预算三态判断保持原合同", () => {
|
||||
const adapter = source("src/pages/reimbursement-workspace/ReimbursementApprovalAdapter.tsx");
|
||||
|
||||
expect(adapter.match(/resolveReimbursementApprovalBlockReason\(/g)).toHaveLength(1);
|
||||
expect(adapter).toContain("throw new Error(decisionBlockReason");
|
||||
expect(adapter).toContain("setActionError(decisionBlockReason");
|
||||
expect(adapter).toContain("{decisionBlockReason}");
|
||||
expect(adapter.match(/snapshot\?\.budgetCheckStatus === "missing"/g)).toHaveLength(3);
|
||||
expect(adapter).not.toContain("完整内容已就绪");
|
||||
expect(adapter).not.toContain("内容未就绪,审批动作已停用");
|
||||
expect(adapter).not.toContain("statusSummary");
|
||||
expect(adapter).toContain("actionError || activeSecondaryAction ?");
|
||||
});
|
||||
|
||||
test("旧审批层叠 class 与更多菜单样式无定义或消费者", () => {
|
||||
const styles = source("src/index.css");
|
||||
const productSources = [
|
||||
source("src/components/patterns/BusinessDetailTemplate.tsx"),
|
||||
source("src/pages/WorkflowTaskDetailPage.tsx"),
|
||||
source("src/pages/reimbursement-workspace/ReimbursementApprovalAdapter.tsx"),
|
||||
].join("\n");
|
||||
|
||||
for (const legacyClass of ["workflow-action-panel", "workflow-action-more"]) {
|
||||
expect(styles).not.toContain(legacyClass);
|
||||
expect(productSources).not.toContain(legacyClass);
|
||||
}
|
||||
expect(productSources).toContain("detail-action-panel lg:sticky lg:top-24");
|
||||
});
|
||||
|
||||
test("PC 与移动明细只展示共享模型中的服务端权威合计", () => {
|
||||
const evidenceList = source("src/components/reimbursements/ReimbursementItemEvidenceList.tsx");
|
||||
const desktopDetail = source("src/pages/ReimbursementDetailPage.tsx");
|
||||
|
||||
在新工单中引用
屏蔽一个用户