docs(spec): 对齐数据/文件页签接 data-page/file-page + DsRow/loadTmRows/filesLoaded

This commit is contained in:
gaozheng 2026-06-09 14:58:55 +08:00
parent 839e5c3487
commit 7cdc7b8077
1 changed files with 13 additions and 9 deletions

View File

@ -47,11 +47,12 @@ token 已由登录注入(`geomativeauthorization` 头),下列接口直接
| 切换工作空间 | POST | `/business/system/tenant/enterprise/switch/{tenantId}` | 信封 code/msg |
| 项目列表 | GET | `/business/project/queryByUser?lastProjectId=` | `{hasNextPage, projectList:[{id, projectName, projectTypeName, referenceCRSCode, referenceCRSName, status, ...}]}`(游标分页,首页传空 lastProjectId |
| 项目结构 | POST | `/business/projectWorkbench/queryProjectStruct` | body `{projectId}`data `{projectStructList:[{id, name, parentId, type, typeId, typeName, confCode}]}` |
| TM 下 DS | GET | `/business/projectWorkbench/queryDsByTmObjectId/{tmObjectId}` | `[{id, name, ddCode, typeName}]` |
| TM 下数据(页签) | POST | `/business/dsObject/data/page` | body `{projectId, structParentId:<tmObjectId>, structParentConfType:2, classifyTypeList:[3], pageNo, pageSize}``data.list[{id, dsName, name(类型名), ddCode}]` |
| TM 下文件(页签) | POST | `/business/dsObject/file/page` | body 同上但 `classifyTypeList:[1]`;项另含 `file{name, size, url}` |
**层级确认(修正需求方假设)**:真实结构**不是** `项目→tm→ds`,而是 **`项目 → GS(工区) → TM(测线) → DS`**。
- `queryProjectStruct` 返回一个**扁平 parent-child 列表**(仅含 GS + TM 两类节点,**不含 DS**),客户端按 `parentId` 自建树。
- DS 不在结构列表里,按 TM 单独拉取(`queryDsByTmObjectId`)。
- DS 不在结构列表里:按 TM 拉数据/文件两类,分别用 `dsObject/data/page`(classify=3)、`dsObject/file/page`(classify=1),传 `structParentId=<tmObjectId>`、`structParentConfType=2`。(实测:`queryByUser` 返回空,项目列表改用 `my/profile/queryProject``queryDsByTmObjectId` 字段不全已弃用。)
- **项目不能直接挂 DS**DS 永远挂在 TM 下。但由于是 `parentId` 扁平结构,**TM 可直接挂在项目下(无中间 GS**——这是"项目直接挂"印象的来源,但叶子仍是 TM→DS。
**节点判定**:结构列表只含 GS+TM**TM = 该节点在结构列表中无子节点(叶子)**;非叶子 = GS。
@ -116,7 +117,7 @@ struct StructNode {
int type = 0;
};
```
`DsNode{id,name,ddType}` 复用;映射时 `ddCode → ddType`
新增 `DsRow{id, dsName, typeName, ddCode, fileName, fileUrl, fileSize}`(数据/文件页签行通用;文件行含 file*)。`DsNode` 仅本地样本仓储继续用
### 5.3 数据访问层 `data`
@ -134,7 +135,9 @@ public:
virtual RepoResult<bool> switchWorkspace(const std::string& tenantId) = 0;
virtual RepoResult<std::vector<ProjectSummary>> listProjects(const std::string& lastProjectId) = 0;
virtual RepoResult<std::vector<StructNode>> loadStructure(const std::string& projectId) = 0;
virtual RepoResult<std::vector<DsNode>> loadDatasetsOfTm(const std::string& tmObjectId) = 0;
virtual RepoResult<std::vector<DsRow>> loadTmRows(const std::string& projectId,
const std::string& tmObjectId,
int classifyType) = 0; // 3=数据 1=文件
};
```
@ -147,7 +150,7 @@ public:
- `parseWorkspaces(QJsonArray) -> vector<Workspace>``isCurTenant==1 → isCurrent`)。
- `parseProjects(QJsonObject) -> {vector<ProjectSummary>, bool hasNextPage}`
- `parseStructNodes(QJsonArray) -> vector<StructNode>`
- `parseDatasets(QJsonArray) -> vector<DsNode>``ddCode→ddType`)。
- `parseDsRows(QJsonArray) -> vector<DsRow>`data/file page 的 `data.list``name→typeName``file{name,size,url}`)。
- `buildStructTree(vector<StructNode>) -> vector<StructTreeNode>`:扁平→**通用树**(不强塞 `Project/Gs/Tm` 刚性模型,
以适配任意层级 + TM 直挂项目)。`StructTreeNode{StructNode node; bool isTm; vector<StructTreeNode> children}`。
- 以 `parentId` 归并;`parentId` 为空或不在集合内(孤儿)的节点为根层。
@ -173,7 +176,8 @@ signals:
void projectsLoaded(const std::vector<data::ProjectSummary>&, QString currentId);
// 发出项目名 + 扁平结构节点建树buildStructTree在 ObjectTreePanel 内完成。
void structureLoaded(const QString& projectName, const std::vector<data::StructNode>&);
void datasetsLoaded(const QString& tmObjectId, const std::vector<data::DsNode>&);
void datasetsLoaded(const QString& tmObjectId, const std::vector<data::DsRow>&); // 数据页签
void filesLoaded(const QString& tmObjectId, const std::vector<data::DsRow>&); // 文件页签
void loadFailed(const QString& stage, const QString& message); // 出错→UI 空/错状态
void busyChanged(bool busy); // 同步阻塞期间置 WaitCursor
private:
@ -202,7 +206,7 @@ private:
`showMessage(msg)` 显示空/错占位。信号 `tmClicked(QString tmObjectId)` / `tmCheckToggled(...)`
(后者为前瞻钩子,本轮无消费者)。
**`app/panels/DatasetListPanel`**(已有)—— `datasetsLoaded``populateDatasetList`;空时显示"暂无数据集"
**`app/panels/DatasetListPanel`** —— `datasetsLoaded`→`populateDatasetList`数据dsName+类型名);`filesLoaded`→`populateFileList`(文件:文件名+可读大小url 存角色备下载);空时占位。列表去隔行变色,改细分割线
**中央/详情**:移除"启动自动渲染本地 demo"DS 点击 → 详情面板与中央视图显示占位文案
"该数据集渲染将在下一阶段接入 dd 接口"。渲染代码保留。
@ -225,7 +229,7 @@ private:
→ controller.switchProject: loadStructure(id) → emit structureLoaded清空 DS 列表/详情占位
选 TM: ObjectTreePanel.tmClicked(tmObjectId)
→ controller.selectTm: loadDatasetsOfTm → emit datasetsLoaded → DatasetListPanel 填充
→ controller.selectTm: loadTmRows(pid,tm,3)+loadTmRows(pid,tm,1) → emit datasetsLoaded + filesLoaded → 数据/文件页签
点 DS: DatasetListPanel → 中央/详情显示占位"待接入"(本轮不渲染真实数据)
```
@ -284,7 +288,7 @@ void rebuildCentralScene(geopro::render::Scene& scene, vtkRenderer* renderer,
## 9. 测试策略
依既有无测试桩 + 依赖 live 服务器的现实,聚焦**纯逻辑单测**GoogleTest + CTest
- `dto/NavDto` 映射:喂样本 JSON取自 OpenAPI example / 手造)验证
`parseWorkspaces / parseProjects / parseStructNodes / parseDatasets` 字段与 `ddCode→ddType`、`isCurTenant→isCurrent`。
`parseWorkspaces / parseProjects / parseStructNodes / parseDsRows` 字段与 `name→typeName`、`isCurTenant→isCurrent`。
- `buildStructTree` 扁平→树:覆盖 项目根→GS→TM、TM 直挂项目(无 GS、孤儿 parentId、空列表、防环 等场景。
- 不做 live 集成 / E2E无桩、依赖真实后端。控制器/UI 信号联动靠手动联调验证。
- 目标纯逻辑文件dto + tree builder覆盖率优先达标UI/网络 IO 不计入。