diff --git a/src/data/api/ApiProjectRepository.cpp b/src/data/api/ApiProjectRepository.cpp index 1bd7b14..193863b 100644 --- a/src/data/api/ApiProjectRepository.cpp +++ b/src/data/api/ApiProjectRepository.cpp @@ -6,6 +6,8 @@ #include #include "ApiClient.hpp" +#include "api/NavLoads.hpp" +#include "api/NavRequest.hpp" #include "dto/NavDto.hpp" namespace geopro::data { @@ -15,6 +17,9 @@ constexpr int kCodeSuccess = 200; bool ok(const net::ApiResponse& r) { return r.code == kCodeSuccess; } +// 异步失败谓词(与同步 ok() 同口径:业务码非 200 或网络错误)。 +bool isFailureA(const net::ApiResponse& r) { return r.code != kCodeSuccess || !r.rawError.isEmpty(); } + std::string errorOf(const net::ApiResponse& r, const char* fallback) { if (!r.msg.isEmpty()) return r.msg.toStdString(); if (!r.rawError.isEmpty()) return r.rawError.toStdString(); @@ -119,4 +124,100 @@ RepoResult> ApiProjectRepository::loadExceptionsByTm( return {true, dto::parseExceptions(r.data.value(QStringLiteral("value")).toArray()), {}}; } +// ── 异步实现(薄封装:endpoint/body/parse 与同步版逐一对齐;解析器在 try 内见 ApiNavRequest)── + +NavRequest* ApiProjectRepository::listWorkspacesAsync() { + auto* call = api_.getAsync(QStringLiteral("/business/system/tenant/enterprise/joined/list")); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseWorkspaces(r.data.value(QStringLiteral("value")).toArray())); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::switchWorkspaceAsync(const std::string& tenantId) { + const QString path = + QStringLiteral("/business/system/tenant/enterprise/switch/%1").arg(enc(tenantId)); + auto* call = api_.postJsonAsync(path, QJsonObject{}); + // 切换空间返回新 accessToken:必须重新注入(与同步版一致),后续请求才落到新空间。 + return new ApiNavRequest(call, [this](const net::ApiResponse& r) { + const QString token = r.data.value(QStringLiteral("accessToken")).toString(); + if (!token.isEmpty()) api_.setToken(token); + return QVariant::fromValue(true); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::pageProjectsAsync(const std::string& nameFilter, + const std::string& typeId, int pageNo, + int pageSize) { + QJsonObject body{{QStringLiteral("projectName"), QString::fromStdString(nameFilter)}, + {QStringLiteral("pageNo"), pageNo}, + {QStringLiteral("pageSize"), pageSize}}; + if (!typeId.empty()) body[QStringLiteral("projectTypeId")] = QString::fromStdString(typeId); + auto* call = api_.postJsonAsync(QStringLiteral("/business/my/profile/project/page"), body); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseProjectPage(r.data)); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::listProjectTypesAsync() { + auto* call = api_.getAsync(QStringLiteral("/business/project/type/list")); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseProjectTypes(r.data.value(QStringLiteral("value")).toArray())); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::loadStructureAsync(const std::string& projectId) { + const QString path = + QStringLiteral("/business/projectStruct/queryProjectStruct/%1").arg(enc(projectId)); + auto* call = api_.getAsync(path); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseStructNodes(r.data.value(QStringLiteral("value")).toArray())); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::loadRowsAsync(const std::string& projectId, + const std::string& parentId, int parentConfType, + int classifyType, int pageNo) { + const QString path = (classifyType == 1) ? QStringLiteral("/business/dsObject/file/page") + : QStringLiteral("/business/dsObject/data/page"); + const QJsonObject body{ + {QStringLiteral("projectId"), QString::fromStdString(projectId)}, + {QStringLiteral("structParentId"), QString::fromStdString(parentId)}, + {QStringLiteral("structParentConfType"), parentConfType}, + {QStringLiteral("classifyTypeList"), QJsonArray{classifyType}}, + {QStringLiteral("pageNo"), pageNo}, + {QStringLiteral("pageSize"), 5}}; + auto* call = api_.postJsonAsync(path, body); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseDsPage(r.data)); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::loadObjectDetailAsync(const std::string& objectId, int confType) { + const QString path = + (confType == 1) + ? QStringLiteral("/business/gsObject/getGsObjectDetail/%1").arg(enc(objectId)) + : QStringLiteral("/business/tmObject/getDetail/%1").arg(enc(objectId)); + auto* call = api_.getAsync(path); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseDynamicForm(r.data)); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::loadDatasetFormAsync(const std::string& dsObjectId) { + const QString path = QStringLiteral("/business/dsObject/dynamicForm/%1").arg(enc(dsObjectId)); + auto* call = api_.getAsync(path); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseDynamicForm(r.data)); + }, &isFailureA); +} + +NavRequest* ApiProjectRepository::loadExceptionsByTmAsync(const std::string& tmObjectId) { + const QString path = + QStringLiteral("/business/exception/queryExceptionByTmObjectId/%1").arg(enc(tmObjectId)); + auto* call = api_.getAsync(path); + return new ApiNavRequest(call, [](const net::ApiResponse& r) { + return QVariant::fromValue(dto::parseExceptions(r.data.value(QStringLiteral("value")).toArray())); + }, &isFailureA); +} + } // namespace geopro::data diff --git a/src/data/api/ApiProjectRepository.hpp b/src/data/api/ApiProjectRepository.hpp index dd27b4b..1845e00 100644 --- a/src/data/api/ApiProjectRepository.hpp +++ b/src/data/api/ApiProjectRepository.hpp @@ -1,15 +1,20 @@ #pragma once #include "repo/IProjectRepository.hpp" +#include "repo/IAsyncProjectRepository.hpp" namespace geopro::net { class ApiClient; } namespace geopro::data { -// 用共享会话 ApiClient 实现导航仓储(同步阻塞)。token 由调用方注入 ApiClient。 -class ApiProjectRepository : public IProjectRepository { +class NavRequest; + +// 用共享会话 ApiClient 实现导航仓储。过渡期同时实现同步(旧)+异步(新)两接口。 +// token 由调用方注入 ApiClient。 +class ApiProjectRepository : public IProjectRepository, public IAsyncProjectRepository { public: explicit ApiProjectRepository(net::ApiClient& api); + // ── 同步(旧,A6 删除) ── RepoResult> listWorkspaces() override; RepoResult switchWorkspace(const std::string& tenantId) override; RepoResult pageProjects(const std::string& nameFilter, const std::string& typeId, @@ -22,6 +27,19 @@ public: RepoResult loadDatasetForm(const std::string& dsObjectId) override; RepoResult> loadExceptionsByTm(const std::string& tmObjectId) override; + // ── 异步(新) ── 返回 NavRequest*(薄封装,一方法一请求)。 + NavRequest* listWorkspacesAsync() override; + NavRequest* switchWorkspaceAsync(const std::string& tenantId) override; + NavRequest* pageProjectsAsync(const std::string& nameFilter, const std::string& typeId, + int pageNo, int pageSize) override; + NavRequest* listProjectTypesAsync() override; + NavRequest* loadStructureAsync(const std::string& projectId) override; + NavRequest* loadRowsAsync(const std::string& projectId, const std::string& parentId, + int parentConfType, int classifyType, int pageNo) override; + NavRequest* loadObjectDetailAsync(const std::string& objectId, int confType) override; + NavRequest* loadDatasetFormAsync(const std::string& dsObjectId) override; + NavRequest* loadExceptionsByTmAsync(const std::string& tmObjectId) override; + private: net::ApiClient& api_; };