diff --git a/src/data/CMakeLists.txt b/src/data/CMakeLists.txt index 57e8a0c..e245aeb 100644 --- a/src/data/CMakeLists.txt +++ b/src/data/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(geopro_data STATIC parse/SampleParsers.cpp repo/LocalSampleRepository.cpp repo/LocalSample3dRepository.cpp + repo/DatasetFieldDictionary.cpp dto/NavDto.cpp dto/Vtk3dRequests.cpp dto/DatasetChartDto.cpp diff --git a/src/data/repo/DatasetFieldDictionary.cpp b/src/data/repo/DatasetFieldDictionary.cpp new file mode 100644 index 0000000..0f76c52 --- /dev/null +++ b/src/data/repo/DatasetFieldDictionary.cpp @@ -0,0 +1,49 @@ +#include "repo/DatasetFieldDictionary.hpp" +#include + +namespace geopro::data { + +DsTypeFields parseFieldMapping(const QJsonObject& d) { + DsTypeFields f; + for (const QJsonValue& gv : d.value(QStringLiteral("formList")).toArray()) { + for (const QJsonValue& vv : gv.toObject().value(QStringLiteral("values")).toArray()) { + const QJsonObject fo = vv.toObject(); + const QString code = fo.value(QStringLiteral("fieldCode")).toString(); + const std::string cfid = fo.value(QStringLiteral("confFieldId")).toString().toStdString(); + if (code == QStringLiteral("arrayType")) { + f.arrayTypeConfFieldId = cfid; + for (const QJsonValue& ov : fo.value(QStringLiteral("optionsObject")).toArray()) { + const QJsonObject oo = ov.toObject(); + f.arrayTypeLabels[oo.value(QStringLiteral("value")).toString().toStdString()] = + oo.value(QStringLiteral("label")).toString().toStdString(); + } + } else if (code == QStringLiteral("collectTime")) { + f.collectTimeConfFieldId = cfid; + } + } + } + return f; +} + +namespace { +std::string propValue(const DsRow& row, const std::string& cfid) { + if (cfid.empty()) return {}; + for (const auto& kv : row.properties) + if (kv.confFieldId == cfid) return kv.value; + return {}; +} +} // namespace + +std::string arrayValueOf(const DsRow& row, const DsTypeFields& f) { + return propValue(row, f.arrayTypeConfFieldId); +} +std::string collectTimeOf(const DsRow& row, const DsTypeFields& f) { + return propValue(row, f.collectTimeConfFieldId); +} + +std::string arrayLabel(const DsTypeFields& f, const std::string& value) { + const auto it = f.arrayTypeLabels.find(value); + return it != f.arrayTypeLabels.end() ? it->second : value; // 缺失回退原值(spec §11) +} + +} // namespace geopro::data diff --git a/src/data/repo/DatasetFieldDictionary.hpp b/src/data/repo/DatasetFieldDictionary.hpp new file mode 100644 index 0000000..b484d47 --- /dev/null +++ b/src/data/repo/DatasetFieldDictionary.hpp @@ -0,0 +1,27 @@ +#pragma once +#include +#include +#include +#include "repo/RepoTypes.hpp" + +namespace geopro::data { + +// 某 dsType 的字段映射(spec §10)。 +struct DsTypeFields { + std::string arrayTypeConfFieldId; // ds 行 properties 里装置类型项的 confFieldId + std::string collectTimeConfFieldId; // 采集时间项的 confFieldId + std::map arrayTypeLabels; // value→中文(来自 optionsObject) +}; + +// 纯函数:从 dsObject/dynamicForm 的 data 解析字段映射(formList → fieldCode==arrayType/collectTime)。 +DsTypeFields parseFieldMapping(const QJsonObject& dynamicFormData); + +// ds 行的装置类型原始值:properties 中 confFieldId==arrayTypeConfFieldId 的 value(缺=空)。 +std::string arrayValueOf(const DsRow& row, const DsTypeFields& f); +// ds 行的采集时间:properties 中 confFieldId==collectTimeConfFieldId 的 value(缺=空)。 +std::string collectTimeOf(const DsRow& row, const DsTypeFields& f); + +// 装置类型 value→中文:命中 arrayTypeLabels 取中文,否则回退原值(spec §11 字典源待坐实时的安全退路)。 +std::string arrayLabel(const DsTypeFields& f, const std::string& value); + +} // namespace geopro::data diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0a5198d..506f233 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -43,6 +43,7 @@ target_sources(geopro_tests PRIVATE data/test_local_repo.cpp) target_sources(geopro_tests PRIVATE data/test_3d_repo.cpp) target_sources(geopro_tests PRIVATE data/test_nav_dto.cpp) target_sources(geopro_tests PRIVATE data/test_vtk3d_requests.cpp) +target_sources(geopro_tests PRIVATE data/test_dataset_field_dictionary.cpp) target_sources(geopro_tests PRIVATE data/test_dataset_chart_dto.cpp) target_sources(geopro_tests PRIVATE data/test_measurement_dto.cpp) target_sources(geopro_tests PRIVATE data/test_gr_dto.cpp) diff --git a/tests/data/test_dataset_field_dictionary.cpp b/tests/data/test_dataset_field_dictionary.cpp new file mode 100644 index 0000000..fc800d5 --- /dev/null +++ b/tests/data/test_dataset_field_dictionary.cpp @@ -0,0 +1,48 @@ +#include +#include +#include "repo/DatasetFieldDictionary.hpp" +using namespace geopro::data; + +namespace { +DsTypeFields parse(const char* js) { + return parseFieldMapping(QJsonDocument::fromJson(QByteArray(js)).object()); +} +} // namespace + +TEST(ParseFieldMapping, ExtractsArrayTypeAndCollectTimeConfFieldIds) { + const DsTypeFields f = parse(R"({"formList":[{"groupName":"基本信息","values":[ + {"confFieldId":"f_ct","fieldCode":"collectTime","fieldName":"采集时间","optionsObject":null}, + {"confFieldId":"f_at","fieldCode":"arrayType","fieldName":"装置类型","optionsObject":[ + {"label":"温纳-施伦贝尔排列","value":"v1"},{"label":"全梯度","value":"v2"}]} + ]}]})"); + EXPECT_EQ(f.arrayTypeConfFieldId, "f_at"); + EXPECT_EQ(f.collectTimeConfFieldId, "f_ct"); + ASSERT_EQ(f.arrayTypeLabels.count("v1"), 1u); + EXPECT_EQ(f.arrayTypeLabels.at("v1"), "温纳-施伦贝尔排列"); + EXPECT_EQ(f.arrayTypeLabels.at("v2"), "全梯度"); +} + +TEST(DatasetFieldDictionary, ArrayValueAndCollectTimeFromRow) { + DsTypeFields f; + f.arrayTypeConfFieldId = "f_at"; + f.collectTimeConfFieldId = "f_ct"; + DsRow row; + row.properties = {{"f_at", "v2"}, {"f_ct", "2026-03-25 16:48:57"}, {"other", "x"}}; + EXPECT_EQ(arrayValueOf(row, f), "v2"); + EXPECT_EQ(collectTimeOf(row, f), "2026-03-25 16:48:57"); +} + +TEST(DatasetFieldDictionary, MissingPropReturnsEmpty) { + DsTypeFields f; + f.arrayTypeConfFieldId = "f_at"; + DsRow row; // 无 properties + EXPECT_EQ(arrayValueOf(row, f), ""); +} + +TEST(DatasetFieldDictionary, ArrayLabelHitsAndFallsBackToRawValue) { + DsTypeFields f; + f.arrayTypeLabels = {{"v1", "温纳"}}; + EXPECT_EQ(arrayLabel(f, "v1"), "温纳"); + // spec §11:原始值不在 optionsObject 时回退显示原值(如实测 1429468249448449)。 + EXPECT_EQ(arrayLabel(f, "1429468249448449"), "1429468249448449"); +}