Files
zyt/artifacts/revisit-cohort-assignment-research.md
T
2026-10-17 16:08:24 +08:00

63 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 复诊接诊率:指派 / 继承写入与兼容性研究
2026-10-16。只读检查产品源码;未读取 `.env` 或凭据;未连接数据库。项目存在 `AGENTS.md`,但 `.trellis/workflow.md` 不存在,无法读取 Trellis 流程与分层规范。
## 关键结论
- 现有报表是“当月指派分母 + 当月成交分子”,不是“指派日期区间内患者的后续接诊队列”。仅把 `month` 换成起止日期会继续产生区间外患者进入分子的错误。
- 新指派、继承已有可用事件字段,无需为重新起算修改患者全局诊次。应在统计层根据入组指派事件重新计算后续订单;`RevisitVisitSlotService` 同时服务诊单节点、到期快照,改变它会影响其他业务。
- 自动指派和个人业绩都直接依赖当前统计实现。页面改队列口径时要明确兼容入口;尤其不要悄悄改变自动指派档位。
## 写入侧与数据字段
| 入口 | 现有行为 | 注意点 |
| --- | --- | --- |
| `DiagnosisLogic::assign`(约 673 行) | 诊单行 `FOR UPDATE`;更新 `assistant_id`、`assign_read_at`;同事务插入指派日志。`is_inherit=1` 仅在目标医助大于 0 时成立。 | `from==to` 允许写入;当前 slot 统计忽略该行,旧 exclude 仍计入新指派。新队列避免把自指派当成新承接事件。 |
| 同上,继承 | 同事务用 `slotAtTime($id,$now)` 写 `inherit_visit_slot` 和 `inherit_visit_slot_calc_time`。 | 快照只用于展示 / 对账。现有统计通过有效订单实时重算 k,所以事后退款、取消、offset 修改会联动。不能把快照当唯一订单数依据;历史回退没有快照。 |
| `AutoAssignPendingDiagnosis::applyAssignment`(约 567 行) | `is_inherit=0`、操作人 0、名称“系统自动分配”;同事务改医助并写日志;`from` 可推断为一中心原医助。 | 自动指派属于新指派,不能以 `from>0` 判定继承。 |
| `AutoAssignLogLogic::rollbackOne`(约 72 行) | 锁自动指派日志和诊单;仅当前医助仍为自动分配目标时允许回退;回到前任 / 0。写指派日志 `is_inherit=0`,并写自动分配日志 rollback 字段。 | 保留写入规则;新口径需把历史回退识别为继承,目标 0 的释放行不入组。 |
| `ExpressTrackingService`(约 702 行) | 发货释放写 `to_assistant_id=0`,未显式写 `is_inherit`(列默认 0)。 | 释放不是新指派,但会终止原医助持有时间段。 |
主要表 / 模型:
- `DiagnosisAssignLog` 只设置表名 `tcm_diagnosis_assign_log`,关闭自动时间戳,无字段白名单。指派核心数据:`id, diagnosis_id, from_assistant_id, to_assistant_id, operator_admin_id, create_time, is_inherit, inherit_visit_slot, inherit_visit_slot_calc_time`;还含最新订单创建人 / 时间快照与操作人信息。
- `tcm_diagnosis`:`assistant_id` 是当前归属,不应代替历史持有时间线;`revisit_slot_start_offset` 为全局诊次偏移(钳制 0~20)。
- `tcm_prescription_order`:有效业务单剔除软删、履约状态 4/9/10;统一调用 `YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery`;序列稳定排序 `(diagnosis_id, create_time, id)`。
- 迁移:`server/sql/1.9.20260601/add_diagnosis_assign_log_is_inherit.sql`;`server/sql/1.9.20261012/06_add_diagnosis_assign_log_inherit_visit_slot.sql`。继承标记引入前的数据无法可靠恢复继承类型,不应按 `from>0` 猜测。
- 现有订单复合索引迁移:`server/sql/1.9.20261012/01_add_prescription_order_diag_ct_index.sql`,`(diagnosis_id, delete_time, fulfillment_status, create_time)`。源码内未找到指派日志建表 DDL,不能据此断言线上索引情况。
## rollback 与重新起算
- `RevisitRateLogic::fetchRollbackKeySet` 使用 `diagnosis_id | rollback_time | rollback_admin_id` 关联到指派日志 `diagnosis_id | create_time | operator_admin_id`;同一事务同一 `$now` 保证当前写入可匹配。需要继承独立页时复用这一兼容规则,不能只筛 `is_inherit=1`。
- 现有 `RevisitRateCalculator::compute` 在 slot 模式将命中回退的日志当继承;exclude 模式完全保留其 `is_inherit=0` 的旧语义。回退无继承快照,订单实时计算仍可用。
- 新继承“重新起算”应按继承事件时间切开序列,继承前历史单不进入继承后的接诊次数。保留同一秒约定:日志时间 `t <= order.create_time` 时归新医助,继承前完成单计数用严格 `< t`。
- 转派 / 释放 / 再次继承会形成多个持有段;要先明确入组去重,再把订单归属到有效段,避免同一订单被多个队列事件重复领取。当前实现按同一医助 × 诊单去重,继承取区间内最早,且同区间新指派优先覆盖继承;这一合并规则不适合直接复用到“新指派和继承分别统计”。
- 当前拒收 / 退款处理是“该诊单存在任意时间状态 9/10 有效订单,则整诊单从分母剔除”,分子只是剔除对应无效单。若沿用需在两个独立页面和明细保持一致;不要无意中改变这一业务规则。
## 当前统计调用方
1. `AutoAssignPendingDiagnosis::execute` 调 `RevisitRateLogic::overview(['month'=>上个自然月,'inherit_mode'=>'slot'])`,再从部门 children 中取医助率。配置实际值为 `project.revisit_rate.auto_assign_tier_field='visit2_rate_new_assign'`,页面默认实际是 `default_inherit_mode='exclude'`(部分注释仍写默认 slot)。
- 分档字段白名单仅 `visit2_rate_new_assign` / `visit2_rate`,对应 `rate_version=v1/v2`。无分母必须继续返回 `null`,否则可能改变谁参与自动指派。
- 自动日志同时记录两套率。历史 v1 行无 `visit2_rate_new_assign` 时,前端回落 `visit2_rate`。不要重解释历史日志字段;如变更分档口径要单独版本化。
2. `AssistantPerformanceController::revisitRate` 只收 `month`,Logic 从配置取 mode,再调 `RevisitRateLogic::assistantOverview`,只返回本人行。
- 本人统计有 600 秒缓存,key 为 `month + assistantId + mode`。改统计口径需更新缓存 key 版本;加日期范围 / 队列类型需纳入 key。
- 前端个人业绩卡片仍按月,响应类型依赖 `month, inherit_mode, slots, in_scope, row`。保持 month 兼容可避免页面破坏,但卡片文案和规则应同步说明指派队列口径。
3. `RevisitRateLogic::overview` 目前不处理 `assistant_id`;只有两个下钻方法调用 `applyRowScope`。新增医助筛选需同时约束 overview 的医助行、部门汇总、总计以及下钻集合。部门归属取当前 `admin_dept` 中最小有效 dept_id,默认限二中心子树。
4. `YejiStatsLogic` 的“被指派数”仍独立按 `is_inherit=0`、区间指派、医助×诊单去重;避免此次顺带修改整个业绩看板。
新独立页还需菜单 / 权限迁移与 MCP review 文案。`AuthMiddleware` 对未登记接口默认放行,因此新增接口须登记权限。现有 `deptOptions` 还被复诊到期页复用,不应改成仅某一队列的选项。
## 测试运行方式与已验证基线
无根级 PHPUnit 配置,`server/composer.json` 无 test script / PHPUnit;相关测试是独立 PHP CLI 脚本,仅加载 `server/vendor/autoload.php`,不启动应用、不连库。当前 PATH PHP:`D:/phpstudy_pro/Extensions/php/php8.2.9nts/php.exe`。
已从项目根目录运行并通过:
```powershell
php server/tests/RevisitRateContractTest.php # 45 checks
php server/tests/RevisitRateInheritSlotTest.php # 57 checks
php server/tests/RevisitVisitSlotServiceTest.php # 20 checks
```
`RevisitRateContractTest` 是源码字符串 / Reflection 契约,明确锁住“分子按当月下单”“继承从 k+1 列入分母”等旧实现,新队列实现需要合理更新这些断言,不能仅为通过保留过时语义。建议纯函数覆盖:区间指派后跨月成交、区间外患者同月成交不计入、自指派、转派终止归属、多次继承与重置、回退继承、同秒排序、医助筛选汇总和两类明细对账;保留全局诊次服务现有测试。