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

这个提交包含在:
2026-05-12 10:41:47 +08:00
父节点 f99fbce3d8
当前提交 72e38db4e5
共修改 23 个文件,包含 1362 行新增和 12 行删除
+75
查看文件
@@ -15,6 +15,7 @@ import {
type PortalRecentActivity,
type PortalTeamStatusItem,
} from "../api/portal";
import { fetchWorkflowTaskSummary, type WorkflowTaskProductivitySummary } from "../api/workflow";
import { isApiError } from "../api/types";
import { useAuth } from "../auth/AuthContext";
import { hasAnyPermission, isManagerRole } from "../auth/permissions";
@@ -46,6 +47,15 @@ type SummaryItem = {
tone?: "normal" | "warning";
};
function workflowEntityLabel(entityType: string) {
if (entityType === "reimbursement") return "报销";
if (entityType === "leave") return "请假";
if (entityType === "purchase_request") return "采购";
if (entityType === "travel_request") return "差旅";
if (entityType === "unknown") return "未知业务";
return entityType;
}
type TodoAggregateItem = {
title: string;
sourceLabel: string;
@@ -435,6 +445,52 @@ function FinanceSummaryPanel({ summary }: { summary: PortalHomePayload["financeS
return <SummaryPanel title="财务待处理" items={items} />;
}
function ApprovalProductivityPanel({
summary,
title = "审批效率摘要",
}: {
summary: WorkflowTaskProductivitySummary | null;
title?: string;
}) {
if (!summary) {
return null;
}
const typeDistribution = summary.byEntityType
.filter((item) => item.pendingTotal > 0)
.map((item) => `${workflowEntityLabel(item.key)} ${item.pendingTotal}`)
.join(" / ");
const items: SummaryItem[] = [
{
key: "workflow-pending-total",
href: "/workflow/tasks",
label: "当前待办",
value: `${summary.pendingTotal} 条`,
note: summary.earliestPendingAt
? `最早待处理:${formatRelativeTime(summary.earliestPendingAt)}`
: "暂无待处理审批。",
tone: summary.pendingTotal > 0 ? "warning" : "normal",
},
{
key: "workflow-overdue-total",
href: "/workflow/tasks",
label: "超时待办",
value: `${summary.overdueTotal} 条`,
note: `平均等待 ${summary.averagePendingAgeHours} 小时`,
tone: summary.overdueTotal > 0 ? "warning" : "normal",
},
{
key: "workflow-entity-distribution",
href: "/workflow/tasks",
label: "业务分布",
value: typeDistribution || "暂无",
note: "按报销、请假、采购、差旅汇总。",
},
];
return <SummaryPanel title={title} items={items} />;
}
function AnnouncementsList({ announcements }: { announcements: PortalHomePayload["announcements"] }) {
const safeAnnouncements = Array.isArray(announcements) ? announcements : [];
@@ -875,6 +931,16 @@ export function PortalHomePage() {
queryFn: () => fetchMyTodayAttendance(),
retry: (failureCount, error) => !isAttendanceFeatureDisabled(error) && failureCount < 2,
});
const workflowSummaryQuery = useQuery({
enabled: hasAnyPermission(permissions, APPROVAL_PORTAL_PERMISSIONS),
queryKey: ["workflow", "tasks", "summary", "mine"],
queryFn: () => fetchWorkflowTaskSummary(),
});
const workflowSystemSummaryQuery = useQuery({
enabled: hasAnyPermission(permissions, ["system.audit.view"]),
queryKey: ["workflow", "tasks", "summary", "system"],
queryFn: () => fetchWorkflowTaskSummary({ scope: "system" }),
});
const canSetupWorkspace = hasAnyPermission(permissions, ["system.settings"]);
useEffect(() => {
@@ -1281,6 +1347,15 @@ export function PortalHomePage() {
{roleCapabilities.canApproveTasks ? (
<SummaryPanel title="审批处理" items={approvalSummaryItems} />
) : null}
{roleCapabilities.canApproveTasks ? (
<ApprovalProductivityPanel summary={workflowSummaryQuery.data ?? null} />
) : null}
{roleCapabilities.canManageSystem ? (
<ApprovalProductivityPanel
title="全局审批效率摘要"
summary={workflowSystemSummaryQuery.data ?? null}
/>
) : null}
{roleCapabilities.canUseFinance ? (
<FinanceSummaryPanel summary={payload.financeSummary ?? null} />
) : null}