diff --git a/src/Client/BattlefieldExplorationSystem b/src/Client/BattlefieldExplorationSystem index ca8aa43..5800020 100755 Binary files a/src/Client/BattlefieldExplorationSystem and b/src/Client/BattlefieldExplorationSystem differ diff --git a/src/Client/include/ui/components/DeviceListPanel.h b/src/Client/include/ui/components/DeviceListPanel.h index 4b4eeb2..e7b8530 100644 --- a/src/Client/include/ui/components/DeviceListPanel.h +++ b/src/Client/include/ui/components/DeviceListPanel.h @@ -241,6 +241,11 @@ private slots: */ void onAddDogClicked(); + /** + * @brief 删除设备按钮点击槽函数 + */ + void onDeleteDeviceClicked(); + /** * @brief 设备卡片选中槽函数 * @param deviceId 设备ID @@ -306,6 +311,13 @@ private: */ QList loadDevicesFromDatabase(); + /** + * @brief 从数据库删除设备 + * @param deviceId 设备ID + * @return 是否删除成功 + */ + bool deleteDeviceFromDatabase(const QString &deviceId); + /** * @brief 应用搜索和过滤 */ @@ -341,6 +353,7 @@ private: // UI组件 - 操作按钮 QPushButton *m_addUAVButton; ///< 添加无人机按钮 QPushButton *m_addDogButton; ///< 添加机器狗按钮 + QPushButton *m_deleteDeviceButton; ///< 删除设备按钮 QPushButton *m_refreshButton; ///< 刷新按钮 // UI组件 - 设备列表区域 diff --git a/src/Client/include/ui/main/MainWindow.h b/src/Client/include/ui/main/MainWindow.h index 9c40e66..41e15fe 100644 --- a/src/Client/include/ui/main/MainWindow.h +++ b/src/Client/include/ui/main/MainWindow.h @@ -100,14 +100,17 @@ public: /** * @brief 添加设备到数据库 + * @param deviceId 设备ID * @param name 设备名称 * @param type 设备类型 ("uav" 或 "dog") * @param ip IP地址 * @param port 端口号 * @param state 状态 (默认为0) + * @param longitude 经度 (默认为0.0) + * @param latitude 纬度 (默认为0.0) * @return 是否成功 */ - bool addDeviceToDatabase(const QString &name, const QString &type, const QString &ip, int port, int state = 0); + bool addDeviceToDatabase(const QString &deviceId, const QString &name, const QString &type, const QString &ip, int port, int state = 0, double longitude = 0.0, double latitude = 0.0); /** * @brief 地图显示控制 diff --git a/src/Client/src/ui/components/DeviceListPanel.cpp b/src/Client/src/ui/components/DeviceListPanel.cpp index 34035b5..c447b0e 100644 --- a/src/Client/src/ui/components/DeviceListPanel.cpp +++ b/src/Client/src/ui/components/DeviceListPanel.cpp @@ -13,6 +13,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include // Qt SQL头文件 #include @@ -93,22 +100,37 @@ void DeviceListPanel::setupUI() // === 操作按钮区域 === m_buttonLayout = new QHBoxLayout(); - m_addUAVButton = new QPushButton("🚁 + 无人机"); - m_addUAVButton->setMaximumHeight(50); - m_addUAVButton->setMaximumWidth(120); + m_addUAVButton = new QPushButton("🚁 +无人机"); + m_addUAVButton->setMaximumHeight(60); // 调大按钮 + m_addUAVButton->setMaximumWidth(110); // 合理调整按钮宽度 + m_addUAVButton->setMinimumWidth(110); // 设置最小宽度确保文字显示完整 + m_addUAVButton->setToolTip("添加新的无人机设备"); - m_addDogButton = new QPushButton("🐕 + 机器狗"); - m_addDogButton->setMaximumHeight(50); - m_addDogButton->setMaximumWidth(120); + m_addDogButton = new QPushButton("🐕 +机器狗"); + m_addDogButton->setMaximumHeight(60); // 调大按钮 + m_addDogButton->setMaximumWidth(110); // 合理调整按钮宽度 + m_addDogButton->setMinimumWidth(110); // 设置最小宽度确保文字显示完整 + m_addDogButton->setToolTip("添加新的机器狗设备"); + + m_deleteDeviceButton = new QPushButton("🗑️ 删除"); + m_deleteDeviceButton->setMaximumHeight(60); + m_deleteDeviceButton->setMaximumWidth(90); // 合理调整按钮宽度 + m_deleteDeviceButton->setMinimumWidth(90); // 设置最小宽度确保文字显示完整 + m_deleteDeviceButton->setToolTip("删除现有设备"); m_refreshButton = new QPushButton("🔄"); - m_refreshButton->setMaximumHeight(32); - m_refreshButton->setMaximumWidth(40); + m_refreshButton->setMaximumHeight(50); // 调大刷新按钮 + m_refreshButton->setMaximumWidth(50); // 保持紧凑的刷新按钮 + m_refreshButton->setMinimumWidth(50); // 设置最小宽度 m_refreshButton->setToolTip("刷新设备列表"); + // 添加按钮间距 m_buttonLayout->addWidget(m_addUAVButton); + m_buttonLayout->addSpacing(5); // 添加5px间距 m_buttonLayout->addWidget(m_addDogButton); - m_buttonLayout->addStretch(); + m_buttonLayout->addSpacing(5); // 添加5px间距 + m_buttonLayout->addWidget(m_deleteDeviceButton); // 添加删除按钮 + m_buttonLayout->addStretch(); // 弹性空间 m_buttonLayout->addWidget(m_refreshButton); // === 设备列表滚动区域 === @@ -205,6 +227,7 @@ void DeviceListPanel::setupStyle() m_addUAVButton->setStyleSheet(buttonStyle); m_addDogButton->setStyleSheet(buttonStyle); + m_deleteDeviceButton->setStyleSheet(buttonStyle); m_refreshButton->setStyleSheet(buttonStyle); // 滚动区域样式 @@ -240,6 +263,7 @@ void DeviceListPanel::connectSignals() // 按钮信号 connect(m_addUAVButton, &QPushButton::clicked, this, &DeviceListPanel::onAddUAVClicked); connect(m_addDogButton, &QPushButton::clicked, this, &DeviceListPanel::onAddDogClicked); + connect(m_deleteDeviceButton, &QPushButton::clicked, this, &DeviceListPanel::onDeleteDeviceClicked); connect(m_refreshButton, &QPushButton::clicked, this, &DeviceListPanel::refreshDeviceList); // 状态监控定时器 @@ -509,6 +533,74 @@ QList DeviceListPanel::loadDevicesFromDatabase() return devices; } +bool DeviceListPanel::deleteDeviceFromDatabase(const QString &deviceId) +{ + qDebug() << "Attempting to delete device from database:" << deviceId; + + // 创建数据库连接 + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DeviceListPanel_Delete_Connection"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + + bool success = false; + + if (db.open()) { + qDebug() << "Successfully connected to database for deletion"; + + QSqlQuery query(db); + query.prepare("DELETE FROM devices WHERE id = ?"); + query.addBindValue(deviceId); + + if (query.exec()) { + if (query.numRowsAffected() > 0) { + qDebug() << "Successfully deleted device from database:" << deviceId; + success = true; + + // 从内存中移除设备 + for (int i = m_allDevices.size() - 1; i >= 0; --i) { + if (m_allDevices[i].id == deviceId) { + m_allDevices.removeAt(i); + break; + } + } + + // 删除设备卡片 + if (m_deviceCards.contains(deviceId)) { + DeviceCard *card = m_deviceCards[deviceId]; + m_deviceCards.remove(deviceId); + m_deviceListLayout->removeWidget(card); + card->deleteLater(); + } + + // 清除选择(如果删除的是当前选中的设备) + if (m_selectedDeviceId == deviceId) { + m_selectedDeviceId.clear(); + } + + // 更新统计信息 + updateDeviceCountStats(); + + } else { + qWarning() << "No device found with ID:" << deviceId; + } + } else { + qWarning() << "Failed to execute delete query:" << query.lastError().text(); + } + + db.close(); + } else { + qWarning() << "Failed to connect to database for deletion:" << db.lastError().text(); + } + + // 清理数据库连接 + QSqlDatabase::removeDatabase("DeviceListPanel_Delete_Connection"); + + return success; +} + void DeviceListPanel::applySearchAndFilter() { qDebug() << "Applying search and filter. Keyword:" << m_currentSearchKeyword @@ -607,6 +699,339 @@ void DeviceListPanel::onAddDogClicked() emit addDeviceRequested("dog"); } +void DeviceListPanel::onDeleteDeviceClicked() +{ + qDebug() << "Delete device button clicked"; + + // 创建删除设备对话框 + QDialog *dialog = new QDialog(this); + dialog->setWindowTitle("删除设备"); + dialog->resize(500, 400); + dialog->setModal(true); + + QVBoxLayout *layout = new QVBoxLayout(dialog); + + // 设置对话框样式 + dialog->setStyleSheet( + "QDialog {" + " background-color: rgb(240, 240, 240);" + " color: rgb(50, 50, 50);" + "}" + ); + + // 标题标签 + QLabel *titleLabel = new QLabel("选择要删除的设备:"); + titleLabel->setStyleSheet( + "QLabel {" + " font-weight: bold;" + " font-size: 16px;" + " color: rgb(50, 50, 50);" + " background-color: transparent;" + " margin-bottom: 10px;" + " padding: 5px;" + "}" + ); + layout->addWidget(titleLabel); + + // 设备列表 + QTableWidget *deviceTable = new QTableWidget(); + deviceTable->setColumnCount(3); + QStringList headers; + headers << "设备ID" << "设备名称" << "设备类型"; + deviceTable->setHorizontalHeaderLabels(headers); + + // 设置表格属性 + deviceTable->setSelectionBehavior(QAbstractItemView::SelectRows); + deviceTable->setSelectionMode(QAbstractItemView::SingleSelection); + deviceTable->horizontalHeader()->setStretchLastSection(true); + deviceTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + + // 隐藏行号列(垂直表头) + deviceTable->verticalHeader()->setVisible(false); + + // 设置表格样式 + deviceTable->setStyleSheet( + "QTableWidget {" + " background-color: white;" + " alternate-background-color: rgb(245, 245, 245);" + " color: rgb(50, 50, 50);" + " gridline-color: rgb(200, 200, 200);" + " selection-background-color: rgb(0, 120, 215);" + " selection-color: white;" + " border: 1px solid rgb(180, 180, 180);" + " border-radius: 4px;" + "}" + "QHeaderView::section {" + " background-color: rgb(230, 230, 230);" + " color: rgb(50, 50, 50);" + " padding: 8px;" + " border: 1px solid rgb(180, 180, 180);" + " font-weight: bold;" + "}" + "QTableWidget::item {" + " padding: 8px;" + " color: rgb(50, 50, 50);" + "}" + "QTableWidget::item:selected {" + " background-color: rgb(0, 120, 215);" + " color: white;" + "}" + ); + + // 从数据库加载所有设备 + QList allDevices = loadDevicesFromDatabase(); + deviceTable->setRowCount(allDevices.size()); + + for (int i = 0; i < allDevices.size(); ++i) { + const DeviceInfo &device = allDevices[i]; + + deviceTable->setItem(i, 0, new QTableWidgetItem(device.id)); + deviceTable->setItem(i, 1, new QTableWidgetItem(device.name)); + + QString deviceTypeText; + if (device.type == "uav") { + deviceTypeText = "🚁 无人机"; + } else if (device.type == "dog") { + deviceTypeText = "🐕 机器狗"; + } else { + deviceTypeText = device.type; + } + deviceTable->setItem(i, 2, new QTableWidgetItem(deviceTypeText)); + } + + layout->addWidget(deviceTable); + + // 按钮区域 + QHBoxLayout *buttonLayout = new QHBoxLayout(); + QPushButton *deleteBtn = new QPushButton("删除选中设备"); + QPushButton *cancelBtn = new QPushButton("取消"); + + deleteBtn->setStyleSheet( + "QPushButton {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(220, 53, 69, 0.8), " + " stop:1 rgba(180, 40, 55, 0.8));" + " color: white;" + " border: 2px solid rgba(220, 53, 69, 0.5);" + " border-radius: 6px;" + " padding: 10px 16px;" + " font-weight: bold;" + "}" + "QPushButton:hover {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(220, 53, 69, 1.0), " + " stop:1 rgba(180, 40, 55, 1.0));" + " border-color: rgba(220, 53, 69, 0.8);" + "}" + "QPushButton:pressed {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(180, 40, 55, 1.0), " + " stop:1 rgba(140, 30, 45, 1.0));" + "}" + ); + + cancelBtn->setStyleSheet( + "QPushButton {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(45, 65, 95, 0.8), " + " stop:1 rgba(25, 40, 65, 0.8));" + " color: rgb(220, 230, 242);" + " border: 2px solid rgba(82, 194, 242, 0.5);" + " border-radius: 6px;" + " padding: 10px 16px;" + " font-weight: bold;" + "}" + "QPushButton:hover {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(82, 194, 242, 0.6), " + " stop:1 rgba(45, 120, 180, 0.6));" + " border-color: rgba(82, 194, 242, 0.8);" + " color: white;" + "}" + ); + + buttonLayout->addStretch(); + buttonLayout->addWidget(deleteBtn); + buttonLayout->addWidget(cancelBtn); + layout->addLayout(buttonLayout); + + // 连接信号 + connect(deleteBtn, &QPushButton::clicked, [this, dialog, deviceTable, allDevices]() { + int selectedRow = deviceTable->currentRow(); + if (selectedRow >= 0 && selectedRow < allDevices.size()) { + const DeviceInfo &selectedDevice = allDevices[selectedRow]; + + // 确认删除 + QMessageBox confirmBox(dialog); + confirmBox.setWindowTitle("确认删除"); + confirmBox.setText(QString("确定要删除设备 '%1' (%2) 吗?") + .arg(selectedDevice.name) + .arg(selectedDevice.id)); + confirmBox.setInformativeText("此操作不可恢复!"); + confirmBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + confirmBox.setDefaultButton(QMessageBox::No); + confirmBox.setIcon(QMessageBox::Question); + + // 设置确认对话框样式 + confirmBox.setStyleSheet( + "QMessageBox {" + " background-color: rgb(240, 240, 240);" + " color: rgb(50, 50, 50);" + "}" + "QMessageBox QLabel {" + " color: rgb(50, 50, 50);" + " font-size: 14px;" + " background-color: transparent;" + "}" + "QMessageBox QPushButton {" + " background-color: rgb(225, 225, 225);" + " color: rgb(50, 50, 50);" + " border: 1px solid rgb(180, 180, 180);" + " border-radius: 4px;" + " padding: 8px 16px;" + " font-size: 14px;" + " min-width: 80px;" + "}" + "QMessageBox QPushButton:hover {" + " background-color: rgb(200, 200, 200);" + "}" + "QMessageBox QPushButton:pressed {" + " background-color: rgb(180, 180, 180);" + "}" + ); + + int reply = confirmBox.exec(); + + if (reply == QMessageBox::Yes) { + // 执行删除操作 + if (deleteDeviceFromDatabase(selectedDevice.id)) { + QMessageBox successBox(dialog); + successBox.setWindowTitle("成功"); + successBox.setText("设备删除成功!"); + successBox.setIcon(QMessageBox::Information); + successBox.setStandardButtons(QMessageBox::Ok); + + // 设置成功对话框样式 + successBox.setStyleSheet( + "QMessageBox {" + " background-color: rgb(240, 240, 240);" + " color: rgb(50, 50, 50);" + "}" + "QMessageBox QLabel {" + " color: rgb(50, 50, 50);" + " font-size: 14px;" + " background-color: transparent;" + "}" + "QMessageBox QPushButton {" + " background-color: rgb(76, 175, 80);" + " color: white;" + " border: none;" + " border-radius: 4px;" + " padding: 8px 16px;" + " font-size: 14px;" + " min-width: 80px;" + " font-weight: bold;" + "}" + "QMessageBox QPushButton:hover {" + " background-color: rgb(67, 160, 71);" + "}" + "QMessageBox QPushButton:pressed {" + " background-color: rgb(56, 142, 60);" + "}" + ); + + successBox.exec(); + + // 刷新设备列表 + refreshDeviceList(); + + dialog->accept(); + } else { + QMessageBox errorBox(dialog); + errorBox.setWindowTitle("错误"); + errorBox.setText("删除设备失败!"); + errorBox.setIcon(QMessageBox::Warning); + errorBox.setStandardButtons(QMessageBox::Ok); + + // 设置错误对话框样式 + errorBox.setStyleSheet( + "QMessageBox {" + " background-color: rgb(240, 240, 240);" + " color: rgb(50, 50, 50);" + "}" + "QMessageBox QLabel {" + " color: rgb(50, 50, 50);" + " font-size: 14px;" + " background-color: transparent;" + "}" + "QMessageBox QPushButton {" + " background-color: rgb(244, 67, 54);" + " color: white;" + " border: none;" + " border-radius: 4px;" + " padding: 8px 16px;" + " font-size: 14px;" + " min-width: 80px;" + " font-weight: bold;" + "}" + "QMessageBox QPushButton:hover {" + " background-color: rgb(229, 57, 53);" + "}" + "QMessageBox QPushButton:pressed {" + " background-color: rgb(211, 47, 47);" + "}" + ); + + errorBox.exec(); + } + } + } else { + QMessageBox warningBox(dialog); + warningBox.setWindowTitle("提示"); + warningBox.setText("请先选择要删除的设备!"); + warningBox.setIcon(QMessageBox::Information); + warningBox.setStandardButtons(QMessageBox::Ok); + + // 设置提示对话框样式 + warningBox.setStyleSheet( + "QMessageBox {" + " background-color: rgb(240, 240, 240);" + " color: rgb(50, 50, 50);" + "}" + "QMessageBox QLabel {" + " color: rgb(50, 50, 50);" + " font-size: 14px;" + " background-color: transparent;" + "}" + "QMessageBox QPushButton {" + " background-color: rgb(33, 150, 243);" + " color: white;" + " border: none;" + " border-radius: 4px;" + " padding: 8px 16px;" + " font-size: 14px;" + " min-width: 80px;" + " font-weight: bold;" + "}" + "QMessageBox QPushButton:hover {" + " background-color: rgb(30, 136, 229);" + "}" + "QMessageBox QPushButton:pressed {" + " background-color: rgb(25, 118, 210);" + "}" + ); + + warningBox.exec(); + } + }); + + connect(cancelBtn, &QPushButton::clicked, dialog, &QDialog::reject); + + // 显示对话框 + dialog->exec(); + delete dialog; +} + void DeviceListPanel::onDeviceCardSelected(const QString &deviceId) { // 清除之前的选择 diff --git a/src/Client/src/ui/main/MainWindow.cpp b/src/Client/src/ui/main/MainWindow.cpp index 38078ed..02b9d22 100644 --- a/src/Client/src/ui/main/MainWindow.cpp +++ b/src/Client/src/ui/main/MainWindow.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -298,17 +300,103 @@ void MainWindow::onAddRobotClicked() { QDialog *dialog = new QDialog(this); dialog->setWindowTitle("添加机器人"); - dialog->resize(400, 300); + dialog->resize(450, 400); QVBoxLayout *layout = new QVBoxLayout(); // 添加输入字段 QFormLayout *formLayout = new QFormLayout(); + QLineEdit *deviceIdEdit = new QLineEdit(); QLineEdit *nameEdit = new QLineEdit(); QLineEdit *ipEdit = new QLineEdit(); + QSpinBox *portEdit = new QSpinBox(); + QDoubleSpinBox *longitudeEdit = new QDoubleSpinBox(); + QDoubleSpinBox *latitudeEdit = new QDoubleSpinBox(); + + // 设置端口号范围和默认值 + portEdit->setRange(1000, 65535); + portEdit->setValue(9090); + + // 从系统配置获取地图中心位置作为默认值 + double defaultLongitude = 116.4; // 默认经度 + double defaultLatitude = 39.9; // 默认纬度 + + // 尝试从数据库获取配置的地图中心位置 + QSqlDatabase configDb = QSqlDatabase::addDatabase("QMYSQL", "TempConnection_Config_Robot"); + configDb.setHostName("localhost"); + configDb.setPort(3306); + configDb.setDatabaseName("Client"); + configDb.setUserName("root"); + configDb.setPassword("hzk200407140238"); + + if (configDb.open()) { + QSqlQuery configQuery(configDb); + // 获取默认中心经度 + configQuery.prepare("SELECT config_value FROM system_config WHERE config_key = 'map.default_center_lon'"); + if (configQuery.exec() && configQuery.next()) { + defaultLongitude = configQuery.value(0).toDouble(); + } + // 获取默认中心纬度 + configQuery.prepare("SELECT config_value FROM system_config WHERE config_key = 'map.default_center_lat'"); + if (configQuery.exec() && configQuery.next()) { + defaultLatitude = configQuery.value(0).toDouble(); + } + configDb.close(); + } + QSqlDatabase::removeDatabase("TempConnection_Config_Robot"); + + // 设置经纬度范围和精度 + longitudeEdit->setRange(-180.0, 180.0); + longitudeEdit->setDecimals(6); + longitudeEdit->setValue(defaultLongitude); + longitudeEdit->setSuffix("°E"); // 添加经度单位 + longitudeEdit->setToolTip(QString("默认地图中心经度: %1°E").arg(defaultLongitude)); + + latitudeEdit->setRange(-90.0, 90.0); + latitudeEdit->setDecimals(6); + latitudeEdit->setValue(defaultLatitude); + latitudeEdit->setSuffix("°N"); // 添加纬度单位 + latitudeEdit->setToolTip(QString("默认地图中心纬度: %1°N").arg(defaultLatitude)); + + // 自动生成设备ID + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "TempConnection_DOG_ID_Add"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + QString suggestedId = "DOG001"; + if (db.open()) { + QSqlQuery query(db); + query.exec("SELECT COUNT(*) FROM devices WHERE device_type = 'dog'"); + if (query.next()) { + int count = query.value(0).toInt(); + suggestedId = QString("DOG%1").arg(count + 1, 3, 10, QChar('0')); + } + db.close(); + } + QSqlDatabase::removeDatabase("TempConnection_DOG_ID_Add"); + + deviceIdEdit->setText(suggestedId); + + // 设置输入框占位符和样式 + deviceIdEdit->setStyleSheet("QLineEdit { color: #333; } QLineEdit:focus { border: 2px solid #52C2F2; }"); + nameEdit->setPlaceholderText("请输入机器人名称"); + nameEdit->setStyleSheet("QLineEdit { color: #333; } QLineEdit:focus { border: 2px solid #52C2F2; }"); + ipEdit->setPlaceholderText("例如: 192.168.1.200"); + ipEdit->setStyleSheet("QLineEdit { color: #333; } QLineEdit:focus { border: 2px solid #52C2F2; }"); + + // 为经纬度输入框设置样式 + longitudeEdit->setStyleSheet("QDoubleSpinBox { color: #666; } QDoubleSpinBox:focus { border: 2px solid #52C2F2; }"); + latitudeEdit->setStyleSheet("QDoubleSpinBox { color: #666; } QDoubleSpinBox:focus { border: 2px solid #52C2F2; }"); + + formLayout->addRow("设备ID:", deviceIdEdit); formLayout->addRow("机器人名称:", nameEdit); formLayout->addRow("IP地址:", ipEdit); + formLayout->addRow("端口号:", portEdit); + formLayout->addRow("经度 (地图中心):", longitudeEdit); + formLayout->addRow("纬度 (地图中心):", latitudeEdit); layout->addLayout(formLayout); @@ -321,13 +409,17 @@ void MainWindow::onAddRobotClicked() buttonLayout->addWidget(cancelBtn); layout->addLayout(buttonLayout); - connect(confirmBtn, &QPushButton::clicked, [this, dialog, nameEdit, ipEdit]() { + connect(confirmBtn, &QPushButton::clicked, [this, dialog, deviceIdEdit, nameEdit, ipEdit, portEdit, longitudeEdit, latitudeEdit]() { + QString deviceId = deviceIdEdit->text().trimmed(); QString name = nameEdit->text().trimmed(); QString ip = ipEdit->text().trimmed(); + int port = portEdit->value(); + double longitude = longitudeEdit->value(); + double latitude = latitudeEdit->value(); - if (!name.isEmpty() && !ip.isEmpty()) { - // 保存到数据库 - if (addDeviceToDatabase(name, "dog", ip, 9090, 0)) { + if (!deviceId.isEmpty() && !name.isEmpty() && !ip.isEmpty()) { + // 保存到数据库,设备状态默认为0(离线) + if (addDeviceToDatabase(deviceId, name, "dog", ip, port, 0, longitude, latitude)) { m_robotList.append(qMakePair(name, ip)); QMessageBox::information(this, "成功", "机器人添加成功!"); @@ -395,17 +487,103 @@ void MainWindow::onAddUAVClicked() { QDialog *dialog = new QDialog(this); dialog->setWindowTitle("添加无人机"); - dialog->resize(400, 300); + dialog->resize(450, 400); QVBoxLayout *layout = new QVBoxLayout(); // 添加输入字段 QFormLayout *formLayout = new QFormLayout(); + QLineEdit *deviceIdEdit = new QLineEdit(); QLineEdit *nameEdit = new QLineEdit(); QLineEdit *ipEdit = new QLineEdit(); + QSpinBox *portEdit = new QSpinBox(); + QDoubleSpinBox *longitudeEdit = new QDoubleSpinBox(); + QDoubleSpinBox *latitudeEdit = new QDoubleSpinBox(); + + // 设置端口号范围和默认值 + portEdit->setRange(1000, 65535); + portEdit->setValue(8080); + + // 从系统配置获取地图中心位置作为默认值 + double defaultLongitude = 116.4; // 默认经度 + double defaultLatitude = 39.9; // 默认纬度 + + // 尝试从数据库获取配置的地图中心位置 + QSqlDatabase configDb = QSqlDatabase::addDatabase("QMYSQL", "TempConnection_Config"); + configDb.setHostName("localhost"); + configDb.setPort(3306); + configDb.setDatabaseName("Client"); + configDb.setUserName("root"); + configDb.setPassword("hzk200407140238"); + + if (configDb.open()) { + QSqlQuery configQuery(configDb); + // 获取默认中心经度 + configQuery.prepare("SELECT config_value FROM system_config WHERE config_key = 'map.default_center_lon'"); + if (configQuery.exec() && configQuery.next()) { + defaultLongitude = configQuery.value(0).toDouble(); + } + // 获取默认中心纬度 + configQuery.prepare("SELECT config_value FROM system_config WHERE config_key = 'map.default_center_lat'"); + if (configQuery.exec() && configQuery.next()) { + defaultLatitude = configQuery.value(0).toDouble(); + } + configDb.close(); + } + QSqlDatabase::removeDatabase("TempConnection_Config"); + + // 设置经纬度范围和精度 + longitudeEdit->setRange(-180.0, 180.0); + longitudeEdit->setDecimals(6); + longitudeEdit->setValue(defaultLongitude); + longitudeEdit->setSuffix("°E"); // 添加经度单位 + longitudeEdit->setToolTip(QString("默认地图中心经度: %1°E").arg(defaultLongitude)); + + latitudeEdit->setRange(-90.0, 90.0); + latitudeEdit->setDecimals(6); + latitudeEdit->setValue(defaultLatitude); + latitudeEdit->setSuffix("°N"); // 添加纬度单位 + latitudeEdit->setToolTip(QString("默认地图中心纬度: %1°N").arg(defaultLatitude)); + + // 自动生成设备ID + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "TempConnection_UAV_ID"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + + QString suggestedId = "UAV001"; + if (db.open()) { + QSqlQuery query(db); + query.exec("SELECT COUNT(*) FROM devices WHERE device_type = 'uav'"); + if (query.next()) { + int count = query.value(0).toInt(); + suggestedId = QString("UAV%1").arg(count + 1, 3, 10, QChar('0')); + } + db.close(); + } + QSqlDatabase::removeDatabase("TempConnection_UAV_ID"); + + deviceIdEdit->setText(suggestedId); + + // 设置输入框占位符和样式 + deviceIdEdit->setStyleSheet("QLineEdit { color: #333; } QLineEdit:focus { border: 2px solid #52C2F2; }"); + nameEdit->setPlaceholderText("请输入无人机名称"); + nameEdit->setStyleSheet("QLineEdit { color: #333; } QLineEdit:focus { border: 2px solid #52C2F2; }"); + ipEdit->setPlaceholderText("例如: 192.168.1.100"); + ipEdit->setStyleSheet("QLineEdit { color: #333; } QLineEdit:focus { border: 2px solid #52C2F2; }"); + // 为经纬度输入框设置样式 + longitudeEdit->setStyleSheet("QDoubleSpinBox { color: #666; } QDoubleSpinBox:focus { border: 2px solid #52C2F2; }"); + latitudeEdit->setStyleSheet("QDoubleSpinBox { color: #666; } QDoubleSpinBox:focus { border: 2px solid #52C2F2; }"); + + formLayout->addRow("设备ID:", deviceIdEdit); formLayout->addRow("无人机名称:", nameEdit); formLayout->addRow("IP地址:", ipEdit); + formLayout->addRow("端口号:", portEdit); + formLayout->addRow("经度 (地图中心):", longitudeEdit); + formLayout->addRow("纬度 (地图中心):", latitudeEdit); layout->addLayout(formLayout); @@ -418,13 +596,17 @@ void MainWindow::onAddUAVClicked() buttonLayout->addWidget(cancelBtn); layout->addLayout(buttonLayout); - connect(confirmBtn, &QPushButton::clicked, [this, dialog, nameEdit, ipEdit]() { + connect(confirmBtn, &QPushButton::clicked, [this, dialog, deviceIdEdit, nameEdit, ipEdit, portEdit, longitudeEdit, latitudeEdit]() { + QString deviceId = deviceIdEdit->text().trimmed(); QString name = nameEdit->text().trimmed(); QString ip = ipEdit->text().trimmed(); + int port = portEdit->value(); + double longitude = longitudeEdit->value(); + double latitude = latitudeEdit->value(); - if (!name.isEmpty() && !ip.isEmpty()) { - // 保存到数据库 - if (addDeviceToDatabase(name, "uav", ip, 8080, 0)) { + if (!deviceId.isEmpty() && !name.isEmpty() && !ip.isEmpty()) { + // 保存到数据库,设备状态默认为0(离线) + if (addDeviceToDatabase(deviceId, name, "uav", ip, port, 0, longitude, latitude)) { m_uavList.append(qMakePair(name, ip)); QMessageBox::information(this, "成功", "无人机添加成功!"); @@ -713,7 +895,7 @@ void MainWindow::initializeDeviceMarkersOnMap() } } -bool MainWindow::addDeviceToDatabase(const QString &name, const QString &type, const QString &ip, int port, int state) +bool MainWindow::addDeviceToDatabase(const QString &deviceId, const QString &name, const QString &type, const QString &ip, int port, int state, double longitude, double latitude) { QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "MainWindow_AddDevice_Connection"); db.setHostName("localhost"); @@ -729,43 +911,40 @@ bool MainWindow::addDeviceToDatabase(const QString &name, const QString &type, c QSqlQuery query(db); - // 生成唯一ID - QString deviceId; - if (type == "uav") { - // 查找现有UAV数量来生成ID - query.exec("SELECT COUNT(*) FROM devices WHERE device_type = 'uav'"); - int count = 0; - if (query.next()) { - count = query.value(0).toInt(); - } - deviceId = QString("UAV%1").arg(count + 1, 3, 10, QChar('0')); // UAV001, UAV002... - } else if (type == "dog") { - // 查找现有DOG数量来生成ID - query.exec("SELECT COUNT(*) FROM devices WHERE device_type = 'dog'"); - int count = 0; - if (query.next()) { - count = query.value(0).toInt(); - } - deviceId = QString("DOG%1").arg(count + 1, 3, 10, QChar('0')); // DOG001, DOG002... + // 检查设备ID是否已存在 + query.prepare("SELECT COUNT(*) FROM devices WHERE id = ?"); + query.addBindValue(deviceId); + if (!query.exec() || !query.next()) { + qWarning() << "Failed to check device ID uniqueness:" << query.lastError().text(); + db.close(); + return false; + } + + if (query.value(0).toInt() > 0) { + qWarning() << "Device ID already exists:" << deviceId; + db.close(); + return false; } // 插入新设备 QString sql = "INSERT INTO devices (id, name, device_type, state, ip, port, longitude, latitude, signal_strength, battery_level) " - "VALUES (?, ?, ?, ?, ?, ?, 0.0, 0.0, 0, 100)"; + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, 100)"; query.prepare(sql); query.addBindValue(deviceId); query.addBindValue(name); query.addBindValue(type); - query.addBindValue(state); // 默认状态为0(离线) + query.addBindValue(state); query.addBindValue(ip); query.addBindValue(port); + query.addBindValue(longitude); + query.addBindValue(latitude); bool success = query.exec(); if (!success) { qWarning() << "Failed to insert device into database:" << query.lastError().text(); } else { - qDebug() << "Successfully added device to database:" << deviceId << name; + qDebug() << "Successfully added device to database:" << deviceId << name << "at" << latitude << "," << longitude; } db.close();