diff --git a/CLAUDE.md b/CLAUDE.md index 490b18d..d1d28b7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,6 +49,15 @@ as a reason to leave it. Surface it, then handle it. (User directive, 2026-06-25 This overrides the "don't fix what isn't broken" bias above *for genuine defects* — it does not license cosmetic refactors or unrequested rewrites. +**Do it yourself — never offload work you can do (User directive, 2026-06-25, binding):** +If you have the tools to do something, DO IT — never tell the user to do it for you. +Read the logs yourself (`%LOCALAPPDATA%/Geomative/Geopro3/logs/geopro_*.log` via Bash/grep), +inspect data/fixtures yourself, build and link yourself (`build.bat app` via PowerShell), +diagnose by adding logging and then reading that log yourself. The ONLY things to ask the +user for are: (a) closing a running app so the exe can relink (LNK1104 — a lock only they can +release), and (b) genuine product decisions. Do not ask the user to read logs, inspect data, +run diagnostics, or interpret output — that is your job. + ## 4. Goal-Driven Execution **Define success criteria. Loop until verified.** diff --git a/src/app/VolumeParamsDialog.cpp b/src/app/VolumeParamsDialog.cpp index 6a881cd..b68f505 100644 --- a/src/app/VolumeParamsDialog.cpp +++ b/src/app/VolumeParamsDialog.cpp @@ -143,13 +143,16 @@ VolumeParamsDialog::VolumeParamsDialog(const QVector& sources, mount_->setModel(model); mount_->setView(view); view->expandAll(); - // 下拉面板加宽:默认只取 combo 宽度+缩进 → 长名被截。按最长节点名的文本宽 + 缩进/箭头/滚动条余量 - // 定最小宽,保证 GS/TM 全名可见(用户反馈被遮住)。 + // 关键:让 combo **自身**按内容加宽(对话框随布局一起变宽)→ popup 宽 = combo 宽,落在对话框内 + // 不外溢;只加宽 popup 而不加宽 combo 会让浮窗比对话框还宽、超出右缘(用户反馈)。 + // 宽度 = 最长节点名文本宽 + 余量(树缩进/展开箭头/滚动条/combo 下拉箭头/内距)。 int maxTextW = 0; const QFontMetrics fm = view->fontMetrics(); for (const auto& n : structure) maxTextW = std::max(maxTextW, fm.horizontalAdvance(QString::fromStdString(n.name))); - view->setMinimumWidth(std::max(geopro::app::scaledPx(260), maxTextW + geopro::app::scaledPx(120))); + const int contentW = std::max(geopro::app::scaledPx(200), maxTextW + geopro::app::scaledPx(80)); + mount_->setMinimumWidth(contentW); // combo 加宽 → 对话框变宽 + view->setMinimumWidth(contentW); // popup 与 combo 同宽 → 不外溢 // 默认选中:指定的 defaultMountId,否则首个节点。view 当前项决定 mountTargetId;combo 显示尽力。 QStandardItem* def = mItems.value(defaultMountId, nullptr); if (!def && model->rowCount() > 0) def = model->item(0); diff --git a/src/data/dto/NavDto.cpp b/src/data/dto/NavDto.cpp index 8b35d69..eca7513 100644 --- a/src/data/dto/NavDto.cpp +++ b/src/data/dto/NavDto.cpp @@ -1,5 +1,7 @@ #include "dto/NavDto.hpp" +#include +#include #include #include #include @@ -116,6 +118,13 @@ std::vector parseStructNodes(const QJsonArray& arr) { std::vector parseDsRows(const QJsonArray& arr) { std::vector out; out.reserve(static_cast(arr.size())); + // 诊断(一次):打印首行原始 JSON,定位装置/采集时间等字段实际所在(properties 形态/attachedParameters)。 + static bool s_loggedRaw = false; + if (!s_loggedRaw && !arr.isEmpty()) { + s_loggedRaw = true; + qInfo().noquote() << "[dsrow-raw]" + << QJsonDocument(arr.first().toObject()).toJson(QJsonDocument::Compact); + } for (const QJsonValue& v : arr) { const QJsonObject o = v.toObject(); DsRow d; @@ -130,15 +139,31 @@ std::vector parseDsRows(const QJsonArray& arr) { d.dsTypeCode = str(o, "dsTypeCode"); d.structParentId = str(o, "structParentId"); d.structParentConfType = o.value(QStringLiteral("structParentConfType")).toInt(); - // properties[] = [{confFieldId,value}](value 用 toVariant().toString() 兼容字符串/数值/时间, - // 与 parseDynamicForm 同口径);非数组形态(文件型 ds)安全返回空。 - const QJsonArray props = o.value(QStringLiteral("properties")).toArray(); - d.properties.reserve(static_cast(props.size())); - for (const QJsonValue& pv : props) { - const QJsonObject po = pv.toObject(); - d.properties.push_back( - {str(po, "confFieldId"), po.value(QStringLiteral("value")).toVariant().toString().toStdString()}); + // properties 后端是泛型 JSON:可能是数组 [{confFieldId,value}] 或对象 {confFieldId:value}。两种都解析 + // (历史只 toArray()→对象形态时丢空,导致装置/采集时间取不到,装置下拉空,用户实测)。 + const QJsonValue propsV = o.value(QStringLiteral("properties")); + if (propsV.isArray()) { + const QJsonArray props = propsV.toArray(); + d.properties.reserve(static_cast(props.size())); + for (const QJsonValue& pv : props) { + const QJsonObject po = pv.toObject(); + d.properties.push_back({str(po, "confFieldId"), + po.value(QStringLiteral("value")).toVariant().toString().toStdString()}); + } + } else if (propsV.isObject()) { + const QJsonObject po = propsV.toObject(); + for (auto it = po.begin(); it != po.end(); ++it) + d.properties.push_back( + {it.key().toStdString(), it.value().toVariant().toString().toStdString()}); } + // 装置类型也可能是顶层字段(arrayType 代码 / arrayTypeName 中文名)→ 同时收为属性,兜底供筛选匹配。 + if (o.contains(QStringLiteral("arrayType"))) + d.properties.push_back( + {"arrayType", o.value(QStringLiteral("arrayType")).toVariant().toString().toStdString()}); + if (o.contains(QStringLiteral("arrayTypeName"))) + d.properties.push_back( + {"arrayTypeName", + o.value(QStringLiteral("arrayTypeName")).toVariant().toString().toStdString()}); const QJsonObject f = o.value(QStringLiteral("file")).toObject(); d.fileName = str(f, "name"); d.fileUrl = str(f, "url");