三面拆分⑫:UI 打磨 —— 补 10 枚缺失图标,蓝图改因果链,台账收成一个模块

图标注册表缺 arrow-left-right/columns/table/tag 等 10 名,用到即渲染成空 SVG —— 补齐;
蓝图四库改真箭头相连的因果链节点卡(卡即入口,删重复的入库段);
驾驶舱终态分布改五色堆叠条;运营数据收成左轨一枚「台账」,域下沉为 2-3 字短名页签
(受理→寻源→定价→议价→替代→共享,按流程序),进模块自动落首域。

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 22:02:49 +08:00
co-authored by Claude Fable 5
parent 4a19690389
commit 34e207c3e8
11 changed files with 266 additions and 170 deletions
@@ -10,6 +10,7 @@
import { useState } from 'react';
import { TERMINAL_STATE_LABEL } from '@contracts';
import type { TerminalState } from '@contracts';
import { Ico } from '@web-shared/Ico.tsx';
import { Chip, Clear, Kpi, NList, NRow, Note, PageHead, QueryGate, Todo } from '@web-shared/gov/primitives.tsx';
import type { Nav } from '@web-shared/gov/gov-route.ts';
import {
@@ -25,6 +26,15 @@ export type HomeProps = { tab: string; nav: Nav };
const pct = (v: number | undefined) => Math.round((v ?? 0) * 100);
/** 终态五名的呈现色 —— 放行绿、驳回琥珀、停滞灰、耗尽红、终止墨,与状态章同族 */
const TERMINAL_TONE: Readonly<Record<string, string>> = {
released: 'var(--ok-accent)',
blocked: 'var(--warn-accent)',
stalled: '#8f959e',
exhausted: 'var(--danger-accent)',
terminated: '#41464e',
};
/* ---------------- 经营驾驶舱(运营首页) ---------------- */
/**
@@ -119,18 +129,35 @@ export function CockpitHome({ nav }: HomeProps) {
unit="tok"
sub={`每放行一单:${(m?.unitCost.minutes ?? 0).toFixed(1)} 分钟 · 调人 ${(m?.unitCost.humanCalls ?? 0).toFixed(1)} 次`}
/>
<Kpi
ico="flag"
label="终态分布"
value={mixTop.length === 0 ? '—' : `${pct(mixTop[0]![1])}%`}
sub={
mixTop.length === 0
? '还没有任务落终态'
: mixTop
.map(([k, v]) => `${TERMINAL_STATE_LABEL[k as TerminalState] ?? k} ${pct(v)}%`)
.join(' · ')
}
/>
{/* 终态分布:比例即信息 —— 五终态五色一条,不把五个百分比塞进一行小字 */}
<div className="g-kpi">
<span className="g-kpi-l">
<Ico name="flag" s={12} />
终态分布
</span>
{mixTop.length === 0 ? (
<>
<span className="g-kpi-v">—</span>
<span className="g-kpi-s">还没有任务落终态</span>
</>
) : (
<>
<span className="g-mixbar">
{mixTop.map(([k, v]) => (
<i key={k} style={{ width: `${pct(v)}%`, background: TERMINAL_TONE[k] ?? '#c9d2dd' }} />
))}
</span>
<span className="g-mixbar-legend">
{mixTop.map(([k, v]) => (
<span key={k}>
<i style={{ background: TERMINAL_TONE[k] ?? '#c9d2dd' }} />
{TERMINAL_STATE_LABEL[k as TerminalState] ?? k} <b>{pct(v)}%</b>
</span>
))}
</span>
</>
)}
</div>
</div>
<Note>
自主率与纠正率<b>成对读</b>,复合为有效自主率——单看自主率会奖励「猛冲后返工」。度量只是仪表,不载权力。