/** * feature `gov-blueprint` —— 设计中心首页:企业蓝图。 * * 一屏回答两个问题:**这家企业被定义成什么样**,**哪里还没定义完**。 * * 因果链:流程包(战略)→ 活动库(方法)→ 工具箱(能力)→ 数据域(对象)。 * 四库各自有页,但「为什么是这四库、它们怎么相互决定」得有一屏能讲 —— 就是这一屏。 * * 这里**不出现任何运行态数字**(在跑几单、30 天起单数、死信数)。 * 设计者看的是定义完不完整,不是今天忙不忙 —— 混进运行数字,这页就退化成第二个驾驶舱。 */ import { Ico } from '@web-shared/Ico.tsx'; import { Clear, Sec, Todo } from '@web-shared/gov/primitives.tsx'; import type { Nav } from '@web-shared/gov/gov-route.ts'; import { useGovActivities, useGovObjects, useGovPackages, useGovTools, useGovTriggers, } from '@web-shared/gov/gov-api.ts'; export type HomeProps = { tab: string; nav: Nav }; export function BlueprintHome({ nav }: HomeProps) { const pkgs = useGovPackages(); const acts = useGovActivities(); const tools = useGovTools(); const objs = useGovObjects(); const trgs = useGovTriggers(); const packages = pkgs.data?.packages ?? []; /* * 没有「草稿」也没有「未闭合」可数了 —— 严格检查 + 保存即生效:不闭合的包**存不进来**。 * 硬摆这两个计数就是摆两个恒为 0 的假指标。改数真能说话的:每条流有几版、最新是第几版。 */ const flowCount = new Set(packages.map((p) => p.id)).size; const activities = acts.data?.activities ?? []; const toolRows = tools.data?.tools ?? []; const objectRows = objs.data?.objects ?? []; const domains = [...new Set(objectRows.map((o) => o.domain))]; const triggers = trgs.data?.triggers ?? []; /** 编排里引用了、但活动库装不出来的活动 —— 图画得通,活儿没人干 */ const referenced = [ ...new Set( packages.flatMap((p) => p.nodes.flatMap((n) => (n.kind === 'activity' && n.activityId !== undefined ? [n.activityId] : [])), ), ), ]; const missingActivities = referenced.filter((id) => !activities.some((a) => a.activityId === id)); /** 没有任何触发器指向的流程包 —— 定义完整,但没人调得起来 */ const uncalled = [...new Set(packages.map((p) => p.id))].filter( (id) => !triggers.some((t) => t.processPackageId === id), ); const gaps = missingActivities.length + uncalled.length; // 因果链是这一屏的主角:四库以真箭头相连 —— 箭头编码的是真实依赖 // (流程包引用活动、活动调工具、活动物化数据),节点卡即入口,点卡即入库。 return ( <>