You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.3 KiB
9.3 KiB
04 saved-view 与看板视图契约
Type: research Status: resolved Blocked by: —
Question
brief 核心域要求「三 workspace 列表/看板/saved-view」,这两项是现有 demo 的已知薄弱点(P3「saved-view 未接」、I-06「pool·board 契约漂移」)。核实:
- saved-view:后端有无保存视图端点(CustomerWorkspaceController 或别处)?「未接」的确切含义是后端缺端点还是 demo 没接线?若有端点:出入参、视图 CRUD 形态。
- 看板视图:pool/overview/mine 三 workspace 的 board 端点与分组维度(按 stage?);I-06 漂移的准确事实——文档允许 pool·board、实现白名单无 pool 特判:当前 jar 实测 pool+board 返回什么(空/报错/降级列表?)。
- Demo 侧呈现决策输入:若后端不支持,如何「仅展示现象」;若支持,字段与交互形态。
Pointers
.scratch/customer-frontend-handover/gap-report.mdP3 条目 +.scratch/customer-e2e-r2/e2e-incr-checks.jsonI-06 原文。crm-customer的 CustomerWorkspaceController 源码(视图类型白名单就在其中或其 service)。- 现有 demo workspace 切换实现(index.html 搜 workspace / board)。
Answer
(研究子代理 2026-09-11,全部结论读码 + 既有 e2e 实测 JSON 佐证,未起服务。)
1. saved-view:后端端点齐全,P3-2「未接」= demo 没挂 UI,不是缺端点
平台端点(crm-preference,SavedViewController @ /api/preference/view)——CRUD 四件套全在:
| 端点 | 形态 | 证据 |
|---|---|---|
GET /view/list?scopeKey= |
列当前用户该 scope 自定义视图(按 seqNo) | SavedViewController.java:37-41 |
POST /view/save?scopeKey= + @RequestBody SavedView |
viewId 空=新建(服务端 UUID)、非空=覆盖编辑;isDefault 单值互斥(save/setDefault 前清同 scope 其余默认位) | SavedViewController.java:45-50;SavedViewServiceImpl.java:48-75,108-114 |
POST /view/delete?scopeKey=&viewId= |
删除 | SavedViewController.java:54-60 |
POST /view/set-default?scopeKey=&viewId= |
图钉设默认(单值互斥) | SavedViewController.java:64-70 |
- 出入参:
SavedView(viewId, name, conditions[], sortField, sortDirection, isDefault, seqNo);SavedViewCondition(field, operator, value)(SavedView.java:19-27、SavedViewCondition.java:13-17)。注意 save 是全平台唯一 @RequestBody JSON 例外(ADR-0017 不覆盖平台端点,API-SUMMARY.md:8、256)——demo 调它要发 JSON 不是表单。 - 客户侧消费已接线:
POST /api/customer/workspace/page入参带savedViewId(CustomerWorkspacePageParam.java:32);CustomerWorkspaceServiceImpl.applySavedView(:156-173)按 workspace 推 scopeKeycustomer.overview|mine|pool(:176-182,常量 CustomerConstants.java:67-69)读视图,经CustomerSavedViewFilter.translate翻成结构化条件 AND 叠加在 workspace 数据集上(不改 @DataScope 边界);RECENT 内置视图不接、视图不存在静默不叠加、board 两端点不接(仅 page 路径设 savedViewConditions,CustomerMapper.java:72-73)。 - demo 做自定义检索编辑器的合法值域:字段池 17 个(CustomerSavedViewFilter.java:36-52;其中 ownerUserId/ownerDeptId 仅 overview|mine、enterPoolTime 仅 pool,越 scope 静默跳过);操作符 8 值
in/notIn/contains/notContains/lt/gt/isNull/isNotNull(in/notIn 多值逗号分隔,CustomerSavedViewOperator.java:17-31);排序字段池仅createTime/lastValidFollowTime/enterPoolTime(CustomerSavedViewFilter.java:61)。未知字段/操作符/需值空值一律静默跳过(不报错)。 - bruno/menuBindings:
bruno-sync.config.jsonmenuBindings 三客户菜单齐(A4 客户管理/客户总览|我的客户|客户公海↔ scopeKeycustomer.*);但 SavedViewController Swagger tags 只挂「A3 商机管理/销售机会/自定义视图」(SavedViewController.java:36 等方法级),客户侧未挂深 tag——bruno 文档里客户 workspace 的 saved-view 归在商机菜单下。 - 结论:P3-2 原文即「API 全通,demo 未挂 UI」(gap-report.md:46)。后端无缺口,纯 demo 接线工作。
2. 看板视图与 I-06:两件事,须拆开
(a) 看板数据端点(crm-customer 域)——pool 已硬拒 67001,overview/mine 全通
- 端点:
POST /api/customer/workspace/board/summary、POST /api/customer/workspace/board/cards(CustomerWorkspaceController.java:43-54;tags 仅「A4 客户管理/客户总览|我的客户/看板列表」)。 - 分组维度:
groupColumn白名单三值stage→customer_stage / star→customer_star_level / 其他(含缺省)→relation_star_level(CustomerWorkspaceServiceImpl.java:185-191);summary 只返回有数据的分组{groupValue, cnt}(CustomerBoardSummaryDTO.java:17-20),空列骨架前端补;cards 必传groupValue否则 67001(:70-72)。 - pool 特判已实现:
assertBoardAllowed(CustomerWorkspaceServiceImpl.java:80-85)——pool 调任一 board 端点 →BusinessErrorException 67001「公海无卡片视图,看板仅支持客户总览/我的客户」(返工票 03,commitfb6044f2026-09-04 引入,早于 r2 jar 2026-09-05 22:29 全量重建;API-SUMMARY.md:68 同口径)。 - 实测佐证:e2e-core-r2-checks.json F-02——overview 的 summary stage/star/relation 三分组全 ✅(groups=[1,2,3] 等,sum=37)、cards stage=2 取卡命中样例 ✅。三套件 JSON 里没有 pool+board/summary 直测用例;按代码路径推断 pool+board = 67001 报错(不是空集、不是降级列表)。
- 原型预期(lanhu-tree-v29.md:42-44):A4 三列表原型只有列表/分屏/卡片视图页,无独立「看板」页(「看板视图」页只在 A5-1 项目管理、A6 数据看板);客户列表页顶部是「数据看板」统计条(a4-2-1*.txt 多处 u20/u58…「数据看板」),检索区有「常用检索 / 自定义检索 / 编辑检索」三段(a4-1-1/a4-2-1 txt:231-242)。返工票 03 拍板「公海只有列表/分屏两视图」。「看板列表」是 bruno 文档侧对 board 端点的命名。
(b) 形态偏好 view-form(crm-preference 域)——I-06 漂移的真正对象,且至今未修
- 端点:
GET /api/preference/view-form/get?scopeKey=(null=未设,前端默认 list)、POST /api/preference/view-form/save?scopeKey=&viewForm=(ViewFormController.java:32-48)——记忆用户在该 scope 上次选的视图形态(list/split/board),与 (a) 的数据端点无关。 - I-06 准确事实(e2e-incr-checks.json 原文):
{"case": "pool·board 被接受 ⚠ 契约漂移(§2.14 称拒绝;实现白名单无 pool 特判)——记档,票 06 聚合", "verdict": "⚠", "detail": "code=0(漂移非缺陷:归 Bruno/API-SUMMARY 文档侧处置)"}——即 savescopeKey=customer.pool&viewForm=board实回 code=0。白名单指ViewFormServiceImpl.ALLOWED_VIEW_FORMS = 全局 {list,split,board}(ViewFormServiceImpl.java:27-30,45-48),scope 无关,crm-preference 全模块无 pool 分支——当前源码仍是如此,漂移持续存在。文档侧已收口:API-SUMMARY.md:268 约定「pool 仅 list/split」+ :270 ⚠ 注记「前端不得依赖拒绝行为」;gap-report.md:68、matrix-a4-1-a4-3.md:13,71 同口径记档。 - 错误码区分:view-form 白名单越界(如
viewForm=card)= 68001(PreferenceConstants.java:15,I-06 实测吻合);pool 调看板数据端点 = 67001。两码别混。
3. Demo 呈现决策输入
现状(.scratch/customer-e2e/demo/index.html):
- 三 workspace 切换在(
switchWs:537-540);viewType 下拉只有 ASSIGNED/COLLABORATING/FOCUSED 三值(:180-184,缺 FOLLOW_UP_DUE/RECENT);全无 board 视图形态、无 view-form 存取、无 preference/view 四端点调用(全文件 0 命中)。 - 已有隐患:
loadSummary(:586)把 board/summary 当「汇总卡」用但没传 groupColumn(后端缺省落 relation_star_level 分组),且字段名对不上 DTO(demo 读it.count/it.name/it.key,DTO 实为cnt/groupValue)→ 数值大概率显 '--';ws=pool 时该调用吃 67001,汇总框落入 catch 显示报错文案。
建议(按「支持→接线、不支持→摆现象」):
- saved-view 支持:viewbar 加「自定义检索」下拉(GET /preference/view/list?scopeKey=customer.{ws})+ 选中后 page 带 savedViewId 重查;「编辑检索」弹窗按 17 字段 × 8 操作符造条件(save 发 JSON)。pool scope 同样可用(saved-view 不拒 pool,字段池自动限 enterPoolTime)。
- 看板支持(overview/mine):加形态切换 list/board,board 形态调 summary(groupColumn=stage,空组前端补骨架) + cards(groupValue=…) 三列渲染;pool 不给看板入口(原型即无),若要展示 I-06 现象:形态偏好仍允许存 board(实测 code=0)但数据端点 67001——可摆「形态记忆成功 + 看板数据拒绝」双现象注记。
- 最小摆法(不做完整交互时):pool 页签固定列表形态 + 汇总条显「公海无看板(67001)」提示;overview/mine 汇总条修字段名 cnt/groupValue 并显式传 groupColumn=stage;view-form get/save 接上即完成跨会话形态记忆演示。