|
|
|
@ -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 <QPushButton>
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
|
|
|
|
|
// Qt headers
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QTableWidgetItem>
|
|
|
|
|
#include <QHeaderView>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QFont>
|
|
|
|
|
#include <QPalette>
|
|
|
|
|
|
|
|
|
|
// Qt SQL headers
|
|
|
|
|
#include <QSqlDatabase>
|
|
|
|
|
#include <QSqlQuery>
|
|
|
|
|
#include <QSqlError>
|
|
|
|
|
|
|
|
|
|
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<QLabel*> labels = this->findChildren<QLabel*>();
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|