#include "desktop_list_page.h" #include #include #include #include #include #include #include namespace vdi { namespace { // 在信息行里加一个拉伸占位(独立函数避免在类外重复声明) void addStretchToRow(QHBoxLayout* row) { row->addStretch(1); } } // namespace DesktopListPage::DesktopListPage(QWidget* parent) : QWidget(parent) { auto* root = new QVBoxLayout(this); root->setContentsMargins(80, 50, 80, 40); root->setSpacing(16); // ---- 标题区 ---- auto* title = new QLabel(QStringLiteral("选择云桌面"), this); QFont titleFont = title->font(); titleFont.setPointSize(26); titleFont.setBold(true); title->setFont(titleFont); title->setAlignment(Qt::AlignCenter); root->addWidget(title); auto* infoRow = new QHBoxLayout(); labelUser_ = new QLabel(this); labelUser_->setStyleSheet(QStringLiteral("color: #8a94a6;")); // 无登录页演示模式下不设"退出登录"(用户身份由设备/平台承担, // 正式认证接入后由 DesktopService 驱动恢复登录流程) infoRow->addWidget(labelUser_); addStretchToRow(infoRow); root->addLayout(infoRow); // ---- 卡片区 ---- auto* scroll = new QScrollArea(this); scroll->setWidgetResizable(true); scroll->setFrameShape(QFrame::NoFrame); scroll->setStyleSheet(QStringLiteral( "QScrollArea { background: transparent; }" "QWidget { background: transparent; }")); auto* cardsHost = new QWidget(scroll); cardsLayout_ = new QVBoxLayout(cardsHost); cardsLayout_->setSpacing(14); cardsLayout_->addStretch(1); scroll->setWidget(cardsHost); root->addWidget(scroll, 1); // ---- 状态条 ---- labelStatus_ = new QLabel(this); labelStatus_->setAlignment(Qt::AlignCenter); labelStatus_->setStyleSheet(QStringLiteral("color: #8a94a6;")); root->addWidget(labelStatus_); } void DesktopListPage::setDesktops(const std::vector& desktops) { desktops_ = desktops; rebuildCards(); } void DesktopListPage::rebuildCards() { actionButtons_.clear(); // 清空旧卡片(最后一项是 stretch) while (cardsLayout_->count() > 1) { QLayoutItem* item = cardsLayout_->takeAt(0); if (item->widget()) { item->widget()->deleteLater(); } delete item; } for (const DesktopInfo& d : desktops_) { auto* card = new QFrame(this); card->setMinimumHeight(96); card->setStyleSheet(QStringLiteral( "QFrame { background: #1a2233; border: 1px solid #2b3654; border-radius: 10px; }" "QFrame:hover { border: 1px solid #2f6feb; }" "QLabel { border: none; background: transparent; }")); auto* row = new QHBoxLayout(card); row->setContentsMargins(24, 16, 24, 16); row->setSpacing(18); auto* textCol = new QVBoxLayout(); textCol->setSpacing(4); auto* name = new QLabel(d.name, card); QFont nameFont = name->font(); nameFont.setPointSize(15); nameFont.setBold(true); name->setFont(nameFont); auto* osLine = new QLabel(d.os, card); osLine->setStyleSheet(QStringLiteral("color: #8a94a6;")); textCol->addWidget(name); textCol->addWidget(osLine); row->addLayout(textCol, 1); // 状态标签(会话通道统一 Moonlight,无需按桌面标注协议) QString stateText; QString stateColor; switch (d.state) { case DesktopState::kAvailable: stateText = QStringLiteral("可连接"); stateColor = QStringLiteral("#3fb950"); break; case DesktopState::kPending: stateText = QStringLiteral("任务进行中"); stateColor = QStringLiteral("#d29922"); break; case DesktopState::kUnassigned: stateText = QStringLiteral("待分配"); stateColor = QStringLiteral("#8a94a6"); break; } auto* state = new QLabel(stateText, card); state->setStyleSheet(QStringLiteral("color: %1; font-weight: bold;").arg(stateColor)); row->addWidget(state); // “设置”:每张卡都可编辑连接参数(协议/地址/应用名/分辨率/帧率) auto* editBtn = new QPushButton(QStringLiteral("设置"), card); editBtn->setMinimumSize(88, 42); editBtn->setEnabled(!busy_); actionButtons_.push_back(editBtn); 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); connectBtn->setStyleSheet(QStringLiteral( "QPushButton { background: #2f6feb; color: white; border: none; " "border-radius: 6px; font-weight: bold; }" "QPushButton:disabled { background: #3a4a63; }")); connectBtn->setEnabled(!busy_); actionButtons_.push_back(connectBtn); connect(connectBtn, &QPushButton::clicked, this, [this, id = d.id]() { if (!busy_) { setBusy(true); setStatus(QStringLiteral("正在连接,请稍候…")); emit desktopSelected(id); } }); row->addWidget(connectBtn); } else { auto* btn = new QPushButton(QStringLiteral("连接"), card); btn->setMinimumSize(110, 42); btn->setEnabled(false); row->addWidget(btn); } cardsLayout_->insertWidget(cardsLayout_->count() - 1, card); } } void DesktopListPage::setStatus(const QString& text, bool error) { labelStatus_->setText(text); labelStatus_->setStyleSheet( QStringLiteral("color: %1;").arg(error ? QStringLiteral("#e05561") : QStringLiteral("#8a94a6"))); } void DesktopListPage::setBusy(bool busy) { busy_ = busy; for (QPushButton* button : actionButtons_) { if (button) { button->setEnabled(!busy_); } } } QString DesktopListPage::currentUser() const { return currentUser_; } void DesktopListPage::setCurrentUser(const QString& user) { currentUser_ = user; labelUser_->setText(user.isEmpty() ? QStringLiteral("当前用户:未登录") : QStringLiteral("当前用户:%1").arg(user)); } } // namespace vdi