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

26 KiB
Raw Blame History

交接文档:数据集详情图表 + 全 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_dataQwtPlot 落地,用户已验收)。
  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.cppAlphaScale::Bit255 解析 → rgba 的 a=1 被当字节 → alpha≈1/255 近透明12 个 rgba 段全成白缝6 个 hex 段因 hex 分支强制 255 才可见)。修复:Bit255Unit(一行)。散点连续插值 ColorMapService 的归一化位置 val/maxVal 已证精确等于原版 Plotly colorscale 位置,无需改。
  • 散点 hover:新增 ScatterHoverTipcanvas 事件过滤器,与 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/插值位置匹配)。
  • 观察(未改,待定):图例 ColorBarWidgetstops-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散点 cautoColorMapService.setDataRange(dataMin,dataMax) 解耦「色阶形状位置(按断点值)」与「数据值归一化(按数据 min/maxRawDataChartView::setDatad.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页签用数据名ChartDatadsNameopenDataset 加可选第 3 参 dsName(默认空,向后兼容测试);kDsNameRole 存 dsNamemain.cpp 双击传入,DatasetDetailPanel addTabdsName(空回退 dsId+ tooltip。
  • 文件:ColorMapService.{hpp,cpp}RawDataChartView.cppScatterHoverTip.cppDatasetDetailController.{hpp,cpp}DatasetListPanel.{hpp,cpp}DatasetDetailPanel.cppmain.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 天前旧文件)。
    • 崩溃捕获SetUnhandledExceptionFilterSEH含未捕获 C++ 异常 0xE06D7363+ std::set_terminate;崩溃时 MiniDumpWriteDumpcrash_*.dmp(链 Dbghelp+ 记一行 [FATAL] 崩溃 code=… addr=… dump=…SetErrorMode 抑制系统弹窗。已用临时 env 自检实测:空指针崩溃 → 生成 6MB dmp + 日志记录 code=0xc0000005自检块已删
    • dmp 可 VS/WinDbg 加载看完整调用栈。
  • 埋点ApiCall::onFinished 记录每个 API 响应URL/http/code/err成功 INFO/失败 WARNDatasetDetailController 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:异常 e06d7363C++ EHVCRUNTIME140!CxxThrowException ← msvcp140!std::_Xlength_error ← geopro_desktop+0x9ad0 ← +0xa94ee ← +0x24b71 ← +0x235c0。即 std::length_errorSTL 容器/字符串用非法 size resize/reserve/构造)。栈帧都在 geopro_desktop含静态链接的 Qwt该 dump 是旧构建、当前 PDB 已不匹配 → 符号化不出函数名。静态排查 dynamicForm 解析 / DynamicFormView / selectDataset 失败路径 / 散点解析(已 try/catch) / 渲染 / ColorMapService 均未见明显抛点 → 确切行待运行期护栏日志点名

修复(主,根治"不该崩"main.cppGuardedApplication : QApplicationoverride 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.cppAddVectoredExceptionHandler 在 C++ 异常0xE06D7363抛出瞬间栈未展开、PDB 匹配)用 DbgHelpSymInitialize+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 为空或指向不在本批的「源文件节点」。
  • DsRowparentIdNavDto::parseDsRows 解析 sourceShowParentId(回退 parentId)DatasetListPanel::populateDatasetListQListWidget 改建 QTreeWidget(两遍法按 parentId 嵌套,卡片委托 applyDatasetCardDelegate 泛化到 QAbstractItemViewmain.cpp datasetListQTreeWidgetsetExpandsOnDoubleClick(false):双击=开详情、展开靠箭头),点击/双击/反向高亮/加载更多 4 处改 QTreeWidget API。文件页签仍平铺 QListWidget。默认折叠(对齐原版)。
  • 测试:test_nav_dto.cpp::ParseDsRowsParentIdForTree

(2) 分页应按「第一层节点(根)」算(原按扁平 DS

  • 根因:后端 dsObject/data/page扁平 DS 分页脚本验证total=10、pageSize=5 返回 5 条扁平行)——子节点的父常落在下一页 → 按页建树出孤儿根、首层数错乱。
  • IAsyncProjectRepository::loadRowsAsyncint 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<totalpageSize 不足取全)qWarning 告警。
  • 测试:test_workbench_nav_controller.cpp::DataPaginatesByRootNodeNotFlatCount6 根→首页 5 根+子=7 行/total=6续页第 6 根;用 qRegisterMetaType<std::vector<DsRow>> 读 spy 行参)。

(3) 暗色主题图表样式未跟随

  • 原详情图 QwtPlotColorBarWidgetLoadingOverlay 全硬编码白底/浅色 → 暗色主题下刺眼白底/白蒙板。原版 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.cppbg/panel 白/#161A20text/secondaryborder/*)。

新文件src/app/panels/chart/ChartTheme.{hpp,cpp}(已加 src/app/CMakeLists.txt)。 改动文件RepoTypes.hppNavDto.cppIAsyncProjectRepository.hppApiProjectRepository.{hpp,cpp}WorkbenchNavController.{hpp,cpp}DatasetListPanel.{hpp,cpp}main.cppRawDataChartView.cppGridDataChartView.cppColorBarWidget.cppLoadingOverlay.cppsrc/app/CMakeLists.txttests/{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
  • 标准测试 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、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. 相关文档

  • 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——评审若建议为构造保证不会发生的情况加防御可不采纳。