Files
Neo-ZQYY/docs/audit/changes/2026-03-23__tenant-admin-review-modal-dynamic-roles.md
Neo 14a12342b5 chore(audit): 补追 96 份未入仓审计孤本 — 覆盖 2026-02-26 ~ 2026-04-08
这些审计记录原本堆积在 docs/audit/changes/changes/ 嵌套误产物目录下(由开发机迁移
79d3c2e 前后的不明批量操作产生)。由于同期 .gitignore 屏蔽了 docs/audit/ 全目录,
它们从未入过 git 任何分支 history。删除即永久丢失。

按 docs/specs/audit-gap-recovery/tasks.md 阶段 1 执行,将全部 96 份 D 类孤本
(主目录无同名、git history 亦无记录)复制到 docs/audit/changes/ 主目录入仓。

涵盖主题: P1-P18 全栈集成 / 多模块累积变更 / ETL bug 修复 / 业务日切 /
   召回与任务引擎改造 / 租户管理与审批 / 董事会财务 / 客户与助教详情 /
   DDL 基线合并 / Kiro 到 Claude Code 迁移

阶段 2(B 类内容漂移 1 份)和阶段 4(嵌套目录删除)独立推进。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 06:35:42 +08:00

105 lines
7.4 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-03-23 17:00:00 |
| Prompt-ID | P20260323-164500 |
| Session-ID | 545eba0a |
| Session 路径 | docs/audit/session_logs/2026-03/23/18_57a8dd3c_164506 |
## 操作摘要
改造 tenant-admin 审核弹窗实现角色下拉从数据库动态读取不硬编码、选择角色后联动查询人员列表coach→ETL 助教表其他→ETL 员工表)、手机号自动匹配、提供"无"选项。后端新增 2 个 API 端点(`GET /api/tenant/roles``GET /api/tenant/site-staff`)和 2 个 Schema`RoleItem``StaffCandidate`)。前端 ReviewModal 组件全面改造。修复前端语法错误(中文引号与 JSX 双引号冲突、filterOption 类型断言)。
关键技术决策:不用 FDW 视图(`fdw_etl.v_dim_assistant`),因为 FDW 视图的 RLS`current_setting('app.current_site_id')`)在跨库场景下不生效。改用 `get_etl_readonly_connection(site_id)` 直连 ETL 库查底层表 `dwd.dim_assistant` / `dwd.dim_staff`,手动加 `site_id` 过滤。
## 变更范围
- 模块:`apps/backend/`FastAPI 路由 + Schema`apps/tenant-admin/`React 前端)
- 接口:新增 `GET /api/tenant/roles``GET /api/tenant/site-staff`
- 数据源:`auth.roles`(业务库)、`dwd.dim_assistant` / `dwd.dim_staff`ETL 库直连)
## 风险与回滚
- 风险ETL 直连依赖 `get_etl_readonly_connection` 可用性;角色表数据变更影响下拉列表;`site-staff` 端点 site_code→site_id 转换依赖 `biz.sites` 数据一致性
- 回滚:删除 2 个新端点(`/roles``/site-staff`+ 2 个新 Schema`RoleItem``StaffCandidate`);前端恢复原 ReviewModal 硬编码版本
## 验证
- 访问 tenant-admin http://localhost:5174 → 用户审批页 → 点击审核 → 确认角色下拉动态加载 4 个角色
- 选择 coach 角色 → 确认人员列表从 ETL 助教表加载
- 选择 staff/head_coach/manager → 确认人员列表从 ETL 员工表加载
- 选择"无" → 确认可以提交
- 前端无编译错误Vite HMR 正常)
## 文件清单
| 文件 | 变更类型 | 说明 |
|------|----------|------|
| `apps/backend/app/routers/tenant_users.py` | 修改 | 新增 `GET /roles``GET /site-staff` 端点 |
| `apps/backend/app/schemas/tenant_users.py` | 修改 | 新增 `RoleItem``StaffCandidate` schema |
| `apps/tenant-admin/src/pages/UserApproval/index.tsx` | 修改 | ReviewModal 组件改造(角色动态化、人员联动、手机号匹配、"无"选项、语法修复) |
## 本次对话文件变更
### 新增文件
- `docs/audit/prompt_logs/prompt_log_20260323_165704.md`
- `docs/audit/session_logs/2026-03/23/18_57a8dd3c_164506/main_01_545eba0a.md`
- `docs/audit/session_logs/2026-03/23/18_57a8dd3c_164506/sub_01_545eba0a.md`
- `docs/audit/session_logs/2026-03/23/17_bc427aef_161938/main_01_6c7c8174.md`
- `docs/audit/session_logs/2026-03/23/17_bc427aef_161938/sub_01_545eba0a.md`
### 修改文件
- `apps/backend/app/routers/tenant_users.py`
- `apps/backend/app/schemas/tenant_users.py`
- `apps/tenant-admin/src/pages/UserApproval/index.tsx`
- `NeoZQYY.code-workspace`
### 删除文件
- `docs/audit/session_logs/2026-03/23/17_bc427aef_161938/main_01_e69d704e.md`
## 改动注解
### `apps/backend/app/routers/tenant_users.py`
- 变更类型:修改
- 原始原因:原审核弹窗角色硬编码在前端,无法适应角色增减;人员列表无联动查询,审核时无法关联助教/员工。用户要求角色从数据库动态读取,并根据角色+门店查询对应人员列表。
- 思路分析:新增 `GET /api/tenant/roles` 端点,从 `auth.roles` 表动态读取小程序可用角色(排除 `tenant_admin`/`site_admin` 管理类角色),返回 `RoleItem` 列表。新增 `GET /api/tenant/site-staff` 端点,接收 `role` + `site_id`/`site_code` 参数,根据角色类型分流查询:`coach` 查 ETL 库 `dwd.dim_assistant``scd2_is_current=1`),其他角色查 `dwd.dim_staff`。关键决策:放弃 FDW 视图RLS 跨库不生效),改用 `get_etl_readonly_connection(site_id)` 直连 ETL 库底层表,手动加 `site_id` 过滤。`site-staff` 端点支持 `site_code` 参数(前端传球房编号),内部先查 `biz.sites` 转换为 `site_id`,再校验权限。
- 修改结果:租户管理员审核时可动态获取角色列表和对应人员列表。`site_admin``managed_site_ids` 权限限制,`tenant_admin` 可查所有店铺。ETL 直连方案绕过了 FDW RLS 跨库失效问题。
### `apps/backend/app/schemas/tenant_users.py`
- 变更类型:修改
- 原始原因:后端新增 2 个端点需要对应的响应 Schema。
- 思路分析:新增 `RoleItem`角色列表项id/code/name/description`StaffCandidate`人员候选项id/identity_label/name/mobile/entry_time/source`StaffCandidate.source` 字段标识数据来源(`assistant`/`staff`),前端据此构造 `staffBinding` 值(格式 `"source:id"`)。`identity_label` 统一承载助教的 `level` 和员工的 `staff_identity` 原始值。
- 修改结果:两个新 Schema 继承 `CamelModel`,自动 snake_case→camelCase 转换,与前端 TypeScript 接口定义对齐。
### `apps/tenant-admin/src/pages/UserApproval/index.tsx`
- 变更类型:修改
- 原始原因:前端 ReviewModal 组件角色下拉硬编码 3 个角色coach/staff/site_admin缺少 head_coach/manager且 site_admin 不应出现在小程序角色中。人员关联只有旧的 match-suggestions按手机号匹配无法列出全部人员供选择。
- 思路分析:角色下拉改为弹窗打开时调用 `GET /api/tenant/roles` 动态获取。新增 `handleRoleChange` 回调:角色变化时调用 `GET /api/tenant/site-staff` 获取人员列表,加载后按申请者手机号自动选中匹配项(前端逻辑)。人员下拉展示格式 `身份角色 - 姓名 - 手机号 - 入职时间`,首项为"无(不关联)"。`staffBinding` 值格式 `"source:id"`(如 `"assistant:123"`)或 `"none"`,提交时解析为 `assistantId`/`staffId`。修复两个语法问题:中文引号 `"无"` 与 JSX 双引号冲突(改用单引号包裹);`filterOption``option?.label` 类型断言(改用 `String()` 包装)。
- 修改结果审核弹窗角色下拉动态化4 个小程序角色),人员列表按角色+门店联动查询,手机号自动匹配,支持"无"选项。前端编译通过Vite HMR 正常。
## 合规检查
### 文档同步
- ⚠️ `apps/backend/app/routers/tenant_users.py` 新增 2 个端点后 `apps/backend/docs/API-REFERENCE.md``docs/contracts/openapi/backend-api.json` 需同步更新
- 新增端点 `GET /api/tenant/roles``GET /api/tenant/site-staff` 需补充到 API 文档
### OpenAPI Spec
- 接口代码已变更OpenAPI spec 需重新导出(`python scripts/ops/_export_openapi.py`
### DDL/迁移
- 无新增迁移 SQL
- ⚠️ DDL 基线待合并
### DB 文档
- 本次无数据库结构变更BD 手册无需更新
---
<!-- AI_CHANGELOG
| 日期 | Prompt | 变更 |
|------|--------|------|
| 2026-03-23 17:00:00 | 租户管理后台审核弹窗改造 | tenant_users.py 新增 roles + site-staff 端点tenant_users schema 新增 RoleItem + StaffCandidatetenant-admin ReviewModal 角色动态化 + 人员联动 + 手机号匹配 + 语法修复 |
-->