## Answer **Status: resolved** ### A. 接线结论(定稿) 复用 crm-preference `user_saved_view` 平台能力,**不重写**。rule of three:商机是样本 1,客户是样本 2;样本 3 出现前不抽共享翻译器(各自 `XxxSavedViewFilter`)。 ### B. scope_key(定稿,3 个) | workspace | scope_key | |---|---| | 客户总览 | `customer.overview` | | 我的客户 | `customer.mine` | | 客户公海 | `customer.pool` | - **公海双视角(普通销售 / 领导)共用 `customer.pool`**:字段池相同,视角只影响行内操作(领取 vs 分配),不影响筛选条件。 ### C. `CustomerSavedViewFilter`(定稿) - filter_json → MyBatis-Plus wrapper 翻译器,对称 `OpportunitySavedViewFilter`。 - **字段池白名单**(票 03 定的可筛选列): | 字段 | 支持操作符 | |---|---| | 客户名称 / 客户编号 | 包含 / 不包含 | | 客户类型 / 行业 / 客户阶段 / 客户星级 / 关系星级 / 战略协议等级 / 已成交VIP等级 / 档案状态 / 地区 | 属于任一 / 不属于任一 | | 最近跟进时间 | 早于 / 晚于 / 从未跟进 / 已有跟进 | | 进入公海时间(仅 pool) | 早于 / 晚于 | | 销售负责人 / 销售部门(仅 overview / mine) | 属于任一 / 不属于任一 | | 创建时间 | 早于 / 晚于 | - **未知字段 / 未知操作符 → 跳过**(不报错,对称商机)。 - **排序字段池**:创建时间 / 最近跟进时间 / 进入公海时间(默认);客户名称等文本字段**不排**(参商机默认口径)。 ### D. PageParam 接入(定稿) - 三 workspace 的 PageParam(`CustomerOverviewPageParam` / `CustomerMinePageParam` / `CustomerPoolPageParam`)均加 `savedViewId`。 - ViewQueryImpl:有 `savedViewId` → 先调 `SavedViewService.get(viewId, scope_key)` 取 filter → 叠加 wrapper;无 → 不叠加。 - 前端进入 workspace:先 `GET /api/preference/view/list?scope_key=...` 取 `isDefault` 视图 → 带 `viewId` 调 `/page`(对称商机)。 ### E. 验收清单(spec 级,不写代码) 1. scope_key 唯一性:`customer.overview` / `customer.mine` / `customer.pool` 三值互斥,与商机 `opportunity.*` 无碰撞。 2. filter 白名单:白名单内字段 + 合法操作符生效;白名单外字段/操作符静默跳过。 3. 默认视图互斥:每 scope 仅一个 `isDefault`(crm-preference 已实现,验证客户三 scope 复用生效)。 4. 端到端:保存自定义检索 → 列表 → 再次进入带 viewId 恢复条件。 5. 数据范围不越权:saved-view 只叠加筛选,**不改变** @DataScope 数据范围。 ### F. 回填 / 下游 - **票 03**:字段池白名单来源(票 03 D 节共用列 + 差异列)。 - **crm-preference**:无改动(纯消费方)。