更新项目配置,新增设备同步模块,优化WebSocket和Swagger配置,增强SCADA系统的免登录接口,支持数据字典项和登录日志的免登录查询与记录。调整Java编译设置,确保更好的开发体验。

This commit is contained in:
geht
2026-04-28 10:23:58 +08:00
parent bbe46dcf2d
commit 142a0bdaba
1013 changed files with 41858 additions and 28 deletions

View File

@@ -0,0 +1,82 @@
using FluentValidation;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using ValidationResult = System.Windows.Controls.ValidationResult;
namespace YY.Admin.Core.FluentValidation
{
internal class FluentAutoValidationRule<T> : ValidationRule, IFluentAutoValidationRule where T : class
{
public IValidator<T>? Validator { get; set; }
/// <summary>
/// 当前绑定控件对应的属性名
/// </summary>
public string? PropertyName { get; set; }
// 👇 ValidationStep.UpdatedValue为true: 让Validate方法中value参数为BindingExpression类型而非值类型
public FluentAutoValidationRule() : base(ValidationStep.UpdatedValue, true) { }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (Validator == null || string.IsNullOrEmpty(PropertyName))
return ValidationResult.ValidResult;
// 如果 value 不是 BindingExpression先尝试判断是否是 BindingGroup (兼容性保护)
if (value is not BindingExpression bindingExpr)
{
// 有时 WPF 在不同阶段会传入 BindingGroup 或其他类型,直接跳过初始化阶段的验证,避免误报
return ValidationResult.ValidResult;
}
// --- 更可靠地判断“初始化阶段的第一次验证” ---
// 如果绑定目标尚未挂到视觉树或控件未 Loaded则视为初始化不执行验证
var target = bindingExpr.Target as DependencyObject;
if (target != null)
{
// 1) 如果是 FrameworkElement 并且还没 Loaded则跳过
if (target is FrameworkElement fe && !fe.IsLoaded)
return ValidationResult.ValidResult;
// 2) 如果 PresentationSource 为空,也说明还没连接到可视树,跳过
var ps = System.Windows.PresentationSource.FromVisual(target as System.Windows.Media.Visual);
if (ps == null)
return ValidationResult.ValidResult;
// 3) 另外,如果控件不可见,也可能是初始化阶段,可根据需要跳过
if (target is UIElement ui && !ui.IsVisible)
return ValidationResult.ValidResult;
}
var dataItem = bindingExpr.DataItem;
if (dataItem == null)
return new ValidationResult(false, "绑定源为空");
// 解析 Path例如 "SysUser.Account"
var path = bindingExpr.ParentBinding.Path?.Path ?? string.Empty;
var rootPropName = path.Split('.')[0]; // SysUser
var modelProp = dataItem.GetType().GetProperty(rootPropName);
if (modelProp == null)
return ValidationResult.ValidResult;
var modelObj = modelProp.GetValue(dataItem);
if (modelObj is not T model)
return ValidationResult.ValidResult;
// 调用 FluentValidation 验证指定属性
var result = Validator.ValidateAsync(model, opts => opts.IncludeProperties(PropertyName))
.ConfigureAwait(false) // 同步等待TaskValidationRule 不支持 async → 只能同步等待。)
.GetAwaiter()
.GetResult();
var error = result.Errors.FirstOrDefault(e => e.PropertyName == PropertyName);
if (error != null)
return new ValidationResult(false, error.ErrorMessage);
return ValidationResult.ValidResult;
}
}
}