逻辑规则的初步增加工能:

1)规则的界面的增删改查
2)规则服务的初步测试,目前测试是OK的
This commit is contained in:
2025-04-21 17:10:11 +08:00
parent 5f85aed486
commit a7fc676b82
24 changed files with 1583 additions and 58 deletions

View File

@@ -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)
{

View File

@@ -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
}
/// <summary>
/// 过热度和过冷度配置弹窗
/// </summary>
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)
{
//取消
}
});
}

View File

@@ -1,4 +1,4 @@
using CapMachine.Model.CANLIN;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.LinDrive;
using ImTools;
using Prism.Ioc;

View File

@@ -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
{
/// <summary>
/// 逻辑服务 - 用于处理数据逻辑转换
/// </summary>
public class LogicRuleService : BindableBase
{
private readonly ILogService LogService;
private readonly IFreeSql FreeSql;
/// <summary>
/// 逻辑转换规则集合
/// </summary>
public ObservableCollection<LogicRuleDto> LogicRuleDtos { get; private set; }
/// <summary>
/// DynamicExpresso解释器
/// </summary>
private Interpreter CurInterpreter { get; set; }
public IMapper Mapper { get; }
/// <summary>
/// 规则表达式缓存(高性能访问)
/// Key: 规则名称, Value: 已编译的Lambda表达式
///private readonly ConcurrentDictionary<string, Func<double, double>> _expressionCache;
/// </summary>
private readonly ConcurrentDictionary<string, Lambda> _expressionCache;
///// <summary>
///// 创建包含指定值的参数数组
///// </summary>
//private Parameter[] CreateParameters(double value)
//{
// return new Parameter[]
// {
// new Parameter("value", typeof(double), value)
// };
//}
/// <summary>
/// 创建包含指定值的参数
/// </summary>
private Parameter CreateParameters(double value)
{
return new Parameter("value", typeof(double),value);
}
/// <summary>
/// 实例化函数
/// </summary>
public LogicRuleService(ILogService logService, IFreeSql freeSql, IMapper mapper)
{
LogService = logService;
FreeSql = freeSql;
Mapper = mapper;
// 初始化集合
LogicRuleDtos = new ObservableCollection<LogicRuleDto>();
_expressionCache = new ConcurrentDictionary<string, Lambda>();
// 初始化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}");
}
}
/// <summary>
/// 从数据库加载规则
/// </summary>
private void LoadRulesFromDatabase()
{
try
{
// 从数据库加载规则
var dbRules = FreeSql.Select<LogicRule>().OrderBy(a => a.Id).ToList();
if (dbRules != null && dbRules.Count > 0)
{
LogicRuleDtos.Clear();
_expressionCache.Clear(); // 清空表达式缓存
foreach (var rule in dbRules)
{
LogicRuleDtos.Add(Mapper.Map<LogicRuleDto>(rule));
}
// 预编译所有表达式
WarmUpExpressionCache();
//LogService.Info($"已从数据库加载并预编译 {dbRules.Count} 条逻辑规则");
}
else
{
LogService.Warn("数据库中没有逻辑规则");
}
}
catch (Exception ex)
{
LogService.Error($"从数据库加载逻辑规则失败: {ex.Message}");
throw; // 重新抛出异常以便调用者处理
}
}
#region LogicRule
/// <summary>
/// 添加新规则
/// </summary>
/// <param name="rule">规则对象</param>
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<LogicRuleDto>(resultInsert));
// 预编译并缓存表达式
CacheExpression(Mapper.Map<LogicRuleDto>(resultInsert));
}
else
{
MessageBox.Show("增加数据失败!");
return;
}
//LogService.Info($"添加新规则: {rule.Name}");
}
/// <summary>
/// 保存规格到数据库中
/// </summary>
/// <returns></returns>
public bool InsertRuleToDb(LogicRule rule, out LogicRule ResultInsert)
{
try
{
// 插入规则到数据库
var result = FreeSql.Insert<LogicRule>(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;
}
}
/// <summary>
/// 更新规则
/// </summary>
/// <param name="rule">规则对象</param>
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<LogicRuleDto>(rule));
}
else
{
// 在找到的位置插入
LogicRuleDtos.Insert(insertIndex - 1, Mapper.Map<LogicRuleDto>(rule));
}
_expressionCache.TryRemove(updatedDto.Name, out _);
CacheExpression(updatedDto);
}
}
//LogService.Info($"更新规则: {rule.Name}");
}
/// <summary>
/// 更新规格到数据库中
/// </summary>
/// <returns></returns>
public bool UpdateRuleToDb(LogicRule rule)
{
try
{
// 更新规则到数据库
var result = FreeSql.Update<LogicRule>()
.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;
}
}
/// <summary>
/// 删除规则
/// </summary>
/// <param name="ruleName">规则名称</param>
public void DeleteRule(string ruleName)
{
var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName);
if (rule == null)
{
MessageBox.Show("找不到删除的数据");
return;
}
var Count = FreeSql.Delete<LogicRule>().Where(r => r.Id == rule.Id).ExecuteAffrows();
if (Count > 0)
{
// 删除规则
LogicRuleDtos.Remove(rule);
// 从缓存中移除表达式
_expressionCache.TryRemove(ruleName, out _);
}
//LogService.Info($"删除规则: {ruleName}");
}
/// <summary>
/// 验证表达式是否有效
/// </summary>
/// <param name="expression">表达式字符串</param>
/// <returns>表达式是否有效</returns>
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
/// <summary>
/// 根据参数类型获取适用的规则
/// </summary>
/// <param name="parameterType">参数类型</param>
/// <returns>适用的规则列表</returns>
public IEnumerable<LogicRuleDto> GetRulesByParameterType(string parameterType)
{
return LogicRuleDtos.Where(r => r.ParameterType == parameterType);
}
/// <summary>
/// 获取指定名称的规则
/// </summary>
/// <param name="ruleName">规则名称</param>
/// <returns>规则对象</returns>
public LogicRuleDto GetRuleByName(string ruleName)
{
var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName);
if (rule == null)
{
throw new KeyNotFoundException($"找不到名为 {ruleName} 的规则");
}
return rule;
}
/// <summary>
/// 应用逻辑转换 - 主要使用方法
/// </summary>
/// <param name="value">输入值</param>
/// <param name="ruleName">规则名称</param>
/// <returns>转换后的输出值</returns>
public double ApplyLogic(double value, string ruleName)
{
var rule = GetRuleByName(ruleName);
return ApplyExpression(value, rule);
}
/// <summary>
/// 应用逻辑转换(基于参数类型自动选择规则)
/// </summary>
/// <param name="value">输入值</param>
/// <param name="parameterType">参数类型</param>
/// <returns>转换后的输出值</returns>
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);
}
/// <summary>
/// 将规则表达式预编译并缓存到字典中
/// </summary>
/// <param name="rule">要缓存的规则</param>
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}");
}
}
/// <summary>
/// 预热表达式缓存 - 预编译所有规则
/// </summary>
private void WarmUpExpressionCache()
{
foreach (var rule in LogicRuleDtos)
{
if (!_expressionCache.ContainsKey(rule.Name))
{
CacheExpression(rule);
}
}
LogService.Info($"已预编译 {_expressionCache.Count} 条规则表达式");
}
/// <summary>
/// 根据规则应用表达式(高性能版本)
/// </summary>
/// <param name="value">输入值</param>
/// <param name="rule">规则对象</param>
/// <returns>转换后的输出值</returns>
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<double, double> 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; // 出错时返回原始值
}
}
/// <summary>
/// 临时测试用
/// </summary>
/// <param name="value"></param>
/// <param name="rule"></param>
/// <returns></returns>
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<double>(rule.Expression);
//Console.WriteLine($"直接执行: 输入={value}, 表达式={rule.Expression}, 结果={result}");
//return result;
}
catch (Exception ex)
{
LogService.Error($"直接执行表达式失败: {ex.Message}");
return value;
}
}
/// <summary>
/// 批量应用逻辑转换 (高性能版本)
/// </summary>
/// <param name="values">原始值字典(键为参数名称,值为原始值)</param>
/// <returns>转换后的值字典</returns>
public Dictionary<string, double> ApplyBatchLogic(Dictionary<string, double> values)
{
// 为了性能,预分配容量
var result = new Dictionary<string, double>(values.Count);
// 缓存参数类型到规则的映射,避免重复查询
var cachedRulesByType = new Dictionary<string, LogicRuleDto>();
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;
}
/// <summary>
/// 从参数名称确定参数类型
/// </summary>
/// <param name="paramName">参数名称</param>
/// <returns>参数类型</returns>
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 "通用";
}
}
}

View File

@@ -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
/// 实例化函数
/// </summary>
/// <param name="eventAggregator"></param>
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<DateTime, RecordInfo> keyValuePairs = new ConcurrentDictionary<DateTime, RecordInfo>();
@@ -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());

View File

@@ -40,10 +40,10 @@ namespace CapMachine.Wpf.Services
new NavigationItem("SuperHeatCool","过热度/过冷度配置","DialogSuperHeatCoolConfigView"),
//new NavigationItem("Palette","过冷度",""),
}),
//new NavigationItem("", "PID设置","",new ObservableCollection<NavigationItem>()
//{
// new NavigationItem("Circle","转速PID",""),
//}),
new NavigationItem("", "规则设置","",new ObservableCollection<NavigationItem>()
{
new NavigationItem("Rule","规则转换","DialogLogicRuleView"),
}),
//new NavigationItem("", "通信配置","",new ObservableCollection<NavigationItem>()
//{
// new NavigationItem("Circle","CAN配置","CANConfigView"),

View File

@@ -1,4 +1,4 @@
using AutoMapper;
using AutoMapper;
using CapMachine.Model;
using CapMachine.Shared.Controls;
using CapMachine.Wpf.ChannelModel;