Files
YuPu-OrpaonEMS/OrpaonEMS.App/Services/ConfigDataService.cs
2025-12-25 11:13:13 +08:00

853 lines
32 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using HslCommunication.MQTT;
using OrpaonEMS.App.Com;
using OrpaonEMS.App.Models;
using OrpaonEMS.App.PrismEvent;
using OrpaonEMS.Core;
using OrpaonEMS.Core.Enums;
using OrpaonEMS.Model;
using OrpaonEMS.Model.Enums;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Documents;
namespace OrpaonEMS.App.Services
{
/// <summary>
/// 系统配置服务中心
/// </summary>
public class ConfigDataService : BindableBase
{
public ConfigDataService(IFreeSql freeSql, ILogService logService, IEventAggregator eventAggregator)
{
FreeSql = freeSql;
LogService = logService;
_eventAggregator = eventAggregator;
//储能运行配置值的实例化-初始值
energyStorageRunConfig = new EnergyStorageRunConfig();
energyStorageRunConfig.PcsChargOffset = double.Parse(ConfigHelper.GetValue("PcsChargOffset"));
energyStorageRunConfig.PcsDisChargOffset = double.Parse(ConfigHelper.GetValue("PcsDisChargOffset"));
energyStorageRunConfig.MaxBatChargRatio = double.Parse(ConfigHelper.GetValue("MaxBatChargRatio"));
energyStorageRunConfig.MaxBatDisChargRatio = double.Parse(ConfigHelper.GetValue("MaxBatDisChargRatio"));
energyStorageRunConfig.BMSSocUpSignLimitValue = double.Parse(ConfigHelper.GetValue("BMSSocUpSignLimitValue"));
energyStorageRunConfig.BMSSocDownSignLimitValue = double.Parse(ConfigHelper.GetValue("BMSSocDownSignLimitValue"));
IsMaster = ConfigHelper.GetValue("IsMaster") == "1" ? true : false;
ServerUrl = ConfigHelper.GetValue("ServerUrl");
Station = ushort.Parse(ConfigHelper.GetValue("Station"));
BMSIP = ConfigHelper.GetValue("BMSIP");
PCSIP = ConfigHelper.GetValue("PCSIP");
IsDebug = ConfigHelper.GetValue("IsDebug") == "True" ? true : false;
IsDemo = ConfigHelper.GetValue("IsDemo") == "True" ? true : false;
EMSActionLimitValue.TargetValue = double.Parse(ConfigHelper.GetValue("ControlTargetValue"));
PcsChangeValue = double.Parse(ConfigHelper.GetValue("PcsChangeValue"));
MqttServerUrl = ConfigHelper.GetValue("MqttServerUrl");
MqttTopic = ConfigHelper.GetValue("MqttTopic");//v1/devices/me/telemetry
MqttServerPort = int.Parse(ConfigHelper.GetValue("MqttServerPort"));
MqttClientId = ConfigHelper.GetValue("MqttClientId");
MqttUser = ConfigHelper.GetValue("MqttUser");
MqttPwd = ConfigHelper.GetValue("MqttPwd");
//数据保存的配置信息
DataLogFile = ConfigHelper.GetValue("DataLogFile");
YuPuSpecialPeakValley = new SpecialPeakValley();
//获取配置信息
ListEnergyStoragePeakValleyTimeConfig = FreeSql.Select<PeakValleyConfig>().ToList();
//削峰填谷模式的时间监视线程
var ListenPeakValleyTimeTaskInfo = Task.Run(() => ListenPeakValleyTimeCycle());
//加载控制参数配置
LoadControlConfigValue();
}
/// <summary>
/// 储能运行配置值
/// </summary>
public EnergyStorageRunConfig energyStorageRunConfig { get; set; }
/// <summary>
/// FreeSQL实例
/// </summary>
public IFreeSql FreeSql { get; }
public ILogService LogService { get; }
/// <summary>
/// 事件聚合器
/// </summary>
private readonly IEventAggregator _eventAggregator;
#region
/// <summary>
/// 是否保存数据信息
/// </summary>
public bool IsSaveDataLog { get; set; } = true;
/// <summary>
/// BMS IP
/// </summary>
public string BMSIP { get; set; }
/// <summary>
/// BMS IP
/// </summary>
public string PCSIP { get; set; }
/// <summary>
/// 是否调试
/// 默认False
/// </summary>
public bool IsDebug { get; set; }
/// <summary>
/// 是不是Demo
/// 默认False
/// </summary>
public bool IsDemo { get; set; }
private bool _IsStartAuto = true;
/// <summary>
/// 在程序运行的初始状态时是否进行开始模式
/// 默认值为True
/// </summary>
public bool IsStartAuto
{
get { return _IsStartAuto; }
set { _IsStartAuto = value; RaisePropertyChanged(); }
}
#endregion
#region Mqtt Server配置参数
/// <summary>
/// MqttServerUrl
/// </summary>
public string MqttServerUrl { get; set; }
/// <summary>
/// MqttUser
/// </summary>
public string MqttUser { get; set; }
/// <summary>
/// MqttPwd
/// </summary>
public string MqttPwd { get; set; }
/// <summary>
/// MqttTopic
/// </summary>
public string MqttTopic { get; set; }
/// <summary>
/// MqttServerPort
/// </summary>
public int MqttServerPort { get; set; }
/// <summary>
/// MqttClientId
/// </summary>
public string MqttClientId { get; set; }
// MqttServerPort MqttClientId
#endregion
#region PCS配置参数
private double _PcsChangeValue;
/// <summary>
/// PCS的变化时的阈值设置
/// </summary>
public double PcsChangeValue
{
get { return _PcsChangeValue; }
set { _PcsChangeValue = value; }
}
#endregion
private double _TransformerCapacity;
/// <summary>
/// 变压器容量设置
/// </summary>
public double TransformerCapacity
{
get { return _TransformerCapacity; }
set { _TransformerCapacity = value; }
}
#region
/// <summary>
/// 月浦特殊的削峰填谷的模型
/// </summary>
public SpecialPeakValley YuPuSpecialPeakValley { get; set; }
/// <summary>
/// 线程使能
/// </summary>
public bool ThreadEnable { get; set; } = true;
/// <summary>
/// 当前的削峰填谷的配置
/// 在配置服务中,供统计服务使用
/// </summary>
public PeakValleyConfig CurPeakValleyConfig { get; set; } = new PeakValleyConfig();
/// <summary>
/// 监听削峰填谷时间信息
/// 这个不管是否处于削峰填谷的时期都可以实时轮训获取
/// 那么当软件处于启动时就可以实时轮训
/// </summary>
/// <returns></returns>
private async Task ListenPeakValleyTimeCycle()
{
while (ThreadEnable)
{
//退出 由Master发送充放电的数据
if (!IsMaster) break;
try
{
//CurPeakValleyConfig = YuPuSpecialPeakValley.GetSpecialPeakValley();
_eventAggregator.GetEvent<PeakValleyTimeEvent>().Publish(YuPuSpecialPeakValley.GetSpecialPeakValley());
var TimeInfo = DateTime.Now.ToString("HH:mm");
foreach (var item in ListEnergyStoragePeakValleyTimeConfig)
{
if (item.Enable)
{
if (GetIsTimeSpan(TimeInfo, item.StartTime, item.EndTime))
{
CurPeakValleyConfig = item;
//_eventAggregator.GetEvent<PeakValleyTimeEvent>().Publish(item.ElePV);
//PeakValleySglModel = item.ElePV;
//switch (item.ElePV)
//{
// case ElePVEnum.Peak:
// EsSysPeakVellayStateMsg = "峰价";
// break;
// case ElePVEnum.Valley:
// EsSysPeakVellayStateMsg = "谷价";
// break;
// case ElePVEnum.Flat:
// EsSysPeakVellayStateMsg = "平价";
// break;
// default:
// break;
//}
break;
}
}
}
await Task.Delay(10000);
//使用这个线程
//mqttClientDrive.mqttEntity.PcsPower = InPowerPCSDataService.Power;
//mqttClientDrive.mqttEntity.PcsTotalReactivePw = InPowerPCSDataService.TotalReactivePw;
//mqttClientDrive.mqttEntity.PcsTotalApparentPw = InPowerPCSDataService.TotalApparentPw;
//mqttClientDrive.mqttEntity.PcsInputVol = InPowerPCSDataService.InputVol;
//mqttClientDrive.mqttEntity.PcsInputCur = InPowerPCSDataService.InputCur;
//mqttClientDrive.mqttEntity.PcsInputPw = InPowerPCSDataService.InputPw;
//mqttClientDrive.mqttEntity.PcsCurAlarmStateStr = InPowerPCSDataService.CurPCSAlarmStateStr;
//mqttClientDrive.mqttEntity.PcsAVol = InPowerPCSDataService.AVol;
//mqttClientDrive.mqttEntity.PcsBVol = InPowerPCSDataService.BVol;
//mqttClientDrive.mqttEntity.PcsCVol = InPowerPCSDataService.CVol;
//mqttClientDrive.mqttEntity.PcsACur = InPowerPCSDataService.ACur;
//mqttClientDrive.mqttEntity.PcsBCur = InPowerPCSDataService.BCur;
//mqttClientDrive.mqttEntity.PcsCCur = InPowerPCSDataService.CCur;
//mqttClientDrive.mqttEntity.PCSFaultStateStr = InPowerPCSDataService.CurPCSFaultStateStr;
//mqttClientDrive.mqttEntity.BmsCur = BmsDataService.BmsCur.RtValue;
//mqttClientDrive.mqttEntity.BmsVol = BmsDataService.BmsVol.RtValue;
//mqttClientDrive.mqttEntity.BmsSOC = BmsDataService.BmsSOC.RtValue;
//mqttClientDrive.mqttEntity.BmsSOH = BmsDataService.BmsSOH.RtValue;
//mqttClientDrive.mqttEntity.BmsSOE = BmsDataService.BmsSOE.RtValue;
//mqttClientDrive.mqttEntity.BmsResP = BmsDataService.BmsResP.RtValue;
//mqttClientDrive.mqttEntity.BmsResN = BmsDataService.BmsResN.RtValue;
//mqttClientDrive.mqttEntity.BmsAccCharg = BmsDataService.BmsAccCharg.RtValue;
//mqttClientDrive.mqttEntity.BmsAccDisCharg = BmsDataService.BmsAccDisCharg.RtValue;
//mqttClientDrive.mqttEntity.BmsPw = 0;
//mqttClientDrive.mqttEntity.BmsBatState = BmsDataService.BmsBatState;
//mqttClientDrive.mqttEntity.MaxChargePowerCell = BmsDataService.MaxChargePowerCell.RtValue;
//mqttClientDrive.mqttEntity.MaxDisChargePowerCell = BmsDataService.MaxDisChargePowerCell.RtValue;
//mqttClientDrive.mqttEntity.InPress = BmsDataService.InPress.RtValue;
//mqttClientDrive.mqttEntity.OutPress = BmsDataService.OutPress.RtValue;
//mqttClientDrive.mqttEntity.OutTemp = BmsDataService.OutTemp.RtValue;
//mqttClientDrive.mqttEntity.InTemp = BmsDataService.InTemp.RtValue;
//mqttClientDrive.mqttEntity.CoolFaultCode = BmsDataService.CoolFaultCode;
//mqttClientDrive.mqttEntity.CoolStates = BmsDataService.CoolStates;
//mqttClientDrive.mqttEntity.FireSmokeTrig = BmsDataService.FireSmokeTrig;
//mqttClientDrive.mqttEntity.FireTempTrig = BmsDataService.FireTempTrig;
//mqttClientDrive.mqttEntity.FireMainPowerState = BmsDataService.FireMainPowerState;
}
catch (Exception ex)
{
LogService.Info($"时间:{DateTime.Now.ToString()}-【ListenPeakValleyTimeCycle】-{ex.Message}");
}
}
}
/// <summary>
/// 判断时间是否在 某一时间段内
/// </summary>
/// <param name="timeStr"></param>
/// <returns></returns>
public bool GetIsTimeSpan(string timeStr, string startTime, string endTime)
{
//判断当前时间是否在工作时间段内
//string _strWorkingDayAM = "08:30";//工作时间上午08:30
//string _strWorkingDayPM = "17:30";
TimeSpan dspStart = DateTime.Parse(startTime).TimeOfDay;
TimeSpan dspEnd = DateTime.Parse(endTime).TimeOfDay;
//string time1 = "2017-2-17 8:10:00";
DateTime t1 = Convert.ToDateTime(timeStr);
TimeSpan dspNow = t1.TimeOfDay;
if (dspNow > dspStart && dspNow < dspEnd)
{
return true;
}
else if (dspStart > dspEnd)//时间区间处于跨天的状态
{
if (dspNow >= dspStart || dspNow <= dspEnd)
{
return true;
}
}
return false;
}
/// <summary>
/// 储能柜的削峰填谷的配置数据集
/// </summary>
public List<PeakValleyConfig> ListEnergyStoragePeakValleyTimeConfig { get; set; }
/// <summary>
/// 电表动作的上限和下限值
///维持电表在一个区间而不是一个具体的值
///相当于回差值的意思,防止维持在一个点反复的波动导致问题
/// </summary>
public EleMeterActionValue EMSActionLimitValue { get; set; } = new EleMeterActionValue()
{
UpValue = 15,
//MidValue = 7,
DownValue = 8,
TargetValue = 12
};
#endregion
#region MasterSlave分布通信参数
/// <summary>
/// 是否是主站
/// </summary>
public bool IsMaster { get; set; }
/// <summary>
/// Client连接Server的Url
/// </summary>
public string ServerUrl { get; set; }
/// <summary>
/// 站信息数据
/// </summary>
public ushort Station { get; set; }
#endregion
#region
/// <summary>
/// 制热设定温度
/// </summary>
public int SetHeadTargetTemp { get; set; } = 25;
/// <summary>
/// 制冷设定温度
/// </summary>
public int SetCoolTargetTemp { get; set; } = 25;
/// <summary>
/// 控制模式
/// 0 停止
/// 1 制冷
/// 2 制热
/// 3 自循环
/// 4 自动
/// </summary>
public int SetCtrModel { get; set; } = 4;
#endregion
#region
/// <summary>
/// 数据保存的地址信息
/// </summary>
public string DataLogFile { get; set; } = string.Empty;
#endregion
#region
/// <summary>
/// 控制参数配置文件路径
/// </summary>
private readonly string _controlConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", "ControlConfigValue.json");
/// <summary>
/// 控制参数配置值
/// </summary>
public ControlConfigValue ControlConfigValue { get; set; }
/// <summary>
/// 加载控制参数配置
/// </summary>
/// <returns>返回加载结果true表示成功false表示失败</returns>
public bool LoadControlConfigValue()
{
try
{
// 确保目录存在
string directory = Path.GetDirectoryName(_controlConfigFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
LogService.Info($"创建配置目录: {directory}");
}
// 检查文件是否存在
if (File.Exists(_controlConfigFilePath))
{
// 读取JSON文件内容
string jsonContent = File.ReadAllText(_controlConfigFilePath, Encoding.UTF8);
// 检查文件是否为空或只包含空对象
if (string.IsNullOrWhiteSpace(jsonContent) || jsonContent.Trim() == "{}" || jsonContent.Trim() == "{\r\n \r\n}")
{
// 文件为空,创建默认配置
LogService.Info("控制参数配置文件为空,创建默认配置");
ControlConfigValue = new ControlConfigValue();
SaveControlConfigValue();
}
else
{
// 反序列化JSON到对象
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
ControlConfigValue = JsonSerializer.Deserialize<ControlConfigValue>(jsonContent, options);
// 验证反序列化结果
if (ControlConfigValue == null)
{
LogService.Warn("控制参数配置反序列化失败,使用默认配置");
ControlConfigValue = new ControlConfigValue();
SaveControlConfigValue();
}
else
{
LogService.Info("成功加载控制参数配置");
// 兼容键名末尾带空格的 SelectedDisChargeModel
try
{
using (var doc = JsonDocument.Parse(jsonContent))
{
var root = doc.RootElement;
if (root.TryGetProperty("SelectedDisChargeModel ", out var selectedProp))
{
if (selectedProp.ValueKind == JsonValueKind.Number)
{
ControlConfigValue.SelectedDisChargeModel = selectedProp.GetInt32();
}
else if (selectedProp.ValueKind == JsonValueKind.String && int.TryParse(selectedProp.GetString(), out var selInt))
{
ControlConfigValue.SelectedDisChargeModel = selInt;
}
}
}
}
catch (Exception ex)
{
LogService.Warn($"SelectedDisChargeModel(带空格) 兼容解析失败: {ex.Message}");
}
}
}
}
else
{
// 文件不存在,创建默认配置
LogService.Info($"控制参数配置文件不存在,创建默认配置: {_controlConfigFilePath}");
ControlConfigValue = new ControlConfigValue();
SaveControlConfigValue();
}
// 兼容旧配置:确保 DisChargeModel 非空,并在为空列表时注入默认项
if (ControlConfigValue != null)
{
if (ControlConfigValue.DisChargeModel == null)
{
ControlConfigValue.DisChargeModel = new List<DisChargeModelItem>();
}
if (ControlConfigValue.DisChargeModel.Count == 0)
{
ControlConfigValue.DisChargeModel.Add(new DisChargeModelItem { Model = 1, DisChargeTime = "08:00" });
ControlConfigValue.DisChargeModel.Add(new DisChargeModelItem { Model = 2, DisChargeTime = "11:00" });
if (ControlConfigValue.SelectedDisChargeModel <= 0)
{
ControlConfigValue.SelectedDisChargeModel = 1;
}
// 保存注入的默认配置
SaveControlConfigValue();
}
}
return true;
}
catch (JsonException jsonEx)
{
// JSON解析错误
LogService.Error($"控制参数配置JSON解析错误: {jsonEx.Message}");
LogService.Error($"异常堆栈: {jsonEx.StackTrace}");
// 使用默认配置
ControlConfigValue = new ControlConfigValue();
// 尝试备份损坏的文件
try
{
if (File.Exists(_controlConfigFilePath))
{
string backupPath = $"{_controlConfigFilePath}.backup_{DateTime.Now:yyyyMMddHHmmss}";
File.Copy(_controlConfigFilePath, backupPath, true);
LogService.Info($"已备份损坏的配置文件到: {backupPath}");
}
}
catch (Exception backupEx)
{
LogService.Error($"备份损坏的配置文件失败: {backupEx.Message}");
}
// 保存默认配置
SaveControlConfigValue();
return false;
}
catch (Exception ex)
{
// 其他异常
LogService.Error($"加载控制参数配置时发生异常: {ex.Message}");
LogService.Error($"异常类型: {ex.GetType().Name}");
LogService.Error($"异常堆栈: {ex.StackTrace}");
// 使用默认配置
ControlConfigValue = new ControlConfigValue();
return false;
}
}
/// <summary>
/// 保存控制参数配置
/// </summary>
/// <returns>返回保存结果true表示成功false表示失败</returns>
public bool SaveControlConfigValue()
{
try
{
// 验证配置对象
if (ControlConfigValue == null)
{
LogService.Error("控制参数配置对象为空,无法保存");
return false;
}
// 确保目录存在
string directory = Path.GetDirectoryName(_controlConfigFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
LogService.Info($"创建配置目录: {directory}");
}
// 序列化对象到JSON
var options = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
string jsonContent = JsonSerializer.Serialize(ControlConfigValue, options);
// 写入文件前先写入临时文件
string tempFilePath = $"{_controlConfigFilePath}.tmp";
File.WriteAllText(tempFilePath, jsonContent, Encoding.UTF8);
// 验证临时文件是否写入成功
if (File.Exists(tempFilePath))
{
// 备份原文件(如果存在)
if (File.Exists(_controlConfigFilePath))
{
string backupPath = $"{_controlConfigFilePath}.bak";
File.Copy(_controlConfigFilePath, backupPath, true);
}
// 用临时文件替换原文件
File.Copy(tempFilePath, _controlConfigFilePath, true);
File.Delete(tempFilePath);
LogService.Info($"成功保存控制参数配置到: {_controlConfigFilePath}");
return true;
}
else
{
LogService.Error("临时配置文件写入失败");
return false;
}
}
catch (IOException ioEx)
{
// 文件IO异常
LogService.Error($"保存控制参数配置时发生IO异常: {ioEx.Message}");
LogService.Error($"异常堆栈: {ioEx.StackTrace}");
return false;
}
catch (JsonException jsonEx)
{
// JSON序列化异常
LogService.Error($"控制参数配置JSON序列化错误: {jsonEx.Message}");
LogService.Error($"异常堆栈: {jsonEx.StackTrace}");
return false;
}
catch (Exception ex)
{
// 其他异常
LogService.Error($"保存控制参数配置时发生异常: {ex.Message}");
LogService.Error($"异常类型: {ex.GetType().Name}");
LogService.Error($"异常堆栈: {ex.StackTrace}");
return false;
}
}
/// <summary>
/// 更新控制参数配置的值并保存
/// </summary>
/// <param name="configValue">要更新的控制参数配置对象</param>
/// <returns>返回更新结果true表示成功false表示失败</returns>
public bool UpdateControlConfigValue(ControlConfigValue configValue)
{
try
{
if (configValue == null)
{
LogService.Error("传入的控制参数配置对象为空");
return false;
}
// 更新配置值
ControlConfigValue.SolarToEsAsFullSoc = configValue.SolarToEsAsFullSoc;
ControlConfigValue.Master_ToSlaveByMasterSoc = configValue.Master_ToSlaveByMasterSoc;
ControlConfigValue.Master_ToSlaveBySlaveSoc = configValue.Master_ToSlaveBySlaveSoc;
ControlConfigValue.Master_SolarToSlaveEsFullByMasterSoc = configValue.Master_SolarToSlaveEsFullByMasterSoc;
ControlConfigValue.Slave_ToMasterBySlaveSoc = configValue.Slave_ToMasterBySlaveSoc;
ControlConfigValue.Slave_ToMasterByMasterSoc = configValue.Slave_ToMasterByMasterSoc;
ControlConfigValue.Slave_SolarToMasterEsFullBySlaverSoc = configValue.Slave_SolarToMasterEsFullBySlaverSoc;
ControlConfigValue.NightMaster_ToMasterFullSoc = configValue.NightMaster_ToMasterFullSoc;
ControlConfigValue.NightSlave_ToSlaveFullSoc = configValue.NightSlave_ToSlaveFullSoc;
// 保存到文件
bool saveResult = SaveControlConfigValue();
if (saveResult)
{
LogService.Info("成功更新并保存控制参数配置");
}
else
{
LogService.Error("更新控制参数配置后保存失败");
}
return saveResult;
}
catch (Exception ex)
{
LogService.Error($"更新控制参数配置时发生异常: {ex.Message}");
LogService.Error($"异常堆栈: {ex.StackTrace}");
return false;
}
}
/// <summary>
/// 获取放电时间配置集合
/// </summary>
/// <returns>放电时间配置列表(永不返回 null</returns>
public List<DisChargeModelItem> GetDisChargeModel()
{
if (ControlConfigValue == null)
{
ControlConfigValue = new ControlConfigValue();
}
if (ControlConfigValue.DisChargeModel == null)
{
ControlConfigValue.DisChargeModel = new List<DisChargeModelItem>();
}
return ControlConfigValue.DisChargeModel;
}
/// <summary>
/// 保存放电时间配置集合
/// </summary>
/// <param name="items">放电时间配置列表</param>
/// <returns>保存结果</returns>
public bool SaveDisChargeModel(List<DisChargeModelItem> items)
{
if (ControlConfigValue == null)
{
ControlConfigValue = new ControlConfigValue();
}
// 基础校验
var list = items ?? new List<DisChargeModelItem>();
foreach (var it in list)
{
if (it == null)
{
LogService.Error("DisChargeModel 中存在空项");
return false;
}
if (string.IsNullOrWhiteSpace(it.DisChargeTime))
{
LogService.Error("DisChargeModel.DisChargeTime 为空");
return false;
}
if (!TimeSpan.TryParse(it.DisChargeTime, out _))
{
LogService.Error($"DisChargeModel.DisChargeTime 格式非法: {it.DisChargeTime},期望 HH:mm");
return false;
}
}
ControlConfigValue.DisChargeModel = list;
return SaveControlConfigValue();
}
/// <summary>
/// 时间上是否可以放电
/// </summary>
/// <returns></returns>
public bool IsTimeCanDischarge()
{
try
{
// 确保配置加载
if (ControlConfigValue == null)
{
LoadControlConfigValue();
}
// 获取放电时间集合(内部已保证非 null
var list = GetDisChargeModel();
// 选中模式 Id缺省=1
int selectedId = 1;
try
{
selectedId = ControlConfigValue?.SelectedDisChargeModel ?? 1;
}
catch { selectedId = 1; }
// 查找选中项,找不到回退第一项
DisChargeModelItem selected = null;
if (list != null && list.Count > 0)
{
foreach (var it in list)
{
if (it != null && it.Model == selectedId)
{
selected = it;
break;
}
}
if (selected == null)
{
selected = list[0];
}
}
// 解析时间HH:mm失败回退 08:00
TimeSpan target;
if (selected != null && !string.IsNullOrWhiteSpace(selected.DisChargeTime) && TimeSpan.TryParse(selected.DisChargeTime, out target))
{
return DateTime.Now.TimeOfDay >= target;
}
else
{
LogService.Warn("IsTimeCanDischarge: 配置时间缺失或格式非法,使用默认 08:00 进行比较");
target = new TimeSpan(8, 0, 0);
return DateTime.Now.TimeOfDay >= target;
}
}
catch (Exception ex)
{
LogService.Error($"IsTimeCanDischarge 执行失败: {ex.Message}");
return false;
}
}
#endregion
}
}