docs(plan): 异步化铺开(导航+登录)计划 + 其余 dd 类型详情图扩展计划(Phase0 样本探查+策略分派打通)
This commit is contained in:
parent
6d0ec909ec
commit
751b486254
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,202 @@
|
|||
# 数据集详情图:扩展到其余 dd 类型 实现计划
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: 用 `superpowers:subagent-driven-development` 执行(每个 bite-sized 任务派一个 subagent,TDD,频繁提交)。步骤用 `- [ ]`。
|
||||
> **铁律(项目记忆,务必遵守):** 任何对原版的不确定,**必须用 Playwright 实地学习原版**,禁止联想猜测;严格 **1:1 复刻**,不加原版没有的特性。**没有活样本的 dd 类型一律 BLOCKED,禁止凭想象写渲染代码。**
|
||||
|
||||
**Goal:** 把「数据集详情图」从只支持 ERT 反演(`dd_inversion_data`)扩展到其余 dd 类型。先打通「控制器按 ddCode 走策略注册表」的分派骨架(未注册类型优雅降级「暂不支持」),再按"样本可得性"逐类落地:有活样本的(ERT 测量类、TEM/timeSensor)做完整复刻,无活样本的(dd_grid / 轨迹 / 测井 / GPR)只列调研占位 + 取样前置条件,BLOCKED。
|
||||
|
||||
**Architecture:** 沿用现有分层,不重造:
|
||||
- 编排层 `DatasetDetailController`(现状对非 `dd_inversion_data` 直接拒绝)→ 改为持 `ChartStrategyRegistry`,按 ddCode 选策略;策略决定「拉哪些接口 + 用哪个 View 渲染」。
|
||||
- 异步数据层 `IAsyncDatasetRepository` + `ChartLoad`/`GridLoad` 句柄(`ApiBatch` 多请求聚合 + 注入解析函数)。每类新 dd 视形态新增句柄类型(如折线 `LineLoad`、图像 `ImageLoad`)或复用现有句柄。
|
||||
- DTO 解析层 `src/data/dto/`(纯函数,单测友好,用抓到的真实响应做夹具)。
|
||||
- 渲染层 `src/app/panels/chart/`:复用 QwtPlot(轴/交互/图例)+ VTK 算法(等值线几何)。按形态归类复用或新建 View:等值面类复用 `ContourPlotItem`/`GridDataChartView`;散点类复用 `ScatterPlotItem`/`RawDataChartView`;折线类(测井)新建 `LineChartView`;图像类(GPR)新建 `ImageChartView`。
|
||||
- 页面壳 `DatasetDetailPanel`(多 Tab) / `DatasetDetailPage`(单 ds 内部页签)。
|
||||
|
||||
**Tech Stack:** C++17、Qt6 Widgets、Qwt 6.2(`cmake/qwt.cmake`,目标名 `qwt`,头在 `external/qwt-src/src`)、VTK 9.6(仅算法层)、GoogleTest/CTest、vcpkg(仅非 Qt 依赖)。
|
||||
|
||||
**依据文档:**
|
||||
- `docs/superpowers/specs/2026-06-11-dataset-detail-view-design.md`(§2.4 后续 dd 类型、§5.3 策略框架、§3 原 web 分析方法)。
|
||||
- `docs/superpowers/HANDOFF-dataset-detail-chart.md`(技术栈/构建/已完成范围)。
|
||||
- `docs/apis/business_OpenAPI.json`(各 dd 类型取数接口,下文已核对路径/参数)。
|
||||
|
||||
**构建/测试命令(本机工具链,固定):**
|
||||
- 构建:`powershell.exe -ExecutionPolicy Bypass -File scripts/dev-build.ps1`
|
||||
- ⚠️ 若 `LNK1104 无法打开 geopro_desktop.exe`:先 `Get-Process geopro_desktop | Stop-Process -Force` 再构建。
|
||||
- 测试:`powershell.exe -ExecutionPolicy Bypass -File scripts/dev-test.ps1`(先 dev-build 再 dev-test)。**基线 89/89 绿。**
|
||||
- 单测过滤:`build/release/tests/geopro_tests.exe --gtest_filter=<Suite>.*`
|
||||
- 运行(视觉验收):`build/release/src/app/geopro_desktop.exe`(需登录)。
|
||||
|
||||
---
|
||||
|
||||
## 0. 现状核实(已读真实代码,勿臆测)
|
||||
|
||||
**关键结论:策略框架已存在但未接入控制器。** 详情:
|
||||
|
||||
- `src/app/panels/chart/IDatasetChartStrategy.hpp`:`IDatasetChartStrategy`(只有纯虚 `std::string ddCode()`)+ `ChartStrategyRegistry`(`add/find/supports`,`std::map<string, unique_ptr>`)。**已写好,但全仓只有单测引用它,控制器/main.cpp 从未构造/使用注册表。**
|
||||
- `src/app/panels/chart/ErtInversionStrategy.hpp`:仅一个 stub —— `ddCode()` 返回 `"dd_inversion_data"`,**无任何 load/render 逻辑**。
|
||||
- `src/controller/DatasetDetailController.cpp`:
|
||||
- `openDataset(dsId, ddCode)`:`if (ddCode != "dd_inversion_data") { emit loadFailed("暂不支持该数据类型的预览"); return; }` —— **硬编码**,未走注册表。
|
||||
- `loadGridData(dsId, ddCode)`:同样 `if (ddCode != "dd_inversion_data") return;` 硬编码。
|
||||
- `tests/app/test_chart_strategy_registry.cpp`:仅测 `add/find/supports/降级`,**未与控制器联动**。
|
||||
- `src/data/repo/IAsyncDatasetRepository.hpp`:`loadChartAsync`(scatter+色阶type1)/ `loadGridAsync`(rows+色阶type2+异常),均**写死 ERT 反演接口**(见 `ApiDatasetRepository.cpp`)。
|
||||
- ddCode 来源:`src/data/dto/NavDto.cpp:124` 从数据集列表项 `o["ddCode"]` 解析;`main.cpp:501` 双击时从 `kDsDdCodeRole` 取出传给 `openDataset`。**ddCode 是 API 给的字符串,源码里除 `dd_inversion_data` 外无其它 dd code 常量**(grep 到的 `dd_custom_command` 等是 CMake `add_custom_command` 等构建符号,非数据类型)。
|
||||
|
||||
**结论:本 plan 的 Phase 1 必须先「打通控制器→注册表分派」,这是所有后续 dd 类型的前置。** 现有 `IDatasetChartStrategy` 接口过窄(只有 ddCode),需扩展为能驱动「加载 + 渲染」。
|
||||
|
||||
---
|
||||
|
||||
## 1. 各 dd 类型:样本可得性 + 渲染归类 + 可推进/BLOCKED 矩阵
|
||||
|
||||
> 现实约束(spec §2.4):当前可访问租户**仅 ERT / TEM / GPR 三类**;**GPR 对象无数据、无测井数据样本**。多数 dd 类型无活样本可参照。
|
||||
> ddCode 列为推断(源码无常量),**Phase 0 须用 Playwright 抓数据集列表项的真实 `ddCode` 字段核对后回填本表**,禁止写死未经核对的 ddCode。
|
||||
|
||||
| 数据类型(菜单/spec) | 推断 ddCode(待 Phase 0 核对) | 取数接口(已核对 OpenAPI 路径/参数) | 渲染归类 / 复用 | 样本可得性 | 状态 |
|
||||
|---|---|---|---|---|---|
|
||||
| ERT 反演(已完成基线) | `dd_inversion_data` | `getErtRawDataScatterGraph/{id}`、`inversion/rows/{id}`、色阶 type1/2、`queryException/{id}` | 散点 + 等值面(已实现) | 有 | ✅ 已完成 |
|
||||
| ERT 测量原始 | 待核对 | `GET dd/ert/measurement/scatter/graph?dsObjectId&vFieldCode`、`GET dd/ert/measurement/rows?dsObjectId` | 散点类 → 复用 `ScatterPlotItem`/`RawDataChartView`;rows 形态待 Phase 0 定 | ERT 租户在,**须 Phase 0 找到有数据对象** | 候选可推进(待 Phase 0 确认有样本) |
|
||||
| ERT 测量/高密度(gr) | 待核对 | `GET dd/ert/measurement/gr/rows?dsObjectId` | 待 Phase 0 看形态(散点/伪剖面) | 同上 | 候选可推进(待 Phase 0 确认) |
|
||||
| TEM 时序(设备时序) | 待核对 | `POST dd/ert/timeSensor/rows`(body `DDTimeSensorDataQueryReqVO`)、`GET dd/ert/timeSensor/page` | 时序折线类 → 新建 `LineChartView`(x=时间,y=数值) | **TEM 租户在**,须 Phase 0 找到有数据对象 + 抓响应 | 候选可推进(待 Phase 0 确认有样本) |
|
||||
| dd_grid(网格) | 待核对 | `GET dd/ert/grid/rows?dsObjectId&pageNo&pageSize` | 等值面类 → 复用 `ContourPlotItem`/`GridDataChartView` | 当前租户**无样本** | 🚫 BLOCKED:待样本 |
|
||||
| 轨迹 | 待核对 | `GET dd/ert/trajectory/rows?dsObjectId`、`GET dd/ert/trajectory/line?dsObjectId&frontCrsCode` | 折线/路径类 → 待样本定(可能复用散点连线或新 `LineChartView`) | 当前租户**无样本** | 🚫 BLOCKED:待样本 |
|
||||
| 测井(well logging) | 待核对(菜单「测井参数表」) | **OpenAPI 未见明确专用 rows 接口** —— Phase 0 须从原版抓真实请求确认接口 | 折线类 → 新建 `LineChartView`(y=深度向下 / x=数值;或 x=时间 y=数值曲线) | **无测井数据样本** | 🚫 BLOCKED:待样本 + 待接口确认 |
|
||||
| GPR(雷达剖面图像) | 待核对 | `GET dd/gpr/channel/image/{dsObjectId}`、`GET dd/gpr/channel/trace/spectrogram`、`GET dd/gpr/channel/querySegmentation` | 图像类 → 新建 `ImageChartView`(位图剖面 + 坐标轴) | **GPR 对象无数据** | 🚫 BLOCKED:待样本 |
|
||||
|
||||
**矩阵小结:** 唯一确定有数据的是 `dd_inversion_data`(已完成)。其余全部需 Phase 0 实地探查;ERT 测量类与 TEM 是**最可能**找到样本的(租户在),但「是否有具体对象带数据」必须 Phase 0 验证后才解锁实现任务。
|
||||
|
||||
---
|
||||
|
||||
## 文件结构(新建/修改总览)
|
||||
|
||||
| 文件 | 动作 | 职责 |
|
||||
|---|---|---|
|
||||
| `src/app/panels/chart/IDatasetChartStrategy.hpp` | 改 | 扩展接口:除 `ddCode()` 外,加描述「加载/渲染契约」的虚方法(详见 Task 1.1) |
|
||||
| `src/app/panels/chart/ErtInversionStrategy.{hpp,cpp}` | 改 | 把 stub 实化为「ERT 反演策略」:声明它需要 chart+grid 加载、用散点/等值面视图 |
|
||||
| `src/controller/DatasetDetailController.{hpp,cpp}` | 改 | 持 `ChartStrategyRegistry&`;`openDataset`/`loadGridData` 改为走注册表分派,未注册→`loadFailed("暂不支持…")` |
|
||||
| `src/app/main.cpp` | 改 | 构造 `ChartStrategyRegistry`,注册 `ErtInversionStrategy`,注入控制器 |
|
||||
| `tests/controller/test_dataset_detail_controller.cpp` | 改 | 加「未注册 ddCode 优雅降级 / 已注册走加载」用例 |
|
||||
| `tests/app/test_chart_strategy_registry.cpp` | 改 | 已有降级用例;按接口扩展补充 |
|
||||
| `docs/superpowers/sample-probe-other-dd-types.md` | 建(Phase 0 产出) | 各类 dd 的「样本可得性矩阵 + 渲染规格 + 真实 API 响应夹具索引」 |
|
||||
| `tests/fixtures/dd/*.json` | 建(Phase 0 产出) | 抓到的真实响应,做 DTO 单测夹具(仅有样本的类型) |
|
||||
| `src/data/dto/DatasetChartDto.{hpp,cpp}` | 改/拆 | 新增各类 dd 的 parse 函数(如 `parseMeasurementScatter`、`parseTimeSensorSeries`)。若文件超 ~400 行则按类型拆 `MeasurementDto.*` / `TimeSensorDto.*` |
|
||||
| `src/data/api/ApiDatasetRepository.{hpp,cpp}` | 改 | 新增对应 `load*Async`(仅有样本类型)|
|
||||
| `src/data/api/DatasetLoads.hpp` | 改 | 新增 `*Parts` 结构(仅有样本类型)|
|
||||
| `src/data/api/DatasetLoadHandles.hpp` + `.cpp` | 改 | 视形态新增句柄类型(如 `LineLoad`/`ImageLoad`),或复用现有 |
|
||||
| `src/app/panels/chart/LineChartView.{hpp,cpp}` | 建(仅当 TEM/测井解锁) | 折线视图(QwtPlot + QwtPlotCurve) |
|
||||
| `src/app/panels/chart/ImageChartView.{hpp,cpp}` | 建(仅当 GPR 解锁) | 图像剖面视图 |
|
||||
| `src/app/CMakeLists.txt` / `tests/CMakeLists.txt` | 改 | 注册新文件/测试 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 0:样本探查(必做,先于一切实现)
|
||||
|
||||
> 目的:把矩阵里的「待核对/BLOCKED」逐一坐实。**不写任何渲染代码。**产出是「样本规格 + 真实响应夹具」,作为后续 TDD 的 RED 依据。
|
||||
|
||||
- [ ] **Task 0.1(核对 ddCode 真值)** 用 Playwright 登录原版 `http://tenant.geomative.cn`,进入 `#/projectSpace/datasetMange/datasetInfo`,遍历可见数据集,抓每个数据集列表项的 `ddCode` 字段(网络响应或前端状态)。把真实 ddCode 回填到本 plan §1 矩阵。→ verify:矩阵「推断 ddCode」列全部替换为实测值,无残留「待核对」。
|
||||
- [ ] **Task 0.2(逐类样本探查)** 对 ERT 测量原始 / ERT 测量gr / TEM / dd_grid / 轨迹 / 测井 / GPR 七类,逐一在原版找「有数据的对象」:
|
||||
- 打开其详情页,截图渲染形态(散点?等值面?折线?图像?);
|
||||
- 在 Network 抓其取数请求的**完整 URL(含 query/path 参数)+ 完整响应 JSON**;
|
||||
- 记录坐标轴语义(x/y 单位、方向、是否等比)、色阶/图例有无、是否有异常叠加。
|
||||
- → verify:每类得出「有样本 / 无样本」结论,有样本的把响应存到 `tests/fixtures/dd/<type>.json`,写进 `docs/superpowers/sample-probe-other-dd-types.md`。
|
||||
- [ ] **Task 0.3(产出规格文档)** 写 `docs/superpowers/sample-probe-other-dd-types.md`:每类一节,含「样本可得性 / 真实接口 / 响应结构 / 渲染规格 / 渲染归类 / 是否解锁」。无样本类明确标 **BLOCKED:待样本**,列「解锁前置条件」(如「需租户导入 GPR 数据 / 需测井样本数据集」)。→ verify:文档七类齐全,与 §1 矩阵一致。
|
||||
- [ ] **Task 0.4(提交)** `docs: dd 类型样本探查矩阵 + 真实响应夹具`。提交规格文档与 fixtures。
|
||||
|
||||
**Phase 0 决策门:** 完成后回到本 plan,把 §1 矩阵中实测有样本的类型从「候选」升为 Phase 2+ 的实现任务;无样本的保持 BLOCKED,不进入实现 Phase。
|
||||
|
||||
---
|
||||
|
||||
## Phase 1:打通策略分派骨架(前置,无须样本即可做)
|
||||
|
||||
> 把控制器从硬编码 `dd_inversion_data` 改为走 `ChartStrategyRegistry`。**行为对 `dd_inversion_data` 必须零回归(仍正常出图),对未注册类型仍降级「暂不支持」。** 这是所有后续 dd 类型的地基。
|
||||
|
||||
- [ ] **Task 1.1(扩展策略接口)** 先读 `IDatasetChartStrategy.hpp`、`DatasetDetailController.{hpp,cpp}` 真实签名。把 `IDatasetChartStrategy` 从「只有 `ddCode()`」扩展为能表达「该类型支持哪些加载阶段」的最小契约,**避免过度设计(YAGNI)**。建议最小形:
|
||||
- 保留 `std::string ddCode() const`。
|
||||
- 加 `bool hasGridPhase() const`(ERT 反演=true;纯散点/折线/图像类=false)—— 让控制器据此决定是否允许 `loadGridData`,替代当前对 `loadGridData` 的硬编码 ddCode 判断。
|
||||
- (渲染分派暂不进接口:现阶段 `chartReady`/`gridReady` 信号 + 现有 `DatasetDetailPage` 已驱动渲染;待新 View 真要接入时再在对应 Phase 扩展,不在 Phase 1 预先抽象。)
|
||||
- 先改 `tests/app/test_chart_strategy_registry.cpp`:加「策略报告 hasGridPhase」的断言(RED)→ 改接口 + `ErtInversionStrategy`(GREEN)。
|
||||
- → verify:`dev-test` `ChartStrategyRegistry.*` 绿。
|
||||
- [ ] **Task 1.2(控制器走注册表 — openDataset)** 改 `DatasetDetailController`:构造函数加 `app::ChartStrategyRegistry& registry`(与现有 `IAsyncDatasetRepository&` 并列)。`openDataset`:把 `if (ddCode != "dd_inversion_data")` 改为 `if (!registry.supports(ddCode)) { emit loadFailed(dsId, "暂不支持该数据类型的预览"); return; }`,其余加载逻辑暂不变(仍走 `loadChartAsync`)。
|
||||
- 先改 `tests/controller/test_dataset_detail_controller.cpp`:用「空注册表 → openDataset 任意 ddCode → 收到 loadFailed」+「注册了 dd_inversion_data → 走加载(mock repo 的 loadChartAsync 被调用)」两个用例(RED)。读现有该测试看 mock repo/句柄如何桩(`tests/data/test_dataset_load_handles.cpp` 有句柄桩可参考)。
|
||||
- → verify:`DatasetDetailController.*` 测试绿。
|
||||
- [ ] **Task 1.3(控制器走注册表 — loadGridData)** `loadGridData`:把 `if (ddCode != "dd_inversion_data") return;` 改为「查策略,`!strategy || !strategy->hasGridPhase()` → return」。补单测:注册一个 `hasGridPhase()==false` 的 fake 策略 → `loadGridData` 不触发 `loadGridAsync`。→ verify:测试绿。
|
||||
- [ ] **Task 1.4(main.cpp 接线)** 在 `main.cpp` 构造 `geopro::app::ChartStrategyRegistry registry;`,`registry.add(std::make_unique<ErtInversionStrategy>());`,把 `registry` 注入 `DatasetDetailController detailCtrl(datasetRepo, registry);`。注意生命周期:registry 须比 detailCtrl 活得久(同作用域、registry 在前声明)。
|
||||
- → verify:`dev-build` 通过;启动 app,双击 ERT 反演 ds **零回归**(原数据散点 + 网格等值面 + 异常均正常出图);双击其它类型仍显示「暂不支持」。
|
||||
- [ ] **Task 1.5(提交)** `refactor(detail): 控制器按 ddCode 走 ChartStrategyRegistry 分派, 未注册优雅降级 (替代硬编码 dd_inversion_data)`。
|
||||
|
||||
---
|
||||
|
||||
## Phase 2:ERT 测量类(散点形态,仅当 Task 0.2 确认有样本才进行)
|
||||
|
||||
> 🔓 解锁条件:Phase 0 确认 ERT 测量(`measurement/scatter/graph` 或 `measurement/rows`)有活样本且抓到真实响应。**未解锁则本 Phase 全部 BLOCKED,跳过。**
|
||||
> 渲染归类:散点类 → **复用** `ScatterPlotItem`/`RawDataChartView`,不新建 View(DRY)。
|
||||
> 接口(已核对):`GET /business/dd/ert/measurement/scatter/graph?dsObjectId=&vFieldCode=`、`GET /business/dd/ert/measurement/rows?dsObjectId=`。注意:**dsObjectId 是 query 参数(≠ 反演的 path 参数)**,且 scatter 需 `vFieldCode`(Phase 0 抓其真实取值)。
|
||||
|
||||
- [ ] **Task 2.1(DTO 解析 + 单测)** 用 `tests/fixtures/dd/ert-measurement-scatter.json` 真实响应做夹具,先写 `tests/data/test_dataset_chart_dto.cpp` 新用例断言字段映射(RED)→ 在 `DatasetChartDto.cpp`(或新拆 `MeasurementDto.cpp`,若主文件超 ~400 行)实现 `parseMeasurementScatter(QJsonObject)`(GREEN)。映射须严格按真实响应字段,**不臆造字段名**。→ verify:DTO 测试绿。
|
||||
- [ ] **Task 2.2(色阶处置)** Phase 0 确认测量散点是否有独立色阶接口/type(反演散点用 `colorGradation/getDetail` type1)。若有,按真实 type 拉;若无色阶(纯散点),ColorBar 隐藏。补单测覆盖色阶解析或缺省。→ verify:测试绿。
|
||||
- [ ] **Task 2.3(异步句柄 + 仓储)** 复用 `ChartLoad`/`ChartParts`(结构相同则直接复用;字段不同则在 `DatasetLoads.hpp` 加 `MeasurementParts` + 句柄)。在 `ApiDatasetRepository` 加 `loadMeasurementChartAsync(dsId)`(`ApiBatch` 组 scatter[+色阶] 请求 + 注入解析)。注意 query 参数编码(参考现有 `enc()`)。补 `tests/data/test_dataset_load_handles.cpp` 用例。→ verify:测试绿。
|
||||
- [ ] **Task 2.4(策略 + 控制器分派)** 新建 `MeasurementStrategy`(`ddCode()` 用 Task 0.1 实测值,`hasGridPhase()` 按 rows 是否等值面而定)。`DatasetDetailController::openDataset` 据策略选择调 `loadMeasurementChartAsync`(若加载形态与反演不同,控制器按 ddCode/策略分支;保持函数 <50 行,必要时抽私有 helper)。`main.cpp` 注册该策略。补控制器单测。→ verify:测试绿。
|
||||
- [ ] **Task 2.5(接入视图 + 视觉验收)** `DatasetDetailPage`/`RawDataChartView` 接收 `chartReady` 渲染散点。启动 app 双击测量类 ds,**对照 Phase 0 截图逐项验收**(点形/色阶/轴/等比),截图发用户确认。→ verify:视觉等价。
|
||||
- [ ] **Task 2.6(rows 形态)** 若 Phase 0 显示 `measurement/rows` 是另一种展示(如伪剖面/列表),据规格归类(等值面→复用 `ContourPlotItem`;表格→另议),重复 2.1–2.5 节奏。**形态不明则 BLOCKED 待 Phase 0 规格。**
|
||||
- [ ] **Task 2.7(提交)** 每 1–2 个 Task 一次原子提交,保持构建绿。`feat(detail): ERT 测量散点详情图 (DTO+仓储+策略+视图)`。
|
||||
|
||||
---
|
||||
|
||||
## Phase 3:TEM / 设备时序(折线形态,仅当 Task 0.2 确认有样本才进行)
|
||||
|
||||
> 🔓 解锁条件:Phase 0 确认 TEM/timeSensor 有活样本且抓到响应。**未解锁 BLOCKED,跳过。**
|
||||
> 渲染归类:时序折线类 → **新建** `LineChartView`(QwtPlot + `QwtPlotCurve`,x=时间,y=数值)。
|
||||
> 接口(已核对):`POST /business/dd/ert/timeSensor/rows`(body `DDTimeSensorDataQueryReqVO`,Phase 0 抓真实 body 字段)、`GET dd/ert/timeSensor/page`。
|
||||
|
||||
- [ ] **Task 3.1(DTO 解析 + 单测)** 用真实响应夹具 `tests/fixtures/dd/tem-timesensor.json`,先写测试(RED)→ 实现 `parseTimeSensorSeries`(→ 时间数组 + 多通道数值序列模型;模型若无现成 core 类型,加最小 `core::TimeSeries`,YAGNI)。→ verify:测试绿。
|
||||
- [ ] **Task 3.2(异步句柄 + 仓储)** 因是 POST + 不同返回,加 `SeriesLoad`/`SeriesParts` 句柄(参照 `ApiChartLoad`/`ApiGridLoad` 写 `ApiSeriesLoad`)+ `loadTimeSensorAsync(dsId)`(`postJsonAsync` 组 body)。补句柄桩单测。→ verify:测试绿。
|
||||
- [ ] **Task 3.3(LineChartView + 组件测)** 新建 `src/app/panels/chart/LineChartView.{hpp,cpp}`:QwtPlot + 每通道一条 `QwtPlotCurve` + 图例 + 平移/缩放(复用 `LivePanner` 模式)。组件测:给定 series → 断言曲线条数/点数。→ verify:测试绿。
|
||||
- [ ] **Task 3.4(策略 + 控制器 + 页面接入)** `TimeSensorStrategy`(实测 ddCode,`hasGridPhase()==false`)。控制器据策略走 `loadTimeSensorAsync` → 新增 `seriesReady` 信号 → `DatasetDetailPage` 用 `LineChartView` 渲染(页内页签按类型选 View)。main.cpp 注册。补控制器单测。→ verify:测试绿 + 启动 app 双击 TEM ds,对照 Phase 0 截图验收。
|
||||
- [ ] **Task 3.5(提交)** `feat(detail): TEM 时序折线详情图 (LineChartView+DTO+仓储+策略)`。
|
||||
|
||||
---
|
||||
|
||||
## Phase 4(BLOCKED:待样本)—— dd_grid / 轨迹 / 测井 / GPR
|
||||
|
||||
> 以下类型当前租户**无活样本**(spec §2.4 + Phase 0 复核)。**绝不规划凭想象的渲染任务**(违反 1:1 复刻原则)。本 Phase 只列「解锁前置条件 + 调研占位」,待样本到位后各自展开为类似 Phase 2/3 的 TDD 任务序列。
|
||||
|
||||
- [ ] **Task 4.1(dd_grid 网格)** 🚫 BLOCKED。
|
||||
- 解锁前置:租户内出现带数据的 dd_grid 对象,Phase 0 抓 `GET dd/ert/grid/rows?dsObjectId&pageNo&pageSize` 真实响应 + 详情页截图。
|
||||
- 预归类:等值面类 → 复用 `ContourPlotItem`/`GridDataChartView`(与反演 rows 同构则可大量复用 `parseInversionGrid` 思路;**须实测响应字段是否一致再决定复用/新 parse**)。
|
||||
- 注意:grid/rows 带分页参数,须确认是否需多页拼接。
|
||||
- [ ] **Task 4.2(轨迹 trajectory)** 🚫 BLOCKED。
|
||||
- 解锁前置:带数据的轨迹对象,抓 `GET dd/ert/trajectory/rows?dsObjectId` + `GET dd/ert/trajectory/line?dsObjectId&frontCrsCode` 响应 + 截图。
|
||||
- 预归类:路径/折线类 → 待样本定(散点连线 or `LineChartView`)。`frontCrsCode` 取值须 Phase 0 抓。
|
||||
- [ ] **Task 4.3(测井 well logging)** 🚫 BLOCKED(双重阻塞:无样本 + 接口未确认)。
|
||||
- 解锁前置:(a) 拿到测井数据样本;(b) **OpenAPI 未见明确测井 rows 接口** → Phase 0 须在原版「测井参数表」相关页面抓真实请求确认接口。
|
||||
- 预归类:折线类 → 复用 `LineChartView`(y=深度向下 / x=数值;或 x=时间 y=数值曲线,按菜单「测井参数表」两种形态,实测后定)。
|
||||
- [ ] **Task 4.4(GPR 雷达剖面)** 🚫 BLOCKED。
|
||||
- 解锁前置:GPR 对象有数据(spec 明确当前 GPR 对象无数据),抓 `GET dd/gpr/channel/image/{dsObjectId}` 响应(确认返回是图片 URL / base64 / 像素数组)+ 详情页截图。
|
||||
- 预归类:图像类 → 新建 `ImageChartView`(位图剖面 + 坐标轴叠加)。返回形态决定加载方式(图片下载 vs JSON 像素)。
|
||||
- 参考相关接口:`dd/gpr/channel/trace/spectrogram`、`dd/gpr/channel/querySegmentation`、`radar/trajectory/ds/{dsObjectId}`。
|
||||
|
||||
---
|
||||
|
||||
## 任务顺序与可构建性
|
||||
|
||||
1. **Phase 0 先行**:无样本不写代码。Phase 0 是纯调研 + 夹具,零代码风险。
|
||||
2. **Phase 1 是地基**:策略分派打通后,每个新 dd 类型才能「注册即生效」。Phase 1 必须保证 ERT 反演零回归(已有 89/89 测试 + 视觉验收兜底)。
|
||||
3. **接口/控制器改形原子落地**:`DatasetDetailController` 构造函数签名变更(加 registry)+ `main.cpp` 接线**须在同一提交**完成(否则构建红)。参照详情图 v2 「Task5+6 合并」教训:跨文件签名变更不拆提交。
|
||||
4. **Phase 2/3 仅在 Phase 0 解锁后展开**;Phase 4 永远 BLOCKED 直到样本到位。
|
||||
5. **每 1–2 个 bite-sized Task 一次提交**,每次提交前 `dev-test` 必须绿。
|
||||
|
||||
## 范围边界
|
||||
|
||||
- 本 plan 仅「详情图渲染扩展」。**不含**工具条编辑功能(白化/滤波/色阶配置/异常框注/自动标注/网格化/另存为/导出/描述富文本/大视图全屏)—— 另案(spec §2.3)。
|
||||
- 不改中央 2D/3D VTK 地图视图。
|
||||
- 不改 ApiClient 异步机制(已单独立项,详情详情链路已异步)。
|
||||
|
||||
---
|
||||
|
||||
## Self-Review(写完计划的自查结论)
|
||||
|
||||
- **核实优先**:所有接口路径/参数(query vs path、POST body schema)均已对 `docs/apis/business_OpenAPI.json` 核对(见 §1 表),未臆造。ddCode 除 `dd_inversion_data` 外源码无常量,已明确标注「待 Phase 0 实测核对」而非编造。
|
||||
- **关键现状坐实**:已读 `DatasetDetailController.cpp` 确认控制器硬编码 `dd_inversion_data`、未用注册表;`ErtInversionStrategy` 是空 stub。Phase 1「打通分派」据此设计,是真实缺口而非假想。
|
||||
- **诚实对待样本约束**:唯一确定有样本的是已完成的反演;其余全部置于 Phase 0 探查门之后。无样本类(dd_grid/轨迹/测井/GPR)一律 BLOCKED + 解锁前置条件,**未规划任何凭想象的渲染任务**,符合 1:1 复刻铁律。
|
||||
- **DRY/复用**:散点复用 `ScatterPlotItem`、等值面复用 `ContourPlotItem`、异步复用 `ApiBatch`/句柄模式;仅折线(TEM/测井)与图像(GPR)两种新形态新建 View,且各自有样本/解锁条件兜底。
|
||||
- **可构建性**:标注了「构造函数签名变更 + main.cpp 接线须同提交」的原子落地约束,避免中间态构建红。
|
||||
- **TDD 无占位符**:每个可推进 Task 给出确切文件路径、RED→GREEN 顺序、verify 命令;BLOCKED Task 给出明确解锁前置条件而非空泛描述。
|
||||
- **风险点**:(1) Phase 0 可能发现 ERT 测量/TEM 也无具体带数据对象 → 则 Phase 2/3 同样 BLOCKED,plan 仍成立(Phase 1 独立有价值)。(2) `IDatasetChartStrategy` 接口扩展刻意保守(只加 `hasGridPhase()`),避免为未解锁类型过度抽象;待新 View 真接入时再演进。
|
||||
Loading…
Reference in New Issue