diff --git a/.windsurfrules b/.windsurfrules new file mode 100644 index 0000000..aca25b0 --- /dev/null +++ b/.windsurfrules @@ -0,0 +1,9 @@ +我是一个 CSharp 软件开发者,我在开发一个压缩机耐久性能台的软件系统,主要功能如下: +# 读取PLC的数据,PLC是西门子的S200 +# 通过DBC配置CAN,通过Ldf配置LIN通信 +# 通过配置程序步骤,能逐步的下载步骤信息到PLC中逐步的执行程序,步骤程序中有SV(设置值),下载的速度数据是下载到压缩机中 +# 获取所有的数据,包括PLC的数据和压缩机的数据,然后能绘制曲线 +# 能对获取的数据进行数据记录,保存到文件中,记录的值是SV数据 +# 能记录日志信息 +# 用中文回复我 +# 请延续我的编码框架 \ No newline at end of file diff --git a/CapMachine.Model/CANLIN/CanLinRWConfig.cs b/CapMachine.Model/CANLIN/CanLinRWConfig.cs index ca6e539..39ed93c 100644 --- a/CapMachine.Model/CANLIN/CanLinRWConfig.cs +++ b/CapMachine.Model/CANLIN/CanLinRWConfig.cs @@ -10,7 +10,7 @@ namespace CapMachine.Model.CANLIN /// /// CAN和LIN的配置数据内容 /// - [Table(Name = "CanLinConfigContent")] + [Table(Name = "CanLinRWConfig")] public class CanLinRWConfig { /// @@ -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/CapMachine.Model.csproj b/CapMachine.Model/CapMachine.Model.csproj index eeb5253..b05dcd5 100644 --- a/CapMachine.Model/CapMachine.Model.csproj +++ b/CapMachine.Model/CapMachine.Model.csproj @@ -6,7 +6,7 @@ enable - + diff --git a/CapMachine.Model/LogicRule.cs b/CapMachine.Model/LogicRule.cs new file mode 100644 index 0000000..b25c84c --- /dev/null +++ b/CapMachine.Model/LogicRule.cs @@ -0,0 +1,58 @@ +using CapMachine.Model.CANLIN; +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +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 513ba26..f917868 100644 --- a/CapMachine.Wpf/App.xaml.cs +++ b/CapMachine.Wpf/App.xaml.cs @@ -1,4 +1,4 @@ -using AutoMapper; +using AutoMapper; using CapMachine.Core; using CapMachine.Core.IService; using CapMachine.Wpf.MapperProfile; @@ -94,7 +94,7 @@ namespace CapMachine.Wpf try { var MachineCode = SoftAuthorizeHelper.GetMachineCode(); - SoftAuthorizeHelper.WriteMachineCodeToFile(MachineCode,""); + SoftAuthorizeHelper.WriteMachineCodeToFile(MachineCode, ""); var PublicKey = SoftAuthorizeHelper.GetPublicKeyDataByFilePath(""); var Lience = SoftAuthorizeHelper.GetLienceDataByFilePath(""); var IsOK = SoftAuthorizeHelper.CheckLience(MachineCode, PublicKey, Lience); @@ -129,6 +129,7 @@ namespace CapMachine.Wpf //containerRegistry.RegisterSingleton(); + containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); ////注册设备服务 @@ -143,6 +144,7 @@ namespace CapMachine.Wpf containerRegistry.RegisterSingleton(); + containerRegistry.RegisterSingleton(); string strsqllite = System.AppDomain.CurrentDomain.BaseDirectory + @"Db\CapMachine.db"; @@ -201,8 +203,10 @@ namespace CapMachine.Wpf containerRegistry.RegisterDialog(); containerRegistry.RegisterDialog(); containerRegistry.RegisterDialog(); + containerRegistry.RegisterDialog(); containerRegistry.RegisterDialog(); + //注册AutoMapper diff --git a/CapMachine.Wpf/CapMachine.Wpf.csproj b/CapMachine.Wpf/CapMachine.Wpf.csproj index 9362185..c175f67 100644 --- a/CapMachine.Wpf/CapMachine.Wpf.csproj +++ b/CapMachine.Wpf/CapMachine.Wpf.csproj @@ -664,12 +664,13 @@ + - - - - - + + + + + diff --git a/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs b/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs index 034b598..cb8acac 100644 --- a/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs +++ b/CapMachine.Wpf/Dtos/CanLinRWConfigDto.cs @@ -1,4 +1,5 @@ -using CapMachine.Model.CANLIN; +using CapMachine.Model; +using CapMachine.Model.CANLIN; using Prism.Mvvm; using System; using System.Collections.Generic; @@ -70,7 +71,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..1e324d6 --- /dev/null +++ b/CapMachine.Wpf/Dtos/LogicRuleDto.cs @@ -0,0 +1,75 @@ +using CapMachine.Model.CANLIN; +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/CanLinRWConfigProfile.cs b/CapMachine.Wpf/MapperProfile/CanLinRWConfigProfile.cs index cc52ea6..b7902c8 100644 --- a/CapMachine.Wpf/MapperProfile/CanLinRWConfigProfile.cs +++ b/CapMachine.Wpf/MapperProfile/CanLinRWConfigProfile.cs @@ -14,7 +14,9 @@ namespace CapMachine.Wpf.MapperProfile { public CanLinRWConfigProfile() { - CreateMap().ReverseMap(); + CreateMap() + .ForMember(dest => dest.LogicRuleDto, opt => opt.MapFrom(src => src.LogicRule)) + .ReverseMap(); } } } diff --git a/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs b/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs new file mode 100644 index 0000000..e6c7e39 --- /dev/null +++ b/CapMachine.Wpf/MapperProfile/LogicRuleProfile.cs @@ -0,0 +1,20 @@ +using AutoMapper; +using CapMachine.Model; +using CapMachine.Wpf.Dtos; +using CapMachine.Wpf.Models; +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/Services/CanDriveService.cs b/CapMachine.Wpf/Services/CanDriveService.cs index 42fd28c..7f31f3a 100644 --- a/CapMachine.Wpf/Services/CanDriveService.cs +++ b/CapMachine.Wpf/Services/CanDriveService.cs @@ -1,4 +1,4 @@ -using CapMachine.Model.CANLIN; +using CapMachine.Model.CANLIN; using CapMachine.Wpf.CanDrive; using ImTools; using Prism.Ioc; @@ -195,7 +195,7 @@ namespace CapMachine.Wpf.Services { if (ToomossCanDrive.OpenState) { - if (ToomossCanDrive.IsCycleSend == false) + if (ToomossCanDrive.IsCycleSend == false)//要防止多次启动导致的问题,来回转换 { if (CmdData.Count > 0) { diff --git a/CapMachine.Wpf/Services/ComActionService.cs b/CapMachine.Wpf/Services/ComActionService.cs index 21fb180..69e51b8 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 { @@ -22,6 +23,7 @@ namespace CapMachine.Wpf.Services public DataRecordService DataRecordService { get; } public SysRunService SysRunServer { get; } public PPCService PPCService { get; } + public ProRuntimeService ProRuntimeService { get; } public CanDriveService CanDriveService { get; } public LinDriveService LinDriveService { get; } public MachineRtDataService MachineRtDataService { get; } @@ -29,7 +31,7 @@ namespace CapMachine.Wpf.Services public ComActionService(ConfigService configService, IEventAggregator eventAggregator, - DataRecordService dataRecordService, SysRunService sysRunService, PPCService pPCService, CanDriveService canDriveService, LinDriveService linDriveService, + DataRecordService dataRecordService, SysRunService sysRunService, PPCService pPCService, ProRuntimeService proRuntimeService, CanDriveService canDriveService, LinDriveService linDriveService, MachineRtDataService machineRtDataService, IDialogService dialogService) { ConfigService = configService; @@ -38,6 +40,7 @@ namespace CapMachine.Wpf.Services DataRecordService = dataRecordService; SysRunServer = sysRunService; PPCService = pPCService; + ProRuntimeService = proRuntimeService; CanDriveService = canDriveService; LinDriveService = linDriveService; MachineRtDataService = machineRtDataService; @@ -61,6 +64,14 @@ namespace CapMachine.Wpf.Services case "过热度/过冷度配置": ShowSuperHeatCool(msg.Par); break; + case "规则转换": + if (ProRuntimeService.MachineRunState1.IsRunState) + { + MessageBox.Show("请不要在运行时编辑规则转换,此时更改可能导致运行出错,请停止后再编辑"); + return; + } + ShowLogicRule(msg.Par); + break; default: break; } @@ -93,6 +104,29 @@ namespace CapMachine.Wpf.Services } + /// + /// 过热度和过冷度配置弹窗 + /// + private void ShowLogicRule(object par) + { + //弹窗 + DialogService.ShowDialog("DialogLogicRuleView", new DialogParameters() { { "Name", par } }, (par) => + { + if (par.Result == ButtonResult.OK) + { + //保存配置信息 + //PPCService.SaveSuperHeatCoolConfig(); + + + } + else if (par.Result == ButtonResult.Cancel) + { + //取消 + + } + + }); + } diff --git a/CapMachine.Wpf/Services/LinDriveService.cs b/CapMachine.Wpf/Services/LinDriveService.cs index 1763f4b..6363025 100644 --- a/CapMachine.Wpf/Services/LinDriveService.cs +++ b/CapMachine.Wpf/Services/LinDriveService.cs @@ -1,4 +1,4 @@ -using CapMachine.Model.CANLIN; +using CapMachine.Model.CANLIN; using CapMachine.Wpf.LinDrive; using ImTools; using Prism.Ioc; diff --git a/CapMachine.Wpf/Services/LogicRuleService.cs b/CapMachine.Wpf/Services/LogicRuleService.cs new file mode 100644 index 0000000..c46f952 --- /dev/null +++ b/CapMachine.Wpf/Services/LogicRuleService.cs @@ -0,0 +1,670 @@ +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(); + //.Reference(typeof(Math)) // 引用Math类 + // //.SetVariable("Math", typeof(Math)) + //.SetVariable("value", 0.2); + + 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 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.TryRemove(updatedDto.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; + } + + /// + /// 应用逻辑转换 - 主要使用方法 + /// + /// 输入值 + /// 规则名称 + /// 转换后的输出值 + public double ApplyLogic(double value, string ruleName) + { + var rule = GetRuleByName(ruleName); + + return ApplyExpression(value, rule); + } + + /// + /// 应用逻辑转换(基于参数类型自动选择规则) + /// + /// 输入值 + /// 参数类型 + /// 转换后的输出值 + public double ApplyLogicByType(double value, string parameterType) + { + var rules = GetRulesByParameterType(parameterType).ToList(); + if (rules.Count == 0) + { + LogService.Warn($"未找到适用于 {parameterType} 的转换规则,将返回原始值"); + return value; + } + + // 如果存在多个规则,取第一个 + var rule = rules.First(); + + return ApplyExpression(value, 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); // 只定义参数类型,不传值 + + // 存入缓存 + _expressionCache[rule.Name] = lambda; + } + 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 ApplyExpressionNoCache(double value, LogicRuleDto rule) + { + try + { + + CurInterpreter.SetVariable("value", value); + var lambda = CurInterpreter.Parse(rule.Expression); + return (double)lambda.Invoke(); + + //// 创建全新的解释器实例 + //var localInterpreter = new Interpreter() + // .Reference(typeof(Math)) + // .SetVariable("Math", typeof(Math)); + + //// 直接设置变量值而不是使用参数 + //localInterpreter.SetVariable("value", value); + //// 解析并执行 + //var result = localInterpreter.Eval(rule.Expression); + //Console.WriteLine($"直接执行: 输入={value}, 表达式={rule.Expression}, 结果={result}"); + //return result; + } + catch (Exception ex) + { + LogService.Error($"直接执行表达式失败: {ex.Message}"); + return value; + } + } + + /// + /// 批量应用逻辑转换 (高性能版本) + /// + /// 原始值字典(键为参数名称,值为原始值) + /// 转换后的值字典 + public Dictionary ApplyBatchLogic(Dictionary values) + { + // 为了性能,预分配容量 + var result = new Dictionary(values.Count); + + // 缓存参数类型到规则的映射,避免重复查询 + var cachedRulesByType = new Dictionary(); + + foreach (var entry in values) + { + var paramName = entry.Key; + var origValue = entry.Value; + + try + { + // 获取参数类型 + var paramType = DetermineParameterType(paramName); + + // 尝试从缓存获取规则 + if (!cachedRulesByType.TryGetValue(paramType, out var rule)) + { + var rules = GetRulesByParameterType(paramType).ToList(); + if (rules.Count > 0) + { + rule = rules.First(); + cachedRulesByType[paramType] = rule; // 添加到缓存 + } + } + + // 如果找到规则,应用转换 + if (rule != null) + { + var convertedValue = ApplyExpression(origValue, rule); + result.Add(paramName, convertedValue); + } + else + { + result.Add(paramName, origValue); // 没有规则时使用原始值 + } + } + catch (Exception ex) + { + LogService.Error($"处理参数 {paramName} 失败: {ex.Message}"); + result.Add(paramName, origValue); // 出错时使用原始值 + } + } + + return result; + } + + /// + /// 从参数名称确定参数类型 + /// + /// 参数名称 + /// 参数类型 + private string DetermineParameterType(string paramName) + { + // 根据参数名称确定类型的逻辑 + // 这里使用简单的名称匹配,实际项目中可能需要更复杂的映射 + if (paramName.Contains("速度") || paramName.Contains("转速")) + return "转速"; + else if (paramName.Contains("功率") || paramName.Contains("pw") || paramName.Contains("power")) + return "功率"; + else if (paramName.Contains("温度") || paramName.Contains("temp")) + return "温度"; + else if (paramName.Contains("压力") || paramName.Contains("press")) + return "压力"; + + // 默认类型 + return "通用"; + } + } +} diff --git a/CapMachine.Wpf/Services/MachineRtDataService.cs b/CapMachine.Wpf/Services/MachineRtDataService.cs index 88ab62a..f72b880 100644 --- a/CapMachine.Wpf/Services/MachineRtDataService.cs +++ b/CapMachine.Wpf/Services/MachineRtDataService.cs @@ -40,6 +40,7 @@ namespace CapMachine.Wpf.Services private IEventAggregator _EventAggregator { get; set; } public AlarmService AlarmService { get; } public ConfigService ConfigService { get; } + public LogicRuleService LogicRuleService { get; } public CanDriveService CanDriveService { get; } public LinDriveService LinDriveService { get; } public SysRunService SysRunService { get; } @@ -133,7 +134,7 @@ namespace CapMachine.Wpf.Services /// 实例化函数 /// /// - public MachineRtDataService(IEventAggregator eventAggregator, AlarmService alarmService, ConfigService configService, + public MachineRtDataService(IEventAggregator eventAggregator, AlarmService alarmService, ConfigService configService, LogicRuleService logicRuleService, CanDriveService canDriveService, LinDriveService linDriveService, SysRunService sysRunService)//, AlarmService alarmService { //ConcurrentDictionary keyValuePairs = new ConcurrentDictionary(); @@ -145,12 +146,12 @@ namespace CapMachine.Wpf.Services //stopwatch.Stop(); //停止Stopwatch //Console.WriteLine("Add Elapsed output runTime:{0}", stopwatch.Elapsed.ToString()); - //MelsecMcNetDrive. //事件服务 _EventAggregator = eventAggregator; AlarmService = alarmService; ConfigService = configService; + LogicRuleService = logicRuleService; CanDriveService = canDriveService; LinDriveService = linDriveService; SysRunService = sysRunService; @@ -2703,6 +2704,7 @@ namespace CapMachine.Wpf.Services //程序步骤的写入 ProRunStepWrite(); + Console.WriteLine($"结果:{LogicRuleService.ApplyExpression(random.NextDouble() * 100, LogicRuleService.LogicRuleDtos.FirstOrDefault())}"); //stopwatch.Stop(); //停止Stopwatch //Console.WriteLine("Add Elapsed output runTime:{0}", stopwatch.Elapsed.TotalSeconds.ToString()); diff --git a/CapMachine.Wpf/Services/NavigationMenuService.cs b/CapMachine.Wpf/Services/NavigationMenuService.cs index db0c4eb..f5a02bd 100644 --- a/CapMachine.Wpf/Services/NavigationMenuService.cs +++ b/CapMachine.Wpf/Services/NavigationMenuService.cs @@ -40,10 +40,10 @@ namespace CapMachine.Wpf.Services new NavigationItem("SuperHeatCool","过热度/过冷度配置","DialogSuperHeatCoolConfigView"), //new NavigationItem("Palette","过冷度",""), }), - //new NavigationItem("", "PID设置","",new ObservableCollection() - //{ - // new NavigationItem("Circle","转速PID",""), - //}), + new NavigationItem("", "规则设置","",new ObservableCollection() + { + new NavigationItem("Rule","规则转换","DialogLogicRuleView"), + }), //new NavigationItem("", "通信配置","",new ObservableCollection() //{ // new NavigationItem("Circle","CAN配置","CANConfigView"), diff --git a/CapMachine.Wpf/Services/ProRuntimeService.cs b/CapMachine.Wpf/Services/ProRuntimeService.cs index ff13549..af8a046 100644 --- a/CapMachine.Wpf/Services/ProRuntimeService.cs +++ b/CapMachine.Wpf/Services/ProRuntimeService.cs @@ -1,4 +1,4 @@ -using AutoMapper; +using AutoMapper; using CapMachine.Model; using CapMachine.Shared.Controls; using CapMachine.Wpf.ChannelModel; diff --git a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs index 5b2c0dd..885486b 100644 --- a/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs +++ b/CapMachine.Wpf/ViewModels/CANConfigViewModel.cs @@ -37,7 +37,7 @@ namespace CapMachine.Wpf.ViewModels { public CANConfigViewModel(IDialogService dialogService, IFreeSql freeSql, IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService, - ComActionService actionService, + ComActionService actionService, LogicRuleService logicRuleService, ConfigService configService, CanDriveService canDriveService, IMapper mapper, MachineRtDataService machineRtDataService) { @@ -47,6 +47,7 @@ namespace CapMachine.Wpf.ViewModels RegionManager = regionManager; SysRunService = sysRunService; ComActionService = actionService; + LogicRuleService = logicRuleService; ConfigService = configService; CanDriveService = canDriveService; Mapper = mapper; @@ -63,6 +64,7 @@ namespace CapMachine.Wpf.ViewModels new CbxItems(){ Key="Anti_Sleep",Text="Anti_Sleep"}, }; + ReadNameCbxItems = new ObservableCollection() { new CbxItems(){ Key="通讯转速",Text="通讯转速"}, @@ -72,8 +74,20 @@ namespace CapMachine.Wpf.ViewModels new CbxItems(){ Key="通讯功率",Text="通讯功率"}, new CbxItems(){ Key="通讯芯片温度",Text="通讯芯片温度"}, }; + InitLoadCanConfigPro(); + WriteRuleCbxItems = new ObservableCollection(); + //选择的读写规则 + foreach (var itemRule in LogicRuleService.LogicRuleDtos) + { + WriteRuleCbxItems.Add(new CbxItems() + { + Key = itemRule.Id.ToString(), + Text = itemRule.Name + }); + } + } @@ -85,6 +99,7 @@ namespace CapMachine.Wpf.ViewModels public IRegionManager RegionManager { get; } public SysRunService SysRunService { get; } public ComActionService ComActionService { get; } + public LogicRuleService LogicRuleService { get; } public ConfigService ConfigService { get; } public CanDriveService CanDriveService { get; } public IMapper Mapper { get; } @@ -107,7 +122,7 @@ namespace CapMachine.Wpf.ViewModels //CAN配置集合数据 canLinConfigPros = FreeSql.Select().Where(a => a.CANLINInfo == CANLIN.CAN) .Include(a => a.CANConfigExd) - .IncludeMany(a => a.CanLinConfigContents) + .IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule) .ToList(); ListCanLinConfigPro = new ObservableCollection(canLinConfigPros); @@ -116,7 +131,7 @@ namespace CapMachine.Wpf.ViewModels SelectCanLinConfigPro = canLinConfigPros.Where(a => a.Id == SelectCanLinConfigPro.Id).FirstOrDefault()!; //无数据就返回 if (SelectCanLinConfigPro == null) return; - + SelectedCANConfigExdDto = Mapper.Map(SelectCanLinConfigPro!.CANConfigExd); //配置信息 @@ -695,7 +710,7 @@ namespace CapMachine.Wpf.ViewModels } //(par as SelectionChangedEventArgs)!.AddedItems[0] == null - if ((par as SelectionChangedEventArgs)!.AddedItems.Count==0) + if ((par as SelectionChangedEventArgs)!.AddedItems.Count == 0) { return; } @@ -833,7 +848,7 @@ namespace CapMachine.Wpf.ViewModels //系统使用了CAN ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.Can; } - + //CAN DBC配置 有DBC配置的话,则直接加载DBC信息 if (!string.IsNullOrEmpty(SelectCanLinConfigPro.CANConfigExd.DbcPath)) { @@ -980,6 +995,16 @@ namespace CapMachine.Wpf.ViewModels set { _WriteNameCbxItems = value; RaisePropertyChanged(); } } + private ObservableCollection _WriteRuleCbxItems; + /// + /// 写入的规格集合 + /// + public ObservableCollection WriteRuleCbxItems + { + get { return _WriteRuleCbxItems; } + set { _WriteRuleCbxItems = value; RaisePropertyChanged(); } + } + private ObservableCollection _ReadNameCbxItems; /// @@ -991,6 +1016,15 @@ namespace CapMachine.Wpf.ViewModels set { _ReadNameCbxItems = value; RaisePropertyChanged(); } } + private ObservableCollection _ReadRuleCbxItems; + /// + /// 读取的规格集合 + /// + public ObservableCollection ReadRuleCbxItems + { + get { return _ReadRuleCbxItems; } + set { _ReadRuleCbxItems = value; RaisePropertyChanged(); } + } //private string _SelectedWriteName; ///// @@ -1106,6 +1140,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..bb820ae --- /dev/null +++ b/CapMachine.Wpf/ViewModels/DialogLogicRuleViewModel.cs @@ -0,0 +1,233 @@ +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; + /// + /// 当前选中的规则 + /// + public LogicRuleDto SelectedRule + { + get { return _selectedRule; } + set { _selectedRule = value; RaisePropertyChanged(); } + } + + 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) + { + //先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件 + SelectedRule = selectedItem.DeepClone(); + } + + ////选中的行数据 + + } + + + 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) + { + if (SelectedRule==null) + { + MessageBox.Show("选中后再操作数据"); + return; + } + //先判断是否是正确的集合数据,防止DataGrid的数据源刷新导致的触发事件 + switch (par) + { + case "Create": + //SelectedRule + LogicRuleService.AddRule(Mapper.Map(SelectedRule)); + break; + case "Update": + LogicRuleService.UpdateRule(Mapper.Map(SelectedRule)); + break; + case "Delete": + 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 + { + { "NewData", "" } + }; + + 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"); + } + + + + #endregion + } +} diff --git a/CapMachine.Wpf/ViewModels/MainViewModel.cs b/CapMachine.Wpf/ViewModels/MainViewModel.cs index 9b37bb1..e10ec67 100644 --- a/CapMachine.Wpf/ViewModels/MainViewModel.cs +++ b/CapMachine.Wpf/ViewModels/MainViewModel.cs @@ -6,6 +6,7 @@ using CapMachine.Wpf.Services; using Prism.Commands; using Prism.Events; using Prism.Regions; +using Prism.Services.Dialogs; using System.Windows.Input; namespace CapMachine.Wpf.ViewModels diff --git a/CapMachine.Wpf/Views/CANConfigView.xaml b/CapMachine.Wpf/Views/CANConfigView.xaml index 5d5b52e..adc557e 100644 --- a/CapMachine.Wpf/Views/CANConfigView.xaml +++ b/CapMachine.Wpf/Views/CANConfigView.xaml @@ -73,7 +73,7 @@ - + @@ -417,36 +417,10 @@ FontSize="18" Text="" /> + - - - - - - + + + + + + + + + + + + + + + + + + + + +