Commit 541ea76a by luoqi

refactor(web): 初选不再筛左栏 —— 撤掉「初选 xx·xx」告示条

点矩阵格子只往助手走,左栏一动不动(原筛选/滚动位置全保留)。

两个理由:
① 人群的证据在助手的确认单里,那才是要审的东西。左栏再给一份,
   两处口径一旦不一致(列表按 plan 分页、矩阵按患者去重,本来就不是一个数)
   主管不知道信哪个;
② 左栏是他挑患者的地方,被上一次初选筛住会让他以为池子空了 ——
   而那条告示要他先看懂、再点掉,才回得到整池。

cell 只留作矩阵内部回显(再打开时看得出刚交过哪一格)。
服务端 potentialTreatment / temperature 两个列表参数保留未动,只是前端不再自动带上。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parent fa0b286b
......@@ -85,14 +85,18 @@ export function PatientPickerRail({
const [tags, setTags] = useState<Set<string>>(new Set()); // "key:value"
/**
* ⭐ 矩阵是召回池的一个**视图模式**,不是新路由(T16:主管本质也是客服,不能劈成两个身份)。
* `cell` = 已初选的那一格;它同时驱动列表筛选,所以「矩阵上写 44」与
* 「点进去列表 44 条」天然一致(口径对数,见后端 plan.service.buildListWhere 的注释)。
*
* ⛔ 初选**不动左栏列表**(2026-08 产品走查)。点一格是把这批人**交给助手**,
* 人群的证据在助手的确认单里(那才是要审的东西);顺手把左栏也筛掉,
* 等于在助手之外又开了第二个"这批人是谁"的说法 —— 两处不一致时主管信哪个?
* 而且左栏是他**挑患者**的地方,被上一次初选筛住会让他以为池子空了。
*/
const [matrixMode, setMatrixMode] = useState(false);
/// 矩阵数据 + 取数中。⭐ 数据**先取好再开浮层**,所以 loading 落在「分配」钮上而不是浮层里
const [matrix, setMatrix] = useState<PoolMatrixData | null>(null);
const [matrixLoading, setMatrixLoading] = useState(false);
const [cell, setCell] = useState<{ treatment: string; treatmentZh: string; temperature: 'hot' | 'warm' | 'cold' } | null>(null);
/// 上一次点过的那一格 —— **只用于矩阵内部回显**(再打开时能看出刚交过哪一格),不外溢到列表
const [cell, setCell] = useState<{ treatment: string; temperature: 'hot' | 'warm' | 'cold' } | null>(null);
const user = useAuthStore((st) => st.user);
const clinicDict = user?.dictionary?.clinics; // 显示 plan 诊所名用(字典查表,非 scope)
......@@ -126,11 +130,10 @@ export function PatientPickerRail({
phoneVerified: realPhoneOnly ? true : undefined,
targetClinicIds: clinics.length ? clinics : undefined,
personaTags: tags.size ? [...tags].join(',') : undefined,
// 初选矩阵两轴 —— 只在召回池视图下生效(「我的」不做初选)
potentialTreatment: view === 'pool' && cell ? cell.treatment : undefined,
temperature: view === 'pool' && cell ? cell.temperature : undefined,
// ⛔ 初选的两轴(potentialTreatment / temperature)**不进这里** —— 见上方 cell 的注释。
// 服务端仍支持这两个参数(plan.service.buildListWhere),只是前端不再自动带上。
}),
[view, keyword, sort, realPhoneOnly, clinics, tags, cell],
[view, keyword, sort, realPhoneOnly, clinics, tags],
);
const { items, total, loading, hasMore, error, loadMore, patchItem, removeItem } = usePatientPicker(filters);
......@@ -203,11 +206,11 @@ export function PatientPickerRail({
/**
* 点矩阵格子 = 完成「初选」,人群随即交给助手(生产线 ① → ②)。
*
* ⚠️ 三件事一起做,少一件都会出问题:
* ① 记下这一格 → 驱动**列表**筛选,主管切回列表能看到这批人是谁(证据在,T14)
* ② 切回列表视图 —— 否则确认单出来了,他还盯着矩阵,不知道刚才那一下做了什么
* ③ 发语义事件 + 跟助手说一句 —— 「怎么演」归 pet-brain,「怎么圈人」归后端,
* 这里**不传 planId 列表**:传了等于把收敛规则搬到前端,而那是会漂的
* ⛔ **不碰左栏列表** —— 这一格只往助手那边走。左栏保持原样(原来的筛选、滚动位置都在),
* 主管的注意力跟着数据流粒子过去,回头看的是确认单,不是被筛过的列表。
* ⚠️ 关掉浮层是必须的:否则确认单在右边开出来了,他还盯着矩阵。
* ⚠️ 这里**不传 planId 列表** —— 「怎么圈人」归后端,传了等于把收敛规则搬到前端,而那是会漂的;
* 「怎么演」归 pet-brain / 舞台层,业务侧只发语义事件
*/
const pickCell = (c: {
treatment: string;
......@@ -217,7 +220,7 @@ export function PatientPickerRail({
rect: { x: number; y: number; w: number; h: number };
}) => {
const tempZh = TEMPERATURE_META[c.temperature].zh;
setCell({ treatment: c.treatment, treatmentZh: c.treatmentZh, temperature: c.temperature });
setCell({ treatment: c.treatment, temperature: c.temperature });
setMatrixMode(false);
// ⭐ 一次调用做完整段移交:发数据流 → 粒子飞到助手 → 落地后自动开大窗并说那句话。
// 这里**不自己 setTimeout**:动画多长是舞台层的事,业务侧知道了就得跟着改(见 store 注释)。
......@@ -325,28 +328,11 @@ export function PatientPickerRail({
</span>
</div>
{/* 已初选的那一格 —— 必须能一眼看见、且能一键撤掉。
不给撤销入口的话,主管点错一格就只能刷新页面(而刷新会丢掉整个对话)。 */}
{cell && view === 'pool' && (
<div className="flex flex-none items-center gap-1.5 border-b border-slate-100 bg-slate-50 px-2 py-1.5 text-[11.5px] text-slate-600">
<span className="text-slate-400">初选</span>
<span className="font-medium text-slate-800">
{cell.treatmentZh} · {TEMPERATURE_META[cell.temperature].zh}
</span>
<button
type="button"
onClick={() => setCell(null)}
title="清除初选,回到整池"
className="ml-auto rounded p-0.5 text-slate-400 transition-colors hover:bg-slate-200 hover:text-slate-700"
>
<X className="h-3 w-3" />
</button>
</div>
)}
{/* ⛔ 这里原来有一条「初选 xx · xx ✕」的条 —— 已撤(2026-08 产品走查)。
它是列表被初选筛过的**告示牌**;列表既然不再跟着筛,告示牌也就没有对象了,
留着反而像是"左栏此刻只剩这批人"。撤销初选的语义现在在助手那边(不采纳确认单即可)。
{/* ⚠️ 常驻的「把这 N 人移交助手」横幅已撤 —— 入口收敛到 tab 行的「分配」一个。
那条路没丢,收进了矩阵浮层底部(见 PoolMatrix 的 filtered):
矩阵只有「治疗项 × 温度」两轴,主管想按别的条件圈人时仍走筛选标签。 */}
⚠️ 常驻的「把这 N 人移交助手」横幅同样已撤 —— 入口收敛到 tab 行的「分配」一个。 */}
{/* 搜索 + 工具行 */}
<div className="flex-none space-y-1.5 border-b border-slate-100 p-2">
......
......@@ -546,6 +546,17 @@ release_note 退回文字说明
见 T16。矩阵是召回池的一个**视图模式** —— tab 行的「**分配**」主色按钮**浮层展开**
不新开路由、也不替换左栏内容(挑格子时列表还在原处,关掉就回到原位置,不丢滚动位置与筛选)。
**点一格之后,左栏一动不动**(2026-08-03 产品走查)。初选的去向只有一个:助手。
> 原实现顺手把左栏也按这一格筛了,并在顶上挂一条「初选 充填 · 窗口外 ✕」的告示。撤掉,两个理由:
> ① **人群的证据在确认单里**,那才是主管要审的东西。左栏再给一份,两处口径一旦不一致
>(列表按 plan 分页、矩阵按患者去重,本来就不是一个数)主管不知道该信哪个;
> ② 左栏是他**挑患者**的地方,被上一次初选筛住会让他以为池子空了 ——
> 而那条告示要他先看懂、再点掉,才回得到整池。
>
> 服务端的 `potentialTreatment` / `temperature` 两个列表参数**保留**(`buildListWhere` 未动),
> 只是前端不再自动带上;将来若要「按初选看列表」,是加回一个显式入口的事。
### 矩阵三档的叫法
**列头用临床说法,不用温度比喻**(2026-08-02 产品定):
......
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