feat(ui): 日期范围筛选控件(双日历面板/可清空/默认今天)替代单 QDateEdit(界面修复 1/2/3)

This commit is contained in:
gaozheng 2026-06-25 11:41:23 +08:00
parent 2e4e4b24e4
commit c2f2b1f94c
5 changed files with 149 additions and 23 deletions

View File

@ -83,6 +83,7 @@ add_executable(geopro_desktop WIN32
panels/columns/Column3DAnalysis.cpp
panels/columns/CategorySection.cpp
panels/columns/CategoryAnalysisTab.cpp
panels/columns/DateRangeEdit.cpp
panels/columns/ColumnDrawer.cpp
panels/AnomalyTablePanel.cpp
panels/LoadingOverlay.cpp

View File

@ -2,7 +2,7 @@
#include <QComboBox>
#include <QDate>
#include <QDateEdit>
#include "panels/columns/DateRangeEdit.hpp"
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
@ -68,21 +68,10 @@ CategorySection::CategorySection(const CategorySpec& spec, geopro::data::Dataset
[this](int) { rebuildList(); });
filterRow->addWidget(arrayCombo_);
}
auto makeDate = [this]() {
auto* d = new QDateEdit(body_);
d->setCalendarPopup(true);
d->setDisplayFormat(QStringLiteral("yyyy-MM-dd"));
d->setSpecialValueText(QStringLiteral("不限")); // 最小日期→显示"不限"
d->setDate(d->minimumDate());
connect(d, &QDateEdit::dateChanged, this, [this](const QDate&) { rebuildList(); });
return d;
};
fromDate_ = makeDate();
toDate_ = makeDate();
filterRow->addWidget(new QLabel(QStringLiteral("采集"), body_));
filterRow->addWidget(fromDate_, 1);
filterRow->addWidget(new QLabel(QStringLiteral(""), body_));
filterRow->addWidget(toDate_, 1);
dateRange_ = new DateRangeEdit(body_);
connect(dateRange_, &DateRangeEdit::rangeChanged, this, [this] { rebuildList(); });
filterRow->addWidget(dateRange_, 1);
body->addLayout(filterRow);
// 段体:可勾选数据树(勾选=渲染)。复用数据列表卡片委托与 populateDatasetList。
@ -152,17 +141,17 @@ bool CategorySection::passesFilters(const DsRow& row) const {
if (!hit) return false;
}
}
// 采集时间collectTime 经 dict 取;缺则回退 createTime最小日期="不限"不约束)。
const bool hasFrom = fromDate_ && fromDate_->date() > fromDate_->minimumDate();
const bool hasTo = toDate_ && toDate_->date() > toDate_->minimumDate();
if (hasFrom || hasTo) {
// 采集时间范围collectTime 经 dict 取;缺则回退 createTime空范围不约束)。
const QDate from = dateRange_ ? dateRange_->from() : QDate();
const QDate to = dateRange_ ? dateRange_->to() : QDate();
if (from.isValid() || to.isValid()) {
const DsTypeFields* f = dict_ ? dict_->fields(spec_.dsTypeCode) : nullptr;
std::string ts = f ? collectTimeOf(row, *f) : std::string();
if (ts.empty()) ts = row.createTime;
const QDate d = QDate::fromString(QString::fromStdString(ts).left(10), QStringLiteral("yyyy-MM-dd"));
if (d.isValid()) {
if (hasFrom && d < fromDate_->date()) return false;
if (hasTo && d > toDate_->date()) return false;
if (from.isValid() && d < from) return false;
if (to.isValid() && d > to) return false;
}
}
return true;

View File

@ -18,6 +18,8 @@ class DatasetFieldDictionary;
namespace geopro::app {
class DateRangeEdit;
// 单个数据类型大类段spec §7段头标题/折叠 + 装置类型/日期筛选 + 「+新增三维体」)+ 段体(可勾选数据树)。
// 勾选数据行 = 渲染(帘面/体素/切片);段头生成按钮据当前勾选源发 generateVolumeRequested。
class CategorySection : public QWidget {
@ -51,8 +53,7 @@ private:
QToolButton* header_ = nullptr; // 折叠头(标题 + 箭头)
QWidget* body_ = nullptr; // 段体容器(折叠时隐藏)
QComboBox* arrayCombo_ = nullptr; // 装置类型筛选(仅 hasArrayTypeFilter
QDateEdit* fromDate_ = nullptr; // 采集时间段·起
QDateEdit* toDate_ = nullptr; // 采集时间段·止
DateRangeEdit* dateRange_ = nullptr; // 采集时间范围筛选(起止双日历,可清空)
QTreeWidget* list_ = nullptr;
};

View File

@ -0,0 +1,97 @@
#include "panels/columns/DateRangeEdit.hpp"
#include <QCalendarWidget>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QToolButton>
#include <QVBoxLayout>
#include "Theme.hpp"
namespace geopro::app {
DateRangeEdit::DateRangeEdit(QWidget* parent) : QWidget(parent) {
auto* lay = new QHBoxLayout(this);
lay->setContentsMargins(0, 0, 0, 0);
lay->setSpacing(0);
btn_ = new QToolButton(this);
btn_->setToolButtonStyle(Qt::ToolButtonTextOnly);
btn_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
btn_->setPopupMode(QToolButton::InstantPopup);
btn_->setToolTip(QStringLiteral("按采集时间筛选(起 ~ 止),可清空"));
connect(btn_, &QToolButton::clicked, this, &DateRangeEdit::openPopup);
lay->addWidget(btn_);
updateText();
}
void DateRangeEdit::openPopup() {
if (!popup_) {
popup_ = new QFrame(this, Qt::Popup);
popup_->setFrameShape(QFrame::StyledPanel);
applyTokenizedStyleSheet(
popup_, QStringLiteral("QFrame{background:{{bg/panel}};border:1px solid {{border/default}};"
"border-radius:8px;}"));
auto* v = new QVBoxLayout(popup_);
v->setContentsMargins(space::kSm, space::kSm, space::kSm, space::kSm);
auto* cals = new QHBoxLayout();
auto* fromCol = new QVBoxLayout();
fromCol->addWidget(new QLabel(QStringLiteral("起始"), popup_));
fromCal_ = new QCalendarWidget(popup_);
fromCol->addWidget(fromCal_);
cals->addLayout(fromCol);
auto* toCol = new QVBoxLayout();
toCol->addWidget(new QLabel(QStringLiteral("结束"), popup_));
toCal_ = new QCalendarWidget(popup_);
toCol->addWidget(toCal_);
cals->addLayout(toCol);
v->addLayout(cals);
auto* btns = new QHBoxLayout();
auto* clr = new QPushButton(QStringLiteral("清空"), popup_);
auto* ok = new QPushButton(QStringLiteral("确定"), popup_);
connect(clr, &QPushButton::clicked, this, &DateRangeEdit::clearAndClose);
connect(ok, &QPushButton::clicked, this, &DateRangeEdit::applyAndClose);
btns->addWidget(clr);
btns->addStretch(1);
btns->addWidget(ok);
v->addLayout(btns);
}
// 已有范围则定位到当前值,否则日历默认今天(不再 1752
if (from_.isValid()) fromCal_->setSelectedDate(from_);
if (to_.isValid()) toCal_->setSelectedDate(to_);
popup_->adjustSize();
popup_->move(mapToGlobal(QPoint(0, height())));
popup_->show();
}
void DateRangeEdit::applyAndClose() {
from_ = fromCal_->selectedDate();
to_ = toCal_->selectedDate();
if (from_.isValid() && to_.isValid() && from_ > to_) std::swap(from_, to_); // 起>止则交换
if (popup_) popup_->hide();
updateText();
emit rangeChanged();
}
void DateRangeEdit::clearAndClose() {
from_ = QDate();
to_ = QDate();
if (popup_) popup_->hide();
updateText();
emit rangeChanged();
}
void DateRangeEdit::updateText() {
if (!from_.isValid() && !to_.isValid()) {
btn_->setText(QStringLiteral("全部时间 ▾"));
return;
}
const QString f = from_.isValid() ? from_.toString(QStringLiteral("yyyy-MM-dd")) : QStringLiteral("不限");
const QString t = to_.isValid() ? to_.toString(QStringLiteral("yyyy-MM-dd")) : QStringLiteral("不限");
btn_->setText(QStringLiteral("%1 ~ %2 ▾").arg(f, t));
}
} // namespace geopro::app

View File

@ -0,0 +1,38 @@
#pragma once
#include <QDate>
#include <QWidget>
class QToolButton;
class QCalendarWidget;
class QFrame;
namespace geopro::app {
// 日期范围选择器spec 采集时间筛选):一个按钮显示「起 ~ 止」,点开弹双日历面板选起止;
// 可清空(回到"全部时间");默认不限,日历定位今天(不再停在 1752
class DateRangeEdit : public QWidget {
Q_OBJECT
public:
explicit DateRangeEdit(QWidget* parent = nullptr);
QDate from() const { return from_; } // 无效 QDate = 不限下限
QDate to() const { return to_; } // 无效 QDate = 不限上限
signals:
void rangeChanged();
private:
void openPopup();
void applyAndClose();
void clearAndClose();
void updateText();
QToolButton* btn_ = nullptr;
QFrame* popup_ = nullptr;
QCalendarWidget* fromCal_ = nullptr;
QCalendarWidget* toCal_ = nullptr;
QDate from_;
QDate to_;
};
} // namespace geopro::app