Browse Source

update:添加OCPP ChargingProfiles配置页面,优化显示逻辑

Bigpang_1 1 tháng trước cách đây
mục cha
commit
a3b44708ed
76 tập tin đã thay đổi với 6101 bổ sung1721 xóa
  1. 5 1
      .vscode/settings.json
  2. 147 77
      cfg/ocpp16_ChargingProfiles.json
  3. 8 8
      rec/styles/Dark.qss
  4. 1 0
      src/main.cpp
  5. 18 11
      src/utils/ConfigManager.cpp
  6. 38 0
      src/utils/ConfigManager.h
  7. 21 15
      src/utils/DataTypeDef.h
  8. 195 53
      src/utils/GeneralInterface.cpp
  9. 27 17
      src/utils/GeneralInterface.h
  10. 5 0
      src/utils/Globals.cpp
  11. 90 2
      src/utils/Globals.h
  12. 34 0
      src/utils/LanguageManager.h
  13. 3 3
      src/utils/LoggerHelper.cpp
  14. 55 0
      src/utils/NFCReaderWorker.h
  15. 116 1
      src/utils/RS485Controller.h
  16. 27 0
      src/utils/TcpServerThread.h
  17. 98 6
      src/utils/VersionManager.h
  18. 168 0
      src/utils/getVersion.c
  19. 71 6
      src/widgets/custom/AnimatedStackedWidget.h
  20. 69 1
      src/widgets/custom/BaseWidget.h
  21. 20 8
      src/widgets/custom/CustomComboBox.cpp
  22. 2 0
      src/widgets/custom/CustomComboBox.h
  23. 21 0
      src/widgets/custom/CustomDoubleSpinBox.h
  24. 60 1
      src/widgets/custom/CustomLineEdit.h
  25. 147 0
      src/widgets/custom/CustomNavigationBar.cpp
  26. 94 0
      src/widgets/custom/CustomNavigationBar.h
  27. 3 1
      src/widgets/custom/CustomQDateTimeEdit.cpp
  28. 39 0
      src/widgets/custom/CustomQDateTimeEdit.h
  29. 23 0
      src/widgets/custom/CustomSpinBox.h
  30. 1 1
      src/widgets/titleBar/TitleBar.cpp
  31. 52 9
      src/widgets/workspace/settings/CcuSettings/FormCcuSetting.cpp
  32. 6 0
      src/widgets/workspace/settings/CcuSettings/FormCcuSetting.h
  33. 70 70
      src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.cpp
  34. 12 6
      src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.h
  35. 646 699
      src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.ui
  36. 1 51
      src/widgets/workspace/settings/CcuSettings/FormChargeGunType.cpp
  37. 0 13
      src/widgets/workspace/settings/CcuSettings/FormChargeGunType.h
  38. 2 2
      src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.cpp
  39. 2 2
      src/widgets/workspace/settings/CcuSettings/FormPriceDetail.cpp
  40. 123 34
      src/widgets/workspace/settings/FormSettings.cpp
  41. 11 0
      src/widgets/workspace/settings/FormSettings.h
  42. 221 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.cpp
  43. 48 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.h
  44. 414 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.ui
  45. 50 8
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.cpp
  46. 103 4
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.h
  47. 48 92
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.ui
  48. 116 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.cpp
  49. 36 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.h
  50. 173 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.ui
  51. 305 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.cpp
  52. 71 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.h
  53. 200 0
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.ui
  54. 7 2
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.cpp
  55. 5 2
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.h
  56. 67 23
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.cpp
  57. 9 3
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.h
  58. 15 18
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.ui
  59. 292 114
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.cpp
  60. 120 35
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.h
  61. 104 107
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.ui
  62. 343 3
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.cpp
  63. 45 2
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.h
  64. 627 20
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.ui
  65. 7 2
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.cpp
  66. 5 2
      src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.h
  67. 2 2
      src/widgets/workspace/settings/OcppSettings/FormAuthCardDetail.cpp
  68. 4 4
      src/widgets/workspace/settings/OcppSettings/FormChargingProfiles.cpp
  69. 1 42
      src/widgets/workspace/settings/OcppSettings/FormOcppSettings.cpp
  70. 0 10
      src/widgets/workspace/settings/OcppSettings/FormOcppSettings.h
  71. 0 125
      src/widgets/workspace/settings/OcppSettings/FormOcppSettings.ui
  72. 55 2
      src/widgets/workspace/settings/OtherSettings/dialog/DialogChargingPopup.h
  73. 1 1
      src/widgets/workspace/settings/OtherSettings/dialog/DialogEditValue.cpp
  74. 27 0
      src/widgets/workspace/settings/OtherSettings/dialog/DialogEditValue.h
  75. 24 0
      src/widgets/workspace/settings/PcuSettings/FormPcuSettings.cpp
  76. 25 0
      src/widgets/workspace/settings/TcuSettings/FormTcuSettings.cpp

+ 5 - 1
.vscode/settings.json

@@ -1,3 +1,7 @@
 {
-    "markdown.validate.enabled": true
+    "markdown.validate.enabled": true,
+    "files.associations": {
+        "vector": "cpp",
+        "xutility": "cpp"
+    }
 }

+ 147 - 77
cfg/ocpp16_ChargingProfiles.json

@@ -1,78 +1,148 @@
 {
-	"count" : 2,
-	"maxLength" : 20,
-	"ChargingProfiles" : [
-		{
-			"chargingProfileId" : 0, 
-			"connectorId" : 0, 
-			"stackLevel" : 0, 
-			
-			"chargingProfilePurpose" : "ChargePointMaxProfile",
-			"chargingProfileKind" : "Absolute", 
-			"recurrencyKind" : "NULL", 
-
-			"validFrom" : "2024-12-20T20:30:00Z", 
-			"validTo" : "2024-12-21T04:30:00Z", 
-
-			"chargingSchedule" : {
-				"duration" : 0, 
-				"startTime" : "2024-12-20T20:30:00Z", 
-				"chargingRateUnit" : "W", 
-				"minChargingRate" : 200,
-				"chargingSchedulePeriod" : [{
-					"startPeriod" : 0,
-					"limit" : 200000, 
-					"numberPhases" : 3
-				}]
-			}
-		},
-		{
-			"chargingProfileId" : 0, 
-			"connectorId" : 0, 
-			"stackLevel" : 0, 
-			
-			"chargingProfilePurpose" : "TxDefaultProfile",
-			"chargingProfileKind" : "Absolute", 
-			"recurrencyKind" : "NULL", 
-
-			"validFrom" : "2024-12-20T20:30:00Z", 
-			"validTo" : "2024-12-21T04:30:00Z", 
-
-			"chargingSchedule" : {
-				"duration" : 0, 
-				"startTime" : "2024-12-20T20:30:00Z", 
-				"chargingRateUnit" : "W", 
-				"minChargingRate" : 200,
-				"chargingSchedulePeriod" : [{
-					"startPeriod" : 0,
-					"limit" : 200000, 
-					"numberPhases" : 3
-				}]
-			}
-		},
-		{
-			"chargingProfileId" : 0, 
-			"connectorId" : 0, 
-			"stackLevel" : 0, 
-			
-			"chargingProfilePurpose" : "TxProfile",
-			"chargingProfileKind" : "Absolute", 
-			"recurrencyKind" : "NULL", 
-
-			"validFrom" : "2024-12-20T20:30:00Z", 
-			"validTo" : "2024-12-21T04:30:00Z", 
-
-			"chargingSchedule" : {
-				"duration" : 0, 
-				"startTime" : "2024-12-20T20:30:00Z", 
-				"chargingRateUnit" : "W", 
-				"minChargingRate" : 200,
-				"chargingSchedulePeriod" : [{
-					"startPeriod" : 0,
-					"limit" : 200000, 
-					"numberPhases" : 3
-				}]
-			}
-		}
-	]
-}
+    "ChargingProfiles": [
+        {
+            "chargingProfileId": 1,
+            "chargingProfileKind": "Absolute",
+            "chargingProfilePurpose": "ChargePointMaxProfile",
+            "chargingSchedule": {
+                "chargingRateUnit": "W",
+                "chargingSchedulePeriod": [
+                    {
+                        "limit": 200000,
+                        "numberPhases": 3,
+                        "startPeriod": 0
+                    }
+                ],
+                "duration": 0,
+                "minChargingRate": 200,
+                "startTime": "2024-12-20T20:30:00Z"
+            },
+            "connectorId": 1,
+            "recurrencyKind": "NULL",
+            "stackLevel": 0,
+            "validFrom": "2024-12-20T20:30:00Z",
+            "validTo": "2024-12-21T04:30:00Z"
+        },
+        {
+            "chargingProfileId": 3,
+            "chargingProfileKind": "Absolute",
+            "chargingProfilePurpose": "TxProfile",
+            "chargingSchedule": {
+                "chargingRateUnit": "W",
+                "chargingSchedulePeriod": [
+                    {
+                        "limit": 200000,
+                        "numberPhases": 3,
+                        "startPeriod": 0
+                    }
+                ],
+                "duration": 0,
+                "minChargingRate": 200,
+                "startTime": "2024-12-20T20:30:00Z"
+            },
+            "connectorId": 1,
+            "recurrencyKind": "NULL",
+            "stackLevel": 0,
+            "validFrom": "2024-12-20T20:30:00Z",
+            "validTo": "2024-12-21T04:30:00Z"
+        },
+        {
+            "chargingProfileId": 2,
+            "chargingProfileKind": "Recurring",
+            "chargingProfilePurpose": "TxDefaultProfile",
+            "chargingSchedule": {
+                "chargingRateUnit": "W",
+                "chargingSchedulePeriod": [
+                    {
+                        "limit": 12000,
+                        "numberPhases": 3,
+                        "startPeriod": 0
+                    },
+                    {
+                        "limit": 20000,
+                        "numberPhases": 3,
+                        "startPeriod": 7200
+                    },
+                    {
+                        "limit": 28000,
+                        "numberPhases": 3,
+                        "startPeriod": 14400
+                    },
+                    {
+                        "limit": 20000,
+                        "numberPhases": 3,
+                        "startPeriod": 21600
+                    },
+                    {
+                        "limit": 32000,
+                        "numberPhases": 3,
+                        "startPeriod": 28800
+                    },
+                    {
+                        "limit": 36000,
+                        "numberPhases": 3,
+                        "startPeriod": 36000
+                    }
+                ],
+                "duration": 0,
+                "minChargingRate": 200,
+                "startTime": "2024-12-20T20:30:00Z"
+            },
+            "connectorId": 1,
+            "recurrencyKind": "Daily",
+            "stackLevel": 0,
+            "validFrom": "2024-12-20T20:30:00Z",
+            "validTo": "2024-12-21T04:30:00Z"
+        },
+        {
+            "chargingProfileId": 4,
+            "chargingProfileKind": "Recurring",
+            "chargingProfilePurpose": "TxDefaultProfile",
+            "chargingSchedule": {
+                "chargingRateUnit": "W",
+                "chargingSchedulePeriod": [
+                    {
+                        "limit": 12000,
+                        "numberPhases": 3,
+                        "startPeriod": 0
+                    },
+                    {
+                        "limit": 20000,
+                        "numberPhases": 3,
+                        "startPeriod": 7200
+                    },
+                    {
+                        "limit": 28000,
+                        "numberPhases": 3,
+                        "startPeriod": 14400
+                    },
+                    {
+                        "limit": 20000,
+                        "numberPhases": 3,
+                        "startPeriod": 21600
+                    },
+                    {
+                        "limit": 32000,
+                        "numberPhases": 3,
+                        "startPeriod": 28800
+                    },
+                    {
+                        "limit": 36000,
+                        "numberPhases": 3,
+                        "startPeriod": 36000
+                    }
+                ],
+                "duration": 0,
+                "minChargingRate": 200,
+                "startTime": "2024-12-20T20:30:00Z"
+            },
+            "connectorId": 1,
+            "recurrencyKind": "Weekly",
+            "stackLevel": 0,
+            "validFrom": "2024-12-20T20:30:00Z",
+            "validTo": "2024-12-21T04:30:00Z"
+        }
+    ],
+    "count": 2,
+    "maxLength": 20
+}

+ 8 - 8
rec/styles/Dark.qss

@@ -5,7 +5,7 @@
 QWidget {
     color:white !important;
     font-family: 'Source Han Sans K';
-    font-size: 24px;
+    font-size: 22px;
 }
 
 QMainWindow {
@@ -135,15 +135,15 @@ FormGunDetail QLabel#gun_index {
 
 FormGunDetail QLabel#gun_type {
     color: #00C1C3;
-    font-size: 24px 'Source Han Sans K';
+    font-size: 22px 'Source Han Sans K';
 }
 
 FormGunDetail QLabel#tips {
-    font-size: 24px 'Source Han Sans K';
+    font-size: 22px 'Source Han Sans K';
 }
 
 QLabel#charge_percent, QLabel#charge_percent_1 {
-    font-size: 52px 'Source Han Sans K';
+    font-size: 48px 'Source Han Sans K';
     font-style: italic;   /* 斜体 */
     font-weight: bold;    /* 加粗 */
 }
@@ -193,7 +193,7 @@ QMessageBox {
 
 QMessageBox QLabel {
     color: white;
-    font-size: 24px;
+    font-size: 22px;
     min-width: 300px;
 }
 
@@ -203,7 +203,7 @@ QMessageBox QPushButton {
     border-radius: 10px;
     padding: 8px 20px;
     min-width: 100px;
-    font-size: 24px;
+    font-size: 22px;
 }
 
 QMessageBox QPushButton:hover {
@@ -280,7 +280,7 @@ QComboBox {
     border: none;
     padding: 5px 10px;
     min-width: 6em;
-    font-size: 24px;
+    font-size: 22px;
 }
 
 QComboBox:hover, QComboBox:focus {
@@ -419,7 +419,7 @@ QDoubleSpinBox {
     color: white;
     border: none;
     padding: 5px 10px;
-    font-size: 24px;
+    font-size: 22px;
 }
 
 QDoubleSpinBox:disabled {

+ 1 - 0
src/main.cpp

@@ -15,6 +15,7 @@
 #include "LoggerHelper.h"
 #include "Globals.h"
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
 static void initGlobals() {
     // 初始化充电枪基本信息

+ 18 - 11
src/utils/ConfigManager.cpp

@@ -326,6 +326,16 @@ void ConfigManager::initConnect()
             m_watcher[ERROR_CODE_NOTE]->addPath(path);
         }
     });
+
+    connect(m_watcher[PRICEINFO], &QFileSystemWatcher::fileChanged, this, [this](const QString& path) {
+        reloadConfig(PRICEINFO, path);
+        priceInfoFromJson();
+
+        // 重新添加监视(文件修改时可能临时被移除监视列表)
+        if (!m_watcher[PRICEINFO]->files().contains(path)) {
+            m_watcher[PRICEINFO]->addPath(path);
+        }
+    });
 }
 
 void ConfigManager::initConfigObject()
@@ -957,7 +967,7 @@ bool ConfigManager::ccuCfgToJson()
     m_cfg_object[CCU_CONFIG]["ISO4217_LeastSign"]       = m_ccu_cfg.ISO4217_LeastSign;
 
     // 将GUN_Detail配置信息写入m_cfg_object
-    m_cfg_object[CCU_CONFIG]["GUN_Detail"]              = gunDetailToJson(m_ccu_cfg.GUN_Detail);
+    m_cfg_object[CCU_CONFIG]["GUN"]                     = gunDetailToJson(m_ccu_cfg.GUN_Detail);
 
     // 将pcuhw配置信息写入m_cfg_object
     m_cfg_object[CONFIG_KEY]["pcuhw"]                   = pcuhwToJson(m_ccu_cfg.pcuhw);
@@ -994,10 +1004,6 @@ QJsonArray ConfigManager::gunDetailToJson(const QList<GUN_DETAIL> &config)
         obj.insert("requestPowerBySOC",     item.requestPowerBySOC);
         obj.insert("GUNOverTemp_Warning",   item.GUNOverTemp_Warning);
         obj.insert("GUNOverTemp_Stopping",  item.GUNOverTemp_Stopping);
-        obj.insert("enable_current_limit",  item.enable_current_limit);
-        obj.insert("permitted_current",     item.permitted_current);
-        obj.insert("enable_powerKW_limit",  item.enable_powerKW_limit);
-        obj.insert("permitted_powerKW",     item.permitted_powerKW);
         arr.append(obj);
     }
 
@@ -1019,10 +1025,10 @@ QJsonObject ConfigManager::pcutcToJson(const PCUTC_CFG &config)
 {
     QJsonObject obj;
 
+    obj.insert("enable",            config.enable);
     obj.insert("connect_ip_string", config.connect_ip_string);
     obj.insert("connect_port",      config.connect_port);
     obj.insert("enable_ssl",        config.enable_ssl);
-    obj.insert("enable",            config.enable);
 
     return obj;
 }
@@ -1031,10 +1037,10 @@ QJsonObject ConfigManager::qttcuToJson(const QTTCU_CFG &config)
 {
     QJsonObject obj;
 
+    obj.insert("enable",            config.enable);
     obj.insert("connect_ip_string", config.connect_ip_string);
     obj.insert("connect_port",      config.connect_port);
     obj.insert("enable_ssl",        config.enable_ssl);
-    obj.insert("enable",            config.enable);
 
     return obj;
 }
@@ -1044,6 +1050,7 @@ QJsonArray ConfigManager::ocpp16ToJson(const QList<OCPP1_6> &config)
     QJsonArray arr;
     for (const auto &item : config) {
         QJsonObject obj;
+        obj.insert("enable",                    item.enable);
         obj.insert("connect_ip_string",         item.connect_ip_string);
         obj.insert("connect_port",              item.connect_port);
         obj.insert("ssl_ca_filepath",           item.ssl_ca_filepath);
@@ -1061,6 +1068,7 @@ QJsonArray ConfigManager::ocpp21ToJson(const QList<OCPP2_1> &config)
     QJsonArray arr;
     for (const auto &item : config) {
         QJsonObject obj;
+        obj.insert("enable",                    item.enable);
         obj.insert("connect_ip_string",         item.connect_ip_string);
         obj.insert("connect_port",              item.connect_port);
         obj.insert("ssl_ca_filepath",           item.ssl_ca_filepath);
@@ -1554,10 +1562,9 @@ bool ConfigManager::chargingCfgToJson()
     if(m_cfg_object.isEmpty()) return false;
     if(!m_cfg_object.contains(CHARGING_PROFILE)) return false;
 
-    auto charging_profiles                  = m_cfg_object[CHARGING_PROFILE];
-    charging_profiles["count"]              = m_charging_profiles.count;
-    charging_profiles["maxLength"]          = m_charging_profiles.maxLength;
-    charging_profiles["ChargingProfiles"]   = chargingProfileDetailToJson(m_charging_profiles.chargingProfiles);
+    m_cfg_object[CHARGING_PROFILE]["count"]              = m_charging_profiles.count;
+    m_cfg_object[CHARGING_PROFILE]["maxLength"]          = m_charging_profiles.maxLength;
+    m_cfg_object[CHARGING_PROFILE]["ChargingProfiles"]   = chargingProfileDetailToJson(m_charging_profiles.chargingProfiles);
 
     return true;
 }

+ 38 - 0
src/utils/ConfigManager.h

@@ -9,6 +9,33 @@
 
 #include "DataTypeDef.h"
 
+/**
+ * @class ConfigManager
+ * @brief ConfigManager 类用于管理配置文件,并提供加载和保存配置文件的功能。
+ * 
+ * ConfigManager 类继承自 QObject,用于管理各种配置文件,如 CCU 配置文件、TCU 配置文件、价格信息文件等。
+ * 它提供了一系列静态方法和实例方法,用于加载和保存配置文件,并提供了获取和设置配置信息的功能。
+ * 
+ * 核心功能包括:
+ * - 加载和保存各种配置文件
+ * - 获取和设置配置信息
+ * - 监控配置文件的变化
+ * 
+ * 使用示例:
+ * @code
+ * ConfigManager* manager = ConfigManager::instance();
+ * manager->loadCcuConfigFile("path/to/ccu/config/file");
+ * uint8_t result = manager->saveConfig(setting_index_enum::Language, QVariant(1));
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - parent: QObject 的父对象,默认为 nullptr
+ * 
+ * 注意事项:
+ * - 请确保在使用 ConfigManager 之前已经正确初始化了应用程序。
+ * - 在使用 ConfigManager 时,请确保配置文件的路径是正确的。
+ * - 保存配置时,请确保提供正确的配置类型和数据。
+ */
 class ConfigManager : public QObject
 {
     Q_OBJECT
@@ -18,6 +45,7 @@ public:
     explicit ConfigManager(QObject *parent = nullptr);
 
 public:
+    // load config file
     uint8_t loadCcuConfigFile(const QString& path);
     uint8_t loadTcuConfigFile(const QString& path);
     uint8_t loadPcuConfigFile(const QString& path);
@@ -28,6 +56,7 @@ public:
     uint8_t loadOffileChargingRecords(const QString& path);
     uint8_t loadErrorCodeNote(const QString& path);
 
+    // save config file
     bool saveConfig(const setting_index_enum& type, const QVariant& data);
 
     tcp_server_cfg_info_t getTcpServerCfg();
@@ -65,6 +94,7 @@ private:
     bool saveConfigToFile(const setting_index_enum type, const QString& path);
     QString getConfigFilePath(const setting_index_enum& type);
 
+    // json to tcu config
     LOG_INFO logCfgFromJson(const QJsonObject& obj);
     PAYMENT_INFO    paymentCfgFromJson(const QJsonObject& obj);
     PRICE_SETTING   jsonToPriceSetting(const QJsonObject& obj);
@@ -85,6 +115,7 @@ private:
     QJsonObject wizarInfoToJson(const WIZAR_INFO& data);
     bool tcuCfgToJson();
 
+    // json to ccu config
     void ccuCfgFromJson();
     QList<GUN_DETAIL> jsonToGUNDetail(const QJsonArray& array);
     PCUHW_CFG jsonToPcuhw(const QJsonObject& obj);
@@ -100,18 +131,22 @@ private:
     QJsonArray ocpp16ToJson(const QList<OCPP1_6>& config);
     QJsonArray ocpp21ToJson(const QList<OCPP2_1>& config);
 
+    // json to pcu config
     void pcuCfgFromJson();
     bool pcuCfgToJson();
 
+    // json to price info
     QList<OFFLINE_PRICE> jsonToOfflinePrice(const QJsonArray &array);
     void priceInfoFromJson();
     QJsonArray offlinePriceToJson(const QList<OFFLINE_PRICE>& config);
     bool priceInfoToJson();
 
+    // json to authorization list
     void authorizationFromJson();
     void fromValue(QList<AUTH_CARD_INFO> &auth_card_info, const QJsonArray& jsonArray);
     bool authorizationToJson();
 
+    // json to ocpp config key
     void configKeyFromJson();
     CORE_PROFILE    jsonToCoreProfile(const QJsonObject& obj);
     AUTH_LIST_MANAGE    jsonToLocalAuthList(const QJsonObject& obj);
@@ -123,6 +158,7 @@ private:
     QJsonObject reservationProfileToJson(const RESE_PROFILE& config);
     QJsonObject smartChargingProfileToJson(const SMART_CHARGE& config);
 
+    // json to charging profiles
     void chargingCfgFromJson();
     QList<charging_schedule_period_info_t>  jsonToChargingSchedulePeriod(const QJsonArray& array);
     charging_schedule_info_t                jsonToChargingSchedule(const QJsonObject &object);
@@ -132,11 +168,13 @@ private:
     QJsonObject chargingScheduleToJson(const charging_schedule_info_t& config);
     QJsonArray chargingProfileDetailToJson(const QList<charging_profiles_detail_info_t>& config);
 
+    // json to charging records
     void chargingRecordsFromJson();
     QList<CHARGING_RECORD_INFO> jsonToChargingRecord(const QJsonArray& array);
     bool chargingRecordsToJson();
     QJsonArray chargingRecordsDetailToJson(const QList<CHARGING_RECORD_INFO>& config);
 
+    // json to QVariant
     QStringList jsonToStringList(const QJsonValue &value);
     QJsonValue stringListToJson(const QStringList& stringList);
     QList<int> jsonToIntList(const QJsonValue &value);

+ 21 - 15
src/utils/DataTypeDef.h

@@ -230,6 +230,7 @@ enum globals_keys_enum {
     GLOBALS_CFG_KEY_KEY,
     GLOBALS_OFFLINE_CHARGING_RECORDS_KEY,
     GLOBALS_TCU_CFG_KEY,
+    GLOBALS_PCU_CFG_KEY,
     GLOBALS_PRICE_INFO_KEY
 };
 
@@ -270,6 +271,7 @@ enum log_level_enum {
     FATAL
 };
 
+// 定义一个枚举类型,表示充电进度
 enum charge_progress_enum {
     PLUG_IN_PROGRESS = 0x0,
     AUTHORIZATION_PROGRESS,
@@ -355,6 +357,10 @@ namespace Workspace {
         constexpr const int OTHER                   = 0x1500;
         namespace Ccu {
             constexpr const int CHARGE_GUN              = 0x1110;
+            namespace ChargeGun {
+                constexpr const int CHARGE_GUN_1        = 0x1111;
+                constexpr const int CHARGE_GUN_2        = 0x1112;
+            }
             constexpr const int AUTH                    = 0x1120;
             constexpr const int OFFLINE_PRICES          = 0x1130;
             constexpr const int PCUHW                   = 0x1140;
@@ -904,33 +910,33 @@ Q_DECLARE_METATYPE(PRICE_INFO)
 
 struct charging_schedule_period_info_t {
     int startPeriod = 0;
-    int limit;
+    int limit{0};
     int numberPhases = 3;
 };
 Q_DECLARE_METATYPE(charging_schedule_period_info_t)
 
 struct charging_schedule_info_t {
-    int                                     duration;
-    QString                                 startTime;
-    QString                                 chargingRateUnit;
-    int                                     minChargingRate;
-    QList<charging_schedule_period_info_t>  chargingSchedulePeriod;
+    int                                     duration{0};
+    QString                                 startTime{"NULL"};
+    QString                                 chargingRateUnit{"W"};
+    int                                     minChargingRate{200};
+    QList<charging_schedule_period_info_t>  chargingSchedulePeriod{charging_schedule_period_info_t()};
 };
 Q_DECLARE_METATYPE(charging_schedule_info_t)
 
 struct charging_profiles_detail_info_t {
-    int                                 chargingProfileId;
-    int                                 connectorId;
-    int                                 stackLevel;
+    int                                 chargingProfileId{0};
+    int                                 connectorId{0};
+    int                                 stackLevel{0};
     
-    QString                             validFrom;
-    QString                             validTo;
+    QString                             validFrom{"NULL"};
+    QString                             validTo{"NULL"};
 
-    QString                             chargingProfilePurpose;
-    QString                             chargingProfileKind;
-    QString                             recurrencyKind;
+    QString                             chargingProfilePurpose{"NULL"};
+    QString                             chargingProfileKind{"Absolute"};
+    QString                             recurrencyKind{"NULL"};
     
-    charging_schedule_info_t            chargingSchedule;
+    charging_schedule_info_t            chargingSchedule{charging_schedule_info_t()};
 };
 Q_DECLARE_METATYPE(charging_profiles_detail_info_t)
 

+ 195 - 53
src/utils/GeneralInterface.cpp

@@ -14,6 +14,7 @@
 #include <QDataStream>
 #include <QScroller>
 #include <QPainter>
+#include <unistd.h>
 
 #include "Globals.h"
 #include "ConfigManager.h"
@@ -494,8 +495,8 @@ QMap<int, QVariant> GeneralInterface::chargingProfileToMapByConnectorId(const QL
 {
     QMap<int, QVariant> result;
     foreach (const auto& data, dataList) {
-        auto map = chargingProfileToMapByStackLevel(dataList,
-                                                    data.connectorId);
+        auto map = chargingProfileToMapByPurpose(dataList,
+                                                 data.connectorId);
         result.insert(data.connectorId, QVariant::fromValue(map));
     }
 
@@ -506,46 +507,20 @@ QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToLis
 {
     QList<charging_profiles_detail_info_t> result;
     foreach (const auto& data, dataMap) {
-        result.append(chargingProfileMapToListByStackLevel(data.value<QMap<int, QVariant>>(), dataMap.key(data)));
+        result.append(chargingProfileMapToListByPurpose(data.value<QMap<QString, QVariant>>(), dataMap.key(data)));
     }
 
     return result;
 }
 
-QMap<int, QVariant> GeneralInterface::chargingProfileToMapByStackLevel(const QList<charging_profiles_detail_info_t> &dataList, const int& connectorId)
-{
-    QMap<int, QVariant> result;
-    foreach (const auto& data, dataList) {
-        if (data.connectorId == connectorId) {
-            auto map = chargingProfileToMapByPurpose(dataList,
-                                                     data.connectorId,
-                                                     data.stackLevel);
-            result.insert(data.stackLevel, QVariant::fromValue(map));
-        }
-    }
-
-    return result;
-}
-
-QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByStackLevel(const QMap<int, QVariant> &dataMap, const int &connectorId)
-{
-    QList<charging_profiles_detail_info_t> result;
-    foreach (const auto& data, dataMap) {
-        result.append(chargingProfileMapToListByPurpose(data.value<QMap<QString, QVariant>>(), connectorId, dataMap.key(data)));
-    }
-
-    return result;
-}
-
-QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByPurpose(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const int &stackLevel)
+QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByPurpose(const QList<charging_profiles_detail_info_t> &dataList,
+                                                                        const int &connectorId)
 {
     QMap<QString, QVariant> result;
     foreach (const auto& data, dataList) {
-        if (data.connectorId == connectorId &&
-            data.stackLevel == stackLevel) {
+        if (data.connectorId == connectorId) {
             auto map = chargingProfileToMapByKind(dataList,
                                                   data.connectorId,
-                                                  data.stackLevel,
                                                   data.chargingProfilePurpose);
             result.insert(data.chargingProfilePurpose, QVariant::fromValue(map));
         }
@@ -554,29 +529,29 @@ QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByPurpose(const QL
     return result;
 }
 
-QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByPurpose(const QMap<QString, QVariant> &dataMap, const int &connectorId, const int &stackLevel)
+QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByPurpose(const QMap<QString, QVariant> &dataMap,
+                                                                                           const int &connectorId)
 {
     QList<charging_profiles_detail_info_t> result;
     foreach (const auto& data, dataMap) {
         result.append(chargingProfileMapToListByKind(data.value<QMap<QString, QVariant>>(),
                                                      connectorId,
-                                                     stackLevel,
                                                      dataMap.key(data)));
     }
 
     return result;
 }
 
-QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByKind(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const int &stackLevel, const QString &purpose)
+QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByKind(const QList<charging_profiles_detail_info_t> &dataList,
+                                                                     const int &connectorId,
+                                                                     const QString &purpose)
 {
     QMap<QString, QVariant> result;
     foreach (const auto& data, dataList) {
         if (data.connectorId == connectorId &&
-            data.stackLevel == stackLevel &&
             data.chargingProfilePurpose == purpose) {
                 auto map = chargingProfileToMapByRecurrencyKind(dataList,
                                                                 data.connectorId,
-                                                                data.stackLevel,
                                                                 data.chargingProfilePurpose,
                                                                 data.chargingProfileKind);
                 result.insert(data.chargingProfileKind, QVariant::fromValue(map));
@@ -586,13 +561,14 @@ QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByKind(const QList
     return result;
 }
 
-QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByKind(const QMap<QString, QVariant> &dataMap, const int &connectorId, const int &stackLevel, const QString &purpose)
+QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByKind(const QMap<QString, QVariant> &dataMap,
+                                                                                        const int &connectorId,
+                                                                                        const QString &purpose)
 {
     QList<charging_profiles_detail_info_t> result;
     foreach (const auto& data, dataMap) {
         result.append(chargingProfileMapToListRecurrencyKind(data.value<QMap<QString, QVariant>>(),
                                                              connectorId,
-                                                             stackLevel,
                                                              purpose,
                                                              dataMap.key(data)));
     }
@@ -600,17 +576,18 @@ QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToLis
     return result;
 }
 
-QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const int &stackLevel, const QString &purpose, const QString &kind)
+QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList,
+                                                                               const int &connectorId,
+                                                                               const QString &purpose,
+                                                                               const QString &kind)
 {
     QMap<QString, QVariant> result;
     foreach (const auto& data, dataList) {
         if (data.connectorId == connectorId &&
-            data.stackLevel == stackLevel &&
             data.chargingProfilePurpose == purpose &&
             data.chargingProfileKind == kind) {
                 auto variantList = chargingProfileToMapByRecurrencyKind(dataList,
                                                                     data.connectorId,
-                                                                    data.stackLevel,
                                                                     data.chargingProfilePurpose,
                                                                     data.chargingProfileKind,
                                                                     data.recurrencyKind);
@@ -621,13 +598,15 @@ QMap<QString, QVariant> GeneralInterface::chargingProfileToMapByRecurrencyKind(c
     return result;
 }
 
-QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListRecurrencyKind(const QMap<QString, QVariant> &dataMap, const int &connectorId, const int &stackLevel, const QString &purpose, const QString &kind)
+QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListRecurrencyKind(const QMap<QString, QVariant> &dataMap,
+                                                                                                const int &connectorId,
+                                                                                                const QString &purpose,
+                                                                                                const QString &kind)
 {
     QList<charging_profiles_detail_info_t> result;
     foreach (const auto& data, dataMap) {
-        result.append(chargingProfileMapToListRecurrencyKind(data.value<QVariantList>(),
+        result.append(chargingProfileMapToListRecurrencyKind(data.value<QMap<int, QVariant>>(),
                                                              connectorId,
-                                                             stackLevel,
                                                              purpose,
                                                              kind,
                                                              dataMap.key(data)));
@@ -636,15 +615,60 @@ QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToLis
     return result;
 }
 
-QVariantList GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const int &stackLevel, const QString &purpose, const QString &kind, const QString &recurrencyKind)
+QMap<int, QVariant> GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList,
+                                                                    const int &connectorId,
+                                                                    const QString &purpose,
+                                                                    const QString &kind,
+                                                                    const QString &recurrencyKind)
 {
-    QVariantList result;
+    QMap<int, QVariant> result;
     foreach (const auto& data, dataList) {
         if (data.connectorId == connectorId &&
-            data.stackLevel == stackLevel &&
             data.chargingProfilePurpose == purpose &&
             data.chargingProfileKind == kind &&
             data.recurrencyKind == recurrencyKind) {
+            auto map = chargingProfileToMapByStackLevel(dataList,
+                                                        data.connectorId,
+                                                        data.chargingProfilePurpose,
+                                                        data.chargingProfileKind,
+                                                        data.recurrencyKind,
+                                                        data.stackLevel);
+            result.insert(data.stackLevel, QVariant::fromValue(map));
+        }
+    }
+
+    return result;
+}
+
+QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListRecurrencyKind(const QMap<int, QVariant> &dataMap,
+                                                                                                const int &connectorId,
+                                                                                                const QString &purpose,
+                                                                                                const QString &kind,
+                                                                                                const QString &recurrencyKind)
+{
+    QList<charging_profiles_detail_info_t> result;
+    foreach (const auto& data, dataMap) {
+        result.append(chargingProfileMapToListByStackLevel(data.value<QVariantList>(),
+                                                           connectorId,
+                                                           purpose,
+                                                           kind,
+                                                           recurrencyKind,
+                                                           dataMap.key(data)));
+    }
+
+    return result;
+}
+
+QVariantList GeneralInterface::chargingProfileToMapByStackLevel(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind, const int &stackLevel)
+{
+    QVariantList result;
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId &&
+            data.chargingProfilePurpose == purpose &&
+            data.chargingProfileKind == kind &&
+            data.recurrencyKind == recurrencyKind &&
+            data.stackLevel == stackLevel) {
+
             result.append(QVariant::fromValue(data));
         }
     }
@@ -652,10 +676,10 @@ QVariantList GeneralInterface::chargingProfileToMapByRecurrencyKind(const QList<
     return result;
 }
 
-QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListRecurrencyKind(const QVariantList &variantList, const int &connectorId, const int &stackLevel, const QString &purpose, const QString &kind, const QString &recurrencyKind)
+QList<charging_profiles_detail_info_t> GeneralInterface::chargingProfileMapToListByStackLevel(const QVariantList &dataMap, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind, const int &stackLevel)
 {
     QList<charging_profiles_detail_info_t> result;
-    foreach (const auto& data, variantList) {
+    foreach (const auto& data, dataMap) {
         if (data.value<charging_profiles_detail_info_t>().connectorId == connectorId &&
             data.value<charging_profiles_detail_info_t>().stackLevel == stackLevel &&
             data.value<charging_profiles_detail_info_t>().chargingProfilePurpose == purpose &&
@@ -679,6 +703,124 @@ int GeneralInterface::getMaxElecment(const QList<int> &list)
     return result;
 }
 
+QString GeneralInterface::getCurrentDate(const int &seconds)
+{
+    QDate date = QDate::currentDate();
+    QTime time = QTime(0, 0, 0).addSecs(seconds);
+    QDateTime dt(date, time);
+    return dt.toString("HH:mm:ss");
+}
+
+int GeneralInterface::getCurrentDate(const QString &time)
+{
+    QTime dt = QTime::fromString(time, "HH:mm:ss");
+    return QTime(0, 0, 0).secsTo(dt);
+}
+
+QString GeneralInterface::getCurrentDateOfWeek(const QString &startTime, const int &seconds)
+{
+    QDateTime dt = QDateTime::fromString(startTime, Qt::ISODate);
+    dt.setTimeSpec(Qt::UTC);
+    dt = dt.addSecs(seconds);
+    return dt.toString("HH:mm:ss");
+}
+
+int GeneralInterface::getCurrentDateSecondOfWeek(const QString &startTime, const int &seconds)
+{
+    // 1. 解析开始时间
+    QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
+    startDt.setTimeSpec(Qt::UTC);
+
+    // 2. 计算目标时间
+    QDateTime targetDt = startDt.addSecs(seconds);
+
+    // 3. 获取当天00:00:00到目标时间的秒数
+    int secondsOfDay = QTime(0, 0, 0).secsTo(targetDt.time());
+    return secondsOfDay;
+}
+
+int GeneralInterface::getCurrentDateOfWeek(const QString &startTime, const int &seconds, const int &dayOfWeek)
+{
+    // 1. 解析开始时间
+    QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
+    startDt.setTimeSpec(Qt::UTC);
+
+    // 2. 获取开始时间所在周的周一
+    QDate startDate = startDt.date();
+    int startDayOfWeek = startDate.dayOfWeek(); // 1=周一
+    QDate monday = startDate.addDays(1 - startDayOfWeek);
+
+    // 3. 目标日期 = 本周的 dayOfWeek
+    QDate targetDate = monday.addDays(dayOfWeek - 1);
+
+    // 4. 用秒数构造 QTime
+    QTime targetTime = QTime(0, 0, 0).addSecs(seconds);
+
+    // 5. 构造目标 QDateTime
+    QDateTime targetDt(targetDate, targetTime, Qt::UTC);
+
+    // 6. 计算秒数差
+    qint64 secondsDiff = startDt.secsTo(targetDt);
+    return static_cast<int>(secondsDiff);
+}
+
+int GeneralInterface::getCurrentDateOfWeek(const QString &startTime, const QString &time, const int& dayOfWeek)
+{
+    // 1. 解析开始时间
+    QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
+    startDt.setTimeSpec(Qt::UTC); // 若有Z,确保为UTC
+
+    // 2. 获取开始时间所在周的周一
+    QDate startDate = startDt.date();
+    int startDayOfWeek = startDate.dayOfWeek(); // 1=周一
+    QDate monday = startDate.addDays(1 - startDayOfWeek);
+
+    // 3. 目标日期 = 本周的 dayOfWeek
+    QDate targetDate = monday.addDays(dayOfWeek - 1);
+
+    // 4. 解析当天时间
+    QTime targetTime = QTime::fromString(time, "HH:mm:ss");
+
+    // 5. 构造目标 QDateTime
+    QDateTime targetDt(targetDate, targetTime, Qt::UTC);
+
+    // 6. 计算秒数差
+    qint64 secondsDiff = startDt.secsTo(targetDt);
+    return static_cast<int>(secondsDiff);
+}
+
+int GeneralInterface::getDayOfWeek(const QString &time)
+{
+    QDateTime dt = QDateTime::fromString(time, Qt::ISODate);
+    dt.setTimeSpec(Qt::UTC); // 明确为UTC时间
+    QDate date = dt.date();
+    return date.dayOfWeek();
+}
+
+void GeneralInterface::sortByStartPeriod(QList<charging_schedule_period_info_t> &list)
+{
+    std::sort(list.begin(), list.end(), [](const charging_schedule_period_info_t &a, const charging_schedule_period_info_t &b) {
+        return a.startPeriod < b.startPeriod;
+    });
+}
+
+void GeneralInterface::sortByStackLevel(QList<charging_profiles_detail_info_t> &list)
+{
+    std::sort(list.begin(), list.end(), [](const charging_profiles_detail_info_t &a, const charging_profiles_detail_info_t &b) {
+        return a.stackLevel > b.stackLevel;
+    });
+}
+
+int GeneralInterface::getMaxChargingProfileId(QList<charging_profiles_detail_info_t> &list)
+{
+    QList<int> chargingProfileIdList;
+    foreach (const auto& data, list) {
+        chargingProfileIdList.append(data.chargingProfileId);
+    }
+
+    return getMaxElecment(chargingProfileIdList);
+}
+
 /*
 QPixmap GeneralInterface::generateQRCode(const QString &text, int size)
 {
@@ -788,7 +930,7 @@ QString GeneralInterface::getGunIconUrl(const uint8_t &type, bool isError)
 bool GeneralInterface::isError(const QList<uint8_t> &error_list)
 {
     return std::any_of(error_list.begin(), error_list.end(),
-                       [](uint8_t value) { return value > CHARGE_GUN_ERROR_MAX_INDEX; });
+                       [](uint8_t value) { return (value > CHARGE_GUN_ERROR_MAX_INDEX); });
 }
 
 uint8_t GeneralInterface::getMaxElement(const QList<uint32_t> &state_list)
@@ -908,7 +1050,7 @@ int GeneralInterface::getAuthResult(const QByteArray &cardId)
 bool GeneralInterface::isTimeout(const QString &date)
 {
     // 将字符串转换为 QDateTime
-    QDateTime targetTime = QDateTime::fromString(date, Qt::ISODateWithMs);
+    QDateTime targetTime = QDateTime::fromString(date, Qt::ISODate);
 
     if (!targetTime.isValid()) {
         return false;
@@ -917,7 +1059,7 @@ bool GeneralInterface::isTimeout(const QString &date)
     // 转换为UTC时间以确保比较准确
     targetTime = targetTime.toUTC();
 
-    QDateTime cur_time = QDateTime::currentDateTime();
+    QDateTime cur_time = QDateTime::currentDateTimeUtc();
 
     return targetTime < cur_time;
 }

+ 27 - 17
src/utils/GeneralInterface.h

@@ -127,52 +127,62 @@ public:
     static QMap<int, QVariant> chargingProfileToMapByConnectorId(const QList<charging_profiles_detail_info_t>& dataList);
     static QList<charging_profiles_detail_info_t> chargingProfileMapToListByConnectorId(const QMap<int, QVariant>& dataMap);
 
-    static QMap<int, QVariant> chargingProfileToMapByStackLevel(const QList<charging_profiles_detail_info_t>& dataList,
-                                                                const int& connectorId);
-    static QList<charging_profiles_detail_info_t> chargingProfileMapToListByStackLevel(const QMap<int, QVariant>& dataMap,
-                                                                                       const int& connectorId);
-
     static QMap<QString, QVariant> chargingProfileToMapByPurpose(const QList<charging_profiles_detail_info_t>& dataList,
-                                                                 const int& connectorId,
-                                                                 const int& stackLevel);
+                                                                 const int& connectorId);
     static QList<charging_profiles_detail_info_t> chargingProfileMapToListByPurpose(const QMap<QString, QVariant>& dataMap,
-                                                                                    const int& connectorId,
-                                                                                    const int& stackLevel);
+                                                                                    const int& connectorId);
 
     static QMap<QString, QVariant> chargingProfileToMapByKind(const QList<charging_profiles_detail_info_t>& dataList,
                                                               const int& connectorId,
-                                                              const int& stackLevel,
                                                               const QString& purpose);
     static QList<charging_profiles_detail_info_t> chargingProfileMapToListByKind(const QMap<QString, QVariant>& dataMap,
                                                                                  const int& connectorId,
-                                                                                 const int& stackLevel,
                                                                                  const QString& purpose);
 
     static QMap<QString, QVariant> chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t>& dataList,
                                                                         const int& connectorId,
-                                                                        const int& stackLevel,
                                                                         const QString& purpose,
                                                                         const QString& kind);
     static QList<charging_profiles_detail_info_t> chargingProfileMapToListRecurrencyKind(const QMap<QString, QVariant>& dataMap,
                                                                                          const int& connectorId,
-                                                                                         const int& stackLevel,
                                                                                          const QString& purpose,
                                                                                          const QString& kind);
 
-    static QVariantList chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t>& dataList,
+    static QMap<int, QVariant> chargingProfileToMapByRecurrencyKind(const QList<charging_profiles_detail_info_t>& dataList,
                                                                         const int& connectorId,
-                                                                        const int& stackLevel,
                                                                         const QString& purpose,
                                                                         const QString& kind,
                                                                         const QString& recurrencyKind);
-    static QList<charging_profiles_detail_info_t> chargingProfileMapToListRecurrencyKind(const QVariantList& variantList,
+    static QList<charging_profiles_detail_info_t> chargingProfileMapToListRecurrencyKind(const QMap<int, QVariant>& dataMap,
                                                                                          const int& connectorId,
-                                                                                         const int& stackLevel,
                                                                                          const QString& purpose,
                                                                                          const QString& kind,
                                                                                          const QString& recurrencyKind);
 
+    static QVariantList chargingProfileToMapByStackLevel(const QList<charging_profiles_detail_info_t>& dataList,
+                                                         const int& connectorId,
+                                                         const QString& purpose,
+                                                         const QString& kind,
+                                                         const QString& recurrencyKind,
+                                                         const int& stackLevel);
+    static QList<charging_profiles_detail_info_t> chargingProfileMapToListByStackLevel(const QVariantList& dataMap,
+                                                                                       const int& connectorId,
+                                                                                       const QString& purpose,
+                                                                                       const QString& kind,
+                                                                                       const QString& recurrencyKind,
+                                                                                       const int& stackLevel);
+
     static int getMaxElecment(const QList<int>& list);
+    static QString getCurrentDate(const int& seconds);
+    static int getCurrentDate(const QString& time);
+    static QString getCurrentDateOfWeek(const QString& startTime, const int& seconds);
+    static int getCurrentDateSecondOfWeek(const QString& startTime, const int& seconds);
+    static int getCurrentDateOfWeek(const QString& startTime, const int& seconds, const int&dayOfWeek);
+    static int getCurrentDateOfWeek(const QString& startTime, const QString& time, const int &dayOfWeek);
+    static int getDayOfWeek(const QString& time);
+    static void sortByStartPeriod(QList<charging_schedule_period_info_t>& list);
+    static void sortByStackLevel(QList<charging_profiles_detail_info_t>& list);
+    static int getMaxChargingProfileId(QList<charging_profiles_detail_info_t>& list);
 };
 
 

+ 5 - 0
src/utils/Globals.cpp

@@ -70,6 +70,8 @@ Globals::Globals(QObject *parent)
     m_keys.insert(GLOBALS_CFG_KEY_KEY,                  Global::Keys::CFG_KEY);
     m_keys.insert(GLOBALS_OFFLINE_CHARGING_RECORDS_KEY, Global::Keys::OFFLINE_CHARGING_RECORDS);
     m_keys.insert(GLOBALS_TCU_CFG_KEY,                  Global::Keys::TCU_CFG);
+    m_keys.insert(GLOBALS_PCU_CFG_KEY,                  Global::Keys::PCU_CFG);
+    m_keys.insert(GLOBALS_PRICE_INFO_KEY,               Global::Keys::PRICEINFO);
 }
 
 void Globals::signalGeneration(const QString &key, const QVariant &value)
@@ -119,6 +121,9 @@ void Globals::signalGeneration(const QString &key, const QVariant &value)
     case GLOBALS_TCU_CFG_KEY:
         emit tcuConfigValueChanged(value.value<TCU_CFG>());
         break;
+    case GLOBALS_PCU_CFG_KEY:
+        emit pcuConfigValueChanged(value.value<PCU_CFG>());
+        break;
     case GLOBALS_PRICE_INFO_KEY:
         emit priceInfoValueChanged(value.value<PRICE_INFO>());
         break;

+ 90 - 2
src/utils/Globals.h

@@ -9,31 +9,118 @@
 
 #include "DataTypeDef.h"
 
+/**
+ * @brief 全局变量管理类,提供全局变量的存储、获取和监听功能。
+ * 
+ * 该类实现了全局变量的存储和管理,支持通过键值对存储和获取数据,并提供了信号机制,当全局变量的值发生变化时,可以发出相应的信号。
+ * 
+ * 核心功能:
+ * - 提供全局变量的存储和获取方法。
+ * - 支持通过键值对存储和获取数据。
+ * - 支持监听全局变量的变化,通过信号机制通知外部。
+ * - 提供静态方法获取类的唯一实例。
+ * 
+ * 使用示例:
+ * @code
+ * Globals* globals = Globals::instance();
+ * globals->setValue("exampleKey", 42);
+ * int value = globals->getValue("exampleKey").toInt();
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - parent: QObject的父对象,默认为nullptr。
+ * 
+ * 注意事项:
+ * - 该类是单例模式,通过静态方法instance()获取唯一实例。
+ * - 使用setValue方法设置值时,如果键已存在,则更新该键的值;如果键不存在,则创建新的键值对。
+ * - 使用getValue方法获取值时,如果键不存在,则返回默认值。
+ * - 使用contains方法检查键是否存在。
+ * - 使用信号机制监听全局变量的变化,需要连接相应的信号槽。
+ * - 使用模板方法setValue和getValue时,需要指定值的类型。
+ */
 class Globals : public QObject
 {
     Q_OBJECT
 public:
+    /**
+     * @brief 获取类的唯一实例。
+     * @return Globals类的唯一实例。
+     */
     static Globals* instance();
+
+    /**
+     * @brief 设置全局变量的值。
+     * @param key 键。
+     * @param value 值。
+     */
     void setValue(const QString& key, const QVariant& value);
+
+    /**
+     * @brief 获取全局变量的值。
+     * @param key 键。
+     * @param defaultValue 默认值,当键不存在时返回。
+     * @return 全局变量的值。
+     */
     QVariant getValue(const QString& key, const QVariant& defaultValue = QVariant());
+
+    /**
+     * @brief 检查全局变量是否存在。
+     * @param key 键。
+     * @return 如果键存在返回true,否则返回false。
+     */
     bool contains(const QString& key) const;
 
+    /**
+     * @brief 获取键的索引。
+     * @param key 键。
+     * @return 键的索引。
+     */
     uint8_t getKeyIndex(const QString& key);
 
+    /**
+     * @brief 获取全局变量的值,指定值的类型。
+     * @tparam T 值的类型。
+     * @param key 键。
+     * @param defaultValue 默认值,当键不存在时返回。
+     * @return 全局变量的值。
+     */
     template<typename T>
     T getValue(const QString& key, const T& defaultValue = T());
 
-template<typename T>
+    /**
+     * @brief 设置全局变量的值,指定值的类型。
+     * @tparam T 值的类型。
+     * @param key 键。
+     * @param value 值。
+     */
+    template<typename T>
     void setValue(const QString& key, const T& value);
 
 private:
+    /**
+     * @brief 构造函数,私有化以实现单例模式。
+     * @param parent QObject的父对象。
+     */
     explicit Globals(QObject *parent = nullptr);
+
+    /**
+     * @brief 析构函数。
+     */
     ~Globals() = default;
 
+    /**
+     * @brief 生成信号。
+     * @param key 键。
+     * @param value 值。
+     */
     void signalGeneration(const QString& key, const QVariant& value);
 
 signals:
-    // 添加一个信号声明 - 当值改变时发出
+    /**
+     * @brief 当值改变时发出。
+     * @param key 键。
+     * @param value 值。
+     */
     void valueChanged(const QString& key, const QVariant& value);
 
     // 为各个全局变量添加信号表明,当值发生变化时发出
@@ -52,6 +139,7 @@ signals:
     void ocppConfigKeyValueChanged(const CONFIG_KEY_INFO& value);
     void chargingRecordsValueChanged(const CHARGING_RECORDS_INFO& value);
     void tcuConfigValueChanged(const TCU_CFG& value);
+    void pcuConfigValueChanged(const PCU_CFG& value);
     void priceInfoValueChanged(const PRICE_INFO& value);
 
 private:

+ 34 - 0
src/utils/LanguageManager.h

@@ -5,6 +5,40 @@
 #include <QTranslator>
 #include <QApplication>
 
+/**
+ * @class LanguageManager
+ * @brief 语言管理器类,用于管理应用程序的语言设置。
+ * 
+ * LanguageManager 类提供了一种集中管理应用程序语言的方法。它允许用户设置和获取当前的语言,
+ * 并通过信号通知其他组件语言已更改。该类使用 QTranslator 来加载和卸载翻译文件。
+ * 
+ * @note 该类是单例模式,通过静态方法 instance() 获取实例。
+ * 
+ * @public
+ * @fn static LanguageManager* instance();
+ * @brief 获取 LanguageManager 的唯一实例。
+ * 
+ * @fn explicit LanguageManager(QObject *parent = nullptr);
+ * @brief 构造函数,创建一个 LanguageManager 实例。如果提供 parent 参数,则将此对象设置为 parent 的子对象。
+ * 
+ * @fn void setLanguage(const QString& language);
+ * @brief 设置应用程序的语言。
+ * @param language 语言代码,例如 "en" 表示英语,"zh" 表示中文。
+ * 
+ * @fn QString currentLanguage() const;
+ * @brief 获取当前设置的语言。
+ * 
+ * @signals
+ * @fn void languageChanged();
+ * @brief 当语言更改时发出此信号。
+ * 
+ * @private
+ * @var QTranslator* m_translator;
+ * @brief 用于加载和卸载翻译文件的 QTranslator 对象。
+ * 
+ * @var QString m_currentLanguage;
+ * @brief 当前设置的语言代码。
+ */
 class LanguageManager : public QObject
 {
     Q_OBJECT

+ 3 - 3
src/utils/LoggerHelper.cpp

@@ -51,7 +51,7 @@ uint8_t LoggerHelper::init(const QString &logDir, log_level_enum level, int maxS
     }
 
     // 创建日志文件
-    QString logPath = m_logDir + "/" + QDateTime::currentDateTime().toString("TCU_yyyyMMdd") + ".log";
+    QString logPath = m_logDir + "/" + QDateTime::currentDateTimeUtc().toString("TCU_yyyyMMdd") + ".log";
     m_logFile.setFileName(logPath);
 
     if(!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
@@ -70,7 +70,7 @@ void LoggerHelper::log(log_level_enum level, const QString &message, const char*
 
     QMutexLocker locker(&m_mutex);
 
-    QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
+    QString time = QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd hh:mm:ss.zzz");
     QString levelStr = levelToString(level);
     QString logMsg = QString("[%1][%2][%3][%4] : %5").arg(time, QString(file), QString::number(line), levelStr, message);
     qDebug() << logMsg;
@@ -130,7 +130,7 @@ void LoggerHelper::rotateLog()
     m_logFile.close();
 
     QString oldPath = m_logFile.fileName();
-    QString newPath = oldPath + "." + QDateTime::currentDateTime().toString("hhmmsszzz");
+    QString newPath = oldPath + "." + QDateTime::currentDateTimeUtc().toString("hhmmsszzz");
 
     QFile::rename(oldPath, newPath);
 

+ 55 - 0
src/utils/NFCReaderWorker.h

@@ -23,6 +23,32 @@ struct charging_control_info_t {
 };
 Q_DECLARE_METATYPE(charging_control_info_t)
 
+/**
+ * @brief NFCReaderWorker 类用于处理NFC读卡器的工作。
+ * 
+ * 该类继承自QObject,用于在Qt框架中实现NFC读卡器的功能。它提供了处理NFC读卡器工作的核心功能,
+ * 包括连接读卡器、读取卡片信息、关闭读卡器端口等。
+ * 
+ * 核心功能包括:
+ * - 连接指定端口上的NFC读卡器
+ * - 读取卡片信息
+ * - 关闭读卡器端口
+ * - 发送读取结果信号
+ * 
+ * 使用示例:
+ * @code
+ * NFCReaderWorker *worker = new NFCReaderWorker();
+ * worker->doWork("COM3", 1, 5000);
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - parent: QObject的父对象,默认为nullptr
+ * 
+ * 注意事项:
+ * - 使用该类时,需要确保已正确配置Qt环境,并且已连接到正确的NFC读卡器。
+ * - 在使用完毕后,应调用closePort()方法关闭读卡器端口。
+ * - 读取卡片信息时,需要提供一个charging_control_info_t类型的引用参数,用于存储读取结果。
+ */
 class NFCReaderWorker : public QObject
 {
     Q_OBJECT
@@ -32,12 +58,41 @@ public:
     ~NFCReaderWorker();
 
 public slots:
+    /**
+     * @brief 连接到指定端口上的NFC读卡器,并开始工作。
+     * 
+     * @param portName 读卡器连接的端口名称
+     * @param gunId 读卡器ID
+     * @param timeout 超时时间,单位为毫秒
+     */
     void doWork(const QString& portName, int gunId, int timeout);
+
+    /**
+     * @brief 读取卡片信息。
+     * 
+     * @param data 用于存储读取结果的charging_control_info_t类型的引用
+     */
     void doReadCard(charging_control_info_t& data);
+
+    /**
+     * @brief 关闭读卡器端口。
+     */
     void closePort();
 
 signals:
+    /**
+     * @brief 读取结果准备就绪信号。
+     * 
+     * @param authResult 认证结果
+     * @param cardId 卡片ID
+     */
     void resultReady(int authResult, const QString& cardId);
+
+    /**
+     * @brief 执行结果准备就绪信号。
+     * 
+     * @param data 用于存储执行结果的charging_control_info_t类型的引用
+     */
     void execResultReady(charging_control_info_t& data);
 
 private:

+ 116 - 1
src/utils/RS485Controller.h

@@ -15,42 +15,157 @@ namespace RS485Error {
     constexpr int DEVICE_ERROR = -6;
 }
 
+/**
+ * @brief RS485控制器类,用于通过RS485串口进行通信。
+ * 
+ * 该类封装了RS485串口的打开、关闭、数据发送和接收功能。它继承自QObject,可以用于Qt应用程序中。
+ * 
+ * 核心功能包括:
+ * - 打开和关闭RS485串口
+ * - 发送数据并等待响应
+ * - 获取最后一次错误信息
+ * - 配置RS485模式
+ * 
+ * 使用示例:
+ * @code
+ * RS485Controller controller;
+ * controller.openPort("/dev/ttyS2", QSerialPort::Baud9600);
+ * QByteArray data = "Hello, RS485!";
+ * QByteArray reply;
+ * if (controller.sendData(data, reply, 3000)) {
+ *     qDebug() << "Received reply:" << reply;
+ * } else {
+ *     qDebug() << "Timeout or error occurred.";
+ * }
+ * controller.closePort();
+ * @endcode
+ * 
+ * @param parent 父对象指针,用于QObject的继承
+ */
 class RS485Controller : public QObject
 {
     Q_OBJECT
 public:
+    /**
+     * @brief 构造函数,创建RS485Controller对象。
+     * 
+     * @param parent 父对象指针,用于QObject的继承
+     */
     explicit RS485Controller(QObject *parent = nullptr);
+
+    /**
+     * @brief 析构函数,销毁RS485Controller对象。
+     */
     ~RS485Controller();
 
+    /**
+     * @brief 打开RS485串口。
+     * 
+     * @param portName 串口名称,默认为"/dev/ttyS2"
+     * @param baudRate 波特率,默认为9600
+     * @param dataBits 数据位,默认为8位
+     * @param parity 奇偶校验,默认为无校验
+     * @param stopBits 停止位,默认为1位
+     * @param flowControl 流控制,默认为无流控制
+     * @return 是否成功打开串口
+     */
     bool openPort(const QString& portName = "/dev/ttyS2",
                   qint32 baudRate = QSerialPort::Baud9600,
                   QSerialPort::DataBits dataBits = QSerialPort::Data8,
                   QSerialPort::Parity parity = QSerialPort::NoParity,
                   QSerialPort::StopBits stopBits = QSerialPort::OneStop,
                   QSerialPort::FlowControl flowControl = QSerialPort::NoFlowControl);
+
+    /**
+     * @brief 关闭RS485串口。
+     */
     void closePort();
+
+    /**
+     * @brief 检查RS485串口是否已打开。
+     * 
+     * @return 串口是否已打开
+     */
     bool isPortOpen() const;
 
-    // 阻塞发送并等待响应,超时返回false
+    /**
+     * @brief 发送数据并等待响应。
+     * 
+     * 该方法会阻塞发送数据,并等待指定超时时间内的响应。如果超时或发生错误,返回false。
+     * 
+     * @param data 要发送的数据
+     * @param reply 接收到的响应数据
+     * @param timeoutMs 超时时间,单位为毫秒,默认为3000毫秒
+     * @return 是否成功接收到响应
+     */
     bool sendData(const QByteArray& data, QByteArray& reply, int timeoutMs = 3000);
 
+    /**
+     * @brief 获取最后一次发生的错误信息。
+     * 
+     * @return 错误信息字符串
+     */
     QString getLastError() const;
 
+    /**
+     * @brief 配置RS485模式。
+     * 
+     * @return 是否成功配置RS485模式
+     */
     bool configureRS485Mode();
 
 signals:
+    /**
+     * @brief 数据接收信号,当接收到数据时触发。
+     * 
+     * @param data 接收到的数据
+     */
     void dataReceived(const QByteArray& data);
+
+    /**
+     * @brief 串口关闭信号,当串口关闭时触发。
+     */
     void serialPortClosed();
+
+    /**
+     * @brief 错误发生信号,当发生错误时触发。
+     * 
+     * @param errorString 错误信息字符串
+     */
     void errorOccurred(const QString& errorString);
 
 private slots:
+    /**
+     * @brief 处理串口数据可读事件。
+     */
     void handleReadyRead();
+
+    /**
+     * @brief 处理串口错误事件。
+     * 
+     * @param error 发生的错误
+     */
     void handleError(QSerialPort::SerialPortError error);
 
 private:
+    /**
+     * @brief 串口对象指针
+     */
     QSerialPort* m_serialPort = nullptr;
+
+    /**
+     * @brief 最后一次错误信息
+     */
     QString m_lastError;
+
+    /**
+     * @brief 最后一次接收到的响应数据
+     */
     QByteArray m_lastReply;
+
+    /**
+     * @brief 是否已接收到响应
+     */
     bool m_replyReceived = false;
 };
 

+ 27 - 0
src/utils/TcpServerThread.h

@@ -27,6 +27,33 @@ constexpr int MAX_RETRY_COUNT = 3;              // 最大重试次数
 constexpr int HEARTBEAT_TIMEOUT = 10000;        // 心跳检测超时时间(毫秒)
 }
 
+/**
+ * @class TcpServerThread
+ * @brief TcpServerThread 类用于管理 TCP 服务器线程,处理客户端连接、数据发送和接收、心跳检测以及充电枪的认证和控制。
+ * 
+ * 该类实现了 TCP 服务器的核心功能,包括初始化服务器、发送和接收数据、处理客户端连接和断开、以及管理充电枪的状态和认证。
+ * 
+ * 核心功能包括:
+ * - 初始化服务器
+ * - 发送和接收数据
+ * - 处理客户端连接和断开
+ * - 管理充电枪的状态和认证
+ * - 发送心跳回复
+ * 
+ * 使用示例:
+ * @code
+ * TcpServerThread* server = TcpServerThread::instance();
+ * server->init();
+ * server->sendData(0x01, QByteArray::fromHex("010203"));
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - parent: 父对象指针,默认为 nullptr
+ * 
+ * 注意事项:
+ * - 在使用该类之前,请确保已正确初始化 Qt 事件循环。
+ * - 在使用该类时,请确保遵循 Qt 的多线程编程规范。
+ */
 class TcpServerThread : public QObject
 {
     Q_OBJECT

+ 98 - 6
src/utils/VersionManager.h

@@ -4,39 +4,131 @@
 #include <QString>
 #include <QJsonObject>
 
+/**
+ * @class VersionManager
+ * @brief VersionManager 类用于管理版本信息,包括版本号、构建日期、提交信息等,并支持从文件加载和保存这些信息。
+ * 
+ * VersionManager 类提供了一系列方法来获取和设置版本信息,并支持从指定的文件路径加载和保存这些信息。它使用 QJsonObject 来存储版本信息,并提供了一些辅助方法来处理 JSON 数据的转换。
+ * 
+ * @note 使用该类时,请确保文件路径是有效的,并且文件格式符合预期。
+ * 
+ * @param filePath 文件路径,用于加载和保存版本信息。
+ * 
+ * @example
+ * // 创建 VersionManager 对象并加载版本信息
+ * VersionManager manager("path/to/version.json");
+ * if (manager.load()) {
+ *     qDebug() << "Version:" << manager.version();
+ *     qDebug() << "Build Date:" << manager.buildDate();
+ *     qDebug() << "Commit:" << manager.commit();
+ *     qDebug() << "Description:" << manager.description();
+ * }
+ */
 class VersionManager
 {
 public:
+    /**
+     * @brief 构造函数,初始化 VersionManager 对象。
+     * 
+     * @param filePath 文件路径,用于加载和保存版本信息。
+     */
     VersionManager(const QString& filePath);
 
+    /**
+     * @brief 从文件加载版本信息。
+     * 
+     * @return 如果加载成功,返回 true;否则返回 false。
+     */
     bool load();
+
+    /**
+     * @brief 将当前版本信息保存到文件。
+     * 
+     * @return 如果保存成功,返回 true;否则返回 false。
+     */
     bool save();
 
+    /**
+     * @brief 重新加载版本信息。
+     * 
+     * @return 如果重新加载成功,返回 true;否则返回 false。
+     */
     bool reload();
 
+    /**
+     * @brief 获取版本号。
+     * 
+     * @return 当前版本号。
+     */
     QString version() const;
+
+    /**
+     * @brief 设置版本号。
+     * 
+     * @param newVersion 新的版本号。
+     */
     void setVersion(const QString &newVersion);
 
+    /**
+     * @brief 获取构建日期。
+     * 
+     * @return 当前构建日期。
+     */
     QString buildDate() const;
+
+    /**
+     * @brief 设置构建日期。
+     * 
+     * @param newBuildDate 新的构建日期。
+     */
     void setBuildDate(const QString &newBuildDate);
 
+    /**
+     * @brief 获取提交信息。
+     * 
+     * @return 当前提交信息。
+     */
     QString commit() const;
+
+    /**
+     * @brief 设置提交信息。
+     * 
+     * @param newCommit 新的提交信息。
+     */
     void setCommit(const QString &newCommit);
 
+    /**
+     * @brief 获取版本描述。
+     * 
+     * @return 当前版本描述。
+     */
     QString description() const;
+
+    /**
+     * @brief 设置版本描述。
+     * 
+     * @param newDescription 新的版本描述。
+     */
     void setDescription(const QString &newDescription);
 
 private:
+    /**
+     * @brief 将 QJsonObject 转换为 JSON 字符串。
+     */
     void jsonObjectToJson();
+
+    /**
+     * @brief 将 JSON 字符串转换为 QJsonObject。
+     */
     void jsonObjectFromJson();
 
 private:
-    QJsonObject m_object;
-    QString m_filePath;
-    QString m_version;
-    QString m_buildDate;
-    QString m_commit;
-    QString m_description;
+    QJsonObject m_object;    //!< 存储版本信息的 JSON 对象。
+    QString m_filePath;      //!< 文件路径。
+    QString m_version;       //!< 版本号。
+    QString m_buildDate;     //!< 构建日期。
+    QString m_commit;        //!< 提交信息。
+    QString m_description;   //!< 版本描述。
 };
 
 #endif // VERSIONMANAGER_H

+ 168 - 0
src/utils/getVersion.c

@@ -0,0 +1,168 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+***************************************************************************************************
+**   touch /home/root/app_run/bin/app_CCU_V1R2B20250512
+**   ln -s /home/root/app_run/bin/app_CCU_V1R2B20250512 /home/root/app_run/bin/app_CCU
+**   touch /home/root/app_run/bin/app_TCU_V1R2B20250611
+**   ln -s /home/root/app_run/bin/app_TCU_V1R2B20250611 /home/root/app_run/bin/app_TCU
+**   touch /home/root/app_run/bin/app_PCU_V1R2B20250710
+**   ln -s /home/root/app_run/bin/app_PCU_V1R2B20250710 /home/root/app_run/bin/app_PCU 
+**   touch /home/root/app_run/bin/YT800KW_V1R2B20250407
+**   ln -s /home/root/app_run/bin/YT800KW_V1R2B20250407 /home/root/app_run/bin/HWVersion 
+***************************************************************************************************
+*/
+
+
+/*
+**  int major;
+**  int minor;
+**  int build;
+**  char linkname[256];
+**  int ret = get_App_Version("app_CCU", linkname, sizeof(linkname), &major, &minor, &build)
+**  if (ret == 0)
+**  {
+**      
+**  }
+*/
+int get_App_Version(const char* appname, char* linkname, int linkname_size, int *major, int *minor, int *build)
+{
+    if (appname == NULL) return -1;
+    if (linkname == NULL) return -1;
+    if (linkname_size < 256) return -1;
+    if (major == NULL) return -1; *major=0;
+    if (minor == NULL) return -1; *minor=0;
+    if (build == NULL) return -1; *build=0;
+    
+    char fullname[256];
+    memset(linkname, 0, linkname_size);
+    sprintf(fullname, "/home/root/app_run/bin/%s", appname);
+    int ret = readlink(fullname, linkname, linkname_size);
+    // printf("%s.linkname=%s\n", appname, linkname);
+    if (0 <= ret && ret < linkname_size)
+    {
+        char* basename = strstr(linkname, appname);
+        if (strncmp(basename, "app_CCU", 7)==0)
+        {
+            sscanf(basename, "app_CCU_V%dR%dB%d", major, minor, build);
+            sprintf(linkname, "%s", basename);
+            // printf("%s_%d_%d_%d\n", appname, *major, *minor, *build);
+            return 0;
+        }
+        if (strncmp(basename, "app_TCU", 7)==0)
+        {
+            sscanf(basename, "app_TCU_V%dR%dB%d", major, minor, build);
+            sprintf(linkname, "%s", basename);
+            // printf("%s_%d_%d_%d\n", appname, *major, *minor, *build);
+            return 0;
+        }
+        if (strncmp(basename, "app_PCU", 7)==0)
+        {
+            sscanf(basename, "app_PCU_V%dR%dB%d", major, minor, build);
+            sprintf(linkname, "%s", basename);
+            // printf("%s_%d_%d_%d\n", appname, *major, *minor, *build);
+            return 0;
+        }
+        return -1;
+    }
+    return -1;
+}
+/*
+**  char HWString[256];
+**  int ret = get_HW_Version(HWString, sizeof(HWString))
+**  if (ret == 0)
+**  {
+**      
+**  }
+*/
+int get_HW_Version(char* version, int version_size)
+{
+    if (version == NULL) return -1;
+    if (version_size < 256) return -1;
+    char linkname[256];
+    memset(version,0,version_size);
+    int ret = readlink("/home/root/app_run/bin/HWVersion", linkname, sizeof(linkname));
+    // printf("HW.LinkString=%s\n", linkname);
+    if (0 <= ret && ret < version_size)
+    {
+        char* lastname = strrchr(linkname, '/');
+        if (lastname)
+        {
+            sprintf(version, "%s", &lastname[1]);
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/*
+int main(int argc, char* argv[])
+{
+    if (argc != 2)
+    {
+        printf("\n\n\tUsage:\n");
+        printf("\tgetVersion app_CCU\n");
+        printf("\tgetVersion app_TCU\n");
+        printf("\tgetVersion app_PCU\n");
+        printf("\tgetVersion HW\n");
+        return -1;
+    }
+    if (strncmp(argv[1], "app_CCU", 7) == 0)
+    {
+        int major;
+        int minor;
+        int build;
+        char linkname[256];
+        int ret = get_App_Version(argv[1], linkname, sizeof(linkname), &major, &minor, &build);
+        if (ret == 0)
+        {
+            printf("linkname=%s, major:%d, minor:%d, build:%d\n", linkname, major, minor, build);
+        }else{
+            printf("failed\n");
+        }
+    }
+    if (strncmp(argv[1], "app_TCU", 7) == 0)
+    {
+        int major;
+        int minor;
+        int build;
+        char linkname[256];
+        int ret = get_App_Version(argv[1], linkname, sizeof(linkname), &major, &minor, &build);
+        if (ret == 0)
+        {
+            printf("linkname=%s, major:%d, minor:%d, build:%d\n", linkname, major, minor, build);
+        }else{
+            printf("failed.\n");
+        }
+    }
+    if (strncmp(argv[1], "app_PCU", 7) == 0)
+    {
+        int major;
+        int minor;
+        int build;
+        char linkname[256];
+        int ret = get_App_Version(argv[1], linkname, sizeof(linkname), &major, &minor, &build);
+        if (ret == 0)
+        {
+            printf("linkname=%s, major:%d, minor:%d, build:%d\n", linkname, major, minor, build);
+        }else{
+            printf("failed\n");
+        }
+    }
+    if (strncmp(argv[1], "HW", 2) == 0)
+    {
+        char linkname[256];
+        int ret = get_HW_Version(linkname, sizeof(linkname));
+        if (ret == 0)
+        {
+            printf("HW.linkname=%s\n", linkname);
+        }else{
+            printf("failed.\n");
+        }
+    }
+    return 0;
+}
+*/

+ 71 - 6
src/widgets/custom/AnimatedStackedWidget.h

@@ -5,6 +5,23 @@
 #include <QPropertyAnimation>
 #include <QParallelAnimationGroup>
 
+/**
+ * @class AnimatedStackedWidget
+ * @brief AnimatedStackedWidget 是一个继承自 QStackedWidget 的类,用于在切换页面时添加动画效果。
+ * 
+ * AnimatedStackedWidget 提供了多种动画方向,包括从左到右、从右到左、从上到下、从下到上、淡入淡出、缩放和旋转。
+ * 用户可以通过设置动画持续时间、动画类型,并调用 slideToIndex、slideToNext 和 slideToPrevious 方法来切换页面并应用动画效果。
+ * 
+ * @note 该类依赖于 Qt 框架中的动画和动画组类,因此需要在 Qt 环境中使用。
+ * 
+ * @example
+ * AnimatedStackedWidget *stackedWidget = new AnimatedStackedWidget(parent);
+ * stackedWidget->setAnimationDuration(500); // 设置动画持续时间为 500 毫秒
+ * stackedWidget->setAnimationType(AnimatedStackedWidget::FadeIn); // 设置动画类型为淡入
+ * stackedWidget->slideToIndex(1); // 切换到索引为 1 的页面
+ * 
+ * @param parent 父 QWidget 对象,默认为 nullptr
+ */
 class AnimatedStackedWidget : public QStackedWidget
 {
     Q_OBJECT
@@ -20,27 +37,75 @@ public:
         Rotate       // 旋转
     };
 
+    /**
+     * @brief 构造函数,创建一个 AnimatedStackedWidget 对象。
+     * 
+     * @param parent 父 QWidget 对象,默认为 nullptr
+     */
     explicit AnimatedStackedWidget(QWidget *parent = nullptr);
+
+    /**
+     * @brief 析构函数,销毁 AnimatedStackedWidget 对象。
+     */
     ~AnimatedStackedWidget();
 
-    // 设置动画持续时间
+    /**
+     * @brief 设置动画持续时间。
+     * 
+     * @param msecs 动画持续时间,以毫秒为单位
+     */
     void setAnimationDuration(int msecs);
-    // 设置动画类型
+
+    /**
+     * @brief 设置动画类型。
+     * 
+     * @param type 动画类型,枚举值之一
+     */
     void setAnimationType(AnimationDirection type);
-    // 切换到指定索引的页面
+
+    /**
+     * @brief 切换到指定索引的页面。
+     * 
+     * @param index 页面索引
+     */
     void slideToIndex(int index);
-    // 切换到下一个页面
+
+    /**
+     * @brief 切换到下一个页面。
+     */
     void slideToNext();
-    // 切换到上一个页面
+
+    /**
+     * @brief 切换到上一个页面。
+     */
     void slideToPrevious();
-    
+
+    /**
+     * @brief 设置当前显示的页面。
+     * 
+     * @param widget 要显示的 QWidget 对象
+     */
     void setCurrentWidget(QWidget *widget) ;
 
 protected:
+    /**
+     * @brief 重写 paintEvent 方法,用于绘制动画效果。
+     * 
+     * @param event QPaintEvent 对象
+     */
     virtual void paintEvent(QPaintEvent *event) override;
 
 private:
+    /**
+     * @brief 初始化动画相关变量。
+     */
     void initAnimation();
+
+    /**
+     * @brief 开始动画。
+     * 
+     * @param nextIndex 下一个页面的索引
+     */
     void startAnimation(int nextIndex);
 
 private:

+ 69 - 1
src/widgets/custom/BaseWidget.h

@@ -4,31 +4,99 @@
 #include <QObject>
 #include <QWidget>
 
+/**
+ * @class BaseWidget
+ * @brief BaseWidget 是一个基于 QWidget 的抽象基类,用于管理表单状态和修改标记。
+ * 
+ * BaseWidget 提供了管理当前表单、前一个表单和修改标记的功能。它是一个抽象类,不能直接实例化。
+ * 子类需要实现 returnParent() 方法,并可以重载其他方法以提供特定的行为。
+ * 
+ * @note 子类必须实现 returnParent() 方法。
+ * 
+ * @param parent 指向父 QWidget 的指针,默认为 nullptr。
+ */
 class BaseWidget : public QWidget
 {
     Q_OBJECT
 public:
+    /**
+     * @brief 构造函数,创建一个新的 BaseWidget 实例。
+     * 
+     * @param parent 指向父 QWidget 的指针,默认为 nullptr。
+     */
     explicit BaseWidget(QWidget *parent = nullptr);
 
+    /**
+     * @brief 返回父 QWidget 的指针。
+     * 
+     * @return 父 QWidget 的指针。
+     */
     virtual bool returnParent() = 0;
 
+    /**
+     * @brief 获取当前表单的索引。
+     * 
+     * @return 当前表单的索引。
+     */
     int currentForm() const;
 
+    /**
+     * @brief 设置当前表单的索引。
+     * 
+     * @param newCurrentForm 新的当前表单索引。
+     */
     void setCurrentForm(int newCurrentForm);
 
+    /**
+     * @brief 获取前一个表单的索引。
+     * 
+     * @return 前一个表单的索引。
+     */
     int prevForm() const;
 
+    /**
+     * @brief 设置前一个表单的索引。
+     * 
+     * @param newPrevForm 新的前一个表单索引。
+     */
     void setPrevForm(int newPrevForm);
 
+    /**
+     * @brief 检查是否有修改。
+     * 
+     * @return 如果有修改返回 true,否则返回 false。
+     */
     bool isModify() const;
 
+    /**
+     * @brief 设置修改标记。
+     * 
+     * @param newIsModify 新的修改标记。
+     */
     void setIsModify(bool newIsModify);
 
 signals:
+    /**
+     * @brief 当标题刷新时发出此信号。
+     * 
+     * @param title 新的标题。
+     */
     void refreshTitles(const QString& title);
 
 private:
-    int m_currentForm, m_prevForm;
+    /**
+     * @brief 当前表单的索引。
+     */
+    int m_currentForm;
+
+    /**
+     * @brief 前一个表单的索引。
+     */
+    int m_prevForm;
+
+    /**
+     * @brief 修改标记。
+     */
     bool m_isModify = false;
 };
 

+ 20 - 8
src/widgets/custom/CustomComboBox.cpp

@@ -75,21 +75,25 @@ QString CustomComboBox::currentText() const
 
 void CustomComboBox::setCurrentIndex(int index)
 {
-    emit currentIndexChanged(index);
+    if (m_currentIndex == index) return;
     m_currentIndex = index;
     listWidget->setCurrentRow(index);
     displayLabel->setText(listWidget->currentItem()->text());
+    emit currentIndexChanged(index);
+    emit currentTextChanged(listWidget->currentItem()->text());
 }
 
 void CustomComboBox::setCurrentText(const QString &text)
 {
     auto row = listWidget->count();
+    if (text == displayLabel->text()) return;
     for (int index = 0; index < row; index ++) {
         if (text == listWidget->item(index)->text()) {
-            emit currentIndexChanged(index);
             m_currentIndex = index;
             listWidget->setCurrentRow(index);
             displayLabel->setText(listWidget->currentItem()->text());
+            emit currentIndexChanged(index);
+            emit currentTextChanged(text);
             return;
         }
     }
@@ -111,6 +115,11 @@ int CustomComboBox::findText(const QString &text)
     return -1;
 }
 
+int CustomComboBox::count()
+{
+    return listWidget->count();
+}
+
 void CustomComboBox::mousePressEvent(QMouseEvent *event)
 {
     QWidget::mousePressEvent(event);
@@ -132,12 +141,15 @@ void CustomComboBox::mousePressEvent(QMouseEvent *event)
 
 void CustomComboBox::onItemClicked(QListWidgetItem *item)
 {
-    displayLabel->setText(item->text());
-    m_currentIndex = listWidget->row(item);
-    emit currentIndexChanged(m_currentIndex);
-    listWidget->hide();
-    isDisplay = false;
-    arrowBtn->setIcon(QIcon(":/icons/spread.png"));
+    if (item->text() != displayLabel->text()) {
+        displayLabel->setText(item->text());
+        m_currentIndex = listWidget->row(item);
+        listWidget->hide();
+        isDisplay = false;
+        arrowBtn->setIcon(QIcon(":/icons/spread.png"));
+        emit currentIndexChanged(m_currentIndex);
+        emit currentTextChanged(item->text());
+    }
 }
 
 bool CustomComboBox::eventFilter(QObject *obj, QEvent *event)

+ 2 - 0
src/widgets/custom/CustomComboBox.h

@@ -42,9 +42,11 @@ public:
     void setCurrentText(const QString& text);
     int currentIndex() const;
     int findText(const QString& text);
+    int count();
 
 signals:
     void currentIndexChanged(int index);
+    void currentTextChanged(QString text);
 
 protected:
     void mousePressEvent(QMouseEvent *event) override;

+ 21 - 0
src/widgets/custom/CustomDoubleSpinBox.h

@@ -10,6 +10,27 @@
 
 #include "settings/OtherSettings/dialog/DialogEditValue.h"
 
+/**
+ * @class CustomDoubleSpinBox
+ * @brief CustomDoubleSpinBox 是一个继承自 QDoubleSpinBox 的自定义小部件,用于在用户界面中显示和编辑双精度浮点数。
+ * 
+ * CustomDoubleSpinBox 类扩展了 QDoubleSpinBox 的功能,允许用户通过自定义对话框编辑数值。该类的主要功能包括:
+ * - 显示和编辑双精度浮点数。
+ * - 通过事件过滤器实现自定义对话框的显示。
+ * 
+ * 使用示例:
+ * @code
+ * CustomDoubleSpinBox *spinBox = new CustomDoubleSpinBox(parentWidget);
+ * spinBox->setValue(3.14);
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - QWidget *parent: 父窗口部件,默认为 nullptr。
+ * 
+ * 注意事项:
+ * - 使用该类时,请确保父窗口部件已经正确初始化。
+ * - 该类可能存在潜在的副作用,例如在编辑过程中可能会改变用户界面状态。
+ */
 class CustomDoubleSpinBox : public QDoubleSpinBox
 {
     Q_OBJECT

+ 60 - 1
src/widgets/custom/CustomLineEdit.h

@@ -7,23 +7,82 @@
 
 #include "settings/OtherSettings/dialog/DialogEditValue.h"
 
+/**
+ * @class CustomLineEdit
+ * @brief CustomLineEdit 是一个继承自 QLineEdit 的自定义编辑框类,用于在应用程序中提供更高级的输入功能。
+ * 
+ * CustomLineEdit 类扩展了 QLineEdit 的功能,通过设置不同的表单类型和编辑类型,可以定制化输入框的行为。
+ * 它还提供了一个事件处理函数,用于处理自定义的事件。
+ * 
+ * @note 使用该类时,需要确保在 Qt 应用程序中正确初始化。
+ * 
+ * @author Your Name
+ * @version 1.0
+ * 
+ * @param parent 指向父 QWidget 的指针,用于设置该 QLineEdit 的父对象。默认为 nullptr。
+ * 
+ * @example
+ * CustomLineEdit *lineEdit = new CustomLineEdit(parentWidget);
+ * lineEdit->setFormType(FormType::SomeType);
+ * lineEdit->setEditType(EditType::SomeType);
+ * 
+ * @warning 请注意,该类使用 QScopedPointer 管理内部资源,因此不需要手动释放内存。
+ */
 class CustomLineEdit : public QLineEdit
 {
     Q_OBJECT
 public:
+    /**
+     * @brief 构造函数,创建一个新的 CustomLineEdit 对象。
+     * 
+     * @param parent 指向父 QWidget 的指针,用于设置该 QLineEdit 的父对象。默认为 nullptr。
+     */
     explicit CustomLineEdit(QWidget *parent = nullptr);
+
+    /**
+     * @brief 析构函数,销毁 CustomLineEdit 对象。
+     */
     ~CustomLineEdit();
 
+    /**
+     * @brief 设置表单类型。
+     * 
+     * @param newFormType 新的表单类型,用于定制化输入框的行为。
+     */
     void setFormType(int newFormType);
 
+    /**
+     * @brief 设置编辑类型。
+     * 
+     * @param newEditType 新的编辑类型,用于定制化输入框的行为。
+     */
     void setEditType(int newEditType);
 
 protected:
+    /**
+     * @brief 事件处理函数,用于处理自定义的事件。
+     * 
+     * @param event 指向 QEvent 的指针,表示发生的事件。
+     * 
+     * @return 如果事件被处理,则返回 true;否则返回 false。
+     */
     bool event(QEvent* event) override;
 
 private:
+    /**
+     * @brief 使用 QScopedPointer 管理的 DialogEditValue 对象指针。
+     */
     QScopedPointer<DialogEditValue> m_input_dialog;
-    int formType, editType;
+
+    /**
+     * @brief 当前表单类型。
+     */
+    int formType;
+
+    /**
+     * @brief 当前编辑类型。
+     */
+    int editType;
 };
 
 #endif // CUSTOMLINEEDIT_H

+ 147 - 0
src/widgets/custom/CustomNavigationBar.cpp

@@ -59,6 +59,77 @@ void CustomNavigationBar::setSelectItem(const int &data)
     }
 }
 
+bool CustomNavigationBar::removeNavigationItem(const QString& text)
+{
+    // 遍历所有顶层项
+    for (int i = 0; i < ui->navigationBar->topLevelItemCount(); ++i) {
+        QTreeWidgetItem* item = ui->navigationBar->topLevelItem(i);
+        if (findAndRemoveItem(item, text)) {
+            return true;  // 找到并删除后直接返回
+        }
+    }
+    return false;  // 未找到
+}
+
+bool CustomNavigationBar::removeNavigationItem(const int& data)
+{
+    // 遍历所有顶层项
+    for (int i = 0; i < ui->navigationBar->topLevelItemCount(); ++i) {
+        QTreeWidgetItem* item = ui->navigationBar->topLevelItem(i);
+        if (findAndRemoveItem(item, data)) {
+            return true;  // 找到并删除后直接返回
+        }
+    }
+    return false;  // 未找到
+}
+
+bool CustomNavigationBar::removeNavigationItem(QTreeWidgetItem* item)
+{
+    if (!item) {
+        return false;
+    }
+    
+    // 检查是否是当前选中的项,如果是则清除选中状态
+    if (ui->navigationBar->currentItem() == item) {
+        ui->navigationBar->setCurrentItem(nullptr);
+    }
+    
+    // 删除项及其所有子项
+    delete item;
+    return true;
+}
+
+void CustomNavigationBar::clearNavigationItems()
+{
+    ui->navigationBar->clear();
+}
+
+QTreeWidgetItem* CustomNavigationBar::findNavigationItem(const QString& text)
+{
+    // 遍历所有顶层项
+    for (int i = 0; i < ui->navigationBar->topLevelItemCount(); ++i) {
+        QTreeWidgetItem* item = ui->navigationBar->topLevelItem(i);
+        QTreeWidgetItem* foundItem = findItemRecursive(item, text);
+        if (foundItem) {
+            return foundItem;  // 找到后直接返回
+        }
+    }
+    return nullptr;  // 未找到
+}
+
+QTreeWidgetItem* CustomNavigationBar::findNavigationItem(const int& data)
+{
+    // 遍历所有顶层项
+    for (int i = 0; i < ui->navigationBar->topLevelItemCount(); ++i) {
+        QTreeWidgetItem* item = ui->navigationBar->topLevelItem(i);
+        QTreeWidgetItem* foundItem = findItemRecursive(item, data);
+        if (foundItem) {
+            return foundItem;  // 找到后直接返回
+        }
+    }
+    return nullptr;  // 未找到
+}
+
 void CustomNavigationBar::initTreeWidget()
 {
     ui->navigationBar->setHeaderHidden(true);
@@ -108,6 +179,82 @@ bool CustomNavigationBar::findAndSelectItem(QTreeWidgetItem *parentItem, const i
     return false;  // 未找到
 }
 
+bool CustomNavigationBar::findAndRemoveItem(QTreeWidgetItem* parentItem, const QString& targetText)
+{
+    // 检查当前项是否符合条件
+    if (parentItem->text(0) == targetText) {
+        removeNavigationItem(parentItem);
+        return true;
+    }
+
+    // 递归检查所有子项
+    for (int i =0; i < parentItem->childCount(); ++i) {
+        QTreeWidgetItem* childItem = parentItem->child(i);
+        if (findAndRemoveItem(childItem, targetText)) {
+            return true;
+        }
+    }
+
+    return false;  // 未找到
+}
+
+bool CustomNavigationBar::findAndRemoveItem(QTreeWidgetItem* parentItem, const int& data)
+{
+    // 检查当前项是否符合条件
+    if (parentItem->data(0, Qt::UserRole).toInt() == data) {
+        removeNavigationItem(parentItem);
+        return true;
+    }
+
+    // 递归检查所有子项
+    for (int i =0; i < parentItem->childCount(); ++i) {
+        QTreeWidgetItem* childItem = parentItem->child(i);
+        if (findAndRemoveItem(childItem, data)) {
+            return true;
+        }
+    }
+
+    return false;  // 未找到
+}
+
+QTreeWidgetItem* CustomNavigationBar::findItemRecursive(QTreeWidgetItem* parentItem, const QString& targetText)
+{
+    // 检查当前项是否符合条件
+    if (parentItem->text(0) == targetText) {
+        return parentItem;
+    }
+
+    // 递归检查所有子项
+    for (int i =0; i < parentItem->childCount(); ++i) {
+        QTreeWidgetItem* childItem = parentItem->child(i);
+        QTreeWidgetItem* foundItem = findItemRecursive(childItem, targetText);
+        if (foundItem) {
+            return foundItem;
+        }
+    }
+
+    return nullptr;  // 未找到
+}
+
+QTreeWidgetItem* CustomNavigationBar::findItemRecursive(QTreeWidgetItem* parentItem, const int& data)
+{
+    // 检查当前项是否符合条件
+    if (parentItem->data(0, Qt::UserRole).toInt() == data) {
+        return parentItem;
+    }
+
+    // 递归检查所有子项
+    for (int i =0; i < parentItem->childCount(); ++i) {
+        QTreeWidgetItem* childItem = parentItem->child(i);
+        QTreeWidgetItem* foundItem = findItemRecursive(childItem, data);
+        if (foundItem) {
+            return foundItem;
+        }
+    }
+
+    return nullptr;  // 未找到
+}
+
 void CustomNavigationBar::slotTreeWidgetItemClicked(const QTreeWidgetItem *item, const int column)
 {
     emit navigationItemClicked(item->data(column, Qt::UserRole).toInt());

+ 94 - 0
src/widgets/custom/CustomNavigationBar.h

@@ -9,6 +9,35 @@ namespace Ui {
 class CustomNavigationBar;
 }
 
+/**
+ * @class CustomNavigationBar
+ * @brief CustomNavigationBar 是一个自定义的导航栏类,继承自 QWidget。
+ * 它提供了一个树形结构来展示导航项,并允许用户通过点击或选择来导航。
+ * 
+ * 核心功能包括:
+ * - 添加导航项
+ * - 展开或折叠所有导航项
+ * - 设置选中的导航项
+ * - 处理导航项点击事件
+ * 
+ * 使用示例:
+ * @code
+ * CustomNavigationBar *navigationBar = new CustomNavigationBar(parentWidget);
+ * navigationBar->addNavigationItem("Home", 1);
+ * navigationBar->addNavigationItem("About", 2, navigationBar->rootItem());
+ * navigationBar->setSelectItem("Home");
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - QWidget *parent: 父窗口部件,默认为 nullptr。
+ * 
+ * 使用限制:
+ * - 本类依赖于 Qt 框架。
+ * - 需要确保在调用任何方法之前,导航栏已经正确初始化。
+ * 
+ * 潜在副作用:
+ * - 在调用某些方法时,可能会导致 UI 更新,影响用户体验。
+ */
 class CustomNavigationBar : public QWidget
 {
     Q_OBJECT
@@ -17,15 +46,80 @@ public:
     explicit CustomNavigationBar(QWidget *parent = nullptr);
     ~CustomNavigationBar();
 
+    /**
+     * @brief 添加一个导航项到导航栏。
+     * @param text 导航项的文本。
+     * @param data 导航项的数据。
+     * @param parent 导航项的父项,默认为 nullptr。
+     * @return 添加的导航项的指针。
+     */
     QTreeWidgetItem* addNavigationItem(const QString &text, const int data, QTreeWidgetItem *parent = nullptr);
+
+    /**
+     * @brief 展开所有导航项。
+     */
     void expandAll();
+
+    /**
+     * @brief 设置选中的导航项,通过文本匹配。
+     * @param text 导航项的文本。
+     */
     void setSelectItem(const QString& text);
+
+    /**
+     * @brief 设置选中的导航项,通过数据匹配。
+     * @param data 导航项的数据。
+     */
     void setSelectItem(const int& data);
 
+    /**
+     * @brief 删除导航项,通过文本匹配。
+     * @param text 导航项的文本。
+     * @return 是否删除成功。
+     */
+    bool removeNavigationItem(const QString& text);
+
+    /**
+     * @brief 删除导航项,通过数据匹配。
+     * @param data 导航项的数据。
+     * @return 是否删除成功。
+     */
+    bool removeNavigationItem(const int& data);
+
+    /**
+     * @brief 删除指定的导航项节点。
+     * @param item 要删除的导航项节点。
+     * @return 是否删除成功。
+     */
+    bool removeNavigationItem(QTreeWidgetItem* item);
+
+    /**
+     * @brief 清空所有导航项。
+     */
+    void clearNavigationItems();
+
+    /**
+     * @brief 查找导航项,通过文本匹配。
+     * @param text 导航项的文本。
+     * @return 找到的导航项指针,未找到返回nullptr。
+     */
+    QTreeWidgetItem* findNavigationItem(const QString& text);
+
+    /**
+     * @brief 查找导航项,通过数据匹配。
+     * @param data 导航项的数据。
+     * @return 找到的导航项指针,未找到返回nullptr。
+     */
+    QTreeWidgetItem* findNavigationItem(const int& data);
+
 private:
     void initTreeWidget();
     bool findAndSelectItem(QTreeWidgetItem* parentItem, const QString& targetText);
     bool findAndSelectItem(QTreeWidgetItem* parentItem, const int& data);
+    bool findAndRemoveItem(QTreeWidgetItem* parentItem, const QString& targetText);
+    bool findAndRemoveItem(QTreeWidgetItem* parentItem, const int& data);
+    QTreeWidgetItem* findItemRecursive(QTreeWidgetItem* parentItem, const QString& targetText);
+    QTreeWidgetItem* findItemRecursive(QTreeWidgetItem* parentItem, const int& data);
 
 private slots:
     void slotTreeWidgetItemClicked(const QTreeWidgetItem* item, const int column);

+ 3 - 1
src/widgets/custom/CustomQDateTimeEdit.cpp

@@ -13,6 +13,8 @@ CustomQDateTimeEdit::CustomQDateTimeEdit(QWidget *parent)
     m_input_dialog->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
     m_input_dialog->setWindowModality(Qt::WindowModal);
 
+    setTimeSpec(Qt::UTC);
+
     QLineEdit* edit = this->findChild<QLineEdit*>();
     if (edit) {
         edit->setReadOnly(true);
@@ -32,7 +34,7 @@ bool CustomQDateTimeEdit::eventFilter(QObject *obj, QEvent *event)
         m_input_dialog->setEditType(EditType::DATETIME);
         auto ret = m_input_dialog->exec();
         if (ret == QDialog::Accepted) {
-            setDateTime(QDateTime::fromString(m_input_dialog->getValue(General::Type::DATE_TIME), Qt::ISODateWithMs));
+            setDateTime(QDateTime::fromString(m_input_dialog->getValue(General::Type::DATE_TIME), Qt::ISODate));
         }
         return true; // 拦截
     }

+ 39 - 0
src/widgets/custom/CustomQDateTimeEdit.h

@@ -10,17 +10,56 @@
 
 #include "settings/OtherSettings/dialog/DialogEditValue.h"
 
+/**
+ * @class CustomQDateTimeEdit
+ * @brief CustomQDateTimeEdit 是一个自定义的 QDateTimeEdit 控件,它允许用户通过对话框编辑日期和时间值。
+ * 
+ * 这个类继承自 QDateTimeEdit,并添加了一个事件过滤器,用于在用户点击控件时显示一个对话框,让用户编辑日期和时间值。
+ * 
+ * @note 使用这个类时,需要确保 Qt 库已经正确安装和配置。
+ * 
+ * @param parent 指向父控件的指针,如果为 nullptr,则此控件没有父控件。
+ * 
+ * @example
+ * 下面是一个简单的示例,展示了如何使用 CustomQDateTimeEdit 控件:
+ * 
+ * @code
+ * QWidget *parentWidget = new QWidget;
+ * CustomQDateTimeEdit *customDateTimeEdit = new CustomQDateTimeEdit(parentWidget);
+ * customDateTimeEdit->setDateTime(QDateTime::currentDateTimeUtc());
+ * @endcode
+ */
 class CustomQDateTimeEdit : public QDateTimeEdit
 {
     Q_OBJECT
 public:
+    /**
+     * @brief 构造函数,创建一个 CustomQDateTimeEdit 对象。
+     * 
+     * @param parent 指向父控件的指针,如果为 nullptr,则此控件没有父控件。
+     */
     explicit CustomQDateTimeEdit(QWidget *parent = nullptr);
+
+    /**
+     * @brief 析构函数,销毁 CustomQDateTimeEdit 对象。
+     */
     ~CustomQDateTimeEdit();
 
 protected:
+    /**
+     * @brief 事件过滤器,用于处理自定义事件。
+     * 
+     * @param obj 发生事件的 QObject 对象。
+     * @param event 发生的事件。
+     * 
+     * @return 如果事件被处理,则返回 true;否则返回 false。
+     */
     bool eventFilter(QObject *obj, QEvent *event) override;
 
 private:
+    /**
+     * @brief 指向一个 DialogEditValue 对象的指针,用于显示对话框编辑日期和时间值。
+     */
     QScopedPointer<DialogEditValue> m_input_dialog;
 };
 

+ 23 - 0
src/widgets/custom/CustomSpinBox.h

@@ -10,6 +10,29 @@
 
 #include "settings/OtherSettings/dialog/DialogEditValue.h"
 
+/**
+ * @class CustomSpinBox
+ * @brief CustomSpinBox 是一个继承自 QSpinBox 的自定义类,用于创建一个带有自定义编辑对话框的数字选择框。
+ * 
+ * 这个类的主要功能是提供一个带有自定义编辑对话框的数字选择框,用户可以通过点击编辑按钮来打开对话框进行数值的编辑。
+ * 
+ * 核心功能包括:
+ * - 提供一个自定义的编辑对话框,用于输入和编辑数值。
+ * - 重写 eventFilter 方法,用于处理自定义的编辑事件。
+ * 
+ * 使用示例:
+ * @code
+ * CustomSpinBox *spinBox = new CustomSpinBox(this);
+ * spinBox->setValue(10);
+ * @endcode
+ * 
+ * 构造函数参数:
+ * - QWidget *parent: 父窗口部件,用于设置 CustomSpinBox 的父对象。
+ * 
+ * 注意事项:
+ * - 使用 CustomSpinBox 时,需要确保父窗口部件已经正确设置。
+ * - 在使用过程中,如果需要自定义编辑对话框的样式和行为,可以通过重写相关方法来实现。
+ */
 class CustomSpinBox : public QSpinBox
 {
     Q_OBJECT

+ 1 - 1
src/widgets/titleBar/TitleBar.cpp

@@ -80,7 +80,7 @@ void TitleBar::initConnect()
 
 void TitleBar::updateTime()
 {
-    QDateTime now = QDateTime::currentDateTime();
+    QDateTime now = QDateTime::currentDateTimeUtc();
     // QDateTime zoneTime = now.toTimeZone(m_timeZone);
     ui->cur_time->setText(now.toString("yyyy-MM-dd HH:mm:ss"));
 }

+ 52 - 9
src/widgets/workspace/settings/CcuSettings/FormCcuSetting.cpp

@@ -14,8 +14,32 @@ FormCcuSetting::FormCcuSetting(BaseWidget *parent)
 {
     ui->setupUi(this);
 
+    initWidget();
+    initConnect();
+}
+
+FormCcuSetting::~FormCcuSetting()
+{
+    delete ui;
+}
+
+bool FormCcuSetting::returnParent()
+{
+    if (getCCUConfig(m_ccu_cfg)) {
+        return ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue<CCU_CFG>(m_ccu_cfg));
+    } else {
+        return false;
+    }
+}
+
+void FormCcuSetting::initWidget()
+{
     GeneralInterface::setTouchScroller(ui->scrollArea);
 
+}
+
+void FormCcuSetting::initConnect()
+{
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
     connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& ccu_cfg) {
         if (!this->isVisible()) return;
@@ -35,19 +59,33 @@ FormCcuSetting::FormCcuSetting(BaseWidget *parent)
             refreshData(m_ccu_cfg);
         }
     });
-}
 
-FormCcuSetting::~FormCcuSetting()
-{
-    delete ui;
+    connectAllValueChanged(this);
 }
 
-bool FormCcuSetting::returnParent()
+void FormCcuSetting::connectAllValueChanged(QWidget *widget)
 {
-    if (getCCUConfig(m_ccu_cfg)) {
-        return ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue<CCU_CFG>(m_ccu_cfg));
-    } else {
-        return false;
+    // QLineEdit
+    if (auto edit = qobject_cast<CustomLineEdit*>(widget)) {
+        connect(edit, &QLineEdit::textChanged, this, &FormCcuSetting::onValueChanged);
+    }
+    // CustomLineEdit
+    else if (auto edit = qobject_cast<CustomLineEdit*>(widget)) {
+        connect(edit, &CustomLineEdit::textChanged, this, &FormCcuSetting::onValueChanged);
+    }
+    // CustomSpinBox
+    else if (auto spin = qobject_cast<CustomSpinBox*>(widget)) {
+        connect(spin, QOverload<int>::of(&QSpinBox::valueChanged), this, &FormCcuSetting::onValueChanged);
+    }
+    // QCheckBox
+    else if (auto check = qobject_cast<QCheckBox*>(widget)) {
+        connect(check, &QCheckBox::stateChanged, this, &FormCcuSetting::onValueChanged);
+    }
+
+    // 递归遍历所有子控件
+    auto list = widget->findChildren<QWidget*>();
+    for (auto child : std::as_const(list)) {
+        connectAllValueChanged(child);
     }
 }
 
@@ -103,3 +141,8 @@ void FormCcuSetting::hideEvent(QHideEvent *event)
     setIsModify(false);
     BaseWidget::hideEvent(event);
 }
+
+void FormCcuSetting::onValueChanged()
+{
+    setIsModify(true);
+}

+ 6 - 0
src/widgets/workspace/settings/CcuSettings/FormCcuSetting.h

@@ -58,6 +58,9 @@ public:
     bool returnParent() override;
 
 private:
+    void initWidget();
+    void initConnect();
+    void connectAllValueChanged(QWidget *widget);
     /**
      * @brief 刷新 CCU 设置数据。
      * @param data CCU 配置数据。
@@ -84,6 +87,9 @@ protected:
      */
     void hideEvent(QHideEvent* event) override;
 
+private slots:
+    void onValueChanged();
+
 private:
     /**
      * @brief 指向 UI 类的指针。

+ 70 - 70
src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.cpp

@@ -1,30 +1,37 @@
 #include "FormChargeGunDetail.h"
 #include "ui_FormChargeGunDetail.h"
 
+#include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "OtherSettings/dialog/DialogChargingPopup.h"
 
-FormChargeGunDetail::FormChargeGunDetail(QWidget *parent)
-    : QWidget(parent)
+FormChargeGunDetail::FormChargeGunDetail(int gun_id, BaseWidget *parent)
+    : BaseWidget(parent)
     , ui(new Ui::FormChargeGunDetail)
+    , m_gun_id(gun_id)
 {
     ui->setupUi(this);
 
     initComboBox();
+    initConnect();
+    setWindowTitle(QString("Gun #%1 Detail Settings").arg(m_gun_id));
+}
+
+FormChargeGunDetail::~FormChargeGunDetail()
+{
+    delete ui;
+}
 
+bool FormChargeGunDetail::returnParent()
+{
+    updateData();
+    return ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue(m_ccu_cfg));
+}
+
+void FormChargeGunDetail::initConnect()
+{
     connectAllValueChanged(this);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
-    connect(ui->status, &QToolButton::clicked, this, [this]() {
-        if (m_is_spread) {
-            ui->gun_detail->hide();
-            ui->status->setIcon(QIcon(":/icons/spread.png"));
-            m_is_spread = false;
-        } else {
-            ui->gun_detail->show();
-            ui->status->setIcon(QIcon(":/icons/packup.png"));
-            m_is_spread = true;
-        }
-    });
 
     // test
     connect(ui->requestPowerByMinutes, &QCheckBox::clicked, this, [this](bool status) {
@@ -47,23 +54,6 @@ FormChargeGunDetail::FormChargeGunDetail(QWidget *parent)
     });
 }
 
-FormChargeGunDetail::~FormChargeGunDetail()
-{
-    delete ui;
-}
-
-GUN_DETAIL FormChargeGunDetail::gun_detail()
-{
-    m_gun_detail = getNewData();
-    return m_gun_detail;
-}
-
-void FormChargeGunDetail::setGun_detail(const GUN_DETAIL &newGun_detail)
-{
-    m_gun_detail = newGun_detail;
-    refreshData();
-}
-
 void FormChargeGunDetail::initComboBox()
 {
     initGunTypeComboBox();
@@ -98,48 +88,50 @@ void FormChargeGunDetail::initCanIfnameComboBox()
 
 void FormChargeGunDetail::refreshData()
 {
-    ui->gun_name->setText(QString(tr("Charge Gun #%1")).arg(QString::number(m_gun_detail.GUN_ID)));
-    ui->GUN_ID->setText(QString::number(m_gun_detail.GUN_ID));
-    ui->GUN_Type->setCurrentText(m_gun_detail.GUN_Type);
-    ui->GUN_Available->setChecked(m_gun_detail.GUN_Available);
-    ui->GUN_maxI->setValue(m_gun_detail.GUN_maxI);
-    ui->slac_ifname->setCurrentText(m_gun_detail.slac_ifname);
-    ui->can_ifname->setCurrentText(m_gun_detail.can_ifname);
-    ui->QRCode_enable->setChecked(m_gun_detail.QRCode_enable);
-    ui->QRCode_URL->setText(m_gun_detail.QRCode_URL);
-    ui->requestPowerByMinutes->setChecked(m_gun_detail.requestPowerByMinutes);
-    ui->requestPowerByPowerKW->setChecked(m_gun_detail.requestPowerByPowerKW);
-    ui->requestPowerBySOC->setChecked(m_gun_detail.requestPowerBySOC);
-    ui->GUNOverTemp_Warning->setValue(m_gun_detail.GUNOverTemp_Warning);
-    ui->GUNOverTemp_Stopping->setValue(m_gun_detail.GUNOverTemp_Stopping);
-    ui->enable_current_limit->setChecked(m_gun_detail.enable_current_limit);
-    ui->permitted_current->setValue(m_gun_detail.permitted_current);
-    ui->enable_powerKW_limit->setChecked(m_gun_detail.enable_powerKW_limit);
-    ui->permitted_powerKW->setValue(m_gun_detail.permitted_powerKW);
+    foreach (const auto& data, m_ccu_cfg.GUN_Detail) {
+        if (data.GUN_ID != m_gun_id) continue;
+        ui->GUN_ID->setText(QString::number(data.GUN_ID));
+        ui->GUN_Type->setCurrentText(data.GUN_Type);
+        ui->GUN_Available->setChecked(data.GUN_Available);
+        ui->GUN_maxI->setValue(data.GUN_maxI);
+        ui->slac_ifname->setCurrentText(data.slac_ifname);
+        ui->can_ifname->setCurrentText(data.can_ifname);
+        ui->QRCode_enable->setChecked(data.QRCode_enable);
+        ui->QRCode_URL->setText(data.QRCode_URL);
+        ui->requestPowerByMinutes->setChecked(data.requestPowerByMinutes);
+        ui->requestPowerByPowerKW->setChecked(data.requestPowerByPowerKW);
+        ui->requestPowerBySOC->setChecked(data.requestPowerBySOC);
+        ui->GUNOverTemp_Warning->setValue(data.GUNOverTemp_Warning);
+        ui->GUNOverTemp_Stopping->setValue(data.GUNOverTemp_Stopping);
+        ui->enable_current_limit->setChecked(data.enable_current_limit);
+        ui->permitted_current->setValue(data.permitted_current);
+        ui->enable_powerKW_limit->setChecked(data.enable_powerKW_limit);
+        ui->permitted_powerKW->setValue(data.permitted_powerKW);
+    }
 }
 
-GUN_DETAIL FormChargeGunDetail::getNewData()
+void FormChargeGunDetail::updateData()
 {
-    GUN_DETAIL data;
-    data.GUN_ID                 = ui->GUN_ID->text().toInt();
-    data.GUN_Type               = ui->GUN_Type->currentText();
-    data.GUN_Available          = ui->GUN_Available->isChecked();
-    data.GUN_maxI               = ui->GUN_maxI->value();
-    data.slac_ifname            = ui->slac_ifname->currentText();
-    data.can_ifname             = ui->can_ifname->currentText();
-    data.QRCode_enable          = ui->QRCode_enable->isChecked();
-    data.QRCode_URL             = ui->QRCode_URL->text();
-    data.requestPowerByMinutes  = ui->requestPowerByMinutes->isChecked();
-    data.requestPowerByPowerKW  = ui->requestPowerByPowerKW->isChecked();
-    data.requestPowerBySOC      = ui->requestPowerBySOC->isChecked();
-    data.GUNOverTemp_Warning    = ui->GUNOverTemp_Warning->value();
-    data.GUNOverTemp_Stopping   = ui->GUNOverTemp_Stopping->value();
-    data.enable_current_limit   = ui->enable_current_limit->isChecked();
-    data.permitted_current      = ui->permitted_current->value();
-    data.enable_powerKW_limit   = ui->enable_powerKW_limit->isChecked();
-    data.permitted_powerKW      = ui->permitted_powerKW->value();
-
-    return data;
+    for(int index = 0; index < m_ccu_cfg.GUN_Detail.size(); index ++) {
+        if (m_ccu_cfg.GUN_Detail[index].GUN_ID != m_gun_id) continue;
+        m_ccu_cfg.GUN_Detail[index].GUN_ID                 = ui->GUN_ID->text().toInt();
+        m_ccu_cfg.GUN_Detail[index].GUN_Type               = ui->GUN_Type->currentText();
+        m_ccu_cfg.GUN_Detail[index].GUN_Available          = ui->GUN_Available->isChecked();
+        m_ccu_cfg.GUN_Detail[index].GUN_maxI               = ui->GUN_maxI->value();
+        m_ccu_cfg.GUN_Detail[index].slac_ifname            = ui->slac_ifname->currentText();
+        m_ccu_cfg.GUN_Detail[index].can_ifname             = ui->can_ifname->currentText();
+        m_ccu_cfg.GUN_Detail[index].QRCode_enable          = ui->QRCode_enable->isChecked();
+        m_ccu_cfg.GUN_Detail[index].QRCode_URL             = ui->QRCode_URL->text();
+        m_ccu_cfg.GUN_Detail[index].requestPowerByMinutes  = ui->requestPowerByMinutes->isChecked();
+        m_ccu_cfg.GUN_Detail[index].requestPowerByPowerKW  = ui->requestPowerByPowerKW->isChecked();
+        m_ccu_cfg.GUN_Detail[index].requestPowerBySOC      = ui->requestPowerBySOC->isChecked();
+        m_ccu_cfg.GUN_Detail[index].GUNOverTemp_Warning    = ui->GUNOverTemp_Warning->value();
+        m_ccu_cfg.GUN_Detail[index].GUNOverTemp_Stopping   = ui->GUNOverTemp_Stopping->value();
+        m_ccu_cfg.GUN_Detail[index].enable_current_limit   = ui->enable_current_limit->isChecked();
+        m_ccu_cfg.GUN_Detail[index].permitted_current      = ui->permitted_current->value();
+        m_ccu_cfg.GUN_Detail[index].enable_powerKW_limit   = ui->enable_powerKW_limit->isChecked();
+        m_ccu_cfg.GUN_Detail[index].permitted_powerKW      = ui->permitted_powerKW->value();
+    }
 }
 
 void FormChargeGunDetail::connectAllValueChanged(QWidget *widget)
@@ -181,5 +173,13 @@ void FormChargeGunDetail::connectAllValueChanged(QWidget *widget)
 
 void FormChargeGunDetail::onValueChanged()
 {
-    emit valueChanged();
+    setIsModify(true);
+}
+
+void FormChargeGunDetail::showEvent(QShowEvent *event)
+{
+    setIsModify(false);
+    m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    refreshData();
+    BaseWidget::showEvent(event);
 }

+ 12 - 6
src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.h

@@ -2,31 +2,33 @@
 #define FORMCHARGEGUNDETAIL_H
 
 #include <QWidget>
+
+#include "BaseWidget.h"
 #include "DataTypeDef.h"
 
 namespace Ui {
 class FormChargeGunDetail;
 }
 
-class FormChargeGunDetail : public QWidget
+class FormChargeGunDetail : public BaseWidget
 {
     Q_OBJECT
 
 public:
-    explicit FormChargeGunDetail(QWidget *parent = nullptr);
+    explicit FormChargeGunDetail(int gun_id, BaseWidget *parent = nullptr);
     ~FormChargeGunDetail();
 
-    GUN_DETAIL gun_detail();
-    void setGun_detail(const GUN_DETAIL &newGun_detail);
+    bool returnParent() override;
 
 private:
+    void initConnect();
     void initComboBox();
     void initGunTypeComboBox();
     void initSlacIfnameComboBox();
     void initCanIfnameComboBox();
 
     void refreshData();
-    GUN_DETAIL getNewData();
+    void updateData();
 
     void connectAllValueChanged(QWidget *widget);
 
@@ -36,9 +38,13 @@ private slots:
 signals:
     void valueChanged();
 
+protected:
+    void showEvent(QShowEvent* event) override;
+
 private:
     Ui::FormChargeGunDetail *ui;
-    GUN_DETAIL m_gun_detail;
+    int m_gun_id;
+    CCU_CFG m_ccu_cfg;
     bool m_is_spread = true;
 };
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 646 - 699
src/widgets/workspace/settings/CcuSettings/FormChargeGunDetail.ui


+ 1 - 51
src/widgets/workspace/settings/CcuSettings/FormChargeGunType.cpp

@@ -1,11 +1,6 @@
 #include "FormChargeGunType.h"
 #include "ui_FormChargeGunType.h"
 
-#include "ConfigManager.h"
-#include "LanguageManager.h"
-#include "GeneralInterface.h"
-#include "CcuSettings/FormChargeGunDetail.h"
-
 #include <QLayoutItem>
 #include <QSpacerItem>
 #include <QMessageBox>
@@ -15,9 +10,6 @@ FormChargeGunType::FormChargeGunType(BaseWidget *parent)
     , ui(new Ui::FormChargeGunType)
 {
     ui->setupUi(this);
-
-    GeneralInterface::setTouchScroller(ui->scrollArea);
-    initConnect();
 }
 
 FormChargeGunType::~FormChargeGunType()
@@ -27,47 +19,5 @@ FormChargeGunType::~FormChargeGunType()
 
 bool FormChargeGunType::returnParent()
 {
-    updateData();
-    return ConfigManager::instance()->saveConfig(CCU_CONFIG, QVariant::fromValue<CCU_CFG>(m_ccu_cfg));
-}
-
-void FormChargeGunType::initConnect()
-{
-    connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
-}
-
-void FormChargeGunType::refreshData()
-{
-    GeneralInterface::clearGridLayoutChiledren(ui->gun_layout);
-    for (const GUN_DETAIL& data : std::as_const(m_ccu_cfg.GUN_Detail)) {
-        m_gun_map[data.GUN_ID] = new FormChargeGunDetail();
-        m_gun_map[data.GUN_ID]->setGun_detail(data);
-        GeneralInterface::gridLayoutAddWidget(ui->gun_layout, m_gun_map[data.GUN_ID]);
-
-        connect(m_gun_map[data.GUN_ID], &FormChargeGunDetail::valueChanged, this, [this]() {
-            setIsModify(true);
-        });
-
-        setIsModify(false);
-    }
-
-    GeneralInterface::gridLayoutAddStrtch(ui->gun_layout);
-}
-
-void FormChargeGunType::updateData()
-{
-    m_ccu_cfg.GUN_Detail.clear();
-    auto form_list = m_gun_map.values();
-    for (int index = 0; index < m_gun_map.count(); index ++) {
-        auto gun_detail = form_list[index];
-        m_ccu_cfg.GUN_Detail.append(gun_detail->gun_detail());
-    }
-}
-
-void FormChargeGunType::showEvent(QShowEvent *event)
-{
-    setIsModify(false);
-    m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
-    refreshData();
-    BaseWidget::showEvent(event);
+    return true;
 }

+ 0 - 13
src/widgets/workspace/settings/CcuSettings/FormChargeGunType.h

@@ -5,8 +5,6 @@
 #include <QScopedPointer>
 
 #include "BaseWidget.h"
-#include "CcuSettings/FormChargeGunDetail.h"
-#include "DataTypeDef.h"
 
 namespace Ui {
 class FormChargeGunType;
@@ -23,18 +21,7 @@ public:
     bool returnParent() override;
 
 private:
-    void initConnect();
-
-    void refreshData();
-    void updateData();
-
-protected:
-    void showEvent(QShowEvent *event) override;
-
-private:
     Ui::FormChargeGunType *ui;
-    QMap<int, FormChargeGunDetail*> m_gun_map;
-    CCU_CFG m_ccu_cfg;
 };
 
 #endif // FORMCHARGEGUNTYPE_H

+ 2 - 2
src/widgets/workspace/settings/CcuSettings/FormOfflinePrice.cpp

@@ -132,8 +132,8 @@ void FormOfflinePrice::refreshPriceInfo(const QList<OFFLINE_PRICE> &info)
     ui->priceTableWidget->clearContents();
     ui->priceTableWidget->setRowCount(0);
     for (const auto& data : info) {
-        auto period = QString("%1-%2").arg(QDateTime::fromString(data.startTime, Qt::ISODateWithMs).toString("HH:mm:ss"),
-                                           QDateTime::fromString(data.endTime, Qt::ISODateWithMs).toString("HH:mm:ss"));
+        auto period = QString("%1-%2").arg(QDateTime::fromString(data.startTime, Qt::ISODate).toString("HH:mm:ss"),
+                                           QDateTime::fromString(data.endTime, Qt::ISODate).toString("HH:mm:ss"));
         auto electric = QString::number(data.electrPrice, 'f', 2);
         auto service = QString::number(data.servicePrice, 'f', 2);
         auto total = QString::number(data.electrPrice+data.servicePrice, 'f', 2);

+ 2 - 2
src/widgets/workspace/settings/CcuSettings/FormPriceDetail.cpp

@@ -34,8 +34,8 @@ FormPriceDetail::~FormPriceDetail()
 
 void FormPriceDetail::refreshData()
 {
-    ui->startTime->setDateTime(QDateTime::fromString(m_price.startTime, Qt::ISODateWithMs));
-    ui->endTime->setDateTime(QDateTime::fromString(m_price.endTime, Qt::ISODateWithMs));
+    ui->startTime->setDateTime(QDateTime::fromString(m_price.startTime, Qt::ISODate));
+    ui->endTime->setDateTime(QDateTime::fromString(m_price.endTime, Qt::ISODate));
     ui->electric->setValue(m_price.electrPrice);
     ui->service->setValue(m_price.servicePrice);
     ui->duration->setValue(m_price.durationPrice);

+ 123 - 34
src/widgets/workspace/settings/FormSettings.cpp

@@ -1,12 +1,16 @@
 #include "FormSettings.h"
 #include "ui_FormSettings.h"
 
+#include "Globals.h"
 #include "DataTypeDef.h"
+#include "ConfigManager.h"
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
 #include "CcuSettings/FormCcuSetting.h"
 #include "CcuSettings/FormOfflinePrice.h"
 #include "CcuSettings/FormChargeGunType.h"
+#include "CcuSettings/FormChargeGunDetail.h"
 #include "CcuSettings/FormPcuhwSettings.h"
 #include "CcuSettings/FormPcutcSettings.h"
 #include "CcuSettings/FormQttcuSettings.h"
@@ -20,6 +24,7 @@
 #include "OcppSettings/FormLocalAuthList.h"
 #include "OcppSettings/FormAuthorizationCache.h"
 
+#include "OcppSettings/FormOcppSettings.h"
 #include "OcppSettings/ChargingProfiles/FormChargingProfilesSettings.h"
 #include "OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.h"
 #include "OcppSettings/ChargingProfiles/FormTxDufaultProfile.h"
@@ -54,29 +59,30 @@ bool FormSettings::returnParent()
     auto form_list = m_formMap.values();
     for (QWidget* widget : std::as_const(form_list)) {
         BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
-        if (!temp) return true;
+        // qDebug() << temp->objectName() << temp->isModify();
+        if (!temp) continue;
         if (temp->isModify()) {
             setIsModify(true);
         }
     }
 
-    bool isSave = false;
-    if (isModify()) {
-        auto ret = QMessageBox::question(this, tr("Save"),
-                                         tr("The content has been modified. Do you want to save the changes?"),
-                                         QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes);
-        if (ret == QMessageBox::Yes) {      // save
-            isSave = true;
-        } else if (ret == QMessageBox::No){ // no save
-            isSave = false;
-        } else {                            // cancel
-            return false;
-        }
-    }
+    bool isSave = true;
+    // if (isModify()) {
+    //     auto ret = QMessageBox::question(this, tr("Save"),
+    //                                      tr("The content has been modified. Do you want to save the changes?"),
+    //                                      QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes);
+    //     if (ret == QMessageBox::Yes) {      // save
+    //         isSave = true;
+    //     } else if (ret == QMessageBox::No){ // no save
+    //         isSave = false;
+    //     } else {                            // cancel
+    //         return false;
+    //     }
+    // }
 
     for (QWidget* widget : std::as_const(form_list)) {
         BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
-        if (!temp) return true;
+        if (!temp) continue;
         if (temp->isModify() && isModify() && isSave) {
             temp->returnParent();
         }
@@ -94,12 +100,54 @@ void FormSettings::initConnect()
     });
 
     auto charging_profiles_form = qobject_cast<FormChargingProfilesSettings*>(m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]);
-    connect(charging_profiles_form, &FormChargingProfilesSettings::currentFormChanged, this, [this](const int& index) {
-        setPrevForm(index);
-        showForm(index);
+    connect(charging_profiles_form, &FormChargingProfilesSettings::currentFormChanged, this, &FormSettings::onUpdateChargingProfileData);
+
+    connect(GLOBALS, &Globals::ccuConfigValueChanged, this, [this](const CCU_CFG& ccu_cfg) {
+        if (m_ccu_cfg.GUN_Numb != ccu_cfg.GUN_Numb) {
+            m_ccu_cfg = ccu_cfg;
+            refreshGunSettingsNavigationBar();
+        }
     });
 }
 
+void FormSettings::refreshNavigationBar()
+{
+    refreshGunSettingsNavigationBar();
+    ui->navigation->setSelectItem(Workspace::Settings::CCU);
+}
+
+void FormSettings::refreshGunSettingsNavigationBar()
+{
+    auto gun_num = m_ccu_cfg.GUN_Numb;
+    for(int index = 0; index < gun_num; index ++) {
+        auto nodeName = QString("Gun Detail #%1").arg(index + 1);
+        if (ui->navigation->findNavigationItem(nodeName)) {
+            ui->navigation->removeNavigationItem(nodeName);
+            m_formMap.remove(getNodeDataByGunId(index+1));
+        } else {
+            auto parentNodeName = QString("Charge Gun Settings");
+            auto parentNode = ui->navigation->findNavigationItem(parentNodeName);
+            if (parentNode) {
+                ui->navigation->addNavigationItem(nodeName, getNodeDataByGunId(index+1), parentNode);
+                m_formMap[getNodeDataByGunId(index+1)]    = new FormChargeGunDetail(index+1);
+            }
+        }
+    }
+
+    refreshStackWidget();
+}
+
+int FormSettings::getNodeDataByGunId(const int &gun_id)
+{
+    switch (gun_id) {
+    case CHARGE_GUN_DEFAULT_1:  return Workspace::Settings::Ccu::ChargeGun::CHARGE_GUN_1;
+    case CHARGE_GUN_DEFAULT_2:  return Workspace::Settings::Ccu::ChargeGun::CHARGE_GUN_2;
+    default:                    return 0;
+    }
+
+    return 0;
+}
+
 void FormSettings::initNavigationBar()
 {
     auto ccu = ui->navigation->addNavigationItem(tr("CCU Settings"),        Workspace::Settings::CCU);
@@ -141,12 +189,36 @@ void FormSettings::showForm(int form)
     emit refreshTitles(m_formMap[form]->windowTitle());
 }
 
+void FormSettings::onUpdateChargingProfileData(const charging_profiles_detail_info_t &info)
+{
+    auto index = GeneralInterface::getChargingProfilePurposeIndex(info.chargingProfilePurpose);
+    switch (index) {
+    case Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE:
+
+        break;
+    case Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE:
+    {
+        auto txDefaultForm = qobject_cast<FormTxDufaultProfile*>(m_formMap[index]);
+        txDefaultForm->setProfile_info(info);
+        break;
+    }
+    case Workspace::Settings::Ocpp::ChargingProfiles::TX_PROFILE:
+
+        break;
+    default:
+        break;
+    }
+
+    setPrevForm(index);
+    showForm(index);
+}
+
 void FormSettings::hideEvent(QHideEvent *event)
 {
     auto form_list = m_formMap.values();
     for (QWidget* widget : std::as_const(form_list)) {
         BaseWidget* temp = qobject_cast<BaseWidget*>(widget);
-        if (!temp) return;
+        if (!temp) continue;
         temp->setIsModify(false);
     }
 
@@ -154,6 +226,13 @@ void FormSettings::hideEvent(QHideEvent *event)
     BaseWidget::hideEvent(event);
 }
 
+void FormSettings::showEvent(QShowEvent *event)
+{
+    m_ccu_cfg = ConfigManager::instance()->ccu_cfg();
+    refreshNavigationBar();
+    BaseWidget::showEvent(event);
+}
+
 void FormSettings::slotReturnPrevForm()
 {
     switch (currentForm()) {
@@ -165,6 +244,11 @@ void FormSettings::slotReturnPrevForm()
         setCurrentForm(Workspace::Home::SETTINGS);
         emit returnPrevForm();
         break;
+    case Workspace::Settings::Ccu::ChargeGun::CHARGE_GUN_1:
+    case Workspace::Settings::Ccu::ChargeGun::CHARGE_GUN_2:
+        showForm(Workspace::Settings::Ccu::CHARGE_GUN);
+        ui->navigation->setSelectItem(Workspace::Settings::Ccu::CHARGE_GUN);
+        break;
     case Workspace::Settings::Ccu::CHARGE_GUN:
     case Workspace::Settings::Ccu::OFFLINE_PRICES:
     case Workspace::Settings::Ccu::PCUHW:
@@ -206,23 +290,23 @@ void FormSettings::initWidget()
     ui->old_settings->setWindowTitle(tr("Settings"));
     ui->new_settings->setWindowTitle(tr("Settings"));
 
-    m_formMap[Workspace::Settings::CCU]                         = new FormCcuSetting();
-    m_formMap[Workspace::Settings::Ccu::OFFLINE_PRICES]         = new FormOfflinePrice();
-    m_formMap[Workspace::Settings::Ccu::CHARGE_GUN]             = new FormChargeGunType();
-    m_formMap[Workspace::Settings::Ccu::PCUHW]                  = new FormPcuhwSettings();
-    m_formMap[Workspace::Settings::Ccu::PCUTC]                  = new FormPcutcSettings();
-    m_formMap[Workspace::Settings::Ccu::QTTCU]                  = new FormQttcuSettings();
-    m_formMap[Workspace::Settings::Ccu::OCPP16]                 = new FormOcppGeneralSettings(OcppVersion::OCPP16);
-    m_formMap[Workspace::Settings::Ccu::OCPP21]                 = new FormOcppGeneralSettings(OcppVersion::OCPP21);
+    m_formMap[Workspace::Settings::CCU]                             = new FormCcuSetting();
+    m_formMap[Workspace::Settings::Ccu::OFFLINE_PRICES]             = new FormOfflinePrice();
+    m_formMap[Workspace::Settings::Ccu::CHARGE_GUN]                 = new FormChargeGunType();
+    m_formMap[Workspace::Settings::Ccu::PCUHW]                      = new FormPcuhwSettings();
+    m_formMap[Workspace::Settings::Ccu::PCUTC]                      = new FormPcutcSettings();
+    m_formMap[Workspace::Settings::Ccu::QTTCU]                      = new FormQttcuSettings();
+    m_formMap[Workspace::Settings::Ccu::OCPP16]                     = new FormOcppGeneralSettings(OcppVersion::OCPP16);
+    m_formMap[Workspace::Settings::Ccu::OCPP21]                     = new FormOcppGeneralSettings(OcppVersion::OCPP21);
 
-    m_formMap[Workspace::Settings::TCU]                         = new FormTcuSettings();
-    m_formMap[Workspace::Settings::PCU]                         = new FormPcuSettings();
+    m_formMap[Workspace::Settings::TCU]                             = new FormTcuSettings();
+    m_formMap[Workspace::Settings::PCU]                             = new FormPcuSettings();
 
-    m_formMap[Workspace::Settings::OCPP]                        = new QWidget();
-    m_formMap[Workspace::Settings::Ocpp::CONFIG_KEY]            = new FormConfigurationKey();
-    m_formMap[Workspace::Settings::Ocpp::LOCAL_AUTH_LIST]       = new FormLocalAuthList();
-    m_formMap[Workspace::Settings::Ocpp::AUTH_CACHE]            = new FormAuthorizationCache();
-    m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]     = new FormChargingProfilesSettings();
+    m_formMap[Workspace::Settings::OCPP]                            = new FormOcppSettings();
+    m_formMap[Workspace::Settings::Ocpp::CONFIG_KEY]                = new FormConfigurationKey();
+    m_formMap[Workspace::Settings::Ocpp::LOCAL_AUTH_LIST]           = new FormLocalAuthList();
+    m_formMap[Workspace::Settings::Ocpp::AUTH_CACHE]                = new FormAuthorizationCache();
+    m_formMap[Workspace::Settings::Ocpp::CHARGING_PROFILES]         = new FormChargingProfilesSettings();
 
     m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::CHARGE_POINT_MAX_PROFILE]    = new FormChargingPointMaxProfile();
     m_formMap[Workspace::Settings::Ocpp::ChargingProfiles::TX_DEFAULT_PROFILE]          = new FormTxDufaultProfile();
@@ -233,6 +317,11 @@ void FormSettings::initWidget()
     m_formMap[Workspace::Settings::Other::FIRMWARE_INFO]        = new FormFirmwareInfo();
     m_formMap[Workspace::Settings::Other::CHARGING_RECORDS]     = new FormChargeRecords();
 
+    refreshStackWidget();
+}
+
+void FormSettings::refreshStackWidget()
+{
     // 添加页面到堆叠窗口并隐藏
     auto widgets = m_formMap.values();
     foreach (const auto& widget, std::as_const(widgets)) {

+ 11 - 0
src/widgets/workspace/settings/FormSettings.h

@@ -5,6 +5,7 @@
 #include <QMap>
 
 #include "BaseWidget.h"
+#include "DataTypeDef.h"
 
 namespace Ui {
 class FormSettings;
@@ -25,20 +26,30 @@ public slots:
 
 private:
     void initWidget();
+    void refreshStackWidget();
     void initConnect();
 
+    void refreshNavigationBar();
+    void refreshGunSettingsNavigationBar();
+    int getNodeDataByGunId(const int& gun_id);
+
     void initNavigationBar();
 
     void showForm(int form);
 
+private slots:
+    void onUpdateChargingProfileData(const charging_profiles_detail_info_t& info);
+
 signals:
     void returnPrevForm();
 
 protected:
     void hideEvent(QHideEvent* event) override;
+    void showEvent(QShowEvent* event) override;
 
 private:
     Ui::FormSettings *ui;
+    CCU_CFG m_ccu_cfg;
 
     // 表单映射,存储不同类型的表单
     QMap<int, QWidget*> m_formMap;

+ 221 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.cpp

@@ -0,0 +1,221 @@
+#include "DialogChargingProfileEdit.h"
+#include "ui_DialogChargingProfileEdit.h"
+
+#include <QScreen>
+#include <QTimer>
+#include <QWindow>
+#include <QDebug>
+#include <QIntValidator>
+#include <QPropertyAnimation>
+
+#include "DataTypeDef.h"
+#include "ConfigManager.h"
+#include "LanguageManager.h"
+#include "GeneralInterface.h"
+
+DialogChargingProfileEdit::DialogChargingProfileEdit(QWidget *parent)
+    : QDialog(parent)
+    , ui(new Ui::DialogChargingProfileEdit)
+{
+    ui->setupUi(this);
+
+    initWidget();
+    initConnect();
+}
+
+DialogChargingProfileEdit::~DialogChargingProfileEdit()
+{
+    delete ui;
+}
+
+void DialogChargingProfileEdit::clear()
+{
+    ui->chargingProfileID->setText("");
+    ui->connectorID->setCurrentIndex();
+    ui->stackLevel->setCurrentIndex();
+    ui->chargingProfilePurpose->setCurrentIndex();
+    ui->chargingProfileKind->setCurrentIndex();
+    ui->recurrencyKind->setCurrentIndex();
+}
+
+charging_profiles_detail_info_t DialogChargingProfileEdit::getChargingProfile()
+{
+    charging_profiles_detail_info_t info;
+    info.chargingProfileId      = ui->chargingProfileID->text().toInt();
+    info.connectorId            = ui->connectorID->currentText().toInt();
+    info.stackLevel             = ui->stackLevel->currentText().toInt();
+    info.chargingProfilePurpose = ui->chargingProfilePurpose->currentText();
+    info.chargingProfileKind    = ui->chargingProfileKind->currentText();
+    info.recurrencyKind         = ui->recurrencyKind->currentText();
+
+    return info;
+}
+
+void DialogChargingProfileEdit::initWidget()
+{
+    setWindowModality(Qt::WindowModal);
+    setAttribute(Qt::WA_TranslucentBackground);
+    setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+
+    setBackground();
+
+    initComboBox();
+}
+
+void DialogChargingProfileEdit::initConnect()
+{
+    connect(ui->cancel, &QPushButton::clicked, this, [this]() {
+        reject();
+    });
+    connect(ui->ok, &QPushButton::clicked, this, [this](){
+        accept();
+    });
+    connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+
+    connect(ui->chargingProfilePurpose, &CustomComboBox::currentTextChanged, this, [this](const QString& text) {
+        if (text == ChargingProfiles::Purpose::CHARGE_POINT_MAX_PROFILE) {
+            ui->connectorID_label->setVisible(true);
+            ui->connectorID->setVisible(false);
+        } else if (text == ChargingProfiles::Purpose::TX_DEFAULT_PROFILE) {
+            ui->connectorID_label->setVisible(false);
+            ui->connectorID->setVisible(true);
+        } else if (text == ChargingProfiles::Purpose::TX_PROFILE) {
+            ui->connectorID_label->setVisible(true);
+            ui->connectorID->setVisible(false);
+        }
+    });
+    connect(ui->chargingProfileKind, &CustomComboBox::currentIndexChanged, this, [this](const int& index) {
+        switch (index) {
+        case ChargingProfiles::Kind::ABSOLUTE_ID:
+        case ChargingProfiles::Kind::RELATIVE_ID:
+            ui->recurrencyKind->setCurrentIndex(ChargingProfiles::RecurrencyKind::NO_RECURRING_ID);
+            ui->recurrencyKind->setEnabled(false);
+            break;
+        case ChargingProfiles::Kind::RECURRING_ID:
+            ui->recurrencyKind->setEnabled(true);
+            break;
+        default:
+            break;
+        }
+    });
+}
+
+void DialogChargingProfileEdit::initComboBox()
+{
+    initConnectorIdComboBox();
+    initStackLevelComboBox();
+    initPurposeComboBox();
+    initKindComboBox();
+    initRecurrencyKindComboBox();
+}
+
+void DialogChargingProfileEdit::initConnectorIdComboBox()
+{
+    auto gun_num = ConfigManager::instance()->ccu_cfg().GUN_Numb;
+    QStringList connectorIDItems;
+    for (int index = 1; index <= gun_num; index ++) {
+        connectorIDItems << QString::number(index);
+    }
+    ui->connectorID->addItems(connectorIDItems);
+    ui->connectorID->setEnabled(gun_num == 1);
+}
+
+void DialogChargingProfileEdit::initStackLevelComboBox()
+{
+    auto stack_level = ConfigManager::instance()->cfg_key().SmartChargingProfile.ChargeProfileMaxStackLevel;
+    QStringList stackLevelItems;
+    for (int index = 0; index <= stack_level; index ++) {
+        stackLevelItems << QString::number(index);
+    }
+    ui->stackLevel->addItems(stackLevelItems);
+}
+
+void DialogChargingProfileEdit::initPurposeComboBox()
+{
+    QStringList purposeItems;
+    purposeItems << ChargingProfiles::Purpose::CHARGE_POINT_MAX_PROFILE
+                 << ChargingProfiles::Purpose::TX_DEFAULT_PROFILE
+                 << ChargingProfiles::Purpose::TX_PROFILE;
+
+    ui->chargingProfilePurpose->addItems(purposeItems);
+}
+
+void DialogChargingProfileEdit::initKindComboBox()
+{
+    QStringList kind_list;
+    kind_list << ChargingProfiles::Kind::ABSOLUTE
+              << ChargingProfiles::Kind::RELATIVE
+              << ChargingProfiles::Kind::RECURRING;
+    ui->chargingProfileKind->addItems(kind_list);
+}
+
+void DialogChargingProfileEdit::initRecurrencyKindComboBox()
+{
+    QStringList recurrencyKindList;
+    recurrencyKindList << ChargingProfiles::RecurrencyKind::NO_RECURRING
+                       << ChargingProfiles::RecurrencyKind::DAILY
+                       << ChargingProfiles::RecurrencyKind::WEEKLY;
+    ui->recurrencyKind->addItems(recurrencyKindList);
+}
+
+void DialogChargingProfileEdit::refreshData()
+{
+    ui->recurrencyKind->setEnabled(false);
+    ui->connectorID_label->setVisible(true);
+    ui->connectorID->setVisible(false);
+    auto charging_profiles = ConfigManager::instance()->charging_profiles().chargingProfiles;
+    ui->chargingProfileID->setText(QString::number(GeneralInterface::getMaxChargingProfileId(charging_profiles) + 1));
+}
+
+void DialogChargingProfileEdit::setBackground()
+{
+    m_background = new QLabel();
+    ui->background_layout->addWidget(m_background, 0, 0, ui->background_layout->rowCount(), ui->background_layout->columnCount());
+    m_background->setPixmap(QPixmap(":/images/price/dialog_edit_background.png"));
+    m_background->lower();
+    m_background->setScaledContents(true);
+}
+
+void DialogChargingProfileEdit::centerWindow()
+{
+    // 确保窗口尺寸已确定(关键修复)
+    this->ensurePolished();
+    // this->adjustSize();
+
+    // 获取有效的屏幕几何尺寸(考虑多显示器)
+    QScreen *screen = QGuiApplication::primaryScreen();
+    if (QWindow *window = this->windowHandle()) {
+        screen = window->screen();
+    }
+    QRect screenGeometry = screen->availableGeometry();
+
+    // 计算居中位置(考虑Wayland特性)
+    int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
+    int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
+
+    if (QGuiApplication::platformName().contains("wayland")) {
+        // Wayland专用处理
+        if (QWindow *window = this->windowHandle()) {
+            // 重要:延迟设置位置,确保Wayland合成器已准备好
+            QTimer::singleShot(100, this, [window, x, y]() {
+                window->setPosition(QPoint(x, y));
+
+                // 替代requestActivate的方案
+                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
+                QTimer::singleShot(50, [window]() {
+                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
+                });
+            });
+        }
+    } else {
+        // 传统X11处理
+        this->move(x, y);
+    }
+}
+
+void DialogChargingProfileEdit::showEvent(QShowEvent *event)
+{
+    centerWindow();
+    refreshData();
+    QDialog::showEvent(event);
+}

+ 48 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.h

@@ -0,0 +1,48 @@
+#ifndef DIALOGCHARGINGPROFILEEDIT_H
+#define DIALOGCHARGINGPROFILEEDIT_H
+
+#include <QDialog>
+#include <QLabel>
+
+#include "DataTypeDef.h"
+
+namespace Ui {
+class DialogChargingProfileEdit;
+}
+
+class DialogChargingProfileEdit : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit DialogChargingProfileEdit(QWidget *parent = nullptr);
+    ~DialogChargingProfileEdit();
+
+    void clear();
+
+    charging_profiles_detail_info_t getChargingProfile();
+
+private:
+    void initWidget();
+    void initConnect();
+    void initComboBox();
+    void initConnectorIdComboBox();
+    void initStackLevelComboBox();
+    void initPurposeComboBox();
+    void initKindComboBox();
+    void initRecurrencyKindComboBox();
+
+    void refreshData();
+
+    void setBackground();
+    void centerWindow();
+
+protected:
+    void showEvent(QShowEvent* event) override;
+
+private:
+    Ui::DialogChargingProfileEdit *ui;
+    QLabel* m_background;
+};
+
+#endif // DIALOGCHARGINGPROFILEEDIT_H

+ 414 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogChargingProfileEdit.ui

@@ -0,0 +1,414 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DialogChargingProfileEdit</class>
+ <widget class="QDialog" name="DialogChargingProfileEdit">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>735</width>
+    <height>606</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="background_layout">
+     <item row="1" column="0">
+      <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
+       <property name="leftMargin">
+        <number>20</number>
+       </property>
+       <property name="topMargin">
+        <number>20</number>
+       </property>
+       <property name="rightMargin">
+        <number>20</number>
+       </property>
+       <property name="bottomMargin">
+        <number>20</number>
+       </property>
+       <item>
+        <widget class="QLabel" name="titles">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>100</height>
+          </size>
+         </property>
+         <property name="font">
+          <font>
+           <pointsize>20</pointsize>
+          </font>
+         </property>
+         <property name="text">
+          <string>Charging Profile Edit</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QGridLayout" name="gridLayout_2">
+         <item row="0" column="0">
+          <widget class="QLabel" name="label">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Charging Profile ID : </string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout">
+           <item>
+            <spacer name="horizontalSpacer">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="QLabel" name="chargingProfileID">
+             <property name="minimumSize">
+              <size>
+               <width>100</width>
+               <height>0</height>
+              </size>
+             </property>
+             <property name="text">
+              <string/>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignCenter</set>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="label_3">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Connector ID : </string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QLabel" name="label_4">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Stack Level : </string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="0">
+          <widget class="QLabel" name="label_5">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Charging Profile Purpose : </string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="0">
+          <widget class="QLabel" name="label_6">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Charging Profile Kind : </string>
+           </property>
+          </widget>
+         </item>
+         <item row="5" column="0">
+          <widget class="QLabel" name="label_7">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Recurrency Kind : </string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_2">
+           <item>
+            <spacer name="horizontalSpacer_2">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="QLabel" name="connectorID_label">
+             <property name="minimumSize">
+              <size>
+               <width>100</width>
+               <height>0</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>0</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="CustomComboBox" name="connectorID" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>80</width>
+               <height>0</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item row="3" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_4">
+           <item>
+            <spacer name="horizontalSpacer_6">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="CustomComboBox" name="chargingProfilePurpose" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>300</width>
+               <height>0</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item row="4" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_5">
+           <item>
+            <spacer name="horizontalSpacer_7">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="CustomComboBox" name="chargingProfileKind" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>80</width>
+               <height>0</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item row="5" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_6">
+           <item>
+            <spacer name="horizontalSpacer_8">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="CustomComboBox" name="recurrencyKind" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>80</width>
+               <height>0</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item row="2" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_7">
+           <item>
+            <spacer name="horizontalSpacer_9">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="CustomComboBox" name="stackLevel" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>80</width>
+               <height>0</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <item>
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="cancel">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Cancel</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="ok">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>OK</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>CustomComboBox</class>
+   <extends>QWidget</extends>
+   <header location="global">CustomComboBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

+ 50 - 8
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.cpp

@@ -9,6 +9,7 @@
 #include <QPropertyAnimation>
 
 #include "LanguageManager.h"
+#include "GeneralInterface.h"
 
 DialogLimitEdit::DialogLimitEdit(QWidget *parent)
     : QDialog(parent)
@@ -30,8 +31,9 @@ DialogLimitEdit::~DialogLimitEdit()
     delete ui;
 }
 
-Limit DialogLimitEdit::limit_info() const
+Limit DialogLimitEdit::limit_info()
 {
+    updateData();
     return m_limit_info;
 }
 
@@ -40,6 +42,12 @@ void DialogLimitEdit::setLimit_info(const Limit &newLimit_info)
     m_limit_info = newLimit_info;
 }
 
+void DialogLimitEdit::clear()
+{
+    m_limit_info.startPeriod    = 0;
+    m_limit_info.limit          = 0;
+}
+
 void DialogLimitEdit::initWidget()
 {
     QStringList unitList;
@@ -47,6 +55,11 @@ void DialogLimitEdit::initWidget()
     unitList << ChargingProfiles::UnitType::WATT;
     ui->chargingRateUnit->addItems(unitList);
 
+    QStringList durationUnitList;
+    durationUnitList << "HH:mm:ss"
+                     << "S";
+    ui->startPeriodUnit->addItems(durationUnitList);
+
     ui->limit->setEditType(EditType::DOUBLE);
 }
 
@@ -70,6 +83,10 @@ void DialogLimitEdit::initConnect()
     connect(ui->ok, &QPushButton::clicked, this, [this](){
         accept();
     });
+    connect(ui->startPeriodUnit, &CustomComboBox::currentIndexChanged, this, [this]() {
+        setDuration();
+    });
+
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
 }
 
@@ -121,18 +138,43 @@ void DialogLimitEdit::centerWindow()
 
 void DialogLimitEdit::refreshData()
 {
-    ui->startTime->setDateTime(QDateTime::fromString(m_limit_info.startTime, Qt::ISODateWithMs));
-    ui->duration->setText(QString::number(m_limit_info.duration));
+    setDuration();
     ui->chargingRateUnit->setCurrentText(m_limit_info.unit);
-    ui->limit->setText(QString::number(m_limit_info.limit / 10000.0, 'f', 2));
+    ui->limit->setText(QString::number(m_limit_info.limit / 1000.0, 'f', 2));
+}
+
+void DialogLimitEdit::setDuration()
+{
+    switch (ui->startPeriodUnit->currentIndex()) {
+    case StartPeriodUnit::UTC_STR:
+        ui->startPeriod->setText(GeneralInterface::getCurrentDate(m_limit_info.startPeriod));
+        ui->startPeriod->setEditType(EditType::TEXT);
+        break;
+    case StartPeriodUnit::SECONDS:
+        ui->startPeriod->setText(QString::number(m_limit_info.startPeriod));
+        ui->startPeriod->setEditType(EditType::INT);
+        break;
+    default:
+        break;
+    }
 }
 
 void DialogLimitEdit::updateData()
 {
-    m_limit_info.startTime  = ui->startTime->dateTime().toString(Qt::ISODateWithMs);
-    m_limit_info.duration   = ui->duration->text().toInt();
-    m_limit_info.unit       = ui->chargingRateUnit->currentText();
-    m_limit_info.limit      = ui->limit->text().toInt() * 10000;
+    m_limit_info.startPeriod    = getDuration();
+    m_limit_info.unit           = ui->chargingRateUnit->currentText();
+    m_limit_info.limit          = ui->limit->text().toDouble() * 1000;
+}
+
+int DialogLimitEdit::getDuration()
+{
+    switch (ui->startPeriodUnit->currentIndex()) {
+    case StartPeriodUnit::UTC_STR:  return GeneralInterface::getCurrentDate(ui->startPeriod->text());
+    case StartPeriodUnit::SECONDS:  return ui->startPeriod->text().toDouble();
+    default:
+        break;
+    }
+    return 0;
 }
 
 void DialogLimitEdit::showEvent(QShowEvent *event)

+ 103 - 4
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.h

@@ -9,41 +9,140 @@ class DialogLimitEdit;
 }
 
 struct Limit {
-    QString startTime;
-    int duration;
+    int startPeriod;
     QString unit;
     int limit;
 };
 
+namespace DurationUnit {
+constexpr const int HOURS   = 0x0;
+constexpr const int MINUTES = 0x1;
+constexpr const int SECONDS = 0x2;
+}
+namespace StartPeriodUnit {
+constexpr const int UTC_STR = 0x0;
+constexpr const int SECONDS = 0x1;
+}
+
+/**
+ * @class DialogLimitEdit
+ * @brief DialogLimitEdit 类是一个基于 QDialog 的对话框,用于显示和编辑限制信息。
+ * 
+ * 该类提供了显示限制信息的功能,并允许用户进行编辑。它继承自 QDialog,并使用 Qt 的 UI 设计器生成的 UI 类。
+ * 
+ * 核心功能包括:
+ * - 显示限制信息
+ * - 编辑限制信息
+ * - 初始化对话框组件
+ * - 连接信号和槽
+ * - 设置背景和居中窗口
+ * 
+ * @param parent 指向父窗口的指针,默认为 nullptr。
+ * 
+ * 使用示例:
+ * @code
+ * DialogLimitEdit dialog(this);
+ * dialog.setLimit_info(someLimit);
+ * dialog.exec();
+ * @endcode
+ * 
+ * 注意事项:
+ * - 在使用该类之前,请确保已经正确初始化了 UI 设计器生成的对象。
+ * - 该类没有特殊的使用限制或潜在的副作用。
+ */
 class DialogLimitEdit : public QDialog
 {
     Q_OBJECT
 
 public:
+    /**
+     * @brief 构造函数,创建一个 DialogLimitEdit 对象。
+     * 
+     * @param parent 指向父窗口的指针,默认为 nullptr。
+     */
     explicit DialogLimitEdit(QWidget *parent = nullptr);
+    
+    /**
+     * @brief 析构函数,销毁 DialogLimitEdit 对象。
+     */
     ~DialogLimitEdit();
 
-    Limit limit_info() const;
+    /**
+     * @brief 获取当前的限制信息。
+     * 
+     * @return 当前限制信息的 Limit 对象。
+     */
+    Limit limit_info();
+    
+    /**
+     * @brief 设置新的限制信息。
+     * 
+     * @param newLimit_info 新的限制信息。
+     */
     void setLimit_info(const Limit &newLimit_info);
 
+    void clear();
+
 private:
+    /**
+     * @brief 初始化对话框组件。
+     */
     void initWidget();
+    
+    /**
+     * @brief 连接信号和槽。
+     */
     void initConnect();
+    
+    /**
+     * @brief 设置对话框背景。
+     */
     void setBackground();
+    
+    /**
+     * @brief 将对话框居中显示。
+     */
     void centerWindow();
 
+    /**
+     * @brief 刷新数据。
+     */
     void refreshData();
+    void setDuration();
+    
+    /**
+     * @brief 更新数据。
+     */
     void updateData();
+    int getDuration();
 
 protected:
+    /**
+     * @brief 重写 showEvent,在对话框显示时执行特定操作。
+     * 
+     * @param event 显示事件。
+     */
     void showEvent(QShowEvent* event) override;
 
 private:
+    /**
+     * @brief 指向 UI 设计器生成的 UI 类的指针。
+     */
     Ui::DialogLimitEdit *ui;
+    
+    /**
+     * @brief 背景标签。
+     */
     QLabel* m_background;
-    // 原始位置
+    
+    /**
+     * @brief 原始位置。
+     */
     QPoint  m_originalPos;
 
+    /**
+     * @brief 当前限制信息。
+     */
     Limit m_limit_info;
 };
 

+ 48 - 92
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogLimitEdit.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>464</width>
-    <height>474</height>
+    <width>673</width>
+    <height>408</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -55,9 +55,9 @@
         </widget>
        </item>
        <item>
-        <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0,0">
-         <item row="3" column="0">
-          <widget class="QLabel" name="label_7">
+        <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0">
+         <item row="0" column="0">
+          <widget class="QLabel" name="label_4">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -65,12 +65,12 @@
             </size>
            </property>
            <property name="text">
-            <string>Limit : </string>
+            <string>Start Period : </string>
            </property>
           </widget>
          </item>
-         <item row="1" column="0">
-          <widget class="QLabel" name="label_5">
+         <item row="2" column="0">
+          <widget class="QLabel" name="label_7">
            <property name="minimumSize">
             <size>
              <width>0</width>
@@ -78,14 +78,14 @@
             </size>
            </property>
            <property name="text">
-            <string>Duration : </string>
+            <string>Limit : </string>
            </property>
           </widget>
          </item>
          <item row="2" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,0">
+          <layout class="QHBoxLayout" name="horizontalLayout_6">
            <item>
-            <spacer name="horizontalSpacer_7">
+            <spacer name="horizontalSpacer_6">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
@@ -98,18 +98,31 @@
             </spacer>
            </item>
            <item>
-            <widget class="CustomComboBox" name="chargingRateUnit" native="true">
-             <property name="minimumSize">
-              <size>
-               <width>40</width>
-               <height>0</height>
-              </size>
+            <widget class="CustomLineEdit" name="limit">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>0</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLabel" name="unit">
+             <property name="text">
+              <string/>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="2" column="0">
+         <item row="1" column="0">
           <widget class="QLabel" name="label_6">
            <property name="minimumSize">
             <size>
@@ -122,23 +135,10 @@
            </property>
           </widget>
          </item>
-         <item row="0" column="0">
-          <widget class="QLabel" name="label_4">
-           <property name="minimumSize">
-            <size>
-             <width>0</width>
-             <height>60</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>Start Time : </string>
-           </property>
-          </widget>
-         </item>
-         <item row="0" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
+         <item row="1" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,0">
            <item>
-            <spacer name="horizontalSpacer">
+            <spacer name="horizontalSpacer_7">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
@@ -151,27 +151,21 @@
             </spacer>
            </item>
            <item>
-            <widget class="CustomQDateTimeEdit" name="startTime">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="alignment">
-              <set>Qt::AlignCenter</set>
-             </property>
-             <property name="displayFormat">
-              <string>yyyy-MM-dd HH:mm:ss</string>
+            <widget class="CustomComboBox" name="chargingRateUnit" native="true">
+             <property name="minimumSize">
+              <size>
+               <width>40</width>
+               <height>0</height>
+              </size>
              </property>
             </widget>
            </item>
           </layout>
          </item>
-         <item row="3" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <item row="0" column="1">
+          <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0">
            <item>
-            <spacer name="horizontalSpacer_6">
+            <spacer name="horizontalSpacer">
              <property name="orientation">
               <enum>Qt::Horizontal</enum>
              </property>
@@ -184,59 +178,26 @@
             </spacer>
            </item>
            <item>
-            <widget class="CustomLineEdit" name="limit">
+            <widget class="CustomLineEdit" name="startPeriod">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
                <horstretch>0</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
              </property>
-             <property name="text">
-              <string>0</string>
-             </property>
              <property name="alignment">
               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
              </property>
             </widget>
            </item>
            <item>
-            <widget class="QLabel" name="unit">
-             <property name="text">
-              <string/>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </item>
-         <item row="1" column="1">
-          <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
-           <item>
-            <spacer name="horizontalSpacer_2">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
+            <widget class="CustomComboBox" name="startPeriodUnit" native="true">
+             <property name="minimumSize">
               <size>
-               <width>40</width>
-               <height>20</height>
+               <width>180</width>
+               <height>0</height>
               </size>
              </property>
-            </spacer>
-           </item>
-           <item>
-            <widget class="CustomLineEdit" name="duration">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="text">
-              <string>0</string>
-             </property>
-             <property name="alignment">
-              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-             </property>
             </widget>
            </item>
           </layout>
@@ -342,11 +303,6 @@
    <extends>QLineEdit</extends>
    <header location="global">CustomLineEdit.h</header>
   </customwidget>
-  <customwidget>
-   <class>CustomQDateTimeEdit</class>
-   <extends>QDateTimeEdit</extends>
-   <header location="global">CustomQDateTimeEdit.h</header>
-  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>

+ 116 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.cpp

@@ -0,0 +1,116 @@
+#include "DialogSelectChargingProfiles.h"
+#include "ui_DialogSelectChargingProfiles.h"
+
+#include <QScreen>
+#include <QTimer>
+#include <QWindow>
+#include <QDebug>
+#include <QIntValidator>
+#include <QPropertyAnimation>
+
+#include "LanguageManager.h"
+#include "DataTypeDef.h"
+
+DialogSelectChargingProfiles::DialogSelectChargingProfiles(QWidget *parent)
+    : QDialog(parent)
+    , ui(new Ui::DialogSelectChargingProfiles)
+{
+    ui->setupUi(this);
+
+    initWidget();
+    initConnect();
+}
+
+DialogSelectChargingProfiles::~DialogSelectChargingProfiles()
+{
+    delete ui;
+}
+
+QString DialogSelectChargingProfiles::getPurpose()
+{
+    return ui->chargingProfilePurpose->currentText();
+}
+
+void DialogSelectChargingProfiles::initWidget()
+{
+    setWindowModality(Qt::WindowModal);
+    setAttribute(Qt::WA_TranslucentBackground);
+    setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+
+    setBackground();
+
+    initComboBox();
+}
+
+void DialogSelectChargingProfiles::initConnect()
+{
+    connect(ui->cancel, &QPushButton::clicked, this, [this]() {
+        reject();
+    });
+    connect(ui->ok, &QPushButton::clicked, this, [this](){
+        accept();
+    });
+    connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+}
+
+void DialogSelectChargingProfiles::initComboBox()
+{
+    QStringList items;
+    items << ChargingProfiles::Purpose::CHARGE_POINT_MAX_PROFILE
+          << ChargingProfiles::Purpose::TX_DEFAULT_PROFILE
+          << ChargingProfiles::Purpose::TX_PROFILE;
+
+    ui->chargingProfilePurpose->addItems(items);
+}
+
+void DialogSelectChargingProfiles::setBackground()
+{
+    m_background = new QLabel();
+    ui->background_layout->addWidget(m_background, 0, 0, ui->background_layout->rowCount(), ui->background_layout->columnCount());
+    m_background->setPixmap(QPixmap(":/images/price/dialog_edit_background.png"));
+    m_background->lower();
+    m_background->setScaledContents(true);
+}
+
+void DialogSelectChargingProfiles::centerWindow()
+{
+    // 确保窗口尺寸已确定(关键修复)
+    this->ensurePolished();
+    // this->adjustSize();
+
+    // 获取有效的屏幕几何尺寸(考虑多显示器)
+    QScreen *screen = QGuiApplication::primaryScreen();
+    if (QWindow *window = this->windowHandle()) {
+        screen = window->screen();
+    }
+    QRect screenGeometry = screen->availableGeometry();
+
+    // 计算居中位置(考虑Wayland特性)
+    int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
+    int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
+
+    if (QGuiApplication::platformName().contains("wayland")) {
+        // Wayland专用处理
+        if (QWindow *window = this->windowHandle()) {
+            // 重要:延迟设置位置,确保Wayland合成器已准备好
+            QTimer::singleShot(100, this, [window, x, y]() {
+                window->setPosition(QPoint(x, y));
+
+                // 替代requestActivate的方案
+                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
+                QTimer::singleShot(50, [window]() {
+                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
+                });
+            });
+        }
+    } else {
+        // 传统X11处理
+        this->move(x, y);
+    }
+}
+
+void DialogSelectChargingProfiles::showEvent(QShowEvent *event)
+{
+    centerWindow();
+    QDialog::showEvent(event);
+}

+ 36 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.h

@@ -0,0 +1,36 @@
+#ifndef DIALOGSELECTCHARGINGPROFILES_H
+#define DIALOGSELECTCHARGINGPROFILES_H
+
+#include <QDialog>
+#include <QLabel>
+
+namespace Ui {
+class DialogSelectChargingProfiles;
+}
+
+class DialogSelectChargingProfiles : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit DialogSelectChargingProfiles(QWidget *parent = nullptr);
+    ~DialogSelectChargingProfiles();
+
+    QString getPurpose();
+
+private:
+    void initWidget();
+    void initConnect();
+    void initComboBox();
+    void setBackground();
+    void centerWindow();
+
+protected:
+    void showEvent(QShowEvent* event) override;
+
+private:
+    Ui::DialogSelectChargingProfiles *ui;
+    QLabel* m_background;
+};
+
+#endif // DIALOGSELECTCHARGINGPROFILES_H

+ 173 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogSelectChargingProfiles.ui

@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DialogSelectChargingProfiles</class>
+ <widget class="QDialog" name="DialogSelectChargingProfiles">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>566</width>
+    <height>269</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="background_layout">
+     <item row="0" column="0">
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <property name="leftMargin">
+        <number>20</number>
+       </property>
+       <property name="topMargin">
+        <number>20</number>
+       </property>
+       <property name="rightMargin">
+        <number>20</number>
+       </property>
+       <property name="bottomMargin">
+        <number>20</number>
+       </property>
+       <item>
+        <widget class="QLabel" name="titles">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>80</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Charging Profiles Select</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
+         <item>
+          <widget class="QLabel" name="label_2">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>60</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Purpose : </string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="CustomComboBox" name="chargingProfilePurpose" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>20</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <item>
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="cancel">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Cancel</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="ok">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>OK</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>CustomComboBox</class>
+   <extends>QWidget</extends>
+   <header location="global">CustomComboBox.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

+ 305 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.cpp

@@ -0,0 +1,305 @@
+#include "DialogWeekDayDetail.h"
+#include "ui_DialogWeekDayDetail.h"
+
+#include <QDebug>
+#include <QScroller>
+#include <QMessageBox>
+#include <QScreen>
+#include <QTimer>
+#include <QWindow>
+#include <QDebug>
+#include <QIntValidator>
+#include <QPropertyAnimation>
+
+#include "LanguageManager.h"
+#include "GeneralInterface.h"
+
+DialogWeekDayDetail::DialogWeekDayDetail(QWidget *parent)
+    : QDialog(parent)
+    , ui(new Ui::DialogWeekDayDetail)
+{
+    ui->setupUi(this);
+
+    initWidget();
+    initConnect();
+}
+
+DialogWeekDayDetail::~DialogWeekDayDetail()
+{
+    delete ui;
+}
+
+void DialogWeekDayDetail::refreshData()
+{
+    refreshTitles(generalInfo.curDay);
+
+    ui->tablewidget->clearContents();
+    ui->tablewidget->setRowCount(0);
+    foreach (const auto& data, std::as_const(m_info_list)) {
+        QString limitStr;
+        if (generalInfo.chargingRateUnit == ChargingProfiles::UnitType::AMPERE) {
+            limitStr = QString("%1 A").arg(QString::number(data.limit));
+        } else if (generalInfo.chargingRateUnit == ChargingProfiles::UnitType::WATT) {
+            limitStr = QString("%1 KW").arg(QString::number(data.limit / 1000.0, 'f', 2));
+        }
+        QString startPeriod = GeneralInterface::getCurrentDateOfWeek(generalInfo.startTime, data.startPeriod);
+        appendTableWidgetItem(startPeriod,
+                              limitStr,
+                              generalInfo.chargingRateUnit);
+    }
+}
+
+void DialogWeekDayDetail::refreshTitles(const int &dayOfWeek)
+{
+    QString titles;
+    switch (dayOfWeek) {
+    case Qt::Monday:
+        titles = "Monday limit settings";
+        break;
+    case Qt::Tuesday:
+        titles = "Tuesday limit settings";
+        break;
+    case Qt::Wednesday:
+        titles = "Wednesday limit settings";
+        break;
+    case Qt::Thursday:
+        titles = "Thursday limit settings";
+        break;
+    case Qt::Friday:
+        titles = "Friday limit settings";
+        break;
+    case Qt::Saturday:
+        titles = "Saturday limit settings";
+        break;
+    case Qt::Sunday:
+        titles = "Sunday limit settings";
+        break;
+    default:
+        break;
+    }
+
+    ui->titles->setText(titles);
+}
+
+void DialogWeekDayDetail::updateData(const charging_schedule_period_info_t &info, const int &index)
+{
+    for(int i = 0; index < m_info_list.size(); i++) {
+        if (i == index) {
+            m_info_list[i] = info;
+        }
+    }
+}
+
+void DialogWeekDayDetail::appendTableWidgetItem(const QString &startPeriod, const QString &limit, const QString &chargingRateUnit)
+{
+    auto row = ui->tablewidget->rowCount();
+    ui->tablewidget->insertRow(row);
+
+    auto startTimeItem = new QTableWidgetItem(startPeriod);
+    startTimeItem->setTextAlignment(Qt::AlignCenter);
+    ui->tablewidget->setItem(row, 0, startTimeItem);
+
+    auto limitTypeItem = new QTableWidgetItem(chargingRateUnit);
+    limitTypeItem->setTextAlignment(Qt::AlignCenter);
+    ui->tablewidget->setItem(row, 1, limitTypeItem);
+
+    auto limitItem = new QTableWidgetItem(limit);
+    limitItem->setTextAlignment(Qt::AlignCenter);
+    ui->tablewidget->setItem(row, 2, limitItem);
+
+    ui->tablewidget->setRowHeight(row, 60);
+    ui->tablewidget->setCurrentItem(nullptr);
+}
+
+bool DialogWeekDayDetail::isExistByStartPeriod(const int &startPeriod)
+{
+    foreach (const auto& data, std::as_const(m_info_list)) {
+        if (data.startPeriod == startPeriod) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void DialogWeekDayDetail::centerWindow()
+{
+    // 确保窗口尺寸已确定(关键修复)
+    this->ensurePolished();
+    // this->adjustSize();
+
+    // 获取有效的屏幕几何尺寸(考虑多显示器)
+    QScreen *screen = QGuiApplication::primaryScreen();
+    if (QWindow *window = this->windowHandle()) {
+        screen = window->screen();
+    }
+    QRect screenGeometry = screen->availableGeometry();
+
+    // 计算居中位置(考虑Wayland特性)
+    int x = (screenGeometry.width() - this->width()) / 2 + screenGeometry.x();
+    int y = (screenGeometry.height() - this->height()) / 2 + screenGeometry.y();
+
+    if (QGuiApplication::platformName().contains("wayland")) {
+        // Wayland专用处理
+        if (QWindow *window = this->windowHandle()) {
+            // 重要:延迟设置位置,确保Wayland合成器已准备好
+            QTimer::singleShot(100, this, [window, x, y]() {
+                window->setPosition(QPoint(x, y));
+
+                // 替代requestActivate的方案
+                window->setFlags(window->flags() | Qt::WindowStaysOnTopHint);
+                QTimer::singleShot(50, [window]() {
+                    window->setFlags(window->flags() & ~Qt::WindowStaysOnTopHint);
+                });
+            });
+        }
+    } else {
+        // 传统X11处理
+        this->move(x, y);
+    }
+}
+
+void DialogWeekDayDetail::onItemDoubleClicked(QTableWidgetItem *item)
+{
+    auto row = item->row();
+    auto data = m_info_list[row];
+    Limit limit_info;
+    limit_info.startPeriod      = GeneralInterface::getCurrentDateSecondOfWeek(generalInfo.startTime, data.startPeriod);
+    limit_info.unit             = generalInfo.chargingRateUnit;
+    limit_info.limit            = data.limit;
+
+    m_limit_dialog->setLimit_info(limit_info);
+    auto ret = m_limit_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto result = m_limit_dialog->limit_info();
+        data.startPeriod                = GeneralInterface::getCurrentDateOfWeek(generalInfo.startTime, result.startPeriod, generalInfo.curDay);
+        generalInfo.chargingRateUnit    = result.unit;
+        data.limit                      = result.limit;
+
+        updateData(data, row);
+        refreshData();
+        emit valueChanged();
+    }
+}
+
+void DialogWeekDayDetail::addBtnClicked()
+{
+    m_limit_dialog->clear();
+    auto ret = m_limit_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto result = m_limit_dialog->limit_info();
+        if (!isExistByStartPeriod(result.startPeriod)) {
+            charging_schedule_period_info_t data;
+            data.startPeriod                = GeneralInterface::getCurrentDateOfWeek(generalInfo.startTime, result.startPeriod, generalInfo.curDay);
+            generalInfo.chargingRateUnit    = result.unit;
+            data.limit                      = result.limit;
+
+            m_info_list.append(data);
+            refreshData();
+            emit valueChanged();
+        } else {
+            QMessageBox::warning(this, "Tips",
+                                 "The time period already exists. Please add it again...");
+        }
+    }
+}
+
+void DialogWeekDayDetail::deleteBtnClicked()
+{
+    auto row = ui->tablewidget->currentRow();
+    if (row > m_info_list.size()) return;
+    m_info_list.removeAt(row);
+
+    refreshData();
+    emit valueChanged();
+}
+
+void DialogWeekDayDetail::showEvent(QShowEvent *event)
+{
+    refreshData();
+    centerWindow();
+    QDialog::showEvent(event);
+}
+
+QList<charging_schedule_period_info_t> DialogWeekDayDetail::info_list() const
+{
+    return m_info_list;
+}
+
+void DialogWeekDayDetail::setInfo_list(const QList<charging_schedule_period_info_t> &newInfo_list)
+{
+    m_info_list = newInfo_list;
+}
+
+GeneralInfo DialogWeekDayDetail::getGeneralInfo() const
+{
+    return generalInfo;
+}
+
+void DialogWeekDayDetail::setGeneralInfo(const GeneralInfo &newGeneralInfo)
+{
+    generalInfo = newGeneralInfo;
+}
+
+void DialogWeekDayDetail::initWidget()
+{
+    setWindowModality(Qt::WindowModal);
+    setAttribute(Qt::WA_TranslucentBackground);
+    setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+
+    initTableWidget();
+    setBackground();
+
+    m_limit_dialog.reset(new DialogLimitEdit);
+    m_limit_dialog->setParent(this);
+    m_limit_dialog->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+    m_limit_dialog->setWindowModality(Qt::WindowModal);
+}
+
+void DialogWeekDayDetail::setBackground()
+{
+    m_background = new QLabel();
+    ui->background_layout->addWidget(m_background, 0, 0, ui->background_layout->rowCount(), ui->background_layout->columnCount());
+    m_background->setPixmap(QPixmap(":/images/price/dialog_edit_background.png"));
+    m_background->lower();
+    m_background->setScaledContents(true);
+}
+
+void DialogWeekDayDetail::initTableWidget()
+{
+    // ui->dailyTablewidget->horizontalHeader()->hide();
+    ui->tablewidget->verticalHeader()->hide();
+
+    ui->tablewidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
+    ui->tablewidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    ui->tablewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+    ui->tablewidget->setSelectionMode(QAbstractItemView::SingleSelection);
+
+    QScroller::grabGesture(ui->tablewidget,              QScroller::TouchGesture);
+    QScroller::grabGesture(ui->tablewidget->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+void DialogWeekDayDetail::initConnect()
+{
+    connect(ui->cancel, &QPushButton::clicked, this, [this]() {
+        reject();
+    });
+    connect(ui->ok, &QPushButton::clicked, this, [this](){
+        accept();
+    });
+    connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this](){
+        ui->retranslateUi(this);
+    });
+
+    connect(ui->tablewidget, &QTableWidget::itemDoubleClicked, this, &DialogWeekDayDetail::onItemDoubleClicked);
+    connect(ui->tablewidget, &QTableWidget::itemSelectionChanged, this, [this]() {
+        if (ui->tablewidget->currentItem()->row() >= 0) {
+            ui->delete_limit->setVisible(true);
+        } else {
+            ui->delete_limit->setVisible(false);
+        }
+    });
+    connect(ui->add_limit,      &QPushButton::clicked, this, &DialogWeekDayDetail::addBtnClicked);
+    connect(ui->delete_limit,   &QPushButton::clicked, this, &DialogWeekDayDetail::deleteBtnClicked);
+}

+ 71 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.h

@@ -0,0 +1,71 @@
+#ifndef DIALOGWEEKDAYDETAIL_H
+#define DIALOGWEEKDAYDETAIL_H
+
+#include <QLabel>
+#include <QDialog>
+#include <QTableWidgetItem>
+
+#include "DataTypeDef.h"
+#include "DialogLimitEdit.h"
+
+namespace Ui {
+class DialogWeekDayDetail;
+}
+
+struct GeneralInfo {
+    int curDay;
+    QString startTime;
+    QString chargingRateUnit;
+};
+
+class DialogWeekDayDetail : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit DialogWeekDayDetail(QWidget *parent = nullptr);
+    ~DialogWeekDayDetail();
+
+    GeneralInfo getGeneralInfo() const;
+    void setGeneralInfo(const GeneralInfo &newGeneralInfo);
+
+    void setInfo_list(const QList<charging_schedule_period_info_t> &newInfo_list);
+
+    QList<charging_schedule_period_info_t> info_list() const;
+
+private:
+    void initWidget();
+    void setBackground();
+    void initTableWidget();
+    void initConnect();
+
+    void refreshData();
+    void refreshTitles(const int& dayOfWeek);
+    void updateData(const charging_schedule_period_info_t& info, const int& index);
+
+    void appendTableWidgetItem(const QString& startPeriod, const QString& limit, const QString& chargingRateUnit);
+
+    bool isExistByStartPeriod(const int& startPeriod);
+
+    void centerWindow();
+
+signals:
+    void valueChanged();
+
+private slots:
+    void onItemDoubleClicked(QTableWidgetItem* item);
+    void addBtnClicked();
+    void deleteBtnClicked();
+
+protected:
+    void showEvent(QShowEvent* event) override;
+
+private:
+    Ui::DialogWeekDayDetail *ui;
+    QLabel* m_background;
+    GeneralInfo generalInfo;
+    QList<charging_schedule_period_info_t> m_info_list;
+    QSharedPointer<DialogLimitEdit> m_limit_dialog;
+};
+
+#endif // DIALOGWEEKDAYDETAIL_H

+ 200 - 0
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/DialogWeekDayDetail.ui

@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DialogWeekDayDetail</class>
+ <widget class="QDialog" name="DialogWeekDayDetail">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>986</width>
+    <height>603</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="background_layout">
+     <item row="0" column="0">
+      <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0">
+       <property name="leftMargin">
+        <number>20</number>
+       </property>
+       <property name="topMargin">
+        <number>20</number>
+       </property>
+       <property name="rightMargin">
+        <number>20</number>
+       </property>
+       <property name="bottomMargin">
+        <number>20</number>
+       </property>
+       <item>
+        <widget class="QLabel" name="titles">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>100</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Monday</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_8">
+         <item>
+          <widget class="QPushButton" name="add_limit">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>ADD</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="delete_limit">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>DEL</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="spacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QTableWidget" name="tablewidget">
+         <column>
+          <property name="text">
+           <string>Start Period</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>Limit Type</string>
+          </property>
+         </column>
+         <column>
+          <property name="text">
+           <string>Limit</string>
+          </property>
+         </column>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <item>
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="cancel">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>Cancel</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QPushButton" name="ok">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>40</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>OK</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 7 - 2
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.cpp

@@ -1,8 +1,8 @@
 #include "FormChargingPointMaxProfile.h"
 #include "ui_FormChargingPointMaxProfile.h"
 
-FormChargingPointMaxProfile::FormChargingPointMaxProfile(QWidget *parent)
-    : QWidget(parent)
+FormChargingPointMaxProfile::FormChargingPointMaxProfile(BaseWidget *parent)
+    : BaseWidget(parent)
     , ui(new Ui::FormChargingPointMaxProfile)
 {
     ui->setupUi(this);
@@ -12,3 +12,8 @@ FormChargingPointMaxProfile::~FormChargingPointMaxProfile()
 {
     delete ui;
 }
+
+bool FormChargingPointMaxProfile::returnParent()
+{
+    return true;
+}

+ 5 - 2
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingPointMaxProfile.h

@@ -2,19 +2,22 @@
 #define FORMCHARGINGPOINTMAXPROFILE_H
 
 #include <QWidget>
+#include "BaseWidget.h"
 
 namespace Ui {
 class FormChargingPointMaxProfile;
 }
 
-class FormChargingPointMaxProfile : public QWidget
+class FormChargingPointMaxProfile : public BaseWidget
 {
     Q_OBJECT
 
 public:
-    explicit FormChargingPointMaxProfile(QWidget *parent = nullptr);
+    explicit FormChargingPointMaxProfile(BaseWidget *parent = nullptr);
     ~FormChargingPointMaxProfile();
 
+    bool returnParent() override;
+
 private:
     Ui::FormChargingPointMaxProfile *ui;
 };

+ 67 - 23
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.cpp

@@ -3,9 +3,9 @@
 
 #include <QScroller>
 
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
-#include "GeneralInterface.h"
 
 FormChargingProfilesSettings::FormChargingProfilesSettings(BaseWidget *parent)
     : BaseWidget(parent)
@@ -30,6 +30,14 @@ bool FormChargingProfilesSettings::returnParent()
 void FormChargingProfilesSettings::initWidget()
 {
     initTableWidget();
+
+    m_charging_profile_info.reset(new DialogChargingProfileEdit());
+    m_charging_profile_info->setParent(this);
+    m_charging_profile_info->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+    m_charging_profile_info->setWindowModality(Qt::WindowModal);
+
+    ui->del->setVisible(false);
+    ui->add->setVisible(false);
 }
 
 void FormChargingProfilesSettings::initTableWidget()
@@ -37,7 +45,11 @@ void FormChargingProfilesSettings::initTableWidget()
     // ui->chargingProfileTableWidget->horizontalHeader()->hide();
     ui->chargingProfileTableWidget->verticalHeader()->hide();
 
-    ui->chargingProfileTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+    ui->chargingProfileTableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+    ui->chargingProfileTableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
+    ui->chargingProfileTableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
+    ui->chargingProfileTableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
+    ui->chargingProfileTableWidget->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
 
     ui->chargingProfileTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
     ui->chargingProfileTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
@@ -51,12 +63,45 @@ void FormChargingProfilesSettings::initConnect()
 {
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
     connect(ui->chargingProfileTableWidget, &QTableWidget::itemDoubleClicked, this, [this](QTableWidgetItem* item){
-        auto purpose = ui->chargingProfileTableWidget->item(item->row(), 0)->text();
-        auto index = GeneralInterface::getChargingProfilePurposeIndex(purpose);
-        if (index != 0) {
-            emit currentFormChanged(index);
+        emit currentFormChanged(m_charging_profiles.chargingProfiles[item->row()]);
+    });
+    connect(GLOBALS, &Globals::chargingProfilesValueChanged, this, [this](const CHARGING_PROFILES& info) {
+        m_charging_profiles = info;
+        refreshData();
+    });
+    connect(ui->chargingProfileTableWidget, &QTableWidget::itemChanged, this, [this]() {
+        if (ui->chargingProfileTableWidget->rowCount() > 0 && ui->chargingProfileTableWidget->rowCount() < ui->count->value()) {
+            ui->del->setVisible(true);
+            ui->add->setVisible(true);
+        }
+        if (ui->chargingProfileTableWidget->rowCount() >= ui->count->value()) {
+            ui->add->setVisible(false);
+            ui->del->setVisible(true);
+        }
+        if (ui->chargingProfileTableWidget->rowCount() == 0) {
+            ui->add->setVisible(true);
+            ui->del->setVisible(false);
+        }
+    });
+
+    connect(ui->add, &QPushButton::clicked, this, [this]() {
+        auto ret = m_charging_profile_info->exec();
+        if (ret == QDialog::Accepted) {
+            charging_profiles_detail_info_t info = m_charging_profile_info->getChargingProfile();
+            m_charging_profiles.chargingProfiles.append(info);
+
+            refreshData();
+            emit currentFormChanged(info);
+            ConfigManager::instance()->saveConfig(CHARGING_PROFILE, QVariant::fromValue(m_charging_profiles));
         }
     });
+    connect(ui->del, &QPushButton::clicked, this, [this]() {
+        auto row = ui->chargingProfileTableWidget->currentRow();
+        m_charging_profiles.chargingProfiles.removeAt(row);
+
+        refreshData();
+        ConfigManager::instance()->saveConfig(CHARGING_PROFILE, QVariant::fromValue(m_charging_profiles));
+    });
 }
 
 void FormChargingProfilesSettings::refreshData()
@@ -70,38 +115,37 @@ void FormChargingProfilesSettings::refreshTableWidget()
 {
     ui->chargingProfileTableWidget->clearContents();
     ui->chargingProfileTableWidget->setRowCount(0);
-
-    charging_profiles_detail_info_t data;
-    if (GeneralInterface::getChargingProfileByPurpose(data, m_charging_profiles.chargingProfiles, ChargingProfiles::Purpose::CHARGE_POINT_MAX_PROFILE)) {
-        emit refreshChargingProfileNavigationBar(data.chargingProfilePurpose);
-        tableWidgetAppendRow(data.chargingProfilePurpose, data.chargingProfileKind, data.recurrencyKind);
-    }
-    if (GeneralInterface::getChargingProfileByPurpose(data, m_charging_profiles.chargingProfiles, ChargingProfiles::Purpose::TX_DEFAULT_PROFILE)) {
-        emit refreshChargingProfileNavigationBar(data.chargingProfilePurpose);
-        tableWidgetAppendRow(data.chargingProfilePurpose, data.chargingProfileKind, data.recurrencyKind);
-    }
-    if (GeneralInterface::getChargingProfileByPurpose(data, m_charging_profiles.chargingProfiles, ChargingProfiles::Purpose::TX_PROFILE)) {
-        emit refreshChargingProfileNavigationBar(data.chargingProfilePurpose);
-        tableWidgetAppendRow(data.chargingProfilePurpose, data.chargingProfileKind, data.recurrencyKind);
+    foreach (const auto& data, m_charging_profiles.chargingProfiles) {
+        tableWidgetAppendRow(data.connectorId, data.chargingProfilePurpose, data.chargingProfileKind, data.recurrencyKind, data.stackLevel);
     }
+
+    ui->chargingProfileTableWidget->setCurrentItem(nullptr);
 }
 
-void FormChargingProfilesSettings::tableWidgetAppendRow(const QString &chargingProfilePurpose, const QString &chargingProfileKind, const QString &recurrencyKind)
+void FormChargingProfilesSettings::tableWidgetAppendRow(const int &connectorId, const QString &chargingProfilePurpose, const QString &chargingProfileKind, const QString &recurrencyKind, const int &stackLevel)
 {
     auto row = ui->chargingProfileTableWidget->rowCount();
     ui->chargingProfileTableWidget->insertRow(row);
 
+    auto connectorIdItem = new QTableWidgetItem(QString::number(connectorId));
+    connectorIdItem->setTextAlignment(Qt::AlignCenter);
+    ui->chargingProfileTableWidget->setItem(row, 0, connectorIdItem);
+
     auto purposeItem = new QTableWidgetItem(chargingProfilePurpose);
     purposeItem->setTextAlignment(Qt::AlignCenter);
-    ui->chargingProfileTableWidget->setItem(row, 0, purposeItem);
+    ui->chargingProfileTableWidget->setItem(row, 1, purposeItem);
 
     auto kindItem = new QTableWidgetItem(chargingProfileKind);
     kindItem->setTextAlignment(Qt::AlignCenter);
-    ui->chargingProfileTableWidget->setItem(row, 1, kindItem);
+    ui->chargingProfileTableWidget->setItem(row, 2, kindItem);
 
     auto recurrencyKindItem = new QTableWidgetItem(recurrencyKind);
     recurrencyKindItem->setTextAlignment(Qt::AlignCenter);
-    ui->chargingProfileTableWidget->setItem(row, 2, recurrencyKindItem);
+    ui->chargingProfileTableWidget->setItem(row, 3, recurrencyKindItem);
+
+    auto stackLevelItem = new QTableWidgetItem(QString::number(stackLevel));
+    stackLevelItem->setTextAlignment(Qt::AlignCenter);
+    ui->chargingProfileTableWidget->setItem(row, 4, stackLevelItem);
 
     ui->chargingProfileTableWidget->setRowHeight(row, 60);
 }

+ 9 - 3
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.h

@@ -2,8 +2,11 @@
 #define FORMCHARGINGPROFILESSETTINGS_H
 
 #include <QWidget>
+#include <QSharedPointer>
+
 #include "BaseWidget.h"
 #include "DataTypeDef.h"
+#include "OcppSettings/ChargingProfiles/DialogChargingProfileEdit.h"
 
 namespace Ui {
 class FormChargingProfilesSettings;
@@ -26,21 +29,24 @@ private:
 
     void refreshData();
     void refreshTableWidget();
-    void tableWidgetAppendRow(const QString& chargingProfilePurpose,
+    void tableWidgetAppendRow(const int& connectorId,
+                              const QString& chargingProfilePurpose,
                               const QString& chargingProfileKind,
-                              const QString& recurrencyKind);
+                              const QString& recurrencyKind,
+                              const int& stackLevel);
     void updateData();
 
 protected:
     void showEvent(QShowEvent* event) override;
 
 signals:
-    void currentFormChanged(const int& index);
+    void currentFormChanged(const charging_profiles_detail_info_t& info);
     void refreshChargingProfileNavigationBar(const QString& purpose);
 
 private:
     Ui::FormChargingProfilesSettings *ui;
     CHARGING_PROFILES m_charging_profiles;
+    QSharedPointer<DialogChargingProfileEdit> m_charging_profile_info;
 };
 
 #endif // FORMCHARGINGPROFILESSETTINGS_H

+ 15 - 18
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormChargingProfilesSettings.ui

@@ -112,17 +112,27 @@
       <widget class="QTableWidget" name="chargingProfileTableWidget">
        <column>
         <property name="text">
-         <string>Charging Profile Purpose</string>
+         <string>connectorID</string>
         </property>
        </column>
        <column>
         <property name="text">
-         <string>Charging Profile Kind</string>
+         <string>chargingProfilePurpose</string>
         </property>
        </column>
        <column>
         <property name="text">
-         <string>Recurrency Kind</string>
+         <string>chargingProfileKind</string>
+        </property>
+       </column>
+       <column>
+        <property name="text">
+         <string>recurrencyKind</string>
+        </property>
+       </column>
+       <column>
+        <property name="text">
+         <string>stackLevel</string>
         </property>
        </column>
       </widget>
@@ -145,7 +155,7 @@
       </spacer>
      </item>
      <item>
-      <widget class="QPushButton" name="pushButton">
+      <widget class="QPushButton" name="del">
        <property name="minimumSize">
         <size>
          <width>80</width>
@@ -158,7 +168,7 @@
       </widget>
      </item>
      <item>
-      <widget class="QPushButton" name="pushButton_2">
+      <widget class="QPushButton" name="add">
        <property name="minimumSize">
         <size>
          <width>80</width>
@@ -170,19 +180,6 @@
        </property>
       </widget>
      </item>
-     <item>
-      <widget class="QPushButton" name="pushButton_3">
-       <property name="minimumSize">
-        <size>
-         <width>80</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>edit</string>
-       </property>
-      </widget>
-     </item>
     </layout>
    </item>
   </layout>

+ 292 - 114
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.cpp

@@ -24,8 +24,7 @@ FormTxDefaultProfileDetail::~FormTxDefaultProfileDetail()
 
 bool FormTxDefaultProfileDetail::returnParent()
 {
-    updateData();
-    return ConfigManager::instance()->saveConfig(CHARGING_PROFILE, QVariant::fromValue(m_profile_infos));
+    return updateData();
 }
 
 void FormTxDefaultProfileDetail::initWidget()
@@ -38,6 +37,11 @@ void FormTxDefaultProfileDetail::initWidget()
     m_limit_dialog->setParent(this);
     m_limit_dialog->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
     m_limit_dialog->setWindowModality(Qt::WindowModal);
+
+    m_weekday_dialog.reset(new DialogWeekDayDetail());
+    m_weekday_dialog->setParent(this);
+    m_weekday_dialog->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+    m_weekday_dialog->setWindowModality(Qt::WindowModal);
 }
 
 void FormTxDefaultProfileDetail::initConnect()
@@ -71,6 +75,7 @@ void FormTxDefaultProfileDetail::initConnect()
             break;
         case ChargingProfiles::RecurrencyKind::WEEKLY_ID:
             ui->stackedWidget->setCurrentWidget(ui->weekly);
+            refreshWeeklyData();
             break;
         default:
             break;
@@ -90,19 +95,13 @@ void FormTxDefaultProfileDetail::initConnect()
         }
     });
 
-    connect(ui->add_limit, &QPushButton::clicked, this, [this](){
-
-    });
-
-    connect(ui->delete_limit, &QPushButton::clicked, this, [this]() {
-
-    });
-
-    connect(ui->save_limit, &QPushButton::clicked, this, [this]() {
-
-    });
+    connect(ui->add_limit,      &QPushButton::clicked, this, &FormTxDefaultProfileDetail::addBtnClicked);
+    connect(ui->delete_limit,   &QPushButton::clicked, this, &FormTxDefaultProfileDetail::deleteBtnClicked);
 
     connect(ui->dailyTablewidget, &QTableWidget::itemDoubleClicked, this, &FormTxDefaultProfileDetail::dialyTableWidgetClicked);
+    connect(ui->weeklyListwidget, &QListWidget::itemDoubleClicked,  this, &FormTxDefaultProfileDetail::weekdayTableWidgetDoubleClicked);
+
+    connect(m_weekday_dialog.data(), &DialogWeekDayDetail::valueChanged, this, [this]() { setIsModify(true); });
 }
 
 void FormTxDefaultProfileDetail::initComboBox()
@@ -152,75 +151,41 @@ void FormTxDefaultProfileDetail::refreshData()
 
 void FormTxDefaultProfileDetail::refreshGeneralData()
 {
-    QMap<int, QVariant> stackLevelData = m_profile_infos_map.value(m_gun_id).value<QMap<int, QVariant>>();
-    auto maxStackLevel = GeneralInterface::getMaxElecment(stackLevelData.keys());
-    if (maxStackLevel < 0) return;
-    QMap<QString, QVariant> purposeData = stackLevelData.value(maxStackLevel).value<QMap<QString, QVariant>>();
-    foreach (const auto& purpose, purposeData.keys()) {
-        if (purpose == ui->chargingProfilePurpose->text()) {
-            QMap<QString, QVariant> kindData = purposeData.value(purpose).value<QMap<QString, QVariant>>();
-            if (kindData.count() == 1) {
-                ui->chargingProfileKind->setCurrentText(kindData.firstKey());
-                QMap<QString, QVariant> recurrencyData = kindData.value(kindData.firstKey()).value<QMap<QString, QVariant>>();
-                if (recurrencyData.count() == 1) {
-                    ui->recurrencyKind->setCurrentText(recurrencyData.firstKey());
-                }
-            }
-        }
-    }
+    if (m_profile_info.connectorId != m_gun_id) return;
+    if (m_profile_info.chargingProfilePurpose != ui->chargingProfilePurpose->text()) return;
+    ui->chargingProfileKind->setCurrentText(m_profile_info.chargingProfileKind);
+    ui->recurrencyKind->setCurrentText(m_profile_info.recurrencyKind);
 }
 
 void FormTxDefaultProfileDetail::refreshDailyData()
 {
-    QMap<int, QVariant> stackLevelData = m_profile_infos_map.value(m_gun_id).value<QMap<int, QVariant>>();
-    auto maxStackLevel = GeneralInterface::getMaxElecment(stackLevelData.keys());
-    if (maxStackLevel < 0) return;
-    auto dailyList = getProfileInfoMap(m_profile_infos_map,
-                                       m_gun_id,
-                                       maxStackLevel,
-                                       ui->chargingProfilePurpose->text(),
-                                       ChargingProfiles::Kind::RECURRING,
-                                       ChargingProfiles::RecurrencyKind::DAILY);
+    ui->startTime->setDateTime(QDateTime::fromString(m_profile_info.chargingSchedule.startTime, Qt::ISODate));
+
     ui->dailyTablewidget->clearContents();
     ui->dailyTablewidget->setRowCount(0);
-    for (const auto& daily : std::as_const(dailyList)) {
+    foreach (const auto& duration_info, m_profile_info.chargingSchedule.chargingSchedulePeriod) {
         QString limitStr = "";
-        if (daily.chargingSchedule.chargingRateUnit == ChargingProfiles::UnitType::AMPERE) {
-            limitStr = QString("%1 A").arg(QString::number(daily.chargingSchedule.chargingSchedulePeriod[0].limit / 10000.0, 'f', 2));
-        } else if (daily.chargingSchedule.chargingRateUnit == ChargingProfiles::UnitType::WATT) {
-            limitStr = QString("%1 KW").arg(QString::number(daily.chargingSchedule.chargingSchedulePeriod[0].limit / 10000.0, 'f', 2));
+        if (m_profile_info.chargingSchedule.chargingRateUnit == ChargingProfiles::UnitType::AMPERE) {
+            limitStr = QString("%1 A").arg(QString::number(duration_info.limit / 1000.0, 'f', 2));
+        } else if (m_profile_info.chargingSchedule.chargingRateUnit == ChargingProfiles::UnitType::WATT) {
+            limitStr = QString("%1 KW").arg(QString::number(duration_info.limit / 1000.0, 'f', 2));
         }
-        appendRowTableWidget(QDateTime::fromString(daily.chargingSchedule.startTime, Qt::ISODateWithMs).toString("HH:mm:ss"),
-                             QString::number(daily.chargingSchedule.duration),
-                             daily.chargingSchedule.chargingRateUnit,
+        QString startPeriod = GeneralInterface::getCurrentDate(duration_info.startPeriod);
+        appendRowTableWidget(startPeriod,
+                             m_profile_info.chargingSchedule.chargingRateUnit,
                              limitStr);
     }
 }
 
 void FormTxDefaultProfileDetail::refreshWeeklyData()
 {
-
+    ui->startTime->setDateTime(QDateTime::fromString(m_profile_info.chargingSchedule.startTime, Qt::ISODate));
 }
 
 void FormTxDefaultProfileDetail::refreshDefaultData()
-{
-    QMap<int, QVariant> stackLevelData = m_profile_infos_map.value(m_gun_id).value<QMap<int, QVariant>>();
-    auto maxStackLevel = GeneralInterface::getMaxElecment(stackLevelData.keys());
-    if (maxStackLevel < 0) return;
-    auto dailyList = getProfileInfoMap(m_profile_infos_map,
-                                       m_gun_id,
-                                       maxStackLevel,
-                                       ui->chargingProfilePurpose->text(),
-                                       ChargingProfiles::Kind::RECURRING,
-                                       ChargingProfiles::RecurrencyKind::DAILY);
-
-    ui->startTime->setDateTime(QDateTime::fromString(dailyList[0].chargingSchedule.startTime, Qt::ISODateWithMs));
-    ui->duration->setText(QString::number(dailyList[0].chargingSchedule.duration));
-    ui->chargingRateUnit->setCurrentText(dailyList[0].chargingSchedule.chargingRateUnit);
-    ui->limit->setText(QString::number(dailyList[0].chargingSchedule.chargingSchedulePeriod[0].limit / 10000.0, 'f', 2));
-}
+{}
 
-void FormTxDefaultProfileDetail::appendRowTableWidget(const QString &startTime, const QString &duration, const QString &limitType, const QString &limit)
+void FormTxDefaultProfileDetail::appendRowTableWidget(const QString &startTime, const QString &limitType, const QString &limit)
 {
     auto row = ui->dailyTablewidget->rowCount();
     ui->dailyTablewidget->insertRow(row);
@@ -229,104 +194,317 @@ void FormTxDefaultProfileDetail::appendRowTableWidget(const QString &startTime,
     startTimeItem->setTextAlignment(Qt::AlignCenter);
     ui->dailyTablewidget->setItem(row, 0, startTimeItem);
 
-    auto durationItem = new QTableWidgetItem(duration);
-    durationItem->setTextAlignment(Qt::AlignCenter);
-    ui->dailyTablewidget->setItem(row, 1, durationItem);
-
     auto limitTypeItem = new QTableWidgetItem(limitType);
     limitTypeItem->setTextAlignment(Qt::AlignCenter);
-    ui->dailyTablewidget->setItem(row, 2, limitTypeItem);
+    ui->dailyTablewidget->setItem(row, 1, limitTypeItem);
 
     auto limitItem = new QTableWidgetItem(limit);
     limitItem->setTextAlignment(Qt::AlignCenter);
-    ui->dailyTablewidget->setItem(row, 3, limitItem);
+    ui->dailyTablewidget->setItem(row, 2, limitItem);
 
     ui->dailyTablewidget->setRowHeight(row, 60);
 }
 
-void FormTxDefaultProfileDetail::updateData()
+bool FormTxDefaultProfileDetail::updateData()
 {
-    m_profile_infos.chargingProfiles = GeneralInterface::chargingProfileMapToList(m_profile_infos_map);
+    CHARGING_PROFILES profile_infos = ConfigManager::instance()->charging_profiles();
+    for(int index = 0; index < profile_infos.chargingProfiles.size(); index ++) {
+        if (profile_infos.chargingProfiles[index].chargingProfilePurpose == m_profile_info.chargingProfilePurpose &&
+            profile_infos.chargingProfiles[index].chargingProfileId == m_profile_info.chargingProfileId) {
+            profile_infos.chargingProfiles[index] = m_profile_info;
+        }
+    }
+
+    return ConfigManager::instance()->saveConfig(CHARGING_PROFILE, QVariant::fromValue(profile_infos));
 }
 
-QMap<int, QVariant> FormTxDefaultProfileDetail::getProfileInfoMap(const QMap<int, QVariant> &map, const int &connectorId)
+QList<charging_profiles_detail_info_t> FormTxDefaultProfileDetail::getProfileInfo(const QList<charging_profiles_detail_info_t> &dataList,
+                                                                                  const int &connectorId,
+                                                                                  const QString &purpose,
+                                                                                  const QString &kind,
+                                                                                  const QString &recurrencyKind)
 {
-    return map.value(connectorId).value<QMap<int, QVariant>>();
+    QList<charging_profiles_detail_info_t> result;
+    if (dataList.isEmpty()) return result;
+
+    auto ret = isExistByRecurrencyKind(dataList, connectorId, purpose, kind, recurrencyKind);
+    if (!ret) return result;
+
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId &&
+            data.chargingProfilePurpose == purpose &&
+            data.chargingProfileKind == kind &&
+            data.recurrencyKind == recurrencyKind) {
+            result.append(data);
+        }
+    }
+
+    return result;
 }
 
-QMap<QString, QVariant> FormTxDefaultProfileDetail::getProfileInfoMap(const QMap<int, QVariant> &map, const int &connectorId, const int &stackLevel)
+charging_profiles_detail_info_t FormTxDefaultProfileDetail::getMaxStackLevel(const QList<charging_profiles_detail_info_t> &dataList)
 {
-    QMap<int, QVariant> connectorIdMap          = map.value(connectorId).value<QMap<int, QVariant>>();
-    QMap<QString, QVariant> stackLevelMap       = connectorIdMap.value(stackLevel).value<QMap<QString, QVariant>>();
-    return stackLevelMap;
+    int maxStackLevel = -1;
+    foreach (const auto& data, dataList) {
+        if (maxStackLevel < data.stackLevel){
+            maxStackLevel = data.stackLevel;
+        }
+    }
+
+    foreach (const auto& data, dataList) {
+        if (maxStackLevel == data.stackLevel){
+            return data;
+        }
+    }
+
+    return charging_profiles_detail_info_t();
 }
 
-QMap<QString, QVariant> FormTxDefaultProfileDetail::getProfileInfoMap(const QMap<int, QVariant> &map, const int &connectorId, const int &stackLevel, const QString &purpose)
+charging_profiles_detail_info_t FormTxDefaultProfileDetail::getProfileInfo(const QList<charging_profiles_detail_info_t> &dataList,
+                                                                           const int &connectorId,
+                                                                           const QString &purpose,
+                                                                           const QString &recurrencyKind,
+                                                                           const QString &kind,
+                                                                           const int &stackLevel)
 {
-    QMap<int, QVariant> connectorIdMap          = map.value(connectorId).value<QMap<int, QVariant>>();
-    QMap<QString, QVariant> stackLevelMap       = connectorIdMap.value(stackLevel).value<QMap<QString, QVariant>>();
-    QMap<QString, QVariant> purposeMap          = stackLevelMap.value(purpose).value<QMap<QString, QVariant>>();
-    return purposeMap;
+    charging_profiles_detail_info_t result;
+    if (dataList.isEmpty()) return result;
+
+    if (!isExistByStackLevel(dataList, connectorId, purpose, recurrencyKind, kind, stackLevel)) return result;
+
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId &&
+            data.stackLevel == stackLevel &&
+            data.chargingProfilePurpose == purpose &&
+            data.chargingProfileKind == kind &&
+            data.recurrencyKind == recurrencyKind) {
+            return result;
+        }
+    }
+
+    return result;
 }
 
-QMap<QString, QVariant> FormTxDefaultProfileDetail::getProfileInfoMap(const QMap<int, QVariant> &map, const int &connectorId, const int &stackLevel, const QString &purpose, const QString &kind)
+void FormTxDefaultProfileDetail::updateData(QList<charging_profiles_detail_info_t> &dataList, const charging_profiles_detail_info_t &data, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind, const int &stackLevel)
 {
-    QMap<int, QVariant> connectorIdMap          = map.value(connectorId).value<QMap<int, QVariant>>();
-    QMap<QString, QVariant> stackLevelMap       = connectorIdMap.value(stackLevel).value<QMap<QString, QVariant>>();
-    QMap<QString, QVariant> purposeMap          = stackLevelMap.value(purpose).value<QMap<QString, QVariant>>();
-    QMap<QString, QVariant> kindMap             = purposeMap.value(kind).value<QMap<QString, QVariant>>();
-    return kindMap;
+    for (int i = dataList.size() - 1; i >= 0; --i) {
+        const charging_profiles_detail_info_t &oldData = dataList.at(i);
+        if (oldData.connectorId == connectorId &&
+            oldData.stackLevel == stackLevel &&
+            oldData.chargingProfilePurpose == purpose &&
+            oldData.chargingProfileKind == kind &&
+            oldData.recurrencyKind == recurrencyKind) {
+            dataList.removeAt(i);
+        }
+    }
+    dataList.append(data);
 }
 
-QList<charging_profiles_detail_info_t> FormTxDefaultProfileDetail::getProfileInfoMap(const QMap<int, QVariant> &map, const int &connectorId, const int &stackLevel, const QString &purpose, const QString &kind, const QString &recurrencyKind)
+bool FormTxDefaultProfileDetail::isExistByConnectorId(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId)
 {
-    QList<charging_profiles_detail_info_t> result;
-    QMap<int, QVariant> connectorIdMap          = map.value(connectorId).value<QMap<int, QVariant>>();
-    QMap<QString, QVariant> stackLevelMap       = connectorIdMap.value(stackLevel).value<QMap<QString, QVariant>>();
-    QMap<QString, QVariant> purposeMap          = stackLevelMap.value(purpose).value<QMap<QString, QVariant>>();
-    QMap<QString, QVariant> kindMap             = purposeMap.value(kind).value<QMap<QString, QVariant>>();
-    QVariantList recurrencyKindMap              = kindMap.value(recurrencyKind).value<QVariantList>();
-
-    foreach (const auto& data, recurrencyKindMap) {
-        result.append(data.value<charging_profiles_detail_info_t>());
+    if (dataList.isEmpty()) return false;
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId) return true;
+    }
+    return false;
+}
+
+bool FormTxDefaultProfileDetail::isExistByPurpose(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const QString &purpose)
+{
+    if (dataList.isEmpty()) return false;
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId &&
+            data.chargingProfilePurpose == purpose) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool FormTxDefaultProfileDetail::isExistByKind(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const QString &purpose, const QString &kind)
+{
+    if (dataList.isEmpty()) return false;
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId &&
+            data.chargingProfilePurpose == purpose &&
+            data.chargingProfileKind == kind) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool FormTxDefaultProfileDetail::isExistByRecurrencyKind(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind)
+{
+    if (dataList.isEmpty()) return false;
+    foreach (const auto& data, dataList) {
+        auto ret = (data.connectorId == connectorId &&
+                    data.chargingProfilePurpose == purpose &&
+                    data.chargingProfileKind == kind &&
+                    data.recurrencyKind == recurrencyKind);
+        if (ret) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool FormTxDefaultProfileDetail::isExistByStackLevel(const QList<charging_profiles_detail_info_t> &dataList, const int &connectorId, const QString &purpose, const QString &kind, const QString &recurrencyKind, const int &stackLevel)
+{
+    if (dataList.isEmpty()) return false;
+    foreach (const auto& data, dataList) {
+        if (data.connectorId == connectorId &&
+            data.chargingProfilePurpose == purpose &&
+            data.chargingProfileKind == kind &&
+            data.recurrencyKind == recurrencyKind &&
+            data.stackLevel == stackLevel) {
+            return true;
+        }
+    }
+    return false;
+}
+
+QList<charging_schedule_period_info_t> FormTxDefaultProfileDetail::getDayOfWeekLimitList(const QList<charging_schedule_period_info_t> &dataList, const QString &startTime, const int &curDay)
+{
+    QList<charging_schedule_period_info_t> result;
+    foreach (const auto& data, std::as_const(dataList)) {
+        if (isDayOfWeek(startTime, curDay, data.startPeriod)) {
+            result.append(data);
+        }
     }
 
     return result;
 }
 
+bool FormTxDefaultProfileDetail::isDayOfWeek(const QString &startTime, const int &curDay, const int &seconds)
+{
+    // 1. 解析开始时间
+    QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
+    startDt.setTimeSpec(Qt::UTC); // 若有Z,确保为UTC
+
+    // 2. 计算目标时间
+    QDateTime targetDt = startDt.addSecs(seconds);
+
+    // 3. 判断目标时间是否为指定周几
+    return targetDt.date().dayOfWeek() == curDay;
+}
+
+void FormTxDefaultProfileDetail::updateWeekPeriodList(QList<charging_schedule_period_info_t> &dataList, const QList<charging_schedule_period_info_t> &newDataList, const QString &startTime, const int &curDay)
+{
+    for(int row = dataList.size() - 1; row >= 0; --row) {
+        if (isDayOfWeek(startTime, curDay, dataList[row].startPeriod)) {
+            dataList.removeAt(row);
+        }
+    }
+
+    dataList.append(newDataList);
+
+    GeneralInterface::sortByStartPeriod(dataList);
+}
+
+int FormTxDefaultProfileDetail::indexOfWeekPeriodList(const QList<charging_schedule_period_info_t> &dataList, const charging_schedule_period_info_t &data)
+{
+    for (int index = 0; index < dataList.size(); index ++) {
+        if (dataList[index].startPeriod == data.startPeriod) {
+            return index;
+        }
+    }
+
+    return -1;
+}
+
 void FormTxDefaultProfileDetail::dialyTableWidgetClicked(QTableWidgetItem *item)
 {
-    QMap<int, QVariant> stackLevelData = m_profile_infos_map.value(m_gun_id).value<QMap<int, QVariant>>();
-    auto maxStackLevel = GeneralInterface::getMaxElecment(stackLevelData.keys());
-    if (maxStackLevel < 0) return;
-    auto dailyList = getProfileInfoMap(m_profile_infos_map,
-                                       m_gun_id,
-                                       maxStackLevel,
-                                       ui->chargingProfilePurpose->text(),
-                                       ChargingProfiles::Kind::RECURRING,
-                                       ChargingProfiles::RecurrencyKind::DAILY);
     Limit limit_info;
-    limit_info.startTime    = dailyList[item->row()].chargingSchedule.startTime;
-    limit_info.duration     = dailyList[item->row()].chargingSchedule.duration;
-    limit_info.unit         = dailyList[item->row()].chargingSchedule.chargingRateUnit;
-    limit_info.limit        = dailyList[item->row()].chargingSchedule.chargingSchedulePeriod[0].limit;
+    limit_info.startPeriod      = m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].startPeriod;
+    limit_info.unit             = m_profile_info.chargingSchedule.chargingRateUnit;
+    limit_info.limit            = m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].limit;
 
     m_limit_dialog->setLimit_info(limit_info);
     auto ret = m_limit_dialog->exec();
     if (ret == QDialog::Accepted) {
         auto result = m_limit_dialog->limit_info();
+        m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].startPeriod          = result.startPeriod;
+        m_profile_info.chargingSchedule.chargingRateUnit                                         = result.unit;
+        m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].limit                = result.limit;
+
+        m_profile_info.chargingSchedule.startTime = ui->startTime->dateTime().toString(Qt::ISODate);
+
+        refreshDailyData();
+        setIsModify(true);
+        emit valueChanged();
+    }
+}
+
+void FormTxDefaultProfileDetail::weekdayTableWidgetDoubleClicked(QListWidgetItem *item)
+{
+    ui->startTime->setDateTime(QDateTime::fromString(m_profile_info.chargingSchedule.startTime, Qt::ISODate));
+    GeneralInfo generalInfo;
+    generalInfo.startTime           = m_profile_info.chargingSchedule.startTime;
+    generalInfo.curDay              = ui->weeklyListwidget->row(item) + 1;
+    generalInfo.chargingRateUnit    = m_profile_info.chargingSchedule.chargingRateUnit;
+    m_weekday_dialog->setGeneralInfo(generalInfo);
+
+    auto dayOfWeekList = getDayOfWeekLimitList(m_profile_info.chargingSchedule.chargingSchedulePeriod, generalInfo.startTime, generalInfo.curDay);
+    m_weekday_dialog->setInfo_list(dayOfWeekList);
+    auto ret = m_weekday_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto limitList = m_weekday_dialog->info_list();
+        updateWeekPeriodList(m_profile_info.chargingSchedule.chargingSchedulePeriod, limitList, generalInfo.startTime, generalInfo.curDay);
+        setIsModify(true);
+        emit valueChanged();
     }
 }
 
+void FormTxDefaultProfileDetail::addBtnClicked()
+{
+    m_limit_dialog->clear();
+    auto ret = m_limit_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto result = m_limit_dialog->limit_info();
+
+        charging_schedule_period_info_t info;
+        info.startPeriod = result.startPeriod;
+        info.limit = result.limit;
+        m_profile_info.chargingSchedule.chargingSchedulePeriod.append(info);
+
+        GeneralInterface::sortByStartPeriod(m_profile_info.chargingSchedule.chargingSchedulePeriod);
+
+        refreshDailyData();
+        setIsModify(true);
+        emit valueChanged();
+    }
+}
+
+void FormTxDefaultProfileDetail::deleteBtnClicked()
+{
+    auto row = ui->dailyTablewidget->currentRow();
+    if (row < 0) return;
+    if (row > m_profile_info.chargingSchedule.chargingSchedulePeriod.size()) return;
+    m_profile_info.chargingSchedule.chargingSchedulePeriod.removeAt(row);
+
+    refreshDailyData();
+    setIsModify(true);
+    emit valueChanged();
+}
+
 void FormTxDefaultProfileDetail::showEvent(QShowEvent *event)
 {
     setIsModify(false);
-    m_profile_infos     = ConfigManager::instance()->charging_profiles();
-    m_profile_infos_map = GeneralInterface::chargingProfileToMap(m_profile_infos.chargingProfiles);
     refreshData();
     BaseWidget::showEvent(event);
 }
 
+charging_profiles_detail_info_t FormTxDefaultProfileDetail::profile_info() const
+{
+    return m_profile_info;
+}
+
+void FormTxDefaultProfileDetail::setProfile_info(charging_profiles_detail_info_t newProfile_info)
+{
+    m_profile_info = newProfile_info;
+}
+
 void FormTxDefaultProfileDetail::setGun_id(int newGun_id)
 {
     m_gun_id = newGun_id;

+ 120 - 35
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.h

@@ -2,6 +2,7 @@
 #define FORMTXDEFAULTPROFILEDETAIL_H
 
 #include <QWidget>
+#include <QListWidgetItem>
 #include <QTableWidgetItem>
 #include <QStyledItemDelegate>
 #include <QStyleOptionViewItem>
@@ -9,27 +10,46 @@
 #include "BaseWidget.h"
 #include "DataTypeDef.h"
 #include "OcppSettings/ChargingProfiles/DialogLimitEdit.h"
+#include "OcppSettings/ChargingProfiles/DialogWeekDayDetail.h"
 
 namespace Ui {
 class FormTxDefaultProfileDetail;
 }
 
-namespace WeekDay {
-constexpr int SUNDAY    = 0x0;
-constexpr int MONDAY    = 0x1;
-constexpr int TUESDAY   = 0x2;
-constexpr int WEDNESDAY = 0x3;
-constexpr int THURSDAY  = 0x4;
-constexpr int FRIDAY    = 0x5;
-constexpr int SATURDAY  = 0x6;
-}
-
 #define LIST_ROW_HEIGHT 60
 
+/**
+ * @class CustomItemDelegate
+ * @brief CustomItemDelegate 是一个自定义的项委托类,继承自 QStyledItemDelegate。
+ * 它主要用于在 QListView 或 QTableView 中自定义项的显示方式,特别是设置项的高度。
+ * 
+ * @note 本类主要重写了 sizeHint 方法,用于设置项的高度。
+ * 
+ * @param parent 指向父对象的指针,默认为 nullptr。
+ * 
+ * @example
+ * CustomItemDelegate *delegate = new CustomItemDelegate(parentWidget);
+ * listView->setItemDelegate(delegate);
+ * 
+ * @sa QStyledItemDelegate
+ */
 class CustomItemDelegate : public QStyledItemDelegate {
 public:
+    /**
+     * @brief 构造函数,创建一个 CustomItemDelegate 对象。
+     * 
+     * @param parent 指向父对象的指针,默认为 nullptr。
+     */
     explicit CustomItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
 
+    /**
+     * @brief 重写 sizeHint 方法,用于设置项的大小提示。
+     * 
+     * @param option 描述项的样式选项。
+     * @param index 项的模型索引。
+     * 
+     * @return 项的大小,高度被设置为 LIST_ROW_HEIGHT。
+     */
     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {
         QSize size = QStyledItemDelegate::sizeHint(option, index);
         size.setHeight(LIST_ROW_HEIGHT); // 设置行高
@@ -37,6 +57,32 @@ public:
     }
 };
 
+/**
+ * @class FormTxDefaultProfileDetail
+ * @brief FormTxDefaultProfileDetail 类用于显示和编辑充电配置文件详细信息。
+ * 
+ * 这个类继承自 BaseWidget,用于创建和管理充电配置文件详细信息界面。它包含多个初始化函数,用于设置界面组件,并提供了刷新数据的方法。
+ * 
+ * 核心功能包括:
+ * - 初始化界面组件
+ * - 刷新数据
+ * - 更新数据
+ * - 获取配置文件信息
+ * 
+ * 构造函数参数:
+ * - BaseWidget *parent: 父窗口指针,默认为 nullptr。
+ * 
+ * 使用示例:
+ * @code
+ * FormTxDefaultProfileDetail *form = new FormTxDefaultProfileDetail(parentWidget);
+ * form->setGun_id(1);
+ * form->show();
+ * @endcode
+ * 
+ * 注意事项:
+ * - 在使用该类之前,请确保已经正确初始化了父窗口。
+ * - 该类中的某些方法可能具有副作用,例如更新数据时可能会改变界面状态。
+ */
 class FormTxDefaultProfileDetail : public BaseWidget
 {
     Q_OBJECT
@@ -49,6 +95,9 @@ public:
 
     void setGun_id(int newGun_id);
 
+    charging_profiles_detail_info_t profile_info() const;
+    void setProfile_info(charging_profiles_detail_info_t newProfile_info);
+
 private:
     void initWidget();
     void initConnect();
@@ -62,44 +111,80 @@ private:
     void refreshWeeklyData();
     void refreshDefaultData();
     void appendRowTableWidget(const QString& startTime,
-                              const QString& duration,
                               const QString& limitType,
                               const QString& limit);
 
-    void updateData();
-
-    QMap<int, QVariant> getProfileInfoMap(const QMap<int, QVariant>& map,
-                                          const int& connectorId);
-    QMap<QString, QVariant> getProfileInfoMap(const QMap<int, QVariant>& map,
-                                          const int& connectorId,
-                                          const int& stackLevel);
-    QMap<QString, QVariant> getProfileInfoMap(const QMap<int, QVariant>& map,
-                                              const int& connectorId,
-                                              const int& stackLevel,
-                                              const QString& purpose);
-    QMap<QString, QVariant> getProfileInfoMap(const QMap<int, QVariant>& map,
-                                              const int& connectorId,
-                                              const int& stackLevel,
-                                              const QString& purpose,
-                                              const QString& kind);
-    QList<charging_profiles_detail_info_t> getProfileInfoMap(const QMap<int, QVariant>& map,
-                                                             const int& connectorId,
-                                                             const int& stackLevel,
-                                                             const QString& purpose,
-                                                             const QString& kind,
-                                                             const QString& recurrencyKind);
+    bool updateData();
+    QList<charging_profiles_detail_info_t> getProfileInfo(const QList<charging_profiles_detail_info_t>& dataList,
+                                                          const int& connectorId,
+                                                          const QString& purpose,
+                                                          const QString& kind,
+                                                          const QString& recurrencyKind);
+    charging_profiles_detail_info_t getMaxStackLevel(const QList<charging_profiles_detail_info_t>& dataList);
+    charging_profiles_detail_info_t getProfileInfo(const QList<charging_profiles_detail_info_t>& dataList,
+                                                   const int& connectorId,
+                                                   const QString& purpose,
+                                                   const QString& kind,
+                                                   const QString& recurrencyKind,
+                                                   const int& stackLevel);
+    void updateData(QList<charging_profiles_detail_info_t>& dataList,
+                    const charging_profiles_detail_info_t& data,
+                    const int& connectorId,
+                    const QString& purpose,
+                    const QString& kind,
+                    const QString& recurrencyKind,
+                    const int& stackLevel);
+
+    bool isExistByConnectorId(const QList<charging_profiles_detail_info_t>& dataList,
+                              const int& connectorId);
+    bool isExistByPurpose(const QList<charging_profiles_detail_info_t>& dataList,
+                          const int& connectorId,
+                          const QString& purpose);
+    bool isExistByKind(const QList<charging_profiles_detail_info_t>& dataList,
+                       const int& connectorId,
+                       const QString& purpose,
+                       const QString& kind);
+    bool isExistByRecurrencyKind(const QList<charging_profiles_detail_info_t>& dataList,
+                                 const int& connectorId,
+                                 const QString& purpose,
+                                 const QString& kind,
+                                 const QString& recurrencyKind);
+    bool isExistByStackLevel(const QList<charging_profiles_detail_info_t>& dataList,
+                             const int& connectorId,
+                             const QString& purpose,
+                             const QString& kind,
+                             const QString& recurrencyKind,
+                             const int& stackLevel);
+
+    QList<charging_schedule_period_info_t> getDayOfWeekLimitList(const QList<charging_schedule_period_info_t>& dataList,
+                                                                 const QString& startTime,
+                                                                 const int& curDay);
+
+    bool isDayOfWeek(const QString& startTime, const int& curDay, const int& seconds);
+    void updateWeekPeriodList(QList<charging_schedule_period_info_t>& dataList,
+                              const QList<charging_schedule_period_info_t>& newDataList,
+                              const QString& startTime,
+                              const int& curDay);
+    int indexOfWeekPeriodList(const QList<charging_schedule_period_info_t>& dataList,
+                              const charging_schedule_period_info_t& data);
+
+signals:
+    void valueChanged();
 
 private slots:
     void dialyTableWidgetClicked(QTableWidgetItem* item);
+    void weekdayTableWidgetDoubleClicked(QListWidgetItem* item);
+    void addBtnClicked();
+    void deleteBtnClicked();
 
 protected:
     void showEvent(QShowEvent* event) override;
 
 private:
     Ui::FormTxDefaultProfileDetail *ui;
-    CHARGING_PROFILES m_profile_infos;
-    QVARIANTMAP_INT_MAP m_profile_infos_map;
+    charging_profiles_detail_info_t m_profile_info;
     QScopedPointer<DialogLimitEdit> m_limit_dialog;
+    QScopedPointer<DialogWeekDayDetail> m_weekday_dialog;
     int m_gun_id;
 };
 

+ 104 - 107
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDefaultProfileDetail.ui

@@ -6,14 +6,20 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>927</width>
-    <height>628</height>
+    <width>996</width>
+    <height>622</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_2">
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
    <item row="0" column="0">
     <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
      <item>
@@ -23,7 +29,7 @@
          <property name="minimumSize">
           <size>
            <width>0</width>
-           <height>60</height>
+           <height>48</height>
           </size>
          </property>
          <property name="text">
@@ -31,10 +37,10 @@
          </property>
         </widget>
        </item>
-       <item row="2" column="1">
-        <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
+       <item row="0" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
          <item>
-          <spacer name="horizontalSpacer_5">
+          <spacer name="horizontalSpacer_3">
            <property name="orientation">
             <enum>Qt::Horizontal</enum>
            </property>
@@ -47,12 +53,9 @@
           </spacer>
          </item>
          <item>
-          <widget class="CustomComboBox" name="recurrencyKind" native="true">
-           <property name="minimumSize">
-            <size>
-             <width>40</width>
-             <height>0</height>
-            </size>
+          <widget class="QLabel" name="chargingProfilePurpose">
+           <property name="text">
+            <string>TxDefaultProfile</string>
            </property>
           </widget>
          </item>
@@ -63,7 +66,7 @@
          <property name="minimumSize">
           <size>
            <width>0</width>
-           <height>60</height>
+           <height>48</height>
           </size>
          </property>
          <property name="text">
@@ -71,10 +74,10 @@
          </property>
         </widget>
        </item>
-       <item row="0" column="1">
-        <layout class="QHBoxLayout" name="horizontalLayout_3">
+       <item row="1" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,0">
          <item>
-          <spacer name="horizontalSpacer_3">
+          <spacer name="horizontalSpacer_4">
            <property name="orientation">
             <enum>Qt::Horizontal</enum>
            </property>
@@ -87,9 +90,12 @@
           </spacer>
          </item>
          <item>
-          <widget class="QLabel" name="chargingProfilePurpose">
-           <property name="text">
-            <string>TxDefaultProfile</string>
+          <widget class="CustomComboBox" name="chargingProfileKind" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>40</width>
+             <height>0</height>
+            </size>
            </property>
           </widget>
          </item>
@@ -100,7 +106,7 @@
          <property name="minimumSize">
           <size>
            <width>0</width>
-           <height>60</height>
+           <height>48</height>
           </size>
          </property>
          <property name="text">
@@ -108,10 +114,10 @@
          </property>
         </widget>
        </item>
-       <item row="1" column="1">
-        <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,0">
+       <item row="2" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
          <item>
-          <spacer name="horizontalSpacer_4">
+          <spacer name="horizontalSpacer_5">
            <property name="orientation">
             <enum>Qt::Horizontal</enum>
            </property>
@@ -124,7 +130,7 @@
           </spacer>
          </item>
          <item>
-          <widget class="CustomComboBox" name="chargingProfileKind" native="true">
+          <widget class="CustomComboBox" name="recurrencyKind" native="true">
            <property name="minimumSize">
             <size>
              <width>40</width>
@@ -135,15 +141,64 @@
          </item>
         </layout>
        </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="label_4">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>48</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Start Time : </string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
+         <item>
+          <spacer name="horizontalSpacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="CustomQDateTimeEdit" name="startTime">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignCenter</set>
+           </property>
+           <property name="displayFormat">
+            <string>yyyy-MM-dd HH:mm:ss</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
       </layout>
      </item>
      <item>
       <widget class="QStackedWidget" name="stackedWidget">
        <property name="currentIndex">
-        <number>2</number>
+        <number>1</number>
        </property>
        <widget class="QWidget" name="weekly">
         <layout class="QGridLayout" name="gridLayout_4">
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
          <item row="0" column="0">
           <widget class="QListWidget" name="weeklyListwidget">
            <property name="font">
@@ -153,12 +208,11 @@
            </property>
            <item>
             <property name="text">
-             <string>Sunday</string>
+             <string>Monday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
-              <bold>false</bold>
+              <pointsize>16</pointsize>
              </font>
             </property>
             <property name="textAlignment">
@@ -167,11 +221,11 @@
            </item>
            <item>
             <property name="text">
-             <string>Monday</string>
+             <string>Tuesday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
+              <pointsize>16</pointsize>
              </font>
             </property>
             <property name="textAlignment">
@@ -180,11 +234,11 @@
            </item>
            <item>
             <property name="text">
-             <string>Tuesday</string>
+             <string>Wednesday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
+              <pointsize>16</pointsize>
              </font>
             </property>
             <property name="textAlignment">
@@ -193,11 +247,11 @@
            </item>
            <item>
             <property name="text">
-             <string>Wednesday</string>
+             <string>Thursday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
+              <pointsize>16</pointsize>
              </font>
             </property>
             <property name="textAlignment">
@@ -206,11 +260,11 @@
            </item>
            <item>
             <property name="text">
-             <string>Thursday</string>
+             <string>Friday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
+              <pointsize>16</pointsize>
              </font>
             </property>
             <property name="textAlignment">
@@ -219,11 +273,11 @@
            </item>
            <item>
             <property name="text">
-             <string>Friday</string>
+             <string>Saturday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
+              <pointsize>16</pointsize>
              </font>
             </property>
             <property name="textAlignment">
@@ -232,11 +286,12 @@
            </item>
            <item>
             <property name="text">
-             <string>Saturday</string>
+             <string>Sunday</string>
             </property>
             <property name="font">
              <font>
-              <pointsize>20</pointsize>
+              <pointsize>16</pointsize>
+              <bold>false</bold>
              </font>
             </property>
             <property name="textAlignment">
@@ -249,18 +304,16 @@
        </widget>
        <widget class="QWidget" name="daily">
         <layout class="QGridLayout" name="gridLayout_7">
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
          <item row="0" column="0">
           <layout class="QGridLayout" name="gridLayout_5">
            <item row="0" column="0">
             <widget class="QTableWidget" name="dailyTablewidget">
              <column>
               <property name="text">
-               <string>Start Time</string>
-              </property>
-             </column>
-             <column>
-              <property name="text">
-               <string>Duration</string>
+               <string>Start Period</string>
               </property>
              </column>
              <column>
@@ -316,19 +369,6 @@
                </property>
               </widget>
              </item>
-             <item>
-              <widget class="QPushButton" name="save_limit">
-               <property name="minimumSize">
-                <size>
-                 <width>80</width>
-                 <height>40</height>
-                </size>
-               </property>
-               <property name="text">
-                <string>SAVE</string>
-               </property>
-              </widget>
-             </item>
             </layout>
            </item>
           </layout>
@@ -340,6 +380,9 @@
          <property name="leftMargin">
           <number>0</number>
          </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
          <item row="0" column="0">
           <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0,0,1">
            <item row="3" column="0">
@@ -424,7 +467,7 @@
               </spacer>
              </item>
              <item>
-              <widget class="CustomLineEdit" name="duration">
+              <widget class="CustomLineEdit" name="startPeriod">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
                  <horstretch>0</horstretch>
@@ -441,39 +484,6 @@
              </item>
             </layout>
            </item>
-           <item row="0" column="1">
-            <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
-             <item>
-              <spacer name="horizontalSpacer">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-               <property name="sizeHint" stdset="0">
-                <size>
-                 <width>40</width>
-                 <height>20</height>
-                </size>
-               </property>
-              </spacer>
-             </item>
-             <item>
-              <widget class="CustomQDateTimeEdit" name="startTime">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="alignment">
-                <set>Qt::AlignCenter</set>
-               </property>
-               <property name="displayFormat">
-                <string>yyyy-MM-dd HH:mm:ss</string>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
            <item row="2" column="1">
             <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,0">
              <item>
@@ -510,20 +520,7 @@
               </size>
              </property>
              <property name="text">
-              <string>Duration : </string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="0">
-            <widget class="QLabel" name="label_4">
-             <property name="minimumSize">
-              <size>
-               <width>0</width>
-               <height>60</height>
-              </size>
-             </property>
-             <property name="text">
-              <string>Start Time : </string>
+              <string>Start Period : </string>
              </property>
             </widget>
            </item>

+ 343 - 3
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.cpp

@@ -1,6 +1,13 @@
 #include "FormTxDufaultProfile.h"
 #include "ui_FormTxDufaultProfile.h"
 
+#include <QScroller>
+
+#include "Globals.h"
+#include "ConfigManager.h"
+#include "LanguageManager.h"
+#include "GeneralInterface.h"
+
 FormTxDufaultProfile::FormTxDufaultProfile(BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormTxDufaultProfile)
@@ -18,22 +25,355 @@ FormTxDufaultProfile::~FormTxDufaultProfile()
 
 bool FormTxDufaultProfile::returnParent()
 {
-    return true;
+    return updateData();
 }
 
 void FormTxDufaultProfile::initWidget()
 {
-    ui->gun_info_widget_1->setGun_id(CHARGE_GUN_DEFAULT_1);
-    ui->gun_info_widget_2->setGun_id(CHARGE_GUN_DEFAULT_2);
+    initComboBox();
+    initTableWidget();
+    initListWidget();
+
+    m_limit_dialog.reset(new DialogLimitEdit());
+    m_limit_dialog->setParent(this);
+    m_limit_dialog->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+    m_limit_dialog->setWindowModality(Qt::WindowModal);
+
+    m_weekday_dialog.reset(new DialogWeekDayDetail());
+    m_weekday_dialog->setParent(this);
+    m_weekday_dialog->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+    m_weekday_dialog->setWindowModality(Qt::WindowModal);
 }
 
 void FormTxDufaultProfile::initConnect()
 {
+    connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this](){
+        ui->retranslateUi(this);
+    });
+    connect(GLOBALS, &Globals::ocppConfigKeyValueChanged, this, [this](const CONFIG_KEY_INFO& info) {
+        if (info.SmartChargingProfile.ChargeProfileMaxStackLevel != ui->stackLevel->count()) {
+            initStackLevelComboBox();
+            ui->stackLevel->setCurrentText(QString::number(m_profile_info.stackLevel));
+        }
+    });
+    connect(ui->chargingProfileKind, &CustomComboBox::currentIndexChanged, this, [this](const int& index) {
+        switch (index) {
+        case ChargingProfiles::Kind::ABSOLUTE_ID:
+        case ChargingProfiles::Kind::RELATIVE_ID:
+            ui->recurrencyKind->setCurrentIndex(ChargingProfiles::RecurrencyKind::NO_RECURRING_ID);
+            ui->recurrencyKind->setEnabled(false);
+            break;
+        case ChargingProfiles::Kind::RECURRING_ID:
+            ui->recurrencyKind->setEnabled(true);
+            break;
+        default:
+            break;
+        }
+    });
+
+    connect(ui->recurrencyKind, &CustomComboBox::currentIndexChanged, this, [this](const int& index) {
+        switch (index) {
+        case ChargingProfiles::RecurrencyKind::NO_RECURRING_ID:
+            ui->stackedWidget->setCurrentWidget(ui->no_recyrrency);
+            break;
+        case ChargingProfiles::RecurrencyKind::DAILY_ID:
+            ui->stackedWidget->setCurrentWidget(ui->daily);
+            refreshDailyData();
+            break;
+        case ChargingProfiles::RecurrencyKind::WEEKLY_ID:
+            ui->stackedWidget->setCurrentWidget(ui->weekly);
+            refreshWeeklyData();
+            break;
+        default:
+            break;
+        }
+    });
+
+    connect(ui->chargingRateUnit, &CustomComboBox::currentIndexChanged, this, [this](const int& index) {
+        switch (index) {
+        case ChargingProfiles::UnitType::AMPERE_ID:
+            ui->unit->setText(tr("A"));
+            break;
+        case ChargingProfiles::UnitType::WATT_ID:
+            ui->unit->setText(tr("KW"));
+            break;
+        default:
+            break;
+        }
+    });
+
+    connect(ui->add_limit,      &QPushButton::clicked, this, &FormTxDufaultProfile::addBtnClicked);
+    connect(ui->delete_limit,   &QPushButton::clicked, this, &FormTxDufaultProfile::deleteBtnClicked);
+
+    connect(ui->dailyTablewidget, &QTableWidget::itemDoubleClicked, this, &FormTxDufaultProfile::dialyTableWidgetClicked);
+    connect(ui->weeklyListwidget, &QListWidget::itemDoubleClicked,  this, &FormTxDufaultProfile::weekdayTableWidgetDoubleClicked);
+
+    connect(m_weekday_dialog.data(), &DialogWeekDayDetail::valueChanged, this, [this]() {
+        setIsModify(true);
+    });
+}
+
+void FormTxDufaultProfile::initComboBox()
+{
+    QStringList kind_list;
+    kind_list << ChargingProfiles::Kind::ABSOLUTE
+              << ChargingProfiles::Kind::RELATIVE
+              << ChargingProfiles::Kind::RECURRING;
+    ui->chargingProfileKind->addItems(kind_list);
+
+    QStringList recurrencyKindList;
+    recurrencyKindList << ChargingProfiles::RecurrencyKind::NO_RECURRING
+                       << ChargingProfiles::RecurrencyKind::DAILY
+                       << ChargingProfiles::RecurrencyKind::WEEKLY;
+    ui->recurrencyKind->addItems(recurrencyKindList);
+
+    QStringList rateUnit;
+    rateUnit << ChargingProfiles::UnitType::WATT
+             << ChargingProfiles::UnitType::AMPERE;
+    ui->chargingRateUnit->addItems(rateUnit);
+
+    initStackLevelComboBox();
+}
+
+void FormTxDufaultProfile::initStackLevelComboBox()
+{
+    ui->stackLevel->clear();
+    auto maxStackLevel = ConfigManager::instance()->cfg_key().SmartChargingProfile.ChargeProfileMaxStackLevel;
+    QStringList stackLevelList;
+    for (int index = 0; index <= maxStackLevel; index ++) {
+        stackLevelList.append(QString::number(index));
+    }
+    ui->stackLevel->addItems(stackLevelList);
+}
+
+void FormTxDufaultProfile::initTableWidget()
+{
+    // ui->dailyTablewidget->horizontalHeader()->hide();
+    ui->dailyTablewidget->verticalHeader()->hide();
+
+    ui->dailyTablewidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
+    ui->dailyTablewidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    ui->dailyTablewidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+    ui->dailyTablewidget->setSelectionMode(QAbstractItemView::SingleSelection);
+
+    QScroller::grabGesture(ui->dailyTablewidget,              QScroller::TouchGesture);
+    QScroller::grabGesture(ui->dailyTablewidget->viewport(),  QScroller::LeftMouseButtonGesture);
+}
+
+void FormTxDufaultProfile::initListWidget()
+{
 
 }
 
+void FormTxDufaultProfile::refreshData()
+{
+    refreshGeneralData();
+}
+
+void FormTxDufaultProfile::refreshGeneralData()
+{
+    if (m_profile_info.chargingProfilePurpose != ui->chargingProfilePurpose->text()) return;
+    ui->connectorID->setText(QString::number(m_profile_info.connectorId));
+    ui->chargingProfileKind->setCurrentText(m_profile_info.chargingProfileKind);
+    ui->recurrencyKind->setCurrentText(m_profile_info.recurrencyKind);
+    ui->startTime->setDateTime(QDateTime::fromString(m_profile_info.chargingSchedule.startTime, Qt::ISODate));
+    ui->stackLevel->setCurrentText(QString::number(m_profile_info.stackLevel));
+}
+
+void FormTxDufaultProfile::refreshDailyData()
+{
+    ui->dailyTablewidget->clearContents();
+    ui->dailyTablewidget->setRowCount(0);
+    foreach (const auto& duration_info, m_profile_info.chargingSchedule.chargingSchedulePeriod) {
+        QString limitStr = "";
+        if (m_profile_info.chargingSchedule.chargingRateUnit == ChargingProfiles::UnitType::AMPERE) {
+            limitStr = QString("%1 A").arg(QString::number(duration_info.limit / 1000.0, 'f', 2));
+        } else if (m_profile_info.chargingSchedule.chargingRateUnit == ChargingProfiles::UnitType::WATT) {
+            limitStr = QString("%1 KW").arg(QString::number(duration_info.limit / 1000.0, 'f', 2));
+        }
+        QString startPeriod = GeneralInterface::getCurrentDate(duration_info.startPeriod);
+        appendRowTableWidget(startPeriod,
+                             m_profile_info.chargingSchedule.chargingRateUnit,
+                             limitStr);
+    }
+}
+
+void FormTxDufaultProfile::refreshWeeklyData()
+{
+
+}
+
+void FormTxDufaultProfile::refreshDefaultData()
+{
+
+}
+
+void FormTxDufaultProfile::appendRowTableWidget(const QString &startTime, const QString &limitType, const QString &limit)
+{
+    auto row = ui->dailyTablewidget->rowCount();
+    ui->dailyTablewidget->insertRow(row);
+
+    auto startTimeItem = new QTableWidgetItem(startTime);
+    startTimeItem->setTextAlignment(Qt::AlignCenter);
+    ui->dailyTablewidget->setItem(row, 0, startTimeItem);
+
+    auto limitTypeItem = new QTableWidgetItem(limitType);
+    limitTypeItem->setTextAlignment(Qt::AlignCenter);
+    ui->dailyTablewidget->setItem(row, 1, limitTypeItem);
+
+    auto limitItem = new QTableWidgetItem(limit);
+    limitItem->setTextAlignment(Qt::AlignCenter);
+    ui->dailyTablewidget->setItem(row, 2, limitItem);
+
+    ui->dailyTablewidget->setRowHeight(row, 60);
+}
+
+bool FormTxDufaultProfile::updateData()
+{
+    CHARGING_PROFILES profile_infos = ConfigManager::instance()->charging_profiles();
+    for(int index = 0; index < profile_infos.chargingProfiles.size(); index ++) {
+        if (profile_infos.chargingProfiles[index].chargingProfilePurpose == m_profile_info.chargingProfilePurpose &&
+            profile_infos.chargingProfiles[index].chargingProfileId == m_profile_info.chargingProfileId) {
+            profile_infos.chargingProfiles[index] = m_profile_info;
+        }
+    }
+
+    return ConfigManager::instance()->saveConfig(CHARGING_PROFILE, QVariant::fromValue(profile_infos));
+}
+
+QList<charging_schedule_period_info_t> FormTxDufaultProfile::getDayOfWeekLimitList(const QList<charging_schedule_period_info_t> &dataList, const QString &startTime, const int &curDay)
+{
+    QList<charging_schedule_period_info_t> result;
+    foreach (const auto& data, std::as_const(dataList)) {
+        if (isDayOfWeek(startTime, curDay, data.startPeriod)) {
+            result.append(data);
+        }
+    }
+
+    return result;
+}
+
+bool FormTxDufaultProfile::isDayOfWeek(const QString &startTime, const int &curDay, const int &seconds)
+{
+    // 1. 解析开始时间
+    QDateTime startDt = QDateTime::fromString(startTime, Qt::ISODate);
+    startDt.setTimeSpec(Qt::UTC); // 若有Z,确保为UTC
+
+    // 2. 计算目标时间
+    QDateTime targetDt = startDt.addSecs(seconds);
+
+    // 3. 判断目标时间是否为指定周几
+    return targetDt.date().dayOfWeek() == curDay;
+}
+
+void FormTxDufaultProfile::updateWeekPeriodList(QList<charging_schedule_period_info_t> &dataList, const QList<charging_schedule_period_info_t> &newDataList, const QString &startTime, const int &curDay)
+{
+    for(int row = dataList.size() - 1; row >= 0; --row) {
+        if (isDayOfWeek(startTime, curDay, dataList[row].startPeriod)) {
+            dataList.removeAt(row);
+        }
+    }
+
+    dataList.append(newDataList);
+
+    GeneralInterface::sortByStartPeriod(dataList);
+}
+
+int FormTxDufaultProfile::indexOfWeekPeriodList(const QList<charging_schedule_period_info_t> &dataList, const charging_schedule_period_info_t &data)
+{
+    for (int index = 0; index < dataList.size(); index ++) {
+        if (dataList[index].startPeriod == data.startPeriod) {
+            return index;
+        }
+    }
+
+    return -1;
+}
+
+void FormTxDufaultProfile::dialyTableWidgetClicked(QTableWidgetItem *item)
+{
+    Limit limit_info;
+    limit_info.startPeriod      = m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].startPeriod;
+    limit_info.unit             = m_profile_info.chargingSchedule.chargingRateUnit;
+    limit_info.limit            = m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].limit;
+
+    m_limit_dialog->setLimit_info(limit_info);
+    auto ret = m_limit_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto result = m_limit_dialog->limit_info();
+        m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].startPeriod          = result.startPeriod;
+        m_profile_info.chargingSchedule.chargingRateUnit                                         = result.unit;
+        m_profile_info.chargingSchedule.chargingSchedulePeriod[item->row()].limit                = result.limit;
+
+        m_profile_info.chargingSchedule.startTime = ui->startTime->dateTime().toString(Qt::ISODate);
+
+        refreshDailyData();
+        setIsModify(true);
+    }
+}
+
+void FormTxDufaultProfile::weekdayTableWidgetDoubleClicked(QListWidgetItem *item)
+{
+    GeneralInfo generalInfo;
+    generalInfo.startTime           = m_profile_info.chargingSchedule.startTime;
+    generalInfo.curDay              = ui->weeklyListwidget->row(item) + 1;
+    generalInfo.chargingRateUnit    = m_profile_info.chargingSchedule.chargingRateUnit;
+    m_weekday_dialog->setGeneralInfo(generalInfo);
+
+    auto dayOfWeekList = getDayOfWeekLimitList(m_profile_info.chargingSchedule.chargingSchedulePeriod, generalInfo.startTime, generalInfo.curDay);
+    m_weekday_dialog->setInfo_list(dayOfWeekList);
+    auto ret = m_weekday_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto limitList = m_weekday_dialog->info_list();
+        updateWeekPeriodList(m_profile_info.chargingSchedule.chargingSchedulePeriod, limitList, generalInfo.startTime, generalInfo.curDay);
+        setIsModify(true);
+    }
+}
+
+void FormTxDufaultProfile::addBtnClicked()
+{
+    m_limit_dialog->clear();
+    auto ret = m_limit_dialog->exec();
+    if (ret == QDialog::Accepted) {
+        auto result = m_limit_dialog->limit_info();
+
+        charging_schedule_period_info_t info;
+        info.startPeriod = result.startPeriod;
+        info.limit = result.limit;
+        m_profile_info.chargingSchedule.chargingSchedulePeriod.append(info);
+
+        GeneralInterface::sortByStartPeriod(m_profile_info.chargingSchedule.chargingSchedulePeriod);
+
+        refreshDailyData();
+        setIsModify(true);
+    }
+}
+
+void FormTxDufaultProfile::deleteBtnClicked()
+{
+    auto row = ui->dailyTablewidget->currentRow();
+    if (row < 0) return;
+    if (row > m_profile_info.chargingSchedule.chargingSchedulePeriod.size()) return;
+    m_profile_info.chargingSchedule.chargingSchedulePeriod.removeAt(row);
+
+    refreshDailyData();
+    setIsModify(true);
+}
+
 void FormTxDufaultProfile::showEvent(QShowEvent *event)
 {
     setIsModify(false);
+    refreshData();
     BaseWidget::showEvent(event);
 }
+
+charging_profiles_detail_info_t FormTxDufaultProfile::profile_info() const
+{
+    return m_profile_info;
+}
+
+void FormTxDufaultProfile::setProfile_info(charging_profiles_detail_info_t newProfile_info)
+{
+    m_profile_info = newProfile_info;
+}

+ 45 - 2
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.h

@@ -2,10 +2,15 @@
 #define FORMTXDUFAULTPROFILE_H
 
 #include <QWidget>
+#include <QListWidgetItem>
+#include <QTableWidgetItem>
+#include <QStyledItemDelegate>
+#include <QStyleOptionViewItem>
 
 #include "BaseWidget.h"
-
 #include "DataTypeDef.h"
+#include "OcppSettings/ChargingProfiles/DialogLimitEdit.h"
+#include "OcppSettings/ChargingProfiles/DialogWeekDayDetail.h"
 
 namespace Ui {
 class FormTxDufaultProfile;
@@ -21,16 +26,54 @@ public:
 
     bool returnParent() override;
 
+    charging_profiles_detail_info_t profile_info() const;
+    void setProfile_info(charging_profiles_detail_info_t newProfile_info);
+
 private:
     void initWidget();
     void initConnect();
+    void initComboBox();
+    void initStackLevelComboBox();
+    void initTableWidget();
+    void initListWidget();
+
+    void refreshData();
+    void refreshGeneralData();
+    void refreshDailyData();
+    void refreshWeeklyData();
+    void refreshDefaultData();
+    void appendRowTableWidget(const QString& startTime,
+                              const QString& limitType,
+                              const QString& limit);
+
+    bool updateData();
+
+    QList<charging_schedule_period_info_t> getDayOfWeekLimitList(const QList<charging_schedule_period_info_t>& dataList,
+                                                                 const QString& startTime,
+                                                                 const int& curDay);
+
+    bool isDayOfWeek(const QString& startTime, const int& curDay, const int& seconds);
+    void updateWeekPeriodList(QList<charging_schedule_period_info_t>& dataList,
+                              const QList<charging_schedule_period_info_t>& newDataList,
+                              const QString& startTime,
+                              const int& curDay);
+    int indexOfWeekPeriodList(const QList<charging_schedule_period_info_t>& dataList,
+                              const charging_schedule_period_info_t& data);
+
+private slots:
+    void dialyTableWidgetClicked(QTableWidgetItem* item);
+    void weekdayTableWidgetDoubleClicked(QListWidgetItem* item);
+    void addBtnClicked();
+    void deleteBtnClicked();
 
 protected:
     void showEvent(QShowEvent* event) override;
 
 private:
     Ui::FormTxDufaultProfile *ui;
-    CHARGING_PROFILES m_profile_infos;
+    charging_profiles_detail_info_t m_profile_info;
+    QScopedPointer<DialogLimitEdit> m_limit_dialog;
+    QScopedPointer<DialogWeekDayDetail> m_weekday_dialog;
 };
 
 #endif // FORMTXDUFAULTPROFILE_H

+ 627 - 20
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxDufaultProfile.ui

@@ -6,40 +6,647 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1060</width>
-    <height>787</height>
+    <width>1063</width>
+    <height>518</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Tx Default Profile Settings</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout">
+  <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
-    <widget class="QTabWidget" name="tabWidget">
-     <property name="currentIndex">
-      <number>0</number>
-     </property>
-     <widget class="FormTxDefaultProfileDetail" name="gun_info_widget_1">
-      <attribute name="title">
-       <string>GUN #1</string>
-      </attribute>
-     </widget>
-     <widget class="FormTxDefaultProfileDetail" name="gun_info_widget_2">
-      <attribute name="title">
-       <string>GUN #2</string>
-      </attribute>
-     </widget>
-    </widget>
+    <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+     <item>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="3" column="0">
+        <widget class="QLabel" name="label_3">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>48</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Recurrency Kind : </string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <item>
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QLabel" name="chargingProfilePurpose">
+           <property name="text">
+            <string>TxDefaultProfile</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="label_2">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>48</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Charging Profile Kind : </string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
+         <item>
+          <spacer name="horizontalSpacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="CustomQDateTimeEdit" name="startTime">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignCenter</set>
+           </property>
+           <property name="displayFormat">
+            <string>yyyy-MM-dd HH:mm:ss</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="2" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,0">
+         <item>
+          <spacer name="horizontalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="CustomComboBox" name="chargingProfileKind" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>40</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="label">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>48</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Charging Profile Purpose : </string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="CustomComboBox" name="recurrencyKind" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>40</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="4" column="0">
+        <widget class="QLabel" name="label_4">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>48</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Start Time : </string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="label_8">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>48</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Connector ID : </string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_9">
+         <item>
+          <spacer name="horizontalSpacer_8">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QLabel" name="connectorID">
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="text">
+            <string>1</string>
+           </property>
+           <property name="alignment">
+            <set>Qt::AlignCenter</set>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_9">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QLabel" name="label_9">
+           <property name="text">
+            <string>Stack Level : </string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_10">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="CustomComboBox" name="stackLevel" native="true">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="QStackedWidget" name="stackedWidget">
+       <property name="currentIndex">
+        <number>1</number>
+       </property>
+       <widget class="QWidget" name="weekly">
+        <layout class="QGridLayout" name="gridLayout_4">
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item row="0" column="0">
+          <widget class="QListWidget" name="weeklyListwidget">
+           <property name="font">
+            <font>
+             <pointsize>20</pointsize>
+            </font>
+           </property>
+           <item>
+            <property name="text">
+             <string>Monday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Tuesday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Wednesday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Thursday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Friday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Saturday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>Sunday</string>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>16</pointsize>
+              <bold>false</bold>
+             </font>
+            </property>
+            <property name="textAlignment">
+             <set>AlignCenter</set>
+            </property>
+           </item>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="daily">
+        <layout class="QGridLayout" name="gridLayout_7">
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item row="0" column="0">
+          <layout class="QGridLayout" name="gridLayout_5">
+           <item row="0" column="0">
+            <widget class="QTableWidget" name="dailyTablewidget">
+             <column>
+              <property name="text">
+               <string>Start Period</string>
+              </property>
+             </column>
+             <column>
+              <property name="text">
+               <string>Limit Type</string>
+              </property>
+             </column>
+             <column>
+              <property name="text">
+               <string>Limit</string>
+              </property>
+             </column>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <layout class="QHBoxLayout" name="horizontalLayout_8">
+             <item>
+              <spacer name="spacer">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="QPushButton" name="add_limit">
+               <property name="minimumSize">
+                <size>
+                 <width>80</width>
+                 <height>40</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>ADD</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QPushButton" name="delete_limit">
+               <property name="minimumSize">
+                <size>
+                 <width>80</width>
+                 <height>40</height>
+                </size>
+               </property>
+               <property name="text">
+                <string>DEL</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="no_recyrrency">
+        <layout class="QGridLayout" name="gridLayout_6">
+         <property name="leftMargin">
+          <number>0</number>
+         </property>
+         <property name="bottomMargin">
+          <number>0</number>
+         </property>
+         <item row="0" column="0">
+          <layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0,0,1">
+           <item row="3" column="0">
+            <widget class="QLabel" name="label_7">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>60</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Limit : </string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <layout class="QHBoxLayout" name="horizontalLayout_6">
+             <item>
+              <spacer name="horizontalSpacer_6">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="CustomLineEdit" name="limit">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="text">
+                <string>0</string>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QLabel" name="unit">
+               <property name="text">
+                <string/>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="label_6">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>60</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Charging Rate Unit : </string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
+             <item>
+              <spacer name="horizontalSpacer_2">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="CustomLineEdit" name="startPeriod">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="text">
+                <string>0</string>
+               </property>
+               <property name="alignment">
+                <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item row="2" column="1">
+            <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,0">
+             <item>
+              <spacer name="horizontalSpacer_7">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="CustomComboBox" name="chargingRateUnit" native="true">
+               <property name="minimumSize">
+                <size>
+                 <width>40</width>
+                 <height>0</height>
+                </size>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item row="1" column="0">
+            <widget class="QLabel" name="label_5">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>60</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Start Period : </string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <spacer name="verticalSpacer_2">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+     </item>
+    </layout>
    </item>
   </layout>
  </widget>
  <customwidgets>
   <customwidget>
-   <class>FormTxDefaultProfileDetail</class>
+   <class>CustomComboBox</class>
    <extends>QWidget</extends>
-   <header>FormTxDefaultProfileDetail.h</header>
+   <header location="global">CustomComboBox.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>CustomLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header location="global">CustomLineEdit.h</header>
+  </customwidget>
+  <customwidget>
+   <class>CustomQDateTimeEdit</class>
+   <extends>QDateTimeEdit</extends>
+   <header location="global">CustomQDateTimeEdit.h</header>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>

+ 7 - 2
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.cpp

@@ -1,8 +1,8 @@
 #include "FormTxProfile.h"
 #include "ui_FormTxProfile.h"
 
-FormTxProfile::FormTxProfile(QWidget *parent)
-    : QWidget(parent)
+FormTxProfile::FormTxProfile(BaseWidget *parent)
+    : BaseWidget(parent)
     , ui(new Ui::FormTxProfile)
 {
     ui->setupUi(this);
@@ -12,3 +12,8 @@ FormTxProfile::~FormTxProfile()
 {
     delete ui;
 }
+
+bool FormTxProfile::returnParent()
+{
+    return true;
+}

+ 5 - 2
src/widgets/workspace/settings/OcppSettings/ChargingProfiles/FormTxProfile.h

@@ -2,19 +2,22 @@
 #define FORMTXPROFILE_H
 
 #include <QWidget>
+#include "BaseWidget.h"
 
 namespace Ui {
 class FormTxProfile;
 }
 
-class FormTxProfile : public QWidget
+class FormTxProfile : public BaseWidget
 {
     Q_OBJECT
 
 public:
-    explicit FormTxProfile(QWidget *parent = nullptr);
+    explicit FormTxProfile(BaseWidget *parent = nullptr);
     ~FormTxProfile();
 
+    bool returnParent() override;
+
 private:
     Ui::FormTxProfile *ui;
 };

+ 2 - 2
src/widgets/workspace/settings/OcppSettings/FormAuthCardDetail.cpp

@@ -74,7 +74,7 @@ void FormAuthCardDetail::setBackgroundImage()
 void FormAuthCardDetail::refreshData()
 {
     ui->idTag->setText(m_auth_info.idTag);
-    ui->expiryDate->setDateTime(QDateTime::fromString(m_auth_info.expiryDate, Qt::ISODateWithMs));
+    ui->expiryDate->setDateTime(QDateTime::fromString(m_auth_info.expiryDate, Qt::ISODate));
     ui->parentIdTag->setText(m_auth_info.parentIdTag);
     ui->status->setCurrentText(m_auth_info.status);
 }
@@ -92,7 +92,7 @@ AUTH_CARD_INFO FormAuthCardDetail::getNewData()
 void FormAuthCardDetail::clearData()
 {
     ui->idTag->setText("");
-    ui->expiryDate->setDateTime(QDateTime::currentDateTime());
+    ui->expiryDate->setDateTime(QDateTime::currentDateTimeUtc());
     ui->parentIdTag->setText("");
     ui->status->setCurrentIndex(0);
 }

+ 4 - 4
src/widgets/workspace/settings/OcppSettings/FormChargingProfiles.cpp

@@ -80,16 +80,16 @@ void FormChargingProfiles::refreshData()
 {
     ui->chargingProfileId->setValue(m_charging_profile_data.chargingProfileId);
     ui->stackLevel->setValue(m_charging_profile_data.stackLevel);
-    ui->validFrom->setDateTime(QDateTime::fromString(m_charging_profile_data.validFrom, Qt::ISODateWithMs));
-    ui->validTo->setDateTime(QDateTime::fromString(m_charging_profile_data.validTo, Qt::ISODateWithMs));
+    ui->validFrom->setDateTime(QDateTime::fromString(m_charging_profile_data.validFrom, Qt::ISODate));
+    ui->validTo->setDateTime(QDateTime::fromString(m_charging_profile_data.validTo, Qt::ISODate));
     ui->chargingProfileKind->setText(m_charging_profile_data.chargingProfileKind);
     ui->recurrencyKind->setText(m_charging_profile_data.recurrencyKind);
     ui->connector_id->setValue(m_charging_profile_data.connectorId);
     // ui->chargingRateUnitType->setText(m_charging_profile_data.chargingRateUnitType);
     // ui->minChargingRate->setValue(m_charging_profile_data.minChargingRate);
     // ui->limitChargingRate->setValue(m_charging_profile_data.limitChargingRate);
-    // ui->startSchedule->setDateTime(QDateTime::fromString(m_charging_profile_data.startSchedule, Qt::ISODateWithMs));
-    // ui->startPeriod->setDateTime(QDateTime::fromString(m_charging_profile_data.startPeriod, Qt::ISODateWithMs));
+    // ui->startSchedule->setDateTime(QDateTime::fromString(m_charging_profile_data.startSchedule, Qt::ISODate));
+    // ui->startPeriod->setDateTime(QDateTime::fromString(m_charging_profile_data.startPeriod, Qt::ISODate));
     // ui->duration->setValue(m_charging_profile_data.duration);
 }
 

+ 1 - 42
src/widgets/workspace/settings/OcppSettings/FormOcppSettings.cpp

@@ -1,16 +1,11 @@
 #include "FormOcppSettings.h"
 #include "ui_FormOcppSettings.h"
 
-#include "LanguageManager.h"
-#include "GeneralInterface.h"
-
 FormOcppSettings::FormOcppSettings(BaseWidget *parent)
     : BaseWidget(parent)
     , ui(new Ui::FormOcppSettings)
 {
     ui->setupUi(this);
-    initConnect();
-    GeneralInterface::setTouchScroller(ui->scrollArea);
 }
 
 FormOcppSettings::~FormOcppSettings()
@@ -20,47 +15,11 @@ FormOcppSettings::~FormOcppSettings()
 
 bool FormOcppSettings::returnParent()
 {
-    updateData();
-    return ConfigManager::instance()->saveConfig(CHARGING_PROFILE, QVariant::fromValue(m_chargingProfilesData));
-}
-
-void FormOcppSettings::initConnect()
-{
-    connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
-}
-
-void FormOcppSettings::refreshData()
-{
-    // GeneralInterface::clearGridLayoutChiledren(ui->profile_layout);
-    // for (const charging_profiles_detail_info_t& data : std::as_const((m_chargingProfilesData.chargingProfiles))) {
-    //     m_chargingProfiles[data.chargingProfileId] = new FormChargingProfiles();
-    //     m_chargingProfiles[data.chargingProfileId]->setCharging_profile_data(data);
-    //     GeneralInterface::gridLayoutAddWidget(ui->profile_layout, m_chargingProfiles[data.chargingProfileId]);
-
-    //     connect(m_chargingProfiles[data.chargingProfileId], &FormChargingProfiles::valueChanged, this, [this]() {
-    //         setIsModify(true);
-    //     });
-
-    //     setIsModify(false);
-    // }
-
-    // GeneralInterface::gridLayoutAddStrtch(ui->profile_layout);
-}
-
-void FormOcppSettings::updateData()
-{
-    // m_chargingProfilesData.chargingProfiles.clear();
-    // auto form_list = m_chargingProfiles.values();
-    // for (int index = 0; index < m_chargingProfiles.count(); index ++) {
-    //     auto charging_profile = form_list[index];
-    //     m_chargingProfilesData.chargingProfiles.append(charging_profile->charging_profile_data());
-    // }
+    return true;
 }
 
 void FormOcppSettings::showEvent(QShowEvent *event)
 {
     setIsModify(false);
-    m_chargingProfilesData = ConfigManager::instance()->charging_profiles();
-    refreshData();
     BaseWidget::showEvent(event);
 }

+ 0 - 10
src/widgets/workspace/settings/OcppSettings/FormOcppSettings.h

@@ -5,8 +5,6 @@
 #include <QWidget>
 
 #include "BaseWidget.h"
-#include "ConfigManager.h"
-#include "OcppSettings/FormChargingProfiles.h"
 
 namespace Ui {
 class FormOcppSettings;
@@ -22,19 +20,11 @@ public:
 
     bool returnParent() override;
 
-private :
-    void initConnect();
-    
-    void refreshData();
-    void updateData();
-
 protected:
     void showEvent(QShowEvent *event) override;
 
 private:
     Ui::FormOcppSettings *ui;
-    QMap<int, FormChargingProfiles*> m_chargingProfiles;
-    CHARGING_PROFILES m_chargingProfilesData;
 };
 
 #endif // FORMOCPPSETTINGS_H

+ 0 - 125
src/widgets/workspace/settings/OcppSettings/FormOcppSettings.ui

@@ -13,132 +13,7 @@
   <property name="windowTitle">
    <string>OCPP Settings</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
-     <item>
-      <layout class="QGridLayout" name="gridLayout">
-       <item row="0" column="0">
-        <widget class="QLabel" name="label">
-         <property name="minimumSize">
-          <size>
-           <width>0</width>
-           <height>60</height>
-          </size>
-         </property>
-         <property name="text">
-          <string>Count : </string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <layout class="QHBoxLayout" name="horizontalLayout">
-         <item>
-          <spacer name="horizontalSpacer">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>40</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-         <item>
-          <widget class="CustomSpinBox" name="count">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="alignment">
-            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="label_2">
-         <property name="minimumSize">
-          <size>
-           <width>0</width>
-           <height>60</height>
-          </size>
-         </property>
-         <property name="text">
-          <string>Max Length : </string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <layout class="QHBoxLayout" name="horizontalLayout_2">
-         <item>
-          <spacer name="horizontalSpacer_2">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>40</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-         <item>
-          <widget class="CustomSpinBox" name="maxLength">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="alignment">
-            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-      </layout>
-     </item>
-     <item>
-      <widget class="QScrollArea" name="scrollArea">
-       <property name="widgetResizable">
-        <bool>true</bool>
-       </property>
-       <widget class="QWidget" name="scrollAreaWidgetContents">
-        <property name="geometry">
-         <rect>
-          <x>0</x>
-          <y>0</y>
-          <width>822</width>
-          <height>431</height>
-         </rect>
-        </property>
-        <layout class="QGridLayout" name="gridLayout_3">
-         <item row="0" column="0">
-          <layout class="QGridLayout" name="profile_layout"/>
-         </item>
-        </layout>
-       </widget>
-      </widget>
-     </item>
-    </layout>
-   </item>
-  </layout>
  </widget>
- <customwidgets>
-  <customwidget>
-   <class>CustomSpinBox</class>
-   <extends>QSpinBox</extends>
-   <header location="global">CustomSpinBox.h</header>
-  </customwidget>
- </customwidgets>
  <resources/>
  <connections/>
 </ui>

+ 55 - 2
src/widgets/workspace/settings/OtherSettings/dialog/DialogChargingPopup.h

@@ -15,6 +15,15 @@ constexpr int ENERGY    = 0x1;
 constexpr int TIME      = 0x2;
 }
 
+/**
+ * @brief 对话框充电弹出窗口类,用于显示充电相关的信息。
+ * 
+ * 该类继承自QDialog,用于在应用程序中显示一个对话框,用于显示充电相关的信息。
+ * 它包含了一些核心功能,如初始化界面、更新显示、设置背景等。
+ * 
+ * @param parent 父窗口指针,默认为nullptr。
+ * @param type 对话框类型,默认为EditType::SOC。
+ */
 class DialogChargingPopup : public QDialog
 {
     Q_OBJECT
@@ -23,24 +32,68 @@ public:
     explicit DialogChargingPopup(QWidget *parent = nullptr, int type = EditType::SOC);
     ~DialogChargingPopup();
 
+    /**
+     * @brief 获取当前对话框的值。
+     * 
+     * @return 当前对话框的值。
+     */
     int getValue();
 
 private:
+    /**
+     * @brief 初始化界面组件。
+     */
     void initWidget();
+
+    /**
+     * @brief 初始化信号槽连接。
+     */
     void initConnect();
+
+    /**
+     * @brief 根据类型更新显示。
+     * 
+     * @param type 对话框类型。
+     */
     void updateShow(int type);
+
+    /**
+     * @brief 设置背景。
+     */
     void setBackground();
+
+    /**
+     * @brief 将窗口居中显示。
+     */
     void centerWindow();
 
-    void initTimeButtonGroup();
+    /**
+     * @brief 初始化SOC按钮组。
+     */
     void initSocButtonGroup();
+
+    /**
+     * @brief 初始化时间按钮组。
+     */
+    void initTimeButtonGroup();
+
+    /**
+     * @brief 初始化能量按钮组。
+     */
     void initEnergyButtonGroup();
 
 private slots:
-    // 键盘可见性改变信号槽
+    /**
+     * @brief 键盘可见性改变信号槽。
+     */
     void onKeyboardVisibilityChanged();
 
 protected:
+    /**
+     * @brief 重写显示事件。
+     * 
+     * @param event 显示事件。
+     */
     void showEvent(QShowEvent* event) override;
 
 private:

+ 1 - 1
src/widgets/workspace/settings/OtherSettings/dialog/DialogEditValue.cpp

@@ -80,7 +80,7 @@ void DialogEditValue::setValue(const QString &text, const int &type)
         ui->long_text->setText(text);
         break;
     case General::Type::DATE_TIME:
-        ui->dateTimeEdit->setDateTime(QDateTime::fromString(text, Qt::ISODateWithMs));
+        ui->dateTimeEdit->setDateTime(QDateTime::fromString(text, Qt::ISODate));
         break;
     }
 }

+ 27 - 0
src/widgets/workspace/settings/OtherSettings/dialog/DialogEditValue.h

@@ -17,6 +17,15 @@ constexpr int DOUBLE    = 0x2;
 constexpr int DATETIME  = 0x3;
 }
 
+/**
+ * @brief DialogEditValue 类用于创建一个对话框,允许用户编辑和显示特定类型的值。
+ * 
+ * 该类继承自 QDialog,用于创建一个用户界面,用户可以在其中编辑和显示特定类型的值。
+ * 主要功能包括设置和获取值、设置编辑类型以及处理键盘可见性变化等。
+ * 
+ * @param parent 父窗口指针,用于设置对话框的父窗口。
+ * @param type 初始值类型,默认为 General::Type::VALUE。
+ */
 class DialogEditValue : public QDialog
 {
     Q_OBJECT
@@ -25,9 +34,27 @@ public:
     explicit DialogEditValue(QWidget *parent = nullptr, int type = General::Type::VALUE);
     ~DialogEditValue();
 
+    /**
+     * @brief 设置对话框显示的值。
+     * 
+     * @param text 要显示的文本值。
+     * @param type 值的类型,默认为 General::Type::VALUE。
+     */
     void setValue(const QString& text, const int& type = General::Type::VALUE);
+
+    /**
+     * @brief 获取对话框当前显示的值。
+     * 
+     * @param type 值的类型,默认为 General::Type::VALUE。
+     * @return 当前显示的文本值。
+     */
     QString getValue(const int& type = General::Type::VALUE);
 
+    /**
+     * @brief 设置编辑类型。
+     * 
+     * @param type 要设置的编辑类型。
+     */
     void setEditType(const int& type);
 
 private:

+ 24 - 0
src/widgets/workspace/settings/PcuSettings/FormPcuSettings.cpp

@@ -1,6 +1,9 @@
 #include "FormPcuSettings.h"
 #include "ui_FormPcuSettings.h"
 
+#include <QMessageBox>
+
+#include "Globals.h"
 #include "ConfigManager.h"
 #include "LanguageManager.h"
 #include "GeneralInterface.h"
@@ -14,6 +17,27 @@ FormPcuSettings::FormPcuSettings(BaseWidget *parent)
     connectAllValueChanged(this);
     GeneralInterface::setTouchScroller(ui->scrollArea);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+    connect(GLOBALS, &Globals::pcuConfigValueChanged, this, [this](const PCU_CFG& info) {
+        if (this->isVisible()) {
+            if (isModify()) {
+                auto ret = QMessageBox::information(this,
+                                                    tr("tips"),
+                                                    tr("Do you want to load the updated configuration file content?"),
+                                                    QMessageBox::No | QMessageBox::Yes);
+                if (ret == QMessageBox::Yes) {
+                    // reload config file
+                    m_pcu_cfg = info;
+                    refreshData();
+                } else if (ret == QMessageBox::No){
+                    return;
+                }
+            } else {
+                // reload config file
+                m_pcu_cfg = info;
+                refreshData();
+            }
+        }
+    });
 }
 
 FormPcuSettings::~FormPcuSettings()

+ 25 - 0
src/widgets/workspace/settings/TcuSettings/FormTcuSettings.cpp

@@ -1,6 +1,9 @@
 #include "FormTcuSettings.h"
 #include "ui_FormTcuSettings.h"
 
+#include <QMessageBox>
+
+#include "Globals.h"
 #include "LanguageManager.h"
 #include "ConfigManager.h"
 #include "GeneralInterface.h"
@@ -14,6 +17,28 @@ FormTcuSettings::FormTcuSettings(BaseWidget *parent)
     connectAllValueChanged(this);
     GeneralInterface::setTouchScroller(ui->scrollArea);
     connect(LanguageManager::instance(), &LanguageManager::languageChanged, this, [this]() { ui->retranslateUi(this); });
+
+    connect(GLOBALS, &Globals::tcuConfigValueChanged, this, [this](const TCU_CFG& info) {
+        if (this->isVisible()) {
+            if (isModify()) {
+                auto ret = QMessageBox::information(this,
+                                                    tr("tips"),
+                                                    tr("Do you want to load the updated configuration file content?"),
+                                                    QMessageBox::No | QMessageBox::Yes);
+                if (ret == QMessageBox::Yes) {
+                    // reload config file
+                    m_tcu_cfg = info;
+                    refreshData();
+                } else if (ret == QMessageBox::No){
+                    return;
+                }
+            } else {
+                // reload config file
+                m_tcu_cfg = info;
+                refreshData();
+            }
+        }
+    });
 }
 
 FormTcuSettings::~FormTcuSettings()

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác