diff --git a/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs index 19456711..a71b7076 100644 --- a/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs +++ b/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs @@ -64,11 +64,13 @@ public sealed class RequiredIFAttribute( var instance = validationContext.ObjectInstance; var targetProperty = instance.GetType().GetProperty(PropertyName); + // 判断校验字段内容是否为字典 + var dictAttr = targetProperty?.GetCustomAttribute(); if (targetProperty == null) return new ValidationResult($"找不到属性: {PropertyName}"); var targetValue = targetProperty.GetValue(instance); - if (!ShouldValidate(targetValue)) return ValidationResult.Success; + if (!ShouldValidate(targetValue, dictAttr)) return ValidationResult.Success; return IsEmpty(value) ? new ValidationResult(ErrorMessage ?? $"{validationContext.MemberName}不能为空") : ValidationResult.Success; } @@ -78,7 +80,7 @@ public sealed class RequiredIFAttribute( /// /// 依赖属性的值 /// 是否需要验证 - private bool ShouldValidate(object targetValue) + private bool ShouldValidate(object targetValue, DictAttribute dictAttr) { switch (Comparison) { @@ -94,8 +96,26 @@ public sealed class RequiredIFAttribute( case Operator.LessThanOrEqual: case Operator.Contains: case Operator.NotContains: - if (targetValue is IEnumerable enumerable) return enumerable.Cast().Any(item => CompareValues(item, TargetValue, Comparison)); - return TargetValue == null ? !IsEmpty(targetValue) : CompareValues(targetValue, TargetValue, Comparison); + // 多选字典 + if (dictAttr != null && targetValue is string targetString && targetString.Contains(',')) + { + var values = targetString.Split(',') + .Select(v => v.Trim()) + .Where(v => !string.IsNullOrEmpty(v)) + .ToArray(); + + return values.Any(value => CompareValues(value, TargetValue, Comparison)); + } + // 处理其他集合情况 + else if (targetValue is IEnumerable enumerable && !(targetValue is string)) + { + return enumerable.Cast().Any(item => CompareValues(item, TargetValue, Comparison)); + } + // 单选字典 + else + { + return TargetValue == null ? !IsEmpty(targetValue) : CompareValues(targetValue, TargetValue, Comparison); + } default: return false; @@ -137,9 +157,28 @@ public sealed class RequiredIFAttribute( case Operator.Contains: case Operator.NotContains: - if (targetValue is not IEnumerable enumerable) return false; - bool contains = enumerable.Cast().Any(item => item != null && item.Equals(sourceValue)); - return comparison == Operator.Contains ? contains : !contains; + if (targetValue == null) return false; + if (sourceValue == null) return comparison == Operator.NotContains; + + // 多选字典 + if (targetValue is string targetString) + { + string sourceString = sourceValue.ToString(); + bool stringContains = targetString.Equals(sourceString); + return comparison == Operator.Contains ? stringContains : !stringContains; + } + // 其他集合类型处理 + else if (targetValue is IEnumerable enumerable && !(targetValue is string)) + { + bool contains = enumerable.OfType().Any(item => + item != null && item.Equals(sourceValue)); + return comparison == Operator.Contains ? contains : !contains; + } + else + { + bool valuesEqual = targetValue.Equals(sourceValue); + return comparison == Operator.Contains ? valuesEqual : !valuesEqual; + } default: return false; diff --git a/Admin.NET/Admin.NET.sln b/Admin.NET/Admin.NET.sln index a452e8a4..a7cc8391 100644 --- a/Admin.NET/Admin.NET.sln +++ b/Admin.NET/Admin.NET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 18 -VisualStudioVersion = 18.0.11012.119 d18.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36511.14 d17.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Admin.NET.Application", "Admin.NET.Application\Admin.NET.Application.csproj", "{C3F5AEC5-ACEE-4109-94E3-3F981DC18268}" EndProject diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.ReZero/Admin.NET.Plugin.ReZero.csproj b/Admin.NET/Plugins/Admin.NET.Plugin.ReZero/Admin.NET.Plugin.ReZero.csproj index 06846115..099d9176 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.ReZero/Admin.NET.Plugin.ReZero.csproj +++ b/Admin.NET/Plugins/Admin.NET.Plugin.ReZero/Admin.NET.Plugin.ReZero.csproj @@ -26,7 +26,7 @@ - + diff --git a/Web/package.json b/Web/package.json index c2c46b78..8de4972e 100644 --- a/Web/package.json +++ b/Web/package.json @@ -2,7 +2,7 @@ "name": "admin.net.pro", "type": "module", "version": "2.4.33", - "lastBuildTime": "2025.09.22", + "lastBuildTime": "2025.09.23", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "author": "zuohuaijun", "license": "MIT", @@ -93,8 +93,8 @@ "@types/node": "^22.18.6", "@types/nprogress": "^0.2.3", "@types/sortablejs": "^1.15.8", - "@typescript-eslint/eslint-plugin": "^8.44.0", - "@typescript-eslint/parser": "^8.44.0", + "@typescript-eslint/eslint-plugin": "^8.44.1", + "@typescript-eslint/parser": "^8.44.1", "@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue-jsx": "^5.1.1", "@vue/compiler-sfc": "^3.5.21", @@ -103,15 +103,15 @@ "colors": "^1.4.0", "dotenv": "^17.2.1", "eslint": "^9.36.0", - "eslint-plugin-vue": "^10.4.0", + "eslint-plugin-vue": "^10.5.0", "globals": "^16.4.0", "less": "^4.4.1", "prettier": "^3.6.2", "rollup-plugin-visualizer": "^6.0.3", - "sass": "^1.93.0", + "sass": "^1.93.1", "terser": "^5.44.0", "typescript": "^5.9.2", - "vite": "^7.1.6", + "vite": "^7.1.7", "vite-auto-i18n-plugin": "^1.1.9", "vite-plugin-cdn-import": "^1.0.1", "vite-plugin-compression2": "^2.2.1", diff --git a/Web/src/components/selector/pulldownSelecter.vue b/Web/src/components/selector/pulldownSelecter.vue index 63948c3e..50caff5c 100644 --- a/Web/src/components/selector/pulldownSelecter.vue +++ b/Web/src/components/selector/pulldownSelecter.vue @@ -1,6 +1,6 @@