三面拆分⑤:企业蓝图首页 —— 四库因果链与待补清单(闭合/缺活动/无调起)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -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 { useGovObjects, useGovTasks } from '@web-shared/gov/gov-api.ts';
|
||||
import { queryKeys } from './query.ts';
|
||||
import { BlueprintHome } from '@features/gov-blueprint';
|
||||
import { TasksHome, TaskLogPage, TaskPage, WfPage } from '@features/gov-task';
|
||||
import { EmpPage, PeopleHome, RolePage } from '@features/gov-staff';
|
||||
import { EdgesPage, PkgPage, WorkflowsHome } from '@features/gov-process';
|
||||
@@ -317,16 +318,6 @@ function LedgerRail({
|
||||
);
|
||||
}
|
||||
|
||||
/** 企业蓝图 —— Task 6 接真;在那之前先给设计者一句「这里将有什么」 */
|
||||
function BlueprintPlaceholder() {
|
||||
return (
|
||||
<Note>
|
||||
这里将把四库串成一条因果链:流程包(战略)→ 活动库(方法)→ 工具箱(能力)→ 数据域(对象),
|
||||
并把「哪里还没定义完」聚成一张待补清单。先从左轨进各库编排。
|
||||
</Note>
|
||||
);
|
||||
}
|
||||
|
||||
/** 台账 —— Task 10 接真;导航项已随数据域长出来了,内容随后 */
|
||||
function LedgersPlaceholder() {
|
||||
return <Note>这里将按域列出全部台账对象、行数据与版本。域的结构在设计中心 · 数据域维护。</Note>;
|
||||
@@ -335,7 +326,7 @@ function LedgersPlaceholder() {
|
||||
function ZoneHome({ zone, tab, nav }: { zone: GovZone; tab: string; nav: Nav }) {
|
||||
const P = {
|
||||
// 设计中心
|
||||
blueprint: BlueprintPlaceholder,
|
||||
blueprint: BlueprintHome,
|
||||
workflows: WorkflowsHome,
|
||||
library: LibraryHome,
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user