Procházet zdrojové kódy

!1518 代码优化
Merge pull request !1518 from 喵你个汪/next

zuohuaijun před 1 rokem
rodič
revize
0a9d13e457
49 změnil soubory, kde provedl 724 přidání a 923 odebrání
  1. 16 32
      Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
  2. 21 27
      Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs
  3. 7 22
      Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs
  4. 0 1
      Admin.NET/Admin.NET.Core/Service/CodeGen/CustomViewEngine.cs
  5. 1 4
      Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs
  6. 1 2
      Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs
  7. 11 12
      Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs
  8. 12 12
      Admin.NET/Admin.NET.Core/Service/Const/SysConstService.cs
  9. 19 36
      Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs
  10. 3 10
      Admin.NET/Admin.NET.Core/Service/Enum/SysEnumService.cs
  11. 51 79
      Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs
  12. 1 1
      Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs
  13. 12 21
      Admin.NET/Admin.NET.Core/Service/Job/JobClusterServer.cs
  14. 3 4
      Admin.NET/Admin.NET.Core/Service/Job/JobMonitor.cs
  15. 9 19
      Admin.NET/Admin.NET.Core/Service/Job/SysJobService.cs
  16. 16 18
      Admin.NET/Admin.NET.Core/Service/Menu/SysMenuService.cs
  17. 6 4
      Admin.NET/Admin.NET.Core/Service/Message/SysEmailService.cs
  18. 7 10
      Admin.NET/Admin.NET.Core/Service/Message/SysMessageService.cs
  19. 8 12
      Admin.NET/Admin.NET.Core/Service/Message/SysSmsService.cs
  20. 4 4
      Admin.NET/Admin.NET.Core/Service/Notice/SysNoticeService.cs
  21. 4 4
      Admin.NET/Admin.NET.Core/Service/OAuth/OAuthSetup.cs
  22. 7 4
      Admin.NET/Admin.NET.Core/Service/OAuth/SysOAuthService.cs
  23. 2 2
      Admin.NET/Admin.NET.Core/Service/OnlineUser/SysOnlineUserService.cs
  24. 53 57
      Admin.NET/Admin.NET.Core/Service/Org/SysOrgService.cs
  25. 2 4
      Admin.NET/Admin.NET.Core/Service/Plugin/SysPluginService.cs
  26. 5 10
      Admin.NET/Admin.NET.Core/Service/Pos/SysPosService.cs
  27. 2 4
      Admin.NET/Admin.NET.Core/Service/Print/SysPrintService.cs
  28. 64 76
      Admin.NET/Admin.NET.Core/Service/Region/SysRegionService.cs
  29. 2 2
      Admin.NET/Admin.NET.Core/Service/Role/SysRoleOrgService.cs
  30. 20 21
      Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs
  31. 3 4
      Admin.NET/Admin.NET.Core/Service/Schedule/SysScheduleService.cs
  32. 1 1
      Admin.NET/Admin.NET.Core/Service/Server/SysServerService.cs
  33. 20 53
      Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs
  34. 4 5
      Admin.NET/Admin.NET.Core/Service/User/SysUserLdapService.cs
  35. 2 2
      Admin.NET/Admin.NET.Core/Service/User/SysUserService.cs
  36. 8 8
      Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarFilter.cs
  37. 124 119
      Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs
  38. 9 9
      Admin.NET/Admin.NET.Core/Utils/ChinaDateTimeConverter.cs
  39. 28 50
      Admin.NET/Admin.NET.Core/Utils/CodeGenUtil.cs
  40. 38 44
      Admin.NET/Admin.NET.Core/Utils/CommonUtil.cs
  41. 10 12
      Admin.NET/Admin.NET.Core/Utils/ComputerUtil.cs
  42. 8 16
      Admin.NET/Admin.NET.Core/Utils/DateTimeUtil.cs
  43. 6 6
      Admin.NET/Admin.NET.Core/Utils/MiniExcelUtil.cs
  44. 10 10
      Admin.NET/Admin.NET.Core/Utils/TripleDES.cs
  45. 54 57
      Admin.NET/Admin.NET.Core/Utils/VerifyFileExtensionName.cs
  46. 1 4
      Admin.NET/Admin.NET.Core/Utils/XlsxFileResult.cs
  47. 15 0
      Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Input.cs.vm
  48. 13 8
      Web/src/components/table/dictLabel.vue
  49. 1 1
      Web/src/utils/download.ts

+ 16 - 32
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -17,36 +17,30 @@ public class SysAuthService : IDynamicApiController, ITransient
 {
     private readonly UserManager _userManager;
     private readonly SqlSugarRepository<SysUser> _sysUserRep;
-    private readonly SqlSugarRepository<SysUserLdap> _sysUserLdap;
     private readonly IHttpContextAccessor _httpContextAccessor;
     private readonly SysMenuService _sysMenuService;
     private readonly SysOnlineUserService _sysOnlineUserService;
     private readonly SysConfigService _sysConfigService;
     private readonly ICaptcha _captcha;
     private readonly SysCacheService _sysCacheService;
-    private readonly SysLdapService _sysLdapService;
 
     public SysAuthService(UserManager userManager,
         SqlSugarRepository<SysUser> sysUserRep,
-        SqlSugarRepository<SysUserLdap> sysUserLdapRep,
         IHttpContextAccessor httpContextAccessor,
         SysMenuService sysMenuService,
         SysOnlineUserService sysOnlineUserService,
         SysConfigService sysConfigService,
         ICaptcha captcha,
-        SysCacheService sysCacheService,
-        SysLdapService sysLdapService)
+        SysCacheService sysCacheService)
     {
         _userManager = userManager;
         _sysUserRep = sysUserRep;
-        _sysUserLdap = sysUserLdapRep;
         _httpContextAccessor = httpContextAccessor;
         _sysMenuService = sysMenuService;
         _sysOnlineUserService = sysOnlineUserService;
         _sysConfigService = sysConfigService;
         _captcha = captcha;
         _sysCacheService = sysCacheService;
-        _sysLdapService = sysLdapService;
     }
 
     /// <summary>
@@ -67,17 +61,14 @@ public class SysAuthService : IDynamicApiController, ITransient
         var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
         var passwordMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysPasswordMaxErrorTimes);
         // 若未配置或误配置为0、负数, 则默认密码错误次数最大为10次
-        if (passwordMaxErrorTimes < 1)
-            passwordMaxErrorTimes = 10;
-        if (passwordErrorTimes > passwordMaxErrorTimes)
-            throw Oops.Oh(ErrorCodeEnum.D1027);
+        if (passwordMaxErrorTimes < 1) passwordMaxErrorTimes = 10;
+        if (passwordErrorTimes > passwordMaxErrorTimes) throw Oops.Oh(ErrorCodeEnum.D1027);
 
         // 是否开启验证码
         if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysCaptcha))
         {
             // 判断验证码
-            if (!_captcha.Validate(input.CodeId.ToString(), input.Code))
-                throw Oops.Oh(ErrorCodeEnum.D0008);
+            if (!_captcha.Validate(input.CodeId.ToString(), input.Code)) throw Oops.Oh(ErrorCodeEnum.D0008);
         }
 
         // 账号是否存在
@@ -85,13 +76,11 @@ public class SysAuthService : IDynamicApiController, ITransient
         _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
 
         // 账号是否被冻结
-        if (user.Status == StatusEnum.Disable)
-            throw Oops.Oh(ErrorCodeEnum.D1017);
+        if (user.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.D1017);
 
         // 租户是否被禁用
         var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
-        if (tenant != null && tenant.Status == StatusEnum.Disable)
-            throw Oops.Oh(ErrorCodeEnum.Z1003);
+        if (tenant?.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.Z1003);
 
         // 是否开启域登录验证
         if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysDomainLogin))
@@ -127,23 +116,18 @@ public class SysAuthService : IDynamicApiController, ITransient
     {
         if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
         {
-            if (!user.Password.Equals(MD5Encryption.Encrypt(password)))
-            {
-                _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
-                throw Oops.Oh(ErrorCodeEnum.D1000);
-            }
+            if (user.Password.Equals(MD5Encryption.Encrypt(password))) return;
+            
+            _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
+            throw Oops.Oh(ErrorCodeEnum.D1000);
         }
-        else
-        {
-            // 国密SM2解密(前端密码传输SM2加密后的)
-            password = CryptogramUtil.SM2Decrypt(password);
 
-            if (!CryptogramUtil.Decrypt(user.Password).Equals(password))
-            {
-                _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
-                throw Oops.Oh(ErrorCodeEnum.D1000);
-            }
-        }
+        // 国密SM2解密(前端密码传输SM2加密后的)
+        password = CryptogramUtil.SM2Decrypt(password);
+        if (CryptogramUtil.Decrypt(user.Password).Equals(password)) return;
+
+        _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
+        throw Oops.Oh(ErrorCodeEnum.D1000);
     }
 
     /// <summary>

+ 21 - 27
Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs

@@ -126,12 +126,10 @@ public class SysLdapService : IDynamicApiController, ITransient
             while (ldapSearchResults.HasMore())
             {
                 var ldapEntry = ldapSearchResults.Next();
-                var sAMAccountName = ldapEntry.GetAttribute(sysLdap.BindAttrAccount)?.StringValue;
-                if (!string.IsNullOrEmpty(sAMAccountName))
-                {
-                    dn = ldapEntry.Dn;
-                    break;
-                }
+                var sAmAccountName = ldapEntry.GetAttribute(sysLdap.BindAttrAccount)?.StringValue;
+                if (string.IsNullOrEmpty(sAmAccountName)) continue;
+                dn = ldapEntry.Dn;
+                break;
             }
 
             if (string.IsNullOrEmpty(dn)) throw Oops.Oh(ErrorCodeEnum.D1002);
@@ -222,10 +220,9 @@ public class SysLdapService : IDynamicApiController, ITransient
                 }
             }
 
-            if (userLdapList.Count == 0)
-                return null;
+            if (userLdapList.Count == 0) return null;
 
-            await App.GetRequiredService<SysUserLdapService>().InsertUserLdaps(sysLdap.TenantId!.Value, userLdapList);
+            await App.GetRequiredService<SysUserLdapService>().InsertUserLdapList(sysLdap.TenantId!.Value, userLdapList);
             return userLdapList;
         }
         catch (LdapException e)
@@ -251,7 +248,7 @@ public class SysLdapService : IDynamicApiController, ITransient
     private static string GetDepartmentCode(LdapAttributeSet attrs, string bindAttrCode)
     {
         return bindAttrCode == "objectGUID"
-            ? new Guid(attrs.GetAttribute(bindAttrCode)?.ByteValue).ToString()
+            ? new Guid(attrs.GetAttribute(bindAttrCode)?.ByteValue!).ToString()
             : attrs.GetAttribute(bindAttrCode)?.StringValue ?? "0";
     }
 
@@ -269,13 +266,12 @@ public class SysLdapService : IDynamicApiController, ITransient
         {
             Account = !attrs.ContainsKey(bindAttrAccount) ? null : attrs.GetAttribute(bindAttrAccount)?.StringValue,
             EmployeeId = !attrs.ContainsKey(bindAttrEmployeeId) ? null : attrs.GetAttribute(bindAttrEmployeeId)?.StringValue,
-            DeptCode = deptCode
+            DeptCode = deptCode,
+            UserName = !attrs.ContainsKey("name") ? null : attrs.GetAttribute("name")?.StringValue,
+            Mail = !attrs.ContainsKey("mail") ? null : attrs.GetAttribute("mail")?.StringValue
         };
-        userLdap.UserName = !attrs.ContainsKey("name") ? null : attrs.GetAttribute("name")?.StringValue;
-        userLdap.Mail = !attrs.ContainsKey("mail") ? null : attrs.GetAttribute("mail")?.StringValue;
         var pwdLastSet = !attrs.ContainsKey("pwdLastSet") ? null : attrs.GetAttribute("pwdLastSet")?.StringValue;
-        if (!pwdLastSet.Equals("0"))
-            userLdap.PwdLastSetTime = DateTime.FromFileTime(Convert.ToInt64(pwdLastSet));
+        if (!pwdLastSet!.Equals("0")) userLdap.PwdLastSetTime = DateTime.FromFileTime(Convert.ToInt64(pwdLastSet));
         var userAccountControl = !attrs.ContainsKey("userAccountControl") ? null : attrs.GetAttribute("userAccountControl")?.StringValue;
         if ((Convert.ToInt32(userAccountControl) & 0x2) == 0x2) // 检查账户是否已过期(通过检查userAccountControl属性的特定位)  
             userLdap.AccountExpiresFlag = true;
@@ -354,13 +350,12 @@ public class SysLdapService : IDynamicApiController, ITransient
                 }
 
                 var attrs = ldapEntry.GetAttributeSet();
-                if (attrs.Count == 0 || attrs.ContainsKey("OU"))
-                {
-                    var sysOrg = CreateSysOrg(attrs, sysLdap, orgList, new SysOrg { Id = 0, Level = 0 });
-                    orgList.Add(sysOrg);
+                if (attrs.Count != 0 && !attrs.ContainsKey("OU")) continue;
 
-                    SearchDnLdapDept(ldapConn, sysLdap, orgList, ldapEntry.Dn, sysOrg);
-                }
+                var sysOrg = CreateSysOrg(attrs, sysLdap, orgList, new SysOrg { Id = 0, Level = 0 });
+                orgList.Add(sysOrg);
+
+                SearchDnLdapDept(ldapConn, sysLdap, orgList, ldapEntry.Dn, sysOrg);
             }
 
             if (orgList.Count == 0)
@@ -407,13 +402,12 @@ public class SysLdapService : IDynamicApiController, ITransient
             }
 
             var attrs = ldapEntry.GetAttributeSet();
-            if (attrs.Count == 0 || attrs.ContainsKey("OU"))
-            {
-                var sysOrg = CreateSysOrg(attrs, sysLdap, listOrgs, org);
-                listOrgs.Add(sysOrg);
+            if (attrs.Count != 0 && !attrs.ContainsKey("OU")) continue;
 
-                SearchDnLdapDept(ldapConn, sysLdap, listOrgs, ldapEntry.Dn, sysOrg);
-            }
+            var sysOrg = CreateSysOrg(attrs, sysLdap, listOrgs, org);
+            listOrgs.Add(sysOrg);
+
+            SearchDnLdapDept(ldapConn, sysLdap, listOrgs, ldapEntry.Dn, sysOrg);
         }
     }
 

+ 7 - 22
Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs

@@ -66,8 +66,7 @@ public class SysCacheService : IDynamicApiController, ISingleton
     [NonAction]
     public bool Set(string key, object value)
     {
-        if (string.IsNullOrWhiteSpace(key)) return false;
-        return _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value);
+        return !string.IsNullOrWhiteSpace(key) && _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value);
     }
 
     /// <summary>
@@ -80,8 +79,7 @@ public class SysCacheService : IDynamicApiController, ISingleton
     [NonAction]
     public bool Set(string key, object value, TimeSpan expire)
     {
-        if (string.IsNullOrWhiteSpace(key)) return false;
-        return _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value, expire);
+        return !string.IsNullOrWhiteSpace(key) && _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value, expire);
     }
 
     public async Task<TR> AdGetAsync<TR>(String cacheName, Func<Task<TR>> del, TimeSpan? expiry = default(TimeSpan?)) where TR : class
@@ -140,28 +138,15 @@ public class SysCacheService : IDynamicApiController, ISingleton
 
     private static string Key(string cacheName, object[] obs)
     {
-        foreach (var obj in obs)
-        {
-            if (obj is TimeSpan)
-            {
-                throw new Exception("缓存参数类型不能能是:TimeSpan类型");
-            }
-        }
-        StringBuilder sb = new StringBuilder(cacheName + ":");
-        foreach (var a in obs)
-        {
-            sb.Append($@"<{KeySingle(a)}>");
-        }
+        if (obs.OfType<TimeSpan>().Any()) throw new Exception("缓存参数类型不能能是:TimeSpan类型");
+        StringBuilder sb = new (cacheName + ":");
+        foreach (var a in obs) sb.Append($"<{KeySingle(a)}>");
         return sb.ToString();
     }
 
-    public static string KeySingle(object t)
+    private static string KeySingle(object t)
     {
-        if (t.GetType().IsClass && !t.GetType().IsPrimitive)
-        {
-            return JsonConvert.SerializeObject(t);
-        }
-        return t?.ToString();
+        return t.GetType().IsClass && !t.GetType().IsPrimitive ? JsonConvert.SerializeObject(t) : t.ToString();
     }
 
     /// <summary>

+ 0 - 1
Admin.NET/Admin.NET.Core/Service/CodeGen/CustomViewEngine.cs

@@ -135,7 +135,6 @@ public class CustomViewEngine : ViewEngineModel
     /// <summary>
     /// 设置默认值
     /// </summary>
-    /// <param name="column"></param>
     /// <returns></returns>
     public string GetAddDefaultValue()
     {

+ 1 - 4
Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs

@@ -97,10 +97,7 @@ public class SysCodeGenConfigService : IDynamicApiController, ITransient
             var codeGenConfig = new SysCodeGenConfig();
 
             var yesOrNo = YesNoEnum.Y.ToString();
-            if (Convert.ToBoolean(tableColumn.ColumnKey))
-            {
-                yesOrNo = YesNoEnum.N.ToString();
-            }
+            if (Convert.ToBoolean(tableColumn.ColumnKey)) yesOrNo = YesNoEnum.N.ToString();
 
             if (CodeGenUtil.IsCommonColumn(tableColumn.PropertyName))
             {

+ 1 - 2
Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs

@@ -78,8 +78,7 @@ public class SysCommonService : IDynamicApiController, ITransient
         var userId = App.User?.FindFirst(ClaimConst.UserId)?.Value;
         var resultStream = App.GetRequiredService<SysCacheService>().Get<MemoryStream>(CacheConst.KeyExcelTemp + userId);
 
-        if (resultStream == null)
-            throw Oops.Oh("错误标记文件已过期。");
+        if (resultStream == null) throw Oops.Oh("错误标记文件已过期。");
 
         return await Task.FromResult(new FileStreamResult(resultStream, "application/octet-stream")
         {

+ 11 - 12
Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs

@@ -61,8 +61,7 @@ public class SysConfigService : IDynamicApiController, ITransient
     public async Task AddConfig(AddConfigInput input)
     {
         var isExist = await _sysConfigRep.IsAnyAsync(u => u.Name == input.Name || u.Code == input.Code);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D9000);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D9000);
 
         await _sysConfigRep.InsertAsync(input.Adapt<SysConfig>());
     }
@@ -77,8 +76,7 @@ public class SysConfigService : IDynamicApiController, ITransient
     public async Task UpdateConfig(UpdateConfigInput input)
     {
         var isExist = await _sysConfigRep.IsAnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D9000);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D9000);
 
         var config = input.Adapt<SysConfig>();
         await _sysConfigRep.AsUpdateable(config).IgnoreColumns(true).ExecuteCommandAsync();
@@ -96,8 +94,9 @@ public class SysConfigService : IDynamicApiController, ITransient
     public async Task DeleteConfig(DeleteConfigInput input)
     {
         var config = await _sysConfigRep.GetFirstAsync(u => u.Id == input.Id);
-        if (config.SysFlag == YesNoEnum.Y) // 禁止删除系统参数
-            throw Oops.Oh(ErrorCodeEnum.D9001);
+        
+        // 禁止删除系统参数
+        if (config.SysFlag == YesNoEnum.Y) throw Oops.Oh(ErrorCodeEnum.D9001);
 
         await _sysConfigRep.DeleteAsync(config);
 
@@ -116,8 +115,9 @@ public class SysConfigService : IDynamicApiController, ITransient
         foreach (var id in ids)
         {
             var config = await _sysConfigRep.GetFirstAsync(u => u.Id == id);
-            if (config.SysFlag == YesNoEnum.Y) // 禁止删除系统参数
-                continue;
+            
+            // 禁止删除系统参数
+            if (config.SysFlag == YesNoEnum.Y) continue;
 
             await _sysConfigRep.DeleteAsync(config);
 
@@ -224,8 +224,8 @@ public class SysConfigService : IDynamicApiController, ITransient
         foreach (var Config in input)
         {
             var info = await _sysConfigRep.GetFirstAsync(c => c.Code == Config.Code);
-            if (info == null)
-                continue;
+            if (info == null) continue;
+            
             await _sysConfigRep.AsUpdateable().SetColumns(u => u.Value == Config.Value).Where(u => u.Code == Config.Code).ExecuteCommandAsync();
             Remove(info);
         }
@@ -297,8 +297,7 @@ public class SysConfigService : IDynamicApiController, ITransient
 
             // 创建文件夹
             var absoluteFileDir = Path.GetDirectoryName(absoluteFilePath);
-            if (!Directory.Exists(absoluteFileDir))
-                Directory.CreateDirectory(absoluteFileDir);
+            if (!Directory.Exists(absoluteFileDir)) Directory.CreateDirectory(absoluteFileDir);
 
             // 保存图标文件
             await File.WriteAllBytesAsync(absoluteFilePath, binData);

+ 12 - 12
Admin.NET/Admin.NET.Core/Service/Const/SysConstService.cs

@@ -27,19 +27,19 @@ public class SysConstService : IDynamicApiController, ITransient
     public async Task<List<ConstOutput>> GetList()
     {
         var key = $"{CacheConst.KeyConst}list";
-        var constlist = _sysCacheService.Get<List<ConstOutput>>(key);
-        if (constlist == null)
+        var constList = _sysCacheService.Get<List<ConstOutput>>(key);
+        if (constList == null)
         {
             var typeList = GetConstAttributeList();
-            constlist = typeList.Select(u => new ConstOutput
+            constList = typeList.Select(u => new ConstOutput
             {
                 Name = u.CustomAttributes.ToList().FirstOrDefault()?.ConstructorArguments.ToList().FirstOrDefault().Value?.ToString() ?? u.Name,
                 Code = u.Name,
                 Data = GetData(Convert.ToString(u.Name))
             }).ToList();
-            _sysCacheService.Set(key, constlist);
+            _sysCacheService.Set(key, constList);
         }
-        return await Task.FromResult(constlist);
+        return await Task.FromResult(constList);
     }
 
     /// <summary>
@@ -51,25 +51,25 @@ public class SysConstService : IDynamicApiController, ITransient
     public async Task<List<ConstOutput>> GetData([Required] string typeName)
     {
         var key = $"{CacheConst.KeyConst}{typeName.ToUpper()}";
-        var constlist = _sysCacheService.Get<List<ConstOutput>>(key);
-        if (constlist == null)
+        var constList = _sysCacheService.Get<List<ConstOutput>>(key);
+        if (constList == null)
         {
             var typeList = GetConstAttributeList();
             var type = typeList.FirstOrDefault(u => u.Name == typeName);
             if (type != null)
             {
-                var isEnum = type.BaseType.Name == "Enum";
-                constlist = type.GetFields()?
+                var isEnum = type.BaseType!.Name == "Enum";
+                constList = type.GetFields()?
                     .Where(isEnum, u => u.FieldType.Name == typeName)
                     .Select(u => new ConstOutput
                     {
                         Name = u.Name,
-                        Code = isEnum ? (int)u.GetValue(BindingFlags.Instance) : u.GetValue(BindingFlags.Instance)
+                        Code = isEnum ? (int)u.GetValue(BindingFlags.Instance)! : u.GetValue(BindingFlags.Instance)
                     }).ToList();
-                _sysCacheService.Set(key, constlist);
+                _sysCacheService.Set(key, constList);
             }
         }
-        return await Task.FromResult(constlist);
+        return await Task.FromResult(constList);
     }
 
     /// <summary>

+ 19 - 36
Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs

@@ -109,10 +109,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
     public List<DbColumnOutput> GetColumnList(string tableName, string configId = SqlSugarConst.MainConfigId)
     {
         var db = _db.AsTenant().GetConnectionScope(configId);
-        if (string.IsNullOrWhiteSpace(tableName))
-            return new List<DbColumnOutput>();
-
-        return db.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt<List<DbColumnOutput>>();
+        return string.IsNullOrWhiteSpace(tableName) ? new List<DbColumnOutput>() : db.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt<List<DbColumnOutput>>();
     }
 
     /// <summary>
@@ -149,8 +146,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
         var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
         db.DbMaintenance.AddColumn(input.TableName, column);
         db.DbMaintenance.AddColumnRemark(input.DbColumnName, input.TableName, input.ColumnDescription);
-        if (column.IsPrimarykey)
-            db.DbMaintenance.AddPrimaryKey(input.TableName, input.DbColumnName);
+        if (column.IsPrimarykey) db.DbMaintenance.AddPrimaryKey(input.TableName, input.DbColumnName);
     }
 
     /// <summary>
@@ -211,7 +207,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
         var typeBuilder = db.DynamicBuilder().CreateClass(input.TableName, new SugarTable() { TableName = input.TableName, TableDescription = input.Description });
         input.DbColumnInfoList.ForEach(u =>
         {
-            var dbColumnName = config.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(u.DbColumnName.Trim()) : u.DbColumnName.Trim();
+            var dbColumnName = config!.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(u.DbColumnName.Trim()) : u.DbColumnName.Trim();
             // 虚拟类都默认string类型,具体以列数据类型为准
             typeBuilder.CreateProperty(dbColumnName, typeof(string), new SugarColumn()
             {
@@ -357,7 +353,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
             if (entityTypes.Count == 1) // 只有一个实体匹配才能过滤
             {
                 // 获取实体的主键对应的属性名称
-                var pkInfo = entityTypes[0].GetProperties().Where(u => u.GetCustomAttribute<SugarColumn>() != null && u.GetCustomAttribute<SugarColumn>().IsPrimaryKey).First();
+                var pkInfo = entityTypes[0].GetProperties().FirstOrDefault(u => u.GetCustomAttribute<SugarColumn>()?.IsPrimaryKey == true);
                 if (pkInfo != null)
                 {
                     var seedDataTypes = App.EffectiveTypes
@@ -367,34 +363,29 @@ public class SysDatabaseService : IDynamicApiController, ITransient
                         )
                         .ToList();
                     // 可能会重名的种子数据不作为过滤项
-                    string doNotFilterfullName1 = $"{input.Position}.SeedData.{input.SeedDataName}";
-                    string doNotFilterfullName2 = $"{input.Position}.{input.SeedDataName}"; // Core中的命名空间没有SeedData
+                    string doNotFilterFullName1 = $"{input.Position}.SeedData.{input.SeedDataName}";
+                    string doNotFilterFullName2 = $"{input.Position}.{input.SeedDataName}"; // Core中的命名空间没有SeedData
 
                     PropertyInfo idPropertySeedData = records[0].GetType().GetProperty("Id");
 
                     for (int i = seedDataTypes.Count - 1; i >= 0; i--)
                     {
                         string fullName = seedDataTypes[i].FullName;
-                        if ((fullName == doNotFilterfullName1) || (fullName == doNotFilterfullName2))
-                            continue;
+                        if ((fullName == doNotFilterFullName1) || (fullName == doNotFilterFullName2)) continue;
+                        
                         // 删除重复数据
                         var instance = Activator.CreateInstance(seedDataTypes[i]);
                         var hasDataMethod = seedDataTypes[i].GetMethod("HasData");
                         var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
                         if (seedData == null) continue;
 
-                        List<object> recordsToRemove = new List<object>();
+                        List<object> recordsToRemove = new ();
                         foreach (var record in records)
                         {
                             object recordId = pkInfo.GetValue(record);
-                            foreach (var d1 in seedData)
+                            if (seedData.Select(d1 => idPropertySeedData.GetValue(d1)).Any(dataId => recordId != null && dataId != null && recordId.Equals(dataId)))
                             {
-                                object dataId = idPropertySeedData.GetValue(d1);
-                                if (recordId != null && dataId != null && recordId.Equals(dataId))
-                                {
-                                    recordsToRemove.Add(record);
-                                    break;
-                                }
+                                recordsToRemove.Add(record);
                             }
                         }
                         foreach (var itemToRemove in recordsToRemove)
@@ -506,26 +497,13 @@ public class SysDatabaseService : IDynamicApiController, ITransient
         var types = new List<Type>();
         if (_codeGenOptions.EntityAssemblyNames != null)
         {
-            foreach (var assemblyName in _codeGenOptions.EntityAssemblyNames)
+            foreach (var asm in _codeGenOptions.EntityAssemblyNames.Select(Assembly.Load))
             {
-                Assembly asm = Assembly.Load(assemblyName);
                 types.AddRange(asm.GetExportedTypes().ToList());
             }
         }
-        bool IsMyAttribute(Attribute[] o)
-        {
-            foreach (Attribute a in o)
-            {
-                if (a.GetType() == type)
-                    return true;
-            }
-            return false;
-        }
-        Type[] cosType = types.Where(o =>
-        {
-            return IsMyAttribute(Attribute.GetCustomAttributes(o, true));
-        }
-        ).ToArray();
+
+        Type[] cosType = types.Where(o => IsMyAttribute(Attribute.GetCustomAttributes(o, true))).ToArray();
 
         foreach (var c in cosType)
         {
@@ -546,6 +524,11 @@ public class SysDatabaseService : IDynamicApiController, ITransient
             });
         }
         return await Task.FromResult(entityInfos);
+
+        bool IsMyAttribute(Attribute[] o)
+        {
+            return o.Any(a => a.GetType() == type);
+        }
     }
 
     /// <summary>

+ 3 - 10
Admin.NET/Admin.NET.Core/Service/Enum/SysEnumService.cs

@@ -32,12 +32,7 @@ public class SysEnumService : IDynamicApiController, ITransient
             .OrderBy(u => u.Name).ThenBy(u => u.FullName)
             .ToList();
 
-        var result = new List<EnumTypeOutput>();
-        foreach (var item in enumTypeList)
-        {
-            result.Add(GetEnumDescription(item));
-        }
-        return result;
+        return enumTypeList.Select(GetEnumDescription).ToList();
     }
 
     /// <summary>
@@ -73,8 +68,7 @@ public class SysEnumService : IDynamicApiController, ITransient
     public List<EnumEntity> GetEnumDataList([FromQuery] EnumInput input)
     {
         var enumType = App.EffectiveTypes.FirstOrDefault(u => u.IsEnum && u.Name == input.EnumName);
-        if (enumType is not { IsEnum: true })
-            throw Oops.Oh(ErrorCodeEnum.D1503);
+        if (enumType is not { IsEnum: true }) throw Oops.Oh(ErrorCodeEnum.D1503);
 
         return enumType.EnumToList();
     }
@@ -92,8 +86,7 @@ public class SysEnumService : IDynamicApiController, ITransient
 
         // 获取字段类型
         var fieldType = entityType.GetProperties().FirstOrDefault(u => u.Name == input.FieldName)?.PropertyType;
-        if (fieldType is not { IsEnum: true })
-            throw Oops.Oh(ErrorCodeEnum.D1503);
+        if (fieldType is not { IsEnum: true }) throw Oops.Oh(ErrorCodeEnum.D1503);
 
         return fieldType.EnumToList();
     }

+ 51 - 79
Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs

@@ -93,14 +93,11 @@ public class SysFileService : IDynamicApiController, ITransient
     /// <param name="files"></param>
     /// <returns></returns>
     [DisplayName("上传多文件")]
-    public async Task<List<SysFile>> UploadFiles([Required] List<IFormFile> files)
+    public List<SysFile> UploadFiles([Required] List<IFormFile> files)
     {
-        var filelist = new List<SysFile>();
-        foreach (var file in files)
-        {
-            filelist.Add(await UploadFile(new UploadFileInput { File = file }));
-        }
-        return filelist;
+        var fileList = new List<SysFile>();
+        files.ForEach(file => fileList.Add(UploadFile(new UploadFileInput { File = file }).Result));
+        return fileList;
     }
 
     /// <summary>
@@ -113,26 +110,7 @@ public class SysFileService : IDynamicApiController, ITransient
     {
         var file = input.Id > 0 ? await GetFile(input.Id) : await _sysFileRep.CopyNew().GetFirstAsync(u => u.Url == input.Url);
         var fileName = HttpUtility.UrlEncode(file.FileName, Encoding.GetEncoding("UTF-8"));
-        var filePath = Path.Combine(file.FilePath, file.Id.ToString() + file.Suffix);
-
-        if (_OSSProviderOptions.Enabled)
-        {
-            var stream = await (await _OSSService.PresignedGetObjectAsync(file.BucketName.ToString(), filePath, 5)).GetAsStreamAsync();
-            return new FileStreamResult(stream.Stream, "application/octet-stream") { FileDownloadName = fileName + file.Suffix };
-        }
-        else if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
-        {
-            using (SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
-               App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]))
-            {
-                return new FileStreamResult(helper.OpenRead(filePath), "application/octet-stream") { FileDownloadName = fileName + file.Suffix };
-            }
-        }
-        else
-        {
-            var path = Path.Combine(App.WebHostEnvironment.WebRootPath, filePath);
-            return new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName + file.Suffix };
-        }
+        return await GetFileStreamResult(file, fileName);
     }
 
     /// <summary>
@@ -144,27 +122,34 @@ public class SysFileService : IDynamicApiController, ITransient
     public async Task<IActionResult> GetPreview([FromRoute] long id)
     {
         var file = await GetFile(id);
-        //var fileName = HttpUtility.UrlEncode(file.FileName, Encoding.GetEncoding("UTF-8"));
-        var filePath = Path.Combine(file.FilePath, file.Id.ToString() + file.Suffix);
+        return await GetFileStreamResult(file, file.Id + "");
+    }
 
+    /// <summary>
+    /// 获取文件流
+    /// </summary>
+    /// <param name="file"></param>
+    /// <param name="fileName"></param>
+    /// <returns></returns>
+    [NonAction]
+    public async Task<IActionResult> GetFileStreamResult(SysFile file, string fileName)
+    {
+        var filePath = Path.Combine(file.FilePath ?? "", file.Id + file.Suffix);
         if (_OSSProviderOptions.Enabled)
         {
-            var stream = await (await _OSSService.PresignedGetObjectAsync(file.BucketName.ToString(), filePath, 5)).GetAsStreamAsync();
-            return new FileStreamResult(stream.Stream, "application/octet-stream");
-        }
-        else if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
-        {
-            using (SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
-               App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]))
-            {
-                return new FileStreamResult(helper.OpenRead(filePath), "application/octet-stream");
-            }
+            var stream = await (await _OSSService.PresignedGetObjectAsync(file.BucketName, filePath, 5)).GetAsStreamAsync();
+            return new FileStreamResult(stream.Stream, "application/octet-stream") { FileDownloadName = fileName + file.Suffix };
         }
-        else
+
+        if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
         {
-            var path = Path.Combine(App.WebHostEnvironment.WebRootPath, filePath);
-            return new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream");
+            using SSHHelper helper = new(App.Configuration["SSHProvider:Host"],
+                App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]);
+            return new FileStreamResult(helper.OpenRead(filePath), "application/octet-stream") { FileDownloadName = fileName + file.Suffix };
         }
+
+        var path = Path.Combine(App.WebHostEnvironment.WebRootPath, filePath);
+        return new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName + file.Suffix };
     }
 
     /// <summary>
@@ -185,19 +170,15 @@ public class SysFileService : IDynamicApiController, ITransient
                 byte[] fileBytes = await response.Content.ReadAsByteArrayAsync();
                 return Convert.ToBase64String(fileBytes);
             }
-            else
-            {
-                throw new HttpRequestException($"Request failed with status code: {response.StatusCode}");
-            }
+            throw new HttpRequestException($"Request failed with status code: {response.StatusCode}");
         }
-        else if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
+
+        if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
         {
             var sysFile = await _sysFileRep.CopyNew().GetFirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
-            using (SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
-               App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]))
-            {
-                return Convert.ToBase64String(helper.ReadAllBytes(sysFile.FilePath));
-            }
+            using SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
+                App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]);
+            return Convert.ToBase64String(helper.ReadAllBytes(sysFile.FilePath));
         }
         else
         {
@@ -212,7 +193,7 @@ public class SysFileService : IDynamicApiController, ITransient
                 Log.Error($"DownloadFileBase64:文件[{realFile}]不存在");
                 throw Oops.Oh($"文件[{sysFile.FilePath}]不存在");
             }
-            byte[] fileBytes = File.ReadAllBytes(realFile);
+            byte[] fileBytes = await File.ReadAllBytesAsync(realFile);
             return Convert.ToBase64String(fileBytes);
         }
     }
@@ -233,22 +214,19 @@ public class SysFileService : IDynamicApiController, ITransient
 
             if (_OSSProviderOptions.Enabled)
             {
-                await _OSSService.RemoveObjectAsync(file.BucketName.ToString(), string.Concat(file.FilePath, "/", $"{input.Id}{file.Suffix}"));
+                await _OSSService.RemoveObjectAsync(file.BucketName, string.Concat(file.FilePath, "/", $"{input.Id}{file.Suffix}"));
             }
             else if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
             {
                 var fullPath = string.Concat(file.FilePath, "/", file.Id + file.Suffix);
-                using (SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
-                   App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]))
-                {
-                    helper.DeleteFile(fullPath);
-                }
+                using SSHHelper helper = new(App.Configuration["SSHProvider:Host"],
+                    App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]);
+                helper.DeleteFile(fullPath);
             }
             else
             {
-                var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FilePath, input.Id.ToString() + file.Suffix);
-                if (File.Exists(filePath))
-                    File.Delete(filePath);
+                var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FilePath ?? "", input.Id + file.Suffix);
+                if (File.Exists(filePath)) File.Delete(filePath);
             }
         }
     }
@@ -295,7 +273,7 @@ public class SysFileService : IDynamicApiController, ITransient
         var fileMd5 = string.Empty;
         if (_uploadOptions.EnableMd5)
         {
-            using (var fileStream = input.File.OpenReadStream())
+            await using (var fileStream = input.File.OpenReadStream())
             {
                 fileMd5 = OssUtils.ComputeContentMd5(fileStream, fileStream.Length);
             }
@@ -306,12 +284,10 @@ public class SysFileService : IDynamicApiController, ITransient
         }
 
         // 验证文件类型
-        if (!_uploadOptions.ContentType.Contains(input.File.ContentType))
-            throw Oops.Oh($"{ErrorCodeEnum.D8001}:{input.File.ContentType}");
+        if (!_uploadOptions.ContentType.Contains(input.File.ContentType)) throw Oops.Oh($"{ErrorCodeEnum.D8001}:{input.File.ContentType}");
 
         // 验证文件大小
-        if (sizeKb > _uploadOptions.MaxSize)
-            throw Oops.Oh($"{ErrorCodeEnum.D8002},允许最大:{_uploadOptions.MaxSize}KB");
+        if (sizeKb > _uploadOptions.MaxSize) throw Oops.Oh($"{ErrorCodeEnum.D8002},允许最大:{_uploadOptions.MaxSize}KB");
 
         // 获取文件后缀
         var suffix = Path.GetExtension(input.File.FileName).ToLower(); // 后缀
@@ -325,12 +301,10 @@ public class SysFileService : IDynamicApiController, ITransient
             if (suffix == ".jpeg" || suffix == ".jpe")
                 suffix = ".jpg";
         }
-        if (string.IsNullOrWhiteSpace(suffix))
-            throw Oops.Oh(ErrorCodeEnum.D8003);
+        if (string.IsNullOrWhiteSpace(suffix)) throw Oops.Oh(ErrorCodeEnum.D8003);
 
         // 防止客户端伪造文件类型
-        if (!string.IsNullOrWhiteSpace(input.AllowSuffix) && !input.AllowSuffix.Contains(suffix))
-            throw Oops.Oh(ErrorCodeEnum.D8003);
+        if (!string.IsNullOrWhiteSpace(input.AllowSuffix) && !input.AllowSuffix.Contains(suffix)) throw Oops.Oh(ErrorCodeEnum.D8003);
         //if (!VerifyFileExtensionName.IsSameType(file.OpenReadStream(), suffix))
         //    throw Oops.Oh(ErrorCodeEnum.D8001);
 
@@ -379,11 +353,9 @@ public class SysFileService : IDynamicApiController, ITransient
         else if (App.Configuration["SSHProvider:Enabled"].ToBoolean())
         {
             var fullPath = string.Concat(path.StartsWith('/') ? path : "/" + path, "/", finalName);
-            using (SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
-               App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]))
-            {
-                helper.UploadFile(input.File.OpenReadStream(), fullPath);
-            }
+            using SSHHelper helper = new(App.Configuration["SSHProvider:Host"],
+                App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]);
+            helper.UploadFile(input.File.OpenReadStream(), fullPath);
         }
         else
         {
@@ -393,7 +365,7 @@ public class SysFileService : IDynamicApiController, ITransient
                 Directory.CreateDirectory(filePath);
 
             var realFile = Path.Combine(filePath, finalName);
-            using (var stream = File.Create(realFile))
+            await using (var stream = File.Create(realFile))
             {
                 await input.File.CopyToAsync(stream);
             }
@@ -479,8 +451,8 @@ public class SysFileService : IDynamicApiController, ITransient
     public async Task<List<SysFile>> GetRelationFiles([FromQuery] RelationQueryInput input)
     {
         return await _sysFileRep.AsQueryable()
-            .WhereIF(input.RelationId.HasValue && input.RelationId > 0, u => u.RelationId == input.RelationId)
-            .WhereIF(input.BelongId.HasValue && input.BelongId > 0, u => u.BelongId == input.BelongId.Value)
+            .WhereIF(input.RelationId is > 0, u => u.RelationId == input.RelationId)
+            .WhereIF(input.BelongId is > 0, u => u.BelongId == input.BelongId.Value)
             .WhereIF(!string.IsNullOrWhiteSpace(input.RelationName), u => u.RelationName == input.RelationName)
             .WhereIF(!string.IsNullOrWhiteSpace(input.FileTypes), u => input.GetFileTypeBS().Contains(u.FileType))
             .Select(u => new SysFile

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs

@@ -33,7 +33,7 @@ public class DbJobPersistence : IJobPersistence
         // 获取所有定义的作业
         var allJobs = App.EffectiveTypes.ScanToBuilders().ToList();
         // 若数据库不存在任何作业,则直接返回
-        if (!db.Queryable<SysJobDetail>().Any(u => true)) return allJobs;
+        if (!await db.Queryable<SysJobDetail>().AnyAsync(u => true, stoppingToken)) return allJobs;
 
         // 遍历所有定义的作业
         foreach (var schedulerBuilder in allJobs)

+ 12 - 21
Admin.NET/Admin.NET.Core/Service/Job/JobClusterServer.cs

@@ -11,11 +11,8 @@ namespace Admin.NET.Core.Service;
 /// </summary>
 public class JobClusterServer : IJobClusterServer
 {
-    private readonly Random rd = new(DateTime.Now.Millisecond);
-
-    public JobClusterServer()
-    {
-    }
+    private static readonly SqlSugarRepository<SysJobCluster> SysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
+    private readonly Random _random = new(DateTime.Now.Millisecond);
 
     /// <summary>
     /// 当前作业调度器启动通知
@@ -23,15 +20,14 @@ public class JobClusterServer : IJobClusterServer
     /// <param name="context">作业集群服务上下文</param>
     public async void Start(JobClusterContext context)
     {
-        var _sysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
         // 在作业集群表中,如果 clusterId 不存在,则新增一条(否则更新一条),并设置 status 为 ClusterStatus.Waiting
-        if (await _sysJobClusterRep.IsAnyAsync(u => u.ClusterId == context.ClusterId))
+        if (await SysJobClusterRep.IsAnyAsync(u => u.ClusterId == context.ClusterId))
         {
-            await _sysJobClusterRep.AsUpdateable().SetColumns(u => u.Status == ClusterStatus.Waiting).Where(u => u.ClusterId == context.ClusterId).ExecuteCommandAsync();
+            await SysJobClusterRep.AsUpdateable().SetColumns(u => u.Status == ClusterStatus.Waiting).Where(u => u.ClusterId == context.ClusterId).ExecuteCommandAsync();
         }
         else
         {
-            await _sysJobClusterRep.AsInsertable(new SysJobCluster { ClusterId = context.ClusterId, Status = ClusterStatus.Waiting }).ExecuteCommandAsync();
+            await SysJobClusterRep.AsInsertable(new SysJobCluster { ClusterId = context.ClusterId, Status = ClusterStatus.Waiting }).ExecuteCommandAsync();
         }
     }
 
@@ -47,21 +43,19 @@ public class JobClusterServer : IJobClusterServer
         while (true)
         {
             // 控制集群心跳频率(放在头部为了防止 IsAnyAsync continue 没sleep占用大量IO和CPU)
-            await Task.Delay(3000 + rd.Next(500, 1000)); // 错开集群同时启动
+            await Task.Delay(3000 + _random.Next(500, 1000)); // 错开集群同时启动
 
             try
             {
-                ICache _cache = App.GetRequiredService<ICacheProvider>().Cache;
+                ICache cache = App.GetRequiredService<ICacheProvider>().Cache;
                 // 使用分布式锁
-                using (_cache.AcquireLock("lock:JobClusterServer:WaitingForAsync", 1000))
+                using (cache.AcquireLock("lock:JobClusterServer:WaitingForAsync", 1000))
                 {
-                    var _sysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
                     // 在这里查询数据库,根据以下两种情况处理
                     // 1) 如果作业集群表已有 status 为 ClusterStatus.Working 则继续循环
                     // 2) 如果作业集群表中还没有其他服务或只有自己,则插入一条集群服务或调用 await WorkNowAsync(clusterId); 之后 return;
                     // 3) 如果作业集群表中没有 status 为 ClusterStatus.Working 的,调用 await WorkNowAsync(clusterId); 之后 return;
-                    if (await _sysJobClusterRep.IsAnyAsync(u => u.Status == ClusterStatus.Working))
-                        continue;
+                    if (await SysJobClusterRep.IsAnyAsync(u => u.Status == ClusterStatus.Working)) continue;
 
                     await WorkNowAsync(clusterId);
                     return;
@@ -77,9 +71,8 @@ public class JobClusterServer : IJobClusterServer
     /// <param name="context">作业集群服务上下文</param>
     public async void Stop(JobClusterContext context)
     {
-        var _sysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
         // 在作业集群表中,更新 clusterId 的 status 为 ClusterStatus.Crashed
-        await _sysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Crashed }, u => u.ClusterId == context.ClusterId);
+        await SysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Crashed }, u => u.ClusterId == context.ClusterId);
     }
 
     /// <summary>
@@ -88,9 +81,8 @@ public class JobClusterServer : IJobClusterServer
     /// <param name="context">作业集群服务上下文</param>
     public async void Crash(JobClusterContext context)
     {
-        var _sysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
         // 在作业集群表中,更新 clusterId 的 status 为 ClusterStatus.Crashed
-        await _sysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Crashed }, u => u.ClusterId == context.ClusterId);
+        await SysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Crashed }, u => u.ClusterId == context.ClusterId);
     }
 
     /// <summary>
@@ -100,8 +92,7 @@ public class JobClusterServer : IJobClusterServer
     /// <returns></returns>
     private static async Task WorkNowAsync(string clusterId)
     {
-        var _sysJobClusterRep = App.GetRequiredService<SqlSugarRepository<SysJobCluster>>();
         // 在作业集群表中,更新 clusterId 的 status 为 ClusterStatus.Working
-        await _sysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Working }, u => u.ClusterId == clusterId);
+        await SysJobClusterRep.UpdateAsync(u => new SysJobCluster { Status = ClusterStatus.Working }, u => u.ClusterId == clusterId);
     }
 }

+ 3 - 4
Admin.NET/Admin.NET.Core/Service/Job/JobMonitor.cs

@@ -12,14 +12,13 @@ namespace Admin.NET.Core.Service;
 public class JobMonitor : IJobMonitor
 {
     private readonly IEventPublisher _eventPublisher;
-    private readonly IServiceScope _serviceScope;
     private readonly SysConfigService _sysConfigService;
 
     public JobMonitor(IServiceScopeFactory scopeFactory)
     {
-        _serviceScope = scopeFactory.CreateScope();
-        _sysConfigService = _serviceScope.ServiceProvider.GetRequiredService<SysConfigService>();
-        _eventPublisher = _serviceScope.ServiceProvider.GetRequiredService<IEventPublisher>(); ;
+        var serviceScope = scopeFactory.CreateScope();
+        _sysConfigService = serviceScope.ServiceProvider.GetRequiredService<SysConfigService>();
+        _eventPublisher = serviceScope.ServiceProvider.GetRequiredService<IEventPublisher>(); ;
     }
 
     public Task OnExecutingAsync(JobExecutingContext context, CancellationToken stoppingToken)

+ 9 - 19
Admin.NET/Admin.NET.Core/Service/Job/SysJobService.cs

@@ -83,8 +83,7 @@ public class SysJobService : IDynamicApiController, ITransient
     public async Task AddJobDetail(AddJobDetailInput input)
     {
         var isExist = await _sysJobDetailRep.IsAnyAsync(u => u.JobId == input.JobId && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1006);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
 
         // 动态创建作业
         Type jobType;
@@ -110,9 +109,7 @@ public class SysJobService : IDynamicApiController, ITransient
                 throw new NotSupportedException();
         }
 
-        _schedulerFactory.AddJob(
-            JobBuilder.Create(jobType)
-                .LoadFrom(input.Adapt<SysJobDetail>()).SetJobType(jobType));
+        _schedulerFactory.AddJob( JobBuilder.Create(jobType).LoadFrom(input.Adapt<SysJobDetail>() ).SetJobType(jobType));
 
         // 延迟一下等待持久化写入,再执行其他字段的更新
         await Task.Delay(500);
@@ -130,12 +127,10 @@ public class SysJobService : IDynamicApiController, ITransient
     public async Task UpdateJobDetail(UpdateJobDetailInput input)
     {
         var isExist = await _sysJobDetailRep.IsAnyAsync(u => u.JobId == input.JobId && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1006);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
 
         var sysJobDetail = await _sysJobDetailRep.GetFirstAsync(u => u.Id == input.Id);
-        if (sysJobDetail.JobId != input.JobId)
-            throw Oops.Oh(ErrorCodeEnum.D1704);
+        if (sysJobDetail.JobId != input.JobId) throw Oops.Oh(ErrorCodeEnum.D1704);
 
         var scheduler = _schedulerFactory.GetJob(sysJobDetail.JobId);
         var oldScriptCode = sysJobDetail.ScriptCode; // 旧脚本代码
@@ -143,8 +138,7 @@ public class SysJobService : IDynamicApiController, ITransient
 
         if (input.CreateType == JobCreateTypeEnum.Script)
         {
-            if (string.IsNullOrEmpty(input.ScriptCode))
-                throw Oops.Oh(ErrorCodeEnum.D1701);
+            if (string.IsNullOrEmpty(input.ScriptCode)) throw Oops.Oh(ErrorCodeEnum.D1701);
 
             if (input.ScriptCode != oldScriptCode)
             {
@@ -153,8 +147,7 @@ public class SysJobService : IDynamicApiController, ITransient
 
                 if (jobType.GetCustomAttributes(typeof(JobDetailAttribute)).FirstOrDefault() is not JobDetailAttribute jobDetailAttribute)
                     throw Oops.Oh(ErrorCodeEnum.D1702);
-                if (jobDetailAttribute.JobId != input.JobId)
-                    throw Oops.Oh(ErrorCodeEnum.D1703);
+                if (jobDetailAttribute.JobId != input.JobId) throw Oops.Oh(ErrorCodeEnum.D1703);
 
                 scheduler?.UpdateDetail(JobBuilder.Create(jobType).LoadFrom(sysJobDetail).SetJobType(jobType));
             }
@@ -205,8 +198,7 @@ public class SysJobService : IDynamicApiController, ITransient
     public async Task AddJobTrigger(AddJobTriggerInput input)
     {
         var isExist = await _sysJobTriggerRep.IsAnyAsync(u => u.TriggerId == input.TriggerId && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1006);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
 
         var jobTrigger = input.Adapt<SysJobTrigger>();
         jobTrigger.Args = "[" + jobTrigger.Args + "]";
@@ -224,8 +216,7 @@ public class SysJobService : IDynamicApiController, ITransient
     public async Task UpdateJobTrigger(UpdateJobTriggerInput input)
     {
         var isExist = await _sysJobTriggerRep.IsAnyAsync(u => u.TriggerId == input.TriggerId && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1006);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1006);
 
         var jobTrigger = input.Adapt<SysJobTrigger>();
         jobTrigger.Args = "[" + jobTrigger.Args + "]";
@@ -303,8 +294,7 @@ public class SysJobService : IDynamicApiController, ITransient
     [DisplayName("执行作业")]
     public void RunJob(JobDetailInput input)
     {
-        if (_schedulerFactory.TryRunJob(input.JobId, out _) != ScheduleResult.Succeed)
-            throw Oops.Oh(ErrorCodeEnum.D1705);
+        if (_schedulerFactory.TryRunJob(input.JobId, out _) != ScheduleResult.Succeed) throw Oops.Oh(ErrorCodeEnum.D1705);
     }
 
     /// <summary>

+ 16 - 18
Admin.NET/Admin.NET.Core/Service/Menu/SysMenuService.cs

@@ -242,17 +242,16 @@ public class SysMenuService : IDynamicApiController, ITransient
     {
         var userId = _userManager.UserId;
         var permissions = _sysCacheService.Get<List<string>>(CacheConst.KeyUserButton + userId);
-        if (permissions == null)
-        {
-            var menuIdList = _userManager.SuperAdmin ? new List<long>() : await GetMenuIdList();
-            permissions = menuIdList.Count > 0 || _userManager.SuperAdmin
-                ? await _sysMenuRep.AsQueryable()
-                    .Where(u => u.Type == MenuTypeEnum.Btn)
-                    .WhereIF(menuIdList.Count > 0, u => menuIdList.Contains(u.Id))
-                    .Select(u => u.Permission).ToListAsync()
-                : new List<string>();
-            _sysCacheService.Set(CacheConst.KeyUserButton + userId, permissions, TimeSpan.FromDays(7));
-        }
+        if (permissions != null) return permissions;
+
+        var menuIdList = _userManager.SuperAdmin ? new() : await GetMenuIdList();
+        permissions = menuIdList.Count > 0 || _userManager.SuperAdmin
+            ? await _sysMenuRep.AsQueryable()
+                .Where(u => u.Type == MenuTypeEnum.Btn)
+                .WhereIF(menuIdList.Count > 0, u => menuIdList.Contains(u.Id))
+                .Select(u => u.Permission).ToListAsync()
+            : new();
+        _sysCacheService.Set(CacheConst.KeyUserButton + userId, permissions, TimeSpan.FromDays(7));
 
         return permissions;
     }
@@ -265,13 +264,12 @@ public class SysMenuService : IDynamicApiController, ITransient
     public async Task<List<string>> GetAllBtnPermList()
     {
         var permissions = _sysCacheService.Get<List<string>>(CacheConst.KeyUserButton + 0);
-        if (permissions == null || permissions.Count == 0)
-        {
-            permissions = await _sysMenuRep.AsQueryable()
-                .Where(u => u.Type == MenuTypeEnum.Btn)
-                .Select(u => u.Permission).ToListAsync();
-            _sysCacheService.Set(CacheConst.KeyUserButton + 0, permissions);
-        }
+        if (permissions != null && permissions.Count != 0) return permissions;
+
+        permissions = await _sysMenuRep.AsQueryable()
+            .Where(u => u.Type == MenuTypeEnum.Btn)
+            .Select(u => u.Permission).ToListAsync();
+        _sysCacheService.Set(CacheConst.KeyUserButton + 0, permissions);
 
         return permissions;
     }

+ 6 - 4
Admin.NET/Admin.NET.Core/Service/Message/SysEmailService.cs

@@ -37,11 +37,13 @@ public class SysEmailService : IDynamicApiController, ITransient
         var webTitle = await _sysConfigService.GetConfigValue<string>(ConfigConst.SysWebTitle);
         title = string.IsNullOrWhiteSpace(title) ? $"{webTitle} 系统邮件" : title;
         var message = new MimeMessage();
+        
         message.From.Add(new MailboxAddress(_emailOptions.DefaultFromEmail, _emailOptions.DefaultFromEmail));
-        if (string.IsNullOrWhiteSpace(toEmail))
-            message.To.Add(new MailboxAddress(_emailOptions.DefaultToEmail, _emailOptions.DefaultToEmail));
-        else
-            message.To.Add(new MailboxAddress(toEmail, toEmail));
+        
+        message.To.Add(string.IsNullOrWhiteSpace(toEmail)
+            ? new MailboxAddress(_emailOptions.DefaultToEmail, _emailOptions.DefaultToEmail)
+            : new MailboxAddress(toEmail, toEmail));
+        
         message.Subject = title;
         message.Body = new TextPart("html")
         {

+ 7 - 10
Admin.NET/Admin.NET.Core/Service/Message/SysMessageService.cs

@@ -16,15 +16,12 @@ public class SysMessageService : IDynamicApiController, ITransient
 {
     private readonly SysCacheService _sysCacheService;
     private readonly IHubContext<OnlineUserHub, IOnlineUserHub> _chatHubContext;
-    private readonly SysConfigService _sysConfigService;
 
     public SysMessageService(SysCacheService sysCacheService,
-        IHubContext<OnlineUserHub, IOnlineUserHub> chatHubContext,
-        SysConfigService sysConfigService)
+        IHubContext<OnlineUserHub, IOnlineUserHub> chatHubContext)
     {
         _sysCacheService = sysCacheService;
         _chatHubContext = chatHubContext;
-        _sysConfigService = sysConfigService;
     }
 
     /// <summary>
@@ -47,8 +44,8 @@ public class SysMessageService : IDynamicApiController, ITransient
     public async Task SendOtherUser(MessageInput input)
     {
         var hashKey = _sysCacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
-        var exceptRecevieUsers = hashKey.Where(u => u.Value.UserId == input.ReceiveUserId).Select(u => u.Value).ToList();
-        await _chatHubContext.Clients.AllExcept(exceptRecevieUsers.Select(t => t.ConnectionId)).ReceiveMessage(input);
+        var exceptReceiveUsers = hashKey.Where(u => u.Value.UserId == input.ReceiveUserId).Select(u => u.Value).ToList();
+        await _chatHubContext.Clients.AllExcept(exceptReceiveUsers.Select(t => t.ConnectionId)).ReceiveMessage(input);
     }
 
     /// <summary>
@@ -60,8 +57,8 @@ public class SysMessageService : IDynamicApiController, ITransient
     public async Task SendUser(MessageInput input)
     {
         var hashKey = _sysCacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
-        var recevieUsers = hashKey.Where(u => u.Value.UserId == input.ReceiveUserId).Select(u => u.Value).ToList();
-        await recevieUsers.ForEachAsync(u => _chatHubContext.Clients.Client(u.ConnectionId).ReceiveMessage(input));
+        var receiveUsers = hashKey.Where(u => u.Value.UserId == input.ReceiveUserId).Select(u => u.Value).ToList();
+        await receiveUsers.ForEachAsync(u => _chatHubContext.Clients.Client(u.ConnectionId ?? "").ReceiveMessage(input));
     }
 
     /// <summary>
@@ -73,7 +70,7 @@ public class SysMessageService : IDynamicApiController, ITransient
     public async Task SendUsers(MessageInput input)
     {
         var hashKey = _sysCacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
-        var recevieUsers = hashKey.Where(u => input.UserIds.Any(a => a == u.Value.UserId)).Select(u => u.Value).ToList();
-        await recevieUsers.ForEachAsync(u => _chatHubContext.Clients.Client(u.ConnectionId).ReceiveMessage(input));
+        var receiveUsers = hashKey.Where(u => input.UserIds.Any(a => a == u.Value.UserId)).Select(u => u.Value).ToList();
+        await receiveUsers.ForEachAsync(u => _chatHubContext.Clients.Client(u.ConnectionId ?? "").ReceiveMessage(input));
     }
 }

+ 8 - 12
Admin.NET/Admin.NET.Core/Service/Message/SysSmsService.cs

@@ -53,10 +53,10 @@ public class SysSmsService : IDynamicApiController, ITransient
     public bool VerifyCode(SmsVerifyCodeInput input)
     {
         var verifyCode = _sysCacheService.Get<string>($"{CacheConst.KeyPhoneVerCode}{input.Phone}");
-        if (string.IsNullOrWhiteSpace(verifyCode))
-            throw Oops.Oh("验证码不存在或已失效,请重新获取!");
-        if (verifyCode != input.Code)
-            throw Oops.Oh("验证码错误!");
+        
+        if (string.IsNullOrWhiteSpace(verifyCode)) throw Oops.Oh("验证码不存在或已失效,请重新获取!");
+        
+        if (verifyCode != input.Code) throw Oops.Oh("验证码错误!");
 
         return true;
     }
@@ -70,8 +70,7 @@ public class SysSmsService : IDynamicApiController, ITransient
     [DisplayName("阿里云发送短信")]
     public async Task AliyunSendSms([Required] string phoneNumber)
     {
-        if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid)
-            throw Oops.Oh("请正确填写手机号码");
+        if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid) throw Oops.Oh("请正确填写手机号码");
 
         // 生成随机验证码
         var random = new Random();
@@ -116,11 +115,9 @@ public class SysSmsService : IDynamicApiController, ITransient
     [DisplayName("发送短信模板")]
     public async Task AliyunSendSmsTemplate([Required] string phoneNumber, [Required] dynamic templateParam)
     {
-        if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid)
-            throw Oops.Oh("请正确填写手机号码");
+        if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid) throw Oops.Oh("请正确填写手机号码");
 
-        if (string.IsNullOrWhiteSpace(templateParam.ToString()))
-            throw Oops.Oh("短信内容不能为空");
+        if (string.IsNullOrWhiteSpace(templateParam.ToString())) throw Oops.Oh("短信内容不能为空");
 
         var client = CreateAliyunClient();
         var template = _smsOptions.Aliyun.GetTemplate();
@@ -153,8 +150,7 @@ public class SysSmsService : IDynamicApiController, ITransient
     [DisplayName("腾讯云发送短信")]
     public async Task TencentSendSms([Required] string phoneNumber)
     {
-        if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid)
-            throw Oops.Oh("请正确填写手机号码");
+        if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid) throw Oops.Oh("请正确填写手机号码");
 
         // 生成随机验证码
         var random = new Random();

+ 4 - 4
Admin.NET/Admin.NET.Core/Service/Notice/SysNoticeService.cs

@@ -91,10 +91,10 @@ public class SysNoticeService : IDynamicApiController, ITransient
     public async Task DeleteNotice(DeleteNoticeInput input)
     {
         var sysNotice = await _sysNoticeRep.GetByIdAsync(input.Id);
-        if (sysNotice.CreateUserId != _userManager.UserId)
-            throw Oops.Oh(ErrorCodeEnum.D7003);
-        if (sysNotice.Status == NoticeStatusEnum.PUBLIC)
-            throw Oops.Oh(ErrorCodeEnum.D7001);
+        
+        if (sysNotice.CreateUserId != _userManager.UserId) throw Oops.Oh(ErrorCodeEnum.D7003);
+        
+        if (sysNotice.Status == NoticeStatusEnum.PUBLIC) throw Oops.Oh(ErrorCodeEnum.D7001);
 
         await _sysNoticeRep.DeleteAsync(u => u.Id == input.Id);
 

+ 4 - 4
Admin.NET/Admin.NET.Core/Service/OAuth/OAuthSetup.cs

@@ -31,13 +31,13 @@ public static class OAuthSetup
             })
             .AddWeixin(options =>
             {
-                options.ClientId = authOpt.Weixin?.ClientId;
-                options.ClientSecret = authOpt.Weixin?.ClientSecret;
+                options.ClientId = authOpt.Weixin?.ClientId!;
+                options.ClientSecret = authOpt.Weixin?.ClientSecret!;
             })
             .AddGitee(options =>
             {
-                options.ClientId = authOpt.Gitee?.ClientId;
-                options.ClientSecret = authOpt.Gitee?.ClientSecret;
+                options.ClientId = authOpt.Gitee?.ClientId!;
+                options.ClientSecret = authOpt.Gitee?.ClientSecret!;
 
                 options.ClaimActions.MapJsonKey(OAuthClaim.GiteeAvatarUrl, "avatar_url");
             });

+ 7 - 4
Admin.NET/Admin.NET.Core/Service/OAuth/SysOAuthService.cs

@@ -39,10 +39,13 @@ public class SysOAuthService : IDynamicApiController, ITransient
         if (string.IsNullOrWhiteSpace(provider) || !await _httpContextAccessor.HttpContext.IsProviderSupportedAsync(provider))
             throw Oops.Oh("不支持的OAuth类型");
 
-        var request = _httpContextAccessor.HttpContext.Request;
+        var request = _httpContextAccessor.HttpContext!.Request;
         var url = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}Callback?provider={provider}&redirectUrl={redirectUrl}";
-        var properties = new AuthenticationProperties { RedirectUri = url };
-        properties.Items["LoginProvider"] = provider;
+        var properties = new AuthenticationProperties
+        {
+            RedirectUri = url,
+            Items = { ["LoginProvider"] = provider }
+        };
         return await Task.FromResult(new ChallengeResult(provider, properties));
     }
 
@@ -59,7 +62,7 @@ public class SysOAuthService : IDynamicApiController, ITransient
         if (string.IsNullOrWhiteSpace(provider) || !await _httpContextAccessor.HttpContext.IsProviderSupportedAsync(provider))
             throw Oops.Oh("不支持的OAuth类型");
 
-        var authenticateResult = await _httpContextAccessor.HttpContext.AuthenticateAsync(provider);
+        var authenticateResult = await _httpContextAccessor.HttpContext!.AuthenticateAsync(provider);
         if (!authenticateResult.Succeeded)
             throw Oops.Oh("授权失败");
 

+ 2 - 2
Admin.NET/Admin.NET.Core/Service/OnlineUser/SysOnlineUserService.cs

@@ -49,7 +49,7 @@ public class SysOnlineUserService : IDynamicApiController, ITransient
     [DisplayName("强制下线")]
     public async Task ForceOffline(SysOnlineUser user)
     {
-        await _onlineUserHubContext.Clients.Client(user.ConnectionId).ForceOffline("强制下线");
+        await _onlineUserHubContext.Clients.Client(user.ConnectionId ?? "").ForceOffline("强制下线");
         await _sysOnlineUerRep.DeleteAsync(user);
     }
 
@@ -67,7 +67,7 @@ public class SysOnlineUserService : IDynamicApiController, ITransient
 
         foreach (var item in userList)
         {
-            await _onlineUserHubContext.Clients.Client(item.ConnectionId).PublicNotice(notice);
+            await _onlineUserHubContext.Clients.Client(item.ConnectionId ?? "").PublicNotice(notice);
         }
     }
 

+ 53 - 57
Admin.NET/Admin.NET.Core/Service/Org/SysOrgService.cs

@@ -56,7 +56,7 @@ public class SysOrgService : IDynamicApiController, ITransient
                 .ToListAsync();
         }
 
-        var orgTree = new List<SysOrg>();
+        List<SysOrg> orgTree;
         if (_userManager.SuperAdmin)
         {
             orgTree = await iSugarQueryable.ToTreeAsync(u => u.Children, u => u.Pid, input.Id);
@@ -69,11 +69,10 @@ public class SysOrgService : IDynamicApiController, ITransient
         }
 
         var sysOrg = await _sysOrgRep.GetSingleAsync(u => u.Id == input.Id);
-        if (sysOrg != null)
-        {
-            sysOrg.Children = orgTree;
-            orgTree = new List<SysOrg> { sysOrg };
-        }
+        if (sysOrg == null) return orgTree;
+
+        sysOrg.Children = orgTree;
+        orgTree = new List<SysOrg> { sysOrg };
         return orgTree;
     }
 
@@ -261,25 +260,20 @@ public class SysOrgService : IDynamicApiController, ITransient
     private void DeleteAllUserOrgCache(long orgId, long orgPid)
     {
         var userOrgKeyList = _sysCacheService.GetKeysByPrefixKey(CacheConst.KeyUserOrg);
-        if (userOrgKeyList != null && userOrgKeyList.Count > 0)
+        if (userOrgKeyList is not { Count: > 0 }) return;
+
+        foreach (var userOrgKey in userOrgKeyList)
         {
-            foreach (var userOrgKey in userOrgKeyList)
-            {
-                var userOrgs = _sysCacheService.Get<List<long>>(userOrgKey);
-                var userId = long.Parse(userOrgKey.Substring(CacheConst.KeyUserOrg));
-                if (userOrgs != null && (userOrgs.Contains(orgId) || userOrgs.Contains(orgPid)))
-                {
-                    SqlSugarFilter.DeleteUserOrgCache(userId, _sysOrgRep.Context.CurrentConnectionConfig.ConfigId.ToString());
-                }
-                if (orgPid == 0)
-                {
-                    var dataScope = _sysCacheService.Get<int>($"{CacheConst.KeyRoleMaxDataScope}{userId}");
-                    if (dataScope == (int)DataScopeEnum.All)
-                    {
-                        SqlSugarFilter.DeleteUserOrgCache(userId, _sysOrgRep.Context.CurrentConnectionConfig.ConfigId.ToString());
-                    }
-                }
-            }
+            var userOrgList = _sysCacheService.Get<List<long>>(userOrgKey);
+            var userId = long.Parse(userOrgKey.Substring(CacheConst.KeyUserOrg));
+            if (userOrgList != null && (userOrgList.Contains(orgId) || userOrgList.Contains(orgPid)))
+                SqlSugarFilter.DeleteUserOrgCache(userId, _sysOrgRep.Context.CurrentConnectionConfig.ConfigId.ToString());
+
+            if (orgPid != 0) continue;
+
+            var dataScope = _sysCacheService.Get<int>($"{CacheConst.KeyRoleMaxDataScope}{userId}");
+            if (dataScope == (int)DataScopeEnum.All)
+                SqlSugarFilter.DeleteUserOrgCache(userId, _sysOrgRep.Context.CurrentConnectionConfig.ConfigId.ToString());
         }
     }
 
@@ -290,8 +284,7 @@ public class SysOrgService : IDynamicApiController, ITransient
     [NonAction]
     public async Task<List<long>> GetUserOrgIdList()
     {
-        if (_userManager.SuperAdmin)
-            return new List<long>();
+        if (_userManager.SuperAdmin) return new();
         return await GetUserOrgIdList(_userManager.UserId, _userManager.OrgId);
     }
 
@@ -303,21 +296,24 @@ public class SysOrgService : IDynamicApiController, ITransient
     public async Task<List<long>> GetUserOrgIdList(long userId, long userOrgId)
     {
         var orgIdList = _sysCacheService.Get<List<long>>($"{CacheConst.KeyUserOrg}{userId}"); // 取缓存
-        if (orgIdList == null || orgIdList.Count < 1)
-        {
-            // 本人创建机构集合
-            var orgList0 = await _sysOrgRep.AsQueryable().Where(u => u.CreateUserId == userId).Select(u => u.Id).ToListAsync();
-            // 扩展机构集合
-            var orgList1 = await _sysUserExtOrgService.GetUserExtOrgList(userId);
-            // 角色机构集合
-            var orgList2 = await GetUserRoleOrgIdList(userId, userOrgId);
-            // 机构并集
-            orgIdList = orgList1.Select(u => u.OrgId).Union(orgList2).Union(orgList0).ToList();
-            // 当前所属机构
-            if (!orgIdList.Contains(userOrgId))
-                orgIdList.Add(userOrgId);
-            _sysCacheService.Set($"{CacheConst.KeyUserOrg}{userId}", orgIdList, TimeSpan.FromDays(7)); // 存缓存
-        }
+        if (orgIdList is { Count: >= 1 }) return orgIdList;
+
+        // 本人创建机构集合
+        var orgList0 = await _sysOrgRep.AsQueryable().Where(u => u.CreateUserId == userId).Select(u => u.Id).ToListAsync();
+        
+        // 扩展机构集合
+        var orgList1 = await _sysUserExtOrgService.GetUserExtOrgList(userId);
+        
+        // 角色机构集合
+        var orgList2 = await GetUserRoleOrgIdList(userId, userOrgId);
+        
+        // 机构并集
+        orgIdList = orgList1.Select(u => u.OrgId).Union(orgList2).Union(orgList0).ToList();
+        
+        // 当前所属机构
+        if (!orgIdList.Contains(userOrgId)) orgIdList.Add(userOrgId);
+        
+        _sysCacheService.Set($"{CacheConst.KeyUserOrg}{userId}", orgIdList, TimeSpan.FromDays(7)); // 存缓存
         return orgIdList;
     }
 
@@ -330,8 +326,8 @@ public class SysOrgService : IDynamicApiController, ITransient
     private async Task<List<long>> GetUserRoleOrgIdList(long userId, long userOrgId)
     {
         var roleList = await _sysUserRoleService.GetUserRoleList(userId);
-        if (roleList.Count < 1)
-            return new List<long>(); // 空机构Id集合
+        
+        if (roleList.Count < 1) return new(); // 空机构Id集合
 
         return await GetUserOrgIdList(roleList, userId, userOrgId);
     }
@@ -354,7 +350,7 @@ public class SysOrgService : IDynamicApiController, ITransient
         // 数据范围的机构集合
         var dataScopeOrgIdList = new List<long>();
 
-        if (roleList != null && roleList.Count > 0)
+        if (roleList is { Count: > 0 })
         {
             roleList.ForEach(u =>
             {
@@ -393,20 +389,20 @@ public class SysOrgService : IDynamicApiController, ITransient
     {
         var orgId = userOrgId;//var orgId = _userManager.OrgId;
         var orgIdList = new List<long>();
-        // 若数据范围是全部,则获取所有机构Id集合
-        if (dataScope == (int)DataScopeEnum.All)
-        {
-            orgIdList = await _sysOrgRep.AsQueryable().Select(u => u.Id).ToListAsync();
-        }
-        // 若数据范围是本部门及以下,则获取本节点和子节点集合
-        else if (dataScope == (int)DataScopeEnum.DeptChild)
-        {
-            orgIdList = await GetChildIdListWithSelfById(orgId);
-        }
-        // 若数据范围是本部门不含子节点,则直接返回本部门
-        else if (dataScope == (int)DataScopeEnum.Dept)
+        switch (dataScope)
         {
-            orgIdList.Add(orgId);
+            // 若数据范围是全部,则获取所有机构Id集合
+            case (int)DataScopeEnum.All:
+                orgIdList = await _sysOrgRep.AsQueryable().Select(u => u.Id).ToListAsync();
+                break;
+            // 若数据范围是本部门及以下,则获取本节点和子节点集合
+            case (int)DataScopeEnum.DeptChild:
+                orgIdList = await GetChildIdListWithSelfById(orgId);
+                break;
+            // 若数据范围是本部门不含子节点,则直接返回本部门
+            case (int)DataScopeEnum.Dept:
+                orgIdList.Add(orgId);
+                break;
         }
         return orgIdList;
     }

+ 2 - 4
Admin.NET/Admin.NET.Core/Service/Plugin/SysPluginService.cs

@@ -46,8 +46,7 @@ public class SysPluginService : IDynamicApiController, ITransient
     public async Task AddPlugin(AddPluginInput input)
     {
         var isExist = await _sysPluginRep.IsAnyAsync(u => u.Name == input.Name || u.AssemblyName == input.AssemblyName);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1900);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1900);
 
         // 添加动态程序集/接口
         input.AssemblyName = CompileAssembly(input.CsharpCode, input.AssemblyName);
@@ -65,8 +64,7 @@ public class SysPluginService : IDynamicApiController, ITransient
     public async Task UpdatePlugin(UpdatePluginInput input)
     {
         var isExist = await _sysPluginRep.IsAnyAsync(u => (u.Name == input.Name || u.AssemblyName == input.AssemblyName) && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1900);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1900);
 
         // 先移除再添加动态程序集/接口
         RemoveAssembly(input.AssemblyName);

+ 5 - 10
Admin.NET/Admin.NET.Core/Service/Pos/SysPosService.cs

@@ -48,8 +48,7 @@ public class SysPosService : IDynamicApiController, ITransient
     [DisplayName("增加职位")]
     public async Task AddPos(AddPosInput input)
     {
-        if (await _sysPosRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code))
-            throw Oops.Oh(ErrorCodeEnum.D6000);
+        if (await _sysPosRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code)) throw Oops.Oh(ErrorCodeEnum.D6000);
 
         await _sysPosRep.InsertAsync(input.Adapt<SysPos>());
     }
@@ -67,8 +66,7 @@ public class SysPosService : IDynamicApiController, ITransient
             throw Oops.Oh(ErrorCodeEnum.D6000);
 
         var sysPos = await _sysPosRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D6003);
-        if (!_userManager.SuperAdmin && sysPos.CreateUserId != _userManager.UserId)
-            throw Oops.Oh(ErrorCodeEnum.D6002);
+        if (!_userManager.SuperAdmin && sysPos.CreateUserId != _userManager.UserId) throw Oops.Oh(ErrorCodeEnum.D6002);
 
         await _sysPosRep.AsUpdateable(input.Adapt<SysPos>()).IgnoreColumns(true).ExecuteCommandAsync();
     }
@@ -83,19 +81,16 @@ public class SysPosService : IDynamicApiController, ITransient
     public async Task DeletePos(DeletePosInput input)
     {
         var sysPos = await _sysPosRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D6003);
-        if (!_userManager.SuperAdmin && sysPos.CreateUserId != _userManager.UserId)
-            throw Oops.Oh(ErrorCodeEnum.D6002);
+        if (!_userManager.SuperAdmin && sysPos.CreateUserId != _userManager.UserId) throw Oops.Oh(ErrorCodeEnum.D6002);
 
         // 若职位有用户则禁止删除
         var hasPosEmp = await _sysPosRep.ChangeRepository<SqlSugarRepository<SysUser>>()
             .IsAnyAsync(u => u.PosId == input.Id);
-        if (hasPosEmp)
-            throw Oops.Oh(ErrorCodeEnum.D6001);
+        if (hasPosEmp) throw Oops.Oh(ErrorCodeEnum.D6001);
 
         // 若附属职位有用户则禁止删除
         var hasExtPosEmp = await _sysUserExtOrgService.HasUserPos(input.Id);
-        if (hasExtPosEmp)
-            throw Oops.Oh(ErrorCodeEnum.D6001);
+        if (hasExtPosEmp) throw Oops.Oh(ErrorCodeEnum.D6001);
 
         await _sysPosRep.DeleteAsync(u => u.Id == input.Id);
     }

+ 2 - 4
Admin.NET/Admin.NET.Core/Service/Print/SysPrintService.cs

@@ -54,8 +54,7 @@ public class SysPrintService : IDynamicApiController, ITransient
     public async Task AddPrint(AddPrintInput input)
     {
         var isExist = await _sysPrintRep.IsAnyAsync(u => u.Name == input.Name);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1800);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1800);
 
         await _sysPrintRep.InsertAsync(input.Adapt<SysPrint>());
     }
@@ -70,8 +69,7 @@ public class SysPrintService : IDynamicApiController, ITransient
     public async Task UpdatePrint(UpdatePrintInput input)
     {
         var isExist = await _sysPrintRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1800);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1800);
 
         await _sysPrintRep.AsUpdateable(input.Adapt<SysPrint>()).IgnoreColumns(true).ExecuteCommandAsync();
     }

+ 64 - 76
Admin.NET/Admin.NET.Core/Service/Region/SysRegionService.cs

@@ -62,22 +62,19 @@ public class SysRegionService : IDynamicApiController, ITransient
     [DisplayName("增加行政区域")]
     public async Task<long> AddRegion(AddRegionInput input)
     {
-        input.Code = input.Code.Trim();
-        if (input.Code.Length != 12 && input.Code.Length != 9 && input.Code.Length != 6)
-            throw Oops.Oh(ErrorCodeEnum.R2003);
+        input.Code = input.Code?.Trim() ?? "";
+        if (input.Code.Length != 12 && input.Code.Length != 9 && input.Code.Length != 6) throw Oops.Oh(ErrorCodeEnum.R2003);
 
         if (input.Pid != 0)
         {
             var pRegion = await _sysRegionRep.GetFirstAsync(u => u.Id == input.Pid);
             pRegion ??= await _sysRegionRep.GetFirstAsync(u => u.Code == input.Pid.ToString());
-            if (pRegion == null)
-                throw Oops.Oh(ErrorCodeEnum.D2000);
+            if (pRegion == null) throw Oops.Oh(ErrorCodeEnum.D2000);
             input.Pid = pRegion.Id;
         }
 
         var isExist = await _sysRegionRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.R2002);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.R2002);
 
         var sysRegion = input.Adapt<SysRegion>();
         var newRegion = await _sysRegionRep.AsInsertable(sysRegion).ExecuteReturnEntityAsync();
@@ -93,34 +90,28 @@ public class SysRegionService : IDynamicApiController, ITransient
     [DisplayName("更新行政区域")]
     public async Task UpdateRegion(UpdateRegionInput input)
     {
-        input.Code = input.Code.Trim();
-        if (input.Code.Length != 12 && input.Code.Length != 9 && input.Code.Length != 6)
-            throw Oops.Oh(ErrorCodeEnum.R2003);
+        input.Code = input.Code?.Trim() ?? "";
+        if (input.Code.Length != 12 && input.Code.Length != 9 && input.Code.Length != 6) throw Oops.Oh(ErrorCodeEnum.R2003);
 
         var sysRegion = await _sysRegionRep.GetFirstAsync(u => u.Id == input.Id);
-        if (sysRegion == null)
-            throw Oops.Oh(ErrorCodeEnum.D1002);
+        if (sysRegion == null) throw Oops.Oh(ErrorCodeEnum.D1002);
 
         if (sysRegion.Pid != input.Pid && input.Pid != 0)
         {
             var pRegion = await _sysRegionRep.GetFirstAsync(u => u.Id == input.Pid);
             pRegion ??= await _sysRegionRep.GetFirstAsync(u => u.Code == input.Pid.ToString());
-            if (pRegion == null)
-                throw Oops.Oh(ErrorCodeEnum.D2000);
+            if (pRegion == null) throw Oops.Oh(ErrorCodeEnum.D2000);
 
             input.Pid = pRegion.Id;
             var regionTreeList = await _sysRegionRep.AsQueryable().ToChildListAsync(u => u.Pid, input.Id, true);
             var childIdList = regionTreeList.Select(u => u.Id).ToList();
-            if (childIdList.Contains(input.Pid))
-                throw Oops.Oh(ErrorCodeEnum.R2004);
+            if (childIdList.Contains(input.Pid)) throw Oops.Oh(ErrorCodeEnum.R2004);
         }
 
-        if (input.Id == input.Pid)
-            throw Oops.Oh(ErrorCodeEnum.R2001);
+        if (input.Id == input.Pid) throw Oops.Oh(ErrorCodeEnum.R2001);
 
         var isExist = await _sysRegionRep.IsAnyAsync(u => (u.Name == input.Name && u.Code == input.Code) && u.Id != sysRegion.Id);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.R2002);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.R2002);
 
         //// 父Id不能为自己的子节点
         //var regionTreeList = await _sysRegionRep.AsQueryable().ToChildListAsync(u => u.Pid, input.Id, true);
@@ -153,20 +144,19 @@ public class SysRegionService : IDynamicApiController, ITransient
     public async Task Sync()
     {
         var syncLevel = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysRegionSyncLevel);
-        if (syncLevel < 1 || syncLevel > 5)
-            syncLevel = 3;//默认区县级
+        if (syncLevel is < 1 or > 5) syncLevel = 3;//默认区县级
         var context = BrowsingContext.New(AngleSharp.Configuration.Default.WithDefaultLoader());
         var dom = await context.OpenAsync(_url);
 
         // 省级
         var itemList = dom.QuerySelectorAll("table.provincetable tr.provincetr td a");
-        if (itemList.Length == 0)
-            throw Oops.Oh(ErrorCodeEnum.R2005);
+        if (itemList.Length == 0) throw Oops.Oh(ErrorCodeEnum.R2005);
 
         await _sysRegionRep.DeleteAsync(u => u.Id > 0);
 
-        foreach (IHtmlAnchorElement item in itemList)
+        foreach (var element in itemList)
         {
+            var item = (IHtmlAnchorElement)element;
             var list = new List<SysRegion>();
 
             var region = new SysRegion
@@ -196,72 +186,70 @@ public class SysRegionService : IDynamicApiController, ITransient
                         Remark = item1.Href,
                         Level = 2,
                     };
+                    
                     // 若URL中查询的一级行政区域缺少Code则通过二级区域填充
                     if (list.Count == 1 && !string.IsNullOrEmpty(region1.Code))
                         region.Code = region1.Code.Substring(0, 2).PadRight(region1.Code.Length, '0');
+                    
                     // 同步层级为“1-省级”退出
-                    if (syncLevel < 2)
-                        break;
+                    if (syncLevel < 2) break;
 
                     list.Add(region1);
 
                     // 区县级
-                    if (!string.IsNullOrEmpty(item1.Href) && syncLevel > 2)
+                    if (string.IsNullOrEmpty(item1.Href) || syncLevel <= 2) continue;
+
+                    var dom2 = await context.OpenAsync(item1.Href);
+                    var itemList2 = dom2.QuerySelectorAll("table.countytable tr.countytr td a");
+                    for (var i2 = 0; i2 < itemList2.Length; i2 += 2)
                     {
-                        var dom2 = await context.OpenAsync(item1.Href);
-                        var itemList2 = dom2.QuerySelectorAll("table.countytable tr.countytr td a");
-                        for (var i2 = 0; i2 < itemList2.Length; i2 += 2)
+                        var item2 = (IHtmlAnchorElement)itemList2[i2 + 1];
+                        var region2 = new SysRegion
                         {
-                            var item2 = (IHtmlAnchorElement)itemList2[i2 + 1];
-                            var region2 = new SysRegion
+                            Id = YitIdHelper.NextId(),
+                            Pid = region1.Id,
+                            Name = item2.TextContent,
+                            Code = itemList2[i2].TextContent,
+                            Remark = item2.Href,
+                            Level = 3,
+                        };
+                        list.Add(region2);
+
+                        // 街道级
+                        if (string.IsNullOrEmpty(item2.Href) || syncLevel <= 3) continue;
+
+                        var dom3 = await context.OpenAsync(item2.Href);
+                        var itemList3 = dom3.QuerySelectorAll("table.towntable tr.towntr td a");
+                        for (var i3 = 0; i3 < itemList3.Length; i3 += 2)
+                        {
+                            var item3 = (IHtmlAnchorElement)itemList3[i3 + 1];
+                            var region3 = new SysRegion
                             {
                                 Id = YitIdHelper.NextId(),
-                                Pid = region1.Id,
-                                Name = item2.TextContent,
-                                Code = itemList2[i2].TextContent,
-                                Remark = item2.Href,
-                                Level = 3,
+                                Pid = region2.Id,
+                                Name = item3.TextContent,
+                                Code = itemList3[i3].TextContent,
+                                Remark = item3.Href,
+                                Level = 4,
                             };
-                            list.Add(region2);
+                            list.Add(region3);
+
+                            // 村级
+                            if (string.IsNullOrEmpty(item3.Href) || syncLevel <= 4) continue;
 
-                            // 街道级
-                            if (!string.IsNullOrEmpty(item2.Href) && syncLevel > 3)
+                            var dom4 = await context.OpenAsync(item3.Href);
+                            var itemList4 = dom4.QuerySelectorAll("table.villagetable tr.villagetr td");
+                            for (var i4 = 0; i4 < itemList4.Length; i4 += 3)
                             {
-                                var dom3 = await context.OpenAsync(item2.Href);
-                                var itemList3 = dom3.QuerySelectorAll("table.towntable tr.towntr td a");
-                                for (var i3 = 0; i3 < itemList3.Length; i3 += 2)
+                                list.Add(new SysRegion
                                 {
-                                    var item3 = (IHtmlAnchorElement)itemList3[i3 + 1];
-                                    var region3 = new SysRegion
-                                    {
-                                        Id = YitIdHelper.NextId(),
-                                        Pid = region2.Id,
-                                        Name = item3.TextContent,
-                                        Code = itemList3[i3].TextContent,
-                                        Remark = item3.Href,
-                                        Level = 4,
-                                    };
-                                    list.Add(region3);
-
-                                    // 村级
-                                    if (!string.IsNullOrEmpty(item3.Href) && syncLevel > 4)
-                                    {
-                                        var dom4 = await context.OpenAsync(item3.Href);
-                                        var itemList4 = dom4.QuerySelectorAll("table.villagetable tr.villagetr td");
-                                        for (var i4 = 0; i4 < itemList4.Length; i4 += 3)
-                                        {
-                                            list.Add(new SysRegion
-                                            {
-                                                Id = YitIdHelper.NextId(),
-                                                Pid = region3.Id,
-                                                Name = itemList4[i4 + 2].TextContent,
-                                                Code = itemList4[i4].TextContent,
-                                                CityCode = itemList4[i4 + 1].TextContent,
-                                                Level = 5,
-                                            });
-                                        }
-                                    }
-                                }
+                                    Id = YitIdHelper.NextId(),
+                                    Pid = region3.Id,
+                                    Name = itemList4[i4 + 2].TextContent,
+                                    Code = itemList4[i4].TextContent,
+                                    CityCode = itemList4[i4 + 1].TextContent,
+                                    Level = 5,
+                                });
                             }
                         }
                     }
@@ -269,7 +257,7 @@ public class SysRegionService : IDynamicApiController, ITransient
             }
 
             //按省份同步快速写入提升同步效率,全部一次性写入容易出现从统计局获取数据失败
-            _sysRegionRep.Context.Fastest<SysRegion>().BulkCopy(list);
+            await _sysRegionRep.Context.Fastest<SysRegion>().BulkCopyAsync(list);
         }
     }
 }

+ 2 - 2
Admin.NET/Admin.NET.Core/Service/Role/SysRoleOrgService.cs

@@ -28,12 +28,12 @@ public class SysRoleOrgService : ITransient
         await _sysRoleOrgRep.DeleteAsync(u => u.RoleId == input.Id);
         if (input.DataScope == (int)DataScopeEnum.Define)
         {
-            var roleOrgs = input.OrgIdList.Select(u => new SysRoleOrg
+            var roleOrgList = input.OrgIdList.Select(u => new SysRoleOrg
             {
                 RoleId = input.Id,
                 OrgId = u
             }).ToList();
-            await _sysRoleOrgRep.InsertRangeAsync(roleOrgs);
+            await _sysRoleOrgRep.InsertRangeAsync(roleOrgList);
         }
     }
 

+ 20 - 21
Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs

@@ -92,8 +92,7 @@ public class SysRoleService : IDynamicApiController, ITransient
     /// <returns></returns>
     private async Task UpdateRoleMenu(AddRoleInput input)
     {
-        if (input.MenuIdList == null || input.MenuIdList.Count < 1)
-            return;
+        if (input.MenuIdList == null || input.MenuIdList.Count < 1) return;
 
         // 将父节点为0的菜单排除,防止前端全选异常
         var pMenuIds = await _sysRoleRep.ChangeRepository<SqlSugarRepository<SysMenu>>().AsQueryable().Where(u => input.MenuIdList.Contains(u.Id) && u.Pid == 0).ToListAsync(u => u.Id);
@@ -135,13 +134,11 @@ public class SysRoleService : IDynamicApiController, ITransient
     {
         // 禁止删除系统管理员角色
         var sysRole = await _sysRoleRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
-        if (sysRole.Code == CommonConst.SysAdminRole)
-            throw Oops.Oh(ErrorCodeEnum.D1019);
+        if (sysRole.Code == CommonConst.SysAdminRole) throw Oops.Oh(ErrorCodeEnum.D1019);
 
         // 若角色有用户则禁止删除
         var userIds = await _sysUserRoleService.GetUserIdList(input.Id);
-        if (userIds != null && userIds.Count > 0)
-            throw Oops.Oh(ErrorCodeEnum.D1025);
+        if (userIds != null && userIds.Count > 0) throw Oops.Oh(ErrorCodeEnum.D1025);
 
         await _sysRoleRep.DeleteAsync(sysRole);
 
@@ -187,21 +184,24 @@ public class SysRoleService : IDynamicApiController, ITransient
         var dataScope = input.DataScope;
         if (!_userManager.SuperAdmin)
         {
-            // 非超级管理员没有全部数据范围权限
-            if (dataScope == (int)DataScopeEnum.All)
-                throw Oops.Oh(ErrorCodeEnum.D1016);
-
-            // 若数据范围自定义,则判断授权数据范围是否有权限
-            if (dataScope == (int)DataScopeEnum.Define)
+            switch (dataScope)
             {
-                var grantOrgIdList = input.OrgIdList;
-                if (grantOrgIdList.Count > 0)
+                // 非超级管理员没有全部数据范围权限
+                case (int)DataScopeEnum.All: throw Oops.Oh(ErrorCodeEnum.D1016);
+                // 若数据范围自定义,则判断授权数据范围是否有权限
+                case (int)DataScopeEnum.Define:
                 {
-                    var orgIdList = await _sysOrgService.GetUserOrgIdList();
-                    if (orgIdList.Count < 1)
-                        throw Oops.Oh(ErrorCodeEnum.D1016);
-                    else if (!grantOrgIdList.All(u => orgIdList.Any(c => c == u)))
-                        throw Oops.Oh(ErrorCodeEnum.D1016);
+                    var grantOrgIdList = input.OrgIdList;
+                    if (grantOrgIdList.Count > 0)
+                    {
+                        var orgIdList = await _sysOrgService.GetUserOrgIdList();
+                        if (orgIdList.Count < 1)
+                            throw Oops.Oh(ErrorCodeEnum.D1016);
+                        if (!grantOrgIdList.All(u => orgIdList.Any(c => c == u)))
+                            throw Oops.Oh(ErrorCodeEnum.D1016);
+                    }
+
+                    break;
                 }
             }
         }
@@ -240,8 +240,7 @@ public class SysRoleService : IDynamicApiController, ITransient
     [DisplayName("设置角色状态")]
     public async Task<int> SetStatus(RoleInput input)
     {
-        if (!Enum.IsDefined(typeof(StatusEnum), input.Status))
-            throw Oops.Oh(ErrorCodeEnum.D3005);
+        if (!Enum.IsDefined(typeof(StatusEnum), input.Status)) throw Oops.Oh(ErrorCodeEnum.D3005);
 
         return await _sysRoleRep.AsUpdateable()
             .SetColumns(u => u.Status == input.Status)

+ 3 - 4
Admin.NET/Admin.NET.Core/Service/Schedule/SysScheduleService.cs

@@ -16,10 +16,10 @@ public class SysScheduleService : IDynamicApiController, ITransient
     private readonly SqlSugarRepository<SysSchedule> _sysSchedule;
 
     public SysScheduleService(UserManager userManager,
-        SqlSugarRepository<SysSchedule> sysSchedle)
+        SqlSugarRepository<SysSchedule> sysSchedule)
     {
         _userManager = userManager;
-        _sysSchedule = sysSchedle;
+        _sysSchedule = sysSchedule;
     }
 
     /// <summary>
@@ -93,8 +93,7 @@ public class SysScheduleService : IDynamicApiController, ITransient
     [DisplayName("设置日程状态")]
     public async Task<int> SetStatus(ScheduleInput input)
     {
-        if (!Enum.IsDefined(typeof(FinishStatusEnum), input.Status))
-            throw Oops.Oh(ErrorCodeEnum.D3005);
+        if (!Enum.IsDefined(typeof(FinishStatusEnum), input.Status)) throw Oops.Oh(ErrorCodeEnum.D3005);
 
         return await _sysSchedule.AsUpdateable()
             .SetColumns(u => u.Status == input.Status)

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Server/SysServerService.cs

@@ -31,7 +31,7 @@ public class SysServerService : IDynamicApiController, ITransient
             ProcessorCount = Environment.ProcessorCount + " 核", // CPU核心数
             SysRunTime = ComputerUtil.GetRunTime(), // 系统运行时间
             RemoteIp = ComputerUtil.GetIpFromOnline(), // 外网地址
-            LocalIp = App.HttpContext?.Connection?.LocalIpAddress.MapToIPv4().ToString(), // 本地地址
+            LocalIp = App.HttpContext?.Connection.LocalIpAddress!.MapToIPv4().ToString(), // 本地地址
             RuntimeInformation.FrameworkDescription, // NET框架
             Environment = App.HostEnvironment.IsDevelopment() ? "Development" : "Production",
             Wwwroot = App.WebHostEnvironment.WebRootPath, // 网站根目录

+ 20 - 53
Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs

@@ -118,8 +118,7 @@ public class SysTenantService : IDynamicApiController, ITransient
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D1301);
 
         // 从库配置判断
-        if (!string.IsNullOrWhiteSpace(input.SlaveConnections) && !JSON.IsValid(input.SlaveConnections))
-            throw Oops.Oh(ErrorCodeEnum.D1302);
+        if (!string.IsNullOrWhiteSpace(input.SlaveConnections) && !JSON.IsValid(input.SlaveConnections)) throw Oops.Oh(ErrorCodeEnum.D1302);
 
         switch (input.TenantType)
         {
@@ -155,11 +154,9 @@ public class SysTenantService : IDynamicApiController, ITransient
     public async Task<int> SetStatus(TenantInput input)
     {
         var tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == input.Id);
-        if (tenant == null || tenant.ConfigId == SqlSugarConst.MainConfigId)
-            throw Oops.Oh(ErrorCodeEnum.Z1001);
+        if (tenant == null || tenant.ConfigId == SqlSugarConst.MainConfigId) throw Oops.Oh(ErrorCodeEnum.Z1001);
 
-        if (!Enum.IsDefined(typeof(StatusEnum), input.Status))
-            throw Oops.Oh(ErrorCodeEnum.D3005);
+        if (!Enum.IsDefined(typeof(StatusEnum), input.Status)) throw Oops.Oh(ErrorCodeEnum.D3005);
 
         tenant.Status = input.Status;
         return await _sysTenantRep.AsUpdateable(tenant).UpdateColumns(u => new { u.Status }).ExecuteCommandAsync();
@@ -175,41 +172,20 @@ public class SysTenantService : IDynamicApiController, ITransient
         var tenantName = tenant.Name;
 
         // 初始化机构
-        var newOrg = new SysOrg
-        {
-            TenantId = tenantId,
-            Pid = 0,
-            Name = tenantName,
-            Code = tenantName,
-            Remark = tenantName,
-        };
+        var newOrg = new SysOrg { TenantId=tenantId, Pid=0, Name=tenantName, Code=tenantName, Remark=tenantName, };
         await _sysOrgRep.InsertAsync(newOrg);
 
         // 初始化角色
-        var newRole = new SysRole
-        {
-            TenantId = tenantId,
-            Name = "租管-" + tenantName,
-            Code = CommonConst.SysAdminRole,
-            DataScope = DataScopeEnum.All,
-            Remark = tenantName
-        };
+        var newRole = new SysRole { TenantId=tenantId, Name="租管-" + tenantName, Code=CommonConst.SysAdminRole, DataScope=DataScopeEnum.All, Remark=tenantName };
         await _sysRoleRep.InsertAsync(newRole);
 
         // 初始化职位
-        var newPos = new SysPos
-        {
-            TenantId = tenantId,
-            Name = "租管-" + tenantName,
-            Code = tenantName,
-            Remark = tenantName,
-        };
+        var newPos = new SysPos { TenantId=tenantId, Name="租管-" + tenantName, Code=tenantName, Remark=tenantName };
         await _sysPosRep.InsertAsync(newPos);
 
         // 初始化系统账号
         var password = await _sysConfigService.GetConfigValue<string>(ConfigConst.SysPassword);
-        var newUser = new SysUser
-        {
+        var newUser = new SysUser {
             TenantId = tenantId,
             Account = tenant.AdminAccount,
             Password = CryptogramUtil.Encrypt(password),
@@ -226,15 +202,11 @@ public class SysTenantService : IDynamicApiController, ITransient
         await _sysUserRep.InsertAsync(newUser);
 
         // 关联用户及角色
-        var newUserRole = new SysUserRole
-        {
-            RoleId = newRole.Id,
-            UserId = newUser.Id
-        };
+        var newUserRole = new SysUserRole { RoleId = newRole.Id, UserId = newUser.Id };
         await _userRoleRep.InsertAsync(newUserRole);
 
         // 关联租户组织机构和管理员用户
-        await _sysTenantRep.UpdateAsync(u => new SysTenant() { UserId = newUser.Id, OrgId = newOrg.Id }, u => u.Id == tenantId);
+        await _sysTenantRep.UpdateAsync(u => new SysTenant { UserId = newUser.Id, OrgId = newOrg.Id }, u => u.Id == tenantId);
 
         // 默认租户管理员角色菜单集合
         var menuIdList = new List<long> { 1300000000111,1300000000121, // 工作台
@@ -259,13 +231,11 @@ public class SysTenantService : IDynamicApiController, ITransient
     public async Task DeleteTenant(DeleteTenantInput input)
     {
         // 禁止删除默认租户
-        if (input.Id.ToString() == SqlSugarConst.MainConfigId)
-            throw Oops.Oh(ErrorCodeEnum.D1023);
+        if (input.Id.ToString() == SqlSugarConst.MainConfigId) throw Oops.Oh(ErrorCodeEnum.D1023);
 
         // 若账号为开放接口绑定租户则禁止删除
         var isOpenAccessTenant = await _sysTenantRep.ChangeRepository<SqlSugarRepository<SysOpenAccess>>().IsAnyAsync(u => u.BindTenantId == input.Id);
-        if (isOpenAccessTenant)
-            throw Oops.Oh(ErrorCodeEnum.D1031);
+        if (isOpenAccessTenant) throw Oops.Oh(ErrorCodeEnum.D1031);
 
         await _sysTenantRep.DeleteAsync(u => u.Id == input.Id);
 
@@ -301,11 +271,10 @@ public class SysTenantService : IDynamicApiController, ITransient
     public async Task UpdateTenant(UpdateTenantInput input)
     {
         var isExist = await _sysOrgRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.OrgId);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1300);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1300);
+        
         isExist = await _sysUserRep.IsAnyAsync(u => u.Account == input.AdminAccount && u.Id != input.UserId);
-        if (isExist)
-            throw Oops.Oh(ErrorCodeEnum.D1301);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1301);
 
         // Id隔离时设置与主库一致
         switch (input.TenantType)
@@ -396,12 +365,11 @@ public class SysTenantService : IDynamicApiController, ITransient
             _sysTenantRep.AsTenant().RemoveConnection(tenantId);
 
         var tenantList = await _sysTenantRep.GetListAsync();
+        
         // 对租户库连接进行SM2加密
-        foreach (var tenant in tenantList)
-        {
-            if (!string.IsNullOrWhiteSpace(tenant.Connection))
-                tenant.Connection = CryptogramUtil.SM2Encrypt(tenant.Connection);
-        }
+        foreach (var tenant in tenantList.Where(tenant => !string.IsNullOrWhiteSpace(tenant.Connection)))
+            tenant.Connection = CryptogramUtil.SM2Encrypt(tenant.Connection);
+        
         _sysCacheService.Set(CacheConst.KeyTenant, tenantList);
     }
 
@@ -435,7 +403,7 @@ public class SysTenantService : IDynamicApiController, ITransient
             {
                 EnableInitDb = true,
                 EnableDiffLog = false,
-                EnableUnderLine = defaultConfig.DbSettings.EnableUnderLine,
+                EnableUnderLine = defaultConfig!.DbSettings.EnableUnderLine,
             }
         };
         SqlSugarSetup.InitTenantDatabase(App.GetRequiredService<ISqlSugarClient>().AsTenant(), config);
@@ -462,8 +430,7 @@ public class SysTenantService : IDynamicApiController, ITransient
         var iTenant = _sysTenantRep.AsTenant();
 
         // 若已存在租户库连接,则直接返回
-        if (iTenant.IsAnyConnection(tenantId.ToString()))
-            return iTenant.GetConnectionScope(tenantId.ToString());
+        if (iTenant.IsAnyConnection(tenantId.ToString())) return iTenant.GetConnectionScope(tenantId.ToString());
 
         lock (iTenant)
         {

+ 4 - 5
Admin.NET/Admin.NET.Core/Service/User/SysUserLdapService.cs

@@ -22,13 +22,13 @@ public class SysUserLdapService : ITransient
     /// 批量插入域账号
     /// </summary>
     /// <param name="tenantId"></param>
-    /// <param name="sysUserLdaps"></param>
+    /// <param name="sysUserLdapList"></param>
     /// <returns></returns>
-    public async Task InsertUserLdaps(long tenantId, List<SysUserLdap> sysUserLdaps)
+    public async Task InsertUserLdapList(long tenantId, List<SysUserLdap> sysUserLdapList)
     {
         await _sysUserLdapRep.DeleteAsync(u => u.TenantId == tenantId);
 
-        await _sysUserLdapRep.InsertRangeAsync(sysUserLdaps);
+        await _sysUserLdapRep.InsertRangeAsync(sysUserLdapList);
 
         await _sysUserLdapRep.AsUpdateable()
             .InnerJoin<SysUser>((l, u) => l.EmployeeId == u.Account)
@@ -48,8 +48,7 @@ public class SysUserLdapService : ITransient
     public async Task AddUserLdap(long tenantId, long userId, string account, string domainAccount)
     {
         var userLdap = await _sysUserLdapRep.GetFirstAsync(u => u.TenantId == tenantId && u.IsDelete == false && (u.Account == account || u.UserId == userId || u.EmployeeId == domainAccount));
-        if (userLdap != null)
-            await _sysUserLdapRep.DeleteByIdAsync(userLdap.Id);
+        if (userLdap != null) await _sysUserLdapRep.DeleteByIdAsync(userLdap.Id);
 
         if (!string.IsNullOrWhiteSpace(domainAccount))
             await _sysUserLdapRep.InsertAsync(new SysUserLdap { EmployeeId = account, TenantId = tenantId, UserId = userId, Account = domainAccount });

+ 2 - 2
Admin.NET/Admin.NET.Core/Service/User/SysUserService.cs

@@ -114,7 +114,7 @@ public class SysUserService : IDynamicApiController, ITransient
 
         // 增加域账号
         if (!string.IsNullOrWhiteSpace(input.DomainAccount))
-            await _sysUserLdapService.AddUserLdap(newUser.TenantId.Value, newUser.Id, newUser.Account, input.DomainAccount);
+            await _sysUserLdapService.AddUserLdap(newUser.TenantId!.Value, newUser.Id, newUser.Account, input.DomainAccount);
 
         // 执行订阅事件
         _sysUserEventHandler.OnEvent(this, SysUserEventTypeEnum.Add, input);
@@ -149,7 +149,7 @@ public class SysUserService : IDynamicApiController, ITransient
         if (input.OrgId != user.OrgId || !input.RoleIdList.OrderBy(u => u).SequenceEqual(roleIds.OrderBy(u => u)))
             await _sysOnlineUserService.ForceOffline(input.Id);
         // 更新域账号
-        await _sysUserLdapService.AddUserLdap(user.TenantId.Value, user.Id, user.Account, input.DomainAccount);
+        await _sysUserLdapService.AddUserLdap(user.TenantId!.Value, user.Id, user.Account, input.DomainAccount);
 
         // 执行订阅事件
         _sysUserEventHandler.OnEvent(this, SysUserEventTypeEnum.Update, input);

+ 8 - 8
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarFilter.cs

@@ -11,7 +11,7 @@ public static class SqlSugarFilter
     /// <summary>
     /// 缓存全局查询过滤器(内存缓存)
     /// </summary>
-    private static readonly ICache _cache = Cache.Default;
+    private static readonly ICache Cache = NewLife.Caching.Cache.Default;
 
     /// <summary>
     /// 删除用户机构缓存
@@ -29,7 +29,7 @@ public static class SqlSugarFilter
         // 用户权限缓存(按钮集合)
         sysCacheService.Remove($"{CacheConst.KeyUserButton}{userId}");
         // 删除用户机构(数据范围)缓存——过滤器
-        _cache.Remove($"db:{dbConfigId}:orgList:{userId}");
+        Cache.Remove($"db:{dbConfigId}:orgList:{userId}");
     }
 
     /// <summary>
@@ -57,7 +57,7 @@ public static class SqlSugarFilter
 
         // 配置用户机构集合缓存
         var cacheKey = $"db:{db.CurrentConnectionConfig.ConfigId}:orgList:{userId}";
-        var orgFilter = _cache.Get<ConcurrentDictionary<Type, LambdaExpression>>(cacheKey);
+        var orgFilter = Cache.Get<ConcurrentDictionary<Type, LambdaExpression>>(cacheKey);
         if (orgFilter == null)
         {
             // 获取用户最大数据范围,如果是全部数据,则跳过
@@ -92,7 +92,7 @@ public static class SqlSugarFilter
                 db.QueryFilter.AddTableFilter(entityType, lambda);
                 orgFilter.TryAdd(entityType, lambda);
             }
-            _cache.Add(cacheKey, orgFilter);
+            Cache.Add(cacheKey, orgFilter);
         }
         else
         {
@@ -128,7 +128,7 @@ public static class SqlSugarFilter
 
         // 配置用户数据范围缓存
         var cacheKey = $"db:{db.CurrentConnectionConfig.ConfigId}:dataScope:{userId}";
-        var dataScopeFilter = _cache.Get<ConcurrentDictionary<Type, LambdaExpression>>(cacheKey);
+        var dataScopeFilter = Cache.Get<ConcurrentDictionary<Type, LambdaExpression>>(cacheKey);
         if (dataScopeFilter == null)
         {
             // 获取业务实体数据表
@@ -151,7 +151,7 @@ public static class SqlSugarFilter
                 db.QueryFilter.AddTableFilter(entityType, lambda);
                 dataScopeFilter.TryAdd(entityType, lambda);
             }
-            _cache.Add(cacheKey, dataScopeFilter);
+            Cache.Add(cacheKey, dataScopeFilter);
         }
         else
         {
@@ -169,7 +169,7 @@ public static class SqlSugarFilter
         // 配置自定义缓存
         var userId = App.User?.FindFirst(ClaimConst.UserId)?.Value;
         var cacheKey = $"db:{db.CurrentConnectionConfig.ConfigId}:custom:{userId}";
-        var tableFilterItemList = _cache.Get<List<TableFilterItem<object>>>(cacheKey);
+        var tableFilterItemList = Cache.Get<List<TableFilterItem<object>>>(cacheKey);
         if (tableFilterItemList == null)
         {
             // 获取自定义实体过滤器
@@ -199,7 +199,7 @@ public static class SqlSugarFilter
                     db.QueryFilter.Add(tableFilterItem);
                 }
             }
-            _cache.Add(cacheKey, tableFilterItems);
+            Cache.Add(cacheKey, tableFilterItems);
         }
         else
         {

+ 124 - 119
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs

@@ -167,19 +167,18 @@ public static class SqlSugarSetup
                 //}
 
                 // 执行时间超过5秒时
-                if (db.Ado.SqlExecutionTime.TotalSeconds > 5)
-                {
-                    var fileName = db.Ado.SqlStackTrace.FirstFileName; // 文件名
-                    var fileLine = db.Ado.SqlStackTrace.FirstLine; // 行号
-                    var firstMethodName = db.Ado.SqlStackTrace.FirstMethodName; // 方法名
-                    var log = $"【{DateTime.Now}——超时SQL】\r\n【所在文件名】:{fileName}\r\n【代码行数】:{fileLine}\r\n【方法名】:{firstMethodName}\r\n" + $"【SQL语句】:{UtilMethods.GetNativeSql(sql, pars)}";
-                    Log.Warning(log);
-                    App.PrintToMiniProfiler("SqlSugar", "Slow", log);
-                }
+                if (!(db.Ado.SqlExecutionTime.TotalSeconds > 5)) return;
+
+                var fileName = db.Ado.SqlStackTrace.FirstFileName; // 文件名
+                var fileLine = db.Ado.SqlStackTrace.FirstLine; // 行号
+                var firstMethodName = db.Ado.SqlStackTrace.FirstMethodName; // 方法名
+                var log = $"【{DateTime.Now}——超时SQL】\r\n【所在文件名】:{fileName}\r\n【代码行数】:{fileLine}\r\n【方法名】:{firstMethodName}\r\n" + $"【SQL语句】:{UtilMethods.GetNativeSql(sql, pars)}";
+                Log.Warning(log);
+                App.PrintToMiniProfiler("SqlSugar", "Slow", log);
             };
         }
         // 数据审计
-        db.Aop.DataExecuting = (oldValue, entityInfo) =>
+        db.Aop.DataExecuting = (_, entityInfo) =>
         {
             // 若正在处理种子数据则直接返回
             if (_isHandlingSeedData) return;
@@ -201,40 +200,39 @@ public static class SqlSugarSetup
                     if (createTime == null || createTime.Equals(DateTime.MinValue))
                         entityInfo.SetValue(DateTime.Now);
                 }
-                // 若当前用户非空(web线程时)
-                if (App.User != null)
+                // 若当前用户为空(非web线程时)
+                if (App.User == null) return;
+
+                dynamic entityValue = entityInfo.EntityValue;
+                if (entityInfo.PropertyName == nameof(EntityTenantId.TenantId))
                 {
-                    dynamic entityValue = entityInfo.EntityValue;
-                    if (entityInfo.PropertyName == nameof(EntityTenantId.TenantId))
-                    {
-                        var tenantId = entityValue.TenantId;
-                        if (tenantId == null || tenantId == 0)
-                            entityInfo.SetValue(App.User.FindFirst(ClaimConst.TenantId)?.Value);
-                    }
-                    else if (entityInfo.PropertyName == nameof(EntityBase.CreateUserId))
-                    {
-                        var createUserId = entityValue.CreateUserId;
-                        if (createUserId == 0 || createUserId == null)
-                            entityInfo.SetValue(App.User.FindFirst(ClaimConst.UserId)?.Value);
-                    }
-                    else if (entityInfo.PropertyName == nameof(EntityBase.CreateUserName))
-                    {
-                        var createUserName = entityValue.CreateUserName;
-                        if (string.IsNullOrEmpty(createUserName))
-                            entityInfo.SetValue(App.User.FindFirst(ClaimConst.RealName)?.Value);
-                    }
-                    else if (entityInfo.PropertyName == nameof(EntityBaseData.CreateOrgId))
-                    {
-                        var createOrgId = entityValue.CreateOrgId;
-                        if (createOrgId == 0 || createOrgId == null)
-                            entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgId)?.Value);
-                    }
-                    else if (entityInfo.PropertyName == nameof(EntityBaseData.CreateOrgName))
-                    {
-                        var createOrgName = entityValue.CreateOrgName;
-                        if (string.IsNullOrEmpty(createOrgName))
-                            entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgName)?.Value);
-                    }
+                    var tenantId = entityValue.TenantId;
+                    if (tenantId == null || tenantId == 0)
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.TenantId)?.Value);
+                }
+                else if (entityInfo.PropertyName == nameof(EntityBase.CreateUserId))
+                {
+                    var createUserId = entityValue.CreateUserId;
+                    if (createUserId == 0 || createUserId == null)
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.UserId)?.Value);
+                }
+                else if (entityInfo.PropertyName == nameof(EntityBase.CreateUserName))
+                {
+                    var createUserName = entityValue.CreateUserName;
+                    if (string.IsNullOrEmpty(createUserName))
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.RealName)?.Value);
+                }
+                else if (entityInfo.PropertyName == nameof(EntityBaseData.CreateOrgId))
+                {
+                    var createOrgId = entityValue.CreateOrgId;
+                    if (createOrgId == 0 || createOrgId == null)
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgId)?.Value);
+                }
+                else if (entityInfo.PropertyName == nameof(EntityBaseData.CreateOrgName))
+                {
+                    var createOrgName = entityValue.CreateOrgName;
+                    if (string.IsNullOrEmpty(createOrgName))
+                        entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgName)?.Value);
                 }
             }
             // 编辑/更新
@@ -286,12 +284,11 @@ public static class SqlSugarSetup
                 var beforeColumns = u.BeforeData[i].Columns;
                 for (int j = 0; j < afterColumns.Count; j++)
                 {
-                    if (afterColumns[j].Value.Equals(beforeColumns[j].Value))
-                    {
-                        beforeColumns.Remove(beforeColumns[j]);
-                        afterColumns.Remove(afterColumns[j]);
-                        j--;
-                    }
+                    if (!afterColumns[j].Value.Equals(beforeColumns[j].Value)) continue;
+
+                    beforeColumns.Remove(beforeColumns[j]);
+                    afterColumns.Remove(afterColumns[j]);
+                    j--;
                 }
             }
 
@@ -329,8 +326,7 @@ public static class SqlSugarSetup
         if (config.DbSettings.EnableInitDb)
         {
             Log.Information($"初始化数据库 {config.DbType} - {config.ConfigId} - {config.ConnectionString}");
-            if (config.DbType != SqlSugar.DbType.Oracle)
-                dbProvider.DbMaintenance.CreateDatabase();
+            if (config.DbType != SqlSugar.DbType.Oracle) dbProvider.DbMaintenance.CreateDatabase();
         }
 
         // 初始化表结构
@@ -362,87 +358,96 @@ public static class SqlSugarSetup
         // 初始化种子数据
         if (config.SeedSettings.EnableInitSeed)
         {
-            _isHandlingSeedData = true;
-
-            Log.Information($"初始化种子数据 {config.DbType} - {config.ConfigId}");
-            var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))))
-                .WhereIF(config.SeedSettings.EnableIncreSeed, u => u.IsDefined(typeof(IncreSeedAttribute), false))
-                .OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList();
+            
+        }
+    }
 
-            int count = 0, sum = seedDataTypes.Count;
-            foreach (var seedType in seedDataTypes)
+    /// <summary>
+    /// 初始化种子数据
+    /// </summary>
+    /// <param name="db"></param>
+    /// <param name="config"></param>
+    private static void InitSeedData(SqlSugarScope db, DbConnectionConfig config)
+    {
+        SqlSugarScopeProvider dbProvider = db.GetConnectionScope(config.ConfigId); 
+        _isHandlingSeedData = true;
+        
+        Log.Information($"初始化种子数据 {config.DbType} - {config.ConfigId}");
+        var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))))
+            .WhereIF(config.SeedSettings.EnableIncreSeed, u => u.IsDefined(typeof(IncreSeedAttribute), false))
+            .OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList();
+        
+        int count = 0, sum = seedDataTypes.Count; 
+        foreach (var seedType in seedDataTypes) 
+        { 
+            var entityType = seedType.GetInterfaces().First().GetGenericArguments().First(); 
+            if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) // 默认库(有系统表特性、没有日志表和租户表特性)
             {
-                var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
-                if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) // 默认库(有系统表特性、没有日志表和租户表特性)
-                {
-                    if (entityType.GetCustomAttribute<SysTableAttribute>() == null && (entityType.GetCustomAttribute<LogTableAttribute>() != null || entityType.GetCustomAttribute<TenantAttribute>() != null))
-                        continue;
-                }
-                else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库
-                {
-                    if (entityType.GetCustomAttribute<LogTableAttribute>() == null)
-                        continue;
-                }
-                else
+                if (entityType.GetCustomAttribute<SysTableAttribute>() == null && (entityType.GetCustomAttribute<LogTableAttribute>() != null || entityType.GetCustomAttribute<TenantAttribute>() != null)) continue;
+            }
+            else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库
+            {
+                if (entityType.GetCustomAttribute<LogTableAttribute>() == null) continue;
+            }
+            else
+            {
+                var att = entityType.GetCustomAttribute<TenantAttribute>(); // 自定义的库
+                if (att == null || att.configId.ToString() != config.ConfigId.ToString()) continue;
+            }
+            
+            var instance = Activator.CreateInstance(seedType); 
+            var hasDataMethod = seedType.GetMethod("HasData"); 
+            var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>(); 
+            if (seedData == null) continue;
+            
+            var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType); 
+            Console.WriteLine($"添加数据 {entityInfo.DbTableName} ({config.ConfigId} - {++count}/{sum},数据量:{seedData.Count()})"); 
+            
+            // 若实体包含Id字段,则设置为当前租户Id递增1
+            if (entityInfo.Columns.Any(u => u.PropertyName == nameof(EntityBaseId.Id))) 
+            {
+                var seedId = config.ConfigId.ToLong();
+                foreach (var sd in seedData)
                 {
-                    var att = entityType.GetCustomAttribute<TenantAttribute>(); // 自定义的库
-                    if (att == null || att.configId.ToString() != config.ConfigId.ToString()) continue;
+                    var id = sd.GetType().GetProperty(nameof(EntityBaseId.Id))!.GetValue(sd, null);
+                    if (id != null && (id.ToString() == "0" || string.IsNullOrWhiteSpace(id.ToString())))
+                        sd.GetType().GetProperty(nameof(EntityBaseId.Id))!.SetValue(sd, ++seedId);
                 }
-
-                var instance = Activator.CreateInstance(seedType);
-                var hasDataMethod = seedType.GetMethod("HasData");
-                var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
-                if (seedData == null) continue;
-
-                var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType);
-                Console.WriteLine($"添加数据 {entityInfo.DbTableName} ({config.ConfigId} - {++count}/{sum},数据量:{seedData.Count()})");
-
-                // 若实体包含Id字段,则设置为当前租户Id递增1
-                if (entityInfo.Columns.Any(u => u.PropertyName == nameof(EntityBaseId.Id)))
+            } 
+            
+            if (entityType.GetCustomAttribute<SplitTableAttribute>(true) != null)
+            {
+                //拆分表的操作需要实体类型,而通过反射很难实现
+                //所以,这里将Init方法写在“种子数据类”内部,再传入 db 反射调用
+                var hasInitMethod = seedType.GetMethod("Init");
+                var parameters = new object[] { db };
+                hasInitMethod?.Invoke(instance, parameters);
+            }
+            else
+            {
+                if (entityInfo.Columns.Any(u => u.IsPrimarykey))
                 {
-                    var seedId = config.ConfigId.ToLong();
-                    foreach (var sd in seedData)
+                    // 按主键进行批量增加和更新
+                    var storage = dbProvider.StorageableByObject(seedData.ToList()).ToStorage();
+                    
+                    // 先修改再插入,否则会更新修改时间字段
+                    if (seedType.GetCustomAttribute<IgnoreUpdateSeedAttribute>() == null) // 有忽略更新种子特性时则不更新
                     {
-                        var id = sd.GetType().GetProperty(nameof(EntityBaseId.Id))!.GetValue(sd, null);
-                        if (id != null && (id.ToString() == "0" || string.IsNullOrWhiteSpace(id.ToString())))
-                            sd.GetType().GetProperty(nameof(EntityBaseId.Id))!.SetValue(sd, ++seedId);
+                        int updateCount = storage.AsUpdateable.IgnoreColumns(entityInfo.Columns.Where(u => u.PropertyInfo.GetCustomAttribute<IgnoreUpdateSeedColumnAttribute>() != null).Select(u => u.PropertyName).ToArray()).ExecuteCommand();
+                        Console.WriteLine($"  修改 {updateCount}/{seedData.Count()} 条记录");
                     }
-                }
-
-                if (entityType.GetCustomAttribute<SplitTableAttribute>(true) != null)
-                {
-                    //拆分表的操作需要实体类型,而通过反射很难实现
-                    //所以,这里将Init方法写在“种子数据类”内部,再传入 db 反射调用
-                    var hasInitMethod = seedType.GetMethod("Init");
-                    var parameters = new object[] { db };
-                    hasInitMethod?.Invoke(instance, parameters);
+                    int insertCount = storage.AsInsertable.ExecuteCommand();
+                    Console.WriteLine($"  插入 {insertCount}/{seedData.Count()} 条记录");
                 }
                 else
                 {
-                    if (entityInfo.Columns.Any(u => u.IsPrimarykey))
-                    {
-                        // 按主键进行批量增加和更新
-                        var storage = dbProvider.StorageableByObject(seedData.ToList()).ToStorage();
-
-                        // 先修改再插入,否则会更新修改时间字段
-                        if (seedType.GetCustomAttribute<IgnoreUpdateSeedAttribute>() == null) // 有忽略更新种子特性时则不更新
-                        {
-                            int updateCount = storage.AsUpdateable.IgnoreColumns(entityInfo.Columns.Where(u => u.PropertyInfo.GetCustomAttribute<IgnoreUpdateSeedColumnAttribute>() != null).Select(u => u.PropertyName).ToArray()).ExecuteCommand();
-                            Console.WriteLine($"  修改 {updateCount}/{seedData.Count()} 条记录");
-                        }
-                        int insertCount = storage.AsInsertable.ExecuteCommand();
-                        Console.WriteLine($"  插入 {insertCount}/{seedData.Count()} 条记录");
-                    }
-                    else
-                    {
-                        // 无主键则只进行插入
-                        if (!dbProvider.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any())
-                            dbProvider.InsertableByObject(seedData.ToList()).ExecuteCommand();
-                    }
+                    // 无主键则只进行插入
+                    if (!dbProvider.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any())
+                        dbProvider.InsertableByObject(seedData.ToList()).ExecuteCommand();
                 }
             }
-            _isHandlingSeedData = false;
         }
+        _isHandlingSeedData = false;
     }
 
     /// <summary>

+ 9 - 9
Admin.NET/Admin.NET.Core/Utils/ChinaDateTimeConverter.cs

@@ -14,16 +14,16 @@ namespace Admin.NET.Core;
 /// </summary>
 public class ChinaDateTimeConverter : DateTimeConverterBase
 {
-    private static readonly IsoDateTimeConverter dtConverter = new() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
+    private static readonly IsoDateTimeConverter DtConverter = new() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
 
     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
     {
-        return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
+        return DtConverter.ReadJson(reader, objectType, existingValue, serializer);
     }
 
     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
     {
-        dtConverter.WriteJson(writer, value, serializer);
+        DtConverter.WriteJson(writer, value, serializer);
     }
 }
 
@@ -32,16 +32,16 @@ public class ChinaDateTimeConverter : DateTimeConverterBase
 /// </summary>
 public class ChinaDateTimeConverterHH : DateTimeConverterBase
 {
-    private static readonly IsoDateTimeConverter dtConverter = new() { DateTimeFormat = "yyyy-MM-dd HH:mm" };
+    private static readonly IsoDateTimeConverter DtConverter = new() { DateTimeFormat = "yyyy-MM-dd HH:mm" };
 
     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
     {
-        return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
+        return DtConverter.ReadJson(reader, objectType, existingValue, serializer);
     }
 
     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
     {
-        dtConverter.WriteJson(writer, value, serializer);
+        DtConverter.WriteJson(writer, value, serializer);
     }
 }
 
@@ -50,15 +50,15 @@ public class ChinaDateTimeConverterHH : DateTimeConverterBase
 /// </summary>
 public class ChinaDateTimeConverterDate : DateTimeConverterBase
 {
-    private static readonly IsoDateTimeConverter dtConverter = new() { DateTimeFormat = "yyyy-MM-dd" };
+    private static readonly IsoDateTimeConverter DtConverter = new() { DateTimeFormat = "yyyy-MM-dd" };
 
     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
     {
-        return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
+        return DtConverter.ReadJson(reader, objectType, existingValue, serializer);
     }
 
     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
     {
-        dtConverter.WriteJson(writer, value, serializer);
+        DtConverter.WriteJson(writer, value, serializer);
     }
 }

+ 28 - 50
Admin.NET/Admin.NET.Core/Utils/CodeGenUtil.cs

@@ -55,63 +55,41 @@ public static class CodeGenUtil
 
         var dataType = dbType switch
         {
-            DbType.Oracle => ConvertDataType_OracleSQL(string.IsNullOrEmpty(dbColumnInfo.OracleDataType) ? dbColumnInfo.DataType : dbColumnInfo.OracleDataType, dbColumnInfo.Length, dbColumnInfo.Scale),
-            DbType.PostgreSQL => ConvertDataType_PostgreSQL(dbColumnInfo.DataType),
-            _ => ConvertDataType_Default(dbColumnInfo.DataType),
+            DbType.Oracle => ConvertDataTypeOracleSql(string.IsNullOrEmpty(dbColumnInfo.OracleDataType) ? dbColumnInfo.DataType : dbColumnInfo.OracleDataType, dbColumnInfo.Length, dbColumnInfo.Scale),
+            DbType.PostgreSQL => ConvertDataTypePostgresSql(dbColumnInfo.DataType),
+            _ => ConvertDataTypeDefault(dbColumnInfo.DataType),
         };
         return dataType + (dbColumnInfo.IsNullable ? "?" : "");
     }
 
-    public static string ConvertDataType_OracleSQL(string dataType, int? length, int? scale)
+    public static string ConvertDataTypeOracleSql(string dataType, int? length, int? scale)
     {
         switch (dataType.ToLower())
         {
-            case "interval year to month":
-                return "int";
-
-            case "interval day to second":
-                return "TimeSpan";
-
-            case "smallint":
-                return "Int16";
-
+            case "interval year to month": return "int";
+            
+            case "interval day to second": return "TimeSpan";
+            
+            case "smallint": return "Int16";
+            
             case "int":
-            case "integer":
-                return "int";
-
-            case "long":
-                return "long";
-
-            case "float":
-                return "float";
-
-            case "decimal":
-                return "decimal";
-
+            case "integer": return "int";
+            
+            case "long": return "long";
+            
+            case "float": return "float";
+            
+            case "decimal": return "decimal";
+            
             case "number":
-                if (length != null)
+                if (length == null) return "decimal";
+                return scale switch
                 {
-                    if (scale != null && scale > 0)
-                    {
-                        return "decimal";
-                    }
-                    else if ((scale != null && scale == 0) || scale == null)
-                    {
-                        if (length > 1 && length < 12)
-                        {
-                            return "int";
-                        }
-                        else if (length > 11)
-                        {
-                            return "long";
-                        }
-                    }
-                    if (length == 1)
-                    {
-                        return "bool";
-                    }
-                }
-                return "decimal";
+                    > 0 => "decimal",
+                    0 or null when length is > 1 and < 12 => "int",
+                    0 or null when length > 11 => "long",
+                    _ => length == 1 ? "bool" : "decimal"
+                };
 
             case "char":
             case "clob":
@@ -145,8 +123,8 @@ public static class CodeGenUtil
         }
     }
 
-    //PostgreSQL数据类型对应的字段类型
-    public static string ConvertDataType_PostgreSQL(string dataType)
+    //PostgresSQL数据类型对应的字段类型
+    public static string ConvertDataTypePostgresSql(string dataType)
     {
         switch (dataType)
         {
@@ -229,7 +207,7 @@ public static class CodeGenUtil
         }
     }
 
-    public static string ConvertDataType_Default(string dataType)
+    public static string ConvertDataTypeDefault(string dataType)
     {
         return dataType.ToLower() switch
         {

+ 38 - 44
Admin.NET/Admin.NET.Core/Utils/CommonUtil.cs

@@ -43,15 +43,15 @@ public static class CommonUtil
     /// <summary>
     /// 生成百分数
     /// </summary>
-    /// <param name="PassCount"></param>
+    /// <param name="passCount"></param>
     /// <param name="allCount"></param>
     /// <returns></returns>
-    public static string ExecPercent(decimal PassCount, decimal allCount)
+    public static string ExecPercent(decimal passCount, decimal allCount)
     {
         string res = "";
         if (allCount > 0)
         {
-            var value = (double)Math.Round(PassCount / allCount * 100, 1);
+            var value = (double)Math.Round(passCount / allCount * 100, 1);
             if (value < 0)
                 res = Math.Round(value + 5 / Math.Pow(10, 0 + 1), 0, MidpointRounding.AwayFromZero).ToString();
             else
@@ -155,17 +155,17 @@ public static class CommonUtil
     public static async Task<IActionResult> ExportExcelData<TSource, TTarget>(ISugarQueryable<TSource> query, Func<TSource, TTarget, TTarget> action = null)
         where TSource : class, new() where TTarget : class, new()
     {
-        var PropMappings = GetExportPropertMap<TSource, TTarget>();
+        var propMappings = GetExportPropertMap<TSource, TTarget>();
         var data = query.ToList();
         //相同属性复制值,字典值转换
         var result = new List<TTarget>();
         foreach (var item in data)
         {
             var newData = new TTarget();
-            foreach (var dict in PropMappings)
+            foreach (var dict in propMappings)
             {
-                var targeProp = dict.Value.Item3;
-                if (targeProp != null)
+                var targetProp = dict.Value.Item3;
+                if (targetProp != null)
                 {
                     var propertyInfo = dict.Value.Item2;
                     var sourceVal = propertyInfo.GetValue(item, null);
@@ -175,21 +175,20 @@ public static class CommonUtil
                     }
 
                     var map = dict.Value.Item1;
-                    if (map != null && map.ContainsKey(sourceVal))
+                    if (map != null && map.TryGetValue(sourceVal, out string newVal1))
                     {
-                        var newVal = map[sourceVal];
-                        targeProp.SetValue(newData, newVal);
+                        targetProp.SetValue(newData, newVal1);
                     }
                     else
                     {
-                        if (targeProp.PropertyType.FullName == propertyInfo.PropertyType.FullName)
+                        if (targetProp.PropertyType.FullName == propertyInfo.PropertyType.FullName)
                         {
-                            targeProp.SetValue(newData, sourceVal);
+                            targetProp.SetValue(newData, sourceVal);
                         }
                         else
                         {
-                            var newVal = sourceVal.ToString().ParseTo(targeProp.PropertyType);
-                            targeProp.SetValue(newData, newVal);
+                            var newVal = sourceVal.ToString().ParseTo(targetProp.PropertyType);
+                            targetProp.SetValue(newData, newVal);
                         }
                     }
                 }
@@ -216,20 +215,19 @@ public static class CommonUtil
         IImporter importer = new ExcelImporter();
         var res = await importer.Import<T>(file.OpenReadStream());
         var message = string.Empty;
-        if (res.HasError)
+        
+        if (!res.HasError) return res.Data;
+
+        if (res.Exception != null)
+            message += $"\r\n{res.Exception.Message}";
+        foreach (DataRowErrorInfo drErrorInfo in res.RowErrors)
         {
-            if (res.Exception != null)
-                message += $"\r\n{res.Exception.Message}";
-            foreach (DataRowErrorInfo drErrorInfo in res.RowErrors)
-            {
-                int rowNum = drErrorInfo.RowIndex;
-                foreach (var item in drErrorInfo.FieldErrors)
-                    message += $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)";
-            }
-            message += "\r\n字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList());
-            throw Oops.Oh("导入异常:" + message);
+            int rowNum = drErrorInfo.RowIndex;
+            foreach (var item in drErrorInfo.FieldErrors)
+                message += $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)";
         }
-        return res.Data;
+        message += "\r\n字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList());
+        throw Oops.Oh("导入异常:" + message);
     }
 
     /// <summary>
@@ -251,24 +249,20 @@ public static class CommonUtil
         App.GetRequiredService<SysCacheService>().Set(CacheConst.KeyExcelTemp + userId, resultStream, TimeSpan.FromMinutes(5));
 
         var message = string.Empty;
-        if (res.HasError)
-        {
-            if (res.Exception != null)
-                message += $"\r\n{res.Exception.Message}";
-            foreach (DataRowErrorInfo drErrorInfo in res.RowErrors)
-            {
-                int rowNum = drErrorInfo.RowIndex;
-                foreach (var item in drErrorInfo.FieldErrors)
-                    message += $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)";
-            }
-            if (res.TemplateErrors.Count > 0)
-                message += "\r\n字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList());
+        if (!res.HasError) return res.Data;
 
-            if (message.Length > 200)
-                message = message.Substring(0, 200) + "...\r\n异常过多,建议下载错误标记文件查看详细错误信息并重新导入。";
-            throw Oops.Oh("导入异常:" + message);
+        if (res.Exception != null)
+            message += $"\r\n{res.Exception.Message}";
+        foreach (DataRowErrorInfo drErrorInfo in res.RowErrors)
+        {
+            message = drErrorInfo.FieldErrors.Aggregate(message, (current, item) => current + $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)");
         }
-        return res.Data;
+        if (res.TemplateErrors.Count > 0)
+            message += "\r\n字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList());
+
+        if (message.Length > 200)
+            message = message.Substring(0, 200) + "...\r\n异常过多,建议下载错误标记文件查看详细错误信息并重新导入。";
+        throw Oops.Oh("导入异常:" + message);
     }
 
     /// <summary>
@@ -432,7 +426,7 @@ public static class CommonUtil
             else
             {
                 propMappings.Add(propertyInfo.Name, new Tuple<Dictionary<object, string>, PropertyInfo, PropertyInfo>(
-                    null, sourceProps.ContainsKey(propertyInfo.Name) ? sourceProps[propertyInfo.Name] : null, propertyInfo));
+                    null, sourceProps.TryGetValue(propertyInfo.Name, out PropertyInfo prop) ? prop : null, propertyInfo));
             }
         }
 
@@ -444,7 +438,7 @@ public static class CommonUtil
     /// </summary>
     /// <typeparam name="TTarget"></typeparam>
     /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
-    private static Dictionary<string, Tuple<string, string>> GetExportDicttMap<TTarget>() where TTarget : new()
+    private static Dictionary<string, Tuple<string, string>> GetExportDictMap<TTarget>() where TTarget : new()
     {
         // 整理导入对象的属性名称,目标属性名,字典Code
         var propMappings = new Dictionary<string, Tuple<string, string>>();

+ 10 - 12
Admin.NET/Admin.NET.Core/Utils/ComputerUtil.cs

@@ -30,7 +30,7 @@ public static class ComputerUtil
         memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB";
         memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB";
         memoryMetrics.TotalRam = Math.Round(memoryMetrics.Total / 1024, 2) + "GB";
-        memoryMetrics.RamRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%";
+        memoryMetrics.RamRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total) + "%";
         memoryMetrics.CpuRate = Math.Ceiling(GetCPURate().ParseToDouble()) + "%";
         return memoryMetrics;
     }
@@ -41,25 +41,25 @@ public static class ComputerUtil
     /// <returns></returns>
     public static String GetOSInfo()
     {
-        string opeartion = string.Empty;
+        string operation = string.Empty;
         if (IsMacOS())
         {
             var output = ShellUtil.Bash("sw_vers | awk 'NR<=2{printf \"%s \", $NF}'");
             if (output != null)
             {
-                opeartion = output.Replace("%", string.Empty);
+                operation = output.Replace("%", string.Empty);
             }
         }
         else if (IsUnix())
         {
             var output = ShellUtil.Bash("awk -F= '/^VERSION_ID/ {print $2}' /etc/os-release | tr -d '\"'");
-            opeartion = output ?? string.Empty;
+            operation = output ?? string.Empty;
         }
         else
         {
-            opeartion = RuntimeInformation.OSDescription;
+            operation = RuntimeInformation.OSDescription;
         }
-        return opeartion;
+        return operation;
     }
 
     /// <summary>
@@ -77,8 +77,7 @@ public static class ComputerUtil
             foreach (var item in disks)
             {
                 var disk = item.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
-                if (disk == null || disk.Length < 5)
-                    continue;
+                if (disk.Length < 5) continue;
 
                 var diskInfo = new DiskInfo()
                 {
@@ -105,8 +104,7 @@ public static class ComputerUtil
             foreach (var item in disks)
             {
                 var disk = item.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
-                if (disk == null || disk.Length < 6)
-                    continue;
+                if (disk.Length < 6) continue;
 
                 var diskInfo = new DiskInfo()
                 {
@@ -122,8 +120,8 @@ public static class ComputerUtil
         }
         else
         {
-            var driv = DriveInfo.GetDrives().Where(u => u.IsReady);
-            foreach (var item in driv)
+            var driveList = DriveInfo.GetDrives().Where(u => u.IsReady);
+            foreach (var item in driveList)
             {
                 if (item.DriveType == DriveType.CDRom) continue;
                 var obj = new DiskInfo()

+ 8 - 16
Admin.NET/Admin.NET.Core/Utils/DateTimeUtil.cs

@@ -36,10 +36,7 @@ public class DateTimeUtil
     /// <returns></returns>
     public static DateTime GetBeginTime(DateTime? dateTime, int days = 0)
     {
-        if (dateTime == DateTime.MinValue || dateTime == null)
-            return DateTime.Now.AddDays(days);
-
-        return dateTime ?? DateTime.Now;
+        return dateTime == DateTime.MinValue || dateTime == null ? DateTime.Now.AddDays(days) : (DateTime)dateTime;
     }
 
     /// <summary>
@@ -90,16 +87,16 @@ public class DateTimeUtil
         long hour = (ms - day * dd) / hh;
         long minute = (ms - day * dd - hour * hh) / mi;
         long second = (ms - day * dd - hour * hh - minute * mi) / ss;
-        long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
+        //long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
 
         string sDay = day < 10 ? "0" + day : "" + day; //天
         string sHour = hour < 10 ? "0" + hour : "" + hour;//小时
         string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
         string sSecond = second < 10 ? "0" + second : "" + second;//秒
-        string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
-        sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond;
+        //string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
+        //sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond;
 
-        return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond);
+        return $"{sDay} 天 {sHour} 小时 {sMinute} 分 {sSecond} 秒";
     }
 
     /// <summary>
@@ -140,12 +137,7 @@ public class DateTimeUtil
     /// <returns></returns>
     public static string FormatDateTime(DateTime? dt)
     {
-        if (dt == null) return string.Empty;
-
-        if (dt.Value.Year == DateTime.Now.Year)
-            return dt.Value.ToString("MM-dd HH:mm");
-        else
-            return dt.Value.ToString("yyyy-MM-dd HH:mm");
+        return dt == null ? string.Empty : dt.Value.ToString(dt.Value.Year == DateTime.Now.Year ? "MM-dd HH:mm" : "yyyy-MM-dd HH:mm");
     }
 
     /// <summary>
@@ -156,8 +148,8 @@ public class DateTimeUtil
     {
         return new List<DateTime>
         {
-            Convert.ToDateTime(time.ToString("D").ToString()),
-            Convert.ToDateTime(time.AddDays(1).ToString("D").ToString()).AddSeconds(-1)
+            Convert.ToDateTime(time.ToString("D")),
+            Convert.ToDateTime(time.AddDays(1).ToString("D")).AddSeconds(-1)
         };
     }
 

+ 6 - 6
Admin.NET/Admin.NET.Core/Utils/MiniExcelUtil.cs

@@ -10,8 +10,8 @@ namespace Admin.NET.Core;
 
 public static class MiniExcelUtil
 {
-    private const string _sheetName = "ImportTemplate";
-    private const string _directory = "export";
+    private const string SheetName = "ImportTemplate";
+    private const string DirectoryName = "export";
 
     /// <summary>
     /// 导出模板Excel
@@ -23,7 +23,7 @@ public static class MiniExcelUtil
         // 在内存中当开辟空间
         var memoryStream = new MemoryStream();
         // 将数据写到内存当中
-        await memoryStream.SaveAsAsync(values, sheetName: _sheetName);
+        await memoryStream.SaveAsAsync(values, sheetName: SheetName);
         // 从0的位置开始写入
         memoryStream.Seek(0, SeekOrigin.Begin);
         return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
@@ -41,7 +41,7 @@ public static class MiniExcelUtil
     {
         using MemoryStream stream = new MemoryStream();
         await file.CopyToAsync(stream);
-        var res = await stream.QueryAsync<T>(sheetName: _sheetName);
+        var res = await stream.QueryAsync<T>(sheetName: SheetName);
         return res.ToArray();
     }
 
@@ -54,7 +54,7 @@ public static class MiniExcelUtil
         var fileName = string.Format("{0}.xlsx", YitIdHelper.NextId());
         try
         {
-            var path = Path.Combine(App.WebHostEnvironment.WebRootPath, _directory);
+            var path = Path.Combine(App.WebHostEnvironment.WebRootPath, DirectoryName);
             if (!Directory.Exists(path))
                 Directory.CreateDirectory(path);
             var filePath = Path.Combine(path, fileName);
@@ -65,6 +65,6 @@ public static class MiniExcelUtil
             throw Oops.Oh("出现错误:" + error);
         }
         var host = CommonUtil.GetLocalhost();
-        return $"{host}/{_directory}/{fileName}";
+        return $"{host}/{DirectoryName}/{fileName}";
     }
 }

+ 10 - 10
Admin.NET/Admin.NET.Core/Utils/TripleDES.cs

@@ -22,13 +22,13 @@ public static class TripleDES
     [Obsolete]
     public static void EncryptFile(string inputFile, string outputFile, string password)
     {
-        using var tdes = new TripleDESCryptoServiceProvider();
-        tdes.Mode = CipherMode.ECB;
-        tdes.Padding = PaddingMode.PKCS7;
-        tdes.Key = Encoding.UTF8.GetBytes(password);
+        using var ties = new TripleDESCryptoServiceProvider();
+        ties.Mode = CipherMode.ECB;
+        ties.Padding = PaddingMode.PKCS7;
+        ties.Key = Encoding.UTF8.GetBytes(password);
         using var inputFileStream = new FileStream(inputFile, FileMode.Open);
         using var encryptedFileStream = new FileStream(outputFile, FileMode.Create);
-        using var cryptoStream = new CryptoStream(encryptedFileStream, tdes.CreateEncryptor(), CryptoStreamMode.Write);
+        using var cryptoStream = new CryptoStream(encryptedFileStream, ties.CreateEncryptor(), CryptoStreamMode.Write);
         inputFileStream.CopyTo(cryptoStream);
     }
 
@@ -41,13 +41,13 @@ public static class TripleDES
     [Obsolete]
     public static void DecryptFile(string inputFile, string outputFile, string password)
     {
-        using var tdes = new TripleDESCryptoServiceProvider();
-        tdes.Mode = CipherMode.ECB;
-        tdes.Padding = PaddingMode.PKCS7;
-        tdes.Key = Encoding.UTF8.GetBytes(password);
+        using var ties = new TripleDESCryptoServiceProvider();
+        ties.Mode = CipherMode.ECB;
+        ties.Padding = PaddingMode.PKCS7;
+        ties.Key = Encoding.UTF8.GetBytes(password);
         using var encryptedFileStream = new FileStream(inputFile, FileMode.Open);
         using var decryptedFileStream = new FileStream(outputFile, FileMode.Create);
-        using var cryptoStream = new CryptoStream(encryptedFileStream, tdes.CreateDecryptor(), CryptoStreamMode.Read);
+        using var cryptoStream = new CryptoStream(encryptedFileStream, ties.CreateDecryptor(), CryptoStreamMode.Read);
         cryptoStream.CopyTo(decryptedFileStream);
     }
 }

+ 54 - 57
Admin.NET/Admin.NET.Core/Utils/VerifyFileExtensionName.cs

@@ -11,81 +11,81 @@ namespace Admin.NET.Core;
 /// </summary>
 public static class VerifyFileExtensionName
 {
-    private static readonly IDictionary<string, string> dics_ext = new Dictionary<string, string>();
-    private static readonly IDictionary<string, HashSet<int>> ext_dics = new Dictionary<string, HashSet<int>>();
+    private static readonly IDictionary<string, string> DicsExt = new Dictionary<string, string>();
+    private static readonly IDictionary<string, HashSet<int>> ExtDics = new Dictionary<string, HashSet<int>>();
 
     static VerifyFileExtensionName()
     {
-        dics_ext.Add("FFD8FFE0", ".jpg");
-        dics_ext.Add("FFD8FFE1", ".jpg");
-        dics_ext.Add("89504E47", ".png");
-        dics_ext.Add("47494638", ".gif");
-        dics_ext.Add("49492A00", ".tif");
-        dics_ext.Add("424D", ".bmp");
+        DicsExt.Add("FFD8FFE0", ".jpg");
+        DicsExt.Add("FFD8FFE1", ".jpg");
+        DicsExt.Add("89504E47", ".png");
+        DicsExt.Add("47494638", ".gif");
+        DicsExt.Add("49492A00", ".tif");
+        DicsExt.Add("424D", ".bmp");
 
         // PS和CAD
-        dics_ext.Add("38425053", ".psd");
-        dics_ext.Add("41433130", ".dwg"); // CAD
-        dics_ext.Add("252150532D41646F6265", ".ps");
+        DicsExt.Add("38425053", ".psd");
+        DicsExt.Add("41433130", ".dwg"); // CAD
+        DicsExt.Add("252150532D41646F6265", ".ps");
 
         // 办公文档类
-        dics_ext.Add("D0CF11E0", ".ppt,.doc,.xls"); // ppt、doc、xls
-        dics_ext.Add("504B0304", ".pptx,.docx,.xlsx"); // pptx、docx、xlsx
+        DicsExt.Add("D0CF11E0", ".ppt,.doc,.xls"); // ppt、doc、xls
+        DicsExt.Add("504B0304", ".pptx,.docx,.xlsx"); // pptx、docx、xlsx
 
         /* 注意由于文本文档录入内容过多,则读取文件头时较为多变-START */
-        dics_ext.Add("0D0A0D0A", ".txt"); // txt
-        dics_ext.Add("0D0A2D2D", ".txt"); // txt
-        dics_ext.Add("0D0AB4B4", ".txt"); // txt
-        dics_ext.Add("B4B4BDA8", ".txt"); // 文件头部为汉字
-        dics_ext.Add("73646673", ".txt"); // txt,文件头部为英文字母
-        dics_ext.Add("32323232", ".txt"); // txt,文件头部内容为数字
-        dics_ext.Add("0D0A09B4", ".txt"); // txt,文件头部内容为数字
-        dics_ext.Add("3132330D", ".txt"); // txt,文件头部内容为数字
+        DicsExt.Add("0D0A0D0A", ".txt"); // txt
+        DicsExt.Add("0D0A2D2D", ".txt"); // txt
+        DicsExt.Add("0D0AB4B4", ".txt"); // txt
+        DicsExt.Add("B4B4BDA8", ".txt"); // 文件头部为汉字
+        DicsExt.Add("73646673", ".txt"); // txt,文件头部为英文字母
+        DicsExt.Add("32323232", ".txt"); // txt,文件头部内容为数字
+        DicsExt.Add("0D0A09B4", ".txt"); // txt,文件头部内容为数字
+        DicsExt.Add("3132330D", ".txt"); // txt,文件头部内容为数字
         /* 注意由于文本文档录入内容过多,则读取文件头时较为多变-END */
 
-        dics_ext.Add("7B5C727466", ".rtf"); // 日记本
+        DicsExt.Add("7B5C727466", ".rtf"); // 日记本
 
-        dics_ext.Add("255044462D312E", ".pdf");
+        DicsExt.Add("255044462D312E", ".pdf");
 
         // 视频或音频类
-        dics_ext.Add("3026B275", ".wma");
-        dics_ext.Add("57415645", ".wav");
-        dics_ext.Add("41564920", ".avi");
-        dics_ext.Add("4D546864", ".mid");
-        dics_ext.Add("2E524D46", ".rm");
-        dics_ext.Add("000001BA", ".mpg");
-        dics_ext.Add("000001B3", ".mpg");
-        dics_ext.Add("6D6F6F76", ".mov");
-        dics_ext.Add("3026B2758E66CF11", ".asf");
+        DicsExt.Add("3026B275", ".wma");
+        DicsExt.Add("57415645", ".wav");
+        DicsExt.Add("41564920", ".avi");
+        DicsExt.Add("4D546864", ".mid");
+        DicsExt.Add("2E524D46", ".rm");
+        DicsExt.Add("000001BA", ".mpg");
+        DicsExt.Add("000001B3", ".mpg");
+        DicsExt.Add("6D6F6F76", ".mov");
+        DicsExt.Add("3026B2758E66CF11", ".asf");
 
         // 压缩包
-        dics_ext.Add("52617221", ".rar");
-        dics_ext.Add("504B03040A000000", ".zip");
-        dics_ext.Add("504B030414000000", ".zip");
-        dics_ext.Add("1F8B08", ".gz");
+        DicsExt.Add("52617221", ".rar");
+        DicsExt.Add("504B03040A000000", ".zip");
+        DicsExt.Add("504B030414000000", ".zip");
+        DicsExt.Add("1F8B08", ".gz");
 
         // 程序文件
-        dics_ext.Add("3C3F786D6C", ".xml");
-        dics_ext.Add("68746D6C3E", ".html");
-        dics_ext.Add("04034b50", ".apk");
+        DicsExt.Add("3C3F786D6C", ".xml");
+        DicsExt.Add("68746D6C3E", ".html");
+        DicsExt.Add("04034b50", ".apk");
         //dics_ext.Add("7061636B", ".java");
         //dics_ext.Add("3C254020", ".jsp");
         //dics_ext.Add("4D5A9000", ".exe");
 
-        dics_ext.Add("44656C69766572792D646174653A", ".eml"); // 邮件
-        dics_ext.Add("5374616E64617264204A", ".mdb"); // Access数据库文件
+        DicsExt.Add("44656C69766572792D646174653A", ".eml"); // 邮件
+        DicsExt.Add("5374616E64617264204A", ".mdb"); // Access数据库文件
 
-        dics_ext.Add("46726F6D", ".mht");
-        dics_ext.Add("4D494D45", ".mhtml");
+        DicsExt.Add("46726F6D", ".mht");
+        DicsExt.Add("4D494D45", ".mhtml");
 
-        foreach (var dics in dics_ext)
+        foreach (var dics in DicsExt)
         {
             foreach (var ext in dics.Value.Split(","))
             {
-                if (!ext_dics.ContainsKey(ext))
-                    ext_dics.Add(ext, new HashSet<int> { dics.Key.Length / 2 });
+                if (!ExtDics.ContainsKey(ext))
+                    ExtDics.Add(ext, new HashSet<int> { dics.Key.Length / 2 });
                 else
-                    ext_dics[ext].Add(dics.Key.Length / 2);
+                    ExtDics[ext].Add(dics.Key.Length / 2);
             }
         }
     }
@@ -102,18 +102,17 @@ public static class VerifyFileExtensionName
             return false;
 
         suffix = suffix.ToLower();
-        if (!ext_dics.ContainsKey(suffix))
-            return false;
+        if (!ExtDics.TryGetValue(suffix, out HashSet<int> dic)) return false;
 
         try
         {
-            foreach (var Len in ext_dics[suffix])
+            foreach (var len in dic)
             {
-                byte[] b = new byte[Len];
+                byte[] b = new byte[len];
                 stream.Read(b, 0, b.Length);
                 // string fileType = System.Text.Encoding.UTF8.GetString(b);
                 string fileKey = GetFileHeader(b);
-                if (dics_ext.ContainsKey(fileKey))
+                if (DicsExt.ContainsKey(fileKey))
                     return true;
             }
         }
@@ -152,14 +151,12 @@ public static class VerifyFileExtensionName
         if (src == null || src.Length <= 0)
             return null;
 
-        string hv;
         for (int i = 0; i < src.Length; i++)
         {
             // 以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式,并转换为大写
-            hv = Convert.ToString(src[i] & 0xFF, 16).ToUpper();
-            if (hv.Length < 2)
-                builder.Append(0);
-            builder.Append(hv);
+            string hVal = Convert.ToString(src[i] & 0xFF, 16).ToUpper();
+            if (hVal.Length < 2) builder.Append(0);
+            builder.Append(hVal);
         }
         return builder.ToString();
     }

+ 1 - 4
Admin.NET/Admin.NET.Core/Utils/XlsxFileResult.cs

@@ -89,10 +89,7 @@ public class XlsxFileResultBase : ActionResult
         var response = context.HttpContext.Response;
         response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
 
-        if (downloadFileName == null)
-        {
-            downloadFileName = Guid.NewGuid().ToString("N") + ".xlsx";
-        }
+        downloadFileName ??= Guid.NewGuid().ToString("N") + ".xlsx";
 
         if (string.IsNullOrEmpty(Path.GetExtension(downloadFileName)))
         {

+ 15 - 0
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Input.cs.vm

@@ -18,6 +18,12 @@ public class @(Model.ClassName)BaseInput
     @:/// <summary>
     @:/// @column.ColumnComment
     @:/// </summary>
+    if (column.EffectType is "EnumSelector" or "DictSelector") {
+    @:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
+    }
+    if (column.WhetherRequired == "Y") {
+    @:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
+    }
     @:public virtual @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
     @:
 }
@@ -38,6 +44,9 @@ public class Page@(Model.ClassName)Input : BasePageInput
     @:/// <summary>
     @:/// @column.ColumnComment
     @:/// </summary>
+    if (column.EffectType is "EnumSelector" or "DictSelector") {
+    @:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
+    }
     @:public @Model.GetNullableNetType(column.NetType) @column.PropertyName { get; set; }
     }
     @:
@@ -53,6 +62,9 @@ public class Add@(Model.ClassName)Input
     @:/// <summary>
     @:/// @column.ColumnComment
     @:/// </summary>
+    if (column.EffectType is "EnumSelector" or "DictSelector") {
+    @:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
+    }
     if (column.WhetherRequired == "Y") {
     @:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
     }
@@ -88,6 +100,9 @@ public class Update@(Model.ClassName)Input
     @:/// <summary>
     @:/// @column.ColumnComment
     @:/// </summary>    
+    if (column.EffectType is "EnumSelector" or "DictSelector") {
+    @:[Dict(@(column.EffectType == "EnumSelector" ? $"nameof({column.DictTypeCode})" : $"\"{column.DictTypeCode}\""), AllowNullValue=true)]
+    }
     if (column.WhetherRequired == "Y" || column.ColumnKey == "True") {
     @:[Required(ErrorMessage = "@(column.ColumnComment)不能为空")]
     }

+ 13 - 8
Web/src/components/table/dictLabel.vue

@@ -1,5 +1,6 @@
 <template>
-	<el-Tag :type="state.tagType">{{ state.label }}</el-Tag>
+	<el-Tag v-if="state.dict" :type="state.dict.tagType ?? 'primary'">{{ state.dict[props.propLabel] ?? props.defaultValue }}</el-Tag>
+  <span v-else>{{ props.value }}</span>
 </template>
 
 <script lang="ts" setup>
@@ -23,9 +24,16 @@ const props = defineProps({
 	},
 });
 
+const tagTypeMap = {
+  "success": 1,
+  "warning": 1,
+  "info": 1,
+  "primary": 1,
+  "danger": 1
+} as any;
+
 const state = reactive({
-	label: props.defaultValue as string,
-	tagType: "primary" as "success" | "warning" | "info" | "primary" | "danger"
+  dict: null as any,
 });
 
 onMounted(() => {
@@ -38,10 +46,7 @@ watch(
 );
 
 const setDictValue = (value: any) => {
-  const dict = useUserInfo().dictList[props.code]?.find((x: any) => x[props.propValue] == value);
-  if (dict) {
-    state.label = dict[props.propLabel] || props.defaultValue;
-    state.tagType = dict.tagType ?? "primary";
-  }
+  state.dict = useUserInfo().dictList[props.code]?.find((x: any) => x[props.propValue] == value);
+  if (state.dict != null && !tagTypeMap[state.dict.tagType]) state.dict.tagType = "primary";
 }
 </script>

+ 1 - 1
Web/src/utils/download.ts

@@ -113,7 +113,7 @@ export function getFileName(headers: RawAxiosResponseHeaders | AxiosResponseHead
  * @param res
  * @param fileName 文件名
  */
-export function downloadStreamFile(res: any, fileName: string | undefined) {
+export function downloadStreamFile(res: any, fileName: string | undefined = undefined) {
 	const contentType = res.headers['content-type'];
 	fileName = fileName || getFileName(res.headers['content-disposition']);
 	const blob = res.data instanceof Blob ? res.data : new Blob([res.data], { type: contentType });