docs(spec): 补齐项目列表弹窗/ds加载更多分页/创建时间显示/分页条数(10·5)/状态映射(1未开始2进行中)
This commit is contained in:
parent
a37596f0d3
commit
475af464d9
|
|
@ -24,8 +24,11 @@
|
||||||
|
|
||||||
**做(In Scope)**
|
**做(In Scope)**
|
||||||
- 工作空间列表 / 切换(真实接口)。
|
- 工作空间列表 / 切换(真实接口)。
|
||||||
- 项目列表 / 切换(真实接口)。
|
- 项目列表 / 切换(真实接口):下拉显示首页项目(首页 10);项目数超过首页 → 下拉底部「全部项目…」打开
|
||||||
|
**项目列表弹窗**(名称/类型过滤 + 分页 + 8 列表格:序号/名称/编号/状态/类型/业主/负责人/创建时间;点项目名切换并关弹窗)。
|
||||||
- 对象树:**按真实结构显示 GS 层**(项目根 → GS → TM);TM 在左下"数据真实显示栏"列出其 DS。
|
- 对象树:**按真实结构显示 GS 层**(项目根 → GS → TM);TM 在左下"数据真实显示栏"列出其 DS。
|
||||||
|
- DS **数据/文件两个页签**接真实分页接口(每页 5);每行显示"名称 / 创建时间 · 类型(数据)或大小(文件)";
|
||||||
|
超过首页 → 列表末尾「加载更多」追加下一页。
|
||||||
- 真实接口失败(断网 / token 过期 / 无数据)→ **显示错误 / 空状态**,**不回退本地样本**。
|
- 真实接口失败(断网 / token 过期 / 无数据)→ **显示错误 / 空状态**,**不回退本地样本**。
|
||||||
- 项目 `referenceCRSCode` 存入导航状态,供下一轮替换硬编码 `EPSG:4547`(本轮不改渲染)。
|
- 项目 `referenceCRSCode` 存入导航状态,供下一轮替换硬编码 `EPSG:4547`(本轮不改渲染)。
|
||||||
|
|
||||||
|
|
@ -34,7 +37,7 @@
|
||||||
→ 点击真实 DS 时中央/详情显示**占位"待接入"**;`render/*` 与 `LocalSampleRepository` 代码**保留不删**。
|
→ 点击真实 DS 时中央/详情显示**占位"待接入"**;`render/*` 与 `LocalSampleRepository` 代码**保留不删**。
|
||||||
- 异步仓储(QFuture/回调)—— 本轮同步阻塞 + WaitCursor(与登录一致),异步留 M1.5。
|
- 异步仓储(QFuture/回调)—— 本轮同步阻塞 + WaitCursor(与登录一致),异步留 M1.5。
|
||||||
- 用户头像 / 姓名接真实 `auth/getUserInfo`(本轮先留静态)。
|
- 用户头像 / 姓名接真实 `auth/getUserInfo`(本轮先留静态)。
|
||||||
- 项目分页"加载更多"的滚动 UI(接口支持 `hasNextPage`,本轮先取首页;翻页留待后续)。
|
- 文件下载(文件页签已展示文件名/大小、下载 `url` 已存入列表项备用,实际下载动作留后续)。
|
||||||
|
|
||||||
## 3. 接口确认结论
|
## 3. 接口确认结论
|
||||||
|
|
||||||
|
|
@ -45,10 +48,11 @@ token 已由登录注入(`geomativeauthorization` 头),下列接口直接
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 工作空间列表 | GET | `/business/system/tenant/enterprise/joined/list` | `[{id, name, ownerType(1个人/2企业), isCurTenant(0/1), logoPath}]` |
|
| 工作空间列表 | GET | `/business/system/tenant/enterprise/joined/list` | `[{id, name, ownerType(1个人/2企业), isCurTenant(0/1), logoPath}]` |
|
||||||
| 切换工作空间 | POST | `/business/system/tenant/enterprise/switch/{tenantId}` | 信封 code/msg |
|
| 切换工作空间 | 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/my/profile/project/page` | body `{projectName(名称模糊,可空), projectTypeId(类型过滤,可空), pageNo, pageSize}`;`data{list:[{id, projectName, projectCode, status, projectTypeId, projectTypeName, ownerCompanyName, responsiblePersonName, createTime, referenceCRSCode}], total}`(实测 `queryByUser`/`queryProject` 返回空或不带分页,弃用) |
|
||||||
| 项目结构 | POST | `/business/projectWorkbench/queryProjectStruct` | body `{projectId}`;data `{projectStructList:[{id, name, parentId, type, typeId, typeName, confCode}]}` |
|
| 项目类型列表 | GET | `/business/project/type/list` | `data.value:[{id, name}]`(弹窗"项目类型"过滤下拉) |
|
||||||
| TM 下数据(页签) | POST | `/business/dsObject/data/page` | body `{projectId, structParentId:<tmObjectId>, structParentConfType:2, classifyTypeList:[3], pageNo, pageSize}`;`data.list[{id, dsName, name(类型名), ddCode}]` |
|
| 项目结构 | GET | `/business/projectStruct/queryProjectStruct/{projectId}` | `data.value:[{id, name, parentId, type(1项目/2TM), typeId, typeName, confCode}]`(仅项目根+TM,不含 DS) |
|
||||||
| TM 下文件(页签) | POST | `/business/dsObject/file/page` | body 同上但 `classifyTypeList:[1]`;项另含 `file{name, size, url}` |
|
| TM 下数据(页签) | POST | `/business/dsObject/data/page` | body `{projectId, structParentId:<tmObjectId>, structParentConfType:2, classifyTypeList:[3], pageNo, pageSize}`;`data{list:[{id, dsName, name(类型名), ddCode, createTime}], total}` |
|
||||||
|
| TM 下文件(页签) | POST | `/business/dsObject/file/page` | body 同上但 `classifyTypeList:[1]`;项另含 `createTime` 与 `file{name, size, url}` |
|
||||||
|
|
||||||
**层级确认(修正需求方假设)**:真实结构**不是** `项目→tm→ds`,而是 **`项目 → GS(工区) → TM(测线) → DS`**。
|
**层级确认(修正需求方假设)**:真实结构**不是** `项目→tm→ds`,而是 **`项目 → GS(工区) → TM(测线) → DS`**。
|
||||||
- `queryProjectStruct` 返回一个**扁平 parent-child 列表**(仅含 GS + TM 两类节点,**不含 DS**),客户端按 `parentId` 自建树。
|
- `queryProjectStruct` 返回一个**扁平 parent-child 列表**(仅含 GS + TM 两类节点,**不含 DS**),客户端按 `parentId` 自建树。
|
||||||
|
|
@ -109,15 +113,19 @@ token 已由登录注入(`geomativeauthorization` 头),下列接口直接
|
||||||
struct Workspace { std::string id, name; int ownerType = 0; bool isCurrent = false; };
|
struct Workspace { std::string id, name; int ownerType = 0; bool isCurrent = false; };
|
||||||
struct ProjectSummary {
|
struct ProjectSummary {
|
||||||
std::string id, name, typeName, crsCode, crsName;
|
std::string id, name, typeName, crsCode, crsName;
|
||||||
int status = 0;
|
std::string code, projectTypeId, ownerCompany, responsiblePerson, createTime; // 弹窗 8 列用
|
||||||
|
int status = 0; // 1=未开始 2=进行中(其余显示数字)
|
||||||
};
|
};
|
||||||
|
struct ProjectType { std::string id, name; }; // 类型过滤下拉
|
||||||
|
struct ProjectListPage { std::vector<ProjectSummary> rows; int total = 0; }; // 项目分页结果
|
||||||
// 项目结构扁平节点(GS / TM);客户端按 parentId 建树。
|
// 项目结构扁平节点(GS / TM);客户端按 parentId 建树。
|
||||||
struct StructNode {
|
struct StructNode {
|
||||||
std::string id, name, parentId, typeName, confCode;
|
std::string id, name, parentId, typeName, confCode;
|
||||||
int type = 0;
|
int type = 0;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
新增 `DsRow{id, dsName, typeName, ddCode, fileName, fileUrl, fileSize}`(数据/文件页签行通用;文件行含 file*)。`DsNode` 仅本地样本仓储继续用。
|
新增 `DsRow{id, dsName, typeName, ddCode, createTime, fileName, fileUrl, fileSize}`(数据/文件页签行通用;文件行含 file*)
|
||||||
|
+ `DsPage{rows, total}`(分页结果)。`DsNode` 仅本地样本仓储继续用。
|
||||||
|
|
||||||
### 5.3 数据访问层 `data`
|
### 5.3 数据访问层 `data`
|
||||||
|
|
||||||
|
|
@ -133,11 +141,15 @@ public:
|
||||||
virtual ~IProjectRepository() = default;
|
virtual ~IProjectRepository() = default;
|
||||||
virtual RepoResult<std::vector<Workspace>> listWorkspaces() = 0;
|
virtual RepoResult<std::vector<Workspace>> listWorkspaces() = 0;
|
||||||
virtual RepoResult<bool> switchWorkspace(const std::string& tenantId) = 0;
|
virtual RepoResult<bool> switchWorkspace(const std::string& tenantId) = 0;
|
||||||
virtual RepoResult<std::vector<ProjectSummary>> listProjects(const std::string& lastProjectId) = 0;
|
// 项目分页(名称/类型过滤)+ 项目类型列表(弹窗用)。
|
||||||
|
virtual RepoResult<ProjectListPage> pageProjects(const std::string& nameFilter,
|
||||||
|
const std::string& typeId, int pageNo,
|
||||||
|
int pageSize) = 0;
|
||||||
|
virtual RepoResult<std::vector<ProjectType>> listProjectTypes() = 0;
|
||||||
virtual RepoResult<std::vector<StructNode>> loadStructure(const std::string& projectId) = 0;
|
virtual RepoResult<std::vector<StructNode>> loadStructure(const std::string& projectId) = 0;
|
||||||
virtual RepoResult<std::vector<DsRow>> loadTmRows(const std::string& projectId,
|
// 按 TM 分页拉数据/文件行:classifyType 3=数据 1=文件;pageNo 从 1 起,pageSize 固定 5。
|
||||||
const std::string& tmObjectId,
|
virtual RepoResult<DsPage> loadTmRows(const std::string& projectId, const std::string& tmObjectId,
|
||||||
int classifyType) = 0; // 3=数据 1=文件
|
int classifyType, int pageNo) = 0;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -148,9 +160,10 @@ public:
|
||||||
|
|
||||||
**`dto/NavDto.{hpp,cpp}`** — 纯函数映射(**无网络、可单测**):
|
**`dto/NavDto.{hpp,cpp}`** — 纯函数映射(**无网络、可单测**):
|
||||||
- `parseWorkspaces(QJsonArray) -> vector<Workspace>`(`isCurTenant==1 → isCurrent`)。
|
- `parseWorkspaces(QJsonArray) -> vector<Workspace>`(`isCurTenant==1 → isCurrent`)。
|
||||||
- `parseProjects(QJsonObject) -> {vector<ProjectSummary>, bool hasNextPage}`。
|
- `parseProjectList(QJsonArray) -> vector<ProjectSummary>` / `parseProjectPage(QJsonObject) -> ProjectListPage{rows,total}`(project/page)。
|
||||||
|
- `parseProjectTypes(QJsonArray) -> vector<ProjectType>`(type/list)。
|
||||||
- `parseStructNodes(QJsonArray) -> vector<StructNode>`。
|
- `parseStructNodes(QJsonArray) -> vector<StructNode>`。
|
||||||
- `parseDsRows(QJsonArray) -> vector<DsRow>`(data/file page 的 `data.list`;`name→typeName`,`file{name,size,url}`)。
|
- `parseDsRows(QJsonArray) -> vector<DsRow>` / `parseDsPage(QJsonObject) -> DsPage{rows,total}`(data/file page;`name→typeName`、`createTime`、`file{name,size,url}`)。
|
||||||
- `buildStructTree(vector<StructNode>) -> vector<StructTreeNode>`:扁平→**通用树**(不强塞 `Project/Gs/Tm` 刚性模型,
|
- `buildStructTree(vector<StructNode>) -> vector<StructTreeNode>`:扁平→**通用树**(不强塞 `Project/Gs/Tm` 刚性模型,
|
||||||
以适配任意层级 + TM 直挂项目)。`StructTreeNode{StructNode node; bool isTm; vector<StructTreeNode> children}`。
|
以适配任意层级 + TM 直挂项目)。`StructTreeNode{StructNode node; bool isTm; vector<StructTreeNode> children}`。
|
||||||
- 以 `parentId` 归并;`parentId` 为空或不在集合内(孤儿)的节点为根层。
|
- 以 `parentId` 归并;`parentId` 为空或不在集合内(孤儿)的节点为根层。
|
||||||
|
|
@ -170,14 +183,17 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void switchWorkspace(const QString& tenantId); // 切空间→重载项目→重载结构
|
void switchWorkspace(const QString& tenantId); // 切空间→重载项目→重载结构
|
||||||
void switchProject(const QString& projectId); // 切项目→重载结构(清 DS/详情)
|
void switchProject(const QString& projectId); // 切项目→重载结构(清 DS/详情)
|
||||||
void selectTm(const QString& tmObjectId); // 选 TM→拉其 DS
|
void selectTm(const QString& tmObjectId); // 选 TM→拉其 DS 首页(数据+文件)
|
||||||
|
void loadMoreData(); // 数据页签"加载更多"→下一页追加
|
||||||
|
void loadMoreFiles(); // 文件页签"加载更多"→下一页追加
|
||||||
signals:
|
signals:
|
||||||
void workspacesLoaded(const std::vector<data::Workspace>&, QString currentId);
|
void workspacesLoaded(const std::vector<data::Workspace>&, QString currentId);
|
||||||
void projectsLoaded(const std::vector<data::ProjectSummary>&, QString currentId);
|
void projectsLoaded(const std::vector<data::ProjectSummary>&, QString currentId, int total); // total 判断"全部项目"入口
|
||||||
// 发出项目名 + 扁平结构节点;建树(buildStructTree)在 ObjectTreePanel 内完成。
|
// 发出项目名 + 扁平结构节点;建树(buildStructTree)在 ObjectTreePanel 内完成。
|
||||||
void structureLoaded(const QString& projectName, const std::vector<data::StructNode>&);
|
void structureLoaded(const QString& projectName, const std::vector<data::StructNode>&);
|
||||||
void datasetsLoaded(const QString& tmObjectId, const std::vector<data::DsRow>&); // 数据页签
|
// total=总数、append=是否追加(加载更多 true / 首页 false)。
|
||||||
void filesLoaded(const QString& tmObjectId, const std::vector<data::DsRow>&); // 文件页签
|
void datasetsLoaded(const QString& tmObjectId, const std::vector<data::DsRow>&, int total, bool append);
|
||||||
|
void filesLoaded(const QString& tmObjectId, const std::vector<data::DsRow>&, int total, bool append);
|
||||||
void loadFailed(const QString& stage, const QString& message); // 出错→UI 空/错状态
|
void loadFailed(const QString& stage, const QString& message); // 出错→UI 空/错状态
|
||||||
void busyChanged(bool busy); // 同步阻塞期间置 WaitCursor
|
void busyChanged(bool busy); // 同步阻塞期间置 WaitCursor
|
||||||
private:
|
private:
|
||||||
|
|
@ -185,10 +201,13 @@ private:
|
||||||
data::IProjectRepository& repo_;
|
data::IProjectRepository& repo_;
|
||||||
std::vector<data::ProjectSummary> lastProjects_; // 供 switchProject 查 name/crsCode
|
std::vector<data::ProjectSummary> lastProjects_; // 供 switchProject 查 name/crsCode
|
||||||
std::string currentWorkspaceId_, currentProjectId_, currentProjectName_, currentCrsCode_;
|
std::string currentWorkspaceId_, currentProjectId_, currentProjectName_, currentCrsCode_;
|
||||||
|
std::string currentTmId_; // 加载更多用:当前选中 TM
|
||||||
|
int dataPageNo_ = 0, filePageNo_ = 0, dataTotal_ = 0, fileTotal_ = 0; // 数据/文件分页游标
|
||||||
bool busy_ = false; // 重入保护:同步请求期间拒绝再次进入
|
bool busy_ = false; // 重入保护:同步请求期间拒绝再次进入
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
编排逻辑:`start()` → `listWorkspaces`(选 isCurrent/首个)→ `listProjects`(选首个)→ `loadStructure`→发扁平节点。
|
编排逻辑:`start()` → `listWorkspaces`(选 isCurrent/首个)→ `pageProjects`(首页 10,选首个)→ `loadStructure`→发扁平节点。
|
||||||
|
`selectTm` 拉数据/文件首页(每页 5);`loadMoreData/Files` 递增页码追加。`switchWorkspace` 成功后用返回的新 accessToken 重注入 ApiClient(否则后续请求仍落旧空间)。
|
||||||
切空间/项目按 §6 时序。每个阶段失败 emit `loadFailed(stage,msg)` 并停在该阶段。
|
切空间/项目按 §6 时序。每个阶段失败 emit `loadFailed(stage,msg)` 并停在该阶段。
|
||||||
**重入保护**:每个公共操作入口 `if (busy_) return;`,并用 RAII guard 在置忙/复位时配平 `busyChanged`
|
**重入保护**:每个公共操作入口 `if (busy_) return;`,并用 RAII guard 在置忙/复位时配平 `busyChanged`
|
||||||
(同步 HTTP 会泵 Qt 事件循环,快速二次点击可能重入并污染状态)。
|
(同步 HTTP 会泵 Qt 事件循环,快速二次点击可能重入并污染状态)。
|
||||||
|
|
@ -196,17 +215,25 @@ private:
|
||||||
### 5.5 UI 层 `app`(被动视图,数据驱动)
|
### 5.5 UI 层 `app`(被动视图,数据驱动)
|
||||||
|
|
||||||
**`app/TopBar`** —— 由"自由函数返回静态 QWidget"升级为**数据驱动类**(QWidget 子类):
|
**`app/TopBar`** —— 由"自由函数返回静态 QWidget"升级为**数据驱动类**(QWidget 子类):
|
||||||
- `setWorkspaces(list, currentId)` / `setProjects(list, currentId)` 重建下拉项。
|
- `setWorkspaces(list, currentId)` / `setProjects(list, currentId, hasMore)` 重建下拉项;`hasMore` 时下拉底部加「全部项目…」。
|
||||||
- 信号 `workspaceSwitchRequested(QString id)` / `projectSwitchRequested(QString id)`。
|
- `setProjectButtonText(name)` —— 弹窗切换项目后更新项目按钮文字。
|
||||||
- 移除硬编码"个人工作空间 / 青海湖项目";用户区暂留静态。
|
- 信号 `workspaceSwitchRequested(id)` / `projectSwitchRequested(id)` / `allProjectsRequested()`(打开项目弹窗)。
|
||||||
- `buildMenuBar` 不变(静态菜单本轮不接)。
|
- 工作空间/项目下拉用互斥 `QActionGroup`(避免"多选"),选中即更新按钮文字。
|
||||||
|
- 移除硬编码"个人工作空间 / 青海湖项目";用户区暂留静态。`buildMenuBar` 不变。
|
||||||
|
|
||||||
**`app/panels/ObjectTreePanel`**(新增)—— 被动:`setStructure(projectName, vector<StructNode>)` 内部调
|
**`app/panels/ObjectTreePanel`**(新增)—— 被动:`setStructure(projectName, vector<StructNode>)` 内部调
|
||||||
`dto::buildStructTree` 重建 `QTreeWidget`(项目根→GS→TM,叶子=TM 可勾选、`UserRole` 存 tmObjectId);
|
`dto::buildStructTree` 重建 `QTreeWidget`(项目根→GS→TM,叶子=TM 可勾选、`UserRole` 存 tmObjectId);
|
||||||
`showMessage(msg)` 显示空/错占位。信号 `tmClicked(QString tmObjectId)` / `tmCheckToggled(...)`
|
`showMessage(msg)` 显示空/错占位。信号 `tmClicked(QString tmObjectId)` / `tmCheckToggled(...)`
|
||||||
(后者为前瞻钩子,本轮无消费者)。
|
(后者为前瞻钩子,本轮无消费者)。
|
||||||
|
|
||||||
**`app/panels/DatasetListPanel`** —— `datasetsLoaded`→`populateDatasetList`(数据:dsName+类型名);`filesLoaded`→`populateFileList`(文件:文件名+可读大小,url 存角色备下载);空时占位。列表去隔行变色,改细分割线。
|
**`app/panels/DatasetListPanel`** —— `datasetsLoaded`→`populateDatasetList`(数据:`dsName / 创建时间 · 类型名`);
|
||||||
|
`filesLoaded`→`populateFileList`(文件:`文件名 / 创建时间 · 可读大小`,url 存角色备下载);空时占位。列表去隔行变色,改细分割线。
|
||||||
|
超过首页 → main 在列表末尾插入「加载更多(已/共)」item(角色 `kDsLoadMoreRole`),点击 → `loadMoreData()`/`loadMoreFiles()` 追加。
|
||||||
|
|
||||||
|
**`app/ProjectListDialog`**(新增 QDialog)—— 项目列表弹窗:顶部 项目名搜索框 + 类型下拉(`listProjectTypes`,含"全部类型") + 搜索/重置;
|
||||||
|
中部 8 列表格(序号/项目名称/项目编号/项目状态/项目类型/业主单位/负责人/创建时间);底部 上/下一页 + "共 N 条 第 x/y 页"。
|
||||||
|
持有 `IProjectRepository&` 自行分页(`pageProjects`,每页 20);状态列 1=未开始/2=进行中(其余数字)。点项目名列 → emit `projectChosen(id,name)` + `accept()`。
|
||||||
|
由 `TopBar::allProjectsRequested` 触发,main 创建并 `exec()`;选中 → `nav.switchProject(id)` + `TopBar::setProjectButtonText(name)`。
|
||||||
|
|
||||||
**中央/详情**:移除"启动自动渲染本地 demo";DS 点击 → 详情面板与中央视图显示占位文案
|
**中央/详情**:移除"启动自动渲染本地 demo";DS 点击 → 详情面板与中央视图显示占位文案
|
||||||
"该数据集渲染将在下一阶段接入 dd 接口"。渲染代码保留。
|
"该数据集渲染将在下一阶段接入 dd 接口"。渲染代码保留。
|
||||||
|
|
@ -228,8 +255,12 @@ private:
|
||||||
切项目: TopBar.projectSwitchRequested(id)
|
切项目: TopBar.projectSwitchRequested(id)
|
||||||
→ controller.switchProject: loadStructure(id) → emit structureLoaded;清空 DS 列表/详情占位
|
→ controller.switchProject: loadStructure(id) → emit structureLoaded;清空 DS 列表/详情占位
|
||||||
|
|
||||||
|
全部项目: TopBar.allProjectsRequested → main 打开 ProjectListDialog(pageProjects 分页 + 名称/类型过滤)
|
||||||
|
→ 点项目名 → projectChosen(id,name) → nav.switchProject(id) + TopBar.setProjectButtonText(name) → 关弹窗
|
||||||
|
|
||||||
选 TM: ObjectTreePanel.tmClicked(tmObjectId)
|
选 TM: ObjectTreePanel.tmClicked(tmObjectId)
|
||||||
→ controller.selectTm: loadTmRows(pid,tm,3)+loadTmRows(pid,tm,1) → emit datasetsLoaded + filesLoaded → 数据/文件页签
|
→ controller.selectTm: loadTmRows(pid,tm,3,1)+loadTmRows(pid,tm,1,1) → emit datasetsLoaded/filesLoaded(total,append=false) → 数据/文件页签
|
||||||
|
加载更多: 点列表末尾"加载更多" → controller.loadMoreData/Files → emit …(total,append=true) → 追加
|
||||||
|
|
||||||
点 DS: DatasetListPanel → 中央/详情显示占位"待接入"(本轮不渲染真实数据)
|
点 DS: DatasetListPanel → 中央/详情显示占位"待接入"(本轮不渲染真实数据)
|
||||||
```
|
```
|
||||||
|
|
@ -306,6 +337,7 @@ void rebuildCentralScene(geopro::render::Scene& scene, vtkRenderer* renderer,
|
||||||
- `src/controller/WorkbenchNavController.{hpp,cpp}`
|
- `src/controller/WorkbenchNavController.{hpp,cpp}`
|
||||||
- `src/app/panels/ObjectTreePanel.{hpp,cpp}`(若不抽,则树构建函数留在 main,但 TopBar 必抽)
|
- `src/app/panels/ObjectTreePanel.{hpp,cpp}`(若不抽,则树构建函数留在 main,但 TopBar 必抽)
|
||||||
- `src/app/CentralScene.{hpp,cpp}`(中央三维编排的数据驱动 helper,见 §8.1)
|
- `src/app/CentralScene.{hpp,cpp}`(中央三维编排的数据驱动 helper,见 §8.1)
|
||||||
|
- `src/app/ProjectListDialog.{hpp,cpp}`(项目列表弹窗,见 §5.5)
|
||||||
- 测试:`tests/data/test_nav_dto.cpp`(NavDto 映射 + buildStructTree)
|
- 测试:`tests/data/test_nav_dto.cpp`(NavDto 映射 + buildStructTree)
|
||||||
|
|
||||||
**改造**
|
**改造**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue