geopro/docs/superpowers/HANDOFF-dataset-detail-char...

151 lines
12 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.

# 交接文档:数据集详情图表 + 全 App 网络层异步化
> 给下一个会话:读完本文件即可无缝接手。最后更新 2026-06-12。
> 分支 **`feat/dataset-detail-chart`**,领先 main **68 commits**,工作区干净,**测试 116/116 全绿**。
---
## 0. 一句话现状
geoproQt6/C++ 离线桌面客户端1:1 复刻赛盈地空 web已完成两大块
1. **数据集详情图表**(仅 ERT 反演 `dd_inversion_data`QwtPlot 落地,用户已验收)。
2. **全 App 网络层 100% 异步化**(详情/导航/登录/项目列表全异步,同步 `QEventLoop` 阻塞路径已彻底删除,无技术债)。
均**未合并入 main**,分支挂起等收尾。
---
## 1. 背景
- geopro = **Qt6 / C++ 离线桌面客户端**,目标**像素级 1:1 复刻** web 系统 `http://tenant.geomative.cn/#/projectSpace/datasetMange/datasetInfo`(赛盈地空)。
- **硬约束**:禁 QWebEngine/Chromium离线。图表用本地 **QwtPlot轴/交互/图例)+ VTK 算法层(等值线几何)+ 连续/离散色阶**。验收 = **视觉等价 + 交互一致**(非字节级 diff
- **标准测试 ds**`id=1458990939709440`ddCode=dd_inversion_data
- 站点 baseUrl`http://tenant.geomative.cn/pop-api`。Auth header`geomativeauthorization: Geomative <token>`。
---
## 2. 技术栈与构建/测试
- Qt6 Widgets + **Qwt 6.2**(源码 `external/qwt-src/`**用 `cmake/qwt.cmake` 以 CMake 构建**静态库,**不要用 qmake**——本机 VS2026 缺 vswhere
- **VTK 9.6 仅算法层**`vtkBandedPolyDataContourFilter`/`vtkStripper`/`vtkSplineFilter`/`vtkDataSetSurfaceFilter`),不做 VTK 渲染。
- CMakeVS 自带)+ Ninja + MSVC 14.51GoogleTest/CTestvcpkg仅非 Qt 依赖)。
- **构建**`powershell.exe -ExecutionPolicy Bypass -File scripts/dev-build.ps1`
- ⚠️ `LNK1104 无法打开 geopro_desktop.exe` = exe 在运行:先 `Get-Process geopro_desktop -ErrorAction SilentlyContinue | Stop-Process -Force` 再构建。
- ⚠️ **改头文件后偶发** ninja 增量陈旧导致链接报「符号在 main.cpp.obj 重复定义」:删 `build/release/src/app/CMakeFiles/geopro_desktop.dir/main.cpp.obj` 后重建。
- **测试**`powershell.exe -ExecutionPolicy Bypass -File scripts/dev-test.ps1`**只跑 ctest 不构建——必须先 dev-build**)。当前 **116/116 绿**
- 单测过滤:`build/release/tests/geopro_tests.exe --gtest_filter=ApiBatch.*`
- ⚠️ 直接跑 exe 时 4 个 `CrsTransform/VoxelRegister/Terrain` 失败是缺 `PROJ_DATA` 环境项;**ctestdev-test会注入环境、全绿**——以 dev-test 的 "X/X passed" 为准。
- **网络/署名**AuthLiveTest 联网真打站点;提交信息**全局禁用署名**(勿加 Co-Authored-By
---
## 3. 第一块:数据集详情图表(已完成,仅 dd_inversion_data
详情含两页签,均经用户逐项验收:
- **原数据**Plotly scattergl 风格散点(方形点/白描边/连续色阶/x 轴顶部)。
- **网格数据**:填充等值面(栅格 QImage+ 黑色等值线vtkStripper+vtkSplineFilter 样条平滑,**每条线只标一个**数值)+ NaN 白边裁剪 + 底部异常表/描述。
数据 API均经 Playwright 实测):
| 页 | 接口 |
|---|---|
| 原数据 | `lvl/colorGradation/getDetail`(type1) + `dd/ert/inversion/getErtRawDataScatterGraph/{id}` |
| 网格 | `dd/ert/inversion/rows/{id}`(服务端网格化,**波动 14s**) + `colorGradation/getDetail`(type2) + `exception/queryException/{id}` |
> ⚠️ 架构偏离:原 spec 定 QGraphicsView**实际落地用 QwtPlot**(见 `plans/2026-06-11-dataset-detail-chart-v2-qwt.md`,权威)。
**策略分派已打通**(本次会话):控制器从硬编码 `dd_inversion_data` 改为走 `ChartStrategyRegistry`(在 **controller 层** `src/controller/IDatasetChartStrategy.hpp`,含 `hasGridPhase()`),未注册类型优雅降级「暂不支持」。`ErtInversionStrategy`app 层)已注册。**这是接其余 dd 类型的地基**。
---
## 4. 第二块:全 App 网络层异步化(本次会话完成,无技术债)
**动机**:原 `ApiClient``QEventLoop` 死等每个请求 → 全 App 冻 UI网格 rows 14s 最痛)。
**核心安全不变量spec §5.0,务必遵守)**「abort 后绝不回灌」靠三件套——
1. 每层 `aborted_` 入口守卫(`disconnect` 只是尽力而为,挡不住已入队的迟到信号);
2. 控制器**句柄身份比对**`if (load != current_) return;` 丢弃迟到信号);
3. **一律 `deleteLater`**,禁止同步 delete。
错误判定口径:业务 `code != 200 || !rawError.isEmpty()`HTTP 200 也可能 code=500
**net 层原语**`src/net/`AUTOMOC 已 ON
- `IApiCall`/`ApiCall`:单请求句柄(包 QNetworkReply`finished(ApiResponse)` + `abort()`,自管理 deleteLater。
- `ApiBatch`**并发汇聚** N 个 IApiCall全成功 `succeeded(QList)` / 任一失败 **fail-fast** `failed(i,resp)`+abort 其余。
- `ApiChain`**串行依赖链**(上步结果喂下步工厂,工厂可抛转 failed。**契约:首个 step 工厂不得同步抛/同步 fire**(否则信号在调用方连接前丢失;生产路径都发异步请求,满足)。
- `ApiResponseParse::buildResponse`sync/async 共用解析(已无 sync 调用方,仅 ApiCall 用)。
- `ApiClient`:仅 `getAsync/postJsonAsync`**同步 `get/postJson`/`await`/QEventLoop 已删除**)。
**data 层**
- 详情:`ChartLoad`/`GridLoad`(抽象基 + `ApiChartLoad`/`ApiGridLoad` 实现,包 ApiBatch + 注入 parse、`IAsyncDatasetRepository`、`ApiDatasetRepository.loadChartAsync/loadGridAsync`、`DatasetLoads.hpp`(ChartParts/GridParts)。
- 导航:`NavRequest`(单非模板句柄,`done(QVariant)`/`failed(QString)``ApiNavRequest` 包 IApiCall + 解析器)、`NavLoads.hpp`(各类型 `Q_DECLARE_METATYPE`)、`IAsyncProjectRepository`9 方法 `...Async` 后缀,返回 `NavRequest*`,薄封装;汇聚/链编排放控制器)、`ApiProjectRepository` 仅实现异步接口。
**controller 层**
- `DatasetDetailController`abort-and-replace + 句柄身份比对 + `loadStarted(dsId,Phase)` + 析构 abort`ChartStrategyRegistry` 分派。
- `WorkbenchNavController`全异步NavRequest 续延依赖链 + 控制器内并发计数 + abort-and-replace + 身份比对);**删除 `busy_`/`BusyGuard`/`drainPendingCheckedTms`**`busyChanged(bool)` 语义改为「有在飞句柄」(去抖);`setCheckedTms` 入口去重 + 「最后一次为准」由 abort-and-replace 承接 + `tmExceptionCache_` 缓存命中不发请求。对外信号面**零改动**main.cpp 接线没动)。
**app 层**
- `AuthService`net 层):`fetchCaptchaAsync()→CaptchaLoad`、`loginAsync()→LoginLoad`(内用 ApiChainverifyCodeCheck→RSA(step2 工厂内)→login2。`LoginWindow`:不冻 + 可取消(析构 abort`repaint()` hack。
- `ProjectListDialog`:改用 `IAsyncProjectRepository`NavRequest + abort-and-replace + 身份比对 + 析构 abort过滤/分页/选项目行为等价。
- `LoadingOverlay`:网格懒加载「加载中」遮罩,接 `loadStarted`、就绪/失败隐藏。
- `main.cpp``qRegisterMetaType<ApiResponse>()`;装配注入 registry/异步 repo引用绑定接线信号面不变
**执行方式**:全程 subagent-driven每块 implementer + spec 符合度评审 + 代码质量评审 opus + follow-up 加固)。测试 75 → 116+41含 abort 回灌防护回归用例)。
---
## 5. 关键文件地图
- net`src/net/{IApiCall.hpp,ApiCall.*,ApiBatch.*,ApiChain.*,ApiResponseParse.*,ApiClient.*,AuthService.*,AuthLoads.*}`
- data`src/data/api/{DatasetLoads.hpp,DatasetLoadHandles.*,ApiDatasetRepository.*,NavRequest.*,NavLoads.hpp,ApiProjectRepository.*,DatasetChartDto.*}`、`src/data/repo/{IAsyncDatasetRepository.hpp,IAsyncProjectRepository.hpp,IDatasetRepository.hpp(本地样例同步,保留),RepoTypes.hpp}`
- controller`src/controller/{DatasetDetailController.*,WorkbenchNavController.*,IDatasetChartStrategy.hpp}`
- app`src/app/main.cpp`、`src/app/panels/{DatasetDetailPanel.*,DatasetDetailPage.*,LoadingOverlay.*,chart/*}`、`src/app/login/LoginWindow.*`、`src/app/ProjectListDialog.*`、`src/app/panels/chart/ErtInversionStrategy.hpp`
- 测试:`tests/net/{FakeApiCall.hpp,test_api_batch.cpp,test_api_chain.cpp,test_auth.cpp(live),test_auth_loads.cpp}`、`tests/data/{test_nav_request.cpp,test_dataset_load_handles.cpp}`、`tests/controller/{test_dataset_detail_controller.cpp,test_workbench_nav_controller.cpp}`、`tests/app/test_chart_strategy_registry.cpp`
---
## 6. 尚未完成 / 下一步(按优先级)
### A. 收尾本分支(最先)
分支领先 main 68 commits、116/116 绿、工作区干净。用户多次选「保持现状」未合并。下一步可问用户:①合并回 main(本地) ②推送建 PR(origin=gitea `https://gitea.geomative.cn/gaozheng/geopro.git`) ③保持现状。用 `superpowers:finishing-a-development-branch`
### B. 其余 dd 类型详情图(计划已写,多数 BLOCKED
计划:`plans/2026-06-11-dataset-detail-other-dd-types.md`。
- **Phase 1策略分派打通✅ 已完成**(本次会话)。
- **Phase 0样本探查需做**——用 Playwright 登录原版 web对每类 dd 找有数据对象、抓真实响应存 fixtures + 渲染规格。**这是后续所有类型的前置。**
- **Phase 2ERT 测量散点)/ Phase 3TEM 折线,新 LineChartView**:仅当 Phase 0 确认有样本才解锁。
- **Phase 4BLOCKED**——dd_grid/轨迹/测井/GPR**当前租户无活数据样本**GPR 对象无数据、无测井数据),按 1:1 复刻铁律不能凭空实现。
- 矩阵详见计划文件。
### C. 工具条编辑类功能(网格页占位按钮,未做,单独立项)
白化 / 滤波处理 / 色阶配置 / 异常框注 / 自动标注 / 网格化 / 另存为 / 导出 / 描述富文本 / 大视图(Esc)全屏。当前是占位按钮。交互较重,建议先 brainstorm 拆解。spec §2.3 列为范围外。
### D. 纯整洁 follow-up非债、非阻断
-`DatasetDetailController::ChartData.grid/gridScale` 死字段(从未填充,预存)。
- 若未来引入 cross-thread/QueuedConnection再补 `qRegisterMetaType<QList<ApiResponse>>()`
---
## 7. 相关文档
- **spec**`docs/superpowers/specs/2026-06-11-apiclient-async-design.md`(异步设计 + §5.0 安全不变量 + §7 错误判定/退出契约 + 顶部「状态更新」=已完成)、`docs/superpowers/specs/2026-06-11-dataset-detail-view-design.md`(详情视图,顶部状态=仅 ERT 反演完成 + QwtPlot 偏离)。
- **plan**`docs/superpowers/plans/2026-06-11-apiclient-async-datasetdetail.md`(详情试点)、`2026-06-11-apiclient-async-rollout.md`(导航 Part A + 登录 Part B均落地、`2026-06-11-dataset-detail-other-dd-types.md`(其余 dd 类型Phase 1 done、`2026-06-11-dataset-detail-chart-v2-qwt.md`QwtPlot 返工,权威)。
- API 文档:`docs/apis`business_OpenAPI.json
- 外部方案:`docs/Geopro3.0_二维图表返工技术方案.md`。
---
## 8. 记忆(务必遵守,`~/.claude/projects/D--Git-lanbingtech-geopro/memory/`
- `reply-in-chinese` — 全程中文回复。
- `study-original-via-playwright`**任何不确定必须用 Playwright 实地看原版,禁止臆测**(尤其做新 dd 类型详情图前抓样本/规格)。
- `no-embellishment-replicate-exactly` — 严格 1:1不加原版没有的特性曾因等值线「周期重复标注」被纠正
---
## 9. 工作方式备注(本次会话沿用,效果好)
- 用户偏好 **subagent-driven** 执行 + 实现后 **code review + spec 符合度** 双评审opus 评审);「非必要不停,一口气做完」。
- **真并行构建在本项目不安全**dev-build 硬编码单一 build 目录 + 多任务共改 main.cpp/CMakeLists→ 用顺序执行worktree 隔离不了构建(硬编码路径 + 冷配置开销)。
- 破坏性接口改形需**原子落地**(同批提交)保持构建绿(详情试点 Task5+6 合并、Part A A4+A5、本次清债 都是此教训)。
- 评审 follow-up 多为小加固直接在新代码上补「不为不可能的场景写错误处理」CLAUDE.md §2——评审若建议为构造保证不会发生的情况加防御可不采纳。
</content>