From 5bf62c410a638a919447474d6acce8e51d5c1ab0 Mon Sep 17 00:00:00 2001 From: zzh <838331105@qq.com> Date: Tue, 23 Sep 2025 09:44:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=81=AF=E6=9D=A1=E7=94=B5?= =?UTF-8?q?=E9=87=8F=E7=AE=A1=E7=90=86=E5=92=8C=E7=81=AF=E6=9D=A1=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=A4=87=E4=BB=BD=E6=81=A2=E5=A4=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lightstripmanager.cpp | 482 +++++++++++++++++++++++++++++++++++++- src/lightstripmanager.h | 22 ++ src/mainwindow.cpp | 9 +- 3 files changed, 504 insertions(+), 9 deletions(-) diff --git a/src/lightstripmanager.cpp b/src/lightstripmanager.cpp index c8987f4..27da0eb 100644 --- a/src/lightstripmanager.cpp +++ b/src/lightstripmanager.cpp @@ -1,6 +1,12 @@ #include "lightstripmanager.h" #include #include +#include +#include +#include +#include +#include +#include // 如果不再需要可以删除: #include LightStripManager::LightStripManager(QWidget *parent) @@ -11,6 +17,7 @@ LightStripManager::LightStripManager(QWidget *parent) { setupUI(); loadSnList(); + loadBatteryInfo(); // 加载电量信息 // 设置窗口属性 setWindowTitle("灯条SN管理器"); @@ -205,11 +212,42 @@ void LightStripManager::setupControlPanel() ); connect(refreshBtn, &QPushButton::clicked, this, &LightStripManager::onRefreshClicked); + // 新增:备份按钮 + backupBtn = new QPushButton("备份列表"); + backupBtn->setMinimumHeight(35); + backupBtn->setStyleSheet( + "QPushButton { " + " background-color: #673AB7; " + " color: white; " + " font-weight: bold; " + " border-radius: 6px; " + " padding: 8px 16px; " + "} " + "QPushButton:hover { background-color: #5E35B1; }" + ); + connect(backupBtn, &QPushButton::clicked, this, &LightStripManager::onBackupClicked); + + // 恢复备份按钮 + restoreBtn = new QPushButton("恢复备份"); + restoreBtn->setStyleSheet( + "QPushButton { " + " background-color: #FF9800; " + " color: white; " + " font-weight: bold; " + " border-radius: 6px; " + " padding: 8px 16px; " + "} " + "QPushButton:hover { background-color: #F57C00; }" + ); + connect(restoreBtn, &QPushButton::clicked, this, &LightStripManager::onRestoreClicked); + row1Layout->addWidget(selectAllBtn); row1Layout->addWidget(deselectAllBtn); row1Layout->addWidget(deleteSelectedBtn); row1Layout->addWidget(clearAllBtn); row1Layout->addWidget(refreshBtn); + row1Layout->addWidget(backupBtn); + row1Layout->addWidget(restoreBtn); row1Layout->addStretch(); // 统计标签 @@ -543,20 +581,31 @@ QWidget* LightStripManager::createSnWidget(const QString &sn) "QCheckBox { " " font-weight: bold; " " font-size: 12px; " + " spacing: 8px; " "} " "QCheckBox::indicator { " - " width: 20px; " - " height: 20px; " + " width: 18px; " + " height: 18px; " + " border-radius: 9px; " + " border: 2px solid #d0d0d0; " + " background-color: #ffffff; " "} " - "QCheckBox::indicator:unchecked { " - " border: 2px solid #ccc; " - " border-radius: 4px; " - " background-color: white; " + "QCheckBox::indicator:unchecked:hover { " + " border: 2px solid #4CAF50; " + " background-color: #f0f8f0; " "} " "QCheckBox::indicator:checked { " " border: 2px solid #4CAF50; " - " border-radius: 4px; " " background-color: #4CAF50; " + "} " + "QCheckBox::indicator:checked:hover { " + " background-color: #66BB6A; " + "} " + "QCheckBox::indicator:checked::after { " + " content: '✓'; " + " color: white; " + " font-size: 12px; " + " font-weight: bold; " "}" ); connect(checkBox, &QCheckBox::stateChanged, this, &LightStripManager::onCheckBoxStateChanged); @@ -580,9 +629,33 @@ QWidget* LightStripManager::createSnWidget(const QString &sn) ); snLabel->setWordWrap(true); + // 创建电量标签 + QLabel *batteryLabel = new QLabel("电量: --"); + batteryLabel->setAlignment(Qt::AlignCenter); + batteryLabel->setStyleSheet( + "QLabel { " + " color: #666; " + " font-size: 10px; " + " background-color: #f5f5f5; " + " border: 1px solid #ddd; " + " border-radius: 3px; " + " padding: 2px 4px; " + " min-height: 8px; " + "}" + ); + + // 存储电量标签的引用 + batteryLabels[sn] = batteryLabel; + + // 如果已有电量信息,则显示并设置正确颜色 + if (batteryInfoMap.contains(sn)) { + updateBatteryInfo(sn, batteryInfoMap[sn]); + } + // 添加到布局 itemLayout->addWidget(checkBox, 0, Qt::AlignCenter); itemLayout->addWidget(snLabel); + itemLayout->addWidget(batteryLabel); itemLayout->addStretch(); return lightStripWidget; @@ -660,12 +733,17 @@ void LightStripManager::onClearSnListClicked() lightStripCheckBoxes.clear(); uniqueSnSet.clear(); + // 清空电量相关数据 + batteryInfoMap.clear(); + batteryLabels.clear(); + // 更新显示 updateSnCount(); updateControlButtons(); // 保存设置 saveSnList(); + saveBatteryInfo(); // 保存电量信息 emit clearAllRequested(); } @@ -751,7 +829,12 @@ void LightStripManager::onDeleteSelectedClicked() // 从集合中移除SN QLabel *snLabel = lightStripWidgets[i]->findChild(); if (snLabel) { - uniqueSnSet.remove(snLabel->text()); + QString sn = snLabel->text(); + uniqueSnSet.remove(sn); + + // 清理电量相关数据 + batteryInfoMap.remove(sn); + batteryLabels.remove(sn); } // 删除widget @@ -861,6 +944,129 @@ void LightStripManager::onAddSnManuallyClicked() msgBox.exec(); } +void LightStripManager::onRestoreClicked() +{ + QString backupDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/backups"; + + // 打开文件选择对话框 + QString filePath = QFileDialog::getOpenFileName( + this, + "选择要恢复的备份文件", + backupDir, + "JSON备份文件 (*.json);;所有文件 (*)" + ); + + if (filePath.isEmpty()) { + return; // 用户取消了选择 + } + + // 加载备份文件 + if (loadBackupFile(filePath)) { + // 恢复成功,刷新显示 + applyResponsiveLayout(); + updateSnCount(); + updateControlButtons(); + + QMessageBox msgBox; + msgBox.setWindowTitle("恢复完成"); + msgBox.setText("备份文件已成功恢复!"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setStyleSheet( + "QMessageBox { " + " color: #000000; " + "} " + "QPushButton { " + " color: #000000; " + " background-color: #f0f0f0; " + " border: 1px solid #ccc; " + " border-radius: 4px; " + " padding: 6px 12px; " + " min-width: 60px; " + "} " + "QPushButton:hover { " + " background-color: #e0e0e0; " + "}" + ); + msgBox.exec(); + } else { + QMessageBox msgBox; + msgBox.setWindowTitle("恢复失败"); + msgBox.setText("无法读取或解析备份文件,请检查文件格式是否正确。"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStyleSheet( + "QMessageBox { " + " color: #000000; " + "} " + "QPushButton { " + " color: #000000; " + " background-color: #f0f0f0; " + " border: 1px solid #ccc; " + " border-radius: 4px; " + " padding: 6px 12px; " + " min-width: 60px; " + "} " + "QPushButton:hover { " + " background-color: #e0e0e0; " + "}" + ); + msgBox.exec(); + } +} + +void LightStripManager::onBackupClicked() +{ + if (uniqueSnSet.isEmpty()) { + QMessageBox msgBox; + msgBox.setWindowTitle("提示"); + msgBox.setText("当前没有灯条SN数据,无需备份。"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setStyleSheet( + "QMessageBox { " + " color: #000000; " + "} " + "QPushButton { " + " color: #000000; " + " background-color: #f0f0f0; " + " border: 1px solid #ccc; " + " border-radius: 4px; " + " padding: 6px 12px; " + " min-width: 60px; " + "} " + "QPushButton:hover { " + " background-color: #e0e0e0; " + "}" + ); + msgBox.exec(); + return; + } + + // 执行备份 + backupSnList(); + + // 显示备份成功消息 + QMessageBox msgBox; + msgBox.setWindowTitle("备份完成"); + msgBox.setText(QString("已成功备份 %1 个灯条SN到新文件。\n备份文件保存在应用数据目录的backups文件夹中。").arg(uniqueSnSet.size())); + msgBox.setIcon(QMessageBox::Information); + msgBox.setStyleSheet( + "QMessageBox { " + " color: #000000; " + "} " + "QPushButton { " + " color: #000000; " + " background-color: #f0f0f0; " + " border: 1px solid #ccc; " + " border-radius: 4px; " + " padding: 6px 12px; " + " min-width: 60px; " + "} " + "QPushButton:hover { " + " background-color: #e0e0e0; " + "}" + ); + msgBox.exec(); +} + void LightStripManager::onSearchTextChanged(const QString &text) { filterSnDisplay(text); @@ -1140,6 +1346,9 @@ void LightStripManager::saveSnList() QStringList snList = uniqueSnSet.values(); settings->setValue("lightStripSnList", snList); qDebug() << "已保存" << snList.size() << "个SN到lightStripSnList"; + + // 注释掉自动备份功能 + // backupSnList(); } // 强制同步到磁盘 @@ -1479,6 +1688,9 @@ void LightStripManager::syncSnListFromMainWindow(const QStringList &snList) lightStripCheckBoxes.clear(); uniqueSnSet.clear(); + // 清理电量标签映射(但保留电量信息数据) + batteryLabels.clear(); + // 批量添加但不保存 for (const QString &sn : snList) { if (!uniqueSnSet.contains(sn)) { @@ -1734,4 +1946,258 @@ void LightStripManager::setupIdentityBindingArea() // 加载保存的身份信息设置 loadIdentitySettings(); +} + +// 电量信息管理方法实现 +void LightStripManager::updateBatteryInfo(const QString &sn, const QString &batteryLevel) +{ + batteryInfoMap[sn] = batteryLevel; + + // 添加调试信息 + qDebug() << "[DEBUG] 更新电量信息 - SN:" << sn << "电量:" << batteryLevel; + + // 更新对应的电量标签 + if (batteryLabels.contains(sn)) { + batteryLabels[sn]->setText(QString("电量: %1").arg(batteryLevel)); + + // 根据电量设置不同颜色 + QString color = "#666"; + QString bgColor = "#fff3cd"; + QString borderColor = "#ffeaa7"; + + bool ok; + int level = batteryLevel.toInt(&ok); + qDebug() << "[DEBUG] 电量转换 - 原值:" << batteryLevel << "转换后:" << level << "转换成功:" << ok; + + if (ok) { + // 判断电量值是毫伏值还是百分比 + if (level > 100) { + qDebug() << "[DEBUG] 检测为毫伏值:" << level; + // 毫伏值,一般锂电池范围 2500-4200mV + if (level < 2600) { // 低电量 (<2.8V) + color = "#d32f2f"; + bgColor = "#ffebee"; + borderColor = "#f8bbd9"; + qDebug() << "[DEBUG] 设置为红色 - 低电量"; + } else if (level < 2900) { // 中等电量 (2.8V-2.9V) + color = "#f57c00"; + bgColor = "#fff3e0"; + borderColor = "#ffcc02"; + qDebug() << "[DEBUG] 设置为黄色 - 中等电量"; + } else { // 健康电量 (≥2.9V) + color = "#388e3c"; + bgColor = "#e8f5e8"; + borderColor = "#4caf50"; + qDebug() << "[DEBUG] 设置为绿色 - 健康电量"; + } + } else { + // 百分比值 (0-100) + if (level <= 20) { + color = "#d32f2f"; + bgColor = "#ffebee"; + borderColor = "#f8bbd9"; + } else if (level <= 50) { + color = "#f57c00"; + bgColor = "#fff3e0"; + borderColor = "#ffcc02"; + } else { + color = "#388e3c"; + bgColor = "#e8f5e8"; + borderColor = "#4caf50"; + } + } + } + + batteryLabels[sn]->setStyleSheet( + QString("QLabel { " + " color: %1; " + " font-size: 10px; " + " background-color: %2; " + " border: 1px solid %3; " + " border-radius: 3px; " + " padding: 2px 4px; " + " min-height: 8px; " + "}").arg(color, bgColor, borderColor) + ); + } + + // 保存电量信息 + saveBatteryInfo(); +} + +void LightStripManager::saveBatteryInfo() +{ + settings->beginGroup("BatteryInfo"); + settings->remove(""); // 清空组内所有键 + + for (auto it = batteryInfoMap.begin(); it != batteryInfoMap.end(); ++it) { + settings->setValue(it.key(), it.value()); + } + + settings->endGroup(); + settings->sync(); + + qDebug() << "保存电量信息,共" << batteryInfoMap.size() << "条记录"; +} + +void LightStripManager::loadBatteryInfo() +{ + batteryInfoMap.clear(); + + settings->beginGroup("BatteryInfo"); + QStringList keys = settings->allKeys(); + + for (const QString &key : keys) { + QString value = settings->value(key).toString(); + batteryInfoMap[key] = value; + + // 如果对应的电量标签存在,更新显示和颜色 + if (batteryLabels.contains(key)) { + updateBatteryInfo(key, value); + } + } + + settings->endGroup(); + + qDebug() << "加载电量信息,共" << batteryInfoMap.size() << "条记录"; +} + +// 新增:SN列表备份功能实现 +void LightStripManager::backupSnList() +{ + if (uniqueSnSet.isEmpty()) { + qDebug() << "SN列表为空,无需备份"; + return; + } + + createBackupFile(); +} + +void LightStripManager::createBackupFile() +{ + QString backupFileName = generateBackupFileName(); + QString backupDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/backups"; + + // 创建备份目录 + QDir dir; + if (!dir.exists(backupDir)) { + if (!dir.mkpath(backupDir)) { + qDebug() << "创建备份目录失败:" << backupDir; + return; + } + } + + QString backupFilePath = backupDir + "/" + backupFileName; + + // 创建备份文件内容 + QJsonObject backupData; + backupData["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate); + backupData["version"] = "1.0"; + backupData["count"] = uniqueSnSet.size(); + + QJsonArray snArray; + QStringList snList = uniqueSnSet.values(); + for (const QString &sn : snList) { + QJsonObject snObject; + snObject["sn"] = sn; + // 如果有电量信息,也一并备份 + if (batteryInfoMap.contains(sn)) { + snObject["battery"] = batteryInfoMap[sn]; + } + snArray.append(snObject); + } + backupData["lightstrips"] = snArray; + + // 写入文件 + QJsonDocument doc(backupData); + QFile file(backupFilePath); + if (file.open(QIODevice::WriteOnly)) { + file.write(doc.toJson()); + file.close(); + qDebug() << "SN列表备份成功:" << backupFilePath; + qDebug() << "备份了" << uniqueSnSet.size() << "个灯条SN"; + } else { + qDebug() << "创建备份文件失败:" << backupFilePath; + } +} + +QString LightStripManager::generateBackupFileName() const +{ + QDateTime now = QDateTime::currentDateTime(); + QString timestamp = now.toString("yyyyMMdd_hhmmss"); + return QString("lightstrip_sn_backup_%1.json").arg(timestamp); +} + +// 新增:SN列表恢复功能实现 +void LightStripManager::restoreSnList() +{ + QString backupDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/backups"; + + // 打开文件选择对话框 + QString filePath = QFileDialog::getOpenFileName( + this, + "选择要恢复的备份文件", + backupDir, + "JSON备份文件 (*.json);;所有文件 (*)" + ); + + if (!filePath.isEmpty()) { + loadBackupFile(filePath); + } +} + +bool LightStripManager::loadBackupFile(const QString &filePath) +{ + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "无法打开备份文件:" << filePath; + return false; + } + + QByteArray data = file.readAll(); + file.close(); + + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(data, &error); + + if (error.error != QJsonParseError::NoError) { + qDebug() << "解析JSON文件失败:" << error.errorString(); + return false; + } + + QJsonObject backupData = doc.object(); + + // 验证文件格式 + if (!backupData.contains("lightstrips") || !backupData["lightstrips"].isArray()) { + qDebug() << "备份文件格式不正确,缺少lightstrips数组"; + return false; + } + + // 清空当前数据 + uniqueSnSet.clear(); + batteryInfoMap.clear(); + + // 恢复SN列表和电量信息 + QJsonArray snArray = backupData["lightstrips"].toArray(); + for (const QJsonValue &value : snArray) { + QJsonObject snObject = value.toObject(); + if (snObject.contains("sn")) { + QString sn = snObject["sn"].toString(); + uniqueSnSet.insert(sn); + + // 如果有电量信息,也一并恢复 + if (snObject.contains("battery")) { + batteryInfoMap[sn] = snObject["battery"].toString(); + } + } + } + + // 保存恢复的数据 + saveSnList(); + saveBatteryInfo(); + + qDebug() << "从备份文件恢复了" << uniqueSnSet.size() << "个灯条SN"; + qDebug() << "恢复了" << batteryInfoMap.size() << "条电量信息"; + + return true; } \ No newline at end of file diff --git a/src/lightstripmanager.h b/src/lightstripmanager.h index 4fe0853..e00a35f 100644 --- a/src/lightstripmanager.h +++ b/src/lightstripmanager.h @@ -47,6 +47,11 @@ public: // 新增:设置主窗口引用 void setMainWindow(MainWindow *mainWindow); + + // 新增:电量信息管理方法 + void updateBatteryInfo(const QString &sn, const QString &batteryLevel); + void saveBatteryInfo(); + void loadBatteryInfo(); signals: void snSelectionChanged(const QStringList &selectedSns); @@ -71,6 +76,8 @@ private slots: void onSendLightAllClicked(); void onCheckBoxStateChanged(); void onRefreshClicked(); + void onBackupClicked(); // 新增:备份按钮槽函数 + void onRestoreClicked(); // 新增:恢复备份按钮槽函数 // 新增:身份信息绑定相关槽函数 void onBindIdentitySelectedClicked(); @@ -97,6 +104,15 @@ private: QWidget* createSnWidget(const QString &sn); void applyResponsiveLayout(); + // 新增:SN列表备份功能 + void backupSnList(); + void createBackupFile(); + QString generateBackupFileName() const; + + // 新增:SN列表恢复功能 + void restoreSnList(); + bool loadBackupFile(const QString &filePath); + // 新增:MQTT发送功能 void sendLightControlMessage(const QStringList &sns); @@ -122,6 +138,8 @@ private: QPushButton *deleteSelectedBtn; QPushButton *clearAllBtn; QPushButton *refreshBtn; + QPushButton *backupBtn; // 新增:备份按钮 + QPushButton *restoreBtn; // 新增:恢复备份按钮 QLineEdit *searchEdit; QLineEdit *manualSnEdit; QPushButton *addSnBtn; @@ -175,6 +193,10 @@ private: QString currentLabel1; QString currentLabel2; QString currentLabel3; + + // 新增:电量信息相关数据 + QMap batteryInfoMap; // SN -> 电量信息的映射 + QMap batteryLabels; // SN -> 电量标签的映射 public: enum MatchRule { EQUAL = 0, // = (00) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2465c94..d90ade8 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1012,7 +1012,8 @@ void MainWindow::processLightReportMessage(const QString &message) { for (const QJsonValue &lightValue : lightsArray) { QJsonObject lightObj = lightValue.toObject(); QString sn = lightObj["sn"].toString(); - messageDisplay->append(QString("[DEBUG] 处理灯条SN: %1").arg(sn)); + QString battery = lightObj["battery"].toString(); + messageDisplay->append(QString("[DEBUG] 处理灯条SN: %1, 电量: %2").arg(sn, battery)); if (!sn.isEmpty() && !uniqueSnSet.contains(sn)) { messageDisplay->append(QString("[DEBUG] 添加新SN到列表: %1").arg(sn)); @@ -1023,6 +1024,12 @@ void MainWindow::processLightReportMessage(const QString &message) { } else if (uniqueSnSet.contains(sn)) { messageDisplay->append(QString("[DEBUG] SN已存在,跳过: %1").arg(sn)); } + + // 更新电量信息到LightStripManager + if (!sn.isEmpty() && !battery.isEmpty() && lightStripManager) { + lightStripManager->updateBatteryInfo(sn, battery); + messageDisplay->append(QString("[DEBUG] 更新电量信息: SN=%1, 电量=%2").arg(sn, battery)); + } } if (newSnCount > 0) {