288 lines
11 KiB
C++
288 lines
11 KiB
C++
#include "TopBar.hpp"
|
||
|
||
#include <QActionGroup>
|
||
#include <QColor>
|
||
#include <QFrame>
|
||
#include <QHBoxLayout>
|
||
#include <QLabel>
|
||
#include <QMenu>
|
||
#include <QMenuBar>
|
||
#include <QSize>
|
||
#include <QStringList>
|
||
#include <QToolButton>
|
||
#include <QVBoxLayout>
|
||
#include <QWidget>
|
||
|
||
#include "Glyphs.hpp"
|
||
#include "Theme.hpp"
|
||
|
||
#include <ElaDef.h>
|
||
#include <ElaIconButton.h>
|
||
#include <ElaMenu.h>
|
||
#include <ElaMenuBar.h>
|
||
#include <ElaToolButton.h>
|
||
|
||
namespace geopro::app {
|
||
|
||
namespace {
|
||
|
||
// ── 专业图标尺寸(统一放大;菜单栏字号亦同步加大)──
|
||
constexpr int kToolIcon = 22; // 工具条右侧图标
|
||
constexpr int kWorkspaceIcon = 20; // 工作空间 / 项目图标
|
||
|
||
// 竖直分隔细线。
|
||
QFrame* makeDivider(QWidget* parent)
|
||
{
|
||
auto* line = new QFrame(parent);
|
||
line->setObjectName(QStringLiteral("topDivider"));
|
||
line->setFrameShape(QFrame::VLine);
|
||
line->setFixedWidth(1);
|
||
line->setFixedHeight(24);
|
||
return line;
|
||
}
|
||
|
||
// 右侧图标按钮(Fluent ElaIconButton:自带图标字体 + 悬停 + 随主题着色)。
|
||
// 用带固定宽高的构造(icon, 字号, 宽, 高, parent)——否则图标会被压扁变形。
|
||
QWidget* makeIconButton(QWidget* parent, ElaIconType::IconName icon, const QString& tip)
|
||
{
|
||
auto* btn = new ElaIconButton(icon, 18, 34, 34, parent);
|
||
btn->setToolTip(tip);
|
||
btn->setCursor(Qt::PointingHandCursor);
|
||
return btn;
|
||
}
|
||
|
||
// ── 四个菜单(结构对齐需求;叶子项当前为静态占位,后续接真实页面)──
|
||
QMenu* buildViewMenu(QWidget* p)
|
||
{
|
||
auto* m = new ElaMenu(QStringLiteral("视图"), p);
|
||
m->addAction(QStringLiteral("分析视图"));
|
||
m->addAction(QStringLiteral("大屏视图"));
|
||
return m;
|
||
}
|
||
|
||
QMenu* buildProjectMenu(QWidget* p)
|
||
{
|
||
auto* m = new ElaMenu(QStringLiteral("项目管理"), p);
|
||
m->addAction(QStringLiteral("数据视图"));
|
||
auto* cfg = m->addMenu(QStringLiteral("项目配置"));
|
||
cfg->addAction(QStringLiteral("基本信息"));
|
||
cfg->addAction(QStringLiteral("项目结构"));
|
||
cfg->addAction(QStringLiteral("视图配置"));
|
||
m->addAction(QStringLiteral("数据管理"));
|
||
auto* biz = m->addMenu(QStringLiteral("业务管理"));
|
||
biz->addAction(QStringLiteral("异常管理"));
|
||
biz->addAction(QStringLiteral("异常体管理"));
|
||
auto* mon = m->addMenu(QStringLiteral("在线监测"));
|
||
mon->addAction(QStringLiteral("项目设备"));
|
||
mon->addAction(QStringLiteral("在线任务管理"));
|
||
auto* doc = m->addMenu(QStringLiteral("项目资料管理"));
|
||
doc->addAction(QStringLiteral("项目资料管理"));
|
||
doc->addAction(QStringLiteral("报告列表"));
|
||
auto* tools = m->addMenu(QStringLiteral("工具组件"));
|
||
tools->addAction(QStringLiteral("装置与脚本"));
|
||
tools->addAction(QStringLiteral("色阶配置"));
|
||
tools->addAction(QStringLiteral("异常类型管理"));
|
||
tools->addAction(QStringLiteral("模型管理"));
|
||
auto* exp = m->addMenu(QStringLiteral("批量导出"));
|
||
exp->addAction(QStringLiteral("文件导出"));
|
||
exp->addAction(QStringLiteral("报告导出"));
|
||
auto* alarm = m->addMenu(QStringLiteral("告警管理"));
|
||
alarm->addAction(QStringLiteral("设备告警"));
|
||
alarm->addAction(QStringLiteral("告警查询"));
|
||
m->addAction(QStringLiteral("自动任务"));
|
||
m->addAction(QStringLiteral("模板管理"));
|
||
return m;
|
||
}
|
||
|
||
QMenu* buildToolsMenu(QWidget* p)
|
||
{
|
||
auto* m = new ElaMenu(QStringLiteral("业务工具"), p);
|
||
m->addAction(QStringLiteral("ERT 思维分析"));
|
||
m->addAction(QStringLiteral("电法脚本与装置"));
|
||
m->addAction(QStringLiteral("Geo 反演"));
|
||
m->addAction(QStringLiteral("三维 GPR 综合分析"));
|
||
return m;
|
||
}
|
||
|
||
QMenu* buildDeviceMenu(QWidget* p)
|
||
{
|
||
auto* m = new ElaMenu(QStringLiteral("设备"), p);
|
||
m->addAction(QStringLiteral("连接设备"));
|
||
m->addAction(QStringLiteral("设备管理"));
|
||
return m;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
QWidget* buildMenuBar(QWidget* parent)
|
||
{
|
||
auto* mb = new ElaMenuBar(parent);
|
||
mb->setObjectName(QStringLiteral("appMenuBar"));
|
||
// ElaMenuBar 自绘 Fluent 外观并自动随 ElaTheme 明暗,不再写内联 QSS。
|
||
mb->addMenu(buildViewMenu(mb));
|
||
mb->addMenu(buildProjectMenu(mb));
|
||
mb->addMenu(buildToolsMenu(mb));
|
||
mb->addMenu(buildDeviceMenu(mb));
|
||
return mb;
|
||
}
|
||
|
||
TopBar::TopBar(QWidget* parent) : QWidget(parent) {
|
||
setObjectName(QStringLiteral("appToolBar"));
|
||
setFixedHeight(56);
|
||
// 字号引用 Theme 排版令牌:工作空间切换器=title(15)、头像/用户名=body·label(13)、
|
||
// 角色名=caption(12)。原 11px 角色名上调到 12,去掉只差 1px 的糊层级。
|
||
// 切换器(ElaToolButton)/图标(ElaIconButton) 自绘 Fluent,不再写它们的 QSS。
|
||
// 仅保留:工具条底/分隔线、头像(圆形自定义)、用户名/角色。头像白字用 white 关键字(恒白)。
|
||
geopro::app::applyThemedStyleSheet(
|
||
this, QStringLiteral(
|
||
"#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }"
|
||
"#topDivider { color:#E1E6EE; }"
|
||
"QToolButton::menu-indicator { image:none; }"
|
||
"#avatar { background:#2D6CB5; color:white; border-radius:17px; font-weight:%2;"
|
||
" font-size:%1px; }"
|
||
"#userName { color:#1F2A3D; font-size:%3px; font-weight:%4; }"
|
||
"#userRole { color:#8A93A3; font-size:%5px; }")
|
||
.arg(type::kBody)
|
||
.arg(type::kWeightBold)
|
||
.arg(type::kLabel)
|
||
.arg(type::kWeightSemibold)
|
||
.arg(type::kCaption));
|
||
|
||
auto* lay = new QHBoxLayout(this);
|
||
lay->setContentsMargins(14, 0, 14, 0);
|
||
lay->setSpacing(0);
|
||
|
||
// 工作空间切换器(Fluent ElaToolButton;数据驱动,初始占位文本待 setWorkspaces 填充)。
|
||
wsBtn_ = new ElaToolButton(this);
|
||
wsBtn_->setObjectName(QStringLiteral("wsSwitcher"));
|
||
wsBtn_->setIcon(makeGlyph(Glyph::Workspace, QColor("#2D6CB5"), kWorkspaceIcon));
|
||
wsBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon));
|
||
wsBtn_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||
wsBtn_->setPopupMode(QToolButton::InstantPopup);
|
||
wsBtn_->setCursor(Qt::PointingHandCursor);
|
||
wsBtn_->setText(QStringLiteral("正在加载工作空间…"));
|
||
wsBtn_->setMenu(new ElaMenu(wsBtn_));
|
||
lay->addWidget(wsBtn_);
|
||
|
||
lay->addSpacing(10);
|
||
lay->addWidget(makeDivider(this));
|
||
lay->addSpacing(10);
|
||
|
||
// 项目切换器(Fluent ElaToolButton;数据驱动)。
|
||
projBtn_ = new ElaToolButton(this);
|
||
projBtn_->setObjectName(QStringLiteral("wsSwitcher"));
|
||
projBtn_->setIcon(makeGlyph(Glyph::Folder, QColor("#2D6CB5"), kWorkspaceIcon));
|
||
projBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon));
|
||
projBtn_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||
projBtn_->setPopupMode(QToolButton::InstantPopup);
|
||
projBtn_->setCursor(Qt::PointingHandCursor);
|
||
projBtn_->setText(QStringLiteral("正在加载项目…"));
|
||
projBtn_->setMenu(new ElaMenu(projBtn_));
|
||
lay->addWidget(projBtn_);
|
||
|
||
lay->addStretch();
|
||
|
||
lay->addWidget(makeIconButton(this, ElaIconType::CircleQuestion, QStringLiteral("帮助")));
|
||
lay->addWidget(makeIconButton(this, ElaIconType::Bell, QStringLiteral("通知")));
|
||
lay->addWidget(makeIconButton(this, ElaIconType::Gear, QStringLiteral("设置")));
|
||
lay->addSpacing(10);
|
||
lay->addWidget(makeDivider(this));
|
||
lay->addSpacing(12);
|
||
|
||
// 用户区:头像可点击 → 弹出菜单(退出登录)。
|
||
auto* avatar = new QToolButton(this);
|
||
avatar->setObjectName(QStringLiteral("avatar"));
|
||
avatar->setText(QStringLiteral("ZL"));
|
||
avatar->setFixedSize(34, 34);
|
||
avatar->setCursor(Qt::PointingHandCursor);
|
||
avatar->setPopupMode(QToolButton::InstantPopup);
|
||
auto* userMenu = new ElaMenu(avatar);
|
||
QObject::connect(userMenu->addAction(QStringLiteral("退出登录")), &QAction::triggered, this,
|
||
[this] { emit logoutRequested(); });
|
||
avatar->setMenu(userMenu);
|
||
lay->addWidget(avatar);
|
||
lay->addSpacing(8);
|
||
|
||
auto* userBox = new QWidget(this);
|
||
auto* userLay = new QVBoxLayout(userBox);
|
||
userLay->setContentsMargins(0, 0, 0, 0);
|
||
userLay->setSpacing(0);
|
||
auto* userName = new QLabel(QStringLiteral("张磊"), userBox);
|
||
userName->setObjectName(QStringLiteral("userName"));
|
||
auto* userRole = new QLabel(QStringLiteral("高级工程师"), userBox);
|
||
userRole->setObjectName(QStringLiteral("userRole"));
|
||
userLay->addWidget(userName);
|
||
userLay->addWidget(userRole);
|
||
lay->addWidget(userBox);
|
||
}
|
||
|
||
void TopBar::setWorkspaces(const std::vector<data::Workspace>& list, const QString& currentId) {
|
||
auto* menu = new ElaMenu(wsBtn_);
|
||
auto* header = menu->addAction(QStringLiteral("切换空间"));
|
||
header->setEnabled(false);
|
||
menu->addSeparator();
|
||
auto* group = new QActionGroup(menu);
|
||
group->setExclusive(true); // 互斥:只一个勾选,避免“多选”
|
||
QString currentName;
|
||
for (const auto& w : list) {
|
||
const QString id = QString::fromStdString(w.id);
|
||
const QString name = QString::fromStdString(w.name);
|
||
auto* a = menu->addAction(name);
|
||
a->setCheckable(true);
|
||
a->setChecked(id == currentId);
|
||
group->addAction(a);
|
||
if (id == currentId) currentName = name;
|
||
QObject::connect(a, &QAction::triggered, this, [this, id, name]() {
|
||
wsBtn_->setText(name); // 立即反馈(下拉箭头由 ElaToolButton 自绘)
|
||
emit workspaceSwitchRequested(id);
|
||
});
|
||
}
|
||
if (list.empty()) {
|
||
auto* none = menu->addAction(QStringLiteral("(暂无空间)"));
|
||
none->setEnabled(false);
|
||
}
|
||
wsBtn_->setMenu(menu);
|
||
wsBtn_->setText(currentName.isEmpty() ? QStringLiteral("选择空间") : currentName);
|
||
}
|
||
|
||
void TopBar::setProjects(const std::vector<data::ProjectSummary>& list, const QString& currentId,
|
||
bool hasMore) {
|
||
auto* menu = new ElaMenu(projBtn_);
|
||
auto* header = menu->addAction(QStringLiteral("切换项目"));
|
||
header->setEnabled(false);
|
||
menu->addSeparator();
|
||
auto* group = new QActionGroup(menu);
|
||
group->setExclusive(true);
|
||
QString currentName;
|
||
for (const auto& p : list) {
|
||
const QString id = QString::fromStdString(p.id);
|
||
const QString name = QString::fromStdString(p.name);
|
||
auto* a = menu->addAction(name);
|
||
a->setCheckable(true);
|
||
a->setChecked(id == currentId);
|
||
group->addAction(a);
|
||
if (id == currentId) currentName = name;
|
||
QObject::connect(a, &QAction::triggered, this, [this, id, name]() {
|
||
projBtn_->setText(name);
|
||
emit projectSwitchRequested(id);
|
||
});
|
||
}
|
||
if (list.empty()) {
|
||
auto* none = menu->addAction(QStringLiteral("(暂无项目)"));
|
||
none->setEnabled(false);
|
||
}
|
||
if (hasMore) {
|
||
menu->addSeparator();
|
||
auto* all = menu->addAction(QStringLiteral("全部项目…"));
|
||
QObject::connect(all, &QAction::triggered, this, [this]() { emit allProjectsRequested(); });
|
||
}
|
||
projBtn_->setMenu(menu);
|
||
projBtn_->setText(currentName.isEmpty() ? QStringLiteral("选择项目") : currentName);
|
||
}
|
||
|
||
void TopBar::setProjectButtonText(const QString& name) {
|
||
projBtn_->setText(name);
|
||
}
|
||
|
||
} // namespace geopro::app
|