Document result delivery workbench design

This commit is contained in:
2026-07-08 10:20:14 +08:00
parent 36a406ae49
commit e4459180ad
7 changed files with 1199 additions and 0 deletions
+2
View File
@@ -35,6 +35,8 @@
Result extraction and access-control audit: current D-InSAR export/registration boundaries, placeholder channels, admin/viewer limitations, and recommended exporter/operator/admin permission model.
- [RESULT_DELIVERY_DOWNLOAD_DESIGN_20260630.md](RESULT_DELIVERY_DOWNLOAD_DESIGN_20260630.md)
Result delivery/download design: asynchronous delivery packages, user-owned downloads, temporary delivery root, DB maintenance, and placeholder boundaries for SBAS/LT-1/Sentinel-1/GF3 ortho.
- [RESULT_CATALOG_SEARCH_DELIVERY_WORKBENCH_DESIGN_20260708.md](RESULT_CATALOG_SEARCH_DELIVERY_WORKBENCH_DESIGN_20260708.md)
Result catalog search and delivery workbench design: server-side catalog search, AOI/map preview, unified delivery item schema, selection basket, and staged implementation plan.
- [DINSAR_TASK_POOL_THREE_ENGINE_REFACTOR_20260614.md](DINSAR_TASK_POOL_THREE_ENGINE_REFACTOR_20260614.md)
D-InSAR 淇濈暀 ENVI/SARscape銆丩andSAR銆丟amma/PyINT 涓夊紩鎿庯紝閫€鍑?ISCE2锛岀粺涓€ Task_Pool銆佺粨鏋滆仛鍚堝拰涓棿鏂囦欢娓呯悊鐨勫綋鍓嶈璁°€?
- [LANDSAR_DEM_PREPARATION_CONTRACT_20260618.md](LANDSAR_DEM_PREPARATION_CONTRACT_20260618.md)
@@ -0,0 +1,479 @@
# 成果目录检索与交付工作台设计
日期:2026-07-08
## 背景
当前“结果提取”页面已经完成了成果交付的基础链路:用户从已登记 catalog 中选择成果,后台创建交付任务,并在交付完成后下载到本地。这个方向是正确的,但当前页面仍然偏向“列表勾选 + 生成交付包”,缺少成果检索、空间预览和地图辅助选择能力。
从业务上看,用户真正需要完成的是:
1. 在成果目录中按时间、区域、传感器、生产引擎和成果状态检索。
2. 在地图上确认成果覆盖范围和预览图。
3. 选择需要交付的成果。
4. 生成后台交付包并下载到本地。
因此本设计将“结果提取”能力升级为“成果目录检索与交付工作台”。“生产结果入库”继续归属 D-InSAR 结果管理页;本页面只处理已登记成果的检索、预览、选择和交付。
## 现状问题
### 前端问题
- `frontend/src/ResultExtractionPanel.jsx` 启动时只加载固定数量结果,默认 `PAGE_SIZE = 100`
- D-InSAR 结果走旧接口 `/api/dinsar-results`LT-1/GF3 正射走 `/api/result-deliveries/catalog/{channel}`,通道数据源不统一。
- “结果检索”只是前端对已加载数组做字符串过滤,不能检索未加载分页,也不能按时间、区域、AOI、状态等业务条件查询。
- 页面没有地图窗口,用户无法判断成果空间覆盖。
- 页面没有成果预览图区域,不能像 D-InSAR 结果目录一样核对位移图或正射快视。
- 选择行为和检索行为耦合在当前可见列表中,缺少稳定的“已选成果篮”概念。
- SBAS、Sentinel-1 等未完全接入通道虽然有占位,但与可交付通道的工作流差异仍不够清楚。
### 后端问题
- `GET /api/result-deliveries/catalog/{channel}` 目前只支持 `limit``offset``query`
- D-InSAR 分支没有真正应用 `query` 条件。
- catalog 返回字段不统一,缺少地图和预览需要的标准字段,例如 `coverage_polygon``bbox``preview_url`
- LT-1/GF3 分支可从 `radar_data``sar_scene_geo` 找到部分空间和预览信息,但没有统一输出到交付 catalog。
- 当前接口语义更像“交付源列表”,不是完整“成果目录检索”。
## 目标
- 将结果提取页面升级为成果目录检索、地图预览、成果选择和交付下载的一体化工作台。
- 统一 D-InSAR、LT-1 正射、GF3 正射的可交付成果 catalog 查询入口。
- 保留 SBAS-InSAR、Sentinel-1 正射占位,但明确标注未开放交付或未接入生产。
- 支持服务端检索,不依赖前端只过滤已加载的前 100 条。
- 支持时间范围、行政区/AOI、成果通道、生产引擎、状态、关键词等查询。
- 地图窗口展示成果 footprint,列表与地图联动。
- 成果预览图和详情面板用于核对质量、日期、路径和交付状态。
- 创建交付包仍使用后台任务,避免 HTTP 请求复制大文件导致 504。
- 保持普通用户不输入服务器任意路径,所有交付都落在受控交付区。
## 非目标
- 本次不实现 Sentinel-1 正射生产。
- 本次不实现 SBAS-InSAR 交付打包,只保留目录展示和清晰占位。
- 本次不改变 D-InSAR 生产结果入库流程。
- 本次不做跨节点对象存储或外部网盘。
- 本次不让用户通过页面直接删除正式成果 catalog 原文件。
- 本次不重构整套用户权限模型,但接口需要保留后续 `exporter/operator/admin` 能力拆分空间。
## 术语边界
| 术语 | 定义 | 页面归属 |
| --- | --- | --- |
| 生产结果入库 | 从 LandSAR、ENVI/SARscape、Gamma 等生产目录提取成果并登记到 catalog | D-InSAR 结果管理 |
| 成果目录检索 | 从已登记 catalog 中按条件查询成果 | 成果目录检索与交付 |
| 成果预览 | 查看成果快视图、位移图、正射缩略图、空间 footprint | 成果目录检索与交付 |
| 成果交付 | 将用户选择的成果复制到受控交付区,生成 manifest/checksum/zip | 成果目录检索与交付 |
| 交付包 | 后台生成的用户可下载成果包 | 成果目录检索与交付 |
## 目标页面结构
页面名称建议从“结果提取”调整为:
```text
成果检索与交付
```
页面采用生产系统工作台结构,不做营销式 hero。建议结构如下:
```text
┌───────────────────────────────────────────────────────────────┐
│ 顶部状态区:当前通道 / 检索结果数 / 已选数量 / 最近交付状态 │
├───────────────┬───────────────────────────────┬───────────────┤
│ 检索条件区 │ 地图预览区 │ 详情与预览区 │
│ - 通道 │ - footprint │ - 快视图 │
│ - 时间 │ - AOI/行政区边界 │ - 元数据 │
│ - 行政区/AOI │ - 选中高亮 │ - 交付状态 │
│ - 引擎/状态 │ - 点击选择/定位 │ - 主文件路径 │
├───────────────┴───────────────────────────────┴───────────────┤
│ 成果列表:分页表格 / 批量选择 / 地图定位 / 预览 / 加入选择篮 │
├───────────────────────────────────────────────────────────────┤
│ 已选成果篮 + 交付选项 + 我的交付包 │
└───────────────────────────────────────────────────────────────┘
```
### 检索条件区
第一阶段需要支持:
- 成果通道:D-InSAR、LT-1 正射、GF3 正射、SBAS 占位、Sentinel-1 占位。
- 时间范围:
- D-InSAR:主影像日期、从影像日期或结果发布时间。
- 单景正射:成像日期。
- 行政区:复用现有省/市行政区选择能力。
- AOI:复用现有上传 SHP/GeoJSON 能力,第一阶段可以先支持行政区,第二阶段支持文件上传。
- 关键词:任务名、产品号、pair_key、路径片段。
- 生产引擎:SARscape、LandSAR、Gamma/PyINT、LT-1 正射链、GF3 SARscape。
- 成果状态:READY、DONE、PARTIAL、FAILED、健康状态。
- 是否有预览:全部、有预览、无预览。
### 地图预览区
地图窗口必须服务于选择,不只是展示。
功能要求:
- 绘制查询结果的 footprint 或 bbox。
- 绘制当前 AOI/行政区边界。
- 列表选中成果时,地图高亮对应 footprint 并定位。
- 地图点击成果时,右侧详情区展示预览和元数据。
- 已加入选择篮的成果使用独立样式标识。
- 没有空间范围的成果在列表中保留,但地图上不绘制,并显示“缺少空间范围”状态。
实现建议:
- 第一阶段可复用 `MiniCoverageMap` 的 bbox/polygon 绘制逻辑,但需要抽成支持交互的 `ResultCatalogMap`
- 地图底图复用现有系统 `getBaseLayerConfig` 和 tile 配置。
- 不在地图上直接叠大体量 GeoTIFF,预览图放到右侧详情区。
### 详情与预览区
选中成果后展示:
- 成果名称、通道、产品 ID。
- 预览图:
- D-InSAR 使用 `/api/dinsar-products/{id}/preview` 或兼容缩略图接口。
- LT-1/GF3 优先使用已生成 WebP/PNG 预览。
- 无预览时显示原因和可维护提示,不阻塞交付。
- 时空信息:
- D-InSARmaster/slave 日期、时间基线、pair_key、引擎。
- 单景正射:成像日期、极化、像素大小、卫星。
- 空间信息:bbox、行政区匹配、coverage_polygon 状态。
- 文件信息:主文件路径、大小、manifest、quality 文件。
- 交付信息:是否已被当前用户交付过、最近交付状态。
### 成果列表
列表需要支持服务端分页,不能只展示前 100 条。
列建议:
- 选择框。
- 成果名称。
- 通道。
- 日期。
- 空间范围状态。
- 生产引擎/配置。
- 文件大小。
- 预览状态。
- 交付状态。
- 操作:定位地图、预览、加入/移出选择篮。
列表和地图联动:
- 点击行:更新详情区。
- 点击“定位”:地图飞到 footprint。
- 勾选:加入选择篮,不应随翻页丢失。
- 批量选择只作用于当前查询结果或当前页,按钮文案必须明确。
### 已选成果篮
当前页面需要独立的选择篮状态,而不是只从当前 `filteredResults` 里计算。
要求:
- 跨分页保持选择。
- 切换通道时保留各通道选择,但创建交付时默认只对当前通道提交。
- 显示已选数量、总大小估算、缺失文件数。
- 支持清空当前通道、移除单项。
- 超过后端 `RESULT_DELIVERY_MAX_ITEMS` 时提前提示。
### 我的交付包
继续复用现有后台交付任务。
展示要求:
- 状态:PENDING、RUNNING、READY、FAILED、CANCELLED、EXPIRED。
- 文件数、总大小、已复制大小。
- 失败项数量和原因摘要。
- manifest、zip、逐文件下载入口。
- 过期时间。
- 刷新按钮和运行中自动轮询。
## 后端接口设计
### 统一成果目录检索
建议保留现有路径,增强为真正的 catalog search
```http
GET /api/result-deliveries/catalog/{channel}
```
查询参数:
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| `limit` | int | 每页数量,默认 100,最大 500 |
| `offset` | int | 分页偏移 |
| `query` | string | 关键词 |
| `date_from` | string | 起始日期,`YYYY-MM-DD``YYYYMMDD` |
| `date_to` | string | 结束日期 |
| `date_mode` | string | `imaging``master``slave``published` |
| `region_tree_id` | string | 行政区树 ID |
| `aoi_token` | string | 已上传 AOI token,第二阶段接入 |
| `engine_code` | string | 生产引擎 |
| `profile_code` | string | 生产配置 |
| `status` | string | 成果状态 |
| `has_preview` | bool | 是否只查有预览成果 |
| `has_geometry` | bool | 是否只查有空间范围成果 |
| `sort` | string | `date_desc``published_desc``name_asc` |
返回:
```json
{
"items": [],
"total": 0,
"limit": 100,
"offset": 0,
"has_more": false,
"summary": {
"channel": "dinsar",
"matched": 0,
"with_geometry": 0,
"with_preview": 0,
"selected_hint": null
}
}
```
### 统一 catalog item 字段
所有通道返回尽量统一字段:
```json
{
"id": 1,
"item_id": 1,
"channel": "dinsar",
"source_kind": "dinsar_result",
"product_id": "xxx",
"display_name": "xxx",
"task_name": "xxx",
"status": "READY",
"health_status": "OK",
"engine_code": "landsar",
"profile_code": "lt1_dinsar",
"pair_key": "20260201_20260301",
"imaging_date": null,
"master_imaging_date": "2026-02-01",
"slave_imaging_date": "2026-03-01",
"published_at": "2026-07-08T10:00:00",
"primary_asset_path": "D:\\...",
"publish_dir": "D:\\...",
"file_size": 123456789,
"preview_url": "/api/dinsar-products/1/preview",
"preview_status": "READY",
"coverage_polygon": [[126.1, 45.1], [126.2, 45.1], [126.2, 45.2], [126.1, 45.2]],
"bbox": {
"min_lon": 126.1,
"min_lat": 45.1,
"max_lon": 126.2,
"max_lat": 45.2
},
"geometry_status": "READY",
"delivery_summary": {
"latest_delivery_id": null,
"latest_status": null
}
}
```
### D-InSAR 字段来源
D-InSAR catalog 应优先读取 `result_products`
- `product_id`
- `catalog_name`
- `product_family`
- `product_type`
- `engine_code`
- `profile_code`
- `pair_key`
- `task_name`
- `task_alias`
- `primary_asset_path`
- `publish_dir`
- `manifest_path`
- `coverage_polygon`
- `min_lon``min_lat``max_lon``max_lat`
- `produced_at`
- `published_at`
兼容旧 `dinsar_results` 的 ID 时,需要同时保留 `compat_result_id`,但前端不应感知两套 ID 规则。
### LT-1 正射字段来源
LT-1 正射 catalog 读取 `sar_scene_geo``radar_data`
- `sar_scene_geo.id` 作为 `item_id`
- `sar_scene_geo.analysis_tif_path` 作为主交付物
- `sar_scene_geo.analysis_dir` 作为发布目录
- `radar_data.imaging_date`
- `radar_data.polarization`
- `radar_data.coverage_polygon`
- `radar_data.min_lon/min_lat/max_lon/max_lat` 或由 polygon 计算 bbox
- `radar_data.preview`/WebP 缓存作为预览来源
### GF3 正射字段来源
GF3 正射 catalog 读取 `radar_data`,必要时左连接 `sar_scene_geo`
- `radar_data.id` 作为 `item_id`
- `radar_data.file_path``sar_scene_geo.analysis_tif_path` 作为主文件/目录
- `radar_data.source_format`
- `radar_data.geocoded_flag`
- `radar_data.imaging_date`
- `radar_data.polarization`
- `radar_data.coverage_polygon`
- WebP/quicklook 作为预览来源
## 空间检索设计
第一阶段:
- 支持行政区 `region_tree_id`
- 后端把行政区 geometry 转为 AOI。
- 对有 `coverage_polygon` 或 bbox 的成果做空间相交过滤。
- 对缺失 geometry 的成果默认不进入空间过滤结果,但在 summary 中统计缺失数量。
第二阶段:
- 支持上传 SHP/GeoJSON,复用现有 AOI upload/token 机制。
- 支持地图框选。
- 支持空间关系选项:
- `intersects`
- `contains_center`
- `overlap_ratio >= threshold`
## 预览设计
### D-InSAR
- 首选标准结果产品预览接口。
- 如果只有兼容旧 `dinsar_results` 缩略图,则 fallback 到旧 `/api/dinsar-results/{id}/thumb`
- 预览失败不影响交付,但列表显示“预览异常”。
### LT-1/GF3 正射
- 优先使用资产 WebP/quicklook。
- 若没有 WebP,但已有 GeoTIFF,可显示“未生成预览”,由运维/扫描任务补建。
- 不在本页面同步触发重建预览,避免打开检索页导致重任务。
## 权限与审计
第一阶段沿用当前登录用户模型:
- 登录用户可查看成果 catalog。
- 登录用户可创建自己的成果交付任务。
- 管理员可查看全部交付任务和执行清理。
- 生产结果入库、目录重建、正式成果删除仍属于管理员/运维能力。
所有交付创建需要记录:
- 用户。
- 查询通道。
- 提交的 item IDs。
- package mode。
- 任务 ID。
- 交付 ID。
后续拆角色时,建议能力名:
```text
result.catalog.read
result.delivery.create
result.delivery.read_own
result.delivery.read_all
result.delivery.cleanup
result.product.ingest
```
## 性能与可靠性
- catalog 查询必须服务端分页。
- `limit` 最大 500,默认 100。
- 空间查询需要优先使用数据库索引;如果当前表缺少 geometry 索引,应先用 bbox 粗筛,再做 polygon 精筛。
- 地图首屏最多绘制当前页或当前查询前 N 个 footprint,避免一次渲染数千 polygon。
- 预览图懒加载,只有选中或进入可视区域才请求。
- 交付包创建只提交 ID 列表,不提交文件路径。
- 后台交付任务必须记录单项失败,不应一个文件失败导致整批不可用。
## 实施阶段
### 阶段 1:文档和接口契约
- 完成本设计文档。
- 明确“成果检索与交付”和“生产结果入库”边界。
- 梳理 D-InSAR、LT-1、GF3 catalog 字段来源。
### 阶段 2:后端 catalog 查询增强
- 增强 `/api/result-deliveries/catalog/{channel}` 参数。
- D-InSAR 分支应用 `query`、分页、日期、引擎和状态过滤。
- LT-1/GF3 分支补充日期、行政区/AOI、状态、预览和 geometry 字段。
- 返回统一 item schema。
- 增加必要的单元测试或接口级测试。
### 阶段 3:前端工作台改造
- 重构 `ResultExtractionPanel.jsx` 为成果检索工作台。
- 新增检索条件区。
- 新增地图预览区。
- 新增详情与预览区。
- 改造列表为服务端分页。
- 新增跨分页选择篮。
- 保留我的交付包列表和后台轮询。
### 阶段 4:联动和质量收口
- 列表、地图、详情三者联动。
- 交付创建前校验最大数量和缺失文件。
- 未接入通道显示明确占位,不可误触发交付。
- 补充空状态、错误状态、加载骨架和响应式布局。
## 验收标准
完成后应满足:
1. 用户可以按通道、时间、关键词、引擎、状态检索成果。
2. 用户可以选择行政区并只查看相交成果。
3. 检索结果不是前端过滤前 100 条,而是服务端分页结果。
4. 地图能显示当前检索结果的 footprint 或 bbox。
5. 点击列表能定位地图并展示预览详情。
6. 点击地图能选中对应成果并展示详情。
7. 用户跨分页选择成果后,选择篮不丢失。
8. 创建交付包仍是后台任务,不出现同步复制导致的 504。
9. D-InSAR、LT-1 正射、GF3 正射三类可交付成果字段一致。
10. SBAS、Sentinel-1 未接入能力不会被用户误认为可执行。
11. 缺失预览或缺失空间范围的成果有明确状态,不阻断其他成果交付。
12. 普通用户不需要输入服务器路径。
## 风险与注意事项
- D-InSAR 旧结果兼容 ID 和新 `result_products.id` 不能混淆,交付创建接口需要继续兼容 `compat_result_ids`
- 某些历史成果可能没有 `coverage_polygon`,空间检索时要给出统计和提示。
- LT-1/GF3 的预览来源可能不一致,第一阶段允许 `preview_status = MISSING`
- 地图渲染大量 polygon 可能卡顿,需要限制首屏绘制数量或做简化。
- 结果提取页面改名后,导航和用户手册需要同步调整。
## 建议代码入口
后端:
- `backend/app/routers/result_deliveries.py`
- `backend/app/services/result_delivery_service.py`
- `backend/app/services/dinsar_read_service.py`
- `backend/app/routers/radar.py` 中已有 AOI/搜索逻辑可参考
前端:
- `frontend/src/ResultExtractionPanel.jsx`
- `frontend/src/api/resultDeliveries.js`
- `frontend/src/components/MiniCoverageMap.jsx`
- `frontend/src/components/DinsarCatalogPanel.jsx`
- `frontend/src/panels/PairPlanningPanel.jsx`
- `frontend/src/hooks/useRadarSearch.js`