设计中心加联调测试台:造入站邮件(带附件)投通道,看真结果
你要的「模拟输入邮件+附件触发起单」。后端**本来就齐了** —— `ingestMailRoute` 契约里早有 attachments,出参也早就回归属解析与三级消费结果。 所以这是纯前端加一个区:设计中心新增 `testbed`,一个页签「入站邮件」。 走的是与真通道**同一条**入站链路(通道归一 → 归属解析 → 统一事件流 → 三级消费)。 邮件通道是外界,模拟通道是 README 明许的;系统内部机制这里一行都不 mock —— 命中判定、起单、消息兜底全是真的。 ## 这一屏回答三个问题 投出去之后就摆三样:归属判到谁(哪一级命中 / 无主的原因 / 默认认领岗位)、 谁接了(任务监听 vs 触发器各命中几个)、没人接落哪儿(消息兜底)。 还有一格**起单前置自检**:投之前就告诉你会不会命中,不用投完了猜。 判据与真实配置同源 —— 通道 id、主题关键词、两个归属键正则,四条逐条给绿灯或说差什么。 预填的样例是一键能起单的那一封;把它改坏,自检立刻指出差哪条。 附件如实说明「只走**登记**」:名字/类型/大小/存证指针进事件信封,内容不解析 —— 解析 Excel/PDF 是活动的事,活动还没实现。不含糊过去。 ## 顺手修一个会静默分裂数据的 bug 通道的归属键正则 `RFQ-[A-Z0-9]+` 不含连字符,`RFQ-2607-501` 只抽到 `RFQ-2607` 就停。 而这个键会成为「受理结论」那一行的**主键** —— 截断了,同一单的数据就静默分裂成两行, 网关读到哪一行全看运气。改成分段续接 `RFQ-[A-Z0-9]+(?:-[A-Z0-9]+)*`, 实测 `RFQ-2607-501` / `RFQ-ABC123` 都整个吃下。 ## 我自己踩的两个 ① 出参类型手搓,`level`/`kind`/`position`/`rationale` **四个字段名全是编的** —— 页面上就摆出两个永远显示「—」的格子。改为直接用契约类型:归属解析真实是按 `outcome` 判别的联合(owned 给 rule+taskId,unowned 给 reason+可选 fallbackPosition)。 为此给契约补了 `IngestMailOutput` 导出(加法)。 ② JSX 正文里写 markdown 的 `**` 会显示成字面星号,换 `<b>`。这坑本轮踩过第二次。 另补两个缺失图标(flask-conical / split),不补就是空 SVG。 ## 实测 界面上点「投递这封信」→ 归属判**无主 · 三级都没对上 · 默认认领岗位 运营** (对新询价完全正确:没有在途任务可归)→ 触发器命中 1 个 → 起单。 起单入参 `customerCode: C014` / `rfqRef: RFQ-2607-501` 都抽对了。 一个值得记的观察:事件起单**没有「来源人」**,所以不装载工作组,A1 的 BD 岗位解析到 真正的 BD(冯兵),任务落他工位而不是我的 —— 这是对的,不是 bug。 要在自己工位上看,用「人工登记起单」那条路(登记人即来源)。 typecheck ✓ lint ✓ depcruise 376 模块 ✓ 498 测试 ✓ Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -35,6 +35,7 @@ export const GOV_ZONES = [
|
||||
'library',
|
||||
'tools',
|
||||
'data',
|
||||
'testbed',
|
||||
// 运营中心
|
||||
'cockpit',
|
||||
'tasks',
|
||||
@@ -51,6 +52,7 @@ export const ZONES: ReadonlyArray<{ key: GovZone; label: string; icon: string }>
|
||||
{ key: 'library', label: '活动库', icon: 'boxes' },
|
||||
{ key: 'tools', label: '工具箱', icon: 'wrench' },
|
||||
{ key: 'data', label: '数据域', icon: 'database' },
|
||||
{ key: 'testbed', label: '测试台', icon: 'flask-conical' },
|
||||
{ key: 'cockpit', label: '驾驶舱', icon: 'gauge' },
|
||||
{ key: 'tasks', label: '任务', icon: 'activity' },
|
||||
{ key: 'people', label: '员工', icon: 'users' },
|
||||
@@ -121,6 +123,12 @@ export const ZM: Readonly<Record<GovZone, { title: string; desc: string; accent:
|
||||
accent: 'linear-gradient(140deg,#0e9fd8,#245bdb)',
|
||||
desc: '对象——企业运营什么。域 × 对象的结构定义:声明物化(最大化合并、只增不破坏)与调用接入(事实源在外)。数据可以自生长,权力不可以自生长。行数据不在这里看——那在运营中心的台账。',
|
||||
},
|
||||
testbed: {
|
||||
title: '联调测试台',
|
||||
icon: 'flask-conical',
|
||||
accent: 'linear-gradient(140deg,#e8833a,#c25f1a)',
|
||||
desc: '把定义**试着跑一遍**:造一封入站邮件(可带附件)投进通道,看归属解析怎么判、哪个触发器命中、有没有起单。邮件通道是外界,模拟通道是允许的;系统内部机制一律真跑 —— 这里投出去的信走的是与真通道同一条入站归一链路。',
|
||||
},
|
||||
system: {
|
||||
title: '系统管理',
|
||||
icon: 'settings',
|
||||
@@ -136,6 +144,7 @@ export const ZM: Readonly<Record<GovZone, { title: string; desc: string; accent:
|
||||
*/
|
||||
export const TABS: Readonly<Record<GovZone, ReadonlyArray<{ key: string; label: string; ico: string }>>> = {
|
||||
blueprint: [{ key: 'map', label: '企业蓝图', ico: 'route' }],
|
||||
testbed: [{ key: 'inbound', label: '入站邮件', ico: 'mail' }],
|
||||
workflows: [
|
||||
{ key: 'overview', label: '总览', ico: 'gauge' },
|
||||
{ key: 'pkgs', label: '流程包', ico: 'boxes' },
|
||||
|
||||
@@ -26,7 +26,7 @@ export const SURFACE_META: Readonly<Record<Surface, { path: string; brand: strin
|
||||
|
||||
/** 区归属:设计五区 + 运营六区,恰好铺满 `GOV_ZONES`(由测试守住) */
|
||||
export const SURFACE_ZONES: Readonly<Record<Surface, readonly GovZone[]>> = {
|
||||
design: ['blueprint', 'workflows', 'library', 'tools', 'data'],
|
||||
design: ['blueprint', 'workflows', 'library', 'tools', 'data', 'testbed'],
|
||||
ops: ['cockpit', 'tasks', 'people', 'ledgers', 'knowledge', 'system'],
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user