From 888a63081baf9df6e1a515d4f3fc693ff78d36db Mon Sep 17 00:00:00 2001 From: gaozheng Date: Thu, 25 Jun 2026 11:50:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E4=B8=89=E7=BB=B4=E4=BD=93?= =?UTF-8?q?=E6=AE=B5=E4=BB=8E=E9=A1=B9=E7=9B=AE=E6=A0=B9=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E5=B1=82=E7=BA=A7=E6=A0=91(=E5=AE=B9=E5=99=A8=E8=8A=82?= =?UTF-8?q?=E7=82=B9+=E4=BD=93=E6=8C=82=E5=BD=92=E5=B1=9E)+=E6=AE=B5?= =?UTF-8?q?=E4=BD=93=E5=8F=B3=E9=94=AE=E8=8F=9C=E5=8D=95(=E8=AF=A6?= =?UTF-8?q?=E6=83=85/=E5=88=A0=E9=99=A4=E5=88=87=E7=89=87=E5=BC=82?= =?UTF-8?q?=E5=B8=B8)(=E7=95=8C=E9=9D=A2=E4=BF=AE=E5=A4=8D=204/5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/main.cpp | 30 +++++++++++++++---- .../panels/columns/CategoryAnalysisTab.cpp | 2 ++ .../panels/columns/CategoryAnalysisTab.hpp | 1 + src/app/panels/columns/CategorySection.cpp | 25 ++++++++++++++++ src/app/panels/columns/CategorySection.hpp | 4 ++- src/data/api/Api3dRepository.cpp | 1 + 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 1516173..60501b7 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -477,15 +477,24 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // splitByCategory 后注入 5 段(电阻率/视电阻率/瞬变/三维体/切片);二维(足迹)经 dim2D 仍走 col2D。 auto lastSourceRows = std::make_shared>(); auto lastStructNodes = std::make_shared>(); // 生成位置候选(项目内 GS/TM) - auto refreshAnalysis = [drawer, scene3dRepo, lastSourceRows]() { + auto refreshAnalysis = [drawer, scene3dRepo, lastSourceRows, lastStructNodes]() { const auto vols = scene3dRepo->volumeRows(); const auto slices = scene3dRepo->sliceRows(); const auto anomalies = scene3dRepo->anomalyRows(); - // 电阻率/视/瞬变段=对象树反演 ds(splitByCategory 按 dsTypeCode 分;voxel 段下方单独喂三级树)。 + // 电阻率/视/瞬变段=对象树反演 ds(splitByCategory 按 dsTypeCode 分;voxel 段下方单独喂完整树)。 drawer->analysisTab()->setBuckets(geopro::app::splitByCategory(*lastSourceRows)); - // 三维体段=「体→切片/异常」三级树:体(根)+切片(parentId=体)+异常(parentId=体/切片); - // 切片不单列段,只在此树(spec §8 修订)。populateDatasetList 按 parentId 自动建树。 - std::vector voxelTree = vols; + // 三维体段=从项目根的完整层级树:项目根/GS/TM 容器节点 → 体(挂生成位置) → 切片(挂体) → 异常(挂体/切片)。 + // populateDatasetList 按 parentId 自动建树(spec §7/§8)。 + std::vector voxelTree; + for (const auto& n : *lastStructNodes) { // 项目根/GS/TM 容器节点(ddCode="container",不可勾选) + geopro::data::DsRow c; + c.id = n.id; + c.dsName = n.name; + c.ddCode = "container"; + c.parentId = n.parentId; + voxelTree.push_back(std::move(c)); + } + for (const auto& v : vols) voxelTree.push_back(v); for (const auto& s : slices) voxelTree.push_back(s); for (const auto& a : anomalies) voxelTree.push_back(a); if (auto* sec = drawer->analysisTab()->section("voxel")) sec->setDatasets(voxelTree); @@ -795,6 +804,17 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re } } }); + // 三维体段右键删除:切片→deleteSlice / 异常→deleteAnomaly,删后刷新树。 + QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::deleteDatasetRequested, &window, + [scene3dRepo, refreshAnalysis](const QString& dsId, const QString& ddCode) { + const std::string id = dsId.toStdString(); + auto ok = [refreshAnalysis]() { refreshAnalysis(); }; + auto err = [](const std::string&) {}; + if (ddCode == QStringLiteral("dd_slice")) + scene3dRepo->deleteSlice(id, ok, err); + else if (ddCode == QStringLiteral("dd_anomaly")) + scene3dRepo->deleteAnomaly(id, ok, err); + }); // O点位置/字体本期 stub(TODO P4:弹框)。 QObject::connect(c3, &geopro::app::Column3DDataset::oPointClicked, vtkWidget, []() { /* TODO P4: O点位置弹框 */ }); diff --git a/src/app/panels/columns/CategoryAnalysisTab.cpp b/src/app/panels/columns/CategoryAnalysisTab.cpp index f443a00..4c42df4 100644 --- a/src/app/panels/columns/CategoryAnalysisTab.cpp +++ b/src/app/panels/columns/CategoryAnalysisTab.cpp @@ -37,6 +37,8 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d connect(sec, &CategorySection::generateVolumeRequested, this, &CategoryAnalysisTab::generateVolumeRequested); connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested); + connect(sec, &CategorySection::deleteDatasetRequested, this, + &CategoryAnalysisTab::deleteDatasetRequested); col->addWidget(sec); } col->addStretch(1); diff --git a/src/app/panels/columns/CategoryAnalysisTab.hpp b/src/app/panels/columns/CategoryAnalysisTab.hpp index 967a337..73fd6f5 100644 --- a/src/app/panels/columns/CategoryAnalysisTab.hpp +++ b/src/app/panels/columns/CategoryAnalysisTab.hpp @@ -30,6 +30,7 @@ signals: void checkedDatasetsChanged(const QStringList& dsIds); // 5 段勾选并集 void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); + void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除切片/异常 private: void recomputeCheckedUnion(); diff --git a/src/app/panels/columns/CategorySection.cpp b/src/app/panels/columns/CategorySection.cpp index 1fbcfb4..45aae93 100644 --- a/src/app/panels/columns/CategorySection.cpp +++ b/src/app/panels/columns/CategorySection.cpp @@ -5,6 +5,8 @@ #include "panels/columns/DateRangeEdit.hpp" #include #include +#include +#include #include #include #include @@ -85,6 +87,8 @@ CategorySection::CategorySection(const CategorySpec& spec, geopro::data::Dataset if (id.isEmpty()) return; emit detailRequested(id, it->data(0, kDsDdCodeRole).toString(), it->data(0, kDsNameRole).toString()); }); + list_->setContextMenuPolicy(Qt::CustomContextMenu); + connect(list_, &QTreeWidget::customContextMenuRequested, this, &CategorySection::showContextMenu); body->addWidget(list_, 1); root->addWidget(body_, 1); @@ -166,10 +170,13 @@ void CategorySection::rebuildList() { const QSignalBlocker block(list_); populateDatasetList(list_, filtered, /*append=*/false); for (QTreeWidgetItemIterator it(list_); *it; ++it) { + // 容器节点(项目根/GS/TM)只作层级骨架,不可勾选。 + if ((*it)->data(0, kDsDdCodeRole).toString() == QStringLiteral("container")) continue; (*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable); (*it)->setCheckState(0, Qt::Unchecked); } } + list_->expandAll(); // 展开容器层级(项目根/GS/TM),让体/切片/异常可见 emitChecked(); // 重建后必为空选,清掉上次渲染勾选 } @@ -182,4 +189,22 @@ QStringList CategorySection::checkedDsIds() const { void CategorySection::emitChecked() { emit checkedDatasetsChanged(checkedDsIds()); } +void CategorySection::showContextMenu(const QPoint& pos) { + QTreeWidgetItem* it = list_->itemAt(pos); + if (!it) return; + const QString id = it->data(0, kDsIdRole).toString(); + const QString ddCode = it->data(0, kDsDdCodeRole).toString(); + if (id.isEmpty() || ddCode == QStringLiteral("container")) return; // 容器节点无操作菜单 + const QString name = it->data(0, kDsNameRole).toString(); + QMenu menu(this); + menu.addAction(QStringLiteral("详情"), this, + [this, id, ddCode, name] { emit detailRequested(id, ddCode, name); }); + // 切片 / 异常可删除(三维体段无 deleteVolume 端点)。 + if (ddCode == QStringLiteral("dd_slice") || ddCode == QStringLiteral("dd_anomaly")) { + menu.addAction(QStringLiteral("删除"), this, + [this, id, ddCode] { emit deleteDatasetRequested(id, ddCode); }); + } + menu.exec(list_->viewport()->mapToGlobal(pos)); +} + } // namespace geopro::app diff --git a/src/app/panels/columns/CategorySection.hpp b/src/app/panels/columns/CategorySection.hpp index afb77c6..f671f58 100644 --- a/src/app/panels/columns/CategorySection.hpp +++ b/src/app/panels/columns/CategorySection.hpp @@ -36,9 +36,11 @@ public: signals: void checkedDatasetsChanged(const QStringList& dsIds); // 数据行勾选=渲染 void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); // 段头「+新增三维体」 - void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 双击=详情 + void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 双击/右键=详情 + void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除(切片/异常) private: + void showContextMenu(const QPoint& pos); // 段体树右键菜单(详情 + 删除) void rebuildList(); // 据 rows_(经装置/日期筛选)重建段体树并复原勾选 void refreshArrayCombo(); // 据当前 rows_ 重填装置类型下拉项(经字典 value→中文) void emitChecked(); // 收集勾选 → checkedDatasetsChanged diff --git a/src/data/api/Api3dRepository.cpp b/src/data/api/Api3dRepository.cpp index ff5de08..7ea6777 100644 --- a/src/data/api/Api3dRepository.cpp +++ b/src/data/api/Api3dRepository.cpp @@ -129,6 +129,7 @@ std::vector Api3dRepository::volumeRows() const { r.dsName = sv.name; r.ddCode = "dd_voxel"; r.typeName = "三维体"; + r.parentId = sv.request ? sv.request->structParentId : std::string(); // 挂生成位置(项目根/GS/TM) rows.push_back(std::move(r)); } return rows;