diff --git a/CapMachine.Model/CANLIN/CanLinRWConfig.cs b/CapMachine.Model/CANLIN/CanLinRWConfig.cs index ca6e539..148c576 100644 --- a/CapMachine.Model/CANLIN/CanLinRWConfig.cs +++ b/CapMachine.Model/CANLIN/CanLinRWConfig.cs @@ -61,5 +61,13 @@ namespace CapMachine.Model.CANLIN public long CanLinConfigProId { get; set; } public CanLinConfigPro? CanLinConfigPro { get; set; } + + + public long LogicRuleId { get; set; } + /// + /// CanLinConfig的逻辑转换规则 + /// 比如:速度下发的数据SV是4000,但是下发到CAN的值是40,可能是其他的逻辑转换规则,这里就是保存其中的逻辑规则 + /// + public LogicRule? LogicRule { get; set; } } } diff --git a/CapMachine.Model/LogicRule.cs b/CapMachine.Model/LogicRule.cs new file mode 100644 index 0000000..18675e1 --- /dev/null +++ b/CapMachine.Model/LogicRule.cs @@ -0,0 +1,52 @@ +using CapMachine.Model.CANLIN; +using FreeSql.DataAnnotations; + +namespace CapMachine.Model +{ + /// + /// 逻辑转换规则模型 + /// + [Table(Name = "LogicRule")] + public class LogicRule + { + /// + /// 主键ID + /// + [Column(IsPrimary = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 规则名称 + /// + [Column(Name = "Name", StringLength = 50)] + public string? Name { get; set; } + + /// + /// 规则描述 + /// + [Column(Name = "Description", StringLength = 200)] + public string? Description { get; set; } + + /// + /// 规则表达式 + /// + [Column(Name = "Expression", StringLength = 500)] + public string? Expression { get; set; } + + /// + /// 适用的参数类型(如:转速、功率等) + /// + [Column(Name = "ParameterType", StringLength = 50)] + public string? ParameterType { get; set; } + + [Column(ServerTime = DateTimeKind.Local, CanUpdate = false)] + public DateTime CreateTime { get; set; } + + /// + /// ///////////////////////////////////////////导航属性/////////////////////////////////////////////////////// + /// + + public List? CanLinRWConfigs { get; set; } + + } +} diff --git a/CapMachine.Wpf/App.xaml.cs b/CapMachine.Wpf/App.xaml.cs index ffc484d..8c8127f 100644 --- a/CapMachine.Wpf/App.xaml.cs +++ b/CapMachine.Wpf/App.xaml.cs @@ -123,7 +123,7 @@ namespace CapMachine.Wpf //containerRegistry.RegisterSingleton(); //containerRegistry.RegisterSingleton(); - + containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); ////注册设备服务 @@ -199,6 +199,7 @@ namespace CapMachine.Wpf containerRegistry.RegisterDialog(); containerRegistry.RegisterDialog(); containerRegistry.RegisterDialog(); + containerRegistry.RegisterDialog(); containerRegistry.RegisterDialog(); diff --git a/CapMachine.Wpf/CanDrive/CanCmdData.cs b/CapMachine.Wpf/CanDrive/CanCmdData.cs index 58baba8..c7a8b74 100644 --- a/CapMachine.Wpf/CanDrive/CanCmdData.cs +++ b/CapMachine.Wpf/CanDrive/CanCmdData.cs @@ -1,4 +1,5 @@ -using System; +using CapMachine.Wpf.Dtos; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -31,5 +32,17 @@ namespace CapMachine.Wpf.CanDrive /// 没有的话,则给默认值 /// public double SignalCmdValue { get; set; } + + ///// + ///// 逻辑规则Id + ///// + //public long LogicRuleId { get; set; } + + /// + /// CanLinConfig的逻辑转换规则 + /// 比如:速度下发的数据SV是4000,但是下发到CAN的值是40,可能是其他的逻辑转换规则,这里就是保存其中的逻辑规则 + /// + public LogicRuleDto? LogicRuleDto { get; set; } + } } diff --git a/CapMachine.Wpf/CapMachine.Wpf.csproj b/CapMachine.Wpf/CapMachine.Wpf.csproj index 5f97789..38d28f8 100644 --- a/CapMachine.Wpf/CapMachine.Wpf.csproj +++ b/CapMachine.Wpf/CapMachine.Wpf.csproj @@ -664,6 +664,7 @@ + diff --git a/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs b/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs index 034b598..8be29e9 100644 --- a/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs +++ b/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs @@ -70,7 +70,12 @@ namespace CapMachine.Wpf.Dtos set { _DefautValue = value; RaisePropertyChanged(); } } - + public long LogicRuleId { get; set; } + /// + /// CanLinConfig的逻辑转换规则 + /// 比如:速度下发的数据SV是4000,但是下发到CAN的值是40,可能是其他的逻辑转换规则,这里就是保存其中的逻辑规则 + /// + public LogicRuleDto? LogicRuleDto { get; set; } } } diff --git a/CapMachine.Wpf/Dtos/LogicRuleDto.cs b/CapMachine.Wpf/Dtos/LogicRuleDto.cs new file mode 100644 index 0000000..7392007 --- /dev/null +++ b/CapMachine.Wpf/Dtos/LogicRuleDto.cs @@ -0,0 +1,73 @@ +using Prism.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.Dtos +{ + /// + /// 逻辑转换规则模型 + /// + public class LogicRuleDto : BindableBase + { + /// + /// 主键ID + /// + public int Id { get; set; } + + + private string _name = string.Empty; + /// + /// 规则名称 + /// + public string Name + { + get { return _name; } + set { SetProperty(ref _name, value); } + } + + + private string _description = string.Empty; + /// + /// 规则描述 + /// + public string Description + { + get { return _description; } + set { SetProperty(ref _description, value); } + } + + private string _expression = string.Empty; + /// + /// 规则表达式 + /// + public string Expression + { + get { return _expression; } + set { _expression = value; RaisePropertyChanged(); } + } + + + private string _parameterType = string.Empty; + /// + /// 适用的参数类型(如:转速、功率等) + /// + public string ParameterType + { + get { return _parameterType; } + set { SetProperty(ref _parameterType, value); } + } + + private DateTime _CreateTime; + /// + /// 适用的参数类型(如:转速、功率等) + /// + public DateTime CreateTime + { + get { return _CreateTime; } + set { _CreateTime = value; RaisePropertyChanged(); } + } + } +} diff --git a/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs b/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs new file mode 100644 index 0000000..51e2843 --- /dev/null +++ b/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs @@ -0,0 +1,19 @@ +using AutoMapper; +using CapMachine.Model; +using CapMachine.Wpf.Dtos; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.MapperProfile +{ + public class LogicRuleProfile : Profile + { + public LogicRuleProfile() + { + CreateMap().ReverseMap(); + } + } +} diff --git a/CapMachine.Wpf/Models/Tag/Cell/MeterValueAttrCell.cs b/CapMachine.Wpf/Models/Tag/Cell/MeterValueAttrCell.cs index 58aa633..2ebe303 100644 --- a/CapMachine.Wpf/Models/Tag/Cell/MeterValueAttrCell.cs +++ b/CapMachine.Wpf/Models/Tag/Cell/MeterValueAttrCell.cs @@ -99,7 +99,7 @@ namespace CapMachine.Wpf.Models.Tag.Cell } } - private string? _EngValueStr; + private string? _EngValueStr="0"; /// /// 工程值的字符串 MV /// diff --git a/CapMachine.Wpf/PrismEvent/LogicRuleChangeEvent.cs b/CapMachine.Wpf/PrismEvent/LogicRuleChangeEvent.cs new file mode 100644 index 0000000..7721b9d --- /dev/null +++ b/CapMachine.Wpf/PrismEvent/LogicRuleChangeEvent.cs @@ -0,0 +1,14 @@ +using Prism.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CapMachine.Wpf.PrismEvent +{ + public class LogicRuleChangeEvent : PubSubEvent + { + + } +} diff --git a/CapMachine.Wpf/Services/CanFdDriveService.cs b/CapMachine.Wpf/Services/CanFdDriveService.cs index 34f497e..7d3844f 100644 --- a/CapMachine.Wpf/Services/CanFdDriveService.cs +++ b/CapMachine.Wpf/Services/CanFdDriveService.cs @@ -1,5 +1,7 @@ using CapMachine.Model.CANLIN; using CapMachine.Wpf.CanDrive; +using CapMachine.Wpf.Models; +using CapMachine.Wpf.Models.ProModelPars; using ImTools; using Prism.Ioc; using Prism.Mvvm; @@ -18,15 +20,17 @@ namespace CapMachine.Wpf.Services public class CanFdDriveService : BindableBase { public HighSpeedDataService HighSpeedDataService { get; } + public LogicRuleService LogicRuleService { get; } /// /// 实例化函数 /// - public CanFdDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider) + public CanFdDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider, LogicRuleService logicRuleService) { ToomossCanFDDrive = new ToomossCanFD(containerProvider); //高速数据服务 HighSpeedDataService = highSpeedDataService; + LogicRuleService = logicRuleService; //ToomossCanFDDrive.StartCanDrive(); } @@ -172,7 +176,14 @@ namespace CapMachine.Wpf.Services { if (SpeedCanCmdData != null) { - SpeedCanCmdData.SignalCmdValue = SpeedData; + if (SpeedCanCmdData.LogicRuleDto == null) + { + //没有启动逻辑规则处理 + SpeedCanCmdData.SignalCmdValue = SpeedData; + return; + } + + SpeedCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto); } //if (EnableCanCmdData != null) //{ @@ -201,7 +212,12 @@ namespace CapMachine.Wpf.Services { if (PwLimitCanCmdData != null) { - PwLimitCanCmdData.SignalCmdValue = PwLimit; + if (PwLimitCanCmdData.LogicRuleDto==null) + { + PwLimitCanCmdData.SignalCmdValue = PwLimit; + return; + } + PwLimitCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(PwLimit, PwLimitCanCmdData.LogicRuleDto!); } } @@ -226,7 +242,12 @@ namespace CapMachine.Wpf.Services { if (PTCPwCanCmdData != null) { - PTCPwCanCmdData.SignalCmdValue = PTCPw; + if (PTCPwCanCmdData.LogicRuleDto == null) + { + PTCPwCanCmdData.SignalCmdValue = PTCPw; + return; + } + PTCPwCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(PTCPw, PTCPwCanCmdData.LogicRuleDto!); } } @@ -238,7 +259,12 @@ namespace CapMachine.Wpf.Services { if (PTCFlowCanCmdData != null) { - PTCFlowCanCmdData.SignalCmdValue = Flow; + if (PTCFlowCanCmdData.LogicRuleDto == null) + { + PTCFlowCanCmdData.SignalCmdValue = Flow; + return; + } + PTCFlowCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(Flow, PTCFlowCanCmdData.LogicRuleDto!); } } @@ -250,7 +276,12 @@ namespace CapMachine.Wpf.Services { if (PTCWaterTempCanCmdData != null) { - PTCWaterTempCanCmdData.SignalCmdValue = WaterTemp; + if (PTCWaterTempCanCmdData.LogicRuleDto == null) + { + PTCWaterTempCanCmdData.SignalCmdValue = WaterTemp; + return; + } + PTCWaterTempCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(WaterTemp, PTCWaterTempCanCmdData.LogicRuleDto!); } } diff --git a/CapMachine.Wpf/Services/ComActionService.cs b/CapMachine.Wpf/Services/ComActionService.cs index 21fb180..8d34e8b 100644 --- a/CapMachine.Wpf/Services/ComActionService.cs +++ b/CapMachine.Wpf/Services/ComActionService.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; namespace CapMachine.Wpf.Services { @@ -61,6 +62,14 @@ namespace CapMachine.Wpf.Services case "过热度/过冷度配置": ShowSuperHeatCool(msg.Par); break; + case "规则转换": + if (SysRunServer.MachineRunState1.IsRunState) + { + MessageBox.Show("请不要在运行时编辑规则转换,此时更改可能导致运行出错,请停止后再编辑"); + return; + } + ShowLogicRule(msg.Par); + break; default: break; } @@ -93,6 +102,40 @@ namespace CapMachine.Wpf.Services } + /// + /// 过热度和过冷度配置弹窗 + /// + private void ShowLogicRule(object par) + { + //弹窗 + DialogService.ShowDialog("DialogLogicRuleView", new DialogParameters() { { "Name", par } }, (par) => + { + if (par.Result == ButtonResult.OK) + { + //保存配置信息 + //PPCService.SaveSuperHeatCoolConfig(); + + //是否改变规格 + var ReturnValue = par.Parameters.GetValue("IsRuleEdit"); + if (ReturnValue) + { + MessageBox.Show("检测到你已经改变了规则,CAN或者LIN配置中如果已经加载规则或者连接的话,则会出现错误,那么你需要重启软件"); + //逻辑可能更改了 + EventAggregator.GetEvent().Publish(""); + } + + + } + else if (par.Result == ButtonResult.Cancel) + { + //取消 + + } + + }); + } + + diff --git a/CapMachine.Wpf/Services/LogicRuleService.cs b/CapMachine.Wpf/Services/LogicRuleService.cs new file mode 100644 index 0000000..5adc573 --- /dev/null +++ b/CapMachine.Wpf/Services/LogicRuleService.cs @@ -0,0 +1,578 @@ +using AutoMapper; +using CapMachine.Core; +using CapMachine.Model; +using CapMachine.Wpf.Dtos; +using DynamicExpresso; +using FreeSql; +using FreeSql.DataAnnotations; +using Prism.Mvvm; +using Syncfusion.Windows.Shared; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace CapMachine.Wpf.Services +{ + /// + /// 逻辑服务 - 用于处理数据逻辑转换 + /// + public class LogicRuleService : BindableBase + { + private readonly ILogService LogService; + private readonly IFreeSql FreeSql; + + /// + /// 逻辑转换规则集合 + /// + public ObservableCollection LogicRuleDtos { get; private set; } + + /// + /// DynamicExpresso解释器 + /// + private Interpreter CurInterpreter { get; set; } + public IMapper Mapper { get; } + + /// + /// 规则表达式缓存(高性能访问) + /// Key: 规则名称, Value: 已编译的Lambda表达式 + ///private readonly ConcurrentDictionary> _expressionCache; + /// + private readonly ConcurrentDictionary> _expressionCache; + + ///// + ///// 创建包含指定值的参数数组 + ///// + //private Parameter[] CreateParameters(double value) + //{ + // return new Parameter[] + // { + // new Parameter("value", typeof(double), value) + // }; + //} + + /// + /// 创建包含指定值的参数 + /// + private Parameter CreateParameters(double value) + { + return new Parameter("value", typeof(double), value); + + } + + /// + /// 实例化函数 + /// + public LogicRuleService(ILogService logService, IFreeSql freeSql, IMapper mapper) + { + LogService = logService; + FreeSql = freeSql; + Mapper = mapper; + + // 初始化集合 + LogicRuleDtos = new ObservableCollection(); + + _expressionCache = new ConcurrentDictionary>(); + + // 初始化DynamicExpresso解释器 + CurInterpreter = new Interpreter(); + + try + { + // 从数据库加载规则 + LoadRulesFromDatabase(); + + } + catch (Exception ex) + { + LogService.Error($"初始化逻辑服务失败: {ex.Message}"); + } + } + + /// + /// 从数据库加载规则 + /// + private void LoadRulesFromDatabase() + { + try + { + // 从数据库加载规则 + var dbRules = FreeSql.Select().OrderBy(a => a.Id).ToList(); + if (dbRules != null && dbRules.Count > 0) + { + LogicRuleDtos.Clear(); + _expressionCache.Clear(); // 清空表达式缓存 + + foreach (var rule in dbRules) + { + LogicRuleDtos.Add(Mapper.Map(rule)); + } + + // 预编译所有表达式 + WarmUpExpressionCache(); + + //LogService.Info($"已从数据库加载并预编译 {dbRules.Count} 条逻辑规则"); + } + else + { + LogService.Warn("数据库中没有逻辑规则"); + } + } + catch (Exception ex) + { + LogService.Error($"从数据库加载逻辑规则失败: {ex.Message}"); + throw; // 重新抛出异常以便调用者处理 + } + } + + + #region 增删改查LogicRule + + + /// + /// 添加新规则 + /// + /// 规则对象 + public void AddRule(LogicRule rule) + { + if (string.IsNullOrWhiteSpace(rule.Name)) + { + MessageBox.Show("规则名称不能为空"); + return; + } + + if (string.IsNullOrWhiteSpace(rule.Expression)) + { + MessageBox.Show("规则表达式不能为空"); + return; + } + + if (LogicRuleDtos.Where(a => a.Name == rule.Name).Any()) + { + MessageBox.Show("已经有另一个相同名称的规则了"); + return; + } + + // 验证表达式是否有效 + if (!ValidateExpression(rule.Expression)) + { + MessageBox.Show("规则表达式验证失败"); + return; + } + + if (InsertRuleToDb(rule, out LogicRule resultInsert)) + { + //此时的resultInsert有新增的ID + // 添加规则 + LogicRuleDtos.Add(Mapper.Map(resultInsert)); + + // 预编译并缓存表达式 + CacheExpression(Mapper.Map(resultInsert)); + } + else + { + MessageBox.Show("增加数据失败!"); + return; + } + //LogService.Info($"添加新规则: {rule.Name}"); + } + + /// + /// 保存规格到数据库中 + /// + /// + public bool InsertRuleToDb(LogicRule rule, out LogicRule ResultInsert) + { + try + { + // 插入规则到数据库 + var result = FreeSql.Insert(rule).ExecuteInserted(); + + // 检查影响的行数 + bool success = result.Count > 0; + + if (success) + { + ResultInsert = result.FirstOrDefault()!; + return success; + //LogService.Info($"成功插入规则: {rule.Name}"); + + // 刷新内存中的规则集合 + //LoadRulesFromDatabase(); + } + else + { + LogService.Warn($"插入规则失败: {rule.Name},没有行受影响"); + ResultInsert = null; + return success; + } + + + } + catch (Exception ex) + { + LogService.Error($"插入规则到数据库时发生异常: {ex.Message}"); + ResultInsert = null; + return false; + } + } + + /// + /// 更新规则 + /// + /// 规则对象 + public void UpdateRule(LogicRule ruleOld, LogicRule rule) + { + if (string.IsNullOrWhiteSpace(rule.Name)) + { + MessageBox.Show("规则名称不能为空"); + return; + } + + if (string.IsNullOrWhiteSpace(rule.Expression)) + { + MessageBox.Show("规则表达式不能为空"); + return; + } + + + // 验证表达式是否有效 + if (!ValidateExpression(rule.Expression)) + { + MessageBox.Show("规则表达式验证失败"); + return; + } + + if (UpdateRuleToDb(rule)) + { + // 更新缓存 + var updatedDto = LogicRuleDtos.FirstOrDefault(r => r.Id == rule.Id); + var insertIndex = LogicRuleDtos.ToList().FindIndex(x => x.Id > rule.Id); + if (updatedDto != null) + { + //移除数据 + LogicRuleDtos.Remove(updatedDto); + if (insertIndex == -1) + { + LogicRuleDtos.Add(Mapper.Map(rule)); + } + else + { + // 在找到的位置插入 + LogicRuleDtos.Insert(insertIndex - 1, Mapper.Map(rule)); + } + + //有可能更改的是名称,那么新名称的话在_expressionCache中肯定是找不到的,可以用之前的ruleOld + _expressionCache.TryRemove(ruleOld.Name!, out _); + CacheExpression(updatedDto); + } + } + + //LogService.Info($"更新规则: {rule.Name}"); + } + + /// + /// 更新规格到数据库中 + /// + /// + public bool UpdateRuleToDb(LogicRule rule) + { + try + { + // 更新规则到数据库 + var result = FreeSql.Update() + .Set(a => a.Name, rule.Name) + .Set(a => a.Description, rule.Description) + .Set(a => a.Expression, rule.Expression) + .Set(a => a.ParameterType, rule.ParameterType) + .Where(r => r.Id == rule.Id) + .ExecuteUpdated(); + + // 检查影响的行数 + bool success = result.Count() > 0; + + if (success) + { + //LogService.Info($"成功更新规则: {rule.Name}"); + + } + else + { + //LogService.Warn($"更新规则失败: {rule.Name},没有行受影响"); + } + + return success; + } + catch (Exception ex) + { + //LogService.Error($"更新规则到数据库时发生异常: {ex.Message}"); + return false; + } + } + + /// + /// 删除规则 + /// + /// 规则名称 + public void DeleteRule(string ruleName) + { + var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName); + if (rule == null) + { + MessageBox.Show("找不到删除的数据"); + return; + } + + var Count = FreeSql.Delete().Where(r => r.Id == rule.Id).ExecuteAffrows(); + if (Count > 0) + { + // 删除规则 + LogicRuleDtos.Remove(rule); + // 从缓存中移除表达式 + _expressionCache.TryRemove(ruleName, out _); + } + + //LogService.Info($"删除规则: {ruleName}"); + } + + /// + /// 验证表达式是否有效 + /// + /// 表达式字符串 + /// 表达式是否有效 + private bool ValidateExpression(string expression) + { + try + { + // 创建测试解释器并直接设置变量 + var interpreter = new Interpreter() + .Reference(typeof(Math)) // 引用Math类 + .SetVariable("Math", typeof(Math)) + .SetVariable("value", 100); // 直接设置值变量 + + // 尝试编译表达式 + var lambda = interpreter.Parse(expression); + + // 尝试执行表达式 + var result = lambda.Invoke(); + + // 检查结果是否为数值类型 + if (result is double doubleResult) + { + // 验证结果不是NaN或Infinity + if (double.IsNaN(doubleResult) || double.IsInfinity(doubleResult)) + { + //LogService.Warn($"表达式执行结果无效 (NaN或Infinity): {expression}"); + return false; + } + } + + return true; + } + catch (Exception ex) + { + LogService.Warn($"验证表达式失败: {expression}, 错误: {ex.Message}"); + return false; + } + } + + + #endregion + + + /// + /// 根据参数类型获取适用的规则 + /// + /// 参数类型 + /// 适用的规则列表 + public IEnumerable GetRulesByParameterType(string parameterType) + { + return LogicRuleDtos.Where(r => r.ParameterType == parameterType); + } + + /// + /// 获取指定名称的规则 + /// + /// 规则名称 + /// 规则对象 + public LogicRuleDto GetRuleByName(string ruleName) + { + var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName); + if (rule == null) + { + throw new KeyNotFoundException($"找不到名为 {ruleName} 的规则"); + } + return rule; + } + + + /// + /// 将规则表达式预编译并缓存到字典中 + /// + /// 要缓存的规则 + private void CacheExpression(LogicRuleDto rule) + { + if (string.IsNullOrEmpty(rule.Name) || string.IsNullOrEmpty(rule.Expression)) + { + return; // 防止空名称或空表达式 + } + + try + { + // ****如下步骤很重要,尝试了很多次才正常运行**** + + // 使用已有的CreateParameters方法创建参数声明 + var parameter = CreateParameters(0); // 值不重要,只是为了获取参数声明 + // 只解析一次,得到 Lambda 对象 + var lambda = CurInterpreter.Parse(rule.Expression, parameter); // 只定义参数类型,不传值 + // 编译为强类型委托 + var compiledFunc = lambda.Compile>(); + + // 存入缓存 + _expressionCache[rule.Name] = compiledFunc; + } + catch (Exception ex) + { + LogService.Error($"缓存规则 {rule.Name} 表达式失败: {ex.Message}"); + } + } + + /// + /// 预热表达式缓存 - 预编译所有规则 + /// + private void WarmUpExpressionCache() + { + foreach (var rule in LogicRuleDtos) + { + if (!_expressionCache.ContainsKey(rule.Name)) + { + CacheExpression(rule); + } + } + LogService.Info($"已预编译 {_expressionCache.Count} 条规则表达式"); + } + + /// + /// 根据规则应用表达式(高性能版本) + /// + /// 输入值 + /// 规则对象 + /// 转换后的输出值 + public double ApplyExpression(double value, LogicRuleDto rule) + { + try + { + // 尝试从缓存获取预编译的表达式 + if (!_expressionCache.TryGetValue(rule.Name, out var compiledExpression)) + { + // 如果缓存中没有,则编译并添加到缓存 + CacheExpression(rule); + + // 再次尝试获取 + if (!_expressionCache.TryGetValue(rule.Name, out compiledExpression)) + { + // 初始解析表达式(只需执行一次) + string expressionText = rule.Expression; + + // 强类型函数 + Func compiledFunc = (v) => + { + // 高性能版本:直接根据公式计算 + try + { + if (expressionText.Contains("value")) + { + var parameters = CreateParameters(v); + var lambda = CurInterpreter.Parse(expressionText, parameters); + return (double)lambda.Invoke(); + } + else + { + // 简单表达式使用直接求值 + return v / 100.0; // 默认处理 + } + } + catch + { + // 出错时返回原值 + return v; + } + }; + // 再次尝试缓存 + CacheExpression(rule); + + return compiledFunc(value); + } + } + + // 创建包含实际值的参数 + var parameter = new Parameter("value", typeof(double), value); + // 使用预编译的表达式执行计算(高性能) + var convertedValue = (double)compiledExpression.Invoke(value); + + return convertedValue; + } + catch (Exception ex) + { + //LogService.Error($"应用规则 {rule.Name} 失败: {ex.Message}"); + return value; // 出错时返回原始值 + } + } + + + /// + /// 快速的执行数据 + /// + /// + /// + /// + public double ApplyExpressionFast(double value, LogicRuleDto rule) + { + try + { + if (!_expressionCache.TryGetValue(rule.Name, out var CurActiveFunc)) + { + CacheExpression(rule); + if (!_expressionCache.TryGetValue(rule.Name, out CurActiveFunc)) + return value; + } + + // 直接调用委托,无反射开销 + return CurActiveFunc(value); + } + catch + { + return value; + } + } + + + /// + /// 如果需要对多个数据应用相同规则,考虑实现批处理版本: + /// + /// + /// + /// + public IEnumerable ApplyExpressionBatch(IEnumerable values, LogicRuleDto rule) + { + if (!_expressionCache.TryGetValue(rule.Name, out var func)) + { + CacheExpression(rule); + if (!_expressionCache.TryGetValue(rule.Name, out func)) + return values; + } + + // 使用并行处理大量数据 + return values.AsParallel().Select(v => + { + try { return func(v); } + catch { return v; } + }); + } + + } +} diff --git a/CapMachine.Wpf/Services/NavigationMenuService.cs b/CapMachine.Wpf/Services/NavigationMenuService.cs index d96ed1e..ab57060 100644 --- a/CapMachine.Wpf/Services/NavigationMenuService.cs +++ b/CapMachine.Wpf/Services/NavigationMenuService.cs @@ -40,6 +40,10 @@ namespace CapMachine.Wpf.Services new NavigationItem("SuperHeatCool","过热度/过冷度配置","DialogSuperHeatCoolConfigView"), //new NavigationItem("Palette","过冷度",""), }), + new NavigationItem("", "规则设置","",new ObservableCollection() + { + new NavigationItem("Rule","规则转换","DialogLogicRuleView"), + }), //new NavigationItem("", "PID设置","",new ObservableCollection() //{ // new NavigationItem("Circle","转速PID",""), diff --git a/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs b/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs index f20664c..86d2cf8 100644 --- a/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs +++ b/CapMachine.Wpf/ViewModels/CANFDConfigViewModel.cs @@ -34,7 +34,7 @@ namespace CapMachine.Wpf.ViewModels { public CANFDConfigViewModel(IDialogService dialogService, IFreeSql freeSql, IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService, - ComActionService actionService,ILogService logService, + ComActionService actionService, ILogService logService, LogicRuleService logicRuleService, ConfigService configService, CanFdDriveService canFdDriveService, IMapper mapper, MachineRtDataService machineRtDataService) { @@ -44,6 +44,7 @@ namespace CapMachine.Wpf.ViewModels RegionManager = regionManager; SysRunService = sysRunService; ComActionService = actionService; + LogicRuleService = logicRuleService; LogService = logService; ConfigService = configService; CanFdDriveService = canFdDriveService; @@ -127,8 +128,10 @@ namespace CapMachine.Wpf.ViewModels new CbxItems(){ Key="通讯PTC膜温",Text="通讯PTC膜温"}, new CbxItems(){ Key="通讯PTC模块温度",Text="通讯PTC模块温度"}, }; - InitLoadCanConfigPro(); + InitLoadCanConfigPro(); + //初始化写规则下拉框 + InitWriteRuleCbx(); } @@ -140,6 +143,7 @@ namespace CapMachine.Wpf.ViewModels public IRegionManager RegionManager { get; } public SysRunService SysRunService { get; } public ComActionService ComActionService { get; } + public LogicRuleService LogicRuleService { get; } public ILogService LogService { get; } public ConfigService ConfigService { get; } public CanFdDriveService CanFdDriveService { get; } @@ -151,8 +155,40 @@ namespace CapMachine.Wpf.ViewModels /// public IDialogService DialogService { get; } + #region 规则 + /// + /// 逻辑更改事件 + /// + /// + /// + private void LogicRuleChangeEventCall(string msg) + { + //InitWriteRuleCbx(); + } + + /// + /// 初始化写规则下拉框 + /// + private void InitWriteRuleCbx() + { + WriteRuleCbxItems = new ObservableCollection(); + //选择的读写规则 + foreach (var itemRule in LogicRuleService.LogicRuleDtos) + { + WriteRuleCbxItems.Add(new CbxItems() + { + Key = itemRule.Id.ToString(), + Text = itemRule.Name + }); + } + + } + + + #endregion + #region CanConfigPro /// @@ -163,7 +199,8 @@ namespace CapMachine.Wpf.ViewModels //CAN配置集合数据 canLinConfigPros = FreeSql.Select().Where(a => a.CANLINInfo == CANLIN.CANFD) .Include(a => a.CANFdConfigExd) - .IncludeMany(a => a.CanLinConfigContents) + .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule) + //.IncludeMany(a => a.CanLinConfigContents) .ToList(); ListCanLinConfigPro = new ObservableCollection(canLinConfigPros); @@ -197,6 +234,7 @@ namespace CapMachine.Wpf.ViewModels MsgName = item.MsgFrameName, SignalName = item.SignalName, SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0, + LogicRuleDto = Mapper.Map(item.LogicRule), }); //CanFdDriveService.CmdData.Add(new CanCmdData() //{ @@ -535,7 +573,7 @@ namespace CapMachine.Wpf.ViewModels //CANConfigExdDto 数据 SelectedCANConfigExdDto = Mapper.Map(SelectCanLinConfigPro!.CANFdConfigExd); - if (SelectedCANConfigExdDto!=null) + if (SelectedCANConfigExdDto != null) { //更新波特率等配置信息 CanFdDriveService.ToomossCanFDDrive.UpdateConfig((uint)SelectedCANConfigExdDto.ArbBaudRate, @@ -557,6 +595,7 @@ namespace CapMachine.Wpf.ViewModels MsgName = item.MsgFrameName, SignalName = item.SignalName, SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0, + LogicRuleDto = Mapper.Map(item.LogicRule), }); //CanFdDriveService.CmdData.Add(new CanCmdData() @@ -1084,6 +1123,15 @@ namespace CapMachine.Wpf.ViewModels set { _ReadNameCbxItems = value; RaisePropertyChanged(); } } + private ObservableCollection _WriteRuleCbxItems; + /// + /// 写入的规格集合 + /// + public ObservableCollection WriteRuleCbxItems + { + get { return _WriteRuleCbxItems; } + set { _WriteRuleCbxItems = value; RaisePropertyChanged(); } + } //private string _SelectedWriteName; ///// @@ -1199,6 +1247,7 @@ namespace CapMachine.Wpf.ViewModels //直接修改 FreeSql.Update(item.Id) .Set(a => a.Name, item.Name) + .Set(a => a.LogicRuleId, item.LogicRuleId) .Set(a => a.DefautValue, item.DefautValue) .ExecuteAffrows(); //ListWriteCanLinRWConfigDto.Remove(SelectedWriteCanLinRWConfigDto); diff --git a/CapMachine.Wpf/ViewModels/DialogLogicRuleViewModel.cs b/CapMachine.Wpf/ViewModels/DialogLogicRuleViewModel.cs new file mode 100644 index 0000000..52add83 --- /dev/null +++ b/CapMachine.Wpf/ViewModels/DialogLogicRuleViewModel.cs @@ -0,0 +1,252 @@ +using AutoMapper; +using CapMachine.Core; +using CapMachine.Model; +using CapMachine.Wpf.Dtos; +using CapMachine.Wpf.Services; +using Masuit.Tools; +using Prism.Commands; +using Prism.Services.Dialogs; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace CapMachine.Wpf.ViewModels +{ + /// + /// 逻辑规则配置的弹窗 + /// + public class DialogLogicRuleViewModel : DialogViewModel + { + public DialogLogicRuleViewModel(IFreeSql freeSql, IMapper mapper, LogicRuleService logicRuleService) + { + Title = "逻辑规则创建"; + + FreeSql = freeSql; + Mapper = mapper; + LogicRuleService = logicRuleService; + + //var Data = Mapper.Map>(LogicRuleService.LogicRuleDtos); + + ListLogicRuleDto = LogicRuleService.LogicRuleDtos; + + } + public IFreeSql FreeSql { get; } + public IMapper Mapper { get; } + public LogicRuleService LogicRuleService { get; } + + private ObservableCollection _ListLogicRuleDto; + /// + /// 数据集合 + /// + public ObservableCollection ListLogicRuleDto + { + get { return _ListLogicRuleDto; } + set { _ListLogicRuleDto = value; RaisePropertyChanged(); } + } + + private LogicRuleDto _selectedRule = new LogicRuleDto(); + /// + /// 当前选中的规则 + /// + public LogicRuleDto SelectedRule + { + get { return _selectedRule; } + set { _selectedRule = value; RaisePropertyChanged(); } + } + + /// + /// 选中更改之前的LogicRuleDto + /// + public LogicRuleDto SelectedRuleOld { get; set; } + + private DelegateCommand _GridSelectionChangedCmd; + /// + /// 选中行数据命令 + /// + public DelegateCommand GridSelectionChangedCmd + { + set + { + _GridSelectionChangedCmd = value; + } + get + { + if (_GridSelectionChangedCmd == null) + { + _GridSelectionChangedCmd = new DelegateCommand((par) => GridSelectionChangedCmdMethod(par)); + } + return _GridSelectionChangedCmd; + } + } + private void GridSelectionChangedCmdMethod(object par) + { + var selectedItem = par as LogicRuleDto; + if (selectedItem != null) + { + //防止需要未更改之前的数据 + SelectedRuleOld = selectedItem; + //先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件 + SelectedRule = selectedItem.DeepClone(); + } + + ////选中的行数据 + + } + + /// + /// 是否编辑 + /// + private bool IsRuleEdit { get; set; } = false; + + private DelegateCommand _RuleCmd; + /// + /// 选中行数据命令 + /// + public DelegateCommand RuleCmd + { + set + { + _RuleCmd = value; + } + get + { + if (_RuleCmd == null) + { + _RuleCmd = new DelegateCommand((par) => RuleCmdMethod(par)); + } + return _RuleCmd; + } + } + private void RuleCmdMethod(string par) + { + + IsRuleEdit = true; + //先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件 + switch (par) + { + case "Create": + //SelectedRule + LogicRuleService.AddRule(Mapper.Map(SelectedRule)); + break; + case "Update": + if (SelectedRule == null) + { + MessageBox.Show("选中后再操作数据"); + return; + } + LogicRuleService.UpdateRule(Mapper.Map(SelectedRuleOld), Mapper.Map(SelectedRule)); + break; + case "Delete": + if (SelectedRule == null) + { + MessageBox.Show("选中后再操作数据"); + return; + } + LogicRuleService.DeleteRule(SelectedRule.Name); + break; + default: + break; + } + ////选中的行数据 + + } + + #region 基础弹窗配置 + + + + private string name; + /// + /// 名称 + /// + public string Name + { + get { return name; } + set { name = value; RaisePropertyChanged(); } + } + + + + private DelegateCommand saveCmd; + /// + /// 保存命令 + /// + public DelegateCommand SaveCmd + { + set + { + saveCmd = value; + } + get + { + if (saveCmd == null) + { + saveCmd = new DelegateCommand(() => SaveCmdMethod()); + } + return saveCmd; + } + } + + /// + /// 保存命令方法 + /// + /// + private void SaveCmdMethod() + { + DialogParameters pars = new DialogParameters + { + { "IsRuleEdit", IsRuleEdit } + }; + + RaiseRequestClose(new DialogResult(ButtonResult.OK, pars)); + } + + private DelegateCommand cancelCmd; + /// + /// 保存命令 + /// + public DelegateCommand CancelCmd + { + set + { + cancelCmd = value; + } + get + { + if (cancelCmd == null) + { + cancelCmd = new DelegateCommand(() => CancelCmdMethod()); + } + return cancelCmd; + } + } + + + /// + /// 取消命令方法 + /// + /// + private void CancelCmdMethod() + { + RaiseRequestClose(new DialogResult(ButtonResult.Cancel)); + } + + /// + /// 窗口打开时的传递的参数 + /// + /// + public override void OnDialogOpened(IDialogParameters parameters) + { + Name = parameters.GetValue("Name"); + IsRuleEdit = false; + } + + + + #endregion + } +} diff --git a/CapMachine.Wpf/Views/CANFDConfigView.xaml b/CapMachine.Wpf/Views/CANFDConfigView.xaml index 86683c4..28032a4 100644 --- a/CapMachine.Wpf/Views/CANFDConfigView.xaml +++ b/CapMachine.Wpf/Views/CANFDConfigView.xaml @@ -779,6 +779,18 @@ + + + + + + + + diff --git a/CapMachine.Wpf/Views/DialogLogicRuleView.xaml b/CapMachine.Wpf/Views/DialogLogicRuleView.xaml new file mode 100644 index 0000000..86fced7 --- /dev/null +++ b/CapMachine.Wpf/Views/DialogLogicRuleView.xaml @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +