From f4ca9bcd38d6b8cb0cb92d6d799641037383b547 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Tue, 9 Jun 2026 11:44:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(controller):=20WorkbenchNavController=20?= =?UTF-8?q?=E5=AF=BC=E8=88=AA=E7=8A=B6=E6=80=81=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 1 + src/controller/CMakeLists.txt | 7 ++ src/controller/WorkbenchNavController.cpp | 108 ++++++++++++++++++++++ src/controller/WorkbenchNavController.hpp | 42 +++++++++ 4 files changed, 158 insertions(+) create mode 100644 src/controller/CMakeLists.txt create mode 100644 src/controller/WorkbenchNavController.cpp create mode 100644 src/controller/WorkbenchNavController.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf87a09..46b32b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,4 +12,5 @@ add_subdirectory(core) add_subdirectory(data) add_subdirectory(net) add_subdirectory(render) +add_subdirectory(controller) add_subdirectory(app) diff --git a/src/controller/CMakeLists.txt b/src/controller/CMakeLists.txt new file mode 100644 index 0000000..45f34d7 --- /dev/null +++ b/src/controller/CMakeLists.txt @@ -0,0 +1,7 @@ +find_package(Qt6 COMPONENTS Core REQUIRED) +add_library(geopro_controller STATIC + WorkbenchNavController.cpp) +target_include_directories(geopro_controller PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(geopro_controller PUBLIC geopro_data Qt6::Core) +target_compile_features(geopro_controller PUBLIC cxx_std_17) +set_target_properties(geopro_controller PROPERTIES AUTOMOC ON AUTOUIC OFF AUTORCC OFF) diff --git a/src/controller/WorkbenchNavController.cpp b/src/controller/WorkbenchNavController.cpp new file mode 100644 index 0000000..4783d07 --- /dev/null +++ b/src/controller/WorkbenchNavController.cpp @@ -0,0 +1,108 @@ +#include "WorkbenchNavController.hpp" + +namespace geopro::controller { + +using data::ProjectSummary; +using data::Workspace; + +WorkbenchNavController::WorkbenchNavController(data::IProjectRepository& repo, QObject* parent) + : QObject(parent), repo_(repo) {} + +void WorkbenchNavController::start() { + emit busyChanged(true); + const auto ws = repo_.listWorkspaces(); + if (!ws.ok) { + emit busyChanged(false); + emit loadFailed(QStringLiteral("workspaces"), QString::fromStdString(ws.error)); + return; + } + QString cur; + for (const auto& w : ws.value) + if (w.isCurrent) cur = QString::fromStdString(w.id); + if (cur.isEmpty() && !ws.value.empty()) cur = QString::fromStdString(ws.value.front().id); + currentWorkspaceId_ = cur.toStdString(); + emit workspacesLoaded(ws.value, cur); + + loadProjectsAndStructure(); + emit busyChanged(false); +} + +void WorkbenchNavController::loadProjectsAndStructure() { + const auto ps = repo_.listProjects(std::string()); + if (!ps.ok) { + emit loadFailed(QStringLiteral("projects"), QString::fromStdString(ps.error)); + return; + } + lastProjects_ = ps.value; + QString curP; + if (!ps.value.empty()) { + const auto& first = ps.value.front(); + curP = QString::fromStdString(first.id); + currentProjectId_ = first.id; + currentProjectName_ = first.name; + currentCrsCode_ = first.crsCode; + } else { + currentProjectId_.clear(); + currentProjectName_.clear(); + currentCrsCode_.clear(); + } + emit projectsLoaded(ps.value, curP); + + if (curP.isEmpty()) { + emit structureLoaded(QString(), {}); // 暂无项目 → 空树 + return; + } + const auto st = repo_.loadStructure(currentProjectId_); + if (!st.ok) { + emit loadFailed(QStringLiteral("structure"), QString::fromStdString(st.error)); + return; + } + emit structureLoaded(QString::fromStdString(currentProjectName_), st.value); +} + +void WorkbenchNavController::switchWorkspace(const QString& tenantId) { + if (tenantId.isEmpty()) return; + emit busyChanged(true); + const auto r = repo_.switchWorkspace(tenantId.toStdString()); + if (!r.ok) { + emit busyChanged(false); + emit loadFailed(QStringLiteral("switchWorkspace"), QString::fromStdString(r.error)); + return; + } + currentWorkspaceId_ = tenantId.toStdString(); + loadProjectsAndStructure(); + emit busyChanged(false); +} + +void WorkbenchNavController::switchProject(const QString& projectId) { + if (projectId.isEmpty()) return; + emit busyChanged(true); + currentProjectId_ = projectId.toStdString(); + for (const auto& p : lastProjects_) + if (p.id == currentProjectId_) { + currentProjectName_ = p.name; + currentCrsCode_ = p.crsCode; + } + const auto st = repo_.loadStructure(currentProjectId_); + if (!st.ok) { + emit busyChanged(false); + emit loadFailed(QStringLiteral("structure"), QString::fromStdString(st.error)); + return; + } + emit structureLoaded(QString::fromStdString(currentProjectName_), st.value); + emit busyChanged(false); +} + +void WorkbenchNavController::selectTm(const QString& tmObjectId) { + if (tmObjectId.isEmpty()) return; + emit busyChanged(true); + const auto ds = repo_.loadDatasetsOfTm(tmObjectId.toStdString()); + emit busyChanged(false); + if (!ds.ok) { + emit loadFailed(QStringLiteral("datasets"), QString::fromStdString(ds.error)); + return; + } + emit datasetsLoaded(tmObjectId, ds.value); +} + +} // namespace geopro::controller diff --git a/src/controller/WorkbenchNavController.hpp b/src/controller/WorkbenchNavController.hpp new file mode 100644 index 0000000..c96d7d1 --- /dev/null +++ b/src/controller/WorkbenchNavController.hpp @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include +#include + +#include "repo/IProjectRepository.hpp" + +namespace geopro::controller { + +// 导航状态机:编排 IProjectRepository,持有当前 空间/项目 状态,经信号驱动 UI。不持有 widget。 +class WorkbenchNavController : public QObject { + Q_OBJECT +public: + explicit WorkbenchNavController(data::IProjectRepository& repo, QObject* parent = nullptr); + + void start(); // 启动:拉空间 → 项目 → 结构 + + QString currentCrsCode() const { return QString::fromStdString(currentCrsCode_); } + +public slots: + void switchWorkspace(const QString& tenantId); + void switchProject(const QString& projectId); + void selectTm(const QString& tmObjectId); + +signals: + void busyChanged(bool busy); + void workspacesLoaded(const std::vector& list, const QString& currentId); + void projectsLoaded(const std::vector& list, const QString& currentId); + void structureLoaded(const QString& projectName, const std::vector& nodes); + void datasetsLoaded(const QString& tmObjectId, const std::vector& list); + void loadFailed(const QString& stage, const QString& message); + +private: + void loadProjectsAndStructure(); // start + switchWorkspace 共用 + + data::IProjectRepository& repo_; + std::vector lastProjects_; + std::string currentWorkspaceId_, currentProjectId_, currentProjectName_, currentCrsCode_; +}; + +} // namespace geopro::controller