人手改的那一手真正落得下去;界面不撒谎那几处补齐
手改是**兜 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:
@@ -1,81 +1,137 @@
|
||||
/**
|
||||
* A4 成本定价的案例模型 —— **双表示同版本**:CMMN XML(机器面)与案例说明书(叙事面)。
|
||||
* A4 成本定价的案例模型 —— **算价归判定表,超限那一下归人**(2026-07-31 照 A1 的状态机模式重做)。
|
||||
*
|
||||
* 2026-07-29 由步序声明(flow)改写而来。原六步各归其位:取价基准与逐条定价属「算价」,
|
||||
* 偏离率与底价门禁属「自检」(两支 DMN:P-01 利润模型、P-02 底价门禁),
|
||||
* 超限条目调人决策是**触达客户利益的一下**,必须人工激活;末尾一张验收单。
|
||||
* 与 A2/A3 的分工:那两个是「一次专家判断」,派一张执行单收回结论就够了;
|
||||
* 定价不同 —— 它**有确定性规则可依**(P-01 利润模型、P-02 底价门禁两支 DMN),
|
||||
* 算价这件事该算不该问。所以它照 A1 的样子分步建模,而不是甩一张单给人。
|
||||
*
|
||||
* 三项:
|
||||
* T_price —— 逐条算价并落草案(拟报单价 / 毛利 / 偏离度 / 门禁处置);
|
||||
* T_approve —— **只在门禁判超限时入场**:触达客户利益的一下,人工激活,派决策卡;
|
||||
* T_release —— 放行(人工激活)。
|
||||
*
|
||||
* 「超限才叫人」是这个活动的要害:每条都叫人,人就成了橡皮图章;一条都不叫,
|
||||
* 底价门禁就是摆设。所以那一项挂前提(`s_over`),由判定表的结论决定它入不入场。
|
||||
*/
|
||||
|
||||
export const CMMN_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL">
|
||||
<case id="pricing">
|
||||
<!--
|
||||
案卷项的 id **就是任务视图里的键名**:
|
||||
draft_total 是草案条数(算完没算完),over_total 是超限条数(要不要叫人)。
|
||||
两个都由 T_price 写进台账,摊平到顶层后驱动前提。
|
||||
-->
|
||||
<caseFileModel>
|
||||
<caseFileItem id="records" name="待定价条目"/>
|
||||
<caseFileItem id="basis" name="取价基准"/>
|
||||
<caseFileItem id="draft" name="报价草案"/>
|
||||
<caseFileItem id="floors" name="底价表"/>
|
||||
<caseFileItem id="pn" name="型号(开案即有)"/>
|
||||
<caseFileItem id="draft_total" name="草案条数"/>
|
||||
<caseFileItem id="over_total" name="超限条数"/>
|
||||
</caseFileModel>
|
||||
<casePlanModel id="plan" name="成本定价" autoComplete="true">
|
||||
<sentry id="s_records">
|
||||
<onPart id="op_rc" caseFileItemRef="records"><standardEvent>create</standardEvent></onPart>
|
||||
</sentry>
|
||||
<sentry id="s_basis">
|
||||
<onPart id="op_bs" caseFileItemRef="basis"><standardEvent>create</standardEvent></onPart>
|
||||
</sentry>
|
||||
<sentry id="s_priced">
|
||||
<onPart id="op_pd" caseFileItemRef="draft"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_pd"><condition>unpriced = 0</condition></ifPart>
|
||||
<onPart id="op_pr" caseFileItemRef="draft_total"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_pr"><condition>draft_total > 0</condition></ifPart>
|
||||
</sentry>
|
||||
<sentry id="s_breach">
|
||||
<onPart id="op_br" caseFileItemRef="draft"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_br"><condition>breaches > 0</condition></ifPart>
|
||||
<!-- 超限才叫人:门禁判出有超限条目,这一项才入场 -->
|
||||
<sentry id="s_over">
|
||||
<onPart id="op_ov" caseFileItemRef="over_total"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_ov"><condition>over_total > 0</condition></ifPart>
|
||||
</sentry>
|
||||
|
||||
<stage id="S1" name="算价" autoComplete="true">
|
||||
<entryCriterion id="ec_s1" sentryRef="s_records"/>
|
||||
<humanTask id="T_basis" name="人工取价基准">
|
||||
<itemControl><manualActivationRule id="m_bs"/></itemControl>
|
||||
</humanTask>
|
||||
<decisionTask id="D_price" name="逐条定价" decisionRef="p01-margin">
|
||||
<entryCriterion id="ec_price" sentryRef="s_basis"/>
|
||||
</decisionTask>
|
||||
</stage>
|
||||
<milestone id="M_priced" name="全条已定价"/>
|
||||
|
||||
<stage id="S2" name="自检" autoComplete="true">
|
||||
<entryCriterion id="ec_s2" sentryRef="s_priced"/>
|
||||
<decisionTask id="D_floor" name="底价门禁" decisionRef="p02-floor"/>
|
||||
<humanTask id="T_breach" name="人工裁超限条目(回调还是注明理由)">
|
||||
<entryCriterion id="ec_breach" sentryRef="s_breach"/>
|
||||
<itemControl><manualActivationRule id="m_br"/><repetitionRule id="r_br"/></itemControl>
|
||||
</humanTask>
|
||||
<planningTable id="pt_s2">
|
||||
<humanTask id="T_refresh_floor" name="人工刷新底价"/>
|
||||
</planningTable>
|
||||
</stage>
|
||||
<milestone id="M_gated" name="门禁已过"/>
|
||||
|
||||
<humanTask id="T_release" name="人工报价草案验收放行">
|
||||
<itemControl><manualActivationRule id="m_rl"/></itemControl>
|
||||
<!-- 算价:判定表说了算,不是临场判 -->
|
||||
<humanTask id="T_price" name="逐条算价:取基准、算毛利与偏离度、过底价门禁">
|
||||
<itemControl><repetitionRule id="r_pr"/></itemControl>
|
||||
</humanTask>
|
||||
|
||||
<timerEventListener id="TL_half" name="时限过半">
|
||||
<timerExpression>PT8H</timerExpression>
|
||||
</timerEventListener>
|
||||
<!-- 超限审批:触达客户利益的一下,必须人工激活 -->
|
||||
<humanTask id="T_approve" name="超限条目决策:低于底价的那几条要人拍板">
|
||||
<entryCriterion id="ec_ap" sentryRef="s_over"/>
|
||||
<itemControl><manualActivationRule id="m_ap"/><repetitionRule id="r_ap"/></itemControl>
|
||||
</humanTask>
|
||||
|
||||
<!-- 放行:触达世界,必须人工激活 -->
|
||||
<humanTask id="T_release" name="报价草案验收放行">
|
||||
<entryCriterion id="ec_rel" sentryRef="s_priced"/>
|
||||
<itemControl><manualActivationRule id="m_rl"/></itemControl>
|
||||
</humanTask>
|
||||
</casePlanModel>
|
||||
</case>
|
||||
</definitions>`;
|
||||
|
||||
export const NARRATIVE = `§0 开案:拿到一批待定价条目即开案。成品是**一份全条目带偏离度的报价草案** ——
|
||||
每条有拟报单价与毛利率,且都过了底价门禁。
|
||||
人签的不是一个数字,是**这个数字的来路**:基准从哪来、毛利怎么算、偏离多少、门禁怎么判。
|
||||
|
||||
S1 算价:先取价基准(历史成交价 / 供应商回价 / 替代料对标价,按可得性择优),
|
||||
再按利润模型 P-01 逐条定价 —— 客户等级、数量档、料号类型、行情共同决定加价率。
|
||||
基准取不到的条目不许拍脑袋定价,回头找寻源或标注「无基准」。
|
||||
**能算的不问人**:P-01(利润模型)与 P-02(底价门禁)两支判定表说了算,你不临场拍价。
|
||||
你的活是把判据取齐、把结论落进台账;**只有超限的那几条才叫人**。
|
||||
|
||||
S2 自检:算出偏离度(基准价 ↔ 拟报价),按底价门禁 P-02 逐条判。
|
||||
**偏离 ±20% 以内自动放过;超限的一律调人** —— 要么回调价格,要么写明为什么这样报。
|
||||
底价超一周没更新的先刷底价再判(裁量项),拿旧底价判新行情等于没判。
|
||||
【T_price 逐条算价】基准价取自历史价情报(A3 的比价结论 / CRM 历史价)。新料号无历史时
|
||||
基准记 0,由底价门禁按「无基准」处置 —— **不凭空编一个偏离率出来**。
|
||||
逐条写进 \`quote_pricing.draft\`:拟报单价 / 目标毛利 / 相对基准偏离 / 门禁处置。
|
||||
同一拍接着把 draft_total(条数)与 over_total(门禁判「超限」的条数)写上 ——
|
||||
这两个数一个是完成判据,一个决定要不要叫人。写完 finish。
|
||||
|
||||
§Z 结案:每条都有拟报单价与毛利率、超限条目已处置、BD 签字放行,自动结案。
|
||||
草案交出去就是下游议价的起点 —— 它不是最终报价,但每一条都要经得起问「为什么是这个价」。`;
|
||||
【T_approve 超限决策】**只在 over_total > 0 时走这一步**。它触达客户利益,
|
||||
所以标了人工激活:**先 start,再发决策卡**(decide,itemId 填 T_approve)。
|
||||
选项按门禁的处置给(照原价报 / 按底价报 / 退回重算),consequence 写清各自的后果;
|
||||
basis 摆上是哪几条、偏离多少、底价是多少(裸卡基座拒发)。
|
||||
人点完,轨迹上会出现「decision 卡回传 —— 人选了:xxx」—— **看到它就照那条路把 draft 改掉**,
|
||||
别再发第二张卡。改完 finish。
|
||||
|
||||
【提交放行】草案有行了 —— **先 start T_release**(人工激活),然后 submit,BD 验收。
|
||||
提交前把两条裁量判据裁掉(judge,criterion 照判据名原样写);终局唯放行,你不能自己宣布完成。
|
||||
|
||||
【一路上要说话】每一拍带一句 say,说**业务的话**:这批料算下来什么价、哪几条压线、
|
||||
要不要找人拍板。一两句、口语。别报「写草稿 N 行」这种系统词。`;
|
||||
|
||||
/**
|
||||
* 步骤剧本 —— 与 A1 同一套:`doneWhen` 为真,引擎自己收步、**不问模型**。
|
||||
*
|
||||
* 两处不给 `doneWhen`:`T_approve`(人工激活,要人拍板)与 `T_release`(触达世界)。
|
||||
* 给了就等于给引擎一把替人签字的钥匙。
|
||||
*/
|
||||
export const PRICING_STEPS = [
|
||||
{
|
||||
item: 'T_price',
|
||||
intent: '逐条算价并落草案:拟报单价 / 毛利 / 偏离度 / 门禁处置,并结算条数与超限数',
|
||||
writes: ['quote_pricing.draft', 'quote_pricing.verdict'],
|
||||
reads: [],
|
||||
tools: [],
|
||||
// 草案有行了才算算完。不写 `!= null` —— 未绑定的名字那样求值为 true(A1 踩过)
|
||||
doneWhen: 'draft_total > 0',
|
||||
guide: `基准价取自历史价情报(A3 的比价结论 / CRM 历史价)。新料号无历史时基准记 0,
|
||||
由底价门禁按「无基准」处置 —— **不凭空编一个偏离率**。
|
||||
逐条写进 \`quote_pricing.draft\`:拟报单价 / 目标毛利 / 相对基准偏离 / 门禁处置。
|
||||
**同一拍接着**把 draft_total 与 over_total(门禁判超限的条数)写上 ——
|
||||
前者是完成判据,后者决定要不要叫人。
|
||||
**同一拍再写一行 \`quote_pricing.verdict\`**(验收机检读的就是它):
|
||||
· draft_total / unpriced_total = 草案条数 / 还没定出价的条数(后者要 = 0);
|
||||
· over_total = 门禁判超限的条数;
|
||||
· unresolved_over_total = 超限里**还没处置**的条数(要 = 0 —— 回调了或注明了理由都算已处置);
|
||||
· summary 一句人话结论。写不对 submit 会被门挡回来。三笔写完再 finish。
|
||||
**每一行都要带 \`rfq_ref\`** —— 它是这一单的单标识(起单入参里就有,原样抄进去)。
|
||||
台账主键第一列就是它:不写,这一行会和**别的单**同料号的那一行撞主键,把人家覆盖掉
|
||||
(实测栽过:A4 的报价草案主键只有 pn,跑四轮只剩最后一轮的 3 行)。`,
|
||||
},
|
||||
{
|
||||
item: 'T_approve',
|
||||
intent: '超限条目要人拍板 —— 发决策卡,照人选的那条路改草案',
|
||||
writes: ['quote_pricing.draft'],
|
||||
reads: [],
|
||||
tools: [],
|
||||
// 人工激活 + 要人拍板 —— 不给 doneWhen,引擎不许替人收
|
||||
guide: `**只在 over_total > 0 时走这一步**。它触达客户利益,标了人工激活:
|
||||
**先 start T_approve**(与发卡排同一拍即可),再发决策卡(decide,itemId 填 T_approve)。
|
||||
选项按门禁处置给(照原价报 / 按底价报 / 退回重算),consequence 写清后果;
|
||||
basis 摆上哪几条、偏离多少、底价多少(**裸卡基座拒发**)。
|
||||
人点完轨迹上会出现「decision 卡回传 —— 人选了:xxx」,**照那条路改 draft,别再发第二张卡**。`,
|
||||
},
|
||||
{
|
||||
item: 'T_release',
|
||||
intent: '草案已齐,提交放行交 BD 验收',
|
||||
writes: [],
|
||||
reads: [],
|
||||
tools: [],
|
||||
guide: `草案有行了 —— **先 start T_release**(人工激活),提交前用 judge 裁掉裁量判据
|
||||
(criterion 照判据名原样写),然后 submit。终局唯放行:你不能自己宣布完成。`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -11,7 +11,6 @@ const DRAFT = 'quote_pricing.draft';
|
||||
|
||||
export default defineActivity({
|
||||
name: 'quote-pricing',
|
||||
paradigm: 'flow',
|
||||
|
||||
async run(base: ActivityBase): Promise<ActivityOutcome> {
|
||||
const items = await base.ledger.read(DRAFT);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
import type { ActivityManifest, DmnModel } from '@contracts';
|
||||
import { PRICING_SKILLS } from './skills.ts';
|
||||
import { CMMN_XML, NARRATIVE } from './case-model.ts';
|
||||
import { CMMN_XML, NARRATIVE, PRICING_STEPS } from './case-model.ts';
|
||||
import { activityIdSchema } from '@contracts';
|
||||
import { PRICING_BASIS, PRICING_PRICED, PRICING_RELEASE } from './views/report.ts';
|
||||
|
||||
@@ -62,7 +62,7 @@ export const manifest: ActivityManifest = {
|
||||
identity: {
|
||||
activityId: ACTIVITY_ID,
|
||||
name: 'A4 · 成本定价',
|
||||
packageVersion: '0.1.6',
|
||||
packageVersion: '2.0.0',
|
||||
category: '统一报价',
|
||||
sdkVersion: '0.1.0-m5',
|
||||
checksum: 'dev-checksum-quote-pricing',
|
||||
@@ -74,8 +74,9 @@ export const manifest: ActivityManifest = {
|
||||
input: {
|
||||
data: {
|
||||
type: 'object',
|
||||
required: ['customerCode', 'records'],
|
||||
required: ['rfqRef', 'customerCode', 'records'],
|
||||
properties: {
|
||||
rfqRef: { type: 'string', title: '询价单号(单标识,贯穿全流程)' },
|
||||
customerCode: { type: 'string' },
|
||||
records: { type: 'array' },
|
||||
// B/C 类由 A3/A2 交回的底价与替代方案;A 类直通时为空
|
||||
@@ -90,21 +91,36 @@ export const manifest: ActivityManifest = {
|
||||
name: 'draft',
|
||||
payload: {
|
||||
type: 'object',
|
||||
required: ['items'],
|
||||
properties: { items: { type: 'array' } },
|
||||
required: ['rfqRef', 'items'],
|
||||
properties: { rfqRef: { type: 'string' }, items: { type: 'array' } },
|
||||
},
|
||||
description: '报价草案(逐条带偏离度)',
|
||||
},
|
||||
],
|
||||
selective: [],
|
||||
},
|
||||
requiredDeliverables: [{ key: 'quote-draft', label: '报价草案(全条目带偏离度)' }],
|
||||
/*
|
||||
* 必交付物**必须给 `ledger` 地址**(2026-07-31 修)。
|
||||
* 不给的话预检退回 `scope[key]` 去找 —— key 是 `benchmark-table` 这样的短横线别名,
|
||||
* 任务视图里永远没有这个键,于是「必交付物缺一不得提交放行」永远拒,
|
||||
* 活办完了也放不了行,连拒五拍熔断(实测 A2 死于此)。
|
||||
*/
|
||||
requiredDeliverables: [
|
||||
{ key: 'quote-draft', label: '报价草案(全条目带偏离度)', ledger: `${DOMAIN}.draft` },
|
||||
],
|
||||
/*
|
||||
* 机检谓词读的是 `verdict` 那张**汇总表**的列(照 A1 的口径)。
|
||||
* 上一版的名字(unpriced;floor-gate 更是连谓词都没有)**台账里根本没有** —— S-FEEL 拿未绑定的名字
|
||||
* 比大小求值为假,判据永远达不了标,submit 门永远拒,连拒五拍熔断。
|
||||
* 判据的名字必须落在台账上,否则「机检」是一句空话(2026-07-31 销账)。
|
||||
*/
|
||||
acceptanceCriteria: [
|
||||
{ key: 'all-priced', label: '每条都有拟报单价与毛利率', level: 'L1', predicate: 'unpriced = 0' },
|
||||
{ key: 'all-priced', label: '每条都有拟报单价与毛利率', level: 'L1', predicate: 'unpriced_total = 0' },
|
||||
// 底价门禁沉为 L2 机检 —— 「约束力收缩」的终点
|
||||
{ key: 'floor-gate', label: '偏离底价 ≤±20%,超限者已回调或注明理由', level: 'L2', modelRef: 'p02-floor' },
|
||||
{ key: 'floor-gate', label: '偏离底价 ≤±20%,超限者已回调或注明理由', level: 'L2', modelRef: 'p02-floor', predicate: 'unresolved_over_total = 0' },
|
||||
{ key: 'pm-release', label: 'BD 放行', level: 'L5' },
|
||||
],
|
||||
revisableAtRelease: [],
|
||||
prohibitions: [
|
||||
{ key: 'no-silent-override', statement: '不得静默绕开 P-02 的结论;要破线只能走「人 · 决策」' },
|
||||
{ key: 'no-stale-floor', statement: '底价超一周未更新的,先刷底价再判' },
|
||||
@@ -115,7 +131,13 @@ export const manifest: ActivityManifest = {
|
||||
humanCallBudget: 3,
|
||||
},
|
||||
resources: {
|
||||
tools: [{ name: 'quote-pricing.basis' }, { name: 'crm.history-price-read' }],
|
||||
/*
|
||||
* `quote-pricing.basis` 已从声明里去掉(2026-07-31):工具箱里从没注册过它,
|
||||
* 装包时静态审一直报「运行时转人代办」—— 而重做后的案例模型压根不调它
|
||||
* (算价归判定表 P-01/P-02,取基准读历史价)。声明一件不存在也不用的工具,
|
||||
* 只会让每一单跑到 A4 就弹一张莫名其妙的转人卡。
|
||||
*/
|
||||
tools: [{ name: 'crm.history-price-read' }],
|
||||
skills: PRICING_SKILLS.map((s) => s.id),
|
||||
models: ['deepseek-v4-flash'],
|
||||
roles: ['BD'],
|
||||
@@ -125,13 +147,16 @@ export const manifest: ActivityManifest = {
|
||||
|
||||
declarations: {
|
||||
models: ['deepseek-v4-flash'],
|
||||
tools: [{ name: 'crm.history-price-read' }, { name: 'quote-pricing.basis' }],
|
||||
tools: [{ name: 'crm.history-price-read' }],
|
||||
ledger: [
|
||||
{
|
||||
domain: DOMAIN,
|
||||
object: 'draft',
|
||||
kind: 'record',
|
||||
caseKey: 'rfq_ref',
|
||||
label: '报价草案',
|
||||
fields: [
|
||||
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
||||
{ name: 'pn', type: 'text', primaryKey: true, masked: false, label: 'PN' },
|
||||
{ name: 'quoted_price', type: 'number', primaryKey: false, masked: false, label: '拟报单价' },
|
||||
{ name: 'margin', type: 'number', primaryKey: false, masked: false, label: '毛利率' },
|
||||
@@ -140,6 +165,27 @@ export const manifest: ActivityManifest = {
|
||||
{ name: 'disposition', type: 'text', primaryKey: false, masked: false, label: '门禁处置' },
|
||||
],
|
||||
},
|
||||
{
|
||||
/*
|
||||
* 定价结论 —— 一单一行的**汇总表**,验收机检谓词的入参就在这儿。
|
||||
* 汇总列与逐行列**故意不同名**:任务视图把草稿行摊平到顶层是「后写的赢」,
|
||||
* 拿逐行列求值只会验到最后写的那一行,那不叫机检、叫抽样(A1 的教训)。
|
||||
*/
|
||||
domain: DOMAIN,
|
||||
object: 'verdict',
|
||||
kind: 'record',
|
||||
caseKey: 'rfq_ref',
|
||||
label: '定价结论',
|
||||
fields: [
|
||||
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
||||
{ name: 'pn', type: 'text', primaryKey: false, masked: false, label: '型号' },
|
||||
{ name: 'draft_total', type: 'integer', primaryKey: false, masked: false, label: '草案条数' },
|
||||
{ name: 'unpriced_total', type: 'integer', primaryKey: false, masked: false, label: '未定价条数' },
|
||||
{ name: 'over_total', type: 'integer', primaryKey: false, masked: false, label: '超限条数' },
|
||||
{ name: 'unresolved_over_total', type: 'integer', primaryKey: false, masked: false, label: '超限未处置条数' },
|
||||
{ name: 'summary', type: 'text', primaryKey: false, masked: false, label: '定价结论' },
|
||||
],
|
||||
},
|
||||
],
|
||||
listeners: [
|
||||
{
|
||||
@@ -166,6 +212,8 @@ export const manifest: ActivityManifest = {
|
||||
cmmnXml: CMMN_XML,
|
||||
narrative: NARRATIVE,
|
||||
dmn: P01_DMN,
|
||||
/* 步骤剧本 —— 与 A1 同一套:doneWhen 真了引擎自己收步,不问模型 */
|
||||
steps: PRICING_STEPS,
|
||||
},
|
||||
skills: PRICING_SKILLS,
|
||||
viewTemplates: [
|
||||
|
||||
@@ -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、留痕关联,' +
|
||||
'不复活旧任务。所以这一屏上还改得动的每一格,过了这道门就要花一整个新实例才改得回来。',
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user