diff --git a/src/Client/.promptx/pouch.json b/src/Client/.promptx/pouch.json index 1a522c1..243cf8d 100644 --- a/src/Client/.promptx/pouch.json +++ b/src/Client/.promptx/pouch.json @@ -1,5 +1,5 @@ { - "currentState": "memory_saved", + "currentState": "role_activated_with_memory", "stateHistory": [ { "from": "initial", @@ -92,7 +92,31 @@ "--tags", "项目进展 Qt开发 BattlefieldExplorationSystem 设备管理 地图集成 Phase4完成" ] + }, + { + "from": "memory_saved", + "command": "init", + "timestamp": "2025-06-21T10:53:24.434Z", + "args": [ + { + "workingDirectory": "/home/hzk/Software_Architecture/src/Client" + } + ] + }, + { + "from": "initialized", + "command": "welcome", + "timestamp": "2025-06-21T10:53:28.298Z", + "args": [] + }, + { + "from": "role_discovery", + "command": "action", + "timestamp": "2025-06-21T10:53:32.598Z", + "args": [ + "qt-ui-developer" + ] } ], - "lastUpdated": "2025-06-19T10:34:01.577Z" + "lastUpdated": "2025-06-21T10:53:32.605Z" } diff --git a/src/Client/.promptx/resource/project.registry.json b/src/Client/.promptx/resource/project.registry.json index aa6af00..e740bfc 100644 --- a/src/Client/.promptx/resource/project.registry.json +++ b/src/Client/.promptx/resource/project.registry.json @@ -4,8 +4,8 @@ "metadata": { "version": "2.0.0", "description": "project 级资源注册表", - "createdAt": "2025-06-19T10:21:01.701Z", - "updatedAt": "2025-06-19T10:21:01.702Z", + "createdAt": "2025-06-21T10:53:24.437Z", + "updatedAt": "2025-06-21T10:53:24.439Z", "resourceCount": 1 }, "resources": [ @@ -17,9 +17,9 @@ "description": "专业角色,提供特定领域的专业能力", "reference": "@project://.promptx/resource/domain/qt-ui-developer/qt-ui-developer.role.md", "metadata": { - "createdAt": "2025-06-19T10:21:01.701Z", - "updatedAt": "2025-06-19T10:21:01.701Z", - "scannedAt": "2025-06-19T10:21:01.701Z" + "createdAt": "2025-06-21T10:53:24.438Z", + "updatedAt": "2025-06-21T10:53:24.438Z", + "scannedAt": "2025-06-21T10:53:24.438Z" } } ], diff --git a/src/Client/BattlefieldExplorationSystem b/src/Client/BattlefieldExplorationSystem index 5800020..e20da90 100755 Binary files a/src/Client/BattlefieldExplorationSystem and b/src/Client/BattlefieldExplorationSystem differ diff --git a/src/Client/forms/dialogs/DeviceDialog.ui b/src/Client/forms/dialogs/DeviceDialog.ui index e108ba4..51fe919 100644 --- a/src/Client/forms/dialogs/DeviceDialog.ui +++ b/src/Client/forms/dialogs/DeviceDialog.ui @@ -6,14 +6,539 @@ 0 0 - 1184 - 734 + 800 + 600 - Dialog + 设备详情 + + true + + + + 8 + + + 12 + + + 12 + + + 12 + + + 12 + + + + + 12 + + + + + + 64 + 64 + + + + + 64 + 64 + + + + 🤖 + + + Qt::AlignCenter + + + font-size: 48px; + + + + + + + 4 + + + + + + 18 + 75 + true + + + + 设备名称 + + + + + + + + 12 + + + + 设备ID: DEV001 + + + + + + + + 12 + + + + 设备类型: 无人机 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 30 + + + + + 75 + true + + + + 在线 + + + Qt::AlignCenter + + + color: white; background-color: green; border-radius: 15px; padding: 5px; + + + + + + + + + Qt::Horizontal + + + + + + + 0 + + + + 基本信息 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::AlignHCenter|Qt::AlignTop + + + 12 + + + 8 + + + 16 + + + 12 + + + 16 + + + 12 + + + + + IP地址: + + + + + + + 192.168.1.100 + + + + + + + 端口: + + + + + + + 8080 + + + + + + + 位置坐标: + + + + + + + 116.40, 39.90 + + + + + + + 信号强度: + + + + + + + 85 + + + %p% + + + + + + + 电池电量: + + + + + + + 95 + + + %p% + + + + + + + 固件版本: + + + + + + + v2.1.0 + + + + + + + + 状态信息 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::AlignHCenter|Qt::AlignTop + + + 12 + + + 8 + + + 16 + + + 12 + + + 16 + + + 12 + + + + + 最后心跳: + + + + + + + 2024-01-01 12:30:45 + + + + + + + 创建时间: + + + + + + + 2024-01-01 08:00:00 + + + + + + + 更新时间: + + + + + + + 2024-01-01 12:30:45 + + + + + + + 运行时长: + + + + + + + 4小时30分钟 + + + + + + + + 操作控制 + + + + 8 + + + 12 + + + 12 + + + 12 + + + 12 + + + + + 8 + + + + + 连接 + + + + + + + 断开 + + + + + + + 定位 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 操作日志 + + + + 6 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + true + + + QAbstractItemView::SelectRows + + + + 时间 + + + + + 操作 + + + + + 结果 + + + + + 操作员 + + + + + + + + + + + + + + + 8 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 刷新 + + + + + + + 关闭 + + + + + + - + + + closeButton + clicked() + DeviceDialog + accept() + + + 745 + 569 + + + 399 + 299 + + + + diff --git a/src/Client/include/ui/dialogs/DeviceDialog.h b/src/Client/include/ui/dialogs/DeviceDialog.h index 515851f..0ab6bff 100644 --- a/src/Client/include/ui/dialogs/DeviceDialog.h +++ b/src/Client/include/ui/dialogs/DeviceDialog.h @@ -2,6 +2,11 @@ #define DEVICEDIALOG_H #include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE namespace Ui { @@ -9,6 +14,11 @@ class DeviceDialog; } QT_END_NAMESPACE +/** + * @brief 设备详情对话框 + * + * 显示设备的详细信息,包括基本信息、状态信息和操作日志 + */ class DeviceDialog : public QDialog { Q_OBJECT @@ -17,10 +27,130 @@ public: explicit DeviceDialog(QWidget *parent = nullptr); ~DeviceDialog(); - void addDeviceInfo(QString name, QString type, QString status, QString position); + /** + * @brief 设置设备详细信息 + * @param deviceId 设备ID + * @param name 设备名称 + * @param type 设备类型 + * @param ip IP地址 + * @param port 端口号 + * @param longitude 经度 + * @param latitude 纬度 + * @param state 设备状态 + * @param signalStrength 信号强度 + * @param batteryLevel 电池电量 + * @param firmwareVersion 固件版本 + * @param lastHeartbeat 最后心跳时间 + * @param createdAt 创建时间 + * @param updatedAt 更新时间 + */ + void setDeviceInfo(const QString &deviceId, const QString &name, const QString &type, + const QString &ip, int port, double longitude, double latitude, + int state, int signalStrength, int batteryLevel, + const QString &firmwareVersion, const QString &lastHeartbeat, + const QString &createdAt, const QString &updatedAt); + + /** + * @brief 加载设备操作日志 + * @param deviceId 设备ID + */ + void loadOperationLogs(const QString &deviceId); + + /** + * @brief 刷新设备信息 + */ + void refreshDeviceInfo(); + +public slots: + /** + * @brief 连接设备 + */ + void onConnectClicked(); + + /** + * @brief 断开设备 + */ + void onDisconnectClicked(); + + /** + * @brief 定位设备 + */ + void onLocateClicked(); + + /** + * @brief 刷新按钮点击 + */ + void onRefreshClicked(); + +signals: + /** + * @brief 请求连接设备信号 + * @param deviceId 设备ID + */ + void deviceConnectRequested(const QString &deviceId); + + /** + * @brief 请求断开设备信号 + * @param deviceId 设备ID + */ + void deviceDisconnectRequested(const QString &deviceId); + + /** + * @brief 请求定位设备信号 + * @param deviceId 设备ID + */ + void deviceLocationRequested(const QString &deviceId); + +private: + /** + * @brief 初始化UI样式 + */ + void setupStyle(); + + /** + * @brief 连接信号槽 + */ + void connectSignals(); + + /** + * @brief 根据设备类型设置图标 + * @param type 设备类型 + */ + void setDeviceIcon(const QString &type); + + /** + * @brief 根据状态设置状态标签 + * @param state 状态值 + */ + void setStatusLabel(int state); + + /** + * @brief 计算运行时长 + * @param createdTime 创建时间 + * @return 运行时长字符串 + */ + QString calculateWorkingTime(const QString &createdTime); + + /** + * @brief 初始化操作日志表格 + */ + void initializeOperationLogTable(); + + /** + * @brief 记录操作日志 + * @param operation 操作类型 + * @param operatorName 操作员名称 + */ + void logOperation(const QString &operation, const QString &operatorName); + + /** + * @brief 设置高对比度字体 + */ + void setHighContrastFonts(); private: Ui::DeviceDialog *ui; + QString m_currentDeviceId; ///< 当前显示的设备ID }; #endif // DEVICEDIALOG_H \ No newline at end of file diff --git a/src/Client/src/ui/dialogs/DeviceDialog.cpp b/src/Client/src/ui/dialogs/DeviceDialog.cpp index 24e1d12..b30563a 100644 --- a/src/Client/src/ui/dialogs/DeviceDialog.cpp +++ b/src/Client/src/ui/dialogs/DeviceDialog.cpp @@ -1,18 +1,52 @@ +/** + * @file DeviceDialog.cpp + * @brief 设备详情对话框实现 + * @author CasualtySightPlus Team + * @date 2024-01-01 + * @version 2.0 + */ + #include "ui/dialogs/DeviceDialog.h" #include "build/ui_DeviceDialog.h" -#include -#include -#include + +// Qt headers +#include +#include +#include +#include +#include +#include +#include + +// Qt SQL headers +#include +#include +#include DeviceDialog::DeviceDialog(QWidget *parent) : QDialog(parent), ui(new Ui::DeviceDialog) { ui->setupUi(this); - setWindowTitle("机器人列表"); - setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); - setAttribute(Qt::WA_TranslucentBackground); - setStyleSheet("background-color: rgba(255, 255, 255, 150);"); // 设置透明度为 150 的白色背景 + + // 设置窗口属性 + setWindowTitle("设备详情"); + setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + setModal(true); + + // 初始化UI样式 + setupStyle(); + + // 连接信号槽 + connectSignals(); + + // 初始化操作日志表格 + initializeOperationLogTable(); + + // 强制设置高对比度字体 + setHighContrastFonts(); + + qDebug() << "DeviceDialog created successfully"; } DeviceDialog::~DeviceDialog() @@ -20,18 +54,606 @@ DeviceDialog::~DeviceDialog() delete ui; } -void DeviceDialog::addDeviceInfo(QString name, QString type, QString status, QString position) +void DeviceDialog::setDeviceInfo(const QString &deviceId, const QString &name, const QString &type, + const QString &ip, int port, double longitude, double latitude, + int state, int signalStrength, int batteryLevel, + const QString &firmwareVersion, const QString &lastHeartbeat, + const QString &createdAt, const QString &updatedAt) +{ + m_currentDeviceId = deviceId; + + // 设置设备图标 + setDeviceIcon(type); + + // 设置基本信息 + ui->deviceNameLabel->setText(name); + ui->deviceIdLabel->setText(QString("设备ID: %1").arg(deviceId)); + + QString typeDisplayName = (type == "uav") ? "无人机" : + (type == "dog") ? "地面机器人" : "未知设备"; + ui->deviceTypeLabel->setText(QString("设备类型: %1").arg(typeDisplayName)); + + // 设置状态标签 + setStatusLabel(state); + + // 定义数值标签的强对比度样式 + QString valueStyle = "QLabel {" + " color: rgb(255, 255, 255);" // 纯白色字体 + " background: rgba(100, 200, 255, 0.2);" + " border: 1px solid rgba(100, 200, 255, 0.4);" + " border-radius: 4px;" + " padding: 4px 8px;" + " font-weight: bold;" + " font-size: 13px;" + "}"; + + // 设置网络信息 - 直接应用样式 + ui->ipAddressValue->setText(ip); + ui->ipAddressValue->setStyleSheet(valueStyle); + ui->portValue->setText(QString::number(port)); + ui->portValue->setStyleSheet(valueStyle); + + // 设置位置信息 - 直接应用样式 + ui->locationValue->setText(QString("%1, %2").arg(longitude, 0, 'f', 6).arg(latitude, 0, 'f', 6)); + ui->locationValue->setStyleSheet(valueStyle); + + // 设置信号强度和电池电量 + ui->signalStrengthBar->setValue(signalStrength); + ui->batteryLevelBar->setValue(batteryLevel); + + // 设置固件版本 - 直接应用样式 + ui->firmwareValue->setText(firmwareVersion.isEmpty() ? "未知" : firmwareVersion); + ui->firmwareValue->setStyleSheet(valueStyle); + + // 设置时间信息 - 直接应用样式 + ui->lastHeartbeatValue->setText(lastHeartbeat.isEmpty() ? "无数据" : lastHeartbeat); + ui->lastHeartbeatValue->setStyleSheet(valueStyle); + ui->createdAtValue->setText(createdAt); + ui->createdAtValue->setStyleSheet(valueStyle); + ui->updatedAtValue->setText(updatedAt); + ui->updatedAtValue->setStyleSheet(valueStyle); + + // 计算并设置运行时长 - 直接应用样式 + ui->workingTimeValue->setText(calculateWorkingTime(createdAt)); + ui->workingTimeValue->setStyleSheet(valueStyle); + + // 设置所有标签的样式 + QString labelStyle = "QLabel {" + " color: rgb(255, 255, 255);" // 纯白色 + " font-weight: 600;" + " font-size: 13px;" + "}"; + + // 应用到所有标签标题 + ui->label_ip->setStyleSheet(labelStyle); + ui->label_port->setStyleSheet(labelStyle); + ui->label_location->setStyleSheet(labelStyle); + ui->label_signal->setStyleSheet(labelStyle); + ui->label_battery->setStyleSheet(labelStyle); + ui->label_firmware->setStyleSheet(labelStyle); + ui->label_lastHeartbeat->setStyleSheet(labelStyle); + ui->label_createdAt->setStyleSheet(labelStyle); + ui->label_updatedAt->setStyleSheet(labelStyle); + ui->label_workingTime->setStyleSheet(labelStyle); + + // 设置头部标签样式 + QString headerStyle = "QLabel {" + " color: rgb(255, 255, 255);" + " font-weight: bold;" + "}"; + ui->deviceNameLabel->setStyleSheet(headerStyle); + ui->deviceIdLabel->setStyleSheet(headerStyle); + ui->deviceTypeLabel->setStyleSheet(headerStyle); + + // 加载操作日志 + loadOperationLogs(deviceId); + + qDebug() << "Device info set for:" << deviceId << name; +} + +void DeviceDialog::loadOperationLogs(const QString &deviceId) +{ + // 连接数据库 + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DeviceDialog_LogQuery"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + + if (!db.open()) { + qWarning() << "Failed to connect to database for operation logs:" << db.lastError().text(); + return; + } + + // 查询操作日志 + QSqlQuery query(db); + QString sql = "SELECT operation_time, operation, operation_result, operator " + "FROM device_operation_logs " + "WHERE device_id = ? " + "ORDER BY operation_time DESC " + "LIMIT 50"; + + query.prepare(sql); + query.addBindValue(deviceId); + + if (!query.exec()) { + qWarning() << "Failed to query operation logs:" << query.lastError().text(); + db.close(); + return; + } + + // 清空表格 + ui->operationLogTable->setRowCount(0); + + // 填充数据 + int row = 0; + while (query.next()) { + ui->operationLogTable->insertRow(row); + + QString operationTime = query.value(0).toString(); + QString operation = query.value(1).toString(); + QString result = query.value(2).toString(); + QString operatorName = query.value(3).toString(); + + ui->operationLogTable->setItem(row, 0, new QTableWidgetItem(operationTime)); + ui->operationLogTable->setItem(row, 1, new QTableWidgetItem(operation)); + ui->operationLogTable->setItem(row, 2, new QTableWidgetItem(result)); + ui->operationLogTable->setItem(row, 3, new QTableWidgetItem(operatorName.isEmpty() ? "系统" : operatorName)); + + // 根据操作结果设置颜色 + QTableWidgetItem *resultItem = ui->operationLogTable->item(row, 2); + if (result == "success") { + resultItem->setBackground(QBrush(QColor(144, 238, 144))); // 浅绿色 + } else if (result == "failed") { + resultItem->setBackground(QBrush(QColor(255, 182, 193))); // 浅红色 + } else if (result == "timeout") { + resultItem->setBackground(QBrush(QColor(255, 255, 224))); // 浅黄色 + } + + row++; + } + + db.close(); + + qDebug() << "Loaded" << row << "operation log entries for device" << deviceId; +} + +void DeviceDialog::refreshDeviceInfo() +{ + if (m_currentDeviceId.isEmpty()) { + return; + } + + // 连接数据库 + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DeviceDialog_Refresh"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + + if (!db.open()) { + qWarning() << "Failed to connect to database for refresh:" << db.lastError().text(); + QMessageBox::warning(this, "错误", "无法连接到数据库"); + return; + } + + // 查询设备信息 + QSqlQuery query(db); + QString sql = "SELECT name, device_type, ip, port, longitude, latitude, state, " + "signal_strength, battery_level, firmware_version, last_heartbeat, " + "created_at, updated_at " + "FROM devices WHERE id = ?"; + + query.prepare(sql); + query.addBindValue(m_currentDeviceId); + + if (!query.exec() || !query.next()) { + qWarning() << "Failed to query device info:" << query.lastError().text(); + QMessageBox::warning(this, "错误", "无法获取设备信息"); + db.close(); + return; + } + + // 更新设备信息 + QString name = query.value("name").toString(); + QString type = query.value("device_type").toString(); + QString ip = query.value("ip").toString(); + int port = query.value("port").toInt(); + double longitude = query.value("longitude").toDouble(); + double latitude = query.value("latitude").toDouble(); + int state = query.value("state").toInt(); + int signalStrength = query.value("signal_strength").toInt(); + int batteryLevel = query.value("battery_level").toInt(); + QString firmwareVersion = query.value("firmware_version").toString(); + QString lastHeartbeat = query.value("last_heartbeat").toString(); + QString createdAt = query.value("created_at").toString(); + QString updatedAt = query.value("updated_at").toString(); + + db.close(); + + // 更新显示 + setDeviceInfo(m_currentDeviceId, name, type, ip, port, longitude, latitude, + state, signalStrength, batteryLevel, firmwareVersion, + lastHeartbeat, createdAt, updatedAt); + + QMessageBox::information(this, "刷新完成", "设备信息已更新"); +} + +void DeviceDialog::onConnectClicked() +{ + if (!m_currentDeviceId.isEmpty()) { + emit deviceConnectRequested(m_currentDeviceId); + + // 记录操作日志 + logOperation("connect", "用户操作"); + } +} + +void DeviceDialog::onDisconnectClicked() +{ + if (!m_currentDeviceId.isEmpty()) { + emit deviceDisconnectRequested(m_currentDeviceId); + + // 记录操作日志 + logOperation("disconnect", "用户操作"); + } +} + +void DeviceDialog::onLocateClicked() +{ + if (!m_currentDeviceId.isEmpty()) { + emit deviceLocationRequested(m_currentDeviceId); + + // 记录操作日志 + logOperation("locate", "用户操作"); + } +} + +void DeviceDialog::onRefreshClicked() +{ + refreshDeviceInfo(); +} + +void DeviceDialog::setupStyle() +{ + // 设置对话框整体样式 + setStyleSheet( + "QDialog {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 rgb(20, 30, 40), stop:1 rgb(30, 40, 50));" + " color: rgb(255, 255, 255);" // 纯白色字体 + "}" + + // 标签样式 - 最强对比度 + "QLabel {" + " color: rgb(255, 255, 255);" // 纯白色 + " background: transparent;" + " font-size: 14px;" // 增大字体 + " font-weight: 600;" // 加粗 + " padding: 3px 6px;" // 适当内边距 + "}" + + // 表单布局样式 - 更紧凑 + "QFormLayout {" + " spacing: 8px;" // 减少行间距 + "}" + + // 数值标签样式 - 突出显示 + "QLabel[class='value-label'] {" + " color: rgb(100, 200, 255);" // 蓝色突出显示数值 + " font-weight: 600;" + " background: rgba(100, 200, 255, 0.1);" + " border: 1px solid rgba(100, 200, 255, 0.2);" + " border-radius: 3px;" + " padding: 4px 8px;" + " margin: 1px;" + "}" + + // 进度条样式 - 更清晰 + "QProgressBar {" + " border: 2px solid rgba(100, 200, 255, 0.4);" + " border-radius: 6px;" + " text-align: center;" + " background-color: rgba(45, 65, 95, 0.4);" + " color: rgb(255, 255, 255);" // 白色文字 + " font-weight: bold;" + " font-size: 12px;" + " min-height: 20px;" // 减少高度使更紧凑 + " max-height: 20px;" + "}" + "QProgressBar::chunk {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0," + " stop:0 rgba(100, 200, 255, 0.8)," + " stop:1 rgba(50, 150, 255, 1.0));" + " border-radius: 4px;" + "}" + + // 按钮样式 - 更清晰 + "QPushButton {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(45, 65, 95, 0.9), " + " stop:1 rgba(25, 40, 65, 0.9));" + " color: rgb(255, 255, 255);" // 纯白字体 + " border: 2px solid rgba(100, 200, 255, 0.6);" + " padding: 6px 12px;" // 减少按钮内边距 + " border-radius: 5px;" + " font-weight: bold;" + " font-size: 12px;" + " min-height: 24px;" // 减少按钮高度 + "}" + "QPushButton:hover {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(100, 200, 255, 0.8), " + " stop:1 rgba(45, 120, 180, 0.8));" + " border: 2px solid rgba(100, 200, 255, 1.0);" + " color: rgb(255, 255, 255);" + "}" + "QPushButton:pressed {" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 rgba(100, 200, 255, 1.0), " + " stop:1 rgba(45, 120, 180, 1.0));" + "}" + + // 选项卡样式 - 更清晰 + "QTabWidget::pane {" + " border: 1px solid rgba(100, 200, 255, 0.4);" + " background: rgba(15, 22, 32, 0.6);" + " margin-top: 2px;" // 减少顶部边距 + "}" + "QTabBar::tab {" + " background: rgba(45, 65, 95, 0.7);" + " color: rgb(220, 230, 242);" + " padding: 6px 12px;" // 减少选项卡内边距 + " margin-right: 1px;" + " border-top-left-radius: 4px;" + " border-top-right-radius: 4px;" + " font-size: 12px;" + " font-weight: 600;" + " min-height: 20px;" + "}" + "QTabBar::tab:selected {" + " background: rgba(100, 200, 255, 0.9);" + " color: rgb(255, 255, 255);" + "}" + "QTabBar::tab:hover:!selected {" + " background: rgba(100, 200, 255, 0.5);" + "}" + + // 表格样式 - 最强对比度 + "QTableWidget {" + " background-color: rgba(10, 15, 25, 0.95);" + " alternate-background-color: rgba(20, 25, 35, 0.95);" + " gridline-color: rgba(100, 200, 255, 0.4);" + " color: rgb(255, 255, 255);" // 纯白色 + " font-size: 12px;" // 增大字体 + " font-weight: 500;" + " selection-background-color: rgba(100, 200, 255, 0.6);" + "}" + "QTableWidget::item {" + " padding: 4px 6px;" // 减少单元格内边距 + " border: none;" + "}" + "QHeaderView::section {" + " background-color: rgba(45, 65, 95, 0.9);" + " color: rgb(255, 255, 255);" + " padding: 6px 8px;" // 减少表头内边距 + " border: 1px solid rgba(100, 200, 255, 0.4);" + " font-weight: bold;" + " font-size: 11px;" + "}" + + // 分组框样式 + "QGroupBox {" + " color: rgb(240, 248, 255);" + " font-weight: bold;" + " font-size: 12px;" + " border: 2px solid rgba(100, 200, 255, 0.4);" + " border-radius: 5px;" + " margin-top: 8px;" // 减少顶部边距 + " padding-top: 5px;" + "}" + "QGroupBox::title {" + " subcontrol-origin: margin;" + " left: 8px;" + " padding: 0 4px 0 4px;" + " color: rgb(100, 200, 255);" + "}" + ); +} + +void DeviceDialog::connectSignals() +{ + // 连接按钮信号 + connect(ui->connectButton, &QPushButton::clicked, this, &DeviceDialog::onConnectClicked); + connect(ui->disconnectButton, &QPushButton::clicked, this, &DeviceDialog::onDisconnectClicked); + connect(ui->locateButton, &QPushButton::clicked, this, &DeviceDialog::onLocateClicked); + connect(ui->refreshButton, &QPushButton::clicked, this, &DeviceDialog::onRefreshClicked); +} + +void DeviceDialog::setDeviceIcon(const QString &type) +{ + if (type == "uav") { + ui->deviceIconLabel->setText("🚁"); + ui->deviceIconLabel->setStyleSheet("font-size: 48px; color: #52C2F2;"); + } else if (type == "dog") { + ui->deviceIconLabel->setText("🤖"); + ui->deviceIconLabel->setStyleSheet("font-size: 48px; color: #52C2F2;"); + } else { + ui->deviceIconLabel->setText("❓"); + ui->deviceIconLabel->setStyleSheet("font-size: 48px; color: #888888;"); + } +} + +void DeviceDialog::setStatusLabel(int state) { - // 创建一个新的机器人信息部件 - QWidget *widget = new QWidget(); - QVBoxLayout *layout = new QVBoxLayout(widget); - layout->addWidget(new QLabel("机器人名称:" + name)); - layout->addWidget(new QLabel("机器人类型:" + type)); - layout->addWidget(new QLabel("机器人状态:" + status)); - layout->addWidget(new QLabel("机器人位置:" + position)); - layout->addStretch(); - widget->setLayout(layout); + QString statusText; + QString statusStyle; + + switch (state) { + case 0: // 离线 + statusText = "离线"; + statusStyle = "color: white; background-color: #FF6B6B; border-radius: 15px; padding: 5px;"; + break; + case 1: // 在线 + statusText = "在线"; + statusStyle = "color: white; background-color: #4ECDC4; border-radius: 15px; padding: 5px;"; + break; + case 2: // 工作中 + statusText = "工作中"; + statusStyle = "color: white; background-color: #45B7D1; border-radius: 15px; padding: 5px;"; + break; + case 3: // 错误 + statusText = "错误"; + statusStyle = "color: white; background-color: #FF8C42; border-radius: 15px; padding: 5px;"; + break; + default: + statusText = "未知"; + statusStyle = "color: white; background-color: #888888; border-radius: 15px; padding: 5px;"; + break; + } + + ui->deviceStatusLabel->setText(statusText); + ui->deviceStatusLabel->setStyleSheet(statusStyle); +} + +QString DeviceDialog::calculateWorkingTime(const QString &createdTime) +{ + if (createdTime.isEmpty()) { + return "未知"; + } + + QDateTime created = QDateTime::fromString(createdTime, "yyyy-MM-dd hh:mm:ss"); + if (!created.isValid()) { + return "未知"; + } + + QDateTime now = QDateTime::currentDateTime(); + qint64 secondsElapsed = created.secsTo(now); + + int days = secondsElapsed / (24 * 3600); + int hours = (secondsElapsed % (24 * 3600)) / 3600; + int minutes = (secondsElapsed % 3600) / 60; + + QString result; + if (days > 0) { + result += QString("%1天").arg(days); + } + if (hours > 0) { + result += QString("%1小时").arg(hours); + } + if (minutes > 0) { + result += QString("%1分钟").arg(minutes); + } + + return result.isEmpty() ? "刚刚创建" : result; +} - // 将机器人信息部件添加到布局中 - layout->addWidget(widget); +void DeviceDialog::initializeOperationLogTable() +{ + // 设置表格列宽 + ui->operationLogTable->horizontalHeader()->setStretchLastSection(true); + ui->operationLogTable->setColumnWidth(0, 150); // 时间列 + ui->operationLogTable->setColumnWidth(1, 100); // 操作列 + ui->operationLogTable->setColumnWidth(2, 80); // 结果列 + + // 设置表格属性 + ui->operationLogTable->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->operationLogTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->operationLogTable->setSortingEnabled(false); +} + +void DeviceDialog::logOperation(const QString &operation, const QString &operatorName) +{ + // 记录操作到数据库 + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DeviceDialog_LogOperation"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + + if (!db.open()) { + qWarning() << "Failed to connect to database for logging operation:" << db.lastError().text(); + return; + } + + QSqlQuery query(db); + QString sql = "INSERT INTO device_operation_logs (device_id, device_type, operation, operation_result, operator) " + "VALUES (?, (SELECT device_type FROM devices WHERE id = ? LIMIT 1), ?, 'success', ?)"; + + query.prepare(sql); + query.addBindValue(m_currentDeviceId); + query.addBindValue(m_currentDeviceId); + query.addBindValue(operation); + query.addBindValue(operatorName); + + if (!query.exec()) { + qWarning() << "Failed to log operation:" << query.lastError().text(); + } else { + qDebug() << "Operation logged:" << operation << "for device" << m_currentDeviceId; + } + + db.close(); +} + +void DeviceDialog::setHighContrastFonts() +{ + // 创建高对比度字体 + QFont boldFont = this->font(); + boldFont.setPointSize(13); + boldFont.setWeight(QFont::Bold); + + QFont normalFont = this->font(); + normalFont.setPointSize(12); + normalFont.setWeight(QFont::Medium); + + // 创建调色板确保文字是白色 + QPalette palette = this->palette(); + palette.setColor(QPalette::WindowText, QColor(255, 255, 255)); + palette.setColor(QPalette::Text, QColor(255, 255, 255)); + palette.setColor(QPalette::ButtonText, QColor(255, 255, 255)); + + // 应用到所有控件 + this->setPalette(palette); + + // 设置字体到对话框 + this->setFont(normalFont); + + // 递归设置所有子控件的字体和颜色 + QList labels = this->findChildren(); + for (QLabel* label : labels) { + label->setPalette(palette); + if (label->objectName().contains("Value") || + label->objectName().contains("deviceName") || + label->objectName().contains("deviceId") || + label->objectName().contains("deviceType")) { + label->setFont(boldFont); + } else { + label->setFont(normalFont); + } + + // 强制设置样式 + label->setStyleSheet("QLabel { color: rgb(255, 255, 255); font-weight: bold; }"); + } + + // 设置表格字体 + if (ui->operationLogTable) { + ui->operationLogTable->setFont(normalFont); + ui->operationLogTable->setPalette(palette); + ui->operationLogTable->setStyleSheet( + "QTableWidget { " + " color: rgb(255, 255, 255); " + " font-weight: 500; " + " background-color: rgba(10, 15, 25, 0.95); " + "} " + "QTableWidget::item { " + " color: rgb(255, 255, 255); " + " font-weight: 500; " + "}" + ); + } + + qDebug() << "High contrast fonts applied"; } diff --git a/src/Client/src/ui/main/MainWindow.cpp b/src/Client/src/ui/main/MainWindow.cpp index 02b9d22..234832e 100644 --- a/src/Client/src/ui/main/MainWindow.cpp +++ b/src/Client/src/ui/main/MainWindow.cpp @@ -8,6 +8,7 @@ #include "ui/main/MainWindow.h" #include "build/ui_MainWindow.h" +#include "ui/dialogs/DeviceDialog.h" // Qt GUI头文件 #include @@ -794,10 +795,79 @@ void MainWindow::onDeviceLocationRequested(const QString &deviceId) void MainWindow::onDeviceDetailsRequested(const QString &deviceId) { qDebug() << "Device details requested for:" << deviceId; - // TODO: 实现设备详情显示逻辑 - // 例如:打开设备详情对话框、显示设备参数等 - QMessageBox::information(this, "设备详情", - QString("设备详情功能正在开发中\n设备ID: %1").arg(deviceId)); + + // 连接数据库获取设备详细信息 + QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "MainWindow_DeviceDetails"); + db.setHostName("localhost"); + db.setPort(3306); + db.setDatabaseName("Client"); + db.setUserName("root"); + db.setPassword("hzk200407140238"); + + if (!db.open()) { + qWarning() << "Failed to connect to database for device details:" << db.lastError().text(); + QMessageBox::warning(this, "错误", "无法连接到数据库"); + return; + } + + // 查询设备信息 + QSqlQuery query(db); + QString sql = "SELECT name, device_type, ip, port, longitude, latitude, state, " + "signal_strength, battery_level, firmware_version, last_heartbeat, " + "created_at, updated_at " + "FROM devices WHERE id = ?"; + + query.prepare(sql); + query.addBindValue(deviceId); + + if (!query.exec() || !query.next()) { + qWarning() << "Failed to query device details:" << query.lastError().text(); + QMessageBox::warning(this, "错误", + QString("无法找到设备信息\n设备ID: %1").arg(deviceId)); + db.close(); + return; + } + + // 获取设备信息 + QString name = query.value("name").toString(); + QString type = query.value("device_type").toString(); + QString ip = query.value("ip").toString(); + int port = query.value("port").toInt(); + double longitude = query.value("longitude").toDouble(); + double latitude = query.value("latitude").toDouble(); + int state = query.value("state").toInt(); + int signalStrength = query.value("signal_strength").toInt(); + int batteryLevel = query.value("battery_level").toInt(); + QString firmwareVersion = query.value("firmware_version").toString(); + QString lastHeartbeat = query.value("last_heartbeat").toString(); + QString createdAt = query.value("created_at").toString(); + QString updatedAt = query.value("updated_at").toString(); + + db.close(); + + // 创建并显示设备详情对话框 + DeviceDialog *dialog = new DeviceDialog(this); + + // 设置设备信息 + dialog->setDeviceInfo(deviceId, name, type, ip, port, longitude, latitude, + state, signalStrength, batteryLevel, firmwareVersion, + lastHeartbeat, createdAt, updatedAt); + + // 连接设备操作信号 + connect(dialog, &DeviceDialog::deviceConnectRequested, + this, &MainWindow::onDeviceControlRequested); + connect(dialog, &DeviceDialog::deviceDisconnectRequested, + this, &MainWindow::onDeviceControlRequested); + connect(dialog, &DeviceDialog::deviceLocationRequested, + this, &MainWindow::onDeviceLocationRequested); + + // 显示对话框 + dialog->exec(); + + // 清理 + dialog->deleteLater(); + + qDebug() << "Device details dialog shown for:" << deviceId; } void MainWindow::onAddDeviceRequested(const QString &deviceType)