From ec1566a80e6ccd0db42b42e04491199bfc0c68f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E4=B8=80=E9=B8=A3?= <1000000008@qq.com> Date: Thu, 29 Oct 2026 14:05:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8C=89=E6=A1=8C=E9=9D=A2=E9=85=8D=E7=BD=AE=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=B8=8E=E5=A4=9A=E7=A7=8D=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 变更详情:桌面连接可配置化——每卡设置、地址支持 IP/域名/VPN 隧道 - 新增 DesktopStore:~/.config/vdi-terminal/desktops.json 持久化连接参数, 首次启动生成三张默认卡(待分配),老盒子自动从 client.conf 迁移 server 地址 - 新增 DesktopSettingsDialog:按桌面编辑协议/地址/应用名/分辨率/帧率, 置顶显示避免被全屏 kiosk 遮挡 - 桌面列表每张卡增加“设置”按钮;管理菜单 Ctrl+Alt+Shift+M 增加入口 - DesktopService 改为从 store 读取;地址为空的桌面显示待分配且不可连接 - 修复:默认卡未按 endpoint 重算状态导致迁移后仍显示待分配 - 实测真机通过:Windows 自动迁移可连接、对话框显示与保存正常 --- terminal/kiosk-shell/CMakeLists.txt | 2 + .../kiosk-shell/src/desktop_list_page.cpp | 10 ++ terminal/kiosk-shell/src/desktop_list_page.h | 2 + terminal/kiosk-shell/src/desktop_service.cpp | 65 +++---- .../src/desktop_settings_dialog.cpp | 143 ++++++++++++++++ .../kiosk-shell/src/desktop_settings_dialog.h | 52 ++++++ terminal/kiosk-shell/src/desktop_store.cpp | 160 ++++++++++++++++++ terminal/kiosk-shell/src/desktop_store.h | 37 ++++ terminal/kiosk-shell/src/main_window.cpp | 32 +++- terminal/kiosk-shell/src/main_window.h | 1 + 10 files changed, 460 insertions(+), 44 deletions(-) create mode 100644 terminal/kiosk-shell/src/desktop_settings_dialog.cpp create mode 100644 terminal/kiosk-shell/src/desktop_settings_dialog.h create mode 100644 terminal/kiosk-shell/src/desktop_store.cpp create mode 100644 terminal/kiosk-shell/src/desktop_store.h diff --git a/terminal/kiosk-shell/CMakeLists.txt b/terminal/kiosk-shell/CMakeLists.txt index 94f39de..838a2ba 100644 --- a/terminal/kiosk-shell/CMakeLists.txt +++ b/terminal/kiosk-shell/CMakeLists.txt @@ -24,7 +24,9 @@ add_executable(kiosk-shell src/main_window.cpp src/login_page.cpp src/desktop_list_page.cpp + src/desktop_settings_dialog.cpp src/desktop_service.cpp + src/desktop_store.cpp src/moonlight_session.cpp src/state_machine.cpp src/config.cpp diff --git a/terminal/kiosk-shell/src/desktop_list_page.cpp b/terminal/kiosk-shell/src/desktop_list_page.cpp index c3f0f4c..d9092a3 100644 --- a/terminal/kiosk-shell/src/desktop_list_page.cpp +++ b/terminal/kiosk-shell/src/desktop_list_page.cpp @@ -132,6 +132,16 @@ void DesktopListPage::rebuildCards() { state->setStyleSheet(QStringLiteral("color: %1; font-weight: bold;").arg(stateColor)); row->addWidget(state); + // “设置”:每张卡都可编辑连接参数(协议/地址/应用名/分辨率/帧率) + auto* editBtn = new QPushButton(QStringLiteral("设置"), card); + editBtn->setMinimumSize(88, 42); + connect(editBtn, &QPushButton::clicked, this, [this, id = d.id]() { + if (!busy_) { + emit editRequested(id); + } + }); + row->addWidget(editBtn); + if (d.state == DesktopState::kAvailable) { auto* connectBtn = new QPushButton(QStringLiteral("连接"), card); connectBtn->setMinimumSize(110, 42); diff --git a/terminal/kiosk-shell/src/desktop_list_page.h b/terminal/kiosk-shell/src/desktop_list_page.h index 4c003b3..01fbeb1 100644 --- a/terminal/kiosk-shell/src/desktop_list_page.h +++ b/terminal/kiosk-shell/src/desktop_list_page.h @@ -36,6 +36,8 @@ public: signals: // 用户点击一张可用桌面卡片 void desktopSelected(const QString& desktopId); + // 用户点击某张卡片的“设置”按钮 + void editRequested(const QString& desktopId); // 用户点击退出登录 void logoutRequested(); diff --git a/terminal/kiosk-shell/src/desktop_service.cpp b/terminal/kiosk-shell/src/desktop_service.cpp index bd2e1bb..2c9687f 100644 --- a/terminal/kiosk-shell/src/desktop_service.cpp +++ b/terminal/kiosk-shell/src/desktop_service.cpp @@ -1,5 +1,7 @@ #include "desktop_service.h" +#include "desktop_store.h" + namespace vdi { void DesktopService::login(const QString& username, const QString& password, AuthCallback callback) { @@ -20,59 +22,34 @@ void DesktopService::login(const QString& username, const QString& password, Aut } void DesktopService::listDesktops(DesktopListCallback callback) { - // 本地演示数据:Windows 可用(Moonlight),Ubuntu/麒麟尚未分配连接信息。 + // 桌面与连接参数来自本地连接配置(现场可配); // 正式版本替换为 /api/v1/terminal/session/desktops(按用户绑定返回)。 - std::vector desktops; - - DesktopInfo windows; - windows.id = QStringLiteral("desk-win10-01"); - windows.name = QStringLiteral("Windows 10"); - windows.os = QStringLiteral("Windows 10 22H2 专业版"); - windows.protocol = Protocol::kMoonlight; - windows.state = DesktopState::kAvailable; - windows.endpoint = QStringLiteral("192.168.1.70"); - windows.app = QStringLiteral("Desktop"); - desktops.push_back(windows); - - DesktopInfo ubuntu; - ubuntu.id = QStringLiteral("desk-ubuntu-01"); - ubuntu.name = QStringLiteral("Ubuntu"); - ubuntu.os = QStringLiteral("Ubuntu 桌面"); - ubuntu.protocol = Protocol::kRdp; - ubuntu.state = DesktopState::kUnassigned; - desktops.push_back(ubuntu); - - DesktopInfo kylin; - kylin.id = QStringLiteral("desk-kylin-01"); - kylin.name = QStringLiteral("麒麟"); - kylin.os = QStringLiteral("银河麒麟桌面"); - kylin.protocol = Protocol::kRdp; - kylin.state = DesktopState::kUnassigned; - desktops.push_back(kylin); - + std::vector desktops = DesktopStore::load(); if (callback) { callback(std::move(desktops), QString()); } } void DesktopService::createTicket(const QString& desktopId, TicketCallback callback) { - // 本地演示票据:直接由桌面列表数据构造。 + // 本地演示票据:由连接配置构造。 // 正式版本替换为 /api/v1/terminal/session/connect-ticket(短期一次性票据)。 ConnectionTicket ticket; ticket.desktopId = desktopId; - std::vector desktops; QString error; - listDesktops([&desktops, &error](std::vector list, const QString& err) { - desktops = std::move(list); - error = err; - }); - - for (const DesktopInfo& d : desktops) { - if (d.id == desktopId) { + listDesktops([&ticket, &error, desktopId](std::vector list, const QString& err) { + if (!err.isEmpty()) { + error = err; + return; + } + for (const DesktopInfo& d : list) { + if (d.id != desktopId) { + continue; + } if (d.state != DesktopState::kAvailable) { - error = QStringLiteral("桌面 %1 尚未分配连接信息").arg(d.name); - break; + error = QStringLiteral("桌面 %1 尚未配置连接地址,请先在“设置”中完成配置") + .arg(d.name); + return; } ticket.protocol = d.protocol; ticket.endpoint = d.endpoint; @@ -80,10 +57,12 @@ void DesktopService::createTicket(const QString& desktopId, TicketCallback callb ticket.width = d.width; ticket.height = d.height; ticket.fps = d.fps; - error.clear(); - break; + return; } - } + if (error.isEmpty() && ticket.endpoint.isEmpty()) { + error = QStringLiteral("桌面不存在"); + } + }); if (callback) { callback(ticket, error); diff --git a/terminal/kiosk-shell/src/desktop_settings_dialog.cpp b/terminal/kiosk-shell/src/desktop_settings_dialog.cpp new file mode 100644 index 0000000..6d93244 --- /dev/null +++ b/terminal/kiosk-shell/src/desktop_settings_dialog.cpp @@ -0,0 +1,143 @@ +#include "desktop_settings_dialog.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "desktop_store.h" + +namespace vdi { + +DesktopSettingsDialog::DesktopSettingsDialog(std::vector desktops, + const QString& selectId, QWidget* parent) + : QDialog(parent), desktops_(std::move(desktops)) { + setWindowTitle(QStringLiteral("桌面连接设置")); + setMinimumWidth(560); + // Kiosk 主窗口是全屏窗口,必须置顶否则对话框会被完全遮挡 + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + + auto* root = new QVBoxLayout(this); + root->setSpacing(14); + + auto* hint = new QLabel( + QStringLiteral("为每张桌面配置连接参数。地址支持 IP、域名或 VPN 隧道地址;" + "地址留空表示待分配,卡片将不可连接。"), + this); + hint->setWordWrap(true); + hint->setStyleSheet(QStringLiteral("color: #8a94a6;")); + root->addWidget(hint); + + auto* form = new QFormLayout(); + form->setHorizontalSpacing(14); + form->setVerticalSpacing(12); + + comboDesktop_ = new QComboBox(this); + for (const DesktopInfo& d : desktops_) { + comboDesktop_->addItem(d.name, d.id); + } + form->addRow(QStringLiteral("桌面"), comboDesktop_); + + comboProtocol_ = new QComboBox(this); + comboProtocol_->addItem(QStringLiteral("Moonlight"), QStringLiteral("moonlight")); + comboProtocol_->addItem(QStringLiteral("RDP"), QStringLiteral("rdp")); + form->addRow(QStringLiteral("协议"), comboProtocol_); + + editEndpoint_ = new QLineEdit(this); + editEndpoint_->setPlaceholderText(QStringLiteral("例如 192.168.1.70 或 VPN 隧道地址")); + form->addRow(QStringLiteral("服务器地址"), editEndpoint_); + + editApp_ = new QLineEdit(this); + editApp_->setPlaceholderText(QStringLiteral("Sunshine 应用名,通常为 Desktop")); + form->addRow(QStringLiteral("应用名(Moonlight)"), editApp_); + + comboResolution_ = new QComboBox(this); + const char* resolutions[] = {"1920x1080", "2560x1440", "1920x1440", "3840x2160", "1280x720"}; + for (const char* r : resolutions) { + comboResolution_->addItem(QString::fromLatin1(r), QString::fromLatin1(r)); + } + form->addRow(QStringLiteral("分辨率"), comboResolution_); + + comboFps_ = new QComboBox(this); + comboFps_->addItem(QStringLiteral("60"), 60); + comboFps_->addItem(QStringLiteral("30"), 30); + form->addRow(QStringLiteral("帧率"), comboFps_); + + root->addLayout(form); + + auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + buttons->button(QDialogButtonBox::Ok)->setText(QStringLiteral("保存")); + buttons->button(QDialogButtonBox::Cancel)->setText(QStringLiteral("取消")); + root->addWidget(buttons); + + connect(comboDesktop_, QOverload::of(&QComboBox::currentIndexChanged), this, + &DesktopSettingsDialog::onDesktopChanged); + connect(buttons, &QDialogButtonBox::accepted, this, &DesktopSettingsDialog::onAccepted); + connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + + // 预选指定桌面 + int index = 0; + if (!selectId.isEmpty()) { + for (int i = 0; i < comboDesktop_->count(); ++i) { + if (comboDesktop_->itemData(i).toString() == selectId) { + index = i; + break; + } + } + } + comboDesktop_->setCurrentIndex(index); + loadCurrent(); +} + +void DesktopSettingsDialog::onDesktopChanged(int index) { + Q_UNUSED(index); + loadCurrent(); +} + +void DesktopSettingsDialog::loadCurrent() { + const QString id = comboDesktop_->currentData().toString(); + for (const DesktopInfo& d : desktops_) { + if (d.id != id) { + continue; + } + loading_ = true; + comboProtocol_->setCurrentIndex(d.protocol == Protocol::kRdp ? 1 : 0); + editEndpoint_->setText(d.endpoint); + editApp_->setText(d.app); + int resIndex = comboResolution_->findData( + QStringLiteral("%1x%2").arg(d.width).arg(d.height)); + comboResolution_->setCurrentIndex(resIndex >= 0 ? resIndex : 0); + int fpsIndex = comboFps_->findData(d.fps); + comboFps_->setCurrentIndex(fpsIndex >= 0 ? fpsIndex : 0); + loading_ = false; + break; + } +} + +void DesktopSettingsDialog::onAccepted() { + const QString id = comboDesktop_->currentData().toString(); + for (DesktopInfo& d : desktops_) { + if (d.id != id) { + continue; + } + d.protocol = comboProtocol_->currentData().toString() == QStringLiteral("rdp") + ? Protocol::kRdp + : Protocol::kMoonlight; + d.endpoint = editEndpoint_->text().trimmed(); + d.app = editApp_->text().trimmed(); + const QString res = comboResolution_->currentData().toString(); + sscanf(res.toLatin1().constData(), "%dx%d", &d.width, &d.height); + d.fps = comboFps_->currentData().toInt(); + d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable; + DesktopStore::update(d); + break; + } + accept(); +} + +} // namespace vdi diff --git a/terminal/kiosk-shell/src/desktop_settings_dialog.h b/terminal/kiosk-shell/src/desktop_settings_dialog.h new file mode 100644 index 0000000..d85e77d --- /dev/null +++ b/terminal/kiosk-shell/src/desktop_settings_dialog.h @@ -0,0 +1,52 @@ +// 桌面连接设置对话框 +// +// 现场环境每套部署的桌面地址不同:选择一张桌面卡, +// 编辑协议(Moonlight/RDP)、地址(IP / 域名 / VPN 隧道地址)、 +// 应用名、分辨率和帧率,保存后立即生效。 +// 地址为空 = 待分配,卡片不可连接。 + +#ifndef KIOSK_SHELL_DESKTOP_SETTINGS_DIALOG_H +#define KIOSK_SHELL_DESKTOP_SETTINGS_DIALOG_H + +#include +#include + +#include "desktop_session.h" + +class QComboBox; +class QLineEdit; + +namespace vdi { + +class DesktopSettingsDialog : public QDialog { + Q_OBJECT + +public: + explicit DesktopSettingsDialog(std::vector desktops, + const QString& selectId = QString(), + QWidget* parent = nullptr); + + // 保存后的桌面列表(供调用方刷新) + std::vector desktops() const { return desktops_; } + +private slots: + void onDesktopChanged(int index); + void onAccepted(); + +private: + void loadCurrent(); + + std::vector desktops_; + + QComboBox* comboDesktop_ = nullptr; + QComboBox* comboProtocol_ = nullptr; + QLineEdit* editEndpoint_ = nullptr; + QLineEdit* editApp_ = nullptr; + QComboBox* comboResolution_ = nullptr; + QComboBox* comboFps_ = nullptr; + bool loading_ = false; +}; + +} // namespace vdi + +#endif // KIOSK_SHELL_DESKTOP_SETTINGS_DIALOG_H diff --git a/terminal/kiosk-shell/src/desktop_store.cpp b/terminal/kiosk-shell/src/desktop_store.cpp new file mode 100644 index 0000000..824b382 --- /dev/null +++ b/terminal/kiosk-shell/src/desktop_store.cpp @@ -0,0 +1,160 @@ +#include "desktop_store.h" + +#include +#include +#include +#include +#include +#include + +#include "config.h" + +namespace vdi { +namespace { + +// 三张默认桌面卡:id/name/os 固定,连接参数由现场配置。 +// endpoint 为空 = 待分配,配置地址后即变为可连接。 +std::vector defaultDesktops(const QString& migratedServer) { + std::vector list; + + DesktopInfo win; + win.id = QStringLiteral("desk-win10-01"); + win.name = QStringLiteral("Windows 10"); + win.os = QStringLiteral("Windows 桌面"); + win.protocol = Protocol::kMoonlight; + win.endpoint = migratedServer; // 兼容老盒子:迁移 client.conf 的 server + win.app = QStringLiteral("Desktop"); + win.width = 1920; + win.height = 1080; + win.fps = 60; + list.push_back(win); + + DesktopInfo ubuntu; + ubuntu.id = QStringLiteral("desk-ubuntu-01"); + ubuntu.name = QStringLiteral("Ubuntu"); + ubuntu.os = QStringLiteral("Ubuntu 桌面"); + ubuntu.protocol = Protocol::kRdp; + list.push_back(ubuntu); + + DesktopInfo kylin; + kylin.id = QStringLiteral("desk-kylin-01"); + kylin.name = QStringLiteral("麒麟"); + kylin.os = QStringLiteral("银河麒麟桌面"); + kylin.protocol = Protocol::kRdp; + list.push_back(kylin); + + return list; +} + +DesktopInfo fromJson(const QJsonObject& obj) { + DesktopInfo d; + d.id = obj.value(QStringLiteral("id")).toString(); + d.name = obj.value(QStringLiteral("name")).toString(); + d.os = obj.value(QStringLiteral("os")).toString(); + d.protocol = obj.value(QStringLiteral("protocol")).toString() == QStringLiteral("rdp") + ? Protocol::kRdp + : Protocol::kMoonlight; + d.endpoint = obj.value(QStringLiteral("endpoint")).toString(); + d.app = obj.value(QStringLiteral("app")).toString(); + d.width = obj.value(QStringLiteral("width")).toInt(1920); + d.height = obj.value(QStringLiteral("height")).toInt(1080); + d.fps = obj.value(QStringLiteral("fps")).toInt(60); + d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable; + return d; +} + +QJsonObject toJson(const DesktopInfo& d) { + QJsonObject obj; + obj.insert(QStringLiteral("id"), d.id); + obj.insert(QStringLiteral("name"), d.name); + obj.insert(QStringLiteral("os"), d.os); + obj.insert(QStringLiteral("protocol"), + d.protocol == Protocol::kRdp ? QStringLiteral("rdp") : QStringLiteral("moonlight")); + obj.insert(QStringLiteral("endpoint"), d.endpoint); + obj.insert(QStringLiteral("app"), d.app); + obj.insert(QStringLiteral("width"), d.width); + obj.insert(QStringLiteral("height"), d.height); + obj.insert(QStringLiteral("fps"), d.fps); + return obj; +} + +} // namespace + +QString DesktopStore::storePath() { + return QString::fromStdString(configDir()) + QStringLiteral("/desktops.json"); +} + +std::vector DesktopStore::load() { + std::vector result; + + QFile file(storePath()); + if (file.exists() && file.open(QIODevice::ReadOnly)) { + const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + const QJsonArray arr = doc.object().value(QStringLiteral("desktops")).toArray(); + for (const QJsonValue& v : arr) { + DesktopInfo d = fromJson(v.toObject()); + if (!d.id.isEmpty()) { + result.push_back(d); + } + } + } + + // 确保三张默认卡始终存在(新环境骨架 / 防止手工编辑删卡)。 + // 兼容老盒子:client.conf 里只要配过 server,就迁移为 Windows 桌面地址。 + const TerminalConfig cfg = loadConfig(); + const QString migrated = result.empty() && !cfg.server.empty() + ? QString::fromStdString(cfg.server) + : QString(); + const std::vector defaults = defaultDesktops(migrated); + for (const DesktopInfo& def : defaults) { + bool found = false; + for (const DesktopInfo& d : result) { + if (d.id == def.id) { + found = true; + break; + } + } + if (!found) { + result.push_back(def); + } + } + + // 统一按 endpoint 推导状态:有地址=可连接,无地址=待分配 + for (DesktopInfo& d : result) { + d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable; + } + return result; +} + +bool DesktopStore::save(const std::vector& desktops) { + QJsonArray arr; + for (const DesktopInfo& d : desktops) { + arr.append(toJson(d)); + } + QJsonObject root; + root.insert(QStringLiteral("version"), 1); + root.insert(QStringLiteral("desktops"), arr); + + const QString path = storePath(); + QDir().mkpath(QFileInfo(path).absolutePath()); + QFile file(path); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + return false; + } + file.write(QJsonDocument(root).toJson(QJsonDocument::Indented)); + return true; +} + +bool DesktopStore::update(const DesktopInfo& info) { + std::vector list = load(); + for (DesktopInfo& d : list) { + if (d.id == info.id) { + d = info; + d.state = d.endpoint.isEmpty() ? DesktopState::kUnassigned : DesktopState::kAvailable; + return save(list); + } + } + return false; +} + +} // namespace vdi diff --git a/terminal/kiosk-shell/src/desktop_store.h b/terminal/kiosk-shell/src/desktop_store.h new file mode 100644 index 0000000..d2869fd --- /dev/null +++ b/terminal/kiosk-shell/src/desktop_store.h @@ -0,0 +1,37 @@ +// 桌面连接配置持久化(JSON) +// +// 每个客户部署环境的桌面地址不同,连接参数不能写死在代码里。 +// 当前阶段由本地文件维护(现场通过"桌面连接设置"界面配置); +// 后续接入管理平台后,本类改为平台下发配置的本地缓存,接口不变。 +// +// 文件:~/.config/vdi-terminal/desktops.json +// 兼容:文件不存在时生成默认骨架;老盒子从 client.conf 的 server 迁移 Windows 地址。 + +#ifndef KIOSK_SHELL_DESKTOP_STORE_H +#define KIOSK_SHELL_DESKTOP_STORE_H + +#include +#include + +#include "desktop_session.h" + +namespace vdi { + +class DesktopStore { +public: + static QString storePath(); + + // 读取桌面列表;确保三张默认卡(Windows/Ubuntu/麒麟)始终存在。 + // state 由 endpoint 是否为空推导:有地址=可连接,无地址=待分配。 + static std::vector load(); + + // 保存完整桌面列表 + static bool save(const std::vector& desktops); + + // 更新单张桌面(按 id 匹配),保存成功返回 true + static bool update(const DesktopInfo& info); +}; + +} // namespace vdi + +#endif // KIOSK_SHELL_DESKTOP_STORE_H diff --git a/terminal/kiosk-shell/src/main_window.cpp b/terminal/kiosk-shell/src/main_window.cpp index ac41589..2042622 100644 --- a/terminal/kiosk-shell/src/main_window.cpp +++ b/terminal/kiosk-shell/src/main_window.cpp @@ -24,6 +24,7 @@ #include #include "desktop_list_page.h" +#include "desktop_settings_dialog.h" #include "login_page.h" namespace vdi { @@ -132,6 +133,7 @@ void MainWindow::setupUi() { stack_->addWidget(list); connect(list, &DesktopListPage::desktopSelected, this, &MainWindow::onDesktopSelected); + connect(list, &DesktopListPage::editRequested, this, &MainWindow::onEditDesktopRequested); connect(list, &DesktopListPage::logoutRequested, this, &MainWindow::onLogoutRequested); // 会话视图 @@ -330,6 +332,28 @@ void MainWindow::onDesktopSelected(const QString& desktopId) { }); } +void MainWindow::onEditDesktopRequested(const QString& desktopId) { + // 桌面连接设置:编辑协议/地址/应用名/分辨率/帧率,保存后立即刷新列表。 + // 现场环境地址不同或走 VPN 隧道时,在这里改地址即可,无需改代码。 + DesktopSettingsDialog dialog(desktops_, desktopId, this); + dialog.setStyleSheet( + QStringLiteral("QWidget { background: #0f1420; color: #e6e9ef; }" + "QLineEdit { background: #1a2233; border: 1px solid #2b3654; " + "border-radius: 4px; padding: 8px; color: #e6e9ef; }" + "QComboBox { background: #1a2233; border: 1px solid #2b3654; " + "border-radius: 4px; padding: 8px; color: #e6e9ef; }" + "QPushButton { background: #232d44; border: 1px solid #2b3654; " + "border-radius: 6px; color: #e6e9ef; }" + "QLabel { color: #e6e9ef; }")); + if (dialog.exec() == QDialog::Accepted) { + desktops_ = dialog.desktops(); + if (desktopListPage_) { + desktopListPage_->setDesktops(desktops_); + desktopListPage_->setStatus(QStringLiteral("连接配置已保存")); + } + } +} + void MainWindow::onLogoutRequested() { stopSessions(); desktopService_.logout(); @@ -546,12 +570,18 @@ void MainWindow::onMenuAction(int action) { break; default: { QMenu menu(this); + QAction* settings = menu.addAction(QStringLiteral("桌面连接设置")); + menu.addSeparator(); QAction* reconnect = menu.addAction(QStringLiteral("重新连接当前桌面")); QAction* disconnect = menu.addAction(QStringLiteral("断开并返回桌面列表")); menu.addSeparator(); QAction* quit = menu.addAction(QStringLiteral("退出终端")); QAction* chosen = menu.exec(QCursor::pos()); - if (chosen == reconnect) { + if (chosen == settings) { + if (fsm_.current() == State::kDesktopList || fsm_.current() == State::kConfig) { + onEditDesktopRequested(QString()); + } + } else if (chosen == reconnect) { onMenuAction(1); } else if (chosen == disconnect) { onMenuAction(2); diff --git a/terminal/kiosk-shell/src/main_window.h b/terminal/kiosk-shell/src/main_window.h index 45c0880..a701a5f 100644 --- a/terminal/kiosk-shell/src/main_window.h +++ b/terminal/kiosk-shell/src/main_window.h @@ -52,6 +52,7 @@ protected: private slots: void onLoginRequested(const QString& username, const QString& password); void onDesktopSelected(const QString& desktopId); + void onEditDesktopRequested(const QString& desktopId); void onLogoutRequested(); void onQuitRequested(); void onFrameImage(const QImage& image);