Commit 3a85d4b1 by luoqi

fix(persona-ui): 说明卡去掉底部注解行

「已经在别处做掉的,这里看不到」「拔牙、补牙、根管等基础项目不计入」这类是在交代
算法边界,客服不需要知道,占位还把卡片拉长。note 从 display 契约里整体删除(16 处)。

三条确实影响判断的信息没丢,并进它该在的位置:
  · 价值分群 —— 「重要 = 消费排同院前 40%」原本藏在注解里,而它正是这 8 个取值的
    第一分野。改成第一条对照项,顺带把副标题写成「按消费高低 × 来得勤不勤 / 最近来没来」
  · 权益身份 —— 副标题补「(不代表现在仍有效)」,免得客服当成当前在保
  · 禁忌标签 —— 副标题补「· 目前只判年龄」,保住"没标记 ≠ 没禁忌"这个边界
折扣锚点的时效提醒也不靠注解 —— 卡片上本来就有超 3 年才出现的 ️ 行,比常驻一句更准。

顺带核对了时间偏好的时区(生产 120 万条预约):
  · 北京时区小时分布是干净的 9-17 营业钟形,12 点午休凹陷 —— +8 漏加或重复加都会把峰值
    推到 1-9 或 17-1
  · 星期分布周六 21.1% / 周日 19.3%(合计 40.4%),周一最低 9.8%,符合"休息日看牙"
  · 抽样对账:画像存的 recordCount=67 / weekendPct=15 与 SQL 现场复算一致
  · planned_for 120 万条 0 个 null → `?? occurredAt` 兜底(钟点不可靠)在生产从不触发
结论:换算无误。硬编 +8 对中国安全(1991 年后无夏令时),多宿主时区仍是既有 follow-up。

454 tests green · pac-web build 通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parent 7e3a4f67
...@@ -60,8 +60,8 @@ describe('spec.display —— 详情页说明', () => { ...@@ -60,8 +60,8 @@ describe('spec.display —— 详情页说明', () => {
const JARGON = ['extractor', 'fact', 'jsonb', '字段', '接口', '口径与召回完全一致', 'K0', 'data.']; const JARGON = ['extractor', 'fact', 'jsonb', '字段', '接口', '口径与召回完全一致', 'K0', 'data.'];
const offenders: string[] = []; const offenders: string[] = [];
for (const [key, spec] of Object.entries(PERSONA_FEATURE_SPECS)) { for (const [key, spec] of Object.entries(PERSONA_FEATURE_SPECS)) {
const text = [spec.display.subtitle, spec.display.note ?? '', const text = [spec.display.subtitle,
...spec.display.rules.map((r) => `${r.label ?? ''}${r.body}`)].join(' '); ...spec.display.rules.map((r) => `${r.label}${r.body}`)].join(' ');
for (const w of JARGON) if (text.includes(w)) offenders.push(`${key}: ${w}`); for (const w of JARGON) if (text.includes(w)) offenders.push(`${key}: ${w}`);
} }
expect(offenders).toEqual([]); expect(offenders).toEqual([]);
......
...@@ -62,11 +62,6 @@ export function PersonaFeatureHover({ ...@@ -62,11 +62,6 @@ export function PersonaFeatureHover({
))} ))}
</ul> </ul>
)} )}
{display?.note && (
<p className="border-t border-slate-100 pt-1.5 text-[10.5px] leading-relaxed text-slate-500">
{display.note}
</p>
)}
</div> </div>
</HoverCardContent> </HoverCardContent>
</HoverCard> </HoverCard>
......
...@@ -57,8 +57,6 @@ export interface PersonaFeatureDisplay { ...@@ -57,8 +57,6 @@ export interface PersonaFeatureDisplay {
* 要精简就精简 body 的字数,不是砍掉结构。 * 要精简就精简 body 的字数,不是砍掉结构。
*/ */
rules: Array<{ label: string; body: string }>; rules: Array<{ label: string; body: string }>;
/** 使用提醒 —— 只写会改变客服**做法**的(边界、已知局限);实现细节不写 */
note?: string;
/** 详情页分组 */ /** 详情页分组 */
group: PersonaFeatureGroup; group: PersonaFeatureGroup;
/** 组内排序(小的在前;留 10 的间隔便于插新标签) */ /** 组内排序(小的在前;留 10 的间隔便于插新标签) */
...@@ -122,15 +120,15 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -122,15 +120,15 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
' R≥4 F≥3 M<4→一般价值 / R=3 F≥3 M<4→一般保持 / R≥4 F=2 M<4→一般发展 / 其余(含 R≤2 任意)→低活跃', ' R≥4 F≥3 M<4→一般价值 / R=3 F≥3 M<4→一般保持 / R≥4 F=2 M<4→一般发展 / 其余(含 R≤2 任意)→低活跃',
].join('\n'), ].join('\n'),
display: { display: {
subtitle: '按最近就诊、来的频次、累计消费分层', subtitle: '按消费高低 × 来得勤不勤 / 最近来没来 分层',
rules: [ rules: [
{ label: '重要价值 / 一般价值', body: '最近还在来,而且来得勤' }, { label: '重要 / 一般', body: '消费排在同院前 40% / 消费偏低' },
{ label: '重要保持 / 一般保持', body: '来得勤,但有段时间没来了' }, { label: '价值', body: '最近还在来,而且来得勤' },
{ label: '重要发展 / 一般发展', body: '最近来过,但来的次数少' }, { label: '保持', body: '来得勤,但有段时间没来了' },
{ label: '重要挽留', body: '消费高,但很久没来了' }, { label: '发展', body: '最近来过,但来的次数少' },
{ label: '挽留', body: '消费高,但很久没来了' },
{ label: '低活跃', body: '很久没来,或三项都偏低' }, { label: '低活跃', body: '很久没来,或三项都偏低' },
], ],
note: '「重要」= 消费排在同院前 40%,「一般」= 消费偏低',
group: 'value', group: 'value',
order: 10, order: 10,
}, },
...@@ -222,7 +220,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -222,7 +220,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '电商平台 / 自媒体网络', body: '线上平台来的' }, { label: '电商平台 / 自媒体网络', body: '线上平台来的' },
{ label: '内部员工 / 其他', body: '其余来源' }, { label: '内部员工 / 其他', body: '其余来源' },
], ],
note: '一经判定不再改,后来谁推荐过也不会覆盖',
group: 'basic', group: 'basic',
order: 40, order: 40,
}, },
...@@ -253,7 +250,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -253,7 +250,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '两口之家', body: '有配偶' }, { label: '两口之家', body: '有配偶' },
{ label: '单身家庭', body: '只有旁系或朋友' }, { label: '单身家庭', body: '只有旁系或朋友' },
], ],
note: '家人没在本院看过牙就推不出来',
group: 'basic', group: 'basic',
order: 30, order: 30,
}, },
...@@ -282,7 +278,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -282,7 +278,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '家庭型', body: '带的是家里人' }, { label: '家庭型', body: '带的是家里人' },
{ label: '社交型', body: '带的是家人以外的人' }, { label: '社交型', body: '带的是家人以外的人' },
], ],
note: '成交额可能很小,谈奖励前先看具体数字',
group: 'value', group: 'value',
order: 50, order: 50,
}, },
...@@ -306,7 +301,7 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -306,7 +301,7 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
'储值会员 储值/预存(或有充值);儿牙会员 儿牙会员/乐牙卡/涂氟年卡;医保 医保。未命中→不打标签。', '储值会员 储值/预存(或有充值);儿牙会员 儿牙会员/乐牙卡/涂氟年卡;医保 医保。未命中→不打标签。',
].join('\n'), ].join('\n'),
display: { display: {
subtitle: '历史结算里用过的卡券或保险', subtitle: '历史结算用过的卡券或保险(不代表现在仍有效)',
rules: [ rules: [
{ label: '高端保险直付', body: 'Bupa、万欣和等商保直付' }, { label: '高端保险直付', body: 'Bupa、万欣和等商保直付' },
{ label: '银行私行权益', body: '私人银行 / 白金卡' }, { label: '银行私行权益', body: '私人银行 / 白金卡' },
...@@ -314,7 +309,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -314,7 +309,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '儿牙会员', body: '儿牙卡 / 涂氟年卡' }, { label: '儿牙会员', body: '儿牙卡 / 涂氟年卡' },
{ label: '医保客户', body: '用过医保结算' }, { label: '医保客户', body: '用过医保结算' },
], ],
note: '只说明曾经这样结算过,不代表现在还有效',
group: 'value', group: 'value',
order: 40, order: 40,
}, },
...@@ -373,7 +367,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -373,7 +367,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '修复史', body: '冠桥 / 贴面 / 嵌体' }, { label: '修复史', body: '冠桥 / 贴面 / 嵌体' },
{ label: '牙周治疗史', body: '洁牙 / 刮治 / 牙周序列' }, { label: '牙周治疗史', body: '洁牙 / 刮治 / 牙周序列' },
], ],
note: '拔牙、补牙、根管等基础项目不计入',
group: 'value', group: 'value',
order: 30, order: 30,
}, },
...@@ -402,7 +395,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -402,7 +395,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '工作日 / 周末', body: '近两年预约多在这几天' }, { label: '工作日 / 周末', body: '近两年预约多在这几天' },
{ label: '上午 / 下午 / 晚间', body: '8-12 / 12-18 / 18-21 点' }, { label: '上午 / 下午 / 晚间', body: '8-12 / 12-18 / 18-21 点' },
], ],
note: '看的是预约时间,不是实际到诊时间',
group: 'action', group: 'action',
order: 60, order: 60,
}, },
...@@ -430,7 +422,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -430,7 +422,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '最低折扣', body: '原价 500 元以上的治疗里谈成过的最深折扣' }, { label: '最低折扣', body: '原价 500 元以上的治疗里谈成过的最深折扣' },
{ label: '日期 / 项目', body: '那一次是什么时候、做的什么' }, { label: '日期 / 项目', body: '那一次是什么时候、做的什么' },
], ],
note: '免费洁牙等促销不计入。锚点可能很久远,报价前先看日期',
group: 'action', group: 'action',
order: 70, order: 70,
}, },
...@@ -461,7 +452,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -461,7 +452,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '免打扰', body: '已标记不接受主动联系' }, { label: '免打扰', body: '已标记不接受主动联系' },
{ label: '不可等候', body: '提过赶时间 / 不能等' }, { label: '不可等候', body: '提过赶时间 / 不能等' },
], ],
note: '命中「免打扰」不要外呼',
group: 'action', group: 'action',
order: 30, order: 30,
}, },
...@@ -491,7 +481,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -491,7 +481,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '晕针 / 晕血', body: '提过怕打针 / 见血不适' }, { label: '晕针 / 晕血', body: '提过怕打针 / 见血不适' },
{ label: '密闭恐惧', body: '提过幽闭 / 长时间张口不适' }, { label: '密闭恐惧', body: '提过幽闭 / 长时间张口不适' },
], ],
note: '从病历文本里识别,没标不等于患者不敏感',
group: 'action', group: 'action',
order: 50, order: 50,
}, },
...@@ -521,7 +510,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -521,7 +510,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '正畸 / 早矫', body: '成人正畸 13-40 岁 / 儿童早矫 3-12 岁' }, { label: '正畸 / 早矫', body: '成人正畸 13-40 岁 / 儿童早矫 3-12 岁' },
{ label: '根管 / 牙周 / 补牙', body: '牙髓、牙周、龋齿' }, { label: '根管 / 牙周 / 补牙', body: '牙髓、牙周、龋齿' },
], ],
note: '已经在别处做掉的,这里看不到',
group: 'action', group: 'action',
order: 10, order: 10,
}, },
...@@ -551,7 +539,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -551,7 +539,6 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
{ label: '高', body: '30-90 天没来' }, { label: '高', body: '30-90 天没来' },
{ label: '中', body: '近期来过或新发现' }, { label: '中', body: '近期来过或新发现' },
], ],
note: '没有待做的项目就不显示这个标签',
group: 'action', group: 'action',
order: 20, order: 20,
}, },
...@@ -575,11 +562,10 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = { ...@@ -575,11 +562,10 @@ export const PERSONA_FEATURE_SPECS: Record<string, PersonaFeatureSpec> = {
'② 量化条件无数据(HbA1c 全量仅10条/血压自由文本);③ 需控制状态/急性期判断+时效窗口 → 留 Layer C(LLM 抽取)。', '② 量化条件无数据(HbA1c 全量仅10条/血压自由文本);③ 需控制状态/急性期判断+时效窗口 → 留 Layer C(LLM 抽取)。',
].join('\n'), ].join('\n'),
display: { display: {
subtitle: '治疗安全预警', subtitle: '治疗安全预警 · 目前只判年龄',
rules: [ rules: [
{ label: '种植禁忌', body: '未满 19 岁,颌骨尚未发育完全' }, { label: '种植禁忌', body: '未满 19 岁,颌骨尚未发育完全' },
], ],
note: '目前只做了年龄这一项 —— 没有标记不等于没有其他禁忌',
group: 'action', group: 'action',
order: 40, order: 40,
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment