275 lines
9.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using ToolLibrary.LogHelper;
using YunDa.SOMS.Entities.DataMonitoring;
using YunDa.SOMS.Redis.Entities.DataMonitorCategory;
using YunDa.SOMS.Redis.Repositories;
using Jint;
namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection.Services
{
/// <summary>
/// 表达式计算服务实现
/// </summary>
public class ExpressionEvaluationService : IExpressionEvaluationService, ITransientDependency
{
private readonly IRedisRepository<TelemeteringModel, string> _telemeteringRedisRepository;
private readonly IRedisRepository<TelesignalisationModel, string> _telesignalisationRedisRepository;
private readonly IRepository<TelemeteringConfiguration, Guid> _telemeteringConfigRepository;
private readonly IRepository<TelesignalisationConfiguration, Guid> _telesignalisationConfigRepository;
// 变量代码正则表达式,匹配 {16385_0} 格式
private static readonly Regex VariableCodeRegex = new Regex(@"\{(\d+_\d+)\}", RegexOptions.Compiled);
public ExpressionEvaluationService(
IRedisRepository<TelemeteringModel, string> telemeteringRedisRepository,
IRedisRepository<TelesignalisationModel, string> telesignalisationRedisRepository,
IRepository<TelemeteringConfiguration, Guid> telemeteringConfigRepository,
IRepository<TelesignalisationConfiguration, Guid> telesignalisationConfigRepository)
{
_telemeteringRedisRepository = telemeteringRedisRepository;
_telesignalisationRedisRepository = telesignalisationRedisRepository;
_telemeteringConfigRepository = telemeteringConfigRepository;
_telesignalisationConfigRepository = telesignalisationConfigRepository;
}
/// <summary>
/// 计算表达式结果
/// </summary>
public async Task<ExpressionEvaluationResult> EvaluateExpressionAsync(
string expression,
int timeWindowSeconds = 60,
CancellationToken cancellationToken = default)
{
var stopwatch = Stopwatch.StartNew();
var result = new ExpressionEvaluationResult();
try
{
// 验证表达式
var validation = ValidateExpression(expression);
if (!validation.IsValid)
{
result.ErrorMessage = string.Join("; ", validation.Errors);
return result;
}
// 提取变量代码
var variableCodes = ExtractVariableCodes(expression);
result.EvaluationDetails.Add($"提取到 {variableCodes.Count} 个变量: {string.Join(", ", variableCodes)}");
// 获取变量值
var variableValues = await GetVariableValuesAsync(variableCodes, timeWindowSeconds, cancellationToken);
result.VariableValues = variableValues;
// 替换表达式中的变量
var evaluableExpression = ReplaceVariablesInExpression(expression, variableValues);
result.EvaluationDetails.Add($"替换后的表达式: {evaluableExpression}");
// 使用JavaScript引擎计算表达式
var engine = new Engine();
var jsResult = engine.Evaluate(evaluableExpression);
result.Result = Convert.ToBoolean(jsResult.ToObject());
result.IsSuccess = true;
result.EvaluationDetails.Add($"计算结果: {result.Result}");
}
catch (Exception ex)
{
result.ErrorMessage = $"表达式计算异常: {ex.Message}";
result.EvaluationDetails.Add($"异常详情: {ex}");
Log4Helper.Error($"表达式计算失败: {expression}", ex);
}
finally
{
stopwatch.Stop();
result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds;
}
return result;
}
/// <summary>
/// 验证表达式语法
/// </summary>
public ExpressionValidationResult ValidateExpression(string expression)
{
var result = new ExpressionValidationResult();
if (string.IsNullOrWhiteSpace(expression))
{
result.Errors.Add("表达式不能为空");
return result;
}
try
{
// 提取变量代码
result.VariableCodes = ExtractVariableCodes(expression);
if (!result.VariableCodes.Any())
{
result.Warnings.Add("表达式中未找到变量代码");
}
// 基本语法检查
if (!IsValidJavaScriptExpression(expression))
{
result.Errors.Add("表达式语法不正确");
}
result.IsValid = !result.Errors.Any();
}
catch (Exception ex)
{
result.Errors.Add($"表达式验证异常: {ex.Message}");
}
return result;
}
/// <summary>
/// 提取表达式中的变量代码
/// </summary>
public List<string> ExtractVariableCodes(string expression)
{
if (string.IsNullOrWhiteSpace(expression))
return new List<string>();
var matches = VariableCodeRegex.Matches(expression);
return matches.Cast<Match>()
.Select(m => m.Groups[1].Value)
.Distinct()
.ToList();
}
#region
/// <summary>
/// 获取变量值
/// </summary>
private async Task<Dictionary<string, object>> GetVariableValuesAsync(
List<string> variableCodes,
int timeWindowSeconds,
CancellationToken cancellationToken)
{
var result = new Dictionary<string, object>();
foreach (var code in variableCodes)
{
try
{
var value = await GetSingleVariableValueAsync(code, timeWindowSeconds, cancellationToken);
result[code] = value;
}
catch (Exception ex)
{
Log4Helper.Warning($"获取变量 {code} 的值失败: {ex.Message}");
result[code] = 0; // 默认值
}
}
return result;
}
/// <summary>
/// 获取单个变量的值
/// </summary>
private async Task<object> GetSingleVariableValueAsync(
string variableCode,
int timeWindowSeconds,
CancellationToken cancellationToken)
{
// 解析变量代码,格式为 "16385_0"
var parts = variableCode.Split('_');
if (parts.Length != 2 || !int.TryParse(parts[0], out var address) || !int.TryParse(parts[1], out var type))
{
throw new ArgumentException($"无效的变量代码格式: {variableCode}");
}
// type: 0=遥测, 1=遥信
if (type == 0)
{
// 遥测数据
var telemetryConfig = await _telemeteringConfigRepository.GetAll()
.FirstOrDefaultAsync(x => x.DispatcherAddress == address, cancellationToken);
if (telemetryConfig != null)
{
var telemetryData = await _telemeteringRedisRepository.HashSetGetAsync(
nameof(TelemeteringModel), telemetryConfig.Id.ToString());
return telemetryData?.Value ?? 0m;
}
}
else if (type == 1)
{
// 遥信数据
var telesignalConfig = await _telesignalisationConfigRepository.GetAll()
.FirstOrDefaultAsync(x => x.DispatcherAddress == address, cancellationToken);
if (telesignalConfig != null)
{
var telesignalData = await _telesignalisationRedisRepository.HashSetGetAsync(
nameof(TelesignalisationModel), telesignalConfig.Id.ToString());
return telesignalData?.Status == true ? 1 : 0;
}
}
return 0; // 默认值
}
/// <summary>
/// 替换表达式中的变量
/// </summary>
private string ReplaceVariablesInExpression(string expression, Dictionary<string, object> variableValues)
{
var result = expression;
foreach (var kvp in variableValues)
{
var placeholder = $"{{{kvp.Key}}}";
var value = kvp.Value?.ToString() ?? "0";
result = result.Replace(placeholder, value);
}
return result;
}
/// <summary>
/// 检查是否为有效的JavaScript表达式
/// </summary>
private bool IsValidJavaScriptExpression(string expression)
{
try
{
// 创建一个临时的JavaScript引擎来验证语法
var engine = new Engine();
// 替换变量为测试值
var testExpression = VariableCodeRegex.Replace(expression, "1");
// 尝试解析表达式
engine.Evaluate(testExpression);
return true;
}
catch
{
return false;
}
}
#endregion
}
}