|
|
@@ -0,0 +1,462 @@
|
|
|
+#include "createmeetingdialog.h"
|
|
|
+#include <QMessageBox>
|
|
|
+#include <QRandomGenerator>
|
|
|
+#include <QRegularExpression>
|
|
|
+#include <QRegularExpressionValidator>
|
|
|
+#include <QScrollArea>
|
|
|
+
|
|
|
+CreateMeetingDialog::CreateMeetingDialog(QWidget *parent)
|
|
|
+ : QDialog(parent)
|
|
|
+ , m_mainLayout(nullptr)
|
|
|
+ , m_formLayout(nullptr)
|
|
|
+ , m_basicGroup(nullptr)
|
|
|
+ , m_basicLayout(nullptr)
|
|
|
+ , m_meetingNameEdit(nullptr)
|
|
|
+ , m_descriptionEdit(nullptr)
|
|
|
+ , m_startTimeEdit(nullptr)
|
|
|
+ , m_durationSpinBox(nullptr)
|
|
|
+ , m_maxParticipantsSpinBox(nullptr)
|
|
|
+ , m_meetingTypeCombo(nullptr)
|
|
|
+ , m_securityGroup(nullptr)
|
|
|
+ , m_securityLayout(nullptr)
|
|
|
+ , m_passwordCheckBox(nullptr)
|
|
|
+ , m_passwordLayout(nullptr)
|
|
|
+ , m_passwordEdit(nullptr)
|
|
|
+ , m_generatePasswordButton(nullptr)
|
|
|
+ , m_recordCheckBox(nullptr)
|
|
|
+ , m_roleGroup(nullptr)
|
|
|
+ , m_roleLayout(nullptr)
|
|
|
+ , m_joinAsAdminCheckBox(nullptr)
|
|
|
+ , m_buttonLayout(nullptr)
|
|
|
+ , m_createButton(nullptr)
|
|
|
+ , m_cancelButton(nullptr)
|
|
|
+{
|
|
|
+ setWindowTitle("创建会议");
|
|
|
+ setModal(true);
|
|
|
+ resize(500, 600);
|
|
|
+
|
|
|
+ setupUI();
|
|
|
+ applyStyles();
|
|
|
+ setDefaultValues();
|
|
|
+
|
|
|
+ // 初始状态下禁用创建按钮
|
|
|
+ m_createButton->setEnabled(false);
|
|
|
+}
|
|
|
+
|
|
|
+CreateMeetingDialog::~CreateMeetingDialog()
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::setupUI()
|
|
|
+{
|
|
|
+ // 创建滚动区域
|
|
|
+ QScrollArea *scrollArea = new QScrollArea(this);
|
|
|
+ scrollArea->setWidgetResizable(true);
|
|
|
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
+
|
|
|
+ QWidget *scrollWidget = new QWidget();
|
|
|
+ scrollArea->setWidget(scrollWidget);
|
|
|
+
|
|
|
+ m_mainLayout = new QVBoxLayout(scrollWidget);
|
|
|
+ m_mainLayout->setContentsMargins(20, 20, 20, 20);
|
|
|
+ m_mainLayout->setSpacing(20);
|
|
|
+
|
|
|
+ // 基本信息组
|
|
|
+ m_basicGroup = new QGroupBox("基本信息", scrollWidget);
|
|
|
+ m_basicLayout = new QFormLayout(m_basicGroup);
|
|
|
+ m_basicLayout->setContentsMargins(15, 15, 15, 15);
|
|
|
+ m_basicLayout->setSpacing(10);
|
|
|
+
|
|
|
+ // 会议名称
|
|
|
+ m_meetingNameEdit = new QLineEdit();
|
|
|
+ m_meetingNameEdit->setPlaceholderText("请输入会议名称");
|
|
|
+ connect(m_meetingNameEdit, &QLineEdit::textChanged, this, &CreateMeetingDialog::onMeetingNameChanged);
|
|
|
+ m_basicLayout->addRow("会议名称 *:", m_meetingNameEdit);
|
|
|
+
|
|
|
+ // 会议描述
|
|
|
+ m_descriptionEdit = new QTextEdit();
|
|
|
+ m_descriptionEdit->setPlaceholderText("请输入会议描述(可选)");
|
|
|
+ m_descriptionEdit->setMaximumHeight(80);
|
|
|
+ m_basicLayout->addRow("会议描述:", m_descriptionEdit);
|
|
|
+
|
|
|
+ // 开始时间
|
|
|
+ m_startTimeEdit = new QDateTimeEdit();
|
|
|
+ m_startTimeEdit->setCalendarPopup(true);
|
|
|
+ m_startTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm");
|
|
|
+ m_basicLayout->addRow("开始时间 *:", m_startTimeEdit);
|
|
|
+
|
|
|
+ // 会议时长
|
|
|
+ m_durationSpinBox = new QSpinBox();
|
|
|
+ m_durationSpinBox->setRange(15, 480); // 15分钟到8小时
|
|
|
+ m_durationSpinBox->setSuffix(" 分钟");
|
|
|
+ m_durationSpinBox->setSingleStep(15);
|
|
|
+ m_basicLayout->addRow("会议时长 *:", m_durationSpinBox);
|
|
|
+
|
|
|
+ // 最大参与人数
|
|
|
+ m_maxParticipantsSpinBox = new QSpinBox();
|
|
|
+ m_maxParticipantsSpinBox->setRange(2, 100);
|
|
|
+ m_maxParticipantsSpinBox->setSuffix(" 人");
|
|
|
+ m_basicLayout->addRow("最大参与人数:", m_maxParticipantsSpinBox);
|
|
|
+
|
|
|
+ // 会议类型
|
|
|
+ m_meetingTypeCombo = new QComboBox();
|
|
|
+ m_meetingTypeCombo->addItems({"视频会议", "音频会议", "屏幕共享", "网络研讨会"});
|
|
|
+ m_basicLayout->addRow("会议类型:", m_meetingTypeCombo);
|
|
|
+
|
|
|
+ m_mainLayout->addWidget(m_basicGroup);
|
|
|
+
|
|
|
+ // 安全设置组
|
|
|
+ m_securityGroup = new QGroupBox("安全设置", scrollWidget);
|
|
|
+ m_securityLayout = new QVBoxLayout(m_securityGroup);
|
|
|
+ m_securityLayout->setContentsMargins(15, 15, 15, 15);
|
|
|
+ m_securityLayout->setSpacing(10);
|
|
|
+
|
|
|
+ // 密码设置
|
|
|
+ m_passwordCheckBox = new QCheckBox("启用会议密码");
|
|
|
+ connect(m_passwordCheckBox, &QCheckBox::toggled, this, &CreateMeetingDialog::onPasswordCheckChanged);
|
|
|
+ m_securityLayout->addWidget(m_passwordCheckBox);
|
|
|
+
|
|
|
+ m_passwordLayout = new QHBoxLayout();
|
|
|
+ m_passwordEdit = new QLineEdit();
|
|
|
+ m_passwordEdit->setPlaceholderText("请输入6-12位密码");
|
|
|
+ m_passwordEdit->setMaxLength(12);
|
|
|
+ m_passwordEdit->setEnabled(false);
|
|
|
+
|
|
|
+ // 设置密码验证器
|
|
|
+ QRegularExpression passwordRegex("[A-Za-z0-9]{6,12}");
|
|
|
+ QRegularExpressionValidator *passwordValidator = new QRegularExpressionValidator(passwordRegex, this);
|
|
|
+ m_passwordEdit->setValidator(passwordValidator);
|
|
|
+
|
|
|
+ m_generatePasswordButton = new QPushButton("生成密码");
|
|
|
+ m_generatePasswordButton->setEnabled(false);
|
|
|
+ connect(m_generatePasswordButton, &QPushButton::clicked, this, &CreateMeetingDialog::generateRandomPassword);
|
|
|
+
|
|
|
+ m_passwordLayout->addWidget(m_passwordEdit);
|
|
|
+ m_passwordLayout->addWidget(m_generatePasswordButton);
|
|
|
+ m_securityLayout->addLayout(m_passwordLayout);
|
|
|
+
|
|
|
+ // 录制设置
|
|
|
+ m_recordCheckBox = new QCheckBox("自动录制会议");
|
|
|
+ m_securityLayout->addWidget(m_recordCheckBox);
|
|
|
+
|
|
|
+ m_mainLayout->addWidget(m_securityGroup);
|
|
|
+
|
|
|
+ // 角色选择组
|
|
|
+ m_roleGroup = new QGroupBox("加入方式", scrollWidget);
|
|
|
+ m_roleLayout = new QVBoxLayout(m_roleGroup);
|
|
|
+ m_roleLayout->setContentsMargins(15, 15, 15, 15);
|
|
|
+ m_roleLayout->setSpacing(10);
|
|
|
+
|
|
|
+ m_joinAsAdminCheckBox = new QCheckBox("以管理员身份加入会议(可以录制和管理)");
|
|
|
+ m_joinAsAdminCheckBox->setChecked(true); // 默认选中管理员模式
|
|
|
+ m_roleLayout->addWidget(m_joinAsAdminCheckBox);
|
|
|
+
|
|
|
+ QLabel *roleHint = new QLabel("提示:取消勾选将以观看者身份加入会议");
|
|
|
+ roleHint->setStyleSheet("color: #666; font-size: 12px;");
|
|
|
+ m_roleLayout->addWidget(roleHint);
|
|
|
+
|
|
|
+ m_mainLayout->addWidget(m_roleGroup);
|
|
|
+
|
|
|
+ // 按钮布局
|
|
|
+ m_buttonLayout = new QHBoxLayout();
|
|
|
+ m_buttonLayout->addStretch();
|
|
|
+
|
|
|
+ m_cancelButton = new QPushButton("取消");
|
|
|
+ m_createButton = new QPushButton("创建会议");
|
|
|
+
|
|
|
+ connect(m_cancelButton, &QPushButton::clicked, this, &CreateMeetingDialog::reject);
|
|
|
+ connect(m_createButton, &QPushButton::clicked, this, &CreateMeetingDialog::accept);
|
|
|
+
|
|
|
+ m_buttonLayout->addWidget(m_cancelButton);
|
|
|
+ m_buttonLayout->addWidget(m_createButton);
|
|
|
+
|
|
|
+ m_mainLayout->addLayout(m_buttonLayout);
|
|
|
+
|
|
|
+ // 设置主布局
|
|
|
+ QVBoxLayout *dialogLayout = new QVBoxLayout(this);
|
|
|
+ dialogLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
+ dialogLayout->addWidget(scrollArea);
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::applyStyles()
|
|
|
+{
|
|
|
+ setStyleSheet(
|
|
|
+ "CreateMeetingDialog {"
|
|
|
+ " background-color: #f8f9fa;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QScrollArea {"
|
|
|
+ " border: none;"
|
|
|
+ " background-color: #f8f9fa;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QGroupBox {"
|
|
|
+ " font-size: 14px;"
|
|
|
+ " font-weight: bold;"
|
|
|
+ " color: #495057;"
|
|
|
+ " border: 2px solid #e9ecef;"
|
|
|
+ " border-radius: 8px;"
|
|
|
+ " margin-top: 10px;"
|
|
|
+ " background-color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QGroupBox::title {"
|
|
|
+ " subcontrol-origin: margin;"
|
|
|
+ " left: 10px;"
|
|
|
+ " padding: 0 8px 0 8px;"
|
|
|
+ " background-color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QLabel {"
|
|
|
+ " font-size: 13px;"
|
|
|
+ " color: #495057;"
|
|
|
+ " font-weight: 500;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QLineEdit {"
|
|
|
+ " border: 2px solid #e9ecef;"
|
|
|
+ " border-radius: 6px;"
|
|
|
+ " padding: 8px 12px;"
|
|
|
+ " font-size: 13px;"
|
|
|
+ " background-color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QLineEdit:focus {"
|
|
|
+ " border-color: #007bff;"
|
|
|
+ " outline: none;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QLineEdit:disabled {"
|
|
|
+ " background-color: #f8f9fa;"
|
|
|
+ " color: #6c757d;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QTextEdit {"
|
|
|
+ " border: 2px solid #e9ecef;"
|
|
|
+ " border-radius: 6px;"
|
|
|
+ " padding: 8px 12px;"
|
|
|
+ " font-size: 13px;"
|
|
|
+ " background-color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QTextEdit:focus {"
|
|
|
+ " border-color: #007bff;"
|
|
|
+ " outline: none;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QDateTimeEdit, QSpinBox, QComboBox {"
|
|
|
+ " border: 2px solid #e9ecef;"
|
|
|
+ " border-radius: 6px;"
|
|
|
+ " padding: 8px 12px;"
|
|
|
+ " font-size: 13px;"
|
|
|
+ " background-color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QDateTimeEdit:focus, QSpinBox:focus, QComboBox:focus {"
|
|
|
+ " border-color: #007bff;"
|
|
|
+ " outline: none;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QCheckBox {"
|
|
|
+ " font-size: 13px;"
|
|
|
+ " color: #495057;"
|
|
|
+ " spacing: 8px;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QCheckBox::indicator {"
|
|
|
+ " width: 16px;"
|
|
|
+ " height: 16px;"
|
|
|
+ " border: 2px solid #e9ecef;"
|
|
|
+ " border-radius: 3px;"
|
|
|
+ " background-color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QCheckBox::indicator:checked {"
|
|
|
+ " background-color: #007bff;"
|
|
|
+ " border-color: #007bff;"
|
|
|
+ " image: url(:/icons/check.png);"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "QPushButton {"
|
|
|
+ " border: none;"
|
|
|
+ " border-radius: 6px;"
|
|
|
+ " padding: 10px 20px;"
|
|
|
+ " font-size: 13px;"
|
|
|
+ " font-weight: 500;"
|
|
|
+ " min-width: 80px;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#createButton {"
|
|
|
+ " background-color: #28a745;"
|
|
|
+ " color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#createButton:hover {"
|
|
|
+ " background-color: #218838;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#createButton:pressed {"
|
|
|
+ " background-color: #1e7e34;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#createButton:disabled {"
|
|
|
+ " background-color: #6c757d;"
|
|
|
+ " color: #adb5bd;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#cancelButton {"
|
|
|
+ " background-color: #6c757d;"
|
|
|
+ " color: white;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#cancelButton:hover {"
|
|
|
+ " background-color: #545b62;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#generatePasswordButton {"
|
|
|
+ " background-color: #17a2b8;"
|
|
|
+ " color: white;"
|
|
|
+ " min-width: 60px;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#generatePasswordButton:hover {"
|
|
|
+ " background-color: #138496;"
|
|
|
+ "}"
|
|
|
+
|
|
|
+ "#generatePasswordButton:disabled {"
|
|
|
+ " background-color: #6c757d;"
|
|
|
+ " color: #adb5bd;"
|
|
|
+ "}"
|
|
|
+ );
|
|
|
+
|
|
|
+ m_createButton->setObjectName("createButton");
|
|
|
+ m_cancelButton->setObjectName("cancelButton");
|
|
|
+ m_generatePasswordButton->setObjectName("generatePasswordButton");
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::setDefaultValues()
|
|
|
+{
|
|
|
+ // 设置默认开始时间为当前时间后1小时
|
|
|
+ QDateTime defaultTime = QDateTime::currentDateTime().addSecs(3600);
|
|
|
+ m_startTimeEdit->setDateTime(defaultTime);
|
|
|
+ m_startTimeEdit->setMinimumDateTime(QDateTime::currentDateTime());
|
|
|
+
|
|
|
+ // 设置默认时长为60分钟
|
|
|
+ m_durationSpinBox->setValue(60);
|
|
|
+
|
|
|
+ // 设置默认最大参与人数为10人
|
|
|
+ m_maxParticipantsSpinBox->setValue(10);
|
|
|
+
|
|
|
+ // 默认选择视频会议
|
|
|
+ m_meetingTypeCombo->setCurrentIndex(0);
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::onPasswordCheckChanged(bool checked)
|
|
|
+{
|
|
|
+ m_passwordEdit->setEnabled(checked);
|
|
|
+ m_generatePasswordButton->setEnabled(checked);
|
|
|
+
|
|
|
+ if (!checked) {
|
|
|
+ m_passwordEdit->clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ validateInput();
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::onMeetingNameChanged()
|
|
|
+{
|
|
|
+ validateInput();
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::validateInput()
|
|
|
+{
|
|
|
+ bool isValid = isValidInput();
|
|
|
+ m_createButton->setEnabled(isValid);
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::generateRandomPassword()
|
|
|
+{
|
|
|
+ const QString chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
+ QString password;
|
|
|
+
|
|
|
+ for (int i = 0; i < 8; ++i) {
|
|
|
+ int index = QRandomGenerator::global()->bounded(chars.length());
|
|
|
+ password.append(chars.at(index));
|
|
|
+ }
|
|
|
+
|
|
|
+ m_passwordEdit->setText(password);
|
|
|
+}
|
|
|
+
|
|
|
+bool CreateMeetingDialog::isValidInput() const
|
|
|
+{
|
|
|
+ // 检查会议名称
|
|
|
+ if (m_meetingNameEdit->text().trimmed().isEmpty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查开始时间
|
|
|
+ if (m_startTimeEdit->dateTime() <= QDateTime::currentDateTime()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果启用了密码,检查密码有效性
|
|
|
+ if (m_passwordCheckBox->isChecked()) {
|
|
|
+ QString password = m_passwordEdit->text().trimmed();
|
|
|
+ if (password.length() < 6 || password.length() > 12) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+MeetingInfo CreateMeetingDialog::getMeetingInfo() const
|
|
|
+{
|
|
|
+ MeetingInfo info;
|
|
|
+ info.meetingName = m_meetingNameEdit->text().trimmed();
|
|
|
+ info.description = m_descriptionEdit->toPlainText().trimmed();
|
|
|
+ info.startTime = m_startTimeEdit->dateTime();
|
|
|
+ info.duration = m_durationSpinBox->value();
|
|
|
+ info.maxParticipants = m_maxParticipantsSpinBox->value();
|
|
|
+ info.requirePassword = m_passwordCheckBox->isChecked();
|
|
|
+ info.password = m_passwordEdit->text().trimmed();
|
|
|
+ info.recordMeeting = m_recordCheckBox->isChecked();
|
|
|
+ info.meetingType = m_meetingTypeCombo->currentText();
|
|
|
+ info.joinAsAdmin = m_joinAsAdminCheckBox->isChecked();
|
|
|
+
|
|
|
+ return info;
|
|
|
+}
|
|
|
+
|
|
|
+bool CreateMeetingDialog::getJoinAsAdmin() const
|
|
|
+{
|
|
|
+ return m_joinAsAdminCheckBox->isChecked();
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::accept()
|
|
|
+{
|
|
|
+ if (!isValidInput()) {
|
|
|
+ QString errorMsg;
|
|
|
+
|
|
|
+ if (m_meetingNameEdit->text().trimmed().isEmpty()) {
|
|
|
+ errorMsg = "请输入会议名称。";
|
|
|
+ } else if (m_startTimeEdit->dateTime() <= QDateTime::currentDateTime()) {
|
|
|
+ errorMsg = "开始时间必须晚于当前时间。";
|
|
|
+ } else if (m_passwordCheckBox->isChecked()) {
|
|
|
+ QString password = m_passwordEdit->text().trimmed();
|
|
|
+ if (password.length() < 6 || password.length() > 12) {
|
|
|
+ errorMsg = "密码长度必须在6-12位之间。";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ QMessageBox::warning(this, "输入错误", errorMsg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_meetingInfo = getMeetingInfo();
|
|
|
+ QDialog::accept();
|
|
|
+}
|
|
|
+
|
|
|
+void CreateMeetingDialog::reject()
|
|
|
+{
|
|
|
+ QDialog::reject();
|
|
|
+}
|