geopro/docs/superpowers/HANDOFF-vtk-category-view-r...

154 lines
16 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.

# 交接VTK 三维分析视图重构(按数据类型分组 + 对象树联动)
> 给下一个会话无缝接手。日期 2026-06-24。分支 `feat/vtk-3d-view`。
> 本会话**产出 spec + 实施 plan + openapi 修订,未改业务代码**——下一步是按 plan 执行实现。
>
> **速览**:把 VTK 左侧三 tab 重构为「按数据类型大类分组」两 tab经真实接口实测定分类/字段、opus 子代理评审、客户两轮交互确认后定稿。产出 spec`specs/2026-06-24-vtk-category-view-refactor-design.md`+ 实施 plan`plans/2026-06-24-vtk-category-view-refactor.md`8 phase/12 task+ openapi v0.6`docs/api/vtk-3d-openapi.json`)。
---
## ⏩ 实施进度2026-06-24 续会话Task 1-10 完成)
**已完成 Task 1-1010/12全部已提交、可编译、逻辑层单测全绿425 测试5 个失败均为 PROJ_DATA 环境性、非回归)。剩 Task 11-12main 接线总成)。**
提交链(在 `a7d558b` docs 之后):
```
a06d9e8 feat(data): createVolume(VoxelGenerateRequest) 重载+fromRequest 派生+请求体打印(mock) # Task10
3af7e44 feat(ui): VtkViewToolbar 画布工具条 + AxesSettingsDialog 坐标轴设置 # Task9
98114a3 feat(ui): CategoryAnalysisTab(QScrollArea 5段)+ColumnDrawer 两tab(旧栏隐藏过渡) # Task8
30e990d feat(ui): CategorySection 类型段组件 + DatasetFieldDictionary 缓存类 # Task7
40646f7 refactor(tree): 评审修复-抽 recomputeAllGsStates 去 nullptr 信号 hack # Task4-6 review 修复
c5b3907 feat(data): DatasetFieldDictionary 解析 arrayType/collectTime 映射+装置字典 # Task6
1978a31 feat(tree): GS 三态状态机(停 AutoTristate)+右键 ds/tm + checkedSourcesChanged # Task4+5(合并)
6b39901 test(data): 补 properties[1] 日期项断言
f00a214 feat(data): VoxelGenerateRequest/SliceGenerateRequest DTO + toJson # Task3
07cf75d feat(app): CategoryConfig 映射表 + splitByCategory # Task2
5a719ca feat(data): DsRow 加 dsTypeCode/properties + parseDsRows 解析 # Task1
```
**已就绪的新构件(均编译通过)**
- 逻辑层:`DsRow` 扩字段、`splitByCategory`(CategoryConfig 5 段)、`Vtk3dRequests`(Voxel/Slice DTO + toJson + `fromRequest`)、`DatasetFieldDictionary`(parseFieldMapping + 缓存类)、`ObjectTreeSelection`(aggregateGsState/dedupeSources)。
- 对象树:`ObjectTreePanel` GS 三态状态机(停 AutoTristate)+ 右键「选择▸ds/tm」+ `checkedSourcesChanged(QList<DataSource>)` 信号(**与旧 `checkedTmsChanged` 并存**Task 12 删旧)。
- UI 组件:`CategorySection`(段头装置/日期筛选+段体可勾选树+「+新增三维体」+双击详情)、`CategoryAnalysisTab`(QScrollArea 5 段setBuckets/section/勾选并集)、`ColumnDrawer` 已改两 tab(三维分析=analysisTab / 二维分析=col2D**旧 col3D_/colAnalysis_ 仍实例化但 hide()、不入 tab**,保留访问器供 main 过渡)、`VtkViewToolbar`、`AxesSettingsDialog`。
- data`Api3dRepository::createVolume(VoxelGenerateRequest)` 重载(组装真实请求体+打印+`lastVoxelRequest`),旧 `createVolume(VolumeBuildParams,name)` 保留。
**⚠️ 当前过渡态**app 可编译运行但「三维分析」tab 是**空的 CategoryAnalysisTab**(数据接线在 Task 12旧三维数据集/三维分析功能已隐藏。对象树 GS 三态+右键 ds/tm **已在现 app 生效**(旧 checkedTmsChanged 仍兼容可立即真实验证plan Task 4 Step 7 清单)。
**偏离 plan 的决策(已记录理由)**:① Task 4+5 合并一个 commitplan Task4 右键已引用 Task5 的 emitCheckedSources循环依赖② DatasetFieldDictionary 异步拉取下放 maindata 层无网络,类只内存缓存);③ CategorySection 段体先平铺populateDatasetList「项目根/GS/TM 容器节点分层」推迟 Task 12 接真实 StructNode④ createSlice 虚接口未改签名SliceGenerateRequest 组装并入 Task 12 main 层。
### 🔧 Task 11+12 待做main.cpp 接线总成,最高风险,须真实 app 验证)
`main.cpp` 1943 行,接线密集。关键现状符号位置:
- `:361` `new ColumnDrawer(centerWidget)` —— 需改传 dict构造已支持第2参 `DatasetFieldDictionary* dict=nullptr`)。
- `:397 refreshAnomalies` / `:448 refreshAnalysis` 闭包用 `drawer->colAnalysis()`
- `:442 c3 = drawer->col3D()``:641` c3 checkedDatasetsChanged→sceneCtrl`:653` c3 generateVolumeRequested→createVolume`:898/902` c3 verticalExaggeration。
- `:579/745` createSlice 调用(补 projectId + 组装 SliceGenerateRequest
- `:584/623` `colAnalysis()->setItemChecked``:666 ca=colAnalysis()`。
- `:1117/1267` 对象树 `checkedTmsChanged` 接线(→改 `checkedSourcesChanged` + confType 分流 `loadRowsAsync(projId, src.id, src.confType, 3, ...)`)。
- `:1134 splitByDimension`→`splitByCategory` + `analysisTab()->setBuckets``:1135 col3D/col2D setDatasets`。
- `:1215 clearCentral`。`:1328 drawer->expand()`。
**Task 11 缺口**`CategoryAnalysisTab`/`CategorySection` 尚无 colAnalysis 的 `setItemChecked`、异常子区 API三维体段需迁入 Column3DAnalysis 异常控件(参 `src/app/panels/columns/Column3DAnalysis.{hpp,cpp}` + main `:397 refreshAnomalies`)。
**Task 12 要点**plan §Task12 Step1-8 已详列):① 对象树勾选→confType 分流拉取→splitByCategory→analysisTab setBuckets② analysisTab checkedDatasetsChanged→并入 checkedProfiles/checkedAnalysis→pushChecked③ generateVolumeRequested→`VolumeParamsDialog` 扩展(左侧勾选源树·可二次增删 + 右侧「生成位置」下拉=项目内 GS/TM→组装 `VoxelGenerateRequest`→`createVolume(req)`;④ 工具条 `VtkViewToolbar` 叠加中央 QVTK + AxesSettingsDialog 接坐标轴;⑤ createSlice 补 `nav.currentProjectId()`;⑥ 删旧 checkedTmsChanged/col3D()/colAnalysis()/splitByDimension/Column3D* 引用 + setStructure 传对象树同源 StructNode容器分层。**建议新会话以充足上下文做,每步 build + 用户真实验证。**
> 下方为初版交接spec/plan 设计定论,仍有效)。
## 1. 背景
- 代码库 = 原版 web 系统(`D:\Git\lanbingtech\commercial-admin`,复刻权威)移植的 Qt6 桌面客户端。
- 现状 VTK 视图左侧 `ColumnDrawer` 是三 tab三维数据集/二维数据集/三维分析),`splitByDimension` 按 `ddCode` 分 3 维度。
- 需求(用户截图设计):把「三维数据集」并入「三维分析」,改成**按数据类型大类分组**(电阻率/视电阻率/瞬变电磁/三维体/切片),每类各自筛选+操作;对象树勾选联动、支持 GS/项目直挂数据;全局视图控制移 VTK 画布工具条。
## 2. 本会话已完成
1. **摸透现状源码**ColumnDrawer/Column3D*/DatasetDimension/DatasetListPanel/ObjectTreePanel/RepoTypes/NavDto/Api3dRepository/main.cpp 接线等)。
2. **真实接口实测定关键事实**(用用户给的 token 直连后端,见 §6——纠正了多个二手猜测。
3. **brainstorming 澄清全部设计决策**(容器布局、分类策略、对象树三态交互、装置类型、生成入口等)。
4. **产出 spec** 并经 **opus 子代理评审 + 据评审修订**GS 三态停 AutoTristate、properties 两接口形态澄清、帘面勾选链承接等)。
5. **产出实施 plan**8 phase/12 taskTDD bite-sized逻辑层完整测试代码、UI 层 build+手动验证)。
6. **客户两轮交互确认**收敛生成三维体交互(见 §3 第 5 条),同步更新 spec/openapi(v0.6)/plan。
7. **openapi 修订**:三维体归属层级 TM → GS/项目根 → 再放开 GS/项目根/TM。
## 3. 最终设计定论(核心,已写入 spec
1. **两 tab**「三维分析」5 段)+「二维分析」(现 `Column2DDataset` 不动)。
2. **大类分类按 `dsTypeCode`**(不是 ddCode——电阻率/视电阻率/瞬变电磁三者 ddCode 同为 `dd_inversion_data`,只 dsTypeCode 不同。映射表 `CategoryConfig` 驱动;三维体/切片按 ddCode`dd_voxel`/`dd_slice`)识别。
3. **对象树联动**
- 非根 GS = **三态复选框**聚合「GS 自身 ds 开关」+「子 TM 勾选」)+ 右键「选择▸ds/tm」**必须停用 `Qt::ItemIsAutoTristate`、手动维护三态**UserRole 存 ds 开关)。
- 项目根 = 无复选框、直挂 ds 固定显示、其下 TM 各自二态勾选。
- 信号 `checkedTmsChanged``checkedSourcesChanged(QList<DataSource{id,confType}>)`,按 `structParentConfType`(1=GS/项目, 2=TM) 分流 `loadRowsAsync`
4. **装置类型/采集时间筛选**:是 ds 结构化属性(`arrayType`/`collectTime`),值在 ds 行 `properties[]`confFieldId`DatasetFieldDictionary`(按 dsType 拉一次 `dynamicForm` 取 confFieldId↔fieldCode 映射 + 装置 value→中文字典解析。装置类型只电阻率/视电阻率段有。日期筛选按 collectTime三维体/切片回退 createTime
5. **新增三维体(客户两轮确认定稿)**
- **入口**:数据类型**段头**「+新增三维体」按钮(电阻率/视电阻率/瞬变段),**不在**对象树/容器节点右键。
- **源数据集** = 三维分析中**当前勾选的同类型 ds**(本段类型、可跨 GS
- 点击 → `VolumeParamsDialog`**左侧**树状(按 GS 分组)展示勾选源、**可勾选/取消供确认或二次修改****右侧**参数:名称、**生成位置**下拉、插值模型、水平/竖向间距、IDW 幂次、最大影响距离。
- **生成位置(归属)**:默认 = 源同属单 GS→该 GS、源跨 GS→项目根用户可改为**项目内任意 GS/TM**`structParentConfType` 1 或 2。源与归属解耦。
6. **VTK 画布工具条**:全局视图控制(坐标轴/比例/快捷视图/缩放)移到中央 VTK 竖排工具条;设置→`AxesSettingsDialog`(X/Y/深度 显示+min/max);快捷视图按钮文字「前/后/上/下/左/右」;复位=现「适配」。
7. **请求体 DTO**`createVolume/createSlice` 扩参,内部按 `VoxelGenerateRequest/SliceGenerateRequest` 组装真实请求体结构(仍 mock 存储、假 id`toJson` 序列化;重构落地即可从 UI 产出给后端联调的真实请求体。
8. **三维体/切片/异常**仍 `Api3dRepository` mock异常迁入三维体段。
## 4. 剩余工作 = 执行 plan
`plans/2026-06-24-vtk-category-view-refactor.md`8 phase/12 task依赖顺序
- **Phase 1-2**Task 1-3DsRow 扩展+parseDsRows / CategoryConfig+splitByCategory / 请求体 DTO —— **纯逻辑完整 TDD**
- **Phase 3-4**Task 4-6GS 三态状态机+checkedSourcesChanged / DatasetFieldDictionary —— 逻辑可单测。
- **Phase 5-6**Task 7-9CategorySection / CategoryAnalysisTab+ColumnDrawer / VtkViewToolbar+AxesSettingsDialog —— build+手动验证。
- **Phase 7-8**Task 10-12Api3d 扩参组装请求体 / 段重组(异常迁三维体段) / main.cpp 接线总成 + 退役 Column3DDataset/Column3DAnalysis。
**建议**subagent-driven每 task 新 subagent + task 间两阶段 review+ 独立 git worktree 隔离。每 task 自带测试/验证+commitPhase 间「新旧信号并存→Task 12 统一切换删旧」保证每次可编译。
**plan 中 Task 7 段头按钮 + Task 12 `VolumeParamsDialog` 扩展(左侧源列表二次增删 + 生成位置下拉)已按 §3.5 定稿写好。**
## 5. 待确认 / 风险
- **装置类型 value→中文 字典源**(唯一待坐实,不阻塞实现):实测 `arrayType` 原始值(如 `1429468249448449`**不在**该字段 `optionsObject`(另一套 id `1456095451258368…`)里;`parseDynamicForm:208` 也不翻译但用户说客户端属性面板显中文。Task 6 先用 optionsObject 建表 + 缺失回退原值。**需用户提供客户端数据集属性面板截图**以定位现有翻译路径(候选:`fieldConfigJsonObject.fieldDataRadius` 指向的全局字典 / `script/arrayTypeList`)。
- **段体容器树建法**Task 7 核心):段体要呈现「项目根/GS/TM 容器节点→ds」层级需 main 传 `setStructure`(对象树同源 StructNode+ ds 的 `structParentId/structParentConfType`Task 1 已解析)建容器节点。
- 三维体/切片/异常仍 mock后端就绪后切真实`I3dSceneRepository` 留缝,见 `HANDOFF-vtk-3d-backend-api.md`)。
## 6. 关键实测事实 + 接口(直连后端核实)
- 后端基址 `http://tenant.geomative.cn/pop-api`header `geomativeauthorization: Geomative <token>`token 本会话由用户提供,下会话需重新索取)。
- 样本项目「演示项目(高密度+瞬变)」`1438889436225536`:项目根 GS `1438889436291072` 下直挂 TMERT1-8 confCode=ERT、TEM1-15 confCode=TEM01**无中间 GS 层**(印证「项目根本质是 GS」「TM 可直挂项目根」)。
- **大类 dsTypeCode**:电阻率=`ERT platform inversion data`、视电阻率=`visual resistivity data`、瞬变电磁反演剖面=`DD TRANSIENT ELECTROMAGNETIC INVERSION`(三者 ddCode 同 `dd_inversion_data`)。
- **ds 行 `properties`**`dsObject/data/page`= `[{confFieldId,value}]` 数组;**`dynamicForm` 的 `properties`** = `{fieldCode:value}` map两接口形态不同勿混
- 装置类型字段 `arrayType`、采集时间 `collectTime`fieldCode装置枚举 `GET /business/script/arrayTypeList``[{itemValue,name}]`15 项)。
- 层级 `structParentConfType`1=GS/项目根2=TM`loadRowsAsync` 第 3 参即透传它(现状 main.cpp:1142 写死 2
- 详情接口 `dsObject/getDetail/{id}`、动态表单 `dsObject/dynamicForm/{id}`(客户端 `loadDatasetFormAsync`→`parseDynamicForm`)。
## 7. 代码地图
**现状关键文件(重构基础):**
| 文件 | 作用 |
|---|---|
| `src/app/panels/columns/ColumnDrawer.{hpp,cpp}` | 现三 tab 容器(→两 tab |
| `src/app/panels/columns/Column3DDataset/Column3DAnalysis/Column2DDataset` | 三栏现状(前两退役、二维不动) |
| `src/app/DatasetDimension.{hpp,cpp}` | splitByDimension→splitByCategory 替代) |
| `src/app/panels/DatasetListPanel.cpp` | populateDatasetList/卡片委托/applyDatasetFilter复用 |
| `src/app/panels/ObjectTreePanel.{hpp,cpp}` | 对象树GS:123 AutoTristate、:174 itemChanged、:207 右键) |
| `src/data/repo/RepoTypes.hpp` | DsRow扩 dsTypeCode/properties/structParent* |
| `src/data/dto/NavDto.cpp` | parseDsRows:116 / parseDynamicForm:179 |
| `src/data/api/Api3dRepository.{hpp,cpp}` | 三维体/切片/异常 mockcreateVolume/createSlice 扩参) |
| `src/data/repo/VolumeBuildParams.hpp` / `src/core/model/Anomaly.hpp` | 三维体参数 / 异常模型 |
| `src/app/main.cpp` | 接线(:388-460 异常/勾选、:1113-1225 对象树→分类分发) |
| `src/data/api/ApiProjectRepository.cpp` | loadRowsAsync parentConfType 透传 |
**新建plan §文件结构):** `CategoryConfig.hpp`、`DatasetCategory.{hpp,cpp}`、`Vtk3dRequests.{hpp,cpp}`、`DatasetFieldDictionary.{hpp,cpp}`、`CategorySection.{hpp,cpp}`、`CategoryAnalysisTab.{hpp,cpp}`、`VtkViewToolbar.{hpp,cpp}`、`AxesSettingsDialog.{hpp,cpp}` + 对应 tests。
**契约文档:** `docs/api/vtk-3d-openapi.json`v0.6-draft、真实 schema `docs/apis/business_OpenAPI.json`DsObjectDataVO/DsTypeVO/ArrayTypeVO
## 8. 铁律 / 注意
- **贴源码/实测,别凭印象**:本会话多次因二手猜测("装置类型要后端补字段"、"properties 形态矛盾"、归属层级)被用户/实测纠正——任何字段/语义先去代码或真实接口核实。
- **复用优先**DatasetListPanel/Api3dRepository/Column2DDataset 复用,不重写。
- **每 task TDD + 可编译 + commit**;不留 TODO 占位。
- 全部回复中文。
## 9. 相关
- spec`docs/superpowers/specs/2026-06-24-vtk-category-view-refactor-design.md`
- plan`docs/superpowers/plans/2026-06-24-vtk-category-view-refactor.md`
- 后端契约交接:`docs/superpowers/HANDOFF-vtk-3d-backend-api.md`(三维体/切片/异常端点)
- 记忆:`vtk-3d-persistence-structure`、`dataset-detail-types-catalog`、`web-3d-view-threetile`、`gpr-volume-design-trio`
- 提交:`eceb964`spec+openapi v0.5)、`ef10c35`plan + 客户变动 + openapi v0.6