#include "api/ApiDatasetCommandRepository.hpp" #include #include #include "ApiBatch.hpp" #include "ApiClient.hpp" #include "IApiCall.hpp" #include "dto/MeasurementDto.hpp" // parseMeasurementScatter(V 值重载复用初始加载解析) #include "dto/DatasetChartDto.hpp" // parseInversionGrid/parseColorBar/parseDatasetAnomalies(网格重载) namespace geopro::data { namespace { // 失败判定与色阶/详情仓储一致:业务码 != 200 或传输错误(rawError 非空)。 bool isOk(const net::ApiResponse& r) { return r.code == 200 && r.rawError.isEmpty(); } // URL 路径段编码(动态 id),与现有 enc 用法一致。 QString enc(const QString& s) { return QString::fromUtf8(QUrl::toPercentEncoding(s)); } // 三类回调骨架:统一「句柄判空 → connect → finished 取值」,消除样板重复。 // 仅状态:(bool ok, QString msg)。 void wireStatus(net::IApiCall* call, std::function cb) { if (call == nullptr) { if (cb) cb(false, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (cb) cb(isOk(resp), resp.msg); }); } // 返回数组:(bool ok, QJsonArray list, QString msg)。顶层数组被 buildResponse 包成 data.value。 void wireArray(net::IApiCall* call, std::function cb) { if (call == nullptr) { if (cb) cb(false, {}, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (!cb) return; if (!isOk(resp)) { cb(false, {}, resp.msg); return; } cb(true, resp.data.value(QStringLiteral("value")).toArray(), resp.msg); }); } // 返回字符串:(bool ok, QString value, QString msg)。 // 原版 res.data 为纯字符串时,parseBody 会包成 {"value": ""},故取 data.value。 void wireString(net::IApiCall* call, std::function cb) { if (call == nullptr) { if (cb) cb(false, {}, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (!cb) return; if (!isOk(resp)) { cb(false, {}, resp.msg); return; } cb(true, resp.data.value(QStringLiteral("value")).toString(), resp.msg); }); } // 返回对象:(bool ok, QJsonObject data, QString msg)。 void wireObject(net::IApiCall* call, std::function cb) { if (call == nullptr) { if (cb) cb(false, {}, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (!cb) return; if (!isOk(resp)) { cb(false, {}, resp.msg); return; } cb(true, resp.data, resp.msg); }); } } // namespace ApiDatasetCommandRepository::ApiDatasetCommandRepository(net::ApiClient& api) : api_(api) {} void ApiDatasetCommandRepository::listInversionScripts( const QString& dsObjectId, std::function cb) { auto* call = api_.getAsync( QStringLiteral("/business/outerInversion/query/script?dsObjectId=%1") .arg(QString::fromUtf8(QUrl::toPercentEncoding(dsObjectId)))); if (call == nullptr) { if (cb) cb(false, {}, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (!cb) return; if (!isOk(resp)) { cb(false, {}, resp.msg); return; } // 模型列表:data 顶层为数组,buildResponse 包成 {"value": [...]}。 cb(true, resp.data.value(QStringLiteral("value")).toArray(), resp.msg); }); } void ApiDatasetCommandRepository::getDynamicForm( const QString& projectId, const QString& typeId, std::function cb) { QJsonObject body{{QStringLiteral("projectId"), projectId}, {QStringLiteral("type"), 6}, {QStringLiteral("typeId"), typeId}}; auto* call = api_.postJsonAsync(QStringLiteral("/business/project/getDynamicForm"), body); if (call == nullptr) { if (cb) cb(false, {}, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (!cb) return; if (!isOk(resp)) { cb(false, {}, resp.msg); return; } // 动态表单:data 为对象(含 formList 数组)。 cb(true, resp.data, resp.msg); }); } void ApiDatasetCommandRepository::submitInversionTask(const QString& dsId, const QString& scriptId, const QJsonObject& properties, std::function cb) { QJsonObject body{{QStringLiteral("dsId"), dsId}, {QStringLiteral("scriptId"), scriptId}, {QStringLiteral("properties"), properties}}; auto* call = api_.postJsonAsync(QStringLiteral("/business/outerInversion/submitInversionTask"), body); if (call == nullptr) { if (cb) cb(false, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (cb) cb(isOk(resp), resp.msg); }); } void ApiDatasetCommandRepository::createVisualResistivityData( const QString& dsObjectId, const QString& scriptId, const QJsonObject& scriptParamListJsonStr, std::function cb) { QJsonObject body{{QStringLiteral("dsObjectId"), dsObjectId}, {QStringLiteral("scriptId"), scriptId}, {QStringLiteral("scriptParamListJsonStr"), scriptParamListJsonStr}}; auto* call = api_.postJsonAsync( QStringLiteral("/business/dd/ert/measurement/createVisualResistivityData"), body); if (call == nullptr) { if (cb) cb(false, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (cb) cb(isOk(resp), resp.msg); }); } // ============================ measurement 散点相关 ============================ void ApiDatasetCommandRepository::saveDisplayStatus(const QString& dsObjectId, const QJsonArray& ids, int status, std::function cb) { QJsonObject body{{QStringLiteral("dsObjectId"), dsObjectId}, {QStringLiteral("ids"), ids}, {QStringLiteral("status"), status}}; wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/measurement/saveDisplayStatus"), body), std::move(cb)); } void ApiDatasetCommandRepository::getScatterFilterConfig( const QString& dsObjectId, const QString& vFieldCode, std::function cb) { wireObject( api_.getAsync(QStringLiteral( "/business/scatterPlotDataFilter/getDataFilterConfig?dsObjectId=%1&vFieldCode=%2") .arg(enc(dsObjectId), enc(vFieldCode))), std::move(cb)); } void ApiDatasetCommandRepository::applyScatterFilter(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/scatterPlotDataFilter"), body), std::move(cb)); } void ApiDatasetCommandRepository::saveRawData(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/measurement/saveRawData"), body), std::move(cb)); } void ApiDatasetCommandRepository::exportMeasurementDat( const QString& dsId, int electrodePosition, int ipDataMark, int typeMeasurement, std::function cb) { auto* call = api_.getAsync( QStringLiteral("/business/dd/ert/measurement/rs2d/" "export?dsId=%1&electrodePosition=%2&ipDataMark=%3&typeMeasurement=%4") .arg(enc(dsId)) .arg(electrodePosition) .arg(ipDataMark) .arg(typeMeasurement)); if (call == nullptr) { if (cb) cb(false, {}, {}, QStringLiteral("请求创建失败")); return; } QObject::connect(call, &net::IApiCall::finished, call, [cb = std::move(cb)](const net::ApiResponse& resp) { if (!cb) return; if (!isOk(resp)) { cb(false, {}, {}, resp.msg); return; } // 导出:data 含 base64 fileData 与 fileName,落盘交由 UI 层。 cb(true, resp.data.value(QStringLiteral("fileName")).toString(), resp.data.value(QStringLiteral("fileData")).toString(), resp.msg); }); } void ApiDatasetCommandRepository::loadMeasurementScatter( const QString& dsObjectId, const QString& vFieldCode, std::function cb) { // 并发拉 scatter/graph(带 vFieldCode) + 色阶 getDetail(type3, businessCode=vFieldCode)。 // 与 ApiDatasetRepository::measurementScatterBatch 同端点/同解析(仅 vFieldCode 可变)。 QList calls{ api_.getAsync( QStringLiteral("/business/dd/ert/measurement/scatter/graph?dsObjectId=%1&vFieldCode=%2") .arg(enc(dsObjectId), enc(vFieldCode))), api_.postJsonAsync(QStringLiteral("/business/lvl/colorGradation/getDetail"), QJsonObject{{QStringLiteral("dsObjectId"), dsObjectId}, {QStringLiteral("businessCode"), vFieldCode}, {QStringLiteral("type"), 3}}), }; auto* batch = new net::ApiBatch(calls, [](const net::ApiResponse& r) { return r.code != 200 || !r.rawError.isEmpty(); }); QObject::connect(batch, &net::ApiBatch::succeeded, batch, [cb](const QList& r) { if (cb) cb(true, dto::parseMeasurementScatter(r[0].data, r[1].data), {}); }); QObject::connect(batch, &net::ApiBatch::failed, batch, [cb](int, const net::ApiResponse& resp) { if (cb) cb(false, {}, resp.msg); }); // ApiBatch 完成/失败后各 call 自行 deleteLater;batch 本身随末次信号后 deleteLater。 QObject::connect(batch, &net::ApiBatch::succeeded, batch, &QObject::deleteLater); QObject::connect(batch, &net::ApiBatch::failed, batch, &QObject::deleteLater); } // ============================ 色阶(lvl)相关 ============================ void ApiDatasetCommandRepository::saveColorGradation(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/lvl/colorGradation"), body), std::move(cb)); } // ============================ inversion 相关 ============================ void ApiDatasetCommandRepository::saveInversionAsData(const QString& dsObjectId, const QString& name, std::function cb) { QJsonObject body{{QStringLiteral("dsObjectId"), dsObjectId}, {QStringLiteral("name"), name}}; wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/inversion/saveAsData"), body), std::move(cb)); } void ApiDatasetCommandRepository::loadInversionGrid( const QString& dsObjectId, std::function cb) { // 与 ApiDatasetRepository::inversionGridBatch 同端点/同解析:rows(慢) + 色阶 type2 + 异常。 QList calls{ api_.getAsync(QStringLiteral("/business/dd/ert/inversion/rows/%1").arg(enc(dsObjectId))), api_.postJsonAsync(QStringLiteral("/business/lvl/colorGradation/getDetail"), QJsonObject{{QStringLiteral("dsObjectId"), dsObjectId}, {QStringLiteral("businessCode"), QString()}, {QStringLiteral("type"), 2}}), api_.getAsync( QStringLiteral("/business/exception/queryException/%1").arg(enc(dsObjectId))), }; auto* batch = new net::ApiBatch(calls, [](const net::ApiResponse& r) { return r.code != 200 || !r.rawError.isEmpty(); }); QObject::connect(batch, &net::ApiBatch::succeeded, batch, [cb](const QList& r) { if (!cb) return; geopro::core::ContourPayload p{ dto::parseInversionGrid(r[0].data), dto::parseColorBar(r[1].data), dto::parseDatasetAnomalies( r[2].data.value(QStringLiteral("value")).toArray())}; cb(true, p, {}); }); QObject::connect(batch, &net::ApiBatch::failed, batch, [cb](int, const net::ApiResponse& resp) { if (cb) cb(false, {}, resp.msg); }); QObject::connect(batch, &net::ApiBatch::succeeded, batch, &QObject::deleteLater); QObject::connect(batch, &net::ApiBatch::failed, batch, &QObject::deleteLater); } void ApiDatasetCommandRepository::listGridAlgorithm( const QString& dsObjectId, std::function cb) { wireArray(api_.getAsync(QStringLiteral("/business/dd/ert/inversion/queryAlgorithmModel/%1") .arg(enc(dsObjectId))), std::move(cb)); } void ApiDatasetCommandRepository::getGridRawDataParams( const QString& dsObjectId, std::function cb) { wireObject(api_.getAsync(QStringLiteral("/business/dd/ert/inversion/getRawData/%1") .arg(enc(dsObjectId))), std::move(cb)); } void ApiDatasetCommandRepository::toGrid(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/inversion/grid"), body), std::move(cb)); } // ============================ 白化相关 ============================ void ApiDatasetCommandRepository::listWhitenedData( const QString& projectId, const QString& tmObjectId, std::function cb) { QJsonObject body{{QStringLiteral("projectId"), projectId}, {QStringLiteral("tmObjectId"), tmObjectId}}; wireArray(api_.postJsonAsync(QStringLiteral("/business/dsObject/queryWhitenedDataList"), body), std::move(cb)); } void ApiDatasetCommandRepository::whitenData(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/inversion/whitenedData"), body), std::move(cb)); } // ============================ 滤波相关 ============================ void ApiDatasetCommandRepository::listFilters(std::function cb) { wireArray(api_.getAsync(QStringLiteral("/business/filter/queryFilter")), std::move(cb)); } void ApiDatasetCommandRepository::newFilter(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/filter"), body), std::move(cb)); } void ApiDatasetCommandRepository::deleteFilter(const QString& id, std::function cb) { wireStatus(api_.deleteAsync(QStringLiteral("/business/filter/delete/%1").arg(enc(id))), std::move(cb)); } void ApiDatasetCommandRepository::applyFilter(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/inversion/filterData"), body), std::move(cb)); } // ============================ 异常 CRUD ============================ void ApiDatasetCommandRepository::listExceptionTypes( const QString& projectId, const QString& remarkSourceType, std::function cb) { wireArray(api_.getAsync( QStringLiteral( "/business/exceptionType/queryExceptionTypeByProjectIdAndType/%1/%2") .arg(enc(projectId), enc(remarkSourceType))), std::move(cb)); } void ApiDatasetCommandRepository::getExceptionName( const QString& exceptionTypeId, const QString& remarkSourceId, std::function cb) { QJsonObject body{{QStringLiteral("exceptionTypeId"), exceptionTypeId}, {QStringLiteral("remarkSourceId"), remarkSourceId}}; // 原版 res.data 直接是名称字符串,回传纯字符串。 wireString(api_.postJsonAsync(QStringLiteral("/business/exception/getExceptionName"), body), std::move(cb)); } void ApiDatasetCommandRepository::newException(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/exception"), body), std::move(cb)); } void ApiDatasetCommandRepository::deleteException(const QString& id, std::function cb) { wireStatus(api_.deleteAsync(QStringLiteral("/business/exception/%1").arg(enc(id))), std::move(cb)); } void ApiDatasetCommandRepository::updateException(const QJsonObject& body, std::function cb) { wireStatus(api_.putJsonAsync(QStringLiteral("/business/exception"), body), std::move(cb)); } // ============================ 自动标注 ============================ void ApiDatasetCommandRepository::executeExceptionMark( const QJsonObject& body, std::function cb) { wireObject( api_.postJsonAsync(QStringLiteral("/business/exception/exception-mark/execute"), body), std::move(cb)); } void ApiDatasetCommandRepository::batchCreateException(const QJsonObject& body, std::function cb) { wireStatus(api_.postJsonAsync(QStringLiteral("/business/exception/batch/create"), body), std::move(cb)); } // ============================ 描述 / dsObject ============================ void ApiDatasetCommandRepository::getDsObjectDetail( const QString& dsObjectId, std::function cb) { wireObject( api_.getAsync(QStringLiteral("/business/dsObject/getDetail/%1").arg(enc(dsObjectId))), std::move(cb)); } void ApiDatasetCommandRepository::updateDsObject(const QJsonObject& body, std::function cb) { // 原版 URL 末尾带斜杠(updateProfileInversionDescription)。 wireStatus(api_.putJsonAsync(QStringLiteral("/business/dsObject/updateDsObject/"), body), std::move(cb)); } } // namespace geopro::data