Files
DMS/DMS.Application/Services/Processors/ValueConvertProcessor.cs
David P.G cdfb906112 feat(处理器): 增强变量处理链并实现批量更新
- 新增 UpdateDbVariableProcessor 处理器,通过队列和定时器实现数据库的批量更新,以降低负载。
  - 重构 ValueConvertProcessor 处理器,使其能够解析 ConversionFormula 公式,计算出最终的 DisplayValue。
  - 扩展 IVariableRepository 仓储接口,添加 UpdateBatchAsync 方法,并使用SqlSugar实现高效的批量更新。
  - 优化 VariableContext 模型,将 NewValue 类型统一为 string,简化了数据流并提升了类型安全。
2025-10-02 17:35:35 +08:00

161 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Data;
using System.Globalization;
using DMS.Application.DTOs;
using DMS.Application.Interfaces;
using DMS.Application.Models;
using Microsoft.Extensions.Logging;
namespace DMS.Application.Services.Processors;
public class ValueConvertProcessor : IVariableProcessor
{
private readonly ILogger<ValueConvertProcessor> _logger;
public ValueConvertProcessor(ILogger<ValueConvertProcessor> logger)
{
_logger = logger;
}
public Task ProcessAsync(VariableContext context)
{
var oldValue = context.Data.DataValue;
// 步骤 1: 将原始值转换为 DataValue 和 NumericValue
ConvertS7ValueToStringAndNumeric(context.Data, context.NewValue);
// 步骤 2: 根据公式计算 DisplayValue
CalculateDisplayValue(context.Data);
context.Data.UpdatedAt = DateTime.Now;
// 如果值没有变化则中断处理链
if (context.Data.DataValue == oldValue)
{
context.IsHandled = true;
}
return Task.CompletedTask;
}
/// <summary>
/// 根据转换公式计算用于UI显示的DisplayValue
/// </summary>
/// <param name="variable">需要处理的变量DTO</param>
private void CalculateDisplayValue(VariableDto variable)
{
// 默认情况下,显示值等于原始数据值
variable.DisplayValue = variable.DataValue;
// 如果没有转换公式,则直接返回
if (string.IsNullOrWhiteSpace(variable.ConversionFormula))
{
return;
}
try
{
// 将公式中的 'x' 替换为实际的数值
// 使用 InvariantCulture 确保小数点是 '.'
string expression = variable.ConversionFormula.ToLowerInvariant()
.Replace("x", variable.NumericValue.ToString(CultureInfo.InvariantCulture));
// 使用 DataTable.Compute 来安全地计算表达式
var result = new DataTable().Compute(expression, null);
// 将计算结果格式化后赋给 DisplayValue
if (result is double || result is decimal || result is float)
{
variable.DisplayValue = string.Format("{0:F2}", result); // 默认格式化为两位小数,可根据需要调整
}
else
{
variable.DisplayValue = result.ToString();
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"为变量 {variable.Name} (ID: {variable.Id}) 计算DisplayValue时出错。公式: '{variable.ConversionFormula}'");
// 如果计算出错DisplayValue 将保持为原始的 DataValue保证程序健壮性
}
}
/// <summary>
/// 将从 S7 读取的对象值转换为字符串表示和数值表示
/// </summary>
/// <param name="variable">关联的变量 DTO</param>
/// <param name="value">从 S7 读取的原始对象值</param>
private void ConvertS7ValueToStringAndNumeric(VariableDto variable, object value)
{
if (value == null)
return;
string directConversion = null;
double numericValue = 0.0;
switch (value)
{
case double d:
directConversion = d.ToString("G17", CultureInfo.InvariantCulture);
numericValue = d;
break;
case float f:
directConversion = f.ToString("G9", CultureInfo.InvariantCulture);
numericValue = f;
break;
case int i:
directConversion = i.ToString(CultureInfo.InvariantCulture);
numericValue = i;
break;
case uint ui:
directConversion = ui.ToString(CultureInfo.InvariantCulture);
numericValue = ui;
break;
case short s:
directConversion = s.ToString(CultureInfo.InvariantCulture);
numericValue = s;
break;
case ushort us:
directConversion = us.ToString(CultureInfo.InvariantCulture);
numericValue = us;
break;
case byte b:
directConversion = b.ToString(CultureInfo.InvariantCulture);
numericValue = b;
break;
case sbyte sb:
directConversion = sb.ToString(CultureInfo.InvariantCulture);
numericValue = sb;
break;
case long l:
directConversion = l.ToString(CultureInfo.InvariantCulture);
numericValue = l;
break;
case ulong ul:
directConversion = ul.ToString(CultureInfo.InvariantCulture);
numericValue = ul;
break;
case bool boolValue:
directConversion = boolValue.ToString().ToLowerInvariant();
numericValue = boolValue ? 1.0 : 0.0;
break;
case string str:
directConversion = str;
if (double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedFromStr))
{
numericValue = parsedFromStr;
}
break;
default:
_logger.LogWarning($"变量 {variable.Name} 读取到未预期的数据类型: {value.GetType().Name}, 值: {value}");
directConversion = value.ToString() ?? string.Empty;
if (double.TryParse(directConversion, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedFromObj))
{
numericValue = parsedFromObj;
}
break;
}
variable.DataValue = directConversion ?? value.ToString() ?? string.Empty;
variable.NumericValue = numericValue;
}
}