继续修改触发器(未完成,修改一个触发器可以添加多个变量)
This commit is contained in:
23
CHANGELOG.md
Normal file
23
CHANGELOG.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# 更新日志
|
||||||
|
|
||||||
|
## v1.1.0 (2025-09-22)
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
- **触发器系统重构**:将触发器与变量的关联关系从一对一改为多对多
|
||||||
|
- 修改了 `TriggerDefinition` 领域模型,将 `VariableId` 属性改为 `VariableIds` 列表
|
||||||
|
- 添加了新的数据库实体 `DbTriggerVariable` 来维护多对多关系
|
||||||
|
- 更新了数据库映射配置和仓储实现
|
||||||
|
- 修改了 DTO 和服务层以支持新的多对多关系
|
||||||
|
- 更新了 WPF UI 以支持多变量选择
|
||||||
|
|
||||||
|
### 技术实现细节
|
||||||
|
- 添加了新的 `TriggerVariables` 数据库表来维护触发器与变量的多对多关系
|
||||||
|
- 更新了 `TriggerRepository` 以处理新的关联表
|
||||||
|
- 修改了 `TriggerManagementService` 的验证逻辑,确保至少选择一个变量
|
||||||
|
- 更新了 WPF 视图模型以支持多选变量
|
||||||
|
- 提供了数据库迁移脚本以更新现有数据库结构
|
||||||
|
|
||||||
|
### 兼容性说明
|
||||||
|
- 此更新涉及数据库结构变更,需要运行迁移脚本
|
||||||
|
- 现有的触发器数据将被迁移到新的表结构中
|
||||||
|
- API 接口保持向后兼容,但返回的数据结构已更新
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using DMS.Core.Models.Triggers;
|
using DMS.Core.Models.Triggers;
|
||||||
|
|
||||||
// 引入枚举
|
// 引入枚举
|
||||||
@@ -15,9 +16,9 @@ namespace DMS.Application.DTOs
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关联的变量 ID
|
/// 关联的变量 ID 列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int VariableId { get; set; }
|
public List<int> VariableIds { get; set; } = new List<int>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发器是否处于激活状态
|
/// 触发器是否处于激活状态
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ public class MappingProfile : Profile
|
|||||||
CreateMap<EmailTemplate, EmailTemplateDto>().ReverseMap();
|
CreateMap<EmailTemplate, EmailTemplateDto>().ReverseMap();
|
||||||
|
|
||||||
CreateMap<EmailLog, EmailLogDto>().ReverseMap();
|
CreateMap<EmailLog, EmailLogDto>().ReverseMap();
|
||||||
CreateMap<TriggerDefinition, TriggerDefinitionDto>().ReverseMap();
|
CreateMap<TriggerDefinition, TriggerDefinitionDto>()
|
||||||
|
.ForMember(dest => dest.VariableIds, opt => opt.MapFrom(src => src.VariableIds))
|
||||||
|
.ReverseMap()
|
||||||
|
.ForMember(dest => dest.VariableIds, opt => opt.MapFrom(src => src.VariableIds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ namespace DMS.Application.Services.Triggers.Impl
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void ValidateTriggerDto(TriggerDefinitionDto dto)
|
private void ValidateTriggerDto(TriggerDefinitionDto dto)
|
||||||
{
|
{
|
||||||
|
// 检查是否至少关联了一个变量
|
||||||
|
if (dto.VariableIds == null || !dto.VariableIds.Any())
|
||||||
|
throw new ArgumentException("触发器必须至少关联一个变量。");
|
||||||
|
|
||||||
// 添加必要的验证逻辑
|
// 添加必要的验证逻辑
|
||||||
switch (dto.Condition)
|
switch (dto.Condition)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace DMS.Core.Models.Triggers
|
namespace DMS.Core.Models.Triggers
|
||||||
{
|
{
|
||||||
@@ -37,9 +38,9 @@ namespace DMS.Core.Models.Triggers
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关联的变量 ID
|
/// 关联的变量列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int VariableId { get; set; }
|
public List<int> VariableIds { get; set; } = new List<int>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发器是否处于激活状态
|
/// 触发器是否处于激活状态
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using DMS.Core.Models.Triggers;
|
using DMS.Core.Models.Triggers;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using SqlSugar.DbConvert;
|
using SqlSugar.DbConvert;
|
||||||
@@ -17,11 +18,6 @@ public class DbTriggerDefinition
|
|||||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 关联的变量 ID。
|
|
||||||
/// </summary>
|
|
||||||
public int VariableId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发器是否处于激活状态。
|
/// 触发器是否处于激活状态。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,4 +92,10 @@ public class DbTriggerDefinition
|
|||||||
/// 最后更新时间。
|
/// 最后更新时间。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 关联的变量 ID 列表(通过中间表关联)。
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
public List<int> VariableIds { get; set; } = new List<int>();
|
||||||
}
|
}
|
||||||
22
DMS.Infrastructure/Entities/DbTriggerVariable.cs
Normal file
22
DMS.Infrastructure/Entities/DbTriggerVariable.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace DMS.Infrastructure.Entities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库实体:表示触发器与变量的多对多关联关系。
|
||||||
|
/// </summary>
|
||||||
|
public class DbTriggerVariable
|
||||||
|
{
|
||||||
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 外键,指向 TriggerDefinitions 表的 Id。
|
||||||
|
/// </summary>
|
||||||
|
public int TriggerDefinitionId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 外键,指向 Variables 表的 Id。
|
||||||
|
/// </summary>
|
||||||
|
public int VariableId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- 创建触发器与变量关联表
|
||||||
|
CREATE TABLE TriggerVariables (
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
TriggerDefinitionId INTEGER NOT NULL,
|
||||||
|
VariableId INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (TriggerDefinitionId) REFERENCES TriggerDefinitions(Id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (VariableId) REFERENCES Variables(Id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 创建索引以提高查询性能
|
||||||
|
CREATE INDEX IX_TriggerVariables_TriggerDefinitionId ON TriggerVariables (TriggerDefinitionId);
|
||||||
|
CREATE INDEX IX_TriggerVariables_VariableId ON TriggerVariables (VariableId);
|
||||||
|
|
||||||
|
-- 迁移现有数据:将TriggerDefinitions表中的VariableId迁移到新的关联表中
|
||||||
|
INSERT INTO TriggerVariables (TriggerDefinitionId, VariableId)
|
||||||
|
SELECT Id, VariableId
|
||||||
|
FROM TriggerDefinitions
|
||||||
|
WHERE VariableId IS NOT NULL AND VariableId > 0;
|
||||||
|
|
||||||
|
-- 删除TriggerDefinitions表中的VariableId列(如果数据库支持)
|
||||||
|
-- 注意:SQLite不支持直接删除列,所以这里只是注释说明
|
||||||
|
-- 在支持的数据库中,可以使用以下语句:
|
||||||
|
-- ALTER TABLE TriggerDefinitions DROP COLUMN VariableId;
|
||||||
@@ -50,10 +50,12 @@ public class MappingProfile : Profile
|
|||||||
opt => opt.MapFrom(src => src.SuppressionDurationTicks.HasValue ?
|
opt => opt.MapFrom(src => src.SuppressionDurationTicks.HasValue ?
|
||||||
TimeSpan.FromTicks(src.SuppressionDurationTicks.Value) :
|
TimeSpan.FromTicks(src.SuppressionDurationTicks.Value) :
|
||||||
(TimeSpan?)null))
|
(TimeSpan?)null))
|
||||||
|
.ForMember(dest => dest.VariableIds, opt => opt.MapFrom(src => src.VariableIds))
|
||||||
.ReverseMap()
|
.ReverseMap()
|
||||||
.ForMember(dest => dest.SuppressionDurationTicks,
|
.ForMember(dest => dest.SuppressionDurationTicks,
|
||||||
opt => opt.MapFrom(src => src.SuppressionDuration.HasValue ?
|
opt => opt.MapFrom(src => src.SuppressionDuration.HasValue ?
|
||||||
src.SuppressionDuration.Value.Ticks :
|
src.SuppressionDuration.Value.Ticks :
|
||||||
(long?)null));
|
(long?)null))
|
||||||
|
.ForMember(dest => dest.VariableIds, opt => opt.MapFrom(src => src.VariableIds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,16 @@ namespace DMS.Infrastructure.Repositories
|
|||||||
public async Task<IEnumerable<TriggerDefinition>> GetAllAsync()
|
public async Task<IEnumerable<TriggerDefinition>> GetAllAsync()
|
||||||
{
|
{
|
||||||
var dbList = await base.GetAllAsync();
|
var dbList = await base.GetAllAsync();
|
||||||
|
// 加载关联的变量ID
|
||||||
|
foreach (var dbTrigger in dbList)
|
||||||
|
{
|
||||||
|
var variableIds = await _dbContext.GetInstance()
|
||||||
|
.Queryable<DbTriggerVariable>()
|
||||||
|
.Where(tv => tv.TriggerDefinitionId == dbTrigger.Id)
|
||||||
|
.Select(tv => tv.VariableId)
|
||||||
|
.ToListAsync();
|
||||||
|
dbTrigger.VariableIds = variableIds;
|
||||||
|
}
|
||||||
return _mapper.Map<List<TriggerDefinition>>(dbList);
|
return _mapper.Map<List<TriggerDefinition>>(dbList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +53,16 @@ namespace DMS.Infrastructure.Repositories
|
|||||||
public async Task<TriggerDefinition?> GetByIdAsync(int id)
|
public async Task<TriggerDefinition?> GetByIdAsync(int id)
|
||||||
{
|
{
|
||||||
var dbTrigger = await base.GetByIdAsync(id);
|
var dbTrigger = await base.GetByIdAsync(id);
|
||||||
|
if (dbTrigger != null)
|
||||||
|
{
|
||||||
|
// 加载关联的变量ID
|
||||||
|
var variableIds = await _dbContext.GetInstance()
|
||||||
|
.Queryable<DbTriggerVariable>()
|
||||||
|
.Where(tv => tv.TriggerDefinitionId == dbTrigger.Id)
|
||||||
|
.Select(tv => tv.VariableId)
|
||||||
|
.ToListAsync();
|
||||||
|
dbTrigger.VariableIds = variableIds;
|
||||||
|
}
|
||||||
return _mapper.Map<TriggerDefinition>(dbTrigger);
|
return _mapper.Map<TriggerDefinition>(dbTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +71,21 @@ namespace DMS.Infrastructure.Repositories
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<TriggerDefinition> AddAsync(TriggerDefinition trigger)
|
public async Task<TriggerDefinition> AddAsync(TriggerDefinition trigger)
|
||||||
{
|
{
|
||||||
var dbTrigger = await base.AddAsync(_mapper.Map<DbTriggerDefinition>(trigger));
|
var dbTrigger = _mapper.Map<DbTriggerDefinition>(trigger);
|
||||||
|
dbTrigger = await base.AddAsync(dbTrigger);
|
||||||
|
|
||||||
|
// 保存关联的变量ID
|
||||||
|
if (trigger.VariableIds != null && trigger.VariableIds.Any())
|
||||||
|
{
|
||||||
|
var triggerVariables = trigger.VariableIds.Select(variableId => new DbTriggerVariable
|
||||||
|
{
|
||||||
|
TriggerDefinitionId = dbTrigger.Id,
|
||||||
|
VariableId = variableId
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
await _dbContext.GetInstance().Insertable(triggerVariables).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
|
||||||
return _mapper.Map(dbTrigger, trigger);
|
return _mapper.Map(dbTrigger, trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +94,33 @@ namespace DMS.Infrastructure.Repositories
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<TriggerDefinition?> UpdateAsync(TriggerDefinition trigger)
|
public async Task<TriggerDefinition?> UpdateAsync(TriggerDefinition trigger)
|
||||||
{
|
{
|
||||||
var rowsAffected = await base.UpdateAsync(_mapper.Map<DbTriggerDefinition>(trigger));
|
var dbTrigger = _mapper.Map<DbTriggerDefinition>(trigger);
|
||||||
return rowsAffected > 0 ? trigger : null;
|
var rowsAffected = await base.UpdateAsync(dbTrigger);
|
||||||
|
|
||||||
|
if (rowsAffected > 0)
|
||||||
|
{
|
||||||
|
// 删除旧的关联关系
|
||||||
|
await _dbContext.GetInstance()
|
||||||
|
.Deleteable<DbTriggerVariable>()
|
||||||
|
.Where(tv => tv.TriggerDefinitionId == dbTrigger.Id)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
|
||||||
|
// 插入新的关联关系
|
||||||
|
if (trigger.VariableIds != null && trigger.VariableIds.Any())
|
||||||
|
{
|
||||||
|
var triggerVariables = trigger.VariableIds.Select(variableId => new DbTriggerVariable
|
||||||
|
{
|
||||||
|
TriggerDefinitionId = dbTrigger.Id,
|
||||||
|
VariableId = variableId
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
await _dbContext.GetInstance().Insertable(triggerVariables).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -71,6 +130,14 @@ namespace DMS.Infrastructure.Repositories
|
|||||||
{
|
{
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
|
// 先删除关联的变量关系
|
||||||
|
await _dbContext.GetInstance()
|
||||||
|
.Deleteable<DbTriggerVariable>()
|
||||||
|
.Where(tv => tv.TriggerDefinitionId == id)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
|
||||||
|
// 再删除触发器本身
|
||||||
var rowsAffected = await _dbContext.GetInstance().Deleteable<DbTriggerDefinition>()
|
var rowsAffected = await _dbContext.GetInstance().Deleteable<DbTriggerDefinition>()
|
||||||
.In(id)
|
.In(id)
|
||||||
.ExecuteCommandAsync();
|
.ExecuteCommandAsync();
|
||||||
@@ -86,9 +153,34 @@ namespace DMS.Infrastructure.Repositories
|
|||||||
{
|
{
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
var dbList = await _dbContext.GetInstance().Queryable<DbTriggerDefinition>()
|
|
||||||
.Where(t => t.VariableId == variableId)
|
// 先查询关联表获取触发器ID
|
||||||
|
var triggerIds = await _dbContext.GetInstance()
|
||||||
|
.Queryable<DbTriggerVariable>()
|
||||||
|
.Where(tv => tv.VariableId == variableId)
|
||||||
|
.Select(tv => tv.TriggerDefinitionId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 再查询触发器定义
|
||||||
|
var dbList = new List<DbTriggerDefinition>();
|
||||||
|
if (triggerIds.Any())
|
||||||
|
{
|
||||||
|
dbList = await _dbContext.GetInstance().Queryable<DbTriggerDefinition>()
|
||||||
|
.In(it => it.Id, triggerIds)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 加载每个触发器的变量ID列表
|
||||||
|
foreach (var dbTrigger in dbList)
|
||||||
|
{
|
||||||
|
var variableIds = await _dbContext.GetInstance()
|
||||||
|
.Queryable<DbTriggerVariable>()
|
||||||
|
.Where(tv => tv.TriggerDefinitionId == dbTrigger.Id)
|
||||||
|
.Select(tv => tv.VariableId)
|
||||||
|
.ToListAsync();
|
||||||
|
dbTrigger.VariableIds = variableIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
_logger.LogInformation($"GetByVariableId {typeof(DbTriggerDefinition).Name},VariableId={variableId},耗时:{stopwatch.ElapsedMilliseconds}ms");
|
_logger.LogInformation($"GetByVariableId {typeof(DbTriggerDefinition).Name},VariableId={variableId},耗时:{stopwatch.ElapsedMilliseconds}ms");
|
||||||
return _mapper.Map<List<TriggerDefinition>>(dbList);
|
return _mapper.Map<List<TriggerDefinition>>(dbList);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
@@ -5,8 +6,10 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
using DMS.Application.DTOs;
|
using DMS.Application.DTOs;
|
||||||
using DMS.Application.Interfaces;
|
using DMS.Application.Interfaces;
|
||||||
using DMS.Application.Interfaces.Database;
|
using DMS.Application.Interfaces.Database;
|
||||||
|
using DMS.Core.Interfaces;
|
||||||
using DMS.Core.Models.Triggers;
|
using DMS.Core.Models.Triggers;
|
||||||
using DMS.WPF.Interfaces;
|
using DMS.WPF.Interfaces;
|
||||||
|
using DMS.WPF.ViewModels.Items;
|
||||||
|
|
||||||
namespace DMS.WPF.ViewModels.Dialogs
|
namespace DMS.WPF.ViewModels.Dialogs
|
||||||
{
|
{
|
||||||
@@ -17,14 +20,21 @@ namespace DMS.WPF.ViewModels.Dialogs
|
|||||||
{
|
{
|
||||||
private readonly IVariableAppService _variableAppService; // To populate variable selection dropdown
|
private readonly IVariableAppService _variableAppService; // To populate variable selection dropdown
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
|
private readonly IDataStorageService _dataStorageService;
|
||||||
private readonly INotificationService _notificationService;
|
private readonly INotificationService _notificationService;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _searchText = "";
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private TriggerDefinitionDto _trigger = new();
|
private TriggerDefinitionDto _trigger = new();
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private List<VariableDto> _availableVariables = new();
|
private List<VariableDto> _availableVariables = new();
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<VariableItemViewModel> _selectedVariables = new();
|
||||||
|
|
||||||
// Properties for easier binding in XAML for SendEmail action config
|
// Properties for easier binding in XAML for SendEmail action config
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _emailRecipients = "";
|
private string _emailRecipients = "";
|
||||||
@@ -38,13 +48,29 @@ namespace DMS.WPF.ViewModels.Dialogs
|
|||||||
public TriggerDialogViewModel(
|
public TriggerDialogViewModel(
|
||||||
IVariableAppService variableAppService,
|
IVariableAppService variableAppService,
|
||||||
IDialogService dialogService,
|
IDialogService dialogService,
|
||||||
|
IDataStorageService dataStorageService,
|
||||||
INotificationService notificationService)
|
INotificationService notificationService)
|
||||||
{
|
{
|
||||||
_variableAppService = variableAppService ?? throw new ArgumentNullException(nameof(variableAppService));
|
_variableAppService = variableAppService ?? throw new ArgumentNullException(nameof(variableAppService));
|
||||||
_dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService));
|
_dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService));
|
||||||
|
_dataStorageService = dataStorageService;
|
||||||
_notificationService = notificationService ?? throw new ArgumentNullException(nameof(notificationService));
|
_notificationService = notificationService ?? throw new ArgumentNullException(nameof(notificationService));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void OnSearchTextChanged(string searchText)
|
||||||
|
{
|
||||||
|
SelectedVariables.Clear();
|
||||||
|
foreach (var variableKv in _dataStorageService.Variables)
|
||||||
|
{
|
||||||
|
if (variableKv.Value.Name.Contains(SearchText))
|
||||||
|
{
|
||||||
|
SelectedVariables.Add(variableKv.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化视图模型(传入待编辑的触发器)
|
/// 初始化视图模型(传入待编辑的触发器)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,6 +86,19 @@ namespace DMS.WPF.ViewModels.Dialogs
|
|||||||
// Load available variables for selection dropdown
|
// Load available variables for selection dropdown
|
||||||
await LoadVariablesAsync();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse action configuration if it's SendEmail
|
// Parse action configuration if it's SendEmail
|
||||||
if (Trigger.Action == ActionType.SendEmail && !string.IsNullOrEmpty(Trigger.ActionConfigurationJson))
|
if (Trigger.Action == ActionType.SendEmail && !string.IsNullOrEmpty(Trigger.ActionConfigurationJson))
|
||||||
{
|
{
|
||||||
@@ -109,9 +148,9 @@ namespace DMS.WPF.ViewModels.Dialogs
|
|||||||
private async Task SaveAsync()
|
private async Task SaveAsync()
|
||||||
{
|
{
|
||||||
// Basic validation
|
// Basic validation
|
||||||
if (Trigger.VariableId == default(int))
|
if (SelectedVariables == null || !SelectedVariables.Any())
|
||||||
{
|
{
|
||||||
_notificationService.ShowWarn("请选择关联的变量");
|
_notificationService.ShowWarn("请至少选择一个关联的变量");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +160,9 @@ namespace DMS.WPF.ViewModels.Dialogs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置选中的变量ID
|
||||||
|
Trigger.VariableIds = SelectedVariables.Select(v => v.Id).ToList();
|
||||||
|
|
||||||
// Validate condition-specific fields
|
// Validate condition-specific fields
|
||||||
switch (Trigger.Condition)
|
switch (Trigger.Condition)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ namespace DMS.WPF.ViewModels.Triggers
|
|||||||
var triggerToEdit = new TriggerDefinitionDto
|
var triggerToEdit = new TriggerDefinitionDto
|
||||||
{
|
{
|
||||||
Id = SelectedTrigger.Id,
|
Id = SelectedTrigger.Id,
|
||||||
VariableId = SelectedTrigger.VariableId,
|
VariableIds = new List<int>(SelectedTrigger.VariableIds),
|
||||||
IsActive = SelectedTrigger.IsActive,
|
IsActive = SelectedTrigger.IsActive,
|
||||||
Condition = SelectedTrigger.Condition,
|
Condition = SelectedTrigger.Condition,
|
||||||
Threshold = SelectedTrigger.Threshold,
|
Threshold = SelectedTrigger.Threshold,
|
||||||
|
|||||||
@@ -5,13 +5,17 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||||
xmlns:enums="clr-namespace:DMS.Core.Models.Triggers;assembly=DMS.Core"
|
xmlns:enums="clr-namespace:DMS.Core.Models.Triggers;assembly=DMS.Core"
|
||||||
xmlns:vc="clr-namespace:DMS.WPF.ValueConverts"
|
xmlns:vmd="clr-namespace:DMS.WPF.ViewModels.Dialogs"
|
||||||
|
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||||
xmlns:ex="clr-namespace:DMS.Extensions"
|
xmlns:ex="clr-namespace:DMS.Extensions"
|
||||||
xmlns:converters="clr-namespace:DMS.WPF.Converters"
|
xmlns:converters="clr-namespace:DMS.WPF.Converters"
|
||||||
Title="{Binding Title}"
|
Title="{Binding Title}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="600" d:DesignWidth="600"
|
d:DesignHeight="600"
|
||||||
MinWidth="500" MinHeight="500"
|
d:DesignWidth="600"
|
||||||
|
d:DataContext="{d:DesignInstance vmd:TriggerDialogViewModel}"
|
||||||
|
MinWidth="500"
|
||||||
|
MinHeight="500"
|
||||||
PrimaryButtonText="{Binding PrimaryButText}"
|
PrimaryButtonText="{Binding PrimaryButText}"
|
||||||
CloseButtonText="取消"
|
CloseButtonText="取消"
|
||||||
PrimaryButtonCommand="{Binding SaveCommand}"
|
PrimaryButtonCommand="{Binding SaveCommand}"
|
||||||
@@ -19,155 +23,239 @@
|
|||||||
DefaultButton="Primary">
|
DefaultButton="Primary">
|
||||||
|
|
||||||
<ui:ContentDialog.Resources>
|
<ui:ContentDialog.Resources>
|
||||||
<converters:EnumToVisibilityConverter x:Key="LocalEnumToVisibilityConverter"/>
|
<converters:EnumToVisibilityConverter x:Key="LocalEnumToVisibilityConverter" />
|
||||||
<ex:EnumBindingSource x:Key="ConditionTypeEnum" EnumType="{x:Type enums:ConditionType}" />
|
<ex:EnumBindingSource x:Key="ConditionTypeEnum"
|
||||||
<ex:EnumBindingSource x:Key="ActionTypeEnum" EnumType="{x:Type enums:ActionType}" />
|
EnumType="{x:Type enums:ConditionType}" />
|
||||||
|
<ex:EnumBindingSource x:Key="ActionTypeEnum"
|
||||||
|
EnumType="{x:Type enums:ActionType}" />
|
||||||
</ui:ContentDialog.Resources>
|
</ui:ContentDialog.Resources>
|
||||||
|
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel Margin="10">
|
<StackPanel Margin="10">
|
||||||
<!-- Basic Info Section -->
|
<!-- Basic Info Section -->
|
||||||
<GroupBox Header="基本信息" Padding="5">
|
<GroupBox Header="基本信息"
|
||||||
|
Padding="5">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Label Content="关联变量:" Width="100" VerticalAlignment="Center"/>
|
<StackPanel>
|
||||||
<ComboBox ItemsSource="{Binding AvailableVariables}"
|
<hc:TextBox hc:InfoElement.Title="搜索变量:"
|
||||||
DisplayMemberPath="Name"
|
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged }">
|
||||||
SelectedValuePath="Id"
|
</hc:TextBox>
|
||||||
SelectedValue="{Binding Trigger.VariableId}"
|
<DataGrid
|
||||||
Width="200" HorizontalAlignment="Left"/>
|
AutoGenerateColumns="False"
|
||||||
</DockPanel>
|
CanUserAddRows="False"
|
||||||
|
ItemsSource="{Binding SelectedVariables}">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Binding="{Binding Name}" Header="变量名"></DataGridTextColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="描述:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="描述:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.Description, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.Description, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="300" HorizontalAlignment="Left"/>
|
Width="300"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<CheckBox Content="激活" IsChecked="{Binding Trigger.IsActive}" Margin="0,0,0,5"/>
|
<CheckBox Content="激活"
|
||||||
|
IsChecked="{Binding Trigger.IsActive}"
|
||||||
|
Margin="0,0,0,5" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<!-- Condition Section -->
|
<!-- Condition Section -->
|
||||||
<GroupBox Header="触发条件" Padding="5" Margin="0,10,0,0">
|
<GroupBox Header="触发条件"
|
||||||
|
Padding="5"
|
||||||
|
Margin="0,10,0,0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="条件类型:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="条件类型:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<ComboBox ItemsSource="{Binding Source={StaticResource ConditionTypeEnum}}"
|
<ComboBox ItemsSource="{Binding Source={StaticResource ConditionTypeEnum}}"
|
||||||
SelectedItem="{Binding Trigger.Condition}"
|
SelectedItem="{Binding Trigger.Condition}"
|
||||||
Width="200" HorizontalAlignment="Left"/>
|
Width="200"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<!-- Conditional Fields based on Condition Type -->
|
<!-- Conditional Fields based on Condition Type -->
|
||||||
<StackPanel Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=GreaterThan}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=GreaterThan}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="阈值:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="阈值:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=LessThan}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=LessThan}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="阈值:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="阈值:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=EqualTo}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=EqualTo}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="阈值:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="阈值:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=NotEqualTo}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=NotEqualTo}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="阈值:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="阈值:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.Threshold, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=InRange}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=InRange}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="下限:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="下限:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.LowerBound, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.LowerBound, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="上限:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="上限:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.UpperBound, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.UpperBound, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=OutOfRange}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Condition, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=OutOfRange}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="下限:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="下限:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.LowerBound, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.LowerBound, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="上限:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="上限:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<TextBox Text="{Binding Trigger.UpperBound, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox Text="{Binding Trigger.UpperBound, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<!-- Action Section -->
|
<!-- Action Section -->
|
||||||
<GroupBox Header="触发动作" Padding="5" Margin="0,10,0,0">
|
<GroupBox Header="触发动作"
|
||||||
|
Padding="5"
|
||||||
|
Margin="0,10,0,0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="动作类型:" Width="100" VerticalAlignment="Center"/>
|
<Label Content="动作类型:"
|
||||||
|
Width="100"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
<ComboBox ItemsSource="{Binding Source={StaticResource ActionTypeEnum}}"
|
<ComboBox ItemsSource="{Binding Source={StaticResource ActionTypeEnum}}"
|
||||||
SelectedItem="{Binding Trigger.Action}"
|
SelectedItem="{Binding Trigger.Action}"
|
||||||
Width="200" HorizontalAlignment="Left"/>
|
Width="200"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<!-- Conditional Fields based on Action Type -->
|
<!-- Conditional Fields based on Action Type -->
|
||||||
<StackPanel Visibility="{Binding Trigger.Action, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=SendEmail}">
|
<StackPanel
|
||||||
|
Visibility="{Binding Trigger.Action, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=SendEmail}">
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="收件人 (分号分隔):" Width="150" VerticalAlignment="Top"/>
|
<Label Content="收件人 (分号分隔):"
|
||||||
<TextBox Text="{Binding EmailRecipients, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
|
Width="150"
|
||||||
AcceptsReturn="True" TextWrapping="Wrap"
|
VerticalAlignment="Top" />
|
||||||
Width="350" Height="60" HorizontalAlignment="Left"/>
|
<TextBox
|
||||||
|
Text="{Binding EmailRecipients, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Width="350"
|
||||||
|
Height="60"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="邮件主题模板:" Width="150" VerticalAlignment="Center"/>
|
<Label Content="邮件主题模板:"
|
||||||
<TextBox Text="{Binding EmailSubjectTemplate, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
|
Width="150"
|
||||||
Width="350" HorizontalAlignment="Left"/>
|
VerticalAlignment="Center" />
|
||||||
|
<TextBox
|
||||||
|
Text="{Binding EmailSubjectTemplate, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
|
||||||
|
Width="350"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="邮件内容模板:" Width="150" VerticalAlignment="Top"/>
|
<Label Content="邮件内容模板:"
|
||||||
<TextBox Text="{Binding EmailBodyTemplate, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
|
Width="150"
|
||||||
AcceptsReturn="True" TextWrapping="Wrap"
|
VerticalAlignment="Top" />
|
||||||
Width="350" Height="100" HorizontalAlignment="Left"/>
|
<TextBox
|
||||||
|
Text="{Binding EmailBodyTemplate, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Width="350"
|
||||||
|
Height="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Add placeholders for other action types if needed -->
|
<!-- Add placeholders for other action types if needed -->
|
||||||
<StackPanel Visibility="{Binding Trigger.Action, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=ActivateAlarm}">
|
<StackPanel
|
||||||
<TextBlock Text="配置激活报警动作..." Margin="5"/>
|
Visibility="{Binding Trigger.Action, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=ActivateAlarm}">
|
||||||
|
<TextBlock Text="配置激活报警动作..."
|
||||||
|
Margin="5" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding Trigger.Action, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=WriteToLog}">
|
<StackPanel
|
||||||
<TextBlock Text="配置写入日志动作..." Margin="5"/>
|
Visibility="{Binding Trigger.Action, Converter={StaticResource LocalEnumToVisibilityConverter}, ConverterParameter=WriteToLog}">
|
||||||
|
<TextBlock Text="配置写入日志动作..."
|
||||||
|
Margin="5" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<!-- Suppression Section -->
|
<!-- Suppression Section -->
|
||||||
<GroupBox Header="抑制设置" Padding="5" Margin="0,10,0,0">
|
<GroupBox Header="抑制设置"
|
||||||
|
Padding="5"
|
||||||
|
Margin="0,10,0,0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<DockPanel Margin="0,0,0,5">
|
<DockPanel Margin="0,0,0,5">
|
||||||
<Label Content="抑制持续时间 (秒):" Width="150" VerticalAlignment="Center"/>
|
<Label Content="抑制持续时间 (秒):"
|
||||||
<TextBox Text="{Binding Trigger.SuppressionDuration, Converter={StaticResource NullableTimeSpanToSecondsConverter}, UpdateSourceTrigger=PropertyChanged}"
|
Width="150"
|
||||||
Width="100" HorizontalAlignment="Left"/>
|
VerticalAlignment="Center" />
|
||||||
|
<TextBox
|
||||||
|
Text="{Binding Trigger.SuppressionDuration, Converter={StaticResource NullableTimeSpanToSecondsConverter}, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Width="100"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -43,3 +43,13 @@ opcUaService.Disconnect();
|
|||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
Unit tests for the OPC UA service are included in the `DMS.Infrastructure.UnitTests` project. Run them using your preferred test runner.
|
Unit tests for the OPC UA service are included in the `DMS.Infrastructure.UnitTests` project. Run them using your preferred test runner.
|
||||||
|
|
||||||
|
## Trigger System
|
||||||
|
|
||||||
|
The trigger system has been updated to support associating triggers with multiple variables instead of just one. This allows for more flexible trigger configurations where a single trigger can monitor multiple variables.
|
||||||
|
|
||||||
|
### Key Changes
|
||||||
|
- Modified `TriggerDefinition` to use a list of variable IDs instead of a single variable ID
|
||||||
|
- Added a new `TriggerVariables` table to maintain the many-to-many relationship between triggers and variables
|
||||||
|
- Updated the UI to support selecting multiple variables when creating or editing triggers
|
||||||
|
- Updated all related services and repositories to handle the new many-to-many relationship
|
||||||
Reference in New Issue
Block a user