Files
zyt/artifacts/revisit-legacy-restore-review.md
T
2026-10-17 16:08:24 +08:00

73 lines
8.6 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-17。基线:`HEAD=c67b3eff69d9a3ac2046861751f159692a0abcd7`。仅审查本地源码、Git 和既有验证记录;未读 `.env` / 凭据,未连接业务库,未发布,未修改产品文件。`.trellis/workflow.md` 在当前工作区不存在。本报告是唯一写入文件。
## 结论
最小可靠恢复是将原 Controller、原 `/stats/revisit_rate/index.vue` 及原 API 函数恢复为 HEAD 的完整契约,保留原 `RevisitRateLogic`、`RevisitRateCalculator`、`RevisitVisitSlotService`、配置、自动分配及个人业绩调用链。新队列功能另外使用 `stats.revisitAssignRate/*` 和 `/stats/revisit_assign_rate`;继承继续使用 `stats.revisitInheritRate/*` 和 `/stats/revisit_inherit_rate`。
仅保留旧计算器还不能保持原功能:上一轮将 `stats.revisitRate/*` Controller 改为队列逻辑,现有页面和外部调用者即使 URL 不变也会获得不同的患者集合、时间范围、分子与分母。因此恢复必须覆盖入口及 API 契约。
审查开始时,原 `RevisitRateLogic` 的差异仅为 7 个 `private` 方法改为 `protected`,计算器与诊次服务无 Git 差异。审查过程中主代理已将旧 Controller、旧页面、旧 MCP review 项恢复,旧 Logic 也恢复为 HEAD,并将队列数据源抽为独立 trait。该并行状态只是观察结果,最终应以主代理收尾 diff 为准。
## HEAD 原入口与依赖
| 层 | 原契约 |
| --- | --- |
| 菜单页面 | 名称「复诊接诊率」,`paths=/stats/revisit_rate`,`component=/stats/revisit_rate/index` |
| 菜单/API 权限 | `stats.revisitRate/overview`、`stats.revisitRate/deptOptions`、`stats.revisitRate/assignLines`、`stats.revisitRate/visitOrderLines` |
| Controller | 四个 action 直接调用 `RevisitRateLogic` 同名方法;overview / 两个明细保留 120 秒执行时间 |
| 查询参数 | overview:`month, dept_ids, inherit_mode`;患者明细另带 `assistant_id, dept_id, kind=new|inherit|all`;订单明细另带 `slot=0|2..50` |
| 前端 API | `revisitRateOverview`、`revisitRateDeptOptions`、`revisitRateAssignLines`、`revisitRateVisitOrderLines`;保留 `RevisitRateInheritMode` 和 `RevisitRateAssignKind` 导出 |
| 默认口径 | `server/config/project.php` 的 `default_inherit_mode='exclude'`;页面首次请求不传 inherit_mode,接收服务端返回口径;用户可手动选择 slot |
| 原页面筛选 | 月份、部门、exclude / slot 口径;重置回默认口径;包含新指派 / 继承 / 合计及订单下钻 |
| 下钻权限 | 患者数:`stats.revisitRate/assignLines`;订单数:`stats.revisitRate/visitOrderLines`;患者详情:`tcm.diagnosis/detail`;订单详情:`tcm.prescriptionOrder/detail` |
| 原个人业绩 | `AssistantPerformanceLogic::revisitRate` → `RevisitRateLogic::assistantOverview`;本人结果按月 / 医助 / 口径缓存 600 秒 |
| 原自动分配 | `AutoAssignPendingDiagnosis` 使用旧 `RevisitRateLogic`;取 slot 模式 overview,但分档字段配置仍为 `visit2_rate_new_assign` |
| 原 MCP 项 | `server/app/mcp/catalog/review/stats.php` 中原四个 `stats.revisitRate/*` 说明和参数白名单必须继续描述按月统计 |
原菜单来源为 `server/sql/1.9.20260610/add_revisit_rate_menu.sql`。恢复旧入口无需改原菜单记录、原权限或执行旧菜单脚本。Vue 路由由 `admin/src/router/index.ts` 的 `import.meta.glob('/src/views/**/*.vue')` 按数据库 component 解析,新增独立入口只需相应组件文件和菜单 component 正确对应。
## 需保持的算法含义
- 分母取所选月的指派事件;原 exclude 模式仅按 `is_inherit=0` 构造医助×诊单集合,保留自指派及历史回退的原处理方式。原 slot 模式另外计算继承起算诊次与每列分母。
- 分子取所选月的有效订单,诊次为跨月累计的全局有效实单序号加原诊单偏移;订单按当时持有人归属。往月指派、当月成交仍可进入分子,率可超过 100%。
- 有拒收 / 退款业务订单的诊单整体剔除;有效订单过滤仍委托原业绩口径;二中心组织范围、当前人事部门归类和去重规则保持 HEAD。
- 队列统计把“入组指派周期”和“累计观察时刻”分开,继承重新起算诊次。这些是另一张统计表的含义,不能复用原四个 API 名称替换原算法。
## 新入口权限与发布边界
`AuthMiddleware::handle` 当前对未登记到菜单权限集合的普通 API 默认放行;只增加 PHP Controller 而漏掉菜单权限登记,会使新增数据接口对登录用户过宽。新增 `stats.revisitAssignRate` 的 overview 和 3 个子接口都应登记;继承入口同理。角色授权应逐 action 从原对应权限复制,不能因拥有 overview 就自动授予患者或订单明细。执行菜单迁移后需按现有流程刷新 `AdminAuthCache`。
原菜单无需改名或搬迁。新指派周期菜单应新增独立 path / component,避免覆盖旧 `stats.revisitRate/overview` 的记录。若已有继承菜单脚本会引用旧页作为父目录与授权来源,可保留这种引用;新增指派周期脚本也可按同样逐权限方式授权。
## 本地证据能确认的发布状态
- `git diff -- server/public/admin`、该目录的 `git status --short` 均为空:当前仓库的公开管理端产物没有相对 HEAD 被替换。
- 公开产物 `server/public/admin/assets/stats-Bz24MGMf.js` 仍包含原四个 `stats.revisitRate/*` 路径;在公开 JS 中未找到 `stats.revisitInheritRate`、`scope_assistant_id` 或新队列标题。不能据此推断远端服务器文件状态。
- 既有验证计划记录生产构建输出为 `.codex-tasks/revisit-cohort-build`,该隔离目录确实存在;记录明确写了未运行 release、业务库迁移未执行。它是先前代理的本地记录,不是生产部署审计。
- `admin/package.json` 的 `npm run build` 实际执行 `vite build && node scripts/release.mjs`;release 会移除并重拷贝 `../server/public/admin`。只做验证构建时应继续使用单独输出目录,并避免运行 release。
- 源码改动在当前工作区尚未提交。Git 未提交、公开目录未变和临时构建存在,可以支持“本地未完成正式 release”的判断,不能单独证明生产环境从未部署。此次未查询生产、不读凭据、不连业务库,故不能声称已经确认线上恢复或线上未受影响。
## 已执行验证
以下测试只加载 autoload / 纯函数或反射源码,不初始化应用数据库,全部通过:
| 命令 | 结果 |
| --- | --- |
| `php server/tests/RevisitRateContractTest.php` | 45 checks |
| `php server/tests/RevisitRateInheritSlotTest.php` | 57 checks |
| `php server/tests/RevisitVisitSlotServiceTest.php` | 20 checks |
合计 122 项旧链路检查。本次未执行数据库测试。
## 主代理收尾需要覆盖的检查
1. 旧 Controller / 旧页面与 HEAD 比对无差异;原 Logic / Calculator / 诊次服务 / 配置 / 自动分配 / 个人业绩无差异。API 文件可以新增独立函数,但原函数签名、URL、参数类型及旧类型导出应保持 HEAD。
2. 原四个 Controller action 明确调用 `RevisitRateLogic`;新增四个指派周期 action 调用 `RevisitCohortLogic` 的 new 类型;继承 action 固定 inherit 类型。禁止通过请求参数切换到另一报表类型。
3. 重跑上述 122 项旧检查;新增队列纯函数检查继续通过。隔离数据库验证若运行,只能显式指定独立本机临时库,并扩展到新指派菜单的 4 项登记、幂等及逐权限复制。
4. 三页及共享组件编译成功;旧页仍调用旧 API,新指派页调用 `stats.revisitAssignRate/*`,继承页调用 `stats.revisitInheritRate/*`。新共享组件迁移后不得留下从原页面目录导入队列实现的误导路径或错误权限前缀。
5. 原页月份 / 默认 exclude / 手动 slot / 患者与订单下钻至少验证一次;新两页的日期、医助筛选及 scope 筛选保持原队列验证。已有 `artifacts/revisit-cohort-browser-check.json` 使用虚构接口响应,只证明旧一轮 UI 行为,不能证明此次入口分离或真实业务数据一致。
6. 同步计划和前端说明中“原入口只统计新指派”“新指派使用 stats.revisitRate”的陈旧描述;原 MCP review 恢复按月参数,新两个 API 项按实际路由声明。运行现有 MCP 目录测试,确认没有旧路径重新被队列说明覆盖。
7. `git diff --check`;构建输出到隔离目录;收尾报告明确本地恢复完成、验证范围及未发布状态,不以虚构数据浏览器测试声称生产数据已核对。