diff --git a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj index 9bb9cd9e..b3cfdc0b 100644 --- a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj +++ b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj @@ -18,9 +18,9 @@ - - - + + + @@ -34,10 +34,10 @@ - + - + @@ -45,7 +45,7 @@ - + diff --git a/Admin.NET/Admin.NET.Core/Const/CacheConst.cs b/Admin.NET/Admin.NET.Core/Const/CacheConst.cs index 758e8ce0..6114a8d7 100644 --- a/Admin.NET/Admin.NET.Core/Const/CacheConst.cs +++ b/Admin.NET/Admin.NET.Core/Const/CacheConst.cs @@ -100,4 +100,9 @@ public class CacheConst /// 系统字典缓存 /// public const string KeyDict = "sys_dict:"; + + /// + /// Excel临时文件缓存 + /// + public const string KeyExcelTemp = "sys_excel_temp:"; } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs index 95848948..3e0d5661 100644 --- a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs +++ b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs @@ -70,7 +70,7 @@ public class EnumToDictJob : IJob }); try { - db.Ado.BeginTran(); + db.BeginTran(); if (uSysDictType.Count > 0) await db.Updateable(uSysDictType).ExecuteCommandAsync(stoppingToken); @@ -78,11 +78,11 @@ public class EnumToDictJob : IJob if (uSysDictData.Count > 0) await db.Updateable(uSysDictData).ExecuteCommandAsync(stoppingToken); - db.Ado.CommitTran(); + db.CommitTran(); } catch (Exception error) { - db.Ado.RollbackTran(); + db.RollbackTran(); Log.Error($"{context.Trigger.Description}更新枚举转换字典入库错误:" + _jsonSerializer.Serialize(error)); throw new Exception($"{context.Trigger.Description}更新枚举转换字典入库错误"); } @@ -123,7 +123,7 @@ public class EnumToDictJob : IJob }); try { - db.Ado.BeginTran(); + db.BeginTran(); if (iDictType.Count > 0) await db.Insertable(iDictType).ExecuteCommandAsync(stoppingToken); @@ -131,11 +131,11 @@ public class EnumToDictJob : IJob if (iDictData.Count > 0) await db.Insertable(iDictData).ExecuteCommandAsync(stoppingToken); - db.Ado.CommitTran(); + db.CommitTran(); } catch (Exception error) { - db.Ado.RollbackTran(); + db.RollbackTran(); Log.Error($"{context.Trigger.Description}新增枚举转换字典入库错误:" + _jsonSerializer.Serialize(error)); throw new Exception($"{context.Trigger.Description}新增枚举转换字典入库错误"); } diff --git a/Admin.NET/Admin.NET.Core/SeedData/SysBaseApiSeedData.cs b/Admin.NET/Admin.NET.Core/SeedData/SysBaseApiSeedData.cs index 24055450..0f4b7152 100644 --- a/Admin.NET/Admin.NET.Core/SeedData/SysBaseApiSeedData.cs +++ b/Admin.NET/Admin.NET.Core/SeedData/SysBaseApiSeedData.cs @@ -19,33 +19,34 @@ public class SysBaseApiSeedData : ISqlSugarEntitySeedData { return new[] { - new SysBaseApi { Id = 1300000000001, Route = "sysAuth/login" }, - new SysBaseApi { Id = 1300000000002, Route = "sysAuth/unLockScreen" }, - new SysBaseApi { Id = 1300000000003, Route = "sysAuth/userInfo" }, - new SysBaseApi { Id = 1300000000004, Route = "sysAuth/refreshToken" }, - new SysBaseApi { Id = 1300000000005, Route = "sysAuth/loginConfig" }, - new SysBaseApi { Id = 1300000000006, Route = "sysAuth/watermarkConfig" }, - new SysBaseApi { Id = 1300000000007, Route = "sysAuth/captcha" }, - new SysBaseApi { Id = 1300000000008, Route = "sysMenu/loginMenuTree" }, - new SysBaseApi { Id = 1300000000009, Route = "sysOAuth/signIn" }, - new SysBaseApi { Id = 1300000000010, Route = "sysOAuth/signInCallback" }, - new SysBaseApi { Id = 1300000000011, Route = "sysOnlineUser/page" }, - new SysBaseApi { Id = 1300000000012, Route = "sysOrg/list" }, - new SysBaseApi { Id = 1300000000013, Route = "sysPos/list" }, - new SysBaseApi { Id = 1300000000014, Route = "sysRole/page" }, - new SysBaseApi { Id = 1300000000015, Route = "sysRole/list" }, - new SysBaseApi { Id = 1300000000016, Route = "sysFile/uploadAvatar" }, - new SysBaseApi { Id = 1300000000017, Route = "sysFile/uploadSignature" }, - new SysBaseApi { Id = 1300000000018, Route = "sysUser/baseInfo" }, - new SysBaseApi { Id = 1300000000019, Route = "sysUser/changePwd" }, - new SysBaseApi { Id = 1300000000020, Route = "sysNotice/page" }, - new SysBaseApi { Id = 1300000000021, Route = "sysNotice/add" }, - new SysBaseApi { Id = 1300000000022, Route = "sysNotice/update" }, - new SysBaseApi { Id = 1300000000023, Route = "sysNotice/delete" }, - new SysBaseApi { Id = 1300000000024, Route = "sysNotice/public" }, - new SysBaseApi { Id = 1300000000025, Route = "sysNotice/setRead" }, - new SysBaseApi { Id = 1300000000026, Route = "sysNotice/pageReceived" }, - new SysBaseApi { Id = 1300000000027, Route = "sysNotice/unReadList" }, + new SysBaseApi { Id = 1300000000010, Route = "sysAuth/login" }, + new SysBaseApi { Id = 1300000000020, Route = "sysAuth/unLockScreen" }, + new SysBaseApi { Id = 1300000000030, Route = "sysAuth/userInfo" }, + new SysBaseApi { Id = 1300000000040, Route = "sysAuth/refreshToken" }, + new SysBaseApi { Id = 1300000000050, Route = "sysAuth/loginConfig" }, + new SysBaseApi { Id = 1300000000060, Route = "sysAuth/watermarkConfig" }, + new SysBaseApi { Id = 1300000000070, Route = "sysAuth/captcha" }, + new SysBaseApi { Id = 1300000000080, Route = "sysAuth/logout" }, + new SysBaseApi { Id = 1300000000090, Route = "sysMenu/loginMenuTree" }, + new SysBaseApi { Id = 1300000000100, Route = "sysOAuth/signIn" }, + new SysBaseApi { Id = 1300000000110, Route = "sysOAuth/signInCallback" }, + new SysBaseApi { Id = 1300000000120, Route = "sysOnlineUser/page" }, + new SysBaseApi { Id = 1300000000130, Route = "sysOrg/list" }, + new SysBaseApi { Id = 1300000000140, Route = "sysPos/list" }, + new SysBaseApi { Id = 1300000000150, Route = "sysRole/page" }, + new SysBaseApi { Id = 1300000000160, Route = "sysRole/list" }, + new SysBaseApi { Id = 1300000000170, Route = "sysFile/uploadAvatar" }, + new SysBaseApi { Id = 1300000000180, Route = "sysFile/uploadSignature" }, + new SysBaseApi { Id = 1300000000190, Route = "sysUser/baseInfo" }, + new SysBaseApi { Id = 1300000000200, Route = "sysUser/changePwd" }, + new SysBaseApi { Id = 1300000000210, Route = "sysNotice/page" }, + new SysBaseApi { Id = 1300000000220, Route = "sysNotice/add" }, + new SysBaseApi { Id = 1300000000230, Route = "sysNotice/update" }, + new SysBaseApi { Id = 1300000000240, Route = "sysNotice/delete" }, + new SysBaseApi { Id = 1300000000250, Route = "sysNotice/public" }, + new SysBaseApi { Id = 1300000000260, Route = "sysNotice/setRead" }, + new SysBaseApi { Id = 1300000000270, Route = "sysNotice/pageReceived" }, + new SysBaseApi { Id = 1300000000280, Route = "sysNotice/unReadList" }, }; } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Auth/Dto/SysLdapInput.cs b/Admin.NET/Admin.NET.Core/Service/Auth/Dto/SysLdapInput.cs index 009000b2..b4d45642 100644 --- a/Admin.NET/Admin.NET.Core/Service/Auth/Dto/SysLdapInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/Auth/Dto/SysLdapInput.cs @@ -9,7 +9,7 @@ namespace Admin.NET.Core.Service; /// /// 系统域登录信息配置输入参数 /// -public class SysLdapInput : BasePageInput +public class PageSysLdapInput : BasePageInput { /// /// 关键字查询 diff --git a/Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs b/Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs index 2514891f..fd6679e8 100644 --- a/Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs @@ -27,7 +27,7 @@ public class SysLdapService : IDynamicApiController, ITransient /// /// [DisplayName("获取系统域登录配置分页列表")] - public async Task> Page(SysLdapInput input) + public async Task> Page(PageSysLdapInput input) { return await _sysLdapRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u => u.Host.Contains(input.SearchKey.Trim())) diff --git a/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs b/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs index 6ddead17..46c79d2a 100644 --- a/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Cache/SysCacheService.cs @@ -144,6 +144,10 @@ public class SysCacheService : IDynamicApiController, ISingleton [DisplayName("获取缓存值")] public object GetValue(string key) { + // 若Key经过URL编码则进行解码 + if (Regex.IsMatch(key, @"%[0-9a-fA-F]{2}")) + key = HttpUtility.UrlDecode(key); + return _cacheProvider.Cache == Cache.Default ? _cacheProvider.Cache.Get($"{_cacheOptions.Prefix}{key}") : _cacheProvider.Cache.Get($"{_cacheOptions.Prefix}{key}"); diff --git a/Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/CodeGenInput.cs b/Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/PageCodeGenInput.cs similarity index 93% rename from Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/CodeGenInput.cs rename to Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/PageCodeGenInput.cs index ca7de041..2e51e331 100644 --- a/Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/CodeGenInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/PageCodeGenInput.cs @@ -1,192 +1,192 @@ -// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 -// -// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 -// -// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! - -namespace Admin.NET.Core.Service; - -/// -/// 代码生成参数类 -/// -public class CodeGenInput : BasePageInput -{ - /// - /// 作者姓名 - /// - public virtual string AuthorName { get; set; } - - /// - /// 类名 - /// - public virtual string ClassName { get; set; } - - /// - /// 是否移除表前缀 - /// - public virtual string TablePrefix { get; set; } - - /// - /// 库定位器名 - /// - public virtual string ConfigId { get; set; } - - /// - /// 数据库名(保留字段) - /// - public virtual string DbName { get; set; } - - /// - /// 数据库类型 - /// - public virtual string DbType { get; set; } - - /// - /// 数据库链接 - /// - public virtual string ConnectionString { get; set; } - - /// - /// 生成方式 - /// - public virtual string GenerateType { get; set; } - - /// - /// 数据库表名 - /// - public virtual string TableName { get; set; } - - /// - /// 命名空间 - /// - public virtual string NameSpace { get; set; } - - /// - /// 业务名(业务代码包名称) - /// - public virtual string BusName { get; set; } - - /// - /// 功能名(数据库表名称) - /// - public virtual string TableComment { get; set; } - - /// - /// 菜单应用分类(应用编码) - /// - public virtual string MenuApplication { get; set; } - - /// - /// 是否生成菜单 - /// - public virtual bool GenerateMenu { get; set; } - - /// - /// 菜单父级 - /// - public virtual long? MenuPid { get; set; } - - /// - /// 页面目录 - /// - public virtual string PagePath { get; set; } - - /// - /// 支持打印类型 - /// - public virtual string PrintType { get; set; } - - /// - /// 打印模版名称 - /// - public virtual string PrintName { get; set; } - - /// - /// 是否使用 Api Service - /// - public virtual bool IsApiService { get; set; } -} - -public class AddCodeGenInput : CodeGenInput -{ - /// - /// 数据库表名 - /// - [Required(ErrorMessage = "数据库表名不能为空")] - public override string TableName { get; set; } - - /// - /// 业务名(业务代码包名称) - /// - [Required(ErrorMessage = "业务名不能为空")] - public override string BusName { get; set; } - - /// - /// 命名空间 - /// - [Required(ErrorMessage = "命名空间不能为空")] - public override string NameSpace { get; set; } - - /// - /// 作者姓名 - /// - [Required(ErrorMessage = "作者姓名不能为空")] - public override string AuthorName { get; set; } - - ///// - ///// 类名 - ///// - //[Required(ErrorMessage = "类名不能为空")] - //public override string ClassName { get; set; } - - ///// - ///// 是否移除表前缀 - ///// - //[Required(ErrorMessage = "是否移除表前缀不能为空")] - //public override string TablePrefix { get; set; } - - /// - /// 生成方式 - /// - [Required(ErrorMessage = "生成方式不能为空")] - public override string GenerateType { get; set; } - - ///// - ///// 功能名(数据库表名称) - ///// - //[Required(ErrorMessage = "数据库表名不能为空")] - //public override string TableComment { get; set; } - - /// - /// 是否生成菜单 - /// - [Required(ErrorMessage = "是否生成菜单不能为空")] - public override bool GenerateMenu { get; set; } - - /// - /// 是否使用 Api Service - /// - public override bool IsApiService { get; set; } -} - -public class DeleteCodeGenInput -{ - /// - /// 代码生成器Id - /// - [Required(ErrorMessage = "代码生成器Id不能为空")] - public long Id { get; set; } -} - -public class UpdateCodeGenInput : CodeGenInput -{ - /// - /// 代码生成器Id - /// - [Required(ErrorMessage = "代码生成器Id不能为空")] - public long Id { get; set; } -} - -public class QueryCodeGenInput : DeleteCodeGenInput -{ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Core.Service; + +/// +/// 代码生成参数类 +/// +public class PageCodeGenInput : BasePageInput +{ + /// + /// 作者姓名 + /// + public virtual string AuthorName { get; set; } + + /// + /// 类名 + /// + public virtual string ClassName { get; set; } + + /// + /// 是否移除表前缀 + /// + public virtual string TablePrefix { get; set; } + + /// + /// 库定位器名 + /// + public virtual string ConfigId { get; set; } + + /// + /// 数据库名(保留字段) + /// + public virtual string DbName { get; set; } + + /// + /// 数据库类型 + /// + public virtual string DbType { get; set; } + + /// + /// 数据库链接 + /// + public virtual string ConnectionString { get; set; } + + /// + /// 生成方式 + /// + public virtual string GenerateType { get; set; } + + /// + /// 数据库表名 + /// + public virtual string TableName { get; set; } + + /// + /// 命名空间 + /// + public virtual string NameSpace { get; set; } + + /// + /// 业务名(业务代码包名称) + /// + public virtual string BusName { get; set; } + + /// + /// 功能名(数据库表名称) + /// + public virtual string TableComment { get; set; } + + /// + /// 菜单应用分类(应用编码) + /// + public virtual string MenuApplication { get; set; } + + /// + /// 是否生成菜单 + /// + public virtual bool GenerateMenu { get; set; } + + /// + /// 菜单父级 + /// + public virtual long? MenuPid { get; set; } + + /// + /// 页面目录 + /// + public virtual string PagePath { get; set; } + + /// + /// 支持打印类型 + /// + public virtual string PrintType { get; set; } + + /// + /// 打印模版名称 + /// + public virtual string PrintName { get; set; } + + /// + /// 是否使用 Api Service + /// + public virtual bool IsApiService { get; set; } +} + +public class AddCodeGenInput : PageCodeGenInput +{ + /// + /// 数据库表名 + /// + [Required(ErrorMessage = "数据库表名不能为空")] + public override string TableName { get; set; } + + /// + /// 业务名(业务代码包名称) + /// + [Required(ErrorMessage = "业务名不能为空")] + public override string BusName { get; set; } + + /// + /// 命名空间 + /// + [Required(ErrorMessage = "命名空间不能为空")] + public override string NameSpace { get; set; } + + /// + /// 作者姓名 + /// + [Required(ErrorMessage = "作者姓名不能为空")] + public override string AuthorName { get; set; } + + ///// + ///// 类名 + ///// + //[Required(ErrorMessage = "类名不能为空")] + //public override string ClassName { get; set; } + + ///// + ///// 是否移除表前缀 + ///// + //[Required(ErrorMessage = "是否移除表前缀不能为空")] + //public override string TablePrefix { get; set; } + + /// + /// 生成方式 + /// + [Required(ErrorMessage = "生成方式不能为空")] + public override string GenerateType { get; set; } + + ///// + ///// 功能名(数据库表名称) + ///// + //[Required(ErrorMessage = "数据库表名不能为空")] + //public override string TableComment { get; set; } + + /// + /// 是否生成菜单 + /// + [Required(ErrorMessage = "是否生成菜单不能为空")] + public override bool GenerateMenu { get; set; } + + /// + /// 是否使用 Api Service + /// + public override bool IsApiService { get; set; } +} + +public class DeleteCodeGenInput +{ + /// + /// 代码生成器Id + /// + [Required(ErrorMessage = "代码生成器Id不能为空")] + public long Id { get; set; } +} + +public class UpdateCodeGenInput : PageCodeGenInput +{ + /// + /// 代码生成器Id + /// + [Required(ErrorMessage = "代码生成器Id不能为空")] + public long Id { get; set; } +} + +public class QueryCodeGenInput : DeleteCodeGenInput +{ } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs index 822df72c..a6ab9946 100644 --- a/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs +++ b/Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs @@ -37,7 +37,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient /// /// [DisplayName("获取代码生成分页列表")] - public async Task> Page(CodeGenInput input) + public async Task> Page(PageCodeGenInput input) { return await _db.Queryable() .WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableName.Contains(input.TableName.Trim())) diff --git a/Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs b/Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs index 91813ae2..792fc444 100644 --- a/Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs @@ -121,4 +121,23 @@ public class SysCommonService : IDynamicApiController, ITransient } return apiList; } + + /// + /// 下载标记错误的临时 Excel(全局) + /// + /// + [DisplayName("下载标记错误的临时 Excel")] + public async Task DownloadErrorExcelTemp([FromQuery] string fileName = null) + { + var userId = App.User?.FindFirst(ClaimConst.UserId)?.Value; + var resultStream = App.GetRequiredService().Get(CacheConst.KeyExcelTemp + userId); + + if (resultStream == null) + throw Oops.Oh("错误标记文件已过期。"); + + return await Task.FromResult(new FileStreamResult(resultStream, "application/octet-stream") + { + FileDownloadName = $"{(string.IsNullOrEmpty(fileName) ? "错误标记_" + DateTime.Now.ToString("yyyyMMddhhmmss") : fileName)}.xlsx" + }); + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/OpenAccess/Dto/OpenAccessInput.cs b/Admin.NET/Admin.NET.Core/Service/OpenAccess/Dto/OpenAccessInput.cs index a3d57932..ee899629 100644 --- a/Admin.NET/Admin.NET.Core/Service/OpenAccess/Dto/OpenAccessInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/OpenAccess/Dto/OpenAccessInput.cs @@ -9,7 +9,7 @@ namespace Admin.NET.Core.Service; /// /// 开放接口身份输入参数 /// -public class OpenAccessInput : BasePageInput +public class PageOpenAccessInput : BasePageInput { /// /// 身份标识 diff --git a/Admin.NET/Admin.NET.Core/Service/OpenAccess/SysOpenAccessService.cs b/Admin.NET/Admin.NET.Core/Service/OpenAccess/SysOpenAccessService.cs index b8fdf2c9..d5d92b02 100644 --- a/Admin.NET/Admin.NET.Core/Service/OpenAccess/SysOpenAccessService.cs +++ b/Admin.NET/Admin.NET.Core/Service/OpenAccess/SysOpenAccessService.cs @@ -54,7 +54,7 @@ public class SysOpenAccessService : IDynamicApiController, ITransient /// /// [DisplayName("获取开放接口身份分页列表")] - public async Task> Page(OpenAccessInput input) + public async Task> Page(PageOpenAccessInput input) { return await _sysOpenAccessRep.AsQueryable() .LeftJoin((u, a) => u.BindUserId == a.Id) diff --git a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs index 23d52f70..9b85f273 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs @@ -27,7 +27,7 @@ public class SysRoleApiService : ITransient { await _sysRoleApiRep.DeleteAsync(u => u.RoleId == input.Id); - var roleApis = input.ApiList.Select(u => new SysRoleApi + var roleApis = input.ApiList.Where(u => !string.IsNullOrWhiteSpace(u)).Select(u => new SysRoleApi { RoleId = input.Id, Route = u diff --git a/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs b/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs index 39587679..67dd0d2e 100644 --- a/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs +++ b/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs @@ -203,7 +203,44 @@ public static class CommonUtil foreach (var item in drErrorInfo.FieldErrors) message += $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)"; } - message += "字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList()); + message += "\r\n字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList()); + throw Oops.Oh("导入异常:" + message); + } + return res.Data; + } + + /// + /// 导入Excel数据并错误标记 + /// + /// + /// + public static async Task> ImportExcelData([Required] IFormFile file, Func, ImportResult> importResultCallback = null) where T : class, new() + { + IImporter importer = new ExcelImporter(); + var resultStream = new MemoryStream(); + var res = await importer.Import(file.OpenReadStream(), resultStream, importResultCallback); + resultStream.Seek(0, SeekOrigin.Begin); + var userId = App.User?.FindFirst(ClaimConst.UserId)?.Value; + + App.GetRequiredService().Remove(CacheConst.KeyExcelTemp + userId); + App.GetRequiredService().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 (message.Length > 200) + message = message.Substring(0, 200) + "...\r\n异常过多,建议下载错误标记文件查看详细错误信息并重新导入。"; throw Oops.Oh("导入异常:" + message); } return res.Data; diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm index de62f3c7..50484b16 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm @@ -20,25 +20,25 @@ +
+ + 如果是在前端生成的实体/表(在生成表选择项里面找不到),请重启后台服务后再进行代码生成。 +
@@ -54,6 +58,14 @@ + diff --git a/Web/src/views/system/codeGen/component/genConfigDialog.vue b/Web/src/views/system/codeGen/component/genConfigDialog.vue index 1a737c3e..e2a05877 100644 --- a/Web/src/views/system/codeGen/component/genConfigDialog.vue +++ b/Web/src/views/system/codeGen/component/genConfigDialog.vue @@ -109,6 +109,7 @@ const state = reactive({ allEnumSelector: [] as any, }); +// 页面初始化 onMounted(async () => { var res = await getAPI(SysDictDataApi).apiSysDictDataDataListCodeGet('code_gen_effect_type'); state.effectTypeList = res.data.result; @@ -140,6 +141,7 @@ onUnmounted(() => { mittBus.off('submitRefresh', () => {}); mittBus.off('submitRefreshFk', () => {}); }); + // 控件类型改变 const effectTypeChange = (data: any, index: number) => { let value = data.effectType; @@ -190,8 +192,8 @@ function effectTypeEnable(data: any) { } // 打开弹窗 -const openDialog = (addRow: any) => { - handleQuery(addRow); +const openDialog = async (addRow: any) => { + await handleQuery(addRow); state.isShowDialog = true; }; diff --git a/Web/src/views/system/codeGen/index.vue b/Web/src/views/system/codeGen/index.vue index 0161b4b0..f7b9fff1 100644 --- a/Web/src/views/system/codeGen/index.vue +++ b/Web/src/views/system/codeGen/index.vue @@ -5,12 +5,12 @@ - + - + @@ -21,7 +21,7 @@ - 查询 + 查询 重置 @@ -29,7 +29,7 @@ - + @@ -62,15 +62,6 @@ 生成 - @@ -84,8 +75,9 @@ import { onMounted, reactive, ref, defineAsyncComponent } from 'vue'; import { ElMessageBox, ElMessage } from 'element-plus'; import { auth } from '/@/utils/authFunction'; -import { VxeGridInstance, VxePagerEvents, VxePagerDefines } from 'vxe-table'; -import { useVxeTable } from '/@/hooks/vxeTableOptionsHook'; +import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table'; +import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook'; +import { Local } from '/@/utils/storage'; import { downloadByUrl } from '/@/utils/download'; import EditCodeGenDialog from './component/editCodeGenDialog.vue'; @@ -93,7 +85,7 @@ import CodeConfigDialog from './component/genConfigDialog.vue'; import { getAPI } from '/@/utils/axios-utils'; import { SysCodeGenApi } from '/@/api-services/api'; -import { SysCodeGen } from '/@/api-services/models'; +import { SysCodeGen, PageCodeGenInput } from '/@/api-services/models'; const PreviewDialog = defineAsyncComponent(() => import('./component/previewDialog.vue')); const xGrid = ref(); @@ -110,90 +102,78 @@ const state = reactive({ tableName: undefined, busName: undefined, }, - tableParams: { - page: 1, - pageSize: 50, - field: 'id', // 默认的排序字段 - order: 'aes', // 排序方向 - descStr: 'desc', // 降序排序的关键字符 - total: 0 as any, + localPageParam: { + pageSize: 50 as number, + defaultSort: { field: 'id', order: 'asc', descStr: 'desc' }, }, visible: false, title: '', applicationNamespaces: [] as Array, }); +// 本地存储参数 +const localPageParamKey = 'localPageParam:sysCodeGen'; // 表格参数配置 -const options = useVxeTable({ - id: 'sysCodeGen', - name: '代码生成', - columns: [ - // { type: 'checkbox', width: 40, fixed: 'left' }, - { type: 'seq', title: '序号', width: 60, fixed: 'left' }, - { field: 'configId', title: '库定位器', minWidth: 200, showOverflow: 'tooltip' }, - { field: 'tableName', title: '表名称', minWidth: 200, showOverflow: 'tooltip' }, - { field: 'busName', title: '业务名', minWidth: 200, showOverflow: 'tooltip' }, - { field: 'nameSpace', title: '命名空间', minWidth: 200, showOverflow: 'tooltip' }, - { field: 'authorName', title: '作者姓名', minWidth: 200, showOverflow: 'tooltip' }, - { field: 'generateType', title: '生成方式', minWidth: 140, showOverflow: 'tooltip', slots: { default: 'row_generateType' } }, - { title: '操作', fixed: 'right', width: 280, showOverflow: true, slots: { default: 'row_buttons' } }, - ], - enableExport: auth('sysCodeGen:export'), - searchCallback: () => handleQuery(), - queryAllCallback: () => fetchData({ pageSize: 99999 }), -}); +const options = useVxeTable( + { + id: 'sysCodeGen', + name: '代码生成', + columns: [ + // { type: 'checkbox', width: 40, fixed: 'left' }, + { type: 'seq', title: '序号', width: 60, fixed: 'left' }, + { field: 'configId', title: '库定位器', minWidth: 200, showOverflow: 'tooltip' }, + { field: 'tableName', title: '表名称', minWidth: 200, showOverflow: 'tooltip' }, + { field: 'busName', title: '业务名', minWidth: 200, showOverflow: 'tooltip' }, + { field: 'nameSpace', title: '命名空间', minWidth: 200, showOverflow: 'tooltip' }, + { field: 'authorName', title: '作者姓名', minWidth: 200, showOverflow: 'tooltip' }, + { field: 'generateType', title: '生成方式', minWidth: 140, showOverflow: 'tooltip', slots: { default: 'row_generateType' } }, + { title: '操作', fixed: 'right', width: 280, showOverflow: true, slots: { default: 'row_buttons' } }, + ], + }, + // vxeGrid配置参数(此处可覆写任何参数),参考vxe-table官方文档 + { + // 代理配置 + proxyConfig: { autoLoad: true, ajax: { query: ({ page, sort }) => handleQueryApi(page, sort) } }, + // 排序配置 + sortConfig: { defaultSort: Local.get(localPageParamKey)?.defaultSort || state.localPageParam.defaultSort }, + // 分页配置 + pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize }, + // 工具栏配置 + toolbarConfig: { export: false }, + } +); // 页面初始化 onMounted(async () => { + state.localPageParam = Local.get(localPageParamKey) || state.localPageParam; await handleQuery(); + + // 获取命名空间集合 let res = await getAPI(SysCodeGenApi).apiSysCodeGenApplicationNamespacesGet(); state.applicationNamespaces = res.data.result as Array; }); -// 查询操作 -const handleQuery = async (reset = false) => { - options.loading = true; - if (reset) state.tableParams.page = 1; - var res = await fetchData(null); - xGrid.value?.loadData(res.data.result?.items ?? []); - state.tableParams.total = res.data.result?.total; - options.loading = false; -}; - -// 获取数据 -const fetchData = async (tableParams: any) => { - let params = Object.assign(state.queryParams, state.tableParams, tableParams); +// 查询api +const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams, sort: VxeGridPropTypes.ProxyAjaxQuerySortCheckedParams) => { + const params = Object.assign(state.queryParams, { page: page.currentPage, pageSize: page.pageSize, field: sort.field, order: sort.order, descStr: 'desc' }) as PageCodeGenInput; return getAPI(SysCodeGenApi).apiSysCodeGenPagePost(params); }; +// 查询操作 +const handleQuery = async () => { + await xGrid.value?.commitProxy('query'); +}; + // 重置操作 -const resetQuery = () => { +const resetQuery = async () => { state.queryParams.busName = undefined; state.queryParams.tableName = undefined; - handleQuery(true); -}; - -const handleConfig = (row: any) => { - CodeConfigRef.value?.openDialog(row); -}; - -// 改变页码序号或页面容量 -const pageChange: VxePagerEvents.PageChange = ({ currentPage, pageSize }: VxePagerDefines.PageChangeEventParams) => { - state.tableParams.page = currentPage; - state.tableParams.pageSize = pageSize; - handleQuery(); -}; - -// 列排序 -const sortChange = (options: any) => { - state.tableParams.field = options.field; - state.tableParams.order = options.order; - handleQuery(); + await xGrid.value?.commitProxy('reload'); }; // 打开新增页面 const handleAdd = () => { - state.title = '增加'; + state.title = '增加代码生成'; EditCodeGenRef.value?.openDialog({ authorName: 'Admin.NET', generateType: '200', @@ -202,12 +182,13 @@ const handleAdd = () => { pagePath: 'main', nameSpace: state.applicationNamespaces[0], generateMenu: false, + isApiService: false, }); }; // 打开编辑页面 const handleEdit = (row: any) => { - state.title = '编辑'; + state.title = '编辑代码生成'; EditCodeGenRef.value?.openDialog(row); }; @@ -220,12 +201,31 @@ const handleDelete = (row: any) => { }) .then(async () => { await getAPI(SysCodeGenApi).apiSysCodeGenDeletePost([{ id: row.id }]); - handleQuery(); + await handleQuery(); ElMessage.success('操作成功'); }) .catch(() => {}); }; +// 表格事件 +const gridEvents: VxeGridListeners = { + // 只对 pager-config 配置时有效,分页发生改变时会触发该事件 + async pageChange({ pageSize }) { + state.localPageParam.pageSize = pageSize; + Local.set(localPageParamKey, state.localPageParam); + }, + // 当排序条件发生变化时会触发该事件 + async sortChange({ field, order }) { + state.localPageParam.defaultSort = { field: field, order: order!, descStr: 'desc' }; + Local.set(localPageParamKey, state.localPageParam); + }, +}; + +// 打开配置 +const handleConfig = (row: any) => { + CodeConfigRef.value?.openDialog(row); +}; + // 开始生成代码 const handleGenerate = (row: any) => { ElMessageBox.confirm(`确定要生成吗?`, '提示', { @@ -236,7 +236,7 @@ const handleGenerate = (row: any) => { .then(async () => { var res = await getAPI(SysCodeGenApi).apiSysCodeGenRunLocalPost(row); if (res.data.result != null && res.data.result.url != null) downloadByUrl({ url: res.data.result.url }); - handleQuery(); + await handleQuery(); ElMessage.success('操作成功'); }) .catch(() => {}); diff --git a/Web/src/views/system/database/database.ts b/Web/src/views/system/database/database.ts index c99a0bde..4bbd5d69 100644 --- a/Web/src/views/system/database/database.ts +++ b/Web/src/views/system/database/database.ts @@ -104,4 +104,9 @@ export const dataTypeList = [ hasLength: false, hasDecimalDigits: false, }, + { + value: 'boolean', + hasLength: false, + hasDecimalDigits: false, + }, ]; diff --git a/Web/src/views/system/database/index.vue b/Web/src/views/system/database/index.vue index d0a90d27..dde043c4 100644 --- a/Web/src/views/system/database/index.vue +++ b/Web/src/views/system/database/index.vue @@ -32,7 +32,7 @@ 增加列 生成实体 - + @@ -81,7 +81,7 @@ import { onMounted, reactive, ref } from 'vue'; import { ElMessageBox, ElMessage } from 'element-plus'; import { useRouter } from 'vue-router'; import { VxeGridInstance } from 'vxe-table'; -import { useVxeTable } from '/@/hooks/vxeTableOptionsHook'; +import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook'; import EditTable from '/@/views/system/database/component/editTable.vue'; import EditColumn from '/@/views/system/database/component/editColumn.vue'; @@ -118,54 +118,58 @@ const state = reactive({ }); // 表格参数配置 -const options = useVxeTable({ - id: 'sysDatabase', - name: '库表信息', - columns: [ - // { type: 'checkbox', width: 40, fixed: 'left' }, - { type: 'seq', title: '序号', width: 50, fixed: 'left' }, - { field: 'dbColumnName', title: '字段名', minWidth: 200, showOverflow: 'tooltip' }, - { field: 'dataType', title: '数据类型', minWidth: 120, showOverflow: 'tooltip' }, - { field: 'isPrimarykey', title: '主键', minWidth: 70, slots: { default: 'row_isPrimarykey' } }, - { field: 'isIdentity', title: '自增', minWidth: 70, slots: { default: 'row_isIdentity' } }, - { field: 'isNullable', title: '可空', minWidth: 70, slots: { default: 'row_isNullable' } }, - { field: 'length', title: '长度', minWidth: 80, showOverflow: 'tooltip' }, - { field: 'decimalDigits', title: '精度', minWidth: 80, showOverflow: 'tooltip' }, - { field: 'defaultValue', title: '默认值', minWidth: 80, showOverflow: 'tooltip' }, - { field: 'columnDescription', title: '描述', minWidth: 200, showOverflow: 'tooltip' }, - { title: '操作', fixed: 'right', width: 100, showOverflow: true, slots: { default: 'row_buttons' } }, - ], - enableExport: true, - searchCallback: () => handleQueryColumn(), - queryAllCallback: () => fetchData({ pageSize: 99999 }), -}); +const options = useVxeTable( + { + id: 'sysDatabase', + name: '库表信息', + columns: [ + // { type: 'checkbox', width: 40, fixed: 'left' }, + { type: 'seq', title: '序号', width: 50, fixed: 'left' }, + { field: 'dbColumnName', title: '字段名', minWidth: 200, showOverflow: 'tooltip' }, + { field: 'dataType', title: '数据类型', minWidth: 120, showOverflow: 'tooltip' }, + { field: 'isPrimarykey', title: '主键', minWidth: 70, slots: { default: 'row_isPrimarykey' } }, + { field: 'isIdentity', title: '自增', minWidth: 70, slots: { default: 'row_isIdentity' } }, + { field: 'isNullable', title: '可空', minWidth: 70, slots: { default: 'row_isNullable' } }, + { field: 'length', title: '长度', minWidth: 80, showOverflow: 'tooltip' }, + { field: 'decimalDigits', title: '精度', minWidth: 80, showOverflow: 'tooltip' }, + { field: 'defaultValue', title: '默认值', minWidth: 80, showOverflow: 'tooltip' }, + { field: 'columnDescription', title: '描述', minWidth: 200, showOverflow: 'tooltip' }, + { title: '操作', fixed: 'right', width: 100, showOverflow: true, slots: { default: 'row_buttons' } }, + ], + }, + // vxeGrid配置参数(此处可覆写任何参数),参考vxe-table官方文档 + { + // 代理配置 + proxyConfig: { autoLoad: true, ajax: { query: () => handleQueryColumnApi() } }, + // 分页配置 + pagerConfig: { enabled: false }, + // 工具栏配置 + toolbarConfig: { export: true }, + } +); // 页面初始化 onMounted(async () => { options.loading = true; - var res = await getAPI(SysDatabaseApi).apiSysDatabaseListGet(); + let res = await getAPI(SysDatabaseApi).apiSysDatabaseListGet(); state.dbData = res.data.result; - options.loading = false; + let appNamesRes = await getAPI(SysCodeGenApi).apiSysCodeGenApplicationNamespacesGet(); state.appNamespaces = appNamesRes.data.result as Array; + options.loading = false; }); -// 查询操作 -const handleQueryColumn = async () => { +// 查询列api +const handleQueryColumnApi = async () => { if (state.tableName == '' || typeof state.tableName == 'undefined') { - await xGrid.value?.loadData([]); - options.loading = false; return; } - options.loading = true; - var res = await fetchData(); - await xGrid.value?.loadData(res.data.result ?? []); - options.loading = false; + return getAPI(SysDatabaseApi).apiSysDatabaseColumnListTableNameConfigIdGet(state.tableName, state.configId); }; -// 获取数据 -const fetchData = async (tableParams?: any) => { - return getAPI(SysDatabaseApi).apiSysDatabaseColumnListTableNameConfigIdGet(state.tableName, state.configId); +// 查询列操作 +const handleQueryColumn = async () => { + await xGrid.value?.commitProxy('query'); }; // 增加表 diff --git a/Web/src/views/system/job/component/editJobDetail.vue b/Web/src/views/system/job/component/editJobDetail.vue index 75887694..6d16d250 100644 --- a/Web/src/views/system/job/component/editJobDetail.vue +++ b/Web/src/views/system/job/component/editJobDetail.vue @@ -44,7 +44,7 @@
扫描触发器 - +
diff --git a/Web/src/views/system/ldap/index.vue b/Web/src/views/system/ldap/index.vue index 65bcf172..28dc89d5 100644 --- a/Web/src/views/system/ldap/index.vue +++ b/Web/src/views/system/ldap/index.vue @@ -95,7 +95,7 @@ import ModifyRecord from '/@/components/table/modifyRecord.vue'; import { getAPI } from '/@/utils/axios-utils'; import { SysLdapApi } from '/@/api-services'; -import { SysLdap, SysLdapInput } from '/@/api-services/models'; +import { SysLdap, PageSysLdapInput } from '/@/api-services/models'; // 异步引用组件 const PrintDialog = defineAsyncComponent(() => import('/@/views/system/print/component/hiprint/preview.vue')); @@ -159,7 +159,7 @@ onMounted(async () => { // 查询api const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams, sort: VxeGridPropTypes.ProxyAjaxQuerySortCheckedParams) => { - const params = Object.assign(state.queryParams, { page: page.currentPage, pageSize: page.pageSize, field: sort.field, order: sort.order, descStr: 'desc' }) as SysLdapInput; + const params = Object.assign(state.queryParams, { page: page.currentPage, pageSize: page.pageSize, field: sort.field, order: sort.order, descStr: 'desc' }) as PageSysLdapInput; return getAPI(SysLdapApi).apiSysLdapPagePost(params); }; diff --git a/Web/src/views/system/menu/index.vue b/Web/src/views/system/menu/index.vue index efc8da60..f9fea7cd 100644 --- a/Web/src/views/system/menu/index.vue +++ b/Web/src/views/system/menu/index.vue @@ -130,6 +130,7 @@ const options = useVxeTable( pagerConfig: { enabled: false }, // 工具栏配置 toolbarConfig: { export: false }, + // 树形配置 treeConfig: { expandAll: false }, } ); diff --git a/Web/src/views/system/openAccess/index.vue b/Web/src/views/system/openAccess/index.vue index 35bfae96..9513d5b4 100644 --- a/Web/src/views/system/openAccess/index.vue +++ b/Web/src/views/system/openAccess/index.vue @@ -71,7 +71,7 @@ import ModifyRecord from '/@/components/table/modifyRecord.vue'; import { getAPI } from '/@/utils/axios-utils'; import { SysOpenAccessApi } from '/@/api-services/api'; -import { OpenAccessInput, OpenAccessOutput } from '/@/api-services/models'; +import { PageOpenAccessInput, OpenAccessOutput } from '/@/api-services/models'; const xGrid = ref(); const editRef = ref>(); @@ -128,7 +128,7 @@ onMounted(async () => { // 查询api const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams, sort: VxeGridPropTypes.ProxyAjaxQuerySortCheckedParams) => { - const params = Object.assign(state.queryParams, { page: page.currentPage, pageSize: page.pageSize, field: sort.field, order: sort.order, descStr: 'desc' }) as OpenAccessInput; + const params = Object.assign(state.queryParams, { page: page.currentPage, pageSize: page.pageSize, field: sort.field, order: sort.order, descStr: 'desc' }) as PageOpenAccessInput; return getAPI(SysOpenAccessApi).apiSysOpenAccessPagePost(params); };