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

226 lines
26 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。**测试 122/122 全绿**。
> ⚠️ **工作区脏**sessions 0.10.5 的代码(散点 hover/日志崩溃捕获/colormap/数据集树/按根分页/暗色主题)**全部未提交**(用户多次选「保持现状」不提交不合并)。`git status` 一大堆 M/??**别假设干净树**;接手前先 `git status` 看清。新增未跟踪文件:`src/app/Logging.*`、`src/app/panels/chart/{ScatterHoverTip,ChartTheme}.*`、`tests/app/test_scatter_hover.cpp`,以及若干 `*.jpeg/*.yml` 临时抓图/抓取产物(非源码,可忽略/清理)。
---
## 0. 一句话现状
geoproQt6/C++ 离线桌面客户端1:1 复刻赛盈地空 web已完成两大块
1. **数据集详情图表**(仅 ERT 反演 `dd_inversion_data`QwtPlot 落地,用户已验收)。
2. **全 App 网络层 100% 异步化**(详情/导航/登录/项目列表全异步,同步 `QEventLoop` 阻塞路径已彻底删除,无技术债)。
均**未合并入 main**,分支挂起等收尾。
### 0.1 2026-06-12 渲染保真修复(本次会话)
用户报客户端散点/网格颜色与原版差异大(大量点透明发白、图例只有 6 色 + 白缝)、散点缺 hover。经 Playwright 抓原版真实 API + 读源码定位为**通用根因**
- **colorBar alpha 标度 bug**(核心):`lvl/colorGradation/getDetail` 返回的 colorBar 是**混合格式**——hex `#00008B` 与 CSS `rgba(0, 0, 170, 1)`**alpha 是 01 浮点**),共 18 段。`DatasetChartDto.cpp` 用 `AlphaScale::Bit255` 解析 → rgba 的 `a=1` 被当字节 → alpha≈1/255 近透明12 个 rgba 段全成白缝6 个 hex 段因 hex 分支强制 255 才可见)。**修复:`Bit255`→`Unit`**(一行)。散点连续插值 `ColorMapService` 的归一化位置 `val/maxVal` 已证**精确等于原版 Plotly colorscale 位置**,无需改。
- **散点 hover**:新增 `ScatterHoverTip`canvas 事件过滤器,与 LivePanner 共存),最近点命中显示 `X/Y/值`(各 3 位小数,对齐原版 Plotly hovertemplate `<b>X:</b> %{x:.3f}…`)。
- 文件:改 `src/data/dto/DatasetChartDto.cpp`;新增 `src/app/panels/chart/ScatterHoverTip.{hpp,cpp}` + 接线 `RawDataChartView.{hpp,cpp}`;测试 `tests/data/test_dataset_chart_dto.cpp`(改用真实混合格式 + 断言 alpha=255 回归)、新增 `tests/app/test_scatter_hover.cpp`。**测试 116→118 全绿**cpp-reviewer APPROVE。
- ⚠️ **像素级视觉 1:1 待用户在运行的 app 内登录核对**(原生 Qt 窗口无法用 Playwright 驱动;以下各层已机器验证:抓包/源码/RED-GREEN/插值位置匹配)。
- 观察(未改,待定):图例 `ColorBarWidget``stops-1=17` 段,丢弃最后一段最深色;原版疑为 18 段。非本次报障,留待用户决定是否补齐。
### 0.2 2026-06-12 第二轮修复(散点 cauto 归一化 + hover mouseTracking + 页签名)
第一轮 alpha 修复后颜色不再透明,但散点仍与原版不一致(挤在暖色中段、无蓝无紫)。复查 Plotly `_fullData`:散点 **`cmin/cmax` 未设 → `cauto` 自动取 vlist 实际 min/max本例 45.93197.79**,把整段色阶铺满数据范围;而客户端 `ColorMapService` 错用 colorBar 全程 01323 归一化数据 → 压进色阶 0.030.15 段。
- **修复 A散点 cauto**`ColorMapService.setDataRange(dataMin,dataMax)` 解耦「色阶形状位置(按断点值)」与「数据值归一化(按数据 min/max`RawDataChartView::setData` 按 `d.scatter.v` 有限值 min/max 调用。**数值验证 1:1**:手算修复后客户端对样本值的 RGB 与原版 Plotly 实测逐字节相同(如中位 92.01→[168,0,35]、62.34→[255,119,0])。网格仍用绝对阈值(`colorAtDiscrete`),不变。
- **修复 Bhover 仍无效)**:根因 `QwtPlotCanvas` 默认不开 mouseTracking → 无按键时收不到 MouseMove。`ScatterHoverTip` 构造里加 `canvas->setMouseTracking(true)`
- **修复 C页签用数据名**`ChartData` 加 `dsName``openDataset` 加可选第 3 参 `dsName`(默认空,向后兼容测试);`kDsNameRole` 存 dsName`main.cpp` 双击传入,`DatasetDetailPanel` `addTab``dsName`(空回退 dsId+ tooltip。
- 文件:`ColorMapService.{hpp,cpp}`、`RawDataChartView.cpp`、`ScatterHoverTip.cpp`、`DatasetDetailController.{hpp,cpp}`、`DatasetListPanel.{hpp,cpp}`、`DatasetDetailPanel.cpp`、`main.cpp`;测试 `test_colormap_service.cpp`(+DataRangeDecouples)。**119/119 全绿**。
- ⚠️ hover/页签名/视觉仍待用户运行核对GUI 无法自动驱动)。
### 0.3 2026-06-12 桌面端日志 + 崩溃捕获(新基础设施)
用户反馈:双击 ds 后状态栏报「内部系统错误」然后客户端崩溃;后端错误可接受,但客户端不该崩。复测发现 scatter/color 接口当时其实 200/干净数据 → 无日志根本无从定位。遂加生产级日志 + 崩溃捕获(已实测打通)。
- **`src/app/Logging.{hpp,cpp}`**`initLogging()`main.cpp 在 setApplicationName 后调用)。
- `qInstallMessageHandler` 接管全 App `qDebug/qInfo/qWarning/qCritical/qFatal` → 写带时间戳/级别的滚动日志:`%LOCALAPPDATA%/Geomative/Geopro3/logs/geopro_YYYYMMDD.log`按天UTF-8+BOM启动清理 14 天前旧文件)。
- **崩溃捕获**`SetUnhandledExceptionFilter`SEH含未捕获 C++ 异常 0xE06D7363+ `std::set_terminate`;崩溃时 `MiniDumpWriteDump``crash_*.dmp`(链 `Dbghelp`+ 记一行 `[FATAL] 崩溃 code=… addr=… dump=…`。`SetErrorMode` 抑制系统弹窗。**已用临时 env 自检实测**:空指针崩溃 → 生成 6MB dmp + 日志记录 code=0xc0000005自检块已删
- dmp 可 VS/WinDbg 加载看完整调用栈。
- **埋点**`ApiCall::onFinished` 记录每个 API 响应URL/http/code/err成功 INFO/失败 WARN`DatasetDetailController` openDataset + 各 loadFailedApp 启动版本/路径。net 层 `qWarning` 自动收录。
- **顺带堵崩溃根因**(评审 H-2 + 防脏数据):`ColorMapService::colorAtContinuous` 对 NaN/Inf 的 t 回退首断点色(原会 `upper_bound` 返回 end() 后解引用越界崩溃);`RawDataChartView` vlist min/max 用 `isfinite` 跳过 NaN/±Inf。+ 单测 `ColorAtContinuousNaNSafe`
- **测试 119→120 全绿**。
### 0.4 2026-06-12 崩溃定位 + 顶层异常护栏
用户提供 dump + log。日志序列`openDataset(ERT2-WS_result.dat)` → **`dynamicForm` 后端返回 `code=500 sys.internalServerError`**(即"内部系统错误")→ scatter 200 → color 200 → `Qt has caught an exception thrown from an event handler` → 崩溃。
**dump 分析winget 装 Microsoft.WinDbg`!analyze -v`**:异常 `e06d7363`C++ EH`VCRUNTIME140!CxxThrowException ← msvcp140!std::_Xlength_error ← geopro_desktop+0x9ad0 ← +0xa94ee ← +0x24b71 ← +0x235c0`。即 **`std::length_error`**STL 容器/字符串用非法 size resize/reserve/构造)。栈帧都在 geopro_desktop含静态链接的 Qwt但**该 dump 是旧构建、当前 PDB 已不匹配 → 符号化不出函数名**。静态排查 dynamicForm 解析 / DynamicFormView / selectDataset 失败路径 / 散点解析(已 try/catch) / 渲染 / ColorMapService 均未见明显抛点 → 确切行**待运行期护栏日志点名**。
**修复(主,根治"不该崩"**`main.cpp` 加 `GuardedApplication : QApplication`override `notify()` try/catch任何 slot/事件处理器抛出的异常被拦截 + `qCritical` 记录 `[guard] 拦截... what | type | receiver=<对象类名> | event=<事件类型>`,然后吞掉(不终止)。后端故障等异常**不再使整个客户端退出**。
**附带**:修 `appendCrashLine` 文件共享 bug崩溃行原写不进日志——g_logFile 独占,第二句柄 open 失败;改为复用已打开句柄);`colorAtContinuous` NaN/Inf 守卫。
**护栏实测**:用户复现,护栏拦到 → 日志 `[guard] 拦截未捕获异常: vector too long | type=std::length_error | receiver=QNetworkReplyHttpImpl | event=43(MetaCall)`。即异常在**网络响应 finished 同步链**里(最后一个 chart 请求 color 返回 → `chartReady→openOrUpdate→渲染`)抛出 `std::length_error`"vector too long" = std::vector 用了非法尺寸,典型负数转 size_t。进程**未崩**(护栏吞掉),但图表没渲染出来。
**诊断基础设施(关键补强)**
1. **Release 构建之前不生成 PDB** → dump/崩溃栈对自家代码全部符号化失败(只有系统 DLL 导出表能解析)。已在根 `CMakeLists.txt` MSVC 块加 `/Zi`(编译) + `/DEBUG /OPT:REF /OPT:ICF`(链接)Release 保持优化的同时产出匹配 PDB。**生产桌面端排障必需。**
2. **VEH 抛点堆栈符号化**`Logging.cpp``AddVectoredExceptionHandler` 在 C++ 异常0xE06D7363**抛出瞬间**栈未展开、PDB 匹配)用 DbgHelp`SymInitialize`+`SymLoadModuleExW`+`SymFromAddrW`+`SymGetLineFromAddrW64`**宽字符**——UNICODE 下必须)打印 `模块+RVA 函数名+偏移 (文件:行)`。自测验证:`reserve(-1)` → 正确打印 `geopro::app::initLogging (Logging.cpp:245)`。即使异常被护栏吞掉也留下抛点栈。
**下一步定位 length_error 确切行**:用当前构建复现一次 → 日志 `[THROW]` 段直接给出 `geopro::app::<类>::<方法> (文件:行)`。**测试 120/120 全绿。**
### 0.5 2026-06-12 数据集列表树化 + 按根分页 + 暗色主题保真(本次会话)
用户三组报障,均已修复、构建链接通过、应用真实流程跑通无崩溃、**测试 120→122 全绿**
**(1) 数据集列表应是树(原为平铺)**
- **实地确认(铁律 Playwright**:原版「数据管理」选 TM 后的数据列表是 **el-table tree-data**(有展开箭头)。脚本直连 API 验证 TM E3项目 1458977804960256 垃圾掩埋場10 个 DS → **4 个根**(默认折叠)= 3×源「ERT原始数据」+ 1×「ERT电极坐标」派生「反演/接地电阻」按 `parentId`(==`sourceShowParentId`)挂源「原始数据」下。根 = parentId 为空或指向不在本批的「源文件节点」。
- **改**`DsRow` 加 `parentId``NavDto::parseDsRows` 解析 `sourceShowParentId`(回退 `parentId`)`DatasetListPanel::populateDatasetList` 由 `QListWidget` 改建 **`QTreeWidget`**(两遍法按 parentId 嵌套,卡片委托 `applyDatasetCardDelegate` 泛化到 `QAbstractItemView``main.cpp` `datasetList``QTreeWidget``setExpandsOnDoubleClick(false)`:双击=开详情、展开靠箭头),点击/双击/反向高亮/加载更多 4 处改 `QTreeWidget` API。文件页签仍平铺 `QListWidget`。默认折叠(对齐原版)。
- 测试:`test_nav_dto.cpp::ParseDsRowsParentIdForTree`。
**(2) 分页应按「第一层节点(根)」算(原按扁平 DS**
- **根因**:后端 `dsObject/data/page` 按**扁平 DS** 分页脚本验证total=10、pageSize=5 返回 5 条扁平行)——子节点的父常落在下一页 → 按页建树出孤儿根、首层数错乱。
- **改**`IAsyncProjectRepository::loadRowsAsync` 加 `int pageSize=5` 参数(接口/`ApiProjectRepository`/测试 stub 同步);`WorkbenchNavController::selectObject` 数据页改用大 pageSize(`kFetchAllPageSize=1000`)**一次取全**整棵,缓存 `allDataRows_`;新私有 `emitNextDataRootPage(bool append)` **客户端按根切页**(每页 `kDataRootPageSize=5` 个根 + 各自整棵子树DFS 收集后按原序输出,`total`=根总数);`loadMoreData` 改同步切下一页(无请求);`dataRootsShown_` 游标,`resetSelectionState` 清空。删因此空置的 `moreDataReq_`。`main.cpp` `addTreeLoadMore` 计数改按顶层根。若 `listCount<total`pageSize 不足取全)`qWarning` 告警。
- 测试:`test_workbench_nav_controller.cpp::DataPaginatesByRootNodeNotFlatCount`6 根→首页 5 根+子=7 行/total=6续页第 6 根;用 `qRegisterMetaType<std::vector<DsRow>>` 读 spy 行参)。
**(3) 暗色主题图表样式未跟随**
- 原详情图 `QwtPlot`、`ColorBarWidget`、`LoadingOverlay` 全硬编码白底/浅色 → 暗色主题下刺眼白底/白蒙板。**原版 web 无暗色,故暗色为客户端自定****浅色分支保持原硬编码值=与原版 1:1 不动,仅暗色改 token**。
- 新增 **`src/app/panels/chart/ChartTheme.{hpp,cpp}`** `applyChartPlotTheme(QwtPlot*)`:按 `isDarkTheme()` 设画布底色(`bg/panel`)/轴字(`text/secondary`)/网格(`border/default`)/零线(`border/strong`),遍历 itemList 重着色 grid/marker。`Raw/GridDataChartView` 删硬编码白块、ctor 末尾调用 + 连 `ThemeManager::changed` 热切换。
- `ColorBarWidget::paintEvent` 底色/边框/刻度字按 `isDarkTheme()`(暗色 `bg/panel`/`border/strong`/`text/secondary`;色带格=数据色不变)+ ctor 连 changed→update。
- `LoadingOverlay` 遮罩纱色由 `rgba(255,255,255,160)` 改按主题(暗色 `bg/app` 深纱)+ label 文字 `text/primary`,连 changed 热切换。
- token 表见 `src/app/Theme.cpp``bg/panel` 白/`#161A20`、`text/secondary`、`border/*`)。
**新文件**`src/app/panels/chart/ChartTheme.{hpp,cpp}`(已加 `src/app/CMakeLists.txt`)。
**改动文件**`RepoTypes.hpp`、`NavDto.cpp`、`IAsyncProjectRepository.hpp`、`ApiProjectRepository.{hpp,cpp}`、`WorkbenchNavController.{hpp,cpp}`、`DatasetListPanel.{hpp,cpp}`、`main.cpp`、`RawDataChartView.cpp`、`GridDataChartView.cpp`、`ColorBarWidget.cpp`、`LoadingOverlay.cpp`、`src/app/CMakeLists.txt`、`tests/{data/test_nav_dto,controller/test_workbench_nav_controller}.cpp`。
**记忆新增**`dataset-list-is-tree`(树结构 + 扁平分页坑 + 按根分页解法 + 暗色图表方案)。
- ⚠️ **待用户运行核对GUI 无法自动驱动)**:① 暗色下网格详情的「加载中…」蒙板是深纱、色阶条深底浅字;② 数据列表按 5 根分页(根多的 TM 才出「加载更多」)+ 树嵌套正确。机器侧已验证:脚本抓原版结构 + 构建 + 122 测试 + 真实登录流程日志跑通(项目 1458977804960256→E3→data/page→getDetail→dynamicForm无崩溃
---
## 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、**122/122 绿**,但**工作区脏**sessions 0.10.5 代码全未提交,见顶部 ⚠️)。用户多次选「保持现状」未提交未合并。**先决**:本次会话两组改动(数据集树/按根分页、暗色主题)**待用户在运行的 app 内目视核对**(见 0.5 末尾清单)——核对通过再谈提交。下一步可问用户:①目视核对本次改动 ②提交这批未提交工作(建议按主题分多个 commit详情图保真 / 日志崩溃捕获 / 数据集树+分页 / 暗色主题)③合并回 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>