# Prototype Review

- 审查目标：`src/prototypes/customer-management`（列表页 + 新增页，重点为风险标签与 KPI 卡片筛选）
- 用户资料/参考资料：
  - 本轮用户说明：风险标签「前台分区、权限分责、底层统一」改造诉求；11 项标签目录与分组权限（信用与回款→财务、合规与法律→法务、经营与履约→业管、开票异常→财务、多头签约→业管）；KPI 卡片筛选不同类型风险客户
  - `.spec/requirements-prd-list.md`、`.spec/requirements-prd-create.md`
  - `src/resources/oneos-web-legacy/需求说明/业务管理/客户管理`
  - 源码：`index.tsx`、`components/*`、`utils/*`、`types/*`、`data/*`
  - `.axhub/make/project.json`（入口与命名）
  - `annotation-source.json`（标注与 PRD 摘要）
- 生成时间：2026-06-30

## 总体点评

客户管理原型在**风险标签列表维护**方向上已形成较完整的演示闭环：统一 `riskTagsByCustomer` 模型、按法务/财务/业管三分区 Drawer、角色切换、打标/审批/日志、批量打标，以及 8 张 KPI 卡片快速筛选，与近期用户口头决策高度一致，业务表达明显强于旧版 PRD 所描述的「单列表 + 运维/风控打标」方案。

当前最影响「需求评审可签字」的问题，不是单个控件缺失，而是**书面规格与实现、Legacy 需求三套口径并行**：`.spec/requirements-prd-list.md` 与 `annotation-source.json` 仍保留旧标签归属（如频繁争议→法务、车辆/资产→运维）、旧角色表（王风控/赵运维打标）、旧抽屉结构（单列表 Tab）和旧风险级别（极高），而源码已改为业管维护经营类标签、8 角色模拟、三分区卡片、致命级枚举与 KPI 卡片。评审若仍引用 PRD 旧章节，会产生「实现错了」的误判。

主流程方面，**列表 + 新增 + 风险标签维护**可演示；但 **详情/编辑/查看** 仍为 Toast，Legacy 与 PRD 均将其列为核心任务，主流程出口不完整。高风险标签的**解除申请**已能提交，但缺少与「新增待审批」对等的审批闭环，业务生命周期在「解除」分支上断档。

## P0-P3 优先级问题

### P1 - 书面 PRD / 标注与当前实现严重脱节，无法作为验收基线

- 证据：`requirements-prd-list.md` §5.1、§7.3–§7.4、§8–§9 仍描述运维/风控打标、标签类型「极高」、抽屉「当前标签」为扁平列表；`annotation-source.json` 中 `cm-risk-tag-drawer` 等节点摘要同步旧版。源码 `utils/riskTagConstants.ts` 已为 11 项目录 + 业管维护经营与履约；`permissions.ts` 为 8 角色且业管/财务/法务分责；`RiskTagDrawer.tsx` 为三分区卡片；`RiskKpiCards.tsx` + `utils/riskKpi.ts` 为 KPI 筛选，PRD §1 页面结构未收录。
- 影响：产品、测试、开发若按 PRD 验收会系统性误判通过/不通过；标注阅读体验与真实原型行为不一致，需求评审无法形成单一真相源。
- 修复方向：以当前源码与用户最新标签规则为准，回写 `requirements-prd-list.md` §1、§5、§7–§11 及 `annotation-source.json`；明确 KPI 卡片口径、三分区 Drawer、11 标签目录、8 角色权限表；标注「资料冲突/待确认」处需产品确认后再冻结。

### P1 - 详情 / 编辑 / 查看主流程未实现，Legacy 与 PRD 核心任务出口缺失

- 证据：PRD 列表 §1 核心任务含「进入详情/编辑」；Legacy `src/resources/.../客户管理` §2.16 要求查看页、编辑页与删除确认；源码 `index.tsx` 中 `onView` / `onEdit` 仅 `showToast('…原型演示')`，无页面路由或表单回显。
- 影响：客户主数据「查—改—审标签—回看档案」链条在列表之后中断；无法验证编辑态是否仍遵守「不在编辑页维护风险标签」约束；与 OneOS Legacy 模块能力不对齐。
- 修复方向：至少补充查看页/编辑页原型（可为只读详情 + 基础字段编辑），并在 PRD 标明与列表标签维护的边界；删除保留二次确认 Mock 即可。

### P1 - 高风险 / 致命标签「解除申请」缺少审批闭环

- 证据：用户改造要求「高风险和致命标签不能直接移除，只能提交解除申请或审批」；`index.tsx` `handleRemoveTag` 在 `isApplication` 时仅设 `removalRequested: true` 并写日志，标签仍为 `active`；`RiskTagDrawer.tsx` 审批面板仅处理 `status === 'pending'` 的新增待审批，无「解除待审批」审批入口与通过/驳回后状态迁移（`removed` / 保持生效）。
- 影响：演示「解除高风险标签」时业务状态停在中间态，审计链路不完整，测试无法覆盖解除审批场景。
- 修复方向：为 `removalRequested` 增加审批 UI（可与新增审批共用面板，区分动作类型）；通过后 `status → removed` 并同步 `labels`；驳回则清除 `removalRequested` 并记录原因。

### P2 - 列表筛选与 KPI 卡片口径分裂，易产生「筛不出 / 数不对」误解

- 证据：筛选区「标签」多选（`FilterPanel.tsx` + `filters.ts`）匹配 `record.labels`，而 `syncRecordLabels` 仅同步**生效中**标签；KPI（`utils/riskKpi.ts`）基于 `riskTagsByCustomer`，「有风险客户」「高风险/待审批」含 `pending` 标签；KPI 切换即时生效，筛选区仍须点「查询」才生效（`pendingFilters` / `appliedFilters` 分离）。
- 影响：同一客户可能在 KPI「高风险/待审批」命中，但筛选区「标签」选不到对应名称；KPI 与高级筛选组合时，用户难以理解最终列表口径。
- 修复方向：统一筛选数据源（建议以 `riskTagsByCustomer` 为准并支持按 tagGroup / category / status 筛）；或在 KPI 激活时联动写入 `appliedFilters`；在 PRD 补充 KPI 与筛选区优先级说明。

### P2 - Legacy 客户台账字段模型与原型列表差异大，合作状态等关键字段未贯通

- 证据：Legacy 要求列表含合作状态、城市、联系人、创建人等；原型 `CustomerRecord` / `CustomerTable` 为工商宽表 + 客户状态（正常/黑名单）+ 业务部门/负责人；新增页有「合作状态」（`CreatePage.tsx`），但列表无该列、筛选无合作状态，提交后也不落库（Toast 返回）。
- 影响：与 OneOS 既有「业务管理-客户管理」认知不一致；无法演示「按合作状态 + 风险标签」联合运营场景；新增字段与列表台账脱节。
- 修复方向：产品确认本原型是「风险增强版台账」还是「Legacy 对齐版」；若对齐 Legacy，补充合作状态/城市等列与筛选，并将新增 Mock 写入本地 state；若刻意简化，在 PRD 写清「不做范围」并与 Legacy 文档交叉引用。

## 完整性与项目对齐

| 维度 | 结论 |
|---|---|
| 核心用户 | 销售、业务负责人、法务、财务、业管、风控、管理层 — 角色切换已覆盖；运维角色可切换但无打标权限，与「经营与履约归业管」一致 |
| 主流程 | 列表筛选 → KPI 卡片 → 表格 → 风险标签 Drawer → 打标/审批/日志：**可演示**；新增页 → 校验 → Toast：**可演示**；详情/编辑/查看：**未实现** |
| 入口/出口 | 入口：侧边栏 `customer-management`（`project.json`）；出口：新增返回列表、Drawer 关闭保持列表状态 — **符合**；缺详情/编辑出口 |
| 范围边界 | PRD 声明导入/导出/删除为 Toast 演示 — **一致**；风险标签不在新增/编辑页维护 — **实现一致**；KPI 卡片、三分区 Drawer、11 标签 — **实现有、PRD 无** |
| 项目 metadata | 原型 id `customer-management`，入口 `index.tsx` — **对齐** |
| 资料冲突/待确认 | ① PRD/annotation vs 当前实现（标签归属、角色、KPI）— **待产品确认并以新口径回写 PRD**；② Legacy vs 原型字段模型 — **待确认范围**；③ 用户会话要求「致命」级 vs PRD「极高」— **实现用 fatal/致命，PRD 未更新**；④ 用户要求高风险附件必填 vs PRD §8.3 附件选填 — **实现已必填，PRD 待确认** |

## 业务逻辑连贯性

**流程顺序**：列表加载 → 角色切换 →（可选）KPI 卡片 / 筛选查询 → 行内打开 Drawer → Tab 切换打标/日志 — 顺序合理。批量打标依赖行选 + 权限，与单客户打标共用表单校验 — 一致。

**状态迁移**：新增低风险/中风险 → `active` 并同步 `labels`；高/致命 → `pending` → 审批 → `active`/`rejected` — **新增链路完整**。移除：低/中风险可直接 `removed`；高/致命仅 `removalRequested` — **解除链路不完整**（见 P1）。复核：`expireDate` 过期展示「待复核」Banner — **前端 Mock 可感知**。

**角色权限**：财务/法务/业管/ admin 可维护各自分区；销售/运维/风控/管理层查看或审批 — 与最新用户标签分组决策一致，但与 PRD §9 冲突。风控、管理层不可新增标签 — 符合用户会话；PRD 仍写风控可打全部标签。

**数据生命周期**：底层统一 `CustomerRiskTag[]`，列表 `labels` 为生效中投影 — 架构自洽。黑名单客户（`status === '黑名单'`）与「严重拖欠/制裁触发黑名单审批」仅 Toast 提示，未驱动 `status` 变更 — 业务联动待补。

**跨页面**：新增页合作状态、省市识别已实现；返回列表后数据不持久 — 原型可接受，但削弱与列表/KPI 联调。

## 状态、异常、边界与恢复

| 类别 | 检查结论 |
|---|---|
| 输入校验 | 打标：原因 ≥10 字、高/致命需附件、日期区间 — **有**；新增客户：必填 Toast — **有**但无字段级恢复（属 UI 范畴，业务上可感知错误） |
| 空/无数据 | 表格空态、分区「暂无该类风险标签」、无日志兜底 — **有** |
| 权限不足 | 销售新增 Tab 无权限文案、分区只读提示 — **有** |
| 重复打标 | 同名有效标签拦截 — **有** |
| 批量部分成功 | 已存在标签客户跳过 — **有**；缺批量结果汇总 Toast（条数/跳过数） |
| 并发/重复点击 | 无防抖；Mock 环境风险低 |
| 网络/集成失败 | 未模拟（原型范围外） |
| 恢复路径 | Drawer 内 error 区展示校验失败；审批驳回需填原因 — **有**；解除申请无后续恢复 — **缺** |
| KPI + 筛选重置 | 「重置」清空筛选并回到 KPI「全部客户」 — **有** |

## 证据与评估说明

- **用户资料优先级**：本轮用户说明（11 标签、分组权限、KPI 卡片、三分区 Drawer）权重高于旧 PRD 章节；评审中已将 PRD/Legacy 与实现冲突标为「待确认」。
- **读取范围**：`.spec/requirements-prd-list.md`、`requirements-prd-create.md`；`src/resources/oneos-web-legacy/需求说明/业务管理/客户管理`；`index.tsx`、`CreatePage.tsx`、`FilterPanel.tsx`、`CustomerTable.tsx`、`RiskTagDrawer.tsx`、`RiskTagForm.tsx`、`RiskLabelTags.tsx`、`RiskKpiCards.tsx`、`BatchRiskTagModal.tsx`；`utils/filters.ts`、`riskKpi.ts`、`riskTagStore.ts`、`riskTagConstants.ts`、`permissions.ts`；`types.ts`、`types/riskTag.ts`；`data/customers.json`、`risk-tag-operation-logs.json`；`.axhub/make/project.json`；`annotation-source.json`（摘要）。未读取 Impeccable 产物。
- **独立评估**：`degraded` — 未拆分子代理；业务基线与源码证据在同一轮审查中完成，已尽量先建立基线再对照实现。
