三面拆分④:驾驶舱首页 —— 度量改接 report 真八指标,纠正率/DMN 不再恒为 0

治理台原先调 memory 的五指标版,还把 submissions/corrections/judgements
硬塞 0 —— 仪表在说谎。八指标本就在 report 里算好,这里接上,与工作台汇报同源同口径。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-27 21:08:42 +08:00
co-authored by Claude Fable 5
parent bb6760d7a4
commit 9fce0fdaa0
11 changed files with 292 additions and 127 deletions
@@ -35,7 +35,7 @@ import {
Todo,
} from '@web-shared/gov/primitives.tsx';
import type { Nav } from '@web-shared/gov/gov-route.ts';
import { useGovActivities, useGovPackages, useGovStaff, useGovTriggers } from '@web-shared/gov/gov-api.ts';
import { useGovActivities, useGovPackages, useGovPkgReports, useGovStaff, useGovTriggers } from '@web-shared/gov/gov-api.ts';
import { FlowFigureBlock } from '@web-shared/gov/flow/FlowFigure.tsx';
import { packageToGraph } from '@web-shared/gov/flow/pkg-to-graph.ts';
import { mergeGraphIntoPackage } from '@web-shared/gov/flow/graph-to-pkg.ts';
@@ -47,23 +47,6 @@ export type HomeProps = { tab: string; nav: Nav };
/* ── 报告:画图即校验,列表与详情同一来源 ─────────────────────────────── */
/** 每个包一份闭合报告 —— 磁贴上的「边 n/m」、待处置清单、发布门都读它 */
function usePkgReports(packages: readonly ProcessPackage[]) {
return useQuery({
queryKey: ['gov', 'process-reports', packages.map((p) => `${p.id}@${p.version}`).join(',')],
enabled: packages.length > 0,
queryFn: async () => {
const entries = await Promise.all(
packages.map(
async (p) =>
[`${p.id}@${p.version}`, await call<ClosureReport>(validateProcessRoute, { body: { pkg: p } })] as const,
),
);
return new Map(entries);
},
});
}
/** 边闭合数:边总数 − 有违规的边(同一条边多处违规只记一次) */
function edgeCheckOf(pkg: ProcessPackage, report: ClosureReport | undefined) {
const total = pkg.edges.length;
@@ -84,7 +67,7 @@ export function WorkflowsHome({ tab, nav }: HomeProps) {
function PackagesHome({ tab, nav }: HomeProps) {
const q = useGovPackages();
const packages = q.data?.packages ?? [];
const reports = usePkgReports(packages);
const reports = useGovPkgReports(packages);
const reportOf = (p: ProcessPackage) => reports.data?.get(`${p.id}@${p.version}`);
const counts = (p: ProcessPackage) => ({
activity: p.nodes.filter((n) => n.kind === 'activity').length,
@@ -860,7 +843,7 @@ export function EdgesPage({ id }: { id: string }) {
const [pid, versionText] = id.split('@');
const q = useGovPackages();
const pkg = (q.data?.packages ?? []).find((p) => p.id === pid && String(p.version) === versionText);
const reports = usePkgReports(pkg === undefined ? [] : [pkg]);
const reports = useGovPkgReports(pkg === undefined ? [] : [pkg]);
if (pkg === undefined) {
return (
<QueryGate query={q}>