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

12 KiB
Raw Blame History

交接文档:数据集详情图表 + 全 App 网络层异步化

给下一个会话:读完本文件即可无缝接手。最后更新 2026-06-12。 分支 feat/dataset-detail-chart,领先 main 68 commits,工作区干净,测试 116/116 全绿


0. 一句话现状

geoproQt6/C++ 离线桌面客户端1:1 复刻赛盈地空 web已完成两大块

  1. 数据集详情图表(仅 ERT 反演 dd_inversion_dataQwtPlot 落地,用户已验收)。
  2. 全 App 网络层 100% 异步化(详情/导航/登录/项目列表全异步,同步 QEventLoop 阻塞路径已彻底删除,无技术债)。

未合并入 main,分支挂起等收尾。


1. 背景

  • geopro = Qt6 / C++ 离线桌面客户端,目标像素级 1:1 复刻 web 系统 http://tenant.geomative.cn/#/projectSpace/datasetMange/datasetInfo(赛盈地空)。
  • 硬约束:禁 QWebEngine/Chromium离线。图表用本地 QwtPlot轴/交互/图例)+ VTK 算法层(等值线几何)+ 连续/离散色阶。验收 = 视觉等价 + 交互一致(非字节级 diff
  • 标准测试 dsid=1458990939709440ddCode=dd_inversion_data
  • 站点 baseUrlhttp://tenant.geomative.cn/pop-api。Auth headergeomativeauthorization: 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()),未注册类型优雅降级「暂不支持」。ErtInversionStrategyapp 层)已注册。这是接其余 dd 类型的地基


4. 第二块:全 App 网络层异步化(本次会话完成,无技术债)

动机:原 ApiClientQEventLoop 死等每个请求 → 全 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:单请求句柄(包 QNetworkReplyfinished(ApiResponse) + abort(),自管理 deleteLater。
  • ApiBatch并发汇聚 N 个 IApiCall全成功 succeeded(QList) / 任一失败 fail-fast failed(i,resp)+abort 其余。
  • ApiChain串行依赖链(上步结果喂下步工厂,工厂可抛转 failed契约:首个 step 工厂不得同步抛/同步 fire(否则信号在调用方连接前丢失;生产路径都发异步请求,满足)。
  • ApiResponseParse::buildResponsesync/async 共用解析(已无 sync 调用方,仅 ApiCall 用)。
  • ApiClient:仅 getAsync/postJsonAsync同步 get/postJson/await/QEventLoop 已删除)。

data 层

  • 详情:ChartLoad/GridLoad(抽象基 + ApiChartLoad/ApiGridLoad 实现,包 ApiBatch + 注入 parseIAsyncDatasetRepositoryApiDatasetRepository.loadChartAsync/loadGridAsyncDatasetLoads.hpp(ChartParts/GridParts)。
  • 导航:NavRequest(单非模板句柄,done(QVariant)/failed(QString)ApiNavRequest 包 IApiCall + 解析器)、NavLoads.hpp(各类型 Q_DECLARE_METATYPE)、IAsyncProjectRepository9 方法 ...Async 后缀,返回 NavRequest*,薄封装;汇聚/链编排放控制器)、ApiProjectRepository 仅实现异步接口。

controller 层

  • DatasetDetailControllerabort-and-replace + 句柄身份比对 + loadStarted(dsId,Phase) + 析构 abortChartStrategyRegistry 分派。
  • WorkbenchNavController全异步NavRequest 续延依赖链 + 控制器内并发计数 + abort-and-replace + 身份比对);删除 busy_/BusyGuard/drainPendingCheckedTmsbusyChanged(bool) 语义改为「有在飞句柄」(去抖);setCheckedTms 入口去重 + 「最后一次为准」由 abort-and-replace 承接 + tmExceptionCache_ 缓存命中不发请求。对外信号面零改动main.cpp 接线没动)。

app 层

  • AuthServicenet 层):fetchCaptchaAsync()→CaptchaLoadloginAsync()→LoginLoad(内用 ApiChainverifyCodeCheck→RSA(step2 工厂内)→login2LoginWindow:不冻 + 可取消(析构 abortrepaint() hack。
  • ProjectListDialog:改用 IAsyncProjectRepositoryNavRequest + abort-and-replace + 身份比对 + 析构 abort过滤/分页/选项目行为等价。
  • LoadingOverlay:网格懒加载「加载中」遮罩,接 loadStarted、就绪/失败隐藏。
  • main.cppqRegisterMetaType<ApiResponse>();装配注入 registry/异步 repo引用绑定接线信号面不变

执行方式:全程 subagent-driven每块 implementer + spec 符合度评审 + 代码质量评审 opus + follow-up 加固)。测试 75 → 116+41含 abort 回灌防护回归用例)。


5. 关键文件地图

  • netsrc/net/{IApiCall.hpp,ApiCall.*,ApiBatch.*,ApiChain.*,ApiResponseParse.*,ApiClient.*,AuthService.*,AuthLoads.*}
  • datasrc/data/api/{DatasetLoads.hpp,DatasetLoadHandles.*,ApiDatasetRepository.*,NavRequest.*,NavLoads.hpp,ApiProjectRepository.*,DatasetChartDto.*}src/data/repo/{IAsyncDatasetRepository.hpp,IAsyncProjectRepository.hpp,IDatasetRepository.hpp(本地样例同步,保留),RepoTypes.hpp}
  • controllersrc/controller/{DatasetDetailController.*,WorkbenchNavController.*,IDatasetChartStrategy.hpp}
  • appsrc/app/main.cppsrc/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. 相关文档

  • specdocs/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 偏离)。
  • plandocs/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 done2026-06-11-dataset-detail-chart-v2-qwt.mdQwtPlot 返工,权威)。
  • API 文档:docs/apisbusiness_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——评审若建议为构造保证不会发生的情况加防御可不采纳。