AP6 增加审批催办与效率摘要

这个提交包含在:
2026-05-12 10:41:47 +08:00
父节点 f99fbce3d8
当前提交 72e38db4e5
共修改 23 个文件,包含 1362 行新增和 12 行删除
@@ -46,6 +46,9 @@ type WorkflowSubmitResponse = {
};
type WorkflowTaskDetailResponse = {
task?: {
status: string;
};
history: Array<{
action: string;
actorId: string | null;
@@ -67,6 +70,24 @@ type NotificationDeliveryListResponse = {
items: unknown[];
};
type NotificationListResponse = {
items: Array<{
type: string;
targetId: string | null;
title: string;
}>;
};
type WorkflowTaskSummaryResponse = {
pendingTotal: number;
overdueTotal: number;
byEntityType: Array<{
key: string;
pendingTotal: number;
overdueTotal: number;
}>;
};
type LeaveTypeListResponse = {
items: Array<{
id: string;
@@ -640,6 +661,73 @@ test.describe("R3 权限直连审计", () => {
}
});
test("AP6 审批催办与待办汇总:申请人可催办且重复催办被限制", async () => {
const employee = await createAuthenticatedApiClient(EMPLOYEE);
const manager = await createAuthenticatedApiClient(MANAGER);
const admin = await createAuthenticatedApiClient(ADMIN);
const clients = [employee, manager, admin];
try {
const leave = await createSubmittedLeave(employee.api, `ap6-remind-${Date.now()}`);
const summaryBefore = await apiGetData<WorkflowTaskSummaryResponse>(manager.api, "/api/workflow/tasks/summary");
expect(summaryBefore.pendingTotal).toBeGreaterThanOrEqual(1);
expect(summaryBefore.byEntityType.some((item) => item.key === "leave" && item.pendingTotal > 0)).toBe(true);
const managerRemind = await manager.api.post(`/api/workflow/tasks/${leave.currentTaskId}/remind`, { data: {} });
expectStatus(managerRemind.status(), [403], "manager POST workflow remind should not act as applicant");
const adminRemind = await admin.api.post(`/api/workflow/tasks/${leave.currentTaskId}/remind`, { data: {} });
expectStatus(adminRemind.status(), [403], "admin-only POST workflow remind should not act as applicant");
const reminded = await apiPostData<{ outcome: string; notificationCount: number }>(
employee.api,
`/api/workflow/tasks/${leave.currentTaskId}/remind`,
{},
);
expect(reminded.outcome).toBe("reminded");
expect(reminded.notificationCount).toBeGreaterThanOrEqual(1);
const duplicate = await employee.api.post(`/api/workflow/tasks/${leave.currentTaskId}/remind`, { data: {} });
expectStatus(duplicate.status(), [409], "duplicate remind should hit 24h cooldown");
const workflowDetail = await apiGetData<WorkflowTaskDetailResponse>(manager.api, `/api/workflow/tasks/${leave.currentTaskId}`);
expect(workflowDetail.task?.status).toBe("pending");
expect(workflowDetail.history.some((item) => item.action === "remind" && item.actorId === employee.me.id)).toBe(true);
expectNoSensitiveKeys(workflowDetail.history);
const notifications = await apiGetData<NotificationListResponse>(
manager.api,
"/api/notifications?type=workflow.task_reminded&page=1&pageSize=20",
);
expect(
notifications.items.some((item) => item.targetId === leave.currentTaskId && item.type === "workflow.task_reminded"),
).toBe(true);
expectNoSensitiveKeys(notifications);
await expectAuditAction(
admin.api,
"WORKFLOW_TASK_REMINDED",
(item) => item.targetId === leave.currentTaskId && item.actorId === employee.me.id,
);
const systemSummary = await apiGetData<WorkflowTaskSummaryResponse>(
admin.api,
"/api/workflow/tasks/summary?scope=system",
);
expect(systemSummary.pendingTotal).toBeGreaterThanOrEqual(summaryBefore.pendingTotal);
await expectApiStatus({
role: "employee",
api: employee.api,
path: "/api/workflow/tasks/summary?scope=system",
statuses: [403],
note: "普通员工不得查看全局审批效率摘要",
});
} finally {
await Promise.all(clients.map((client) => client.dispose()));
}
});
test("PA6 审计留痕:登录、审批历史、附件下载、导出与通知投递可追溯且脱敏", async () => {
const employee = await createAuthenticatedApiClient(EMPLOYEE);
const manager = await createAuthenticatedApiClient(MANAGER);