人手改的那一手真正落得下去;界面不撒谎那几处补齐

手改是**兜 AI 的错**的那一手 —— 这一轮把它从「摆在那儿但落不了地」做成真的:

件上就地改
· 保存**按地址收**,不看当下那张卡:载荷从前借道工单的 `blocks[i]` 取列名,
  于是熔断卡(没有 blocks)在屏上时,人补的那一格一个字都送不出去 ——
  而他要补的恰恰是把这一单卡住的那个必填格。授权面改由活动清单的台账声明把关。
· **能增删行**:错不止「这一格填错了」,还有「这一行不该在」与「漏了一行」。
  删挂记号不当场抹掉(看得见、可后悔),且**删要说出来**(`drops`)——
  「没回传就是删了」会把一次不完整的回传变成一次删表。
· **必填没填按不下提交**:与放行门 L1 同一个数同一套算法;闸上摆出差在哪一行哪一格。
· 只写真改了的那几行 —— 改一格却留「修订 4 行」的痕,那句话是假的。

判据与门
· 裁量判据带谓词时**谓词说了算**:「选填缺口已补齐」基座数得出来,
  人填好的目标价它照样判「客户未提供」的毛病由此消掉。
· 验收卡判据**读时现算** —— 人在成果件上补一格,判据跟着变。
· 放行门认「**办完了没有**」不认「有人写过」:从前写个 `false` 就把门推开,
  于是一单没打标就进了放行门。三个数全由基座现数。
· 拒回把「活没干完」说成「数或行对不上」的毛病:判据点名的表一行都没写时直说那一步没办。
  **指向两扇打不开的门,比不指还糟。**

界面不撒谎
· 日志只有三色:负责人绿 · 智能体蓝 · 系统灰(归侧五种是度量的分法,不是给人看的)。
· 验收收口答两件事:落了什么(按**交付物**点名,一份成果的几张表并成一行)、
  往哪儿去(转出哪一口、带过去哪些字段);一个口都没发就直说到此为止。
· 签完到收尾之间那一段有自己的话「字已签下,正在落地」—— 中间态本来就该说出来,只是要说对。
· 消息不再被内部事件刷屏:只有从通道进来的件才谈得上「无人认领」。
· 建客户公司与联系人**一次确认落两行**;联系人编码自增不问人;卡面摆表的人读名。

A1 三案例端到端全 released:全 A 类直通 12 拍 / 客户点名跳一条 10 拍 / 新客户缺必填 14 拍。
五道门禁全绿(971 passed)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
This commit is contained in:
2026-08-02 13:41:44 +08:00
co-authored by Claude Opus 5
parent 94f1c7a4ef
commit 259192f736
228 changed files with 27850 additions and 2847 deletions
+164 -39
View File
@@ -1,67 +1,192 @@
/**
* A4 视图模版 —— 定价的三屏:取价基准 / 定价与门禁 / 报价草案待放行(AM 07)。
* 定价这件事最需要「把判据摊开」:人签的不是一个数字,是这个数字的来路。
* A4 成本定价的 HTML 报告模版 —— **活动自己持有的资产**(§10.3),随包版本冻结。
*
* 定价这件事最需要「把判据摊开」:**人签的不是一个数字,是这个数字的来路**。
* 所以三张屏不按「概览 / 明细 / 结论」排,按**一个价是怎么长出来的**排:
* ① 取价基准 —— 跟谁比。基准取错,后面每一条偏离率都是假的,而假偏离率长得跟真的一样;
* ② 定价与底价门禁 —— 凭什么是这个价。两张决策表的规则原样摆出来,人能逐条倒着核;
* ③ 报价草案待放行 —— 签字前最后一次能改的机会,门后的都算数了。
*
* 一个局面一张,局面变了让 Agent 用 `view` 换,不在一张里堆条件分支。
* 容器是 `sandbox=""` iframe:无脚本、无外链、样式自带;数据由基座推送时填
* (`data-slot` 取值、`data-rows` 逐行展开)。
*
* 两条贯穿全包的呈现纪律:
* · **状态章一律用「在办」灯,不用「已办」印** —— 模版是随包冻结的静态字符串,
* 它盖不了一个还没发生的章。三张屏都是放行前的局面,盖「已通过」就是撒谎;
* · **`verdict` 的橙档专指「还没发生,等你按」** —— 绿只留给已达标的机检结论。
* 放行后果是预告不是既成事实,一律走橙档。
*/
import { kvCard, noteCard, tableCard, viewShell } from '@sdk';
import { noteOnly, section, stagesOnly, statsBand, tableOnly, verdict, viewShell } from '@sdk';
/**
* 静态阶梯 —— **规则本身不是数据**:P-01 的毛利档、P-02 的三档处置随包冻结,
* 它们不该走 `data-rows` 等基座来填(那会让「规则」看起来像「这一单的结果」)。
* 沿用外壳已有的 `.steps` 版式,与引擎推的阶段列表同一副面孔 —— 页面上只该有一套样式。
*/
function ladder(rows: ReadonlyArray<readonly [string, string, string]>): string {
return `<ul class="steps">${rows
.map(
([no, term, gloss]) =>
`<li><span class="n">${no}</span><span><span class="t">${term}</span> <span class="d">${gloss}</span></span></li>`,
)
.join('')}</ul>`;
}
/** 局面一:S1 算价刚开场 —— 人此刻要核的是「这一单跟谁比、落在哪一档」 */
export const PRICING_BASIS = viewShell({
title: '取价基准',
kicker: 'A4 · 成本定价',
kicker: 'A4 · 成本定价 · S1 算价',
tone: 'brand',
icon: 'coins',
stamp: { kind: 'live', text: '算价中' },
sign: 'A4 成本定价 · 取价基准(本单草稿)',
body:
kvCard('本单标的', [
['客户编码', 'customerCode', 'mono'],
['型号 PN', 'pn', 'mono'],
['物料类型', 'materialType', 'tag'],
]) +
kvCard('价格基准', [
['上次成交价', 'last_price'],
/*
* 指标带摆的是**利润模型 P-01 的三个入参 + 这一单的工作量**,不是所有字段。
* 三个档位键取的是清单里 P-01 声明的决策入参名(customerGrade / materialType /
* volumeTier)—— 决策表照这三个名字取值,模版就照这三个名字摆,不另起炉灶。
* `records` 是起单入参的数组,基座渲染数组时给的是条数,正好是「这一单要定几条价」。
*/
statsBand([
['待定价条目', 'records'],
['客户等级', 'customerGrade'],
['料号类型', 'materialType'],
['数量档', 'volumeTier'],
]) +
noteCard('基准从哪来', '基准价取自历史价情报(CRM)。新料号无历史时基准记 0,由底价门禁按<b>无基准</b>处置 —— 不凭空编一个偏离率出来。'),
section('基准从哪来 —— 四级优先级',
ladder([
['1', '本客户近期成交价', '最贴近这一单的真实议价空间'],
['2', '同型号他客户成交价', '价位可比,但议价空间要留余量'],
['3', '供应商底价表', '成本侧的锚,不含客户侧信息'],
['4', '无基准', '新料号、久未报价的老料号都会落到这里'],
]) +
noteOnly(
'<b>无基准不是异常,它本身就是一种基准。</b>此时偏离率记 0 —— 没有可偏离的对象,' +
'由底价门禁按「无基准」处置。不要拿一个不相干的价去凑一个偏离率出来:' +
'那比没有基准更危险,因为它<b>看起来像有依据</b>。',
),
{ text: '越靠前越贴近实情' },
) +
section('本单待定价条目',
tableOnly('mine:quote_pricing.draft', [
['型号 PN', 'pn', 'mono'],
['基准价', 'last_price'],
['拟报单价', 'quoted_price'],
['毛利率', 'margin'],
]),
{ text: '只列本单写下的行' },
) +
section('案例当下进程', stagesOnly('case:stages'), { text: 'Enabled ≠ Active' }),
});
/** 局面二:S2 自检 —— 人此刻要核的是「凭什么是这个价、门禁怎么判的」 */
export const PRICING_PRICED = viewShell({
title: '定价与底价门禁',
kicker: 'A4 · DMN 两表',
tone: 'ok',
kicker: 'A4 · 成本定价 · S2 自检',
tone: 'brand',
icon: 'gauge',
stamp: { kind: 'live', text: '自检中' },
sign: 'A4 成本定价 · 定价自检(判定表 P-01 / P-02)',
body:
kvCard('定价结论', [
/* 标签一律照台账声明的列名(基准价 / 拟报单价 / 毛利率 / 偏离度 / 门禁处置):
同一个数在指标带上叫一个名、在下面的表里叫另一个名,签字的人就得先花一秒确认它俩是不是一回事 */
statsBand([
['基准价', 'last_price'],
['拟报单价', 'quoted_price'],
['目标毛利', 'margin'],
['相对基准偏离', 'deviation'],
['门禁处置', 'disposition', 'tag'],
['毛利率', 'margin'],
['偏离度', 'deviation'],
]) +
noteCard(
'两张决策表各管一段',
'<b>利润模型 P-01</b>:客户等级 × 物料类型 × 数量档 → 目标毛利区间。' +
'<b>底价门禁 P-02</b>:偏离底价 ±20% 即止 —— 超限的不是「拦下」,而是转人裁断(回调还是注明理由)。' +
'两表都是确定性求值,同输入必同结论;命中的规则行随出参留痕,事后可逐条复盘。',
section('逐条定价结论',
tableOnly('mine:quote_pricing.draft', [
['型号 PN', 'pn', 'mono'],
['基准价', 'last_price'],
['拟报单价', 'quoted_price'],
['毛利率', 'margin'],
['偏离度', 'deviation'],
['门禁处置', 'disposition'],
]),
{ text: '判据在左 · 结论在右' },
) +
section('目标毛利怎么定的 —— 利润模型 P-01',
ladder([
['1', '战略客户 · A 类标准件 · 大批量', '目标毛利 8%–10%'],
['2', '普通客户 · A 类标准件', '12%–15%'],
['3', 'B 类波动件', '15%–20%'],
['4', 'C 类替代 / EOL', '≥20%,或一事一议'],
['5', '以上都不命中', '兜底按普通客户标准件 12%–15%'],
]) +
noteOnly(
'自上而下取<b>第一条命中</b>的规则,同输入必得同结论、零方差零 token,命中的规则行随出参留痕。' +
'不要为了让门禁「过」而回头改毛利参数 —— 那是把判据改成结论,决策表也就失去了它唯一的价值。',
),
{ text: '首条命中' },
) +
section('偏离怎么判的 —— 底价门禁 P-02',
ladder([
['1', '拟报价 ≥ 底价', '直接放行'],
['2', '低于底价 ≤ 20%', 'PM 附理由放行'],
['3', '低于底价 超 20%', '拦截 · BOSS 拍板'],
]) +
noteOnly(
'门禁不是「拦下」而是<b>分流</b>:超限的一律调人 —— 要么回调价格,要么写明为什么这样报,' +
'两条路都合法,但都要留下理由。这条留痕将来会成为客户等级与利润模型的迭代素材。',
),
{ text: '±20% 即止' },
) +
section('本单门禁结论',
/*
* 结论章里嵌 `data-slot`:处置与偏离都是**这一单算出来的事实**,
* 写死一句「已通过」就是替判定表下结论。橙档在此的意思是「还没定,等人处置」。
*/
verdict('底价门禁 P-02 处置:<b data-slot="disposition"></b>', 'wait', '偏离度 <b data-slot="deviation"></b>') +
noteOnly(
'禁区两条随本单同行:<b>不得静默绕开 P-02 的结论</b> —— 要破线只能走「人 · 决策」;' +
'<b>底价超一周未更新的,先刷底价再判</b> —— 拿旧底价判新行情等于没判。',
),
),
});
/** 局面三:待放行 —— 验收单上人要签的那份成果报告 */
export const PRICING_RELEASE = viewShell({
title: '报价草案 · 待放行',
kicker: 'A4 · 成果预览',
kicker: 'A4 · 成本定价 · 成果待签',
tone: 'case',
icon: 'shield-check',
stamp: { kind: 'live', text: '待签字放行' },
sign: 'A4 成本定价 · 报价草案(待放行)',
body:
tableCard(
'本单报价草案',
'mine:quote_pricing.draft',
[
['型号', 'pn', 'mono'],
statsBand([
['拟报单价', 'quoted_price'],
['毛利率', 'margin'],
['偏离度', 'deviation'],
['门禁处置', 'disposition'],
]) +
section('本单交付:报价草案',
tableOnly('mine:quote_pricing.draft', [
['型号 PN', 'pn', 'mono'],
['基准价', 'last_price'],
['拟报价', 'quoted_price'],
['毛利', 'margin'],
['偏离', 'deviation'],
['门禁', 'disposition'],
],
'逐条列出,便于放行前逐条核对。',
['拟报单价', 'quoted_price'],
['毛利率', 'margin'],
['偏离度', 'deviation'],
['门禁处置', 'disposition'],
]) +
noteOnly('只列<b>本单</b>写下的行 —— 别单放行过的记录不混进来。逐条列出,便于放行前逐条核对。'),
{ text: '本单草稿' },
) +
noteCard(
'放行之后',
'放行通过 → 草稿合并入正式版 → 进 <b>AP 定价审批</b>(卡到 PM 工位)。' +
'审批驳回按声明走向<b>回 A4 重开新实例</b> —— 新任务 ID、留痕关联,不复活旧任务。',
section('放行前要过的三道判据',
ladder([
['1', '每条都有拟报单价与毛利率', 'L1 机检 · unpriced = 0'],
['2', '偏离底价 ≤ ±20%,超限者已回调或注明理由', 'L2 机检 · 底价门禁 P-02'],
['3', 'BD 放行', 'L5 人签 · 签了才算数'],
]),
{ text: '两机检 · 一人签' },
) +
section('放行之后会发生什么',
verdict('放行即落地:草稿合并入正式版,草案提交 A5 定价审批', 'wait', '审批点卡在 PM 工位') +
noteOnly(
'审批驳回按<b>声明</b>走向,不由临场决定:<b>回 A4 重开新实例</b> —— 新任务 ID、留痕关联,' +
'不复活旧任务。所以这一屏上还改得动的每一格,过了这道门就要花一整个新实例才改得回来。',
),
),
});