三面拆分⑤:企业蓝图首页 —— 四库因果链与待补清单(闭合/缺活动/无调起)

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:11:09 +08:00
co-authored by Claude Fable 5
parent 9fce0fdaa0
commit 19108af6fa
3 changed files with 176 additions and 11 deletions
+2 -11
View File
@@ -23,6 +23,7 @@ import { SURFACE_META, SURFACE_ZONES, canSeeSurface } from '@web-shared/gov/surf
import type { Surface } from '@web-shared/gov/surfaces.ts'; import type { Surface } from '@web-shared/gov/surfaces.ts';
import { useGovObjects, useGovTasks } from '@web-shared/gov/gov-api.ts'; import { useGovObjects, useGovTasks } from '@web-shared/gov/gov-api.ts';
import { queryKeys } from './query.ts'; import { queryKeys } from './query.ts';
import { BlueprintHome } from '@features/gov-blueprint';
import { TasksHome, TaskLogPage, TaskPage, WfPage } from '@features/gov-task'; import { TasksHome, TaskLogPage, TaskPage, WfPage } from '@features/gov-task';
import { EmpPage, PeopleHome, RolePage } from '@features/gov-staff'; import { EmpPage, PeopleHome, RolePage } from '@features/gov-staff';
import { EdgesPage, PkgPage, WorkflowsHome } from '@features/gov-process'; import { EdgesPage, PkgPage, WorkflowsHome } from '@features/gov-process';
@@ -317,16 +318,6 @@ function LedgerRail({
); );
} }
/** 企业蓝图 —— Task 6 接真;在那之前先给设计者一句「这里将有什么」 */
function BlueprintPlaceholder() {
return (
<Note>
这里将把四库串成一条因果链:流程包(战略)→ 活动库(方法)→ 工具箱(能力)→ 数据域(对象),
并把「哪里还没定义完」聚成一张待补清单。先从左轨进各库编排。
</Note>
);
}
/** 台账 —— Task 10 接真;导航项已随数据域长出来了,内容随后 */ /** 台账 —— Task 10 接真;导航项已随数据域长出来了,内容随后 */
function LedgersPlaceholder() { function LedgersPlaceholder() {
return <Note>这里将按域列出全部台账对象、行数据与版本。域的结构在设计中心 · 数据域维护。</Note>; return <Note>这里将按域列出全部台账对象、行数据与版本。域的结构在设计中心 · 数据域维护。</Note>;
@@ -335,7 +326,7 @@ function LedgersPlaceholder() {
function ZoneHome({ zone, tab, nav }: { zone: GovZone; tab: string; nav: Nav }) { function ZoneHome({ zone, tab, nav }: { zone: GovZone; tab: string; nav: Nav }) {
const P = { const P = {
// 设计中心 // 设计中心
blueprint: BlueprintPlaceholder, blueprint: BlueprintHome,
workflows: WorkflowsHome, workflows: WorkflowsHome,
library: LibraryHome, library: LibraryHome,
tools: ToolsHome, tools: ToolsHome,
@@ -0,0 +1,5 @@
/**
* feature `gov-blueprint` 唯一出口(编码规范 §9.1)。
* 企业蓝图 —— 设计中心首页:四库因果链与待补清单。
*/
export { BlueprintHome } from './internal/panel.tsx';
@@ -0,0 +1,169 @@
/**
* feature `gov-blueprint` —— 设计中心首页:企业蓝图。
*
* 一屏回答两个问题:**这家企业被定义成什么样**,**哪里还没定义完**。
*
* 因果链:流程包(战略)→ 活动库(方法)→ 工具箱(能力)→ 数据域(对象)。
* 四库各自有页,但「为什么是这四库、它们怎么相互决定」得有一屏能讲 —— 就是这一屏。
*
* 这里**不出现任何运行态数字**(在跑几单、30 天起单数、死信数)。
* 设计者看的是定义完不完整,不是今天忙不忙 —— 混进运行数字,这页就退化成第二个驾驶舱。
*/
import { Clear, Entry, Kpi, Sec, Todo } from '@web-shared/gov/primitives.tsx';
import type { Nav } from '@web-shared/gov/gov-route.ts';
import {
useGovActivities,
useGovObjects,
useGovPackages,
useGovPkgReports,
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 ?? [];
const reports = useGovPkgReports(packages);
const reportOf = (id: string, version: number) => reports.data?.get(`${id}@${version}`);
const drafts = packages.filter((p) => p.state !== 'published');
const draftBad = drafts.filter((p) => reportOf(p.id, p.version)?.publishable === false);
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 = draftBad.length + missingActivities.length + uncalled.length;
// 因果链那句话写在区说明里(ZM.blueprint.desc),此处不重复 —— 直接上四库读数
return (
<>
<div className="g-kpis">
<Kpi
ico="workflow"
tone="brand"
label="流程包 · 战略"
value={packages.length}
sub={`草稿 ${drafts.length} · 未闭合 ${draftBad.length}`}
/>
<Kpi
ico="boxes"
tone="auto"
label="活动 · 方法"
value={activities.length}
sub="一个活动 = 一个任务的定义"
/>
<Kpi
ico="wrench"
tone="collab"
label="工具 · 能力"
value={toolRows.length}
sub={`读类 ${toolRows.filter((t) => t.effect === 'read').length} · 写类 ${toolRows.filter((t) => t.effect === 'write').length}`}
/>
<Kpi
ico="database"
tone="ok"
label="数据域 · 对象"
value={domains.length}
sub={`${objectRows.length} 个对象 · 发布即在运营中心长出台账位`}
/>
</div>
<Sec ico="flag" title="待补清单" extra="定义上的缺口聚在这里,点进即改 —— 不散落在四库">
{gaps === 0 ? (
<Clear>没有缺口 —— 流程包全部闭合,引用的活动都装好了,每条流也都有触发器调得起来。</Clear>
) : (
<div className="g-todo">
{draftBad.map((p) => (
<Todo
key={`bad-${p.id}@${p.version}`}
tone="warn"
ico="git-merge"
title={`${p.name} v${p.version} · 闭合校验未过`}
desc={
(reportOf(p.id, p.version)?.violations ?? []).map((v) => v.message).join(';') ||
'存在未通过闭合校验的声明'
}
acts={[
{ label: '去编排', ico: 'route', onClick: () => nav.push({ k: 'pkg', id: `${p.id}@${p.version}` }) },
]}
/>
))}
{missingActivities.map((id) => (
<Todo
key={`miss-${id}`}
tone="danger"
ico="boxes"
title={`编排引用了未安装的活动:${id}`}
desc="图上画得通,运行时长不出任务 —— 去活动库把它装上,或在编排里换一个已装的活动。"
acts={[{ label: '去活动库', ico: 'boxes', onClick: () => nav.jump('library', 'shelf') }]}
/>
))}
{uncalled.map((id) => (
<Todo
key={`uncalled-${id}`}
tone="warn"
ico="zap"
title={`${packages.find((p) => p.id === id)?.name ?? id} 没有任何调起规则`}
desc="流程定义完整,但没人调得起来 —— 给它配一条周期 / 事件 / 登记触发器。"
acts={[{ label: '去配规则', ico: 'zap', onClick: () => nav.jump('workflows', 'rules') }]}
/>
))}
</div>
)}
</Sec>
<Sec ico="route" title="从这里进四库" extra="每库一页:定义在库里改,缺口在上面看">
<div className="g-entries">
<Entry
ico="workflow"
title="流程包 · 企业以哪些流转运转"
desc="五要素编排、版本谱系、边映射校验;调起规则也在本区"
onClick={() => nav.jump('workflows', 'pkgs')}
/>
<Entry
ico="boxes"
title="活动库 · 每件事怎么干"
desc="已安装活动的资产货架:契约面、范式、两条版本序列"
onClick={() => nav.jump('library', 'shelf')}
/>
<Entry
ico="wrench"
title="工具箱 · 系统能对世界做什么"
desc="读类过程中自由调用,写类只登记动作意向、放行后落地"
onClick={() => nav.jump('tools', 'catalog')}
/>
<Entry
ico="database"
title="数据域 · 企业运营什么"
desc="域与对象的结构定义;行数据在运营中心的台账看"
onClick={() => nav.jump('data', 'domains')}
/>
</div>
</Sec>
</>
);
}