445 lines
21 KiB
C++
445 lines
21 KiB
C++
#include "api/ApiDatasetCommandRepository.hpp"
|
||
|
||
#include <utility>
|
||
|
||
#include <QUrl>
|
||
|
||
#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<void(bool, QString)> 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<void(bool, QJsonArray, QString)> 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": "<string>"},故取 data.value。
|
||
void wireString(net::IApiCall* call, std::function<void(bool, QString, QString)> 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<void(bool, QJsonObject, QString)> 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<void(bool, QJsonArray, QString)> 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<void(bool, QJsonObject, QString)> 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<void(bool, QString)> 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<void(bool, QString)> 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<void(bool, QString)> 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<void(bool, QJsonObject, QString)> 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<void(bool, QString)> cb) {
|
||
wireStatus(api_.postJsonAsync(QStringLiteral("/business/scatterPlotDataFilter"), body),
|
||
std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::saveRawData(const QJsonObject& body,
|
||
std::function<void(bool, QString)> 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<void(bool, QString, QString, QString)> 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<void(bool, geopro::core::ScatterPayload, QString)> cb) {
|
||
// 并发拉 scatter/graph(带 vFieldCode) + 色阶 getDetail(type3, businessCode=vFieldCode)。
|
||
// 与 ApiDatasetRepository::measurementScatterBatch 同端点/同解析(仅 vFieldCode 可变)。
|
||
QList<net::IApiCall*> 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<net::ApiResponse>& 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<void(bool, QString)> cb) {
|
||
wireStatus(api_.postJsonAsync(QStringLiteral("/business/lvl/colorGradation"), body),
|
||
std::move(cb));
|
||
}
|
||
|
||
// ============================ inversion 相关 ============================
|
||
|
||
void ApiDatasetCommandRepository::saveInversionAsData(const QString& dsObjectId,
|
||
const QString& name,
|
||
std::function<void(bool, QString)> 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<void(bool, geopro::core::ContourPayload, QString)> cb) {
|
||
// 与 ApiDatasetRepository::inversionGridBatch 同端点/同解析:rows(慢) + 色阶 type2 + 异常。
|
||
QList<net::IApiCall*> 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<net::ApiResponse>& 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<void(bool, QJsonArray, QString)> 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<void(bool, QJsonObject, QString)> 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<void(bool, QString)> 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<void(bool, QJsonArray, QString)> 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<void(bool, QString)> cb) {
|
||
wireStatus(api_.postJsonAsync(QStringLiteral("/business/dd/ert/inversion/whitenedData"), body),
|
||
std::move(cb));
|
||
}
|
||
|
||
// ============================ 滤波相关 ============================
|
||
|
||
void ApiDatasetCommandRepository::listFilters(std::function<void(bool, QJsonArray, QString)> cb) {
|
||
wireArray(api_.getAsync(QStringLiteral("/business/filter/queryFilter")), std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::newFilter(const QJsonObject& body,
|
||
std::function<void(bool, QString)> cb) {
|
||
wireStatus(api_.postJsonAsync(QStringLiteral("/business/filter"), body), std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::deleteFilter(const QString& id,
|
||
std::function<void(bool, QString)> cb) {
|
||
wireStatus(api_.deleteAsync(QStringLiteral("/business/filter/delete/%1").arg(enc(id))),
|
||
std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::applyFilter(const QJsonObject& body,
|
||
std::function<void(bool, QString)> 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<void(bool, QJsonArray, QString)> 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<void(bool, QString, QString)> 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<void(bool, QString)> cb) {
|
||
wireStatus(api_.postJsonAsync(QStringLiteral("/business/exception"), body), std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::deleteException(const QString& id,
|
||
std::function<void(bool, QString)> cb) {
|
||
wireStatus(api_.deleteAsync(QStringLiteral("/business/exception/%1").arg(enc(id))),
|
||
std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::updateException(const QJsonObject& body,
|
||
std::function<void(bool, QString)> cb) {
|
||
wireStatus(api_.putJsonAsync(QStringLiteral("/business/exception"), body), std::move(cb));
|
||
}
|
||
|
||
// ============================ 自动标注 ============================
|
||
|
||
void ApiDatasetCommandRepository::executeExceptionMark(
|
||
const QJsonObject& body, std::function<void(bool, QJsonObject, QString)> cb) {
|
||
wireObject(
|
||
api_.postJsonAsync(QStringLiteral("/business/exception/exception-mark/execute"), body),
|
||
std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::batchCreateException(const QJsonObject& body,
|
||
std::function<void(bool, QString)> cb) {
|
||
wireStatus(api_.postJsonAsync(QStringLiteral("/business/exception/batch/create"), body),
|
||
std::move(cb));
|
||
}
|
||
|
||
// ============================ 描述 / dsObject ============================
|
||
|
||
void ApiDatasetCommandRepository::getDsObjectDetail(
|
||
const QString& dsObjectId, std::function<void(bool, QJsonObject, QString)> cb) {
|
||
wireObject(
|
||
api_.getAsync(QStringLiteral("/business/dsObject/getDetail/%1").arg(enc(dsObjectId))),
|
||
std::move(cb));
|
||
}
|
||
|
||
void ApiDatasetCommandRepository::updateDsObject(const QJsonObject& body,
|
||
std::function<void(bool, QString)> cb) {
|
||
// 原版 URL 末尾带斜杠(updateProfileInversionDescription)。
|
||
wireStatus(api_.putJsonAsync(QStringLiteral("/business/dsObject/updateDsObject/"), body),
|
||
std::move(cb));
|
||
}
|
||
|
||
} // namespace geopro::data
|