From 1b3ac27958ff101d299c818e7d9053bdd2e45095 Mon Sep 17 00:00:00 2001 From: KaneLeung Date: Fri, 12 Jul 2024 08:43:23 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=8F=82=E7=AE=80=E5=8C=96Vxe?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E6=97=B6=E9=97=B4=E5=88=97=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 25e4cc6b..d6ce6e98 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 @@ -154,11 +154,7 @@ @: - } else if(@column.EffectType == "DatePicker") { - @: - } + } } } +
+ + 如果是在前端生成的实体/表(在生成表选择项里面找不到),请重启后台服务后再进行代码生成。 +
@@ -57,7 +61,7 @@ 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 @@
扫描触发器 - +
From 8bb9505af705cb6f218712b3ba3d38520b746a45 Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Fri, 12 Jul 2024 14:23:28 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=98=8E=E6=8F=92=E4=BB=B6=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B=E4=BB=A3=E7=A0=81=E5=90=8C=E6=AD=A5=E4=B8=8E=E6=B8=85?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Plugins/Admin.NET.Plugin.DingTalk/Const/DingTalkConst.cs | 2 ++ .../Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkUser.cs | 4 +++- .../Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs | 4 ++-- Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewPro.cs | 3 ++- .../Plugins/Admin.NET.Plugin.GoView/Entity/GoViewProData.cs | 1 + 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Const/DingTalkConst.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Const/DingTalkConst.cs index 9df79af4..4547390e 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Const/DingTalkConst.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Const/DingTalkConst.cs @@ -36,10 +36,12 @@ public class DingTalkConst /// 主部门Id /// public const string DeptId = "sys00-mainDeptId"; + /// /// 主部门 /// public const string Dept = "sys00-mainDept"; + /// /// 职位 /// diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkUser.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkUser.cs index fee3251c..fe2f0137 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkUser.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkUser.cs @@ -73,23 +73,25 @@ public class DingTalkUser : EntityBase [SugarColumn(ColumnDescription = "工号", Length = 16)] [MaxLength(16)] public string? JobNumber { get; set; } + /// /// 主部门Id /// [SugarColumn(ColumnDescription = "主部门Id", Length = 16)] [MaxLength(16)] public string? DeptId { get; set; } + /// /// 主部门 /// [SugarColumn(ColumnDescription = "主部门", Length = 16)] [MaxLength(16)] public string? Dept { get; set; } + /// /// 职位 /// [SugarColumn(ColumnDescription = "职位", Length = 16)] [MaxLength(16)] public string? Position { get; set; } - } \ No newline at end of file diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs index 02322eda..71365f0c 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs @@ -43,7 +43,7 @@ public class DingTalkService : IDynamicApiController, IScoped /// /// /// - [DisplayName("获取在职员工列表")] + [HttpPost, DisplayName("获取在职员工列表")] public async Task> GetDingTalkCurrentEmployeesList(string access_token, [Required] GetDingTalkCurrentEmployeesListInput input) { return await _dingTalkApi.GetDingTalkCurrentEmployeesList(access_token, input); @@ -55,7 +55,7 @@ public class DingTalkService : IDynamicApiController, IScoped /// /// /// - [DisplayName("获取员工花名册字段信息")] + [HttpPost, DisplayName("获取员工花名册字段信息")] public async Task>> GetDingTalkCurrentEmployeesRosterList(string access_token, [Required] GetDingTalkCurrentEmployeesRosterListInput input) { return await _dingTalkApi.GetDingTalkCurrentEmployeesRosterList(access_token, input); diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewPro.cs b/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewPro.cs index 023d5c9b..0594ca67 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewPro.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewPro.cs @@ -1,4 +1,4 @@ -// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // @@ -10,6 +10,7 @@ namespace Admin.NET.Plugin.GoView; /// GoView 项目表 /// [SugarTable(null, "GoView 项目表")] +[SysTable] public class GoViewPro : EntityTenant { /// diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewProData.cs b/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewProData.cs index a792c033..ab5bd036 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewProData.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.GoView/Entity/GoViewProData.cs @@ -10,6 +10,7 @@ namespace Admin.NET.Plugin.GoView; /// GoView 项目数据表 /// [SugarTable(null, "GoView 项目数据表")] +[SysTable] public class GoViewProData : EntityTenant { /// From 5385e86478133414c80fb49eaf627ef10e53dd8b Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Fri, 12 Jul 2024 14:29:34 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=98=8E1=E3=80=81=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AF=BC=E5=85=A5Excel=E6=95=B0=E6=8D=AE=E5=B9=B6=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=A0=87=E8=AE=B0=E6=8E=A5=E5=8F=A3=202=E3=80=81?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=8B=E8=BD=BD=E5=B7=B2=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84=E4=B8=B4=E6=97=B6Excel=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Admin.NET/Admin.NET.Core/Const/CacheConst.cs | 5 +++ .../Service/Common/SysCommonService.cs | 19 +++++++++ Admin.NET/Admin.NET.Core/Util/CommonUtil.cs | 39 ++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) 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/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/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; From af2fd572d57b0d1c4e79d3fecdadf57bc7a2a7f6 Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Fri, 12 Jul 2024 23:08:47 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=F0=9F=98=8E1=E3=80=81=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E5=80=BC=E8=8B=A5Key=E7=BB=8F=E8=BF=87URL?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=88=99=E8=BF=9B=E8=A1=8C=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=20=202=E3=80=81=E4=BC=98=E5=8C=96=E6=9E=9A=E4=B8=BE=E8=BD=AC?= =?UTF-8?q?=E5=AD=97=E5=85=B8=20=203=E3=80=81=E5=8D=87=E7=BA=A7npm?= =?UTF-8?q?=E5=8C=85=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs | 12 ++++++------ .../Admin.NET.Core/Service/Cache/SysCacheService.cs | 4 ++++ Web/package.json | 6 +++--- Web/src/views/system/database/database.ts | 5 +++++ 4 files changed, 18 insertions(+), 9 deletions(-) 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/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/Web/package.json b/Web/package.json index 2e26ea50..60a66464 100644 --- a/Web/package.json +++ b/Web/package.json @@ -31,7 +31,7 @@ "echarts": "^5.5.1", "echarts-gl": "^2.0.9", "echarts-wordcloud": "^2.1.0", - "element-plus": "^2.7.6", + "element-plus": "^2.7.7", "exceljs": "^4.4.0", "ezuikit": "^1.0.0", "ezuikit-js": "^8.0.5", @@ -68,8 +68,8 @@ "vue-signature-pad": "^3.0.2", "vue3-tree-org": "^4.2.2", "vuedraggable": "4.0.3", - "vxe-pc-ui": "^4.0.61", - "vxe-table": "^4.7.48", + "vxe-pc-ui": "^4.0.64", + "vxe-table": "^4.7.49", "vxe-table-plugin-element": "^4.0.4", "vxe-table-plugin-export-xlsx": "^4.0.5", "xe-utils": "^3.5.28", 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, + }, ]; From 2e3149a0286267086772c673a77ec5b5d8a37ce7 Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Sat, 13 Jul 2024 00:17:32 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=98=8E=E4=BF=AE=E5=A4=8D=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E8=A7=92=E8=89=B2=E6=8E=A5=E5=8F=A3=E8=B5=84=E6=BA=90?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 1db321346bd2625dd49b95b63787e194fc86cccf Mon Sep 17 00:00:00 2001 From: 362270511 <362270511@qq.com> Date: Sat, 13 Jul 2024 11:12:47 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Admin.NET/Admin.NET.?= =?UTF-8?q?Core/Service/Wechat/SysWxOpenService.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加微信小程序消息发送签名验证方法 --- .../Service/Wechat/SysWxOpenService.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs b/Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs index 9dfd2e08..1383910a 100644 --- a/Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs @@ -114,6 +114,25 @@ public class SysWxOpenService : IDynamicApiController, ITransient }; } + /// + /// 验证签名 🔖 + /// + [AllowAnonymous] + [NonUnify] + [ApiDescriptionSettings(Name = "VerifySignature"), HttpGet] + [DisplayName("验证签名")] + public string VerifySignature([FromQuery] VerifySignatureInput input) + { + + bool valid = _wechatApiClient.VerifyEventSignatureForEcho(input.timestamp, input.nonce, input.signature); + if (!valid) + { + return "fail"; + } + + return input.echostr; + } + /// /// 获取订阅消息模板列表 🔖 /// From a588c3836914295e508e9bab613f8e3ff0d8c200 Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Sun, 14 Jul 2024 01:10:02 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=F0=9F=98=8E1=E3=80=81=E6=80=A7=E5=88=AB?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E8=B0=83=E6=95=B4=202=E3=80=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E5=AD=97=E5=85=B8=E6=9C=8D=E5=8A=A1=20=203=E3=80=81?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Admin.NET.Core/Admin.NET.Core.csproj | 2 +- Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs | 22 +++--- .../Service/Dict/Dto/DictDataInput.cs | 1 + .../Service/Dict/Dto/DictTypeInput.cs | 1 + .../Service/Dict/SysDictDataService.cs | 28 +++----- .../Service/Dict/SysDictTypeService.cs | 27 ++----- .../Service/Enum/SysEnumService.cs | 2 +- Admin.NET/Admin.NET.Core/Util/CommonUtil.cs | 70 ++++++++++--------- Web/package.json | 10 +-- Web/src/views/system/user/index.vue | 3 +- 10 files changed, 76 insertions(+), 90 deletions(-) diff --git a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj index b3cfdc0b..ae198a5b 100644 --- a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj +++ b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj @@ -26,7 +26,7 @@ - + diff --git a/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs b/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs index 3284532c..5b5a7904 100644 --- a/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs +++ b/Admin.NET/Admin.NET.Core/Enum/GenderEnum.cs @@ -7,26 +7,32 @@ namespace Admin.NET.Core; /// -/// 性别枚举 +/// 性别枚举(GB/T 2261.1-2003) /// [Description("性别枚举")] public enum GenderEnum { /// - /// 男 + /// 未知的性别 /// - [Description("男")] + [Description("未知的性别")] + Unknown = 0, + + /// + /// 男性 + /// + [Description("男性")] Male = 1, /// - /// 女 + /// 女性 /// - [Description("女")] + [Description("女性")] Female = 2, /// - /// 其他 + /// 未说明的性别 /// - [Description("其他")] - Other = 3 + [Description("未说明的性别")] + Unspecified = 9 } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictDataInput.cs b/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictDataInput.cs index eccdff36..b9a1b183 100644 --- a/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictDataInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictDataInput.cs @@ -11,6 +11,7 @@ public class DictDataInput : BaseIdInput /// /// 状态 /// + [Dict("StatusEnum")] public StatusEnum Status { get; set; } } diff --git a/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictTypeInput.cs b/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictTypeInput.cs index 7884ada2..fc6327e7 100644 --- a/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictTypeInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/Dict/Dto/DictTypeInput.cs @@ -11,6 +11,7 @@ public class DictTypeInput : BaseIdInput /// /// 状态 /// + [Dict("StatusEnum")] public StatusEnum Status { get; set; } } diff --git a/Admin.NET/Admin.NET.Core/Service/Dict/SysDictDataService.cs b/Admin.NET/Admin.NET.Core/Service/Dict/SysDictDataService.cs index dd99cf59..dc6dfc4c 100644 --- a/Admin.NET/Admin.NET.Core/Service/Dict/SysDictDataService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Dict/SysDictDataService.cs @@ -1,4 +1,4 @@ -// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // @@ -16,8 +16,8 @@ public class SysDictDataService : IDynamicApiController, ITransient private readonly SysCacheService _sysCacheService; private readonly SqlSugarRepository _sysDictDataRep; - public SysDictDataService(SqlSugarRepository sysDictDataRep, - SysCacheService sysCacheService) + public SysDictDataService(SqlSugarRepository sysDictDataRep + , SysCacheService sysCacheService) { _sysDictDataRep = sysDictDataRep; _sysCacheService = sysCacheService; @@ -60,8 +60,7 @@ public class SysDictDataService : IDynamicApiController, ITransient public async Task AddDictData(AddDictDataInput input) { var isExist = await _sysDictDataRep.IsAnyAsync(u => u.Code == input.Code && u.DictTypeId == input.DictTypeId); - if (isExist) - throw Oops.Oh(ErrorCodeEnum.D3003); + if (isExist) throw Oops.Oh(ErrorCodeEnum.D3003); await _sysDictDataRep.InsertAsync(input.Adapt()); } @@ -98,9 +97,7 @@ public class SysDictDataService : IDynamicApiController, ITransient [DisplayName("删除字典值")] public async Task DeleteDictData(DeleteDictDataInput input) { - var dictData = await _sysDictDataRep.GetFirstAsync(u => u.Id == input.Id); - if (dictData == null) - throw Oops.Oh(ErrorCodeEnum.D3004); + var dictData = await _sysDictDataRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3004); var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync(); _sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}"); @@ -128,18 +125,13 @@ public class SysDictDataService : IDynamicApiController, ITransient [DisplayName("修改字典值状态")] public async Task SetStatus(DictDataInput input) { - var dictData = await _sysDictDataRep.GetFirstAsync(u => u.Id == input.Id); - if (dictData == null) - throw Oops.Oh(ErrorCodeEnum.D3004); - - if (!Enum.IsDefined(typeof(StatusEnum), input.Status)) - throw Oops.Oh(ErrorCodeEnum.D3005); + var dictData = await _sysDictDataRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3004); var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync(); _sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}"); dictData.Status = input.Status; - await _sysDictDataRep.UpdateAsync(dictData); + await _sysDictDataRep.AsUpdateable(dictData).UpdateColumns(u => new { u.Status }, true).ExecuteCommandAsync(); } /// @@ -156,13 +148,9 @@ public class SysDictDataService : IDynamicApiController, ITransient if (dictDataList == null) { dictDataList = await _sysDictDataRep.AsQueryable() - .Where(u => u.DictTypeId == dictTypeId) - .OrderBy(u => new { u.OrderNo, u.Code }) - .ToListAsync(); - + .Where(u => u.DictTypeId == dictTypeId).OrderBy(u => new { u.OrderNo, u.Code }).ToListAsync(); _sysCacheService.Set($"{CacheConst.KeyDict}{dictType.Code}", dictDataList); } - return dictDataList; } diff --git a/Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs b/Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs index b205336c..da75928a 100644 --- a/Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs @@ -60,10 +60,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient [DisplayName("获取字典类型-值列表")] public async Task> GetDataList([FromQuery] GetDataDictTypeInput input) { - var dictType = await _sysDictTypeRep.GetFirstAsync(u => u.Code == input.Code); - if (dictType == null) - throw Oops.Oh(ErrorCodeEnum.D3000); - + var dictType = await _sysDictTypeRep.GetFirstAsync(u => u.Code == input.Code) ?? throw Oops.Oh(ErrorCodeEnum.D3000); return await _sysDictDataService.GetDictDataListByDictTypeId(dictType.Id); } @@ -77,8 +74,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient public async Task AddDictType(AddDictTypeInput input) { var isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Code == input.Code); - if (isExist) - throw Oops.Oh(ErrorCodeEnum.D3001); + if (isExist) throw Oops.Oh(ErrorCodeEnum.D3001); await _sysDictTypeRep.InsertAsync(input.Adapt()); } @@ -94,12 +90,10 @@ public class SysDictTypeService : IDynamicApiController, ITransient public async Task UpdateDictType(UpdateDictTypeInput input) { var isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Id == input.Id); - if (!isExist) - throw Oops.Oh(ErrorCodeEnum.D3000); + if (!isExist) throw Oops.Oh(ErrorCodeEnum.D3000); isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Code == input.Code && u.Id != input.Id); - if (isExist) - throw Oops.Oh(ErrorCodeEnum.D3001); + if (isExist) throw Oops.Oh(ErrorCodeEnum.D3001); _sysCacheService.Remove($"{CacheConst.KeyDict}{input.Code}"); await _sysDictTypeRep.UpdateAsync(input.Adapt()); @@ -115,9 +109,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient [DisplayName("删除字典类型")] public async Task DeleteDictType(DeleteDictTypeInput input) { - var dictType = await _sysDictTypeRep.GetFirstAsync(u => u.Id == input.Id); - if (dictType == null) - throw Oops.Oh(ErrorCodeEnum.D3000); + var dictType = await _sysDictTypeRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3000); // 删除字典值 await _sysDictTypeRep.DeleteAsync(dictType); @@ -144,17 +136,12 @@ public class SysDictTypeService : IDynamicApiController, ITransient [DisplayName("修改字典类型状态")] public async Task SetStatus(DictTypeInput input) { - var dictType = await _sysDictTypeRep.GetFirstAsync(u => u.Id == input.Id); - if (dictType == null) - throw Oops.Oh(ErrorCodeEnum.D3000); - - if (!Enum.IsDefined(typeof(StatusEnum), input.Status)) - throw Oops.Oh(ErrorCodeEnum.D3005); + var dictType = await _sysDictTypeRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3000); _sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}"); dictType.Status = input.Status; - await _sysDictTypeRep.UpdateAsync(dictType); + await _sysDictTypeRep.AsUpdateable(dictType).UpdateColumns(u => new { u.Status }, true).ExecuteCommandAsync(); } /// diff --git a/Admin.NET/Admin.NET.Core/Service/Enum/SysEnumService.cs b/Admin.NET/Admin.NET.Core/Service/Enum/SysEnumService.cs index e8e204bf..a15b1138 100644 --- a/Admin.NET/Admin.NET.Core/Service/Enum/SysEnumService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Enum/SysEnumService.cs @@ -49,7 +49,7 @@ public class SysEnumService : IDynamicApiController, ITransient { string description = type.Name; var attrs = type.GetCustomAttributes(typeof(DescriptionAttribute), false); - if (attrs.Any()) + if (attrs.Length != 0) { var att = ((DescriptionAttribute[])attrs)[0]; description = att.Description; diff --git a/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs b/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs index 67dd0d2e..ab0910df 100644 --- a/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs +++ b/Admin.NET/Admin.NET.Core/Util/CommonUtil.cs @@ -49,12 +49,12 @@ public static class CommonUtil // 代理模式:获取真正的本机地址 // X-Original-Host=原始请求 // X-Forwarded-Server=从哪里转发过来 - if (App.HttpContext.Request.Headers.ContainsKey("Origin")) // 配置成完整的路径如(结尾不要带"/"),比如 https://www.abc.com - result = $"{App.HttpContext.Request.Headers["Origin"]}"; - else if (App.HttpContext.Request.Headers.ContainsKey("X-Original")) // 配置成完整的路径如(结尾不要带"/"),比如 https://www.abc.com - result = $"{App.HttpContext.Request.Headers["X-Original"]}"; - else if (App.HttpContext.Request.Headers.ContainsKey("X-Original-Host")) - result = $"{App.HttpContext.Request.Scheme}://{App.HttpContext.Request.Headers["X-Original-Host"]}"; + if (App.HttpContext.Request.Headers.TryGetValue("Origin", out Microsoft.Extensions.Primitives.StringValues value1)) // 配置成完整的路径如(结尾不要带"/"),比如 https://www.abc.com + result = $"{value1}"; + else if (App.HttpContext.Request.Headers.TryGetValue("X-Original", out Microsoft.Extensions.Primitives.StringValues value2)) // 配置成完整的路径如(结尾不要带"/"),比如 https://www.abc.com + result = $"{value2}"; + else if (App.HttpContext.Request.Headers.TryGetValue("X-Original-Host", out Microsoft.Extensions.Primitives.StringValues value3)) + result = $"{App.HttpContext.Request.Scheme}://{value3}"; return result; } @@ -107,7 +107,7 @@ public static class CommonUtil /// public static async Task ExportExcelTemplate(string fileName = null) where T : class, new() { - IImporter importer = new ExcelImporter(); + var importer = new ExcelImporter(); var res = await importer.GenerateTemplateBytes(); return new FileContentResult(res, "application/octet-stream") { FileDownloadName = $"{(string.IsNullOrEmpty(fileName) ? typeof(T).Name : fileName)}.xlsx" }; @@ -152,9 +152,9 @@ public static class CommonUtil } var map = dict.Value.Item1; - if (map != null && map.ContainsKey(sourceVal)) + if (map != null && map.TryGetValue(sourceVal, out string value)) { - var newVal = map[sourceVal]; + var newVal = value; targeProp.SetValue(newData, newVal); } else @@ -190,7 +190,7 @@ public static class CommonUtil /// public static async Task> ImportExcelData([Required] IFormFile file) where T : class, new() { - IImporter importer = new ExcelImporter(); + var importer = new ExcelImporter(); var res = await importer.Import(file.OpenReadStream()); var message = string.Empty; if (res.HasError) @@ -212,11 +212,13 @@ public static class CommonUtil /// /// 导入Excel数据并错误标记 /// + /// /// + /// /// public static async Task> ImportExcelData([Required] IFormFile file, Func, ImportResult> importResultCallback = null) where T : class, new() { - IImporter importer = new ExcelImporter(); + var importer = new ExcelImporter(); var resultStream = new MemoryStream(); var res = await importer.Import(file.OpenReadStream(), resultStream, importResultCallback); resultStream.Seek(0, SeekOrigin.Begin); @@ -240,7 +242,7 @@ public static class CommonUtil message += "\r\n字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList()); if (message.Length > 200) - message = message.Substring(0, 200) + "...\r\n异常过多,建议下载错误标记文件查看详细错误信息并重新导入。"; + message = string.Concat(message.AsSpan(0, 200), "...\r\n异常过多,建议下载错误标记文件查看详细错误信息并重新导入。"); throw Oops.Oh("导入异常:" + message); } return res.Data; @@ -337,7 +339,7 @@ public static class CommonUtil else { propMappings.Add(propertyInfo.Name, new Tuple, PropertyInfo, PropertyInfo>( - null, propertyInfo, tTargetProps.ContainsKey(propertyInfo.Name) ? tTargetProps[propertyInfo.Name] : null)); + null, propertyInfo, tTargetProps.TryGetValue(propertyInfo.Name, out PropertyInfo value) ? value : null)); } } @@ -379,34 +381,34 @@ public static class CommonUtil else { propMappings.Add(propertyInfo.Name, new Tuple, PropertyInfo, PropertyInfo>( - null, sourceProps.ContainsKey(propertyInfo.Name) ? sourceProps[propertyInfo.Name] : null, propertyInfo)); + null, sourceProps.TryGetValue(propertyInfo.Name, out PropertyInfo value) ? value : null, propertyInfo)); } } return propMappings; } - /// - /// 获取属性映射 - /// - /// - /// 整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 - private static Dictionary> GetExportDicttMap() where TTarget : new() - { - // 整理导入对象的属性名称,目标属性名,字典Code - var propMappings = new Dictionary>(); - var tTargetProps = typeof(TTarget).GetProperties(); - foreach (var propertyInfo in tTargetProps) - { - var attrs = propertyInfo.GetCustomAttribute(); - if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode)) - { - propMappings.Add(propertyInfo.Name, new Tuple(attrs.TargetPropName, attrs.TypeCode)); - } - } + ///// + ///// 获取属性映射 + ///// + ///// + ///// 整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 + //private static Dictionary> GetExportDicttMap() where TTarget : new() + //{ + // // 整理导入对象的属性名称,目标属性名,字典Code + // var propMappings = new Dictionary>(); + // var tTargetProps = typeof(TTarget).GetProperties(); + // foreach (var propertyInfo in tTargetProps) + // { + // var attrs = propertyInfo.GetCustomAttribute(); + // if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode)) + // { + // propMappings.Add(propertyInfo.Name, new Tuple(attrs.TargetPropName, attrs.TypeCode)); + // } + // } - return propMappings; - } + // return propMappings; + //} /// /// 解析IP地址 diff --git a/Web/package.json b/Web/package.json index 60a66464..467a1bfa 100644 --- a/Web/package.json +++ b/Web/package.json @@ -2,7 +2,7 @@ "name": "admin.net.pro", "type": "module", "version": "2.4.33", - "lastBuildTime": "2024.07.12", + "lastBuildTime": "2024.07.14", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "author": "zuohuaijun", "license": "MIT", @@ -68,8 +68,8 @@ "vue-signature-pad": "^3.0.2", "vue3-tree-org": "^4.2.2", "vuedraggable": "4.0.3", - "vxe-pc-ui": "^4.0.64", - "vxe-table": "^4.7.49", + "vxe-pc-ui": "^4.0.67", + "vxe-table": "^4.7.50", "vxe-table-plugin-element": "^4.0.4", "vxe-table-plugin-export-xlsx": "^4.0.5", "xe-utils": "^3.5.28", @@ -88,10 +88,10 @@ "@vitejs/plugin-vue-jsx": "^4.0.0", "@vue/compiler-sfc": "^3.4.31", "code-inspector-plugin": "^0.14.2", - "eslint": "^9.6.0", + "eslint": "^9.7.0", "eslint-plugin-vue": "^9.27.0", "less": "^4.2.0", - "prettier": "^3.3.2", + "prettier": "^3.3.3", "rollup-plugin-visualizer": "^5.12.0", "sass": "^1.77.8", "terser": "^5.31.2", diff --git a/Web/src/views/system/user/index.vue b/Web/src/views/system/user/index.vue index e32c9c86..575bda91 100644 --- a/Web/src/views/system/user/index.vue +++ b/Web/src/views/system/user/index.vue @@ -54,7 +54,8 @@