Procházet zdrojové kódy

Merge branch 'next' of https://gitee.com/tao-wen/Admin.NET into next

hans_wen před 1 rokem
rodič
revize
41422ce655

+ 1 - 0
Admin.NET/Admin.NET.Application/Admin.NET.Application.csproj

@@ -4,6 +4,7 @@
     <TargetFramework>net6.0</TargetFramework>
     <NoWarn>1701;1702;1591;8632</NoWarn>
     <DocumentationFile></DocumentationFile>
+    <ImplicitUsings>enable</ImplicitUsings>
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
     <Nullable>disable</Nullable>
     <Copyright>© Admin.NET</Copyright>

+ 8 - 7
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -19,10 +19,10 @@
     <PackageReference Include="AspNet.Security.OAuth.Gitee" Version="6.0.15" />
     <PackageReference Include="AspNet.Security.OAuth.Weixin" Version="6.0.15" />
     <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
-    <PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.13.8" />
-    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.2.25" />
-    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.2.25" />
-    <PackageReference Include="Furion.Pure" Version="4.9.2.25" />
+    <PackageReference Include="Elastic.Clients.Elasticsearch" Version="8.13.11" />
+    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.2.35" />
+    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.2.35" />
+    <PackageReference Include="Furion.Pure" Version="4.9.2.35" />
     <PackageReference Include="IPTools.China" Version="1.6.0" />
     <PackageReference Include="IPTools.International" Version="1.6.0" />
     <PackageReference Include="Lazy.Captcha.Core" Version="2.0.6" />
@@ -35,12 +35,13 @@
     <PackageReference Include="NewLife.Redis" Version="5.6.2024.420-beta0005" />
     <PackageReference Include="Novell.Directory.Ldap.NETStandard" Version="3.6.0" />
     <PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.1.9" />
+    <PackageReference Include="QRCoder" Version="1.5.1" />
     <PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
     <PackageReference Include="SixLabors.ImageSharp.Web" Version="3.1.2" />
-    <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="3.0.0" />
+    <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="3.1.0" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.2.0" />
-    <PackageReference Include="SqlSugarCore" Version="5.1.4.152" />
-    <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.12" />
+    <PackageReference Include="SqlSugarCore" Version="5.1.4.154" />
+    <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.13" />
     <PackageReference Include="UAParser" Version="3.1.47" />
     <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
     <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.29" />

+ 6 - 0
Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs

@@ -25,6 +25,12 @@ public enum ErrorCodeEnum
     [ErrorCodeItemMetadata("账号不存在")]
     D0009,
 
+    /// <summary>
+    /// 密匙不匹配
+    /// </summary>
+    [ErrorCodeItemMetadata("密匙不匹配")]
+    D0010,
+
     /// <summary>
     /// 密码不正确
     /// </summary>

+ 2 - 1
Admin.NET/Admin.NET.Core/Logging/DatabaseLoggingWriter.cs

@@ -45,7 +45,8 @@ public class DatabaseLoggingWriter : IDatabaseLoggingWriter, IDisposable
                 TraceId = logMsg.TraceId,
                 Exception = logMsg.Exception == null ? null : JSON.Serialize(logMsg.Exception),
                 Message = logMsg.Message,
-                LogLevel = logMsg.LogLevel
+                LogLevel = logMsg.LogLevel,
+                Status = "200",
             }).ExecuteCommandAsync();
             return;
         }

+ 0 - 1
Admin.NET/Admin.NET.Core/SeedData/SysDictDataSeedData.cs

@@ -65,7 +65,6 @@ public class SysDictDataSeedData : ISqlSugarEntitySeedData<SysDictData>
             new SysDictData{ Id=1300000000504, DictTypeId=1300000000105, Value="EntityTenant【租户实体】", Code="EntityTenant", OrderNo=1, Remark="【租户实体】", Status=StatusEnum.Disable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
             new SysDictData{ Id=1300000000505, DictTypeId=1300000000105, Value="EntityBaseData【业务实体】", Code="EntityBaseData", OrderNo=1, Remark="【业务实体】", Status=StatusEnum.Disable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
             new SysDictData{ Id=1300000000506, DictTypeId=1300000000105, Value="EntityTenantBaseData【租户业务实体】", Code="EntityTenantBaseData", OrderNo=1, Remark="【租户业务实体】", Status=StatusEnum.Disable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
-            new SysDictData{ Id=1300000000507, DictTypeId=1300000000105, Value="无基类", Code="", OrderNo=1, Remark="【无基类】", Status=StatusEnum.Disable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
 
             new SysDictData{ Id=1300000000601, DictTypeId=1300000000106, Value="不需要", Code="off", OrderNo=100, Remark="不需要打印支持", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") },
             new SysDictData{ Id=1300000000602, DictTypeId=1300000000106, Value="绑定打印模版", Code="custom", OrderNo=101, Remark="绑定打印模版", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") },

+ 9 - 2
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -90,7 +90,14 @@ public class SysAuthService : IDynamicApiController, ITransient
             throw Oops.Oh(ErrorCodeEnum.Z1003);
 
         // 国密SM2解密(前端密码传输SM2加密后的)
-        input.Password = CryptogramUtil.SM2Decrypt(input.Password);
+        try
+        {
+            input.Password = CryptogramUtil.SM2Decrypt(input.Password);
+        }
+        catch
+        {
+            throw Oops.Oh(ErrorCodeEnum.D0010);
+        }
 
         // 是否开启域登录验证
         if (await _sysConfigService.GetConfigValue<bool>(CommonConst.SysDomainLogin))
@@ -248,7 +255,7 @@ public class SysAuthService : IDynamicApiController, ITransient
         var org = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysOrg>>().GetFirstAsync(u => u.Id == user.OrgId);
         // 获取职位
         var pos = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysPos>>().GetFirstAsync(u => u.Id == user.PosId);
-        // 获取拥有按钮权限集合
+        // 获取按钮集合
         var buttons = await _sysMenuService.GetOwnBtnPermList();
         // 获取权限集合
         var roleIds = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserRole>>().AsQueryable()

+ 9 - 4
Admin.NET/Admin.NET.Core/Service/Org/SysOrgService.cs

@@ -117,11 +117,16 @@ public class SysOrgService : IDynamicApiController, ITransient
         }
 
         // 删除与此父机构有关的用户机构缓存
-        var pOrg = await _sysOrgRep.GetFirstAsync(u => u.Id == input.Pid);
-        if (pOrg != null)
-            DeleteAllUserOrgCache(pOrg.Id, pOrg.Pid);
-        else if (input.Pid == 0)
+        if (input.Pid == 0)
+        {
             DeleteAllUserOrgCache(0, 0);
+        }
+        else
+        {
+            var pOrg = await _sysOrgRep.GetFirstAsync(u => u.Id == input.Pid);
+            if (pOrg != null)
+                DeleteAllUserOrgCache(pOrg.Id, pOrg.Pid);
+        }
 
         var newOrg = await _sysOrgRep.AsInsertable(input.Adapt<SysOrg>()).ExecuteReturnEntityAsync();
         return newOrg.Id;

+ 5 - 3
Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs

@@ -43,7 +43,8 @@ public class SysRoleService : IDynamicApiController, ITransient
     public async Task<SqlSugarPagedList<SysRole>> Page(PageRoleInput input)
     {
         return await _sysRoleRep.AsQueryable()
-            .WhereIF(!_userManager.SuperAdmin, u => u.CreateUserId == _userManager.UserId) // 若非超管,则只能操作自己创建的角色
+            .WhereIF(!_userManager.SuperAdmin, u => u.TenantId == _userManager.TenantId) // 若非超管,则只能操作本租户的角色
+            .WhereIF(!_userManager.SuperAdmin && !_userManager.SysAdmin, u => u.CreateUserId == _userManager.UserId) // 若非超管且非系统管理员,则只能操作自己创建的角色
             .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
             .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code))
             .OrderBy(u => u.OrderNo)
@@ -58,10 +59,11 @@ public class SysRoleService : IDynamicApiController, ITransient
     public async Task<List<RoleOutput>> GetList()
     {
         // 当前用户已拥有的角色集合
-        var roleIdList = _userManager.SuperAdmin ? null : await _sysUserRoleService.GetUserRoleIdList(_userManager.UserId);
+        var roleIdList = _userManager.SuperAdmin ? new List<long>() : await _sysUserRoleService.GetUserRoleIdList(_userManager.UserId);
 
         return await _sysRoleRep.AsQueryable()
-            .WhereIF(roleIdList != null, u => u.CreateUserId == _userManager.UserId || roleIdList.Contains(u.Id)) // 若非超管,则只显示自己创建和已拥有的角色
+            .WhereIF(!_userManager.SuperAdmin, u => u.TenantId == _userManager.TenantId) // 若非超管,则只能操作本租户的角色
+            .WhereIF(!_userManager.SuperAdmin && !_userManager.SysAdmin, u => u.CreateUserId == _userManager.UserId || roleIdList.Contains(u.Id)) // 若非超管且非系统管理员,则只显示自己创建和已拥有的角色
             .OrderBy(u => u.OrderNo).Select<RoleOutput>().ToListAsync();
     }
 

+ 27 - 2
Admin.NET/Admin.NET.Core/Service/Server/SysServerService.cs

@@ -4,13 +4,20 @@
 //
 // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
 
+using AlibabaCloud.SDK.Dysmsapi20170525.Models;
 using AngleSharp.Html.Parser;
+using AspNet.Security.OAuth.Gitee;
+using AspNet.Security.OAuth.Weixin;
 using AspNetCoreRateLimit;
 using Elastic.Clients.Elasticsearch;
+using IPTools.Core;
 using Lazy.Captcha.Core;
 using Magicodes.ExporterAndImporter.Pdf;
+using Magicodes.ExporterAndImporter.Word;
 using MailKit.Net.Smtp;
+using Novell.Directory.Ldap;
 using OnceMi.AspNetCore.OSS;
+using QRCoder;
 
 namespace Admin.NET.Core.Service;
 
@@ -96,15 +103,24 @@ public class SysServerService : IDynamicApiController, ITransient
         var jsonAssembly = typeof(NewtonsoftJsonMvcCoreBuilderExtensions).Assembly.GetName();
         var excelAssembly = typeof(IExcelImporter).Assembly.GetName();
         var pdfAssembly = typeof(IPdfExporter).Assembly.GetName();
+        var wordAssembly = typeof(IWordExporter).Assembly.GetName();
         var captchaAssembly = typeof(ICaptcha).Assembly.GetName();
         var wechatApiAssembly = typeof(WechatApiClient).Assembly.GetName();
         var wechatTenpayAssembly = typeof(WechatTenpayClient).Assembly.GetName();
         var ossAssembly = typeof(IOSSServiceFactory).Assembly.GetName();
         var parserAssembly = typeof(Parser).Assembly.GetName();
-        var nestAssembly = typeof(ElasticsearchClient).Assembly.GetName();
+        var elasticsearchClientAssembly = typeof(ElasticsearchClient).Assembly.GetName();
         var limitAssembly = typeof(IpRateLimitMiddleware).Assembly.GetName();
         var htmlParserAssembly = typeof(HtmlParser).Assembly.GetName();
         var fluentEmailAssembly = typeof(SmtpClient).Assembly.GetName();
+        var qRCodeGeneratorAssembly = typeof(QRCodeGenerator).Assembly.GetName();
+        var sendSmsRequestAssembly = typeof(SendSmsRequest).Assembly.GetName();
+        var imageAssembly = typeof(Image).Assembly.GetName();
+        var rabbitMQAssembly = typeof(RabbitMQEventSourceStore).Assembly.GetName();
+        var ldapConnectionAssembly = typeof(LdapConnection).Assembly.GetName();
+        var ipToolAssembly = typeof(IpTool).Assembly.GetName();
+        var weixinAuthenticationOptionsAssembly = typeof(WeixinAuthenticationOptions).Assembly.GetName();
+        var giteeAuthenticationOptionsAssembly = typeof(GiteeAuthenticationOptions).Assembly.GetName();
 
         return new[]
         {
@@ -115,15 +131,24 @@ public class SysServerService : IDynamicApiController, ITransient
             new { jsonAssembly.Name, jsonAssembly.Version },
             new { excelAssembly.Name, excelAssembly.Version },
             new { pdfAssembly.Name, pdfAssembly.Version },
+            new { wordAssembly.Name, wordAssembly.Version },
             new { captchaAssembly.Name, captchaAssembly.Version },
             new { wechatApiAssembly.Name, wechatApiAssembly.Version },
             new { wechatTenpayAssembly.Name, wechatTenpayAssembly.Version },
             new { ossAssembly.Name, ossAssembly.Version },
             new { parserAssembly.Name, parserAssembly.Version },
-            new { nestAssembly.Name, nestAssembly.Version },
+            new { elasticsearchClientAssembly.Name, elasticsearchClientAssembly.Version },
             new { limitAssembly.Name, limitAssembly.Version },
             new { htmlParserAssembly.Name, htmlParserAssembly.Version },
             new { fluentEmailAssembly.Name, fluentEmailAssembly.Version },
+            new { qRCodeGeneratorAssembly.Name, qRCodeGeneratorAssembly.Version },
+            new { sendSmsRequestAssembly.Name, sendSmsRequestAssembly.Version },
+            new { imageAssembly.Name, imageAssembly.Version },
+            new { rabbitMQAssembly.Name, rabbitMQAssembly.Version },
+            new { ldapConnectionAssembly.Name, ldapConnectionAssembly.Version },
+            new { ipToolAssembly.Name, ipToolAssembly.Version },
+            new { weixinAuthenticationOptionsAssembly.Name, weixinAuthenticationOptionsAssembly.Version },
+            new { giteeAuthenticationOptionsAssembly.Name, giteeAuthenticationOptionsAssembly.Version },
         };
     }
 }

+ 6 - 1
Admin.NET/Admin.NET.Core/Service/User/SysUserService.cs

@@ -313,6 +313,11 @@ public class SysUserService : IDynamicApiController, ITransient
         var password = await _sysConfigService.GetConfigValue<string>(CommonConst.SysPassword);
         user.Password = CryptogramUtil.Encrypt(password);
         await _sysUserRep.AsUpdateable(user).UpdateColumns(u => u.Password).ExecuteCommandAsync();
+
+        // 清空密码错误次数
+        var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{user.Account}";
+        _sysCacheService.Remove(keyErrorPasswordCount);
+
         return password;
     }
 
@@ -326,8 +331,8 @@ public class SysUserService : IDynamicApiController, ITransient
     {
         var user = await _sysUserRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
 
-        var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{user.Account}";
         // 清空密码错误次数
+        var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{user.Account}";
         _sysCacheService.Remove(keyErrorPasswordCount);
     }
 

+ 5 - 0
Admin.NET/Admin.NET.Core/Service/User/UserManager.cs

@@ -38,6 +38,11 @@ public class UserManager : IScoped
     /// </summary>
     public bool SuperAdmin => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString();
 
+    /// <summary>
+    /// 是否系统管理员
+    /// </summary>
+    public bool SysAdmin => _httpContextAccessor.HttpContext?.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SysAdmin).ToString();
+
     /// <summary>
     /// 组织机构Id
     /// </summary>

+ 4 - 7
Admin.NET/Admin.NET.Core/SignatureAuth/SignatureAuthenticationHandler.cs

@@ -16,16 +16,12 @@ namespace Admin.NET.Core;
 /// </summary>
 public sealed class SignatureAuthenticationHandler : AuthenticationHandler<SignatureAuthenticationOptions>
 {
-    private readonly SysCacheService _cacheService;
-
     public SignatureAuthenticationHandler(IOptionsMonitor<SignatureAuthenticationOptions> options,
         ILoggerFactory logger,
         UrlEncoder encoder,
-        ISystemClock clock,
-        SysCacheService cacheService)
+        ISystemClock clock)
         : base(options, logger, encoder, clock)
     {
-        _cacheService = cacheService;
     }
 
     private new SignatureAuthenticationEvent Events
@@ -78,10 +74,11 @@ public sealed class SignatureAuthenticationHandler : AuthenticationHandler<Signa
             return await AuthenticateResultFailAsync("sign 无效的签名");
 
         // 重放检测
+        var cache = App.GetRequiredService<SysCacheService>();
         var cacheKey = $"{CacheConst.KeyOpenAccessNonce}{accessKey}|{nonce}";
-        if (_cacheService.ExistKey(cacheKey))
+        if (cache.ExistKey(cacheKey))
             return await AuthenticateResultFailAsync("重复的请求");
-        _cacheService.Set(cacheKey, null, Options.AllowedDateDrift * 2); // 缓存过期时间为偏差范围时间的2倍
+        cache.Set(cacheKey, null, Options.AllowedDateDrift * 2); // 缓存过期时间为偏差范围时间的2倍
 
         // 已验证成功
         var signatureValidatedContext = new SignatureValidatedContext(Context, Scheme, Options)

+ 9 - 3
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs

@@ -173,17 +173,22 @@ public static class SqlSugarSetup
         // 数据审计
         db.Aop.DataExecuting = (oldValue, entityInfo) =>
         {
+            // 新增/插入
             if (entityInfo.OperationType == DataFilterType.InsertByObject)
             {
-                // 主键(long类型)且没有值的---赋值雪花Id
+                // 若主键是长整型且空则赋值雪花Id
                 if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long))
                 {
                     var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
                     if (id == null || (long)id == 0)
                         entityInfo.SetValue(YitIdHelper.NextId());
                 }
-                if (entityInfo.PropertyName == nameof(EntityBase.CreateTime))
+                // 若创建时间为空则赋值当前时间
+                else if (entityInfo.PropertyName == nameof(EntityBase.CreateTime) && entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue) == null)
+                {
                     entityInfo.SetValue(DateTime.Now);
+                }
+                // 若当前用户非空(web线程时)
                 if (App.User != null)
                 {
                     if (entityInfo.PropertyName == nameof(EntityTenantId.TenantId))
@@ -218,7 +223,8 @@ public static class SqlSugarSetup
                     }
                 }
             }
-            if (entityInfo.OperationType == DataFilterType.UpdateByObject)
+            // 编辑/更新
+            else if (entityInfo.OperationType == DataFilterType.UpdateByObject)
             {
                 if (entityInfo.PropertyName == nameof(EntityBase.UpdateTime))
                     entityInfo.SetValue(DateTime.Now);

+ 17 - 9
Admin.NET/Admin.NET.Core/Util/CommonUtil.cs

@@ -100,7 +100,6 @@ public static class CommonUtil
         }
     }
 
-
     /// <summary>
     /// 导出模板Excel
     /// </summary>
@@ -114,8 +113,6 @@ public static class CommonUtil
         return new FileStreamResult(new FileStream(res.FileName, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName };
     }
 
-
-
     /// <summary>
     /// 导出模板Excel
     /// </summary>
@@ -129,27 +126,37 @@ public static class CommonUtil
         return await (Task<IActionResult>)closedGenerateTemplateMethod.Invoke(null, new object[] { fileName });
     }
 
-
     /// <summary>
     /// 导入数据Excel
     /// </summary>
     /// <typeparam name="T"></typeparam>
     /// <param name="file"></param>
+    /// <param name="importResultCallback"></param>
     /// <returns></returns>
-    public static async Task<ICollection<T>> ImportExcelData<T>([Required] IFormFile file) where T : class, new()
+    public static async Task<ICollection<T>> ImportExcelData<T>([Required] IFormFile file, Func<ImportResult<T>, ImportResult<T>> importResultCallback = null) where T : class, new()
     {
         var newFile = await App.GetRequiredService<SysFileService>().UploadFile(file, "");
         var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, newFile.FilePath, newFile.Id.ToString() + newFile.Suffix);
+        var errorFileUrl = Path.Combine(newFile.FilePath, newFile.Id.ToString() + "_" + newFile.Suffix);
 
         IImporter importer = new ExcelImporter();
-        var res = await importer.Import<T>(filePath);
+        var res = await importer.Import<T>(filePath, importResultCallback);
         if (res == null || res.Exception != null)
             throw Oops.Oh("导入异常:" + res.Exception);
+        if (res.HasError)
+        {
+            if (res.TemplateErrors.Count > 0)
+            {
+                throw Oops.Oh("导入模板格式错误");
+            }
+            else
+            {
+                throw Oops.Oh($"请下载错误文件,根据提示修改后再次导入,<a href='{errorFileUrl}' target='_blank'>点击下载</a>");
+            }
+        }
         return res.Data;
     }
 
-
-
     /// <summary>
     /// 导入数据Excel
     /// </summary>
@@ -160,7 +167,8 @@ public static class CommonUtil
     {
         MethodInfo importMethod = typeof(CommonUtil).GetMethods().FirstOrDefault(p => p.Name == "ImportExcelData" && p.IsGenericMethodDefinition);
         MethodInfo closedImportMethod = importMethod.MakeGenericMethod(dataDto.GetType());
-        var task = (Task)closedImportMethod.Invoke(null, new object[] { file });
+        var parameters = importMethod.GetParameters();
+        var task = (Task)closedImportMethod.Invoke(null, new object[] { file, parameters[1].DefaultValue });
         await task;
         return task.GetType().GetProperty("Result").GetValue(task);
     }

+ 0 - 1
Admin.NET/Admin.NET.Web.Core/Admin.NET.Web.Core.csproj

@@ -16,7 +16,6 @@
 
   <ItemGroup>
     <ProjectReference Include="..\Admin.NET.Application\Admin.NET.Application.csproj" />
-    <ProjectReference Include="..\Admin.NET.Core\Admin.NET.Core.csproj" />
   </ItemGroup>
 
 </Project>

+ 1 - 1
Admin.NET/Plugins/Admin.NET.Plugin.ReZero/Admin.NET.Plugin.ReZero.csproj

@@ -24,7 +24,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Rezero.Api" Version="1.0.19" />
+    <PackageReference Include="Rezero.Api" Version="1.0.35" />
   </ItemGroup>  
 
   <ItemGroup>

+ 15 - 15
Web/package.json

@@ -13,40 +13,40 @@
 	"dependencies": {
 		"@element-plus/icons-vue": "^2.3.1",
 		"@microsoft/signalr": "^8.0.0",
-		"@vue-office/docx": "^1.6.0",
-		"@vue-office/excel": "^1.7.6",
-		"@vue-office/pdf": "^2.0.1",
+		"@vue-office/docx": "^1.6.1",
+		"@vue-office/excel": "^1.7.8",
+		"@vue-office/pdf": "^2.0.2",
 		"@vueuse/core": "^10.9.0",
 		"@wangeditor/editor": "^5.1.23",
 		"@wangeditor/editor-for-vue": "^5.1.12",
 		"animate.css": "^4.1.1",
 		"axios": "^1.6.8",
 		"countup.js": "^2.8.0",
-		"cropperjs": "^1.6.1",
+		"cropperjs": "^1.6.2",
 		"echarts": "^5.5.0",
 		"echarts-gl": "^2.0.9",
 		"echarts-wordcloud": "^2.1.0",
-		"element-plus": "^2.7.1",
+		"element-plus": "^2.7.2",
 		"js-cookie": "^3.0.5",
 		"js-table2excel": "^1.1.2",
 		"jsplumb": "^2.15.6",
 		"lodash-es": "^4.17.21",
 		"mitt": "^3.0.1",
-		"monaco-editor": "^0.47.0",
+		"monaco-editor": "^0.48.0",
 		"nprogress": "^0.2.0",
 		"pinia": "^2.1.7",
 		"print-js": "^1.6.0",
 		"push.js": "^1.0.12",
 		"qrcodejs2-fixes": "^0.0.2",
 		"qs": "^6.12.1",
-		"relation-graph": "^2.1.42",
+		"relation-graph": "^2.2.0",
 		"screenfull": "^6.0.2",
 		"sm-crypto-v2": "^1.9.0",
 		"sortablejs": "^1.15.2",
 		"splitpanes": "^3.1.5",
 		"vcrontab-3": "^3.3.22",
 		"vform3-builds": "^3.0.10",
-		"vue": "^3.4.23",
+		"vue": "^3.4.26",
 		"vue-clipboard3": "^2.0.0",
 		"vue-demi": "^0.14.7",
 		"vue-grid-layout": "3.0.0-beta1",
@@ -64,22 +64,22 @@
 		"@types/node": "^20.12.7",
 		"@types/nprogress": "^0.2.3",
 		"@types/sortablejs": "^1.15.8",
-		"@typescript-eslint/eslint-plugin": "^7.7.0",
-		"@typescript-eslint/parser": "^7.7.0",
+		"@typescript-eslint/eslint-plugin": "^7.7.1",
+		"@typescript-eslint/parser": "^7.7.1",
 		"@vitejs/plugin-vue": "^5.0.4",
 		"@vitejs/plugin-vue-jsx": "^3.1.0",
-		"@vue/compiler-sfc": "^3.4.23",
-		"code-inspector-plugin": "^0.12.2",
-		"eslint": "^8.56.0",
+		"@vue/compiler-sfc": "^3.4.26",
+		"code-inspector-plugin": "^0.13.0",
+		"eslint": "^9.1.1",
 		"eslint-plugin-vue": "^9.25.0",
 		"less": "^4.2.0",
 		"prettier": "^3.2.5",
 		"rollup-plugin-visualizer": "^5.12.0",
 		"sass": "^1.75.0",
-		"terser": "^5.30.3",
+		"terser": "^5.30.4",
 		"typescript": "^5.4.5",
 		"vite": "^5.2.10",
-		"vite-plugin-cdn-import": "^0.3.5",
+		"vite-plugin-cdn-import": "^1.0.1",
 		"vite-plugin-compression2": "^1.1.0",
 		"vite-plugin-vue-setup-extend-plus": "^0.1.0",
 		"vue-eslint-parser": "^9.4.2"

+ 5 - 35
Web/src/components/iconSelector/index.vue

@@ -1,16 +1,6 @@
 <template>
 	<div class="icon-selector w100 h100">
-		<el-input
-			v-model="state.fontIconSearch"
-			:placeholder="state.fontIconPlaceholder"
-			:clearable="clearable"
-			:disabled="disabled"
-			:size="size"
-			ref="inputWidthRef"
-			@clear="onClearFontIcon"
-			@focus="onIconFocus"
-			@blur="onIconBlur"
-		>
+		<el-input v-model="state.fontIconSearch" :placeholder="state.fontIconPlaceholder" :clearable="clearable" :disabled="disabled" :size="size" ref="inputWidthRef" @clear="onClearFontIcon">
 			<template #prepend>
 				<SvgIcon
 					:name="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix"
@@ -20,15 +10,7 @@
 				<i v-else :class="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix" class="font14"></i>
 			</template>
 		</el-input>
-		<el-popover
-			placement="bottom"
-			:width="state.fontIconWidth"
-			transition="el-zoom-in-top"
-			popper-class="icon-selector-popper"
-			trigger="click"
-			:virtual-ref="inputWidthRef"
-			virtual-triggering
-		>
+		<el-popover placement="bottom" :width="state.fontIconWidth" transition="el-zoom-in-top" popper-class="icon-selector-popper" trigger="click" :virtual-ref="inputWidthRef" virtual-triggering>
 			<template #default>
 				<div class="icon-selector-warp">
 					<div class="icon-selector-warp-title">{{ title }}</div>
@@ -119,20 +101,6 @@ const state = reactive({
 	},
 });
 
-// 处理 input 获取焦点时,modelValue 有值时,改变 input 的 placeholder 值
-const onIconFocus = () => {
-	if (!props.modelValue) return false;
-	state.fontIconSearch = '';
-	state.fontIconPlaceholder = props.modelValue;
-};
-// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
-const onIconBlur = () => {
-	const list = fontIconTabNameList();
-	setTimeout(() => {
-		const icon = list.filter((icon: string) => icon === state.fontIconSearch);
-		if (icon.length <= 0) state.fontIconSearch = '';
-	}, 300);
-};
 // 图标搜索及图标数据显示
 const fontIconSheetsFilterList = computed(() => {
 	const list = fontIconTabNameList();
@@ -159,7 +127,7 @@ const initModeValueEcho = () => {
 // 处理 icon 类型,用于回显时,tab 高亮与初始化数据
 const initFontIconName = () => {
 	let name = 'ali';
-    if(props.modelValue == undefined) name = 'ele';
+	if (props.modelValue == undefined) name = 'ele';
 	else if (props.modelValue!.indexOf('iconfont') > -1) name = 'ali';
 	else if (props.modelValue!.indexOf('ele-') > -1) name = 'ele';
 	else if (props.modelValue!.indexOf('fa') > -1) name = 'awe';
@@ -235,8 +203,10 @@ onMounted(() => {
 watch(
 	() => props.modelValue,
 	() => {
+		state.fontIconSearch = '';
 		initModeValueEcho();
 		initFontIconName();
+		getInputWidth();
 	}
 );
 </script>

+ 5 - 1
Web/src/utils/request.ts

@@ -127,7 +127,11 @@ service.interceptors.response.use(
 			} else {
 				message = serve.message;
 			}
-			ElMessage.error(message);
+			ElMessage({
+				dangerouslyUseHTMLString: true,
+				message: message,
+				type:'error'
+			});
 			throw new Error(message);
 		}
 

+ 5 - 0
Web/src/views/system/dict/component/editDictData.vue

@@ -19,6 +19,11 @@
 							<el-input v-model="state.ruleForm.code" placeholder="编码" clearable />
 						</el-form-item>
 					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="名称" prop="name" :rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]">
+							<el-input v-model="state.ruleForm.name" placeholder="名称" clearable />
+						</el-form-item>
+					</el-col>
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
 						<el-form-item label="标签类型">
 							<el-radio-group v-model="state.ruleForm.tagType">

+ 1 - 0
Web/src/views/system/dict/index.vue

@@ -99,6 +99,7 @@
 							</template>
 						</el-table-column>
 						<el-table-column prop="code" label="编码" header-align="center" min-width="120" show-overflow-tooltip />
+						<el-table-column prop="name" label="名称" header-align="center" min-width="120" show-overflow-tooltip />
 						<el-table-column prop="extData" label="拓展数据" width="90" align="center">
 							<template #default="scope">
 								<el-tag type="warning" v-if="scope.row.extData == null || scope.row.extData == ''">空</el-tag>