1 feat: 重构触发器设计,移除触发条件并添加名称字段
2
3 - 从Trigger、DbTriggerDefinition和TriggerItem类中移除了所有条件相关的属性(Condition, Threshold, LowerBound, UpperBound)
4 - 删除了ConditionType枚举,简化了触发器逻辑
5 - 为触发器添加了Name字段,在核心模型、数据库实体和视图模型中都添加了该属性
6 - 删除了TriggerDialog界面中的变量选择和搜索功能
7 - 从TriggerDialog界面中删除了触发条件相关的UI元素
8 - 更新了TriggerDialogViewModel,移除了条件相关的验证和业务逻辑
9 - 更新了TriggersViewModel,移除了条件的初始化设置
10 - 更新了AutoMapper配置文件,增加TriggerItem与Trigger之间的映射
11 - 在TriggerEvaluationService中移除了条件判断逻辑,现在激活的触发器会直接执行动作
12 - 更新了App.xaml,移除了对已删除枚举的引用
13 - 修改了保存验证逻辑,确保触发器名称不能为空
This commit is contained in:
@@ -49,7 +49,7 @@ namespace DMS.Application.Services.Management
|
||||
public async Task<Trigger> CreateTriggerAsync(Trigger triggerDto)
|
||||
{
|
||||
// 1. 验证 DTO (可以在应用层或领域层做)
|
||||
ValidateTriggerDto(triggerDto);
|
||||
// ValidateTriggerDto(triggerDto);
|
||||
|
||||
// 2. 转换 DTO 到实体
|
||||
var triggerEntity = _mapper.Map<Trigger>(triggerDto);
|
||||
@@ -150,23 +150,6 @@ namespace DMS.Application.Services.Management
|
||||
throw new ArgumentException("触发器必须至少关联一个变量。");
|
||||
|
||||
// 添加必要的验证逻辑
|
||||
switch (dto.Condition)
|
||||
{
|
||||
case ConditionType.GreaterThan:
|
||||
case ConditionType.LessThan:
|
||||
case ConditionType.EqualTo:
|
||||
case ConditionType.NotEqualTo:
|
||||
if (!dto.Threshold.HasValue)
|
||||
throw new ArgumentException($"{dto.Condition} requires Threshold.");
|
||||
break;
|
||||
case ConditionType.InRange:
|
||||
case ConditionType.OutOfRange:
|
||||
if (!dto.LowerBound.HasValue || !dto.UpperBound.HasValue)
|
||||
throw new ArgumentException($"{dto.Condition} requires LowerBound and UpperBound.");
|
||||
if (dto.LowerBound > dto.UpperBound)
|
||||
throw new ArgumentException("LowerBound must be less than or equal to UpperBound.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace DMS.Application.Services.Triggers.Impl
|
||||
switch (context.Trigger.Action)
|
||||
{
|
||||
case ActionType.SendEmail:
|
||||
await ExecuteSendEmail(context);
|
||||
// await ExecuteSendEmail(context);
|
||||
break;
|
||||
case ActionType.ActivateAlarm:
|
||||
_logger.LogWarning("Action 'ActivateAlarm' is not implemented yet.");
|
||||
@@ -61,72 +61,5 @@ namespace DMS.Application.Services.Triggers.Impl
|
||||
}
|
||||
}
|
||||
|
||||
#region 私有执行方法
|
||||
|
||||
private async Task ExecuteSendEmail(TriggerContext context)
|
||||
{
|
||||
if (_emailService == null)
|
||||
{
|
||||
_logger.LogWarning("Email service is not configured, skipping SendEmail action for trigger '{TriggerId}'.", context.Trigger.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
var config = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(context.Trigger.ActionConfigurationJson);
|
||||
if (config == null ||
|
||||
!config.TryGetValue("Recipients", out var recipientsElement) ||
|
||||
!config.TryGetValue("SubjectTemplate", out var subjectTemplateElement) ||
|
||||
!config.TryGetValue("BodyTemplate", out var bodyTemplateElement))
|
||||
{
|
||||
_logger.LogError("Invalid configuration for SendEmail action for trigger '{TriggerId}'.", context.Trigger.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
var recipients = recipientsElement.Deserialize<List<string>>();
|
||||
var subjectTemplate = subjectTemplateElement.GetString();
|
||||
var bodyTemplate = bodyTemplateElement.GetString();
|
||||
|
||||
if (recipients == null || string.IsNullOrEmpty(subjectTemplate) || string.IsNullOrEmpty(bodyTemplate))
|
||||
{
|
||||
_logger.LogError("Missing required fields in SendEmail configuration for trigger '{TriggerId}'.", context.Trigger.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Simple token replacement - in practice, use a templating engine like Scriban, RazorLight etc.
|
||||
// Note: This assumes context.Variable and context.CurrentValue have Name properties/values.
|
||||
// You might need to adjust the token names and values based on your actual Variable structure.
|
||||
var subject = subjectTemplate
|
||||
.Replace("{VariableName}", context.Variable?.Name ?? "Unknown")
|
||||
.Replace("{CurrentValue}", context.CurrentValue?.ToString() ?? "N/A")
|
||||
.Replace("{Threshold}", context.Trigger.Threshold?.ToString() ?? "N/A")
|
||||
.Replace("{LowerBound}", context.Trigger.LowerBound?.ToString() ?? "N/A")
|
||||
.Replace("{UpperBound}", context.Trigger.UpperBound?.ToString() ?? "N/A");
|
||||
|
||||
var body = bodyTemplate
|
||||
.Replace("{VariableName}", context.Variable?.Name ?? "Unknown")
|
||||
.Replace("{CurrentValue}", context.CurrentValue?.ToString() ?? "N/A")
|
||||
.Replace("{Threshold}", context.Trigger.Threshold?.ToString() ?? "N/A")
|
||||
.Replace("{LowerBound}", context.Trigger.LowerBound?.ToString() ?? "N/A")
|
||||
.Replace("{UpperBound}", context.Trigger.UpperBound?.ToString() ?? "N/A")
|
||||
.Replace("{Timestamp}", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
// await _emailService.SendEmailAsync(recipients, subject, body);
|
||||
}
|
||||
|
||||
private async Task ExecuteActivateAlarm(TriggerContext context)
|
||||
{
|
||||
var alarmId = $"trigger_{context.Trigger.Id}_{context.Variable.Id}";
|
||||
var message = $"Trigger '{context.Trigger.Description}' activated for variable '{context.Variable.Name}' with value '{context.CurrentValue}'.";
|
||||
// 假设 INotificationService 有 RaiseAlarmAsync 方法
|
||||
// await _notificationService.RaiseAlarmAsync(alarmId, message);
|
||||
}
|
||||
|
||||
private async Task ExecuteWriteToLog(TriggerContext context)
|
||||
{
|
||||
var message = $"Trigger '{context.Trigger.Description}' activated for variable '{context.Variable.Name}' with value '{context.CurrentValue}'.";
|
||||
// 假设 ILoggingService 有 LogTriggerAsync 方法
|
||||
// await _loggingService.LogTriggerAsync(message);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -109,31 +109,10 @@ namespace DMS.Application.Services.Triggers.Impl
|
||||
return false; // Cannot evaluate null
|
||||
}
|
||||
|
||||
// Attempt conversion from object to double - adjust parsing logic as needed for your data types
|
||||
if (!double.TryParse(currentValueObj.ToString(), out double currentValue))
|
||||
{
|
||||
_logger.LogWarning("Could not parse current value '{CurrentValue}' to double for trigger evaluation (trigger ID: {TriggerId}).", currentValueObj, trigger.Id);
|
||||
return false;
|
||||
}
|
||||
// 由于移除了条件,所有激活的触发器都会被触发
|
||||
_logger.LogInformation("Trigger activated for trigger ID: {TriggerId}", trigger.Id);
|
||||
|
||||
bool result = trigger.Condition switch
|
||||
{
|
||||
ConditionType.GreaterThan => currentValue > trigger.Threshold,
|
||||
ConditionType.LessThan => currentValue < trigger.Threshold,
|
||||
ConditionType.EqualTo => Math.Abs(currentValue - trigger.Threshold.GetValueOrDefault()) < double.Epsilon,
|
||||
ConditionType.NotEqualTo => Math.Abs(currentValue - trigger.Threshold.GetValueOrDefault()) >= double.Epsilon,
|
||||
ConditionType.InRange => currentValue >= trigger.LowerBound && currentValue <= trigger.UpperBound,
|
||||
ConditionType.OutOfRange => currentValue < trigger.LowerBound || currentValue > trigger.UpperBound,
|
||||
_ => false
|
||||
};
|
||||
|
||||
if(result)
|
||||
{
|
||||
_logger.LogInformation("Trigger condition met: Variable value {CurrentValue} satisfies {Condition} for trigger ID: {TriggerId}",
|
||||
currentValue, trigger.Condition, trigger.Id);
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,19 +3,6 @@ using System.Collections.Generic;
|
||||
|
||||
namespace DMS.Core.Models.Triggers
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器条件类型枚举
|
||||
/// </summary>
|
||||
public enum ConditionType
|
||||
{
|
||||
GreaterThan,
|
||||
LessThan,
|
||||
EqualTo,
|
||||
NotEqualTo,
|
||||
InRange, // 值在 LowerBound 和 UpperBound 之间 (包含边界)
|
||||
OutOfRange // 值低于 LowerBound 或高于 UpperBound
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发器动作类型枚举
|
||||
/// </summary>
|
||||
@@ -37,6 +24,11 @@ namespace DMS.Core.Models.Triggers
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 关联的变量列表
|
||||
/// </summary>
|
||||
@@ -47,28 +39,6 @@ namespace DMS.Core.Models.Triggers
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
// --- 条件部分 ---
|
||||
|
||||
/// <summary>
|
||||
/// 触发条件类型
|
||||
/// </summary>
|
||||
public ConditionType Condition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阈值 (用于 GreaterThan, LessThan, EqualTo, NotEqualTo)
|
||||
/// </summary>
|
||||
public double? Threshold { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下限 (用于 InRange, OutOfRange)
|
||||
/// </summary>
|
||||
public double? LowerBound { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上限 (用于 InRange, OutOfRange)
|
||||
/// </summary>
|
||||
public double? UpperBound { get; set; }
|
||||
|
||||
// --- 动作部分 ---
|
||||
|
||||
/// <summary>
|
||||
@@ -93,6 +63,7 @@ namespace DMS.Core.Models.Triggers
|
||||
/// </summary>
|
||||
public DateTime? LastTriggeredAt { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 触发器描述
|
||||
/// </summary>
|
||||
|
||||
@@ -18,37 +18,17 @@ public class DbTriggerDefinition
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器名称
|
||||
/// </summary>
|
||||
[SugarColumn(Length = 200, IsNullable = true)]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 触发器是否处于激活状态。
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
// --- 条件部分 ---
|
||||
|
||||
/// <summary>
|
||||
/// 触发条件类型。
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "varchar(20)", SqlParameterDbType = typeof(EnumToStringConvert))]
|
||||
public ConditionType Condition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阈值 (用于 GreaterThan, LessThan, EqualTo, NotEqualTo)。
|
||||
/// </summary>
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public double? Threshold { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下限 (用于 InRange, OutOfRange)。
|
||||
/// </summary>
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public double? LowerBound { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上限 (用于 InRange, OutOfRange)。
|
||||
/// </summary>
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public double? UpperBound { get; set; }
|
||||
|
||||
// --- 动作部分 ---
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -46,6 +46,7 @@ public class MappingProfile : Profile
|
||||
|
||||
// --- 触发器映射 ---
|
||||
CreateMap<DbTriggerDefinition, Trigger>()
|
||||
.ForMember(dest => dest.Variables, opt => opt.Ignore()) // 忽略Variables属性映射,因为可能需要特殊处理
|
||||
.ReverseMap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@
|
||||
<FontFamily x:Key="MdFontIcons">/Assets/Fonts/materialdesignicons-webfont.ttf#Material Design Icons</FontFamily>
|
||||
|
||||
<!-- Enum Values for ComboBoxes -->
|
||||
<ObjectDataProvider x:Key="ConditionTypeEnum" ObjectType="{x:Type sys:Enum}" MethodName="GetValues">
|
||||
<ObjectDataProvider.MethodParameters>
|
||||
<x:Type TypeName="triggers:ConditionType"/>
|
||||
</ObjectDataProvider.MethodParameters>
|
||||
</ObjectDataProvider>
|
||||
|
||||
<ObjectDataProvider x:Key="ActionTypeEnum" ObjectType="{x:Type sys:Enum}" MethodName="GetValues">
|
||||
<ObjectDataProvider.MethodParameters>
|
||||
<x:Type TypeName="triggers:ActionType"/>
|
||||
|
||||
@@ -16,6 +16,12 @@ namespace DMS.WPF.ItemViewModel
|
||||
[ObservableProperty]
|
||||
private int _id;
|
||||
|
||||
/// <summary>
|
||||
/// 触发器名称
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private string _name = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 触发器描述
|
||||
/// </summary>
|
||||
@@ -28,30 +34,6 @@ namespace DMS.WPF.ItemViewModel
|
||||
[ObservableProperty]
|
||||
private bool _isActive;
|
||||
|
||||
/// <summary>
|
||||
/// 触发条件类型
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private ConditionType _condition;
|
||||
|
||||
/// <summary>
|
||||
/// 阈值 (用于 GreaterThan, LessThan, EqualTo, NotEqualTo)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private double? _threshold;
|
||||
|
||||
/// <summary>
|
||||
/// 下限 (用于 InRange, OutOfRange)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private double? _lowerBound;
|
||||
|
||||
/// <summary>
|
||||
/// 上限 (用于 InRange, OutOfRange)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private double? _upperBound;
|
||||
|
||||
/// <summary>
|
||||
/// 动作类型
|
||||
/// </summary>
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace DMS.WPF.Profiles
|
||||
CreateMap<Variable, VariableItem>()
|
||||
.ReverseMap();
|
||||
CreateMap<NlogDto, NlogItem>().ReverseMap();
|
||||
|
||||
// 添加触发器相关映射
|
||||
CreateMap<TriggerItem, Core.Models.Triggers.Trigger>()
|
||||
.ForMember(dest => dest.Variables, opt => opt.Ignore()) // 忽略Variables属性,因为这个通常在业务逻辑中处理
|
||||
.ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,14 @@ namespace DMS.WPF.ViewModels.Dialogs
|
||||
/// </summary>
|
||||
public partial class TriggerDialogViewModel : DialogViewModelBase<TriggerItem?>
|
||||
{
|
||||
private readonly IVariableAppService _variableAppService; // To populate variable selection dropdown
|
||||
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IDataStorageService _dataStorageService;
|
||||
private readonly INotificationService _notificationService;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _searchText = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private TriggerItem _trigger = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private List<VariableItem> _availableVariables = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<VariableItem> _selectedVariables = new();
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<VariableItem> _filteredVariables = new();
|
||||
|
||||
// Properties for easier binding in XAML for SendEmail action config
|
||||
[ObservableProperty]
|
||||
private string _emailRecipients = "";
|
||||
@@ -50,78 +38,16 @@ namespace DMS.WPF.ViewModels.Dialogs
|
||||
private string _emailBodyTemplate = "";
|
||||
|
||||
public TriggerDialogViewModel(
|
||||
IVariableAppService variableAppService,
|
||||
IDialogService dialogService,
|
||||
IDataStorageService dataStorageService,
|
||||
INotificationService notificationService)
|
||||
{
|
||||
_variableAppService = variableAppService ?? throw new ArgumentNullException(nameof(variableAppService));
|
||||
_dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService));
|
||||
_dataStorageService = dataStorageService;
|
||||
_notificationService = notificationService ?? throw new ArgumentNullException(nameof(notificationService));
|
||||
}
|
||||
|
||||
partial void OnSearchTextChanged(string searchText)
|
||||
{
|
||||
UpdateFilteredVariables();
|
||||
}
|
||||
|
||||
private void UpdateFilteredVariables()
|
||||
{
|
||||
FilteredVariables.Clear();
|
||||
|
||||
// 如果没有搜索文本,显示所有可用变量
|
||||
if (string.IsNullOrEmpty(SearchText))
|
||||
{
|
||||
foreach (var variable in AvailableVariables)
|
||||
{
|
||||
// 只显示未被选中的变量
|
||||
if (!SelectedVariables.Contains(variable))
|
||||
{
|
||||
FilteredVariables.Add(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 根据搜索文本过滤变量
|
||||
foreach (var variable in AvailableVariables)
|
||||
{
|
||||
// 只显示未被选中的变量且名称包含搜索文本的变量
|
||||
if (!SelectedVariables.Contains(variable) &&
|
||||
variable.Name.Contains(SearchText, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
FilteredVariables.Add(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将变量添加到选中列表
|
||||
/// </summary>
|
||||
/// <param name="variable">要添加的变量</param>
|
||||
public void AddVariable(VariableItem variable)
|
||||
{
|
||||
if (!SelectedVariables.Contains(variable))
|
||||
{
|
||||
SelectedVariables.Add(variable);
|
||||
UpdateFilteredVariables();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从选中列表中移除变量
|
||||
/// </summary>
|
||||
/// <param name="variable">要移除的变量</param>
|
||||
public void RemoveVariable(VariableItem variable)
|
||||
{
|
||||
if (SelectedVariables.Contains(variable))
|
||||
{
|
||||
SelectedVariables.Remove(variable);
|
||||
UpdateFilteredVariables();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化视图模型(传入待编辑的触发器)
|
||||
@@ -134,25 +60,6 @@ namespace DMS.WPF.ViewModels.Dialogs
|
||||
Trigger = triggerItemViewModel;
|
||||
Title = Trigger.Id == default(int) ? "新建触发器" : "编辑触发器";
|
||||
PrimaryButText = "保存";
|
||||
|
||||
// Load available variables for selection dropdown
|
||||
await LoadVariablesAsync();
|
||||
|
||||
// Load selected variables
|
||||
if (Trigger.VariableIds != null && Trigger.VariableIds.Any())
|
||||
{
|
||||
foreach (var variableId in Trigger.VariableIds)
|
||||
{
|
||||
var variable = AvailableVariables.FirstOrDefault(v => v.Id == variableId);
|
||||
if (variable != null)
|
||||
{
|
||||
SelectedVariables.Add(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化过滤后的变量列表
|
||||
UpdateFilteredVariables();
|
||||
|
||||
// Parse action configuration if it's SendEmail
|
||||
if (Trigger.Action == ActionType.SendEmail && !string.IsNullOrEmpty(Trigger.ActionConfigurationJson))
|
||||
@@ -179,23 +86,7 @@ namespace DMS.WPF.ViewModels.Dialogs
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载所有可用的变量
|
||||
/// </summary>
|
||||
private async Task LoadVariablesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 使用数据存储服务中的变量列表
|
||||
AvailableVariables = new List<VariableItem>(_dataStorageService.Variables.Select(kvp => kvp.Value));
|
||||
UpdateFilteredVariables();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_notificationService.ShowError($"加载变量列表失败: {ex.Message}");
|
||||
AvailableVariables = new List<VariableItem>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 保存按钮点击命令
|
||||
@@ -203,10 +94,9 @@ namespace DMS.WPF.ViewModels.Dialogs
|
||||
[RelayCommand]
|
||||
private async Task SaveAsync()
|
||||
{
|
||||
// Basic validation
|
||||
if (SelectedVariables == null || !SelectedVariables.Any())
|
||||
if (string.IsNullOrWhiteSpace(Trigger.Name))
|
||||
{
|
||||
_notificationService.ShowWarn("请至少选择一个关联的变量");
|
||||
_notificationService.ShowWarn("请输入触发器名称");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,39 +106,7 @@ namespace DMS.WPF.ViewModels.Dialogs
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置选中的变量ID
|
||||
foreach (var selectedVariable in SelectedVariables)
|
||||
{
|
||||
Trigger.VariableIds.Add(selectedVariable.Id);
|
||||
}
|
||||
|
||||
// Validate condition-specific fields
|
||||
switch (Trigger.Condition)
|
||||
{
|
||||
case ConditionType.GreaterThan:
|
||||
case ConditionType.LessThan:
|
||||
case ConditionType.EqualTo:
|
||||
case ConditionType.NotEqualTo:
|
||||
if (!Trigger.Threshold.HasValue)
|
||||
{
|
||||
_notificationService.ShowWarn($"{Trigger.Condition} 条件需要设置阈值");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ConditionType.InRange:
|
||||
case ConditionType.OutOfRange:
|
||||
if (!Trigger.LowerBound.HasValue || !Trigger.UpperBound.HasValue)
|
||||
{
|
||||
_notificationService.ShowWarn($"{Trigger.Condition} 条件需要设置下限和上限");
|
||||
return;
|
||||
}
|
||||
if (Trigger.LowerBound > Trigger.UpperBound)
|
||||
{
|
||||
_notificationService.ShowWarn("下限必须小于或等于上限");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Prepare action configuration based on selected action type
|
||||
if (Trigger.Action == ActionType.SendEmail)
|
||||
|
||||
@@ -57,7 +57,6 @@ namespace DMS.WPF.ViewModels
|
||||
var newTrigger = new TriggerItem()
|
||||
{
|
||||
IsActive = true,
|
||||
Condition = Core.Models.Triggers.ConditionType.GreaterThan,
|
||||
Action = Core.Models.Triggers.ActionType.SendEmail,
|
||||
Description = "新建触发器",
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
<converters:EnumToVisibilityConverter x:Key="LocalEnumToVisibilityConverter" />
|
||||
<converters:IntToVisibilityConverter x:Key="IntToVisibilityConverter" />
|
||||
<converters:EmptyCollectionToVisibilityConverter x:Key="EmptyCollectionToVisibilityConverter" />
|
||||
<ex:EnumBindingSource x:Key="ConditionTypeEnum"
|
||||
EnumType="{x:Type enums:ConditionType}" />
|
||||
<ex:EnumBindingSource x:Key="ActionTypeEnum"
|
||||
EnumType="{x:Type enums:ActionType}" />
|
||||
</ui:ContentDialog.Resources>
|
||||
@@ -39,6 +37,15 @@
|
||||
<GroupBox Header="基本信息"
|
||||
Padding="5">
|
||||
<StackPanel>
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="名称:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.Name, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="300"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="描述:"
|
||||
Width="100"
|
||||
@@ -51,188 +58,10 @@
|
||||
<CheckBox Content="激活"
|
||||
IsChecked="{Binding Trigger.IsActive}"
|
||||
Margin="0,0,0,10" />
|
||||
|
||||
<!-- Selected Variables Section -->
|
||||
<Label Content="已选择的变量:"
|
||||
FontWeight="Bold"
|
||||
Margin="0,0,0,5"/>
|
||||
<Border BorderBrush="LightGray" BorderThickness="1"
|
||||
Padding="5"
|
||||
Margin="0,0,0,10"
|
||||
Background="WhiteSmoke">
|
||||
<WrapPanel x:Name="SelectedVariablesPanel">
|
||||
<ItemsControl ItemsSource="{Binding SelectedVariables}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type items:VariableItem}">
|
||||
<Border Background="LightBlue"
|
||||
CornerRadius="3"
|
||||
Margin="2"
|
||||
Padding="5,2">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<Button Content="×"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="2"
|
||||
Click="RemoveVariableButton_Click"
|
||||
Tag="{Binding}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock Text="暂无选择的变量"
|
||||
FontStyle="Italic"
|
||||
Foreground="Gray"
|
||||
Visibility="{Binding SelectedVariables, Converter={StaticResource EmptyCollectionToVisibilityConverter}}"/>
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Variable Search Section -->
|
||||
<Label Content="搜索变量:"
|
||||
FontWeight="Bold"
|
||||
Margin="0,0,0,5"/>
|
||||
<TextBox x:Name="SearchTextBox"
|
||||
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0,0,0,5"
|
||||
ui:ControlHelper.PlaceholderText="输入变量名称进行搜索"/>
|
||||
|
||||
<Border BorderBrush="LightGray"
|
||||
BorderThickness="1"
|
||||
Height="150"
|
||||
Margin="0,0,0,10">
|
||||
<ListBox x:Name="VariableListBox"
|
||||
ItemsSource="{Binding FilteredVariables}"
|
||||
SelectionMode="Single"
|
||||
MouseDoubleClick="VariableListBox_MouseDoubleClick">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type items:VariableItem}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
|
||||
<TextBlock Text=" - " />
|
||||
<TextBlock Text="{Binding Description}" FontStyle="Italic" Foreground="Gray"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- Condition Section -->
|
||||
<GroupBox Header="触发条件"
|
||||
Padding="5"
|
||||
Margin="0,10,0,0">
|
||||
<StackPanel>
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="条件类型:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource ConditionTypeEnum}}"
|
||||
SelectedItem="{Binding Trigger.Condition}"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
|
||||
<!-- Conditional Fields based on Condition Type -->
|
||||
<StackPanel
|
||||
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=GreaterThan}">
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="阈值:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=LessThan}">
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="阈值:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=EqualTo}">
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="阈值:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=NotEqualTo}">
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="阈值:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=InRange}">
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="下限:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.LowerBound, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="上限:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.UpperBound, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=OutOfRange}">
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="下限:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.LowerBound, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
<DockPanel Margin="0,0,0,5">
|
||||
<Label Content="上限:"
|
||||
Width="100"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox Text="{Binding Trigger.UpperBound, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- Action Section -->
|
||||
<GroupBox Header="触发动作"
|
||||
|
||||
@@ -31,28 +31,6 @@ namespace DMS.WPF.Views.Dialogs
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理变量列表双击事件,将选中的变量添加到已选择列表
|
||||
/// </summary>
|
||||
private void VariableListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (VariableListBox.SelectedItem is VariableItem selectedVariable)
|
||||
{
|
||||
var viewModel = DataContext as ViewModels.Dialogs.TriggerDialogViewModel;
|
||||
viewModel?.AddVariable(selectedVariable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理移除变量按钮点击事件
|
||||
/// </summary>
|
||||
private void RemoveVariableButton_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Controls.Button button && button.Tag is VariableItem variable)
|
||||
{
|
||||
var viewModel = DataContext as ViewModels.Dialogs.TriggerDialogViewModel;
|
||||
viewModel?.RemoveVariable(variable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user