From 062bacd0ecf71fa71f32f496dd9ee63a849892f7 Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Sun, 16 Jun 2024 02:40:42 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=98=8E=E5=90=8C=E6=AD=A5=E5=8D=87?= =?UTF-8?q?=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Admin.NET.Core/Admin.NET.Core.csproj | 6 +- Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs | 3 +- .../SeedData/SysMenuSeedData.cs | 2 + .../Service/Config/Dto/ConfigInput.cs | 16 +++ .../Service/Config/SysConfigService.cs | 24 +++- .../Service/Job/DbJobPersistence.cs | 10 +- .../Service/Message/SysSmsService.cs | 41 +++++- .../wwwroot/Template/Service.cs.vm | 6 + .../wwwroot/Template/editDialog.vue.vm | 43 +++---- .../wwwroot/Template/index.vue.vm | 33 ++--- .../wwwroot/Upload/logo.png | Bin 0 -> 15178 bytes .../Admin.NET.Plugin.ReZero.csproj | 2 +- Web/{.prettierrc.js => .prettierrc.cjs} | 0 Web/package.json | 23 ++-- Web/src/api-services/apis/sys-config-api.ts | 108 ++++++++++++++-- Web/src/api-services/apis/sys-sms-api.ts | 96 ++++++++++++++ .../api-services/models/batch-config-input.ts | 38 ++++++ Web/src/api-services/models/index.ts | 1 + Web/src/views/about/index.vue | 120 ++++++++++++++++++ .../system/database/component/addTable.vue | 7 + Web/src/views/system/database/index.vue | 2 +- Web/src/views/system/log/exlog/index.vue | 2 +- Web/src/views/system/org/index.vue | 6 +- Web/vite.config.ts | 1 + 24 files changed, 511 insertions(+), 79 deletions(-) create mode 100644 Admin.NET/Admin.NET.Web.Entry/wwwroot/Upload/logo.png rename Web/{.prettierrc.js => .prettierrc.cjs} (100%) create mode 100644 Web/src/api-services/models/batch-config-input.ts create mode 100644 Web/src/views/about/index.vue diff --git a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj index 583bdf82..5f5d9587 100644 --- a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj +++ b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj @@ -17,7 +17,7 @@ - + @@ -33,11 +33,11 @@ - + - + diff --git a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs index c113b1bb..95848948 100644 --- a/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs +++ b/Admin.NET/Admin.NET.Core/Job/EnumToDictJob.cs @@ -1,4 +1,4 @@ -// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // @@ -59,6 +59,7 @@ public class EnumToDictJob : IJob dictData.Value = enumData.Value.ToString(); dictData.Code = enumData.Name; dictData.OrderNo = enumData.Value + 10; + dictData.Name = enumData.Describe; uSysDictData.Add(dictData); } }); diff --git a/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs b/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs index 1ee40f4d..d2eb934d 100644 --- a/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs +++ b/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs @@ -192,6 +192,8 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData new SysMenu{ Id=1310000000711, Pid=1310000000701, Title="后台教程", Path="/doc/furion", Name="sysFurion", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://furion.baiqian.ltd/", Icon="ele-Promotion", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000712, Pid=1310000000701, Title="前端教程", Path="/doc/element", Name="sysElement", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://element-plus.gitee.io/zh-CN/", Icon="ele-Position", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 }, new SysMenu{ Id=1310000000713, Pid=1310000000701, Title="SqlSugar", Path="/doc/SqlSugar", Name="sysSqlSugar", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://www.donet5.com/Home/Doc", Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 }, + + new SysMenu{ Id=1310000000801, Pid=0, Title="关于项目", Path="/about", Name="about", Component="/about/index", Icon="ele-InfoFilled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2023-03-12 00:00:00"), OrderNo=15000 }, }; } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Config/Dto/ConfigInput.cs b/Admin.NET/Admin.NET.Core/Service/Config/Dto/ConfigInput.cs index 1fdc16b4..d5c0b3ec 100644 --- a/Admin.NET/Admin.NET.Core/Service/Config/Dto/ConfigInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/Config/Dto/ConfigInput.cs @@ -38,4 +38,20 @@ public class UpdateConfigInput : AddConfigInput public class DeleteConfigInput : BaseIdInput { +} + +/// +/// 批量配置参数输入 +/// +public class BatchConfigInput +{ + /// + /// 编码 + /// + public string Code { get; set; } + + /// + /// 属性值 + /// + public string Value { get; set; } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs b/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs index 820bb2f8..6c0fafac 100644 --- a/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs @@ -44,9 +44,11 @@ public class SysConfigService : IDynamicApiController, ITransient /// /// [DisplayName("获取参数配置列表")] - public async Task> GetList() + public async Task> List(PageConfigInput input) { - return await _sysConfigRep.GetListAsync(); + return await _sysConfigRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.GroupCode?.Trim()), u => u.GroupCode.Equals(input.GroupCode)) + .ToListAsync(); } /// @@ -147,7 +149,7 @@ public class SysConfigService : IDynamicApiController, ITransient var value = _sysCacheService.Get($"{CacheConst.KeyConfig}{code}"); if (string.IsNullOrEmpty(value)) { - var config = await _sysConfigRep.GetFirstAsync(u => u.Code == code); + var config = await _sysConfigRep.CopyNew().GetFirstAsync(u => u.Code == code); value = config != null ? config.Value : default; _sysCacheService.Set($"{CacheConst.KeyConfig}{code}", value); } @@ -210,6 +212,22 @@ public class SysConfigService : IDynamicApiController, ITransient return refreshTokenExpire == 0 ? 40 : refreshTokenExpire; } + /// + /// 批量更新参数配置值 + /// + /// + /// + [ApiDescriptionSettings(Name = "BatchUpdate"), HttpPost] + [DisplayName("批量更新参数配置值")] + public async Task BatchUpdateConfig(List input) + { + foreach (var Config in input) + { + await _sysConfigRep.AsUpdateable().SetColumns(u => u.Value == Config.Value).Where(u => u.Code == Config.Code).ExecuteCommandAsync(); + _sysCacheService.Remove($"{CacheConst.KeyConfig}{Config.Code}"); + } + } + /// /// 获取系统信息 🔖 /// diff --git a/Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs b/Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs index 83fdd7f9..3dbcc2ed 100644 --- a/Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs +++ b/Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs @@ -1,4 +1,4 @@ -// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // @@ -27,7 +27,7 @@ public class DbJobPersistence : IJobPersistence public async Task> PreloadAsync(CancellationToken stoppingToken) { using var scope = _serviceScopeFactory.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); + var db = scope.ServiceProvider.GetRequiredService().CopyNew(); var dynamicJobCompiler = scope.ServiceProvider.GetRequiredService(); // 获取所有定义的作业 @@ -132,7 +132,7 @@ public class DbJobPersistence : IJobPersistence { using (var scope = _serviceScopeFactory.CreateScope()) { - var db = scope.ServiceProvider.GetRequiredService(); + var db = scope.ServiceProvider.GetRequiredService().CopyNew(); var jobDetail = context.JobDetail.Adapt(); switch (context.Behavior) @@ -160,7 +160,7 @@ public class DbJobPersistence : IJobPersistence { using (var scope = _serviceScopeFactory.CreateScope()) { - var db = scope.ServiceProvider.GetRequiredService(); + var db = scope.ServiceProvider.GetRequiredService().CopyNew(); var jobTrigger = context.Trigger.Adapt(); switch (context.Behavior) @@ -188,7 +188,7 @@ public class DbJobPersistence : IJobPersistence { using (var scope = _serviceScopeFactory.CreateScope()) { - var db = scope.ServiceProvider.GetRequiredService(); + var db = scope.ServiceProvider.GetRequiredService().CopyNew(); var jobTriggerRecord = timeline.Adapt(); await db.Insertable(jobTriggerRecord).ExecuteCommandAsync(); diff --git a/Admin.NET/Admin.NET.Core/Service/Message/SysSmsService.cs b/Admin.NET/Admin.NET.Core/Service/Message/SysSmsService.cs index 466c962d..83dfadaf 100644 --- a/Admin.NET/Admin.NET.Core/Service/Message/SysSmsService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Message/SysSmsService.cs @@ -1,4 +1,4 @@ -// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // @@ -73,7 +73,7 @@ public class SysSmsService : IDynamicApiController, ITransient TemplateParam = templateParam.ToString(), // 模板中的变量替换JSON串 OutId = YitIdHelper.NextId().ToString() }; - var sendSmsResponse = client.SendSms(sendSmsRequest); + var sendSmsResponse = await client.SendSmsAsync(sendSmsRequest); if (sendSmsResponse.Body.Code == "OK" && sendSmsResponse.Body.Message == "OK") { // var bizId = sendSmsResponse.Body.BizId; @@ -87,6 +87,43 @@ public class SysSmsService : IDynamicApiController, ITransient await Task.CompletedTask; } + /// + /// 发送短信模板 + /// + /// + /// + /// + [AllowAnonymous] + [DisplayName("发送短信模板")] + public async Task AliyunSendSmsTemplate([Required] string phoneNumber, [Required] dynamic templateParam) + { + if (!phoneNumber.TryValidate(ValidationTypes.PhoneNumber).IsValid) + throw Oops.Oh("请正确填写手机号码"); + + if (string.IsNullOrWhiteSpace(templateParam.ToString())) + throw Oops.Oh("短信内容不能为空"); + + var client = CreateAliyunClient(); + var sendSmsRequest = new SendSmsRequest + { + PhoneNumbers = phoneNumber, // 待发送手机号, 多个以逗号分隔 + SignName = _smsOptions.Aliyun.SignName, // 短信签名 + TemplateCode = _smsOptions.Aliyun.TemplateCode, // 短信模板 + TemplateParam = templateParam.ToString(), // 模板中的变量替换JSON串 + OutId = YitIdHelper.NextId().ToString() + }; + var sendSmsResponse = await client.SendSmsAsync(sendSmsRequest); + if (sendSmsResponse.Body.Code == "OK" && sendSmsResponse.Body.Message == "OK") + { + } + else + { + throw Oops.Oh($"短信发送失败:{sendSmsResponse.Body.Code}-{sendSmsResponse.Body.Message}"); + } + + await Task.CompletedTask; + } + /// /// 腾讯云发送短信 📨 /// diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Service.cs.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Service.cs.vm index a42bda89..6b81ee0c 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Service.cs.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Service.cs.vm @@ -1,3 +1,9 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + using Admin.NET.Core.Service; using @(@Model.NameSpace).Entity; using Microsoft.AspNetCore.Http; diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue.vm b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue.vm index 2fe982e8..e26550fc 100644 --- a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue.vm +++ b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue.vm @@ -135,7 +135,7 @@ @: @: @: - @: + @: @: @: @@ -172,14 +172,23 @@ import type { FormRules } from "element-plus"; @if(@Model.TableField.Any(x=>x.EffectType == "ConstSelector")){ @:import { getConstType } from "/@@/utils/constHelper"; - } +} +@if(@Model.TableField.Any(x=>x.EffectType == "Select")){ + @:import { getDictDataItem as di, getDictDataList as dl } from '/@@/utils/dict-utils'; +} +@if(@Model.TableField.Any(x=>x.EffectType == "EnumSelector")){ + @:import { getDictLabelByVal as dv } from '/@@/utils/dict-utils'; +} +@if(@Model.TableField.Any(x=>x.EffectType == "DatePicker")){ + @:import { formatDate } from '/@@/utils/formatTime'; +} @if(@Model.TableField.Any(x=>x.EffectType == "Upload")){ @:import { Plus } from "@@element-plus/icons-vue"; @:import { UploadRequestOptions } from "element-plus"; @:import {@string.Join(",",Model.TableField.Where(x=>x.EffectType == "Upload").Select(x=>"upload"+x.PropertyName).ToList())} from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; } import { add@(@Model.ClassName), update@(@Model.ClassName), detail@(@Model.ClassName) } from "/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)"; - @foreach (var column in Model.TableField){ +@foreach (var column in Model.TableField){ if(@column.EffectType == "ApiTreeSelect" && !definedObjects.ContainsKey("import__@(@column.FkEntityName)Tree")){ @{definedObjects.Add("import__@(@column.FkEntityName)Tree", 1);} @:import { get@(@column.FkEntityName)Tree } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; @@ -187,17 +196,12 @@ if(@column.EffectType == "fk" && @column.WhetherAddUpdate == "Y"){ @:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)'; } - } - @if(@Model.TableField.Any(x=>x.EffectType == "EnumSelector")){ +} +@if(@Model.TableField.Any(x=>x.EffectType == "EnumSelector")){ @:import { getAPI } from '/@@/utils/axios-utils'; @:import { SysEnumApi } from '/@@/api-services/api'; - } +} - @foreach (var column in Model.TableField){ - if(@column.EffectType == "EnumSelector"){ - @:const getEnum@(@column.PropertyName)Data = ref([]); - } - } //父级传递来的参数 var props = defineProps({ title: { @@ -220,7 +224,12 @@ @:@column.LowerPropertyName: [{required: true, message: '请选择@(@column.ColumnComment)!', trigger: 'change',},], } } - } +} + }); + + // 页面加载时 + onMounted(() => { + }); // 打开弹窗 @@ -312,16 +321,6 @@ } } - - // 页面加载时 - onMounted(async () => { - @foreach (var column in Model.TableField){ - if(@column.EffectType == "EnumSelector"){ - @:getEnum@(@column.PropertyName)Data.value = (await getAPI(SysEnumApi).apiSysEnumEnumDataListGet('@(@column.DictTypeCode)')).data.result ?? []; - } - } - }); - //将属性或者函数暴露给父组件 defineExpose({ openDialog }); 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 a9b55298..18139233 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 @@ -47,7 +47,7 @@ }else if(@column.EffectType == "fk"){ @: @: - @: + @: @: @: @@ -63,7 +63,7 @@ }else if(@column.EffectType == "EnumSelector"){ @: @: - @: + @: @: @: @@ -165,7 +165,7 @@ else if(@column.EffectType == "EnumSelector"){ @: @: @: } @@ -215,11 +215,19 @@ import { ref } from "vue"; import { ElMessageBox, ElMessage } from "element-plus"; import { auth } from '/@@/utils/authFunction'; + @if(@Model.TableField.Any(x=>x.EffectType == "ConstSelector")){ @:import { codeToName, getConstType } from "/@@/utils/constHelper"; } - import { getDictDataItem as di, getDictDataList as dl } from '/@@/utils/dict-utils'; - import { formatDate } from '/@@/utils/formatTime'; + @if(@Model.TableField.Any(x=>x.EffectType == "Select")){ + @:import { getDictDataItem as di, getDictDataList as dl } from '/@@/utils/dict-utils'; + } + @if(@Model.TableField.Any(x=>x.EffectType == "EnumSelector")){ + @:import { getDictLabelByVal as dv } from '/@@/utils/dict-utils'; + } + @if(@Model.TableField.Any(x=>x.EffectType == "DatePicker")){ + @:import { formatDate } from '/@@/utils/formatTime'; + } @if(@Model.PrintType == "custom"){ @:// 推荐设置操作 width 为 200 @@ -242,15 +250,6 @@ @:import commonFunction from '/@@/utils/commonFunction'; } - @foreach (var column in Model.QueryWhetherList){ - if(@column.EffectType == "EnumSelector"){ - @:const getEnum@(@column.PropertyName)Data_Index = ref([]); - } - } - - @if(@Model.QueryWhetherList.Any(x=>x.EffectType == "EnumSelector")){ - @:const { getEnumDesc } = commonFunction(); - } @if(haveLikeCdt){ @:const showAdvanceQueryUI = ref(false); }else { @@ -274,7 +273,6 @@ const changeAdvanceQueryUI = () => { showAdvanceQueryUI.value = !showAdvanceQueryUI.value; } - // 查询操作 const handleQuery = async () => { @@ -283,11 +281,6 @@ tableData.value = res.data.result?.items ?? []; tableParams.value.total = res.data.result?.total; loading.value = false; - @foreach (var column in Model.QueryWhetherList){ - if(@column.EffectType == "EnumSelector"){ - @:getEnum@(@column.PropertyName)Data_Index.value = (await getAPI(SysEnumApi).apiSysEnumEnumDataListGet('@(@column.DictTypeCode)')).data.result ?? []; - } - } }; // 列排序 diff --git a/Admin.NET/Admin.NET.Web.Entry/wwwroot/Upload/logo.png b/Admin.NET/Admin.NET.Web.Entry/wwwroot/Upload/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5de6838f98ff076058d38ba125b4d1cbd6040804 GIT binary patch literal 15178 zcmWlgV{~I}6oqTswrv|z+jcvh+P2Nqood>tJ+*Dyw(WlTvQ~0e{@mOo_dRFteV#W; zSy2iR4i63l1O!n=T0#|gGzUJjVW5DosZ>H4zypMpsDda6NX-a0Wb`TUJ+7;ywyTiMf~4sD%Is2;YW`gs8gb+Jzr%2FBvzQ`wmvmt_d9 z2$v*e?`$BM+yV$3O;jOODNWW+nq<*z1`6l)-vH%X?ii{syf`_QmTQ%e7Lpbc60mys zdWZfV1a=lZB?pb~_pS1?)6-MCm7Mplw!Q&1q#>?}X?zB$atP&X>f;5A6 z_o(gb^pX;)(W$94i}5rWP0h575?X$bt5hUHKI!S-f`|JF!kRUloSgOEkH22Gp1Y{C zx$Ke|^_ryH-7gPT%n|^0>rFDl@q`vv8?C>Slau3lo-^9o+OBeeCu#M0zN%haT%^>{ z(BLIX_}fxfH#@xj^XJbS-0%Xk3|?Md(TVYi$w@?0b!=>G?wvJ$pNEq=bTz}{M{n-d z&8s+m_Y0cqtxli(fbXy1^DD(sj11fKOE6wXU%D+1g6E4vt^&$v4=k_EX>!gNB_zC zFYyxuDR*KOYnzyWK3~Ashf{@S6(1nRmBxcY;y1jM(L~vGUl@E%gr}a@+v(qKn4|}= zfo0vPcYH~dEffo83Ds$jEwAI_Jin(^fL^oxB}K$;K2fOud5jra%hB?T3$v(|K=3Ow zzji2ZK16|k;0Lq!`(?937N6VM;|zSU59xDpW1~7D1Pml3Bpk%S;UO)gZ0j}6t_TT9 zl5}XhA&oN$6y`}Fn$}q6wH05!5u8!L=VRXPGZS>aCtCM6_DAQX$T`k)5QdVG-{Yd! zb=UiqIZ0{?+vk?kFd;Q{u4{6R^BAr3-6%D^`h1xhwIm450oQa`C>W2jL{N1yCcWlJ zFeE$%9!1~5aT!$P+EoAy}MiAFeVdn0SyUC4z z0^FIw2S~&`j`_ad@7w7n{o$h?UH628pwQll(iBL$JQB18O>GhCAufcRzZM!YuCL#o zF7>8-fT!~4Mho3DpDmQ67I<7xQ>z7s{`)3$8AtqiBE@FE!GkN{d1H9_^~p(dgvD&g zz})$e-0^l+0S1wF=gaUhW>eGoM7@&**>T;UOk%$8cD{tzdHma_#D1%z)#syiilPkO z|7|{RjB{C^T#DH5!Q}4>?b>gzBV4b8Bq{U#p}4B6%#dd=y^^=1Y=73O;bQF9eq%)A>?US6#NH$C8YCq)T#w^&LjNGJbx z7@Ifl;7>XNlI5PDMW1x|duz$s^SG_&{#flt?aC9~X@1@3eUGFl3B4MLBE%QP^T~dF z91D*_6Z_`7>R){FfamN&&Jr2bn~!SfM|^@sN`npSpJyz_$>xCx%fbN-)d=H^n8w1ck%j&D3 ziVZytNC@}YG)o+RUVnep1iBn#vwb}^che@plQ%C~&BQGx2!Fls&d|c6`Tah1ROway z`gfQ=Ra#ay+IiWuZU`=_BrCyE|9&0t?ej{7SSSjX^t>I=4fq6891Zuo7d%PPl9iRk zd(y-^`D3Yvta#LV{JR|lcZK6|LRsa?a=+{{yOR4PriM?>i^-1DFu3AHwX#B zybpzl_b@e*M4nf`JEN%;^8~!Eb_FI>d6MgZuj7Ctk<2^{hoJeH5H}|1b#d=fC``di zz{~7En`JvCf!hI*6TqEob*84x1YzE3?@zpgV+D#I9kG9q&vqk-zm`x!_P^e*9YCXU z>wq^DQ%%R+7~z9ZqlU1}{qgkl$uKSZt+;`SNdT-(lQ=vwWo!ZWwy)Z2QI}oFxyO=@ z)xSH6{+|!vfZW+)xpYapU9{Yo%u&(ho<{3=`)F#YVN5Ok+bRkuXx;;@?l+B!XA=%f zvy`v!BhXKSOd>pOdOw@o9(X7HA;Eom!|l$vtL1E)ML@lrVxQV z(BM$aQ>k+5V4`gy1i%HIr;n?I5RY%)va6?nfONKG^!>IRRq45XvDy%jm6umjSdvNL z&4*PuP0UYXbu^KwHS|qlaKgcmfB+9S--;t_IhplX1Z)fOia+Gq#Q%O%E~;p2(`0iy z2>AfZca{I;-8eHgP1QHu_d*cf0a!T3o|L4d1R3*rbO)_FTaZVyj7aTLBkp0|60R>SLr zRyj`LaLq&Q$X$~mnF+vUTrKc^(ZIMBvB?D^aTcY}5noDADM}Kb8~|g{<@f${otB>7 zT)2iD@X}9?AIk7q~XgbBwj-IIYU%3q|eowRPKEPitS)701R=$$t>& zd_wF`uurGjZ?={B?yl7NzTTl)SXd~P+!MB?Sm>^>BK!Sc8ImzG{!BdNkQY4~U#%pP zitD06M1OKf=Lq;3D*5H4l2HHlG*vZ2xzK>qJV*atJ^h>KFX8Y9XX4^-3MZ1C+jgV1 zT1{nTr6etEGQ(jQ1gOtrSxpUd^mlAf7CHIr$#P8|m_!}?_4E6t%kdN=cm#uN@yh0A zyNA*XsGk} zs@Ps4L2qfgQeX2(3`|VQiR#`Xp{00Q$^;xH{gzrlsdGpBdXwEbYJkd6>ScW}Ir(V5 zzu-}ZnQo_%j?OB0&R*Z!4+8##9CZ4%jd-(}Q3{hZ9$REFLnS*qyJLx=>7*oo3No0B zBqo$+9hCQSk`bA1N-17LlxIk6eUyJ=){Qd&#R#&}pBHQYDm3==j;C@HD&3(%_$d5E zATh-1o+IY+CS#Q>rBwgU*hg7<4*7WC;{J&P{bdLpx_DOZnoNkBd7AVBN-pqR6YzN+ zAoTe#zb($`*|J0-VGE;`-~k9!;{z4%=Cc?}l_IV8jhb2h|BA+spjF_AJa>Y8egpfh zmZReP3ju`S6PR&9bqbY278KkU4X!5CF+m!=7RCwLRpz_FsWNY)JKs{ngd~jat+j9azb@@EcfITx z(PS3>M#h>z*N7t)_J`xfgTH>wx@ZA*hzW6C5T1#Ony$9N91srqjT|qYxc2KV{zE=K zXxFG$V7K_%xt|u+TGZ#$Isbg#7KZjV6QiokgFQq(F!t&Z{(hatx^@!ZbXzt^9+Psd z{eOYcuT#u!t0T@Vch{7aIf+}*rxptWf1d96>FAww97g#+;z-3mwcA{+`<}I`bSXOu z`YlkFhR%8T2s3lhy8UCYnTZeptlGVX8#|--N0azO0lmBZ5#zv*NKX`hqTKX1f;Qub zf;vuRdU0U^{UIRAqpdR`;p#2EcT`=a*L>*^5!lq zebR*lbU0bkv3vx{)s?MPC|MTs7I0#+Xg3e9~(=Bz2Ma;{uOcvA5M)>3*!GxmIM@Yc`-2MG|O?TCQLR@*yHJNmt z0`tL=HPSoq0HNFklU$aIWUh+xU4Z`k5OR-Eaf^pA@f3=b;QU@%e{9l~KY6%Pr@{Q~ z;dCrL4S|(%ALVzRqWNsNDH2<29xrIYdJG;x`&qm6#qQ0nbAZtt~EuH6C@q%rPd|vQ!c~cq`Er1=7rzaDwDW5`t4UzLiE2cY&{$eMVOZZqP@ls_zx2 zuh(Ph&q;YZ&Z+EknfpDU^00pNdcNA!>UD=b`(F&Ty&$*7yhx7OM3mQs*zdcBEUMS- z1LcD{clOVY+adh&u;1(_drF$76ZkG??`Tn3>LH_kb+646npOdT80Ic*)F7|1(Dz1b z0;FR6T(5RJ+$agYS<)KGqzQi(*oP_(egMbxG-lXk60D-Ikyyq^B|6#uonx50=XdNxG?{vNO~YaWaE zQho{zsJjZCZb%4}DCVwNHjmmhZ!Vqj{mpgHf|W7(?f-UKB^1J8-P88)o7F5Frt(2; zm4of;j~r90gu%xceT}VKkjoS=by1WFckQrA#r6F2La`in@j%XV&LHS{7O+anc`M|T zKW<9I0RO3H3yvD$&r>C;76wXE9*4lB&O5W&ZR~(fc;=3o904!qzHPqe4VP`>dwh+_ zr!AlBQ{(i6eI@7i%_Cqp_@$V|QML%_*af?h=d7xnbN0v_@G7@vaDoEPKlrf|f~;!T zTwSf`q+58t;s1V#%ZwLr+;Km}UZAC`51u_Qa9-IU4-(kv&LDP7u@Q>W90fz{byoH_ z96cJ{VosGC3W?x_B4*1BfRA~pz`aQ!9)VY$0e}%=A~Iy5nt#q5z(784Mb~b`y*9fpky~ zg%q7~&o&8@l`3uw6)6;;{^-4|o(z|NX8;|M3aQbJ<@cmn0OA^b)Q5Hy7imk$M>tTh zFfJh;mOKsPEBs#o9iXK;V&L26B)eMBUyCxI+V>LBO%nAyQGVZbO2B6`Ndow}aYfhG zAa+G!%{9Hj8c(_(m-K4Fb?TCAE?9yT&m2*ExY$9ii6&AR*PZWgW8{-kY*pBCM0{z-Dw*NoBGXOypHH5?Y5N*~OXlQL7_@Ak;)h!@R| z`s!i|X+58qi|bxQ)a&6rK126aiv*C3*kIHS8oj>NcPK+DoUQ>Sb+y?H* zqjeD!YDo^m*vE_2d$$#PP7 zXgZ1pp9KW29aJkANr?Dd9CJ%fx?@yq)Ttve3Ug#Ox2E#NR`o2TthQm0ftHvg(lH{M zzW7o7LE_Q~&Z7nL9u~2bMA{>)kWCG7@sZH}~eZM9)AUwiL~;9$#hv3PHITiVqRQ z-ADoxJ0k8rKT5(5Ti@N+;=_+t1<&=MIpM`WYrDqxD1q9dZK3!rw_I(IKAk5Vpnbtx zNna4t11m>_RGaSfC~h5d^L&~ji*l|VHT{uki{-(WDaRB95JV=pAJ^t85-`u;61sAt zflZcKxDi3(dR4->f1UE^VowK*XHF;_K9%rARwVFWwX9wOLj#Q&A-A&y@sb5}QD=No zBDP?bZ62aKvA$4X#9%q+J^iP*G<(v5Z6zuD|7Eoc)ats84#u%>z!ENZULc49;nV>i z5hEN!LM`-TdiJkUp5$hmo8DgIvI2cQ8?6fYUj$;IkIetge?*;Z6ov&DcnTPjWsPJs zgR?zZFaaH*^R(bI#lsyEF57{Z$gX3_z4JXObtXc_`~3Uk`7`B@@0I6MMXRid$7Q2{ z8T;S(p(t!g$pRQ;F}$F@g<>B(Zzn~~v4s3jUQ^r#^O-cFY*n}e)d>3Dr^U}9B+Nr^ zjU&;`o9@|X2okf0B1hnpqylJ<*1Xz85W}=1nwQ*Lo@VgveNnVQH~}F@WxwE;+t~fG z5CaY_8m9f-7D`pF&0?LE;~HRWLtmHl9Lk0<2@#S249zdbsG;Y*Lm(Hf3In)GmFP+W zPOMxfX7W~Jsr(qCXom*HD43`h;YR&buL!~mWcnj4Cz99(6w|`rzI}#G?|SBxAzgN` z`&Z+}YiRsulxz^J%`=QR#l^*l7!`J~(Cz#1a&wo_A0Ho>+?%fRlPT0nztL*cGmVEQ z#E%9IokuC5ZCOiao~86V8Ob#TIRQ)@}|9bxgUw(l=adGTl^}A8LVc7WhJ)*EjNAe zdA%hctLN?|mG}NnpFu`oN|1Wu!zM0(>PC zQr!&{z%xtC8&W3h8tQDuCQhA#C+(ppR;MV85zWjXJxULBr!&!*^kZ`XiU43Fb!I$< zOdJH!v~_Hy0#q{8A!bH+m9t@rX6YLWN)l9NuXl%jEPo@M5|F(+x7^~_%Opo#sNU+T zWI#i+S0F7`9;X>~>JJXIRnqKP43eQig2YS@aE{FDKotui75~+~vsWuB<|{f9vB{7P zKZ}_@_NW#<zfld#l;P0}bVu<%lRUplZd-{nPmmlVpiDa;5d57A zU9_o&bOqi%%|7*g!4QcH{|TFIA{|q-Q5}z&gF1`xO)aL5>~@1>XPJC&tB0}{8gWvN zpC>i&9gigVV2<>ts)3QJEpfM*YkEmLu6cn*bSSo=rzr1k^5P?5w22cf3`{T! zsBo|(LIs>~j8;7DL|TK-!ARI{vFJD<_K9#W9tFwxlFR;jR4}rqB+k^lHCBaAahoqu1 zS2Rq@@zzqFSK09|V=KHSEIHqZXB^a;aYiZZmxEMA-n-5sU$({>N`nqi)_w&v7SC`d zrg`PNbC7 zCzBKf81$NK!3JhiU#3^6g6%^)z4|CI`5&PU1$iS2lq?6Y+f5?E=290Tb-dVTbyRm; z*HwP0ch6H8clhu|?mKl63og3(4Teno>LB^~xGKR^zNIY>qZt6wMX(a$a(1-exq$eo)I5d1QJ zyqhQLs$(AU*=WPWT8VL1{8ZH46tJA zl4Lim0k-c+Iie@%eQ=_UIWDGJt%p2G1ZK_VW=?PjBxD}a9hNBk-Lu}mXtCH(X8(w~ z@cw~d<+#Nob$aipr%0ra8S7U)TRez0MWNBBkK@rA=G=e+wBY-i(cEfaKa3@I1jY&% zs1xZl4$>vDF_K2TUqga$mbSFK^ryz9stHcyΝQ9n_#gO?R_K!1ibz22Dysub2CW zFPc)Q?;Yq{61gCT7G{CzH|1Pujq2+V$2=Rs3!C4l?yHH67OyZjjm8cLc`PJCSOL7g z80J(l+zC;R9BOe)Jmk@HN8&ecm#tS_oAT9%ZFcH1H|^}bIKxBU`@i&!9U|C$A3Qh9 z1$7A0$H>qS)Yg`4rQb$Ll$<-}3T8}c1s^&)Prbn4>XQYq;@sdSQ7`HQQBIV8atgz- zH;0HuCe)u)7=!$xfN>|!ePZqQ>m((Heq6gqQY&Qeb$?IyRJc(YE*OAzFh#|h%6hDt zW8Aw{>sf0J&IE1>w@2TeE6}<~=`m%%{7;m|B$`M%bGd7c^w@(I5W`n{prqCPqYy`3 zH*}rE8-+`*W+O0Xp_e+()}|g|*iy;UsJ-9KIk?uI4LUMq?t4W%{C+PHA8ZYocthRv|r)gC`Ljr8c0oOFXaOH z56z?x>mt3c>kj7=^nU-gGE}#;)Md#5HMAy1ECW}WSI(Bw9qskTPp~u(Oa203Z6$fsw;d;*`X)Z zX#@vrIJ?f)R?)5i_1`Tah}xc0>#F5#CRG|B=V$xktq+QK5tyQ0o}*Zl!5b^Dcv$?l zDXl2?gmbIlxkbaC4Fg=1lDRfPph?NLf^dI1*X1Ed*AnnJ$Kc7JlaHRLY=*91s_E$H z#G(j1&D-S(JoO!~E?&Nr%{TSzTO~=$e6BmWtMq=~v`w-iQnu^gNqTkKK6)gY87PQ3 zM3iL*mS>@HqoPnNAh_!=y~{3cb!}Qr>+c`NO`8H&qPIBBmwJ6pcGbqgQuSbNzIP zJ`sNCt;%J$QZy@%_oY?AI;4)Q|Gh{1L`DGxaN`T+DU2lA0Oof_<$t9+)Dn*qNs6Qr zG)Ll;j7xfP`G2PO@NB{(75L`|Mvr`)CB|NsuA0iDH&>`Qck0}E*+p##)QF|2Ux8}f z=meAMLL467er

e%8jy!2D+V8s#!s>Hi2gKdnqy-mYCJ+ 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 - + diff --git a/Web/.prettierrc.js b/Web/.prettierrc.cjs similarity index 100% rename from Web/.prettierrc.js rename to Web/.prettierrc.cjs diff --git a/Web/package.json b/Web/package.json index ecce033e..8e32c211 100644 --- a/Web/package.json +++ b/Web/package.json @@ -2,6 +2,7 @@ "name": "admin.net.pro", "type": "module", "version": "2.4.33", + "lastBuildTime": "2024.6.16", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "author": "zuohuaijun", "license": "MIT", @@ -19,7 +20,7 @@ "@vue-office/docx": "^1.6.2", "@vue-office/excel": "^1.7.8", "@vue-office/pdf": "^2.0.2", - "@vueuse/core": "^10.10.0", + "@vueuse/core": "^10.11.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", "animate.css": "^4.1.1", @@ -52,14 +53,14 @@ "splitpanes": "^3.1.5", "vcrontab-3": "^3.3.22", "vform3-builds": "^3.0.10", - "vue": "^3.4.27", + "vue": "^3.4.29", "vue-clipboard3": "^2.0.0", "vue-demi": "^0.14.8", "vue-grid-layout": "3.0.0-beta1", "vue-i18n": "^9.13.1", "vue-json-pretty": "^2.4.0", "vue-plugin-hiprint": "0.0.57-beta20", - "vue-router": "^4.3.2", + "vue-router": "^4.3.3", "vue-signature-pad": "^3.0.2", "vue3-tree-org": "^4.2.2", "vuedraggable": "4.0.3", @@ -71,21 +72,21 @@ "@types/node": "^20.14.2", "@types/nprogress": "^0.2.3", "@types/sortablejs": "^1.15.8", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "@vitejs/plugin-vue": "^5.0.5", "@vitejs/plugin-vue-jsx": "^4.0.0", - "@vue/compiler-sfc": "^3.4.27", - "code-inspector-plugin": "^0.14.1", - "eslint": "^9.4.0", + "@vue/compiler-sfc": "^3.4.29", + "code-inspector-plugin": "^0.14.2", + "eslint": "^9.5.0", "eslint-plugin-vue": "^9.26.0", "less": "^4.2.0", - "prettier": "^3.3.1", + "prettier": "^3.3.2", "rollup-plugin-visualizer": "^5.12.0", - "sass": "^1.77.4", + "sass": "^1.77.5", "terser": "^5.31.1", "typescript": "^5.4.5", - "vite": "^5.2.13", + "vite": "^5.3.1", "vite-plugin-cdn-import": "^1.0.1", "vite-plugin-compression2": "^1.1.1", "vite-plugin-vue-setup-extend": "^0.4.0", diff --git a/Web/src/api-services/apis/sys-config-api.ts b/Web/src/api-services/apis/sys-config-api.ts index c1604a0d..5bee5bff 100644 --- a/Web/src/api-services/apis/sys-config-api.ts +++ b/Web/src/api-services/apis/sys-config-api.ts @@ -23,6 +23,7 @@ import { AdminResultListSysConfig } from '../models'; import { AdminResultObject } from '../models'; import { AdminResultSqlSugarPagedListSysConfig } from '../models'; import { AdminResultSysConfig } from '../models'; +import { BatchConfigInput } from '../models'; import { DeleteConfigInput } from '../models'; import { InfoSaveInput } from '../models'; import { PageConfigInput } from '../models'; @@ -129,6 +130,54 @@ export const SysConfigApiAxiosParamCreator = function (configuration?: Configura options: localVarRequestOptions, }; }, + /** + * + * @summary 批量更新参数配置值 + * @param {Array} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + apiSysConfigBatchUpdatePost: async (body?: Array, options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/sysConfig/batchUpdate`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, 'https://example.com'); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + // http bearer authentication required + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + localVarHeaderParameter["Authorization"] = "Bearer " + accessToken; + } + + localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + + const query = new URLSearchParams(localVarUrlObj.search); + for (const key in localVarQueryParameter) { + query.set(key, localVarQueryParameter[key]); + } + for (const key in options.params) { + query.set(key, options.params[key]); + } + localVarUrlObj.search = (new URLSearchParams(query)).toString(); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || ""); + + return { + url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, + options: localVarRequestOptions, + }; + }, /** * * @summary 删除参数配置 🔖 @@ -275,10 +324,11 @@ export const SysConfigApiAxiosParamCreator = function (configuration?: Configura /** * * @summary 获取参数配置列表 🔖 + * @param {PageConfigInput} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - apiSysConfigListGet: async (options: AxiosRequestConfig = {}): Promise => { + apiSysConfigListPost: async (body?: PageConfigInput, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/api/sysConfig/list`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, 'https://example.com'); @@ -286,7 +336,7 @@ export const SysConfigApiAxiosParamCreator = function (configuration?: Configura if (configuration) { baseOptions = configuration.baseOptions; } - const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -299,6 +349,8 @@ export const SysConfigApiAxiosParamCreator = function (configuration?: Configura localVarHeaderParameter["Authorization"] = "Bearer " + accessToken; } + localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + const query = new URLSearchParams(localVarUrlObj.search); for (const key in localVarQueryParameter) { query.set(key, localVarQueryParameter[key]); @@ -309,6 +361,8 @@ export const SysConfigApiAxiosParamCreator = function (configuration?: Configura localVarUrlObj.search = (new URLSearchParams(query)).toString(); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || ""); return { url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, @@ -539,6 +593,20 @@ export const SysConfigApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, + /** + * + * @summary 批量更新参数配置值 + * @param {Array} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysConfigBatchUpdatePost(body?: Array, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { + const localVarAxiosArgs = await SysConfigApiAxiosParamCreator(configuration).apiSysConfigBatchUpdatePost(body, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; + return axios.request(axiosRequestArgs); + }; + }, /** * * @summary 删除参数配置 🔖 @@ -583,11 +651,12 @@ export const SysConfigApiFp = function(configuration?: Configuration) { /** * * @summary 获取参数配置列表 🔖 + * @param {PageConfigInput} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async apiSysConfigListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { - const localVarAxiosArgs = await SysConfigApiAxiosParamCreator(configuration).apiSysConfigListGet(options); + async apiSysConfigListPost(body?: PageConfigInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { + const localVarAxiosArgs = await SysConfigApiAxiosParamCreator(configuration).apiSysConfigListPost(body, options); return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; return axios.request(axiosRequestArgs); @@ -677,6 +746,16 @@ export const SysConfigApiFactory = function (configuration?: Configuration, base async apiSysConfigBatchDeletePost(body?: Array, options?: AxiosRequestConfig): Promise> { return SysConfigApiFp(configuration).apiSysConfigBatchDeletePost(body, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary 批量更新参数配置值 + * @param {Array} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysConfigBatchUpdatePost(body?: Array, options?: AxiosRequestConfig): Promise> { + return SysConfigApiFp(configuration).apiSysConfigBatchUpdatePost(body, options).then((request) => request(axios, basePath)); + }, /** * * @summary 删除参数配置 🔖 @@ -709,11 +788,12 @@ export const SysConfigApiFactory = function (configuration?: Configuration, base /** * * @summary 获取参数配置列表 🔖 + * @param {PageConfigInput} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async apiSysConfigListGet(options?: AxiosRequestConfig): Promise> { - return SysConfigApiFp(configuration).apiSysConfigListGet(options).then((request) => request(axios, basePath)); + async apiSysConfigListPost(body?: PageConfigInput, options?: AxiosRequestConfig): Promise> { + return SysConfigApiFp(configuration).apiSysConfigListPost(body, options).then((request) => request(axios, basePath)); }, /** * @@ -786,6 +866,17 @@ export class SysConfigApi extends BaseAPI { public async apiSysConfigBatchDeletePost(body?: Array, options?: AxiosRequestConfig) : Promise> { return SysConfigApiFp(this.configuration).apiSysConfigBatchDeletePost(body, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary 批量更新参数配置值 + * @param {Array} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SysConfigApi + */ + public async apiSysConfigBatchUpdatePost(body?: Array, options?: AxiosRequestConfig) : Promise> { + return SysConfigApiFp(this.configuration).apiSysConfigBatchUpdatePost(body, options).then((request) => request(this.axios, this.basePath)); + } /** * * @summary 删除参数配置 🔖 @@ -821,12 +912,13 @@ export class SysConfigApi extends BaseAPI { /** * * @summary 获取参数配置列表 🔖 + * @param {PageConfigInput} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SysConfigApi */ - public async apiSysConfigListGet(options?: AxiosRequestConfig) : Promise> { - return SysConfigApiFp(this.configuration).apiSysConfigListGet(options).then((request) => request(this.axios, this.basePath)); + public async apiSysConfigListPost(body?: PageConfigInput, options?: AxiosRequestConfig) : Promise> { + return SysConfigApiFp(this.configuration).apiSysConfigListPost(body, options).then((request) => request(this.axios, this.basePath)); } /** * diff --git a/Web/src/api-services/apis/sys-sms-api.ts b/Web/src/api-services/apis/sys-sms-api.ts index d09dc347..59366fd1 100644 --- a/Web/src/api-services/apis/sys-sms-api.ts +++ b/Web/src/api-services/apis/sys-sms-api.ts @@ -72,6 +72,64 @@ export const SysSmsApiAxiosParamCreator = function (configuration?: Configuratio options: localVarRequestOptions, }; }, + /** + * + * @summary 发送短信模板 + * @param {any} body + * @param {string} phoneNumber + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + apiSysSmsAliyunSendSmsTemplatePhoneNumberPost: async (body: any, phoneNumber: string, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'body' is not null or undefined + if (body === null || body === undefined) { + throw new RequiredError('body','Required parameter body was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberPost.'); + } + // verify required parameter 'phoneNumber' is not null or undefined + if (phoneNumber === null || phoneNumber === undefined) { + throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberPost.'); + } + const localVarPath = `/api/sysSms/aliyunSendSmsTemplate/{phoneNumber}` + .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, 'https://example.com'); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + // http bearer authentication required + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + localVarHeaderParameter["Authorization"] = "Bearer " + accessToken; + } + + localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + + const query = new URLSearchParams(localVarUrlObj.search); + for (const key in localVarQueryParameter) { + query.set(key, localVarQueryParameter[key]); + } + for (const key in options.params) { + query.set(key, options.params[key]); + } + localVarUrlObj.search = (new URLSearchParams(query)).toString(); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || ""); + + return { + url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, + options: localVarRequestOptions, + }; + }, /** * * @summary 发送短信 📨 @@ -193,6 +251,21 @@ export const SysSmsApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, + /** + * + * @summary 发送短信模板 + * @param {any} body + * @param {string} phoneNumber + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body: any, phoneNumber: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { + const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body, phoneNumber, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; + return axios.request(axiosRequestArgs); + }; + }, /** * * @summary 发送短信 📨 @@ -240,6 +313,17 @@ export const SysSmsApiFactory = function (configuration?: Configuration, basePat async apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise> { return SysSmsApiFp(configuration).apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary 发送短信模板 + * @param {any} body + * @param {string} phoneNumber + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body: any, phoneNumber: string, options?: AxiosRequestConfig): Promise> { + return SysSmsApiFp(configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body, phoneNumber, options).then((request) => request(axios, basePath)); + }, /** * * @summary 发送短信 📨 @@ -281,6 +365,18 @@ export class SysSmsApi extends BaseAPI { public async apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig) : Promise> { return SysSmsApiFp(this.configuration).apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary 发送短信模板 + * @param {any} body + * @param {string} phoneNumber + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SysSmsApi + */ + public async apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body: any, phoneNumber: string, options?: AxiosRequestConfig) : Promise> { + return SysSmsApiFp(this.configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body, phoneNumber, options).then((request) => request(this.axios, this.basePath)); + } /** * * @summary 发送短信 📨 diff --git a/Web/src/api-services/models/batch-config-input.ts b/Web/src/api-services/models/batch-config-input.ts new file mode 100644 index 00000000..452146bf --- /dev/null +++ b/Web/src/api-services/models/batch-config-input.ts @@ -0,0 +1,38 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * OpenAPI spec version: 1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + /** + * 批量配置参数输入 + * + * @export + * @interface BatchConfigInput + */ +export interface BatchConfigInput { + + /** + * 编码 + * + * @type {string} + * @memberof BatchConfigInput + */ + code?: string | null; + + /** + * 属性值 + * + * @type {string} + * @memberof BatchConfigInput + */ + value?: string | null; +} diff --git a/Web/src/api-services/models/index.ts b/Web/src/api-services/models/index.ts index d1648432..94172478 100644 --- a/Web/src/api-services/models/index.ts +++ b/Web/src/api-services/models/index.ts @@ -102,6 +102,7 @@ export * from './api-info'; export * from './api-output'; export * from './assembly'; export * from './base-proc-input'; +export * from './batch-config-input'; export * from './calendar'; export * from './calendar-algorithm-type'; export * from './calendar-week-rule'; diff --git a/Web/src/views/about/index.vue b/Web/src/views/about/index.vue new file mode 100644 index 00000000..f3864372 --- /dev/null +++ b/Web/src/views/about/index.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/Web/src/views/system/database/component/addTable.vue b/Web/src/views/system/database/component/addTable.vue index 3372d95f..19a98263 100644 --- a/Web/src/views/system/database/component/addTable.vue +++ b/Web/src/views/system/database/component/addTable.vue @@ -300,6 +300,13 @@ function handleColDown(record: EditRecordRow, index: number) { } function ChangeExForArray(index1: number, index2: number, array: Array) { + let maxIndex = state.tableData.length - 1; //最大索引 + if (index2 > maxIndex) { + index2 = 0; + } + if (index2 < 0) { + index2 = maxIndex; + } let temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; diff --git a/Web/src/views/system/database/index.vue b/Web/src/views/system/database/index.vue index e8510c00..e469454a 100644 --- a/Web/src/views/system/database/index.vue +++ b/Web/src/views/system/database/index.vue @@ -15,7 +15,7 @@ 增加表 - 编辑表 + 编辑表 删除表 可视化 diff --git a/Web/src/views/system/log/exlog/index.vue b/Web/src/views/system/log/exlog/index.vue index 2fbe777d..cf5d3bc1 100644 --- a/Web/src/views/system/log/exlog/index.vue +++ b/Web/src/views/system/log/exlog/index.vue @@ -16,7 +16,7 @@ 清空 - 导出 + 导出 diff --git a/Web/src/views/system/org/index.vue b/Web/src/views/system/org/index.vue index 51630b22..879dfaa3 100644 --- a/Web/src/views/system/org/index.vue +++ b/Web/src/views/system/org/index.vue @@ -107,10 +107,14 @@ const handleQuery = async (updateTree: boolean = false) => { // 是否更新左侧机构列表树 if (updateTree == true) { orgTreeRef.value?.initTreeData(); + // 更新编辑页面机构列表树 + var res = await getAPI(SysOrgApi).apiSysOrgListGet(0); + state.orgTreeData = res.data.result ?? []; } // 若无选择节点并且查询条件为空时,更新编辑页面机构列表树 - if (state.queryParams.id == 0 && state.queryParams.name == undefined && state.queryParams.code == undefined && state.queryParams.type == undefined) state.orgTreeData = state.orgData; + if (state.queryParams.id == 0 && state.queryParams.name == undefined && state.queryParams.code == undefined && state.queryParams.type == undefined && updateTree == false) + state.orgTreeData = state.orgData; }; // 重置操作 diff --git a/Web/vite.config.ts b/Web/vite.config.ts index 055aede4..3266a0d4 100644 --- a/Web/vite.config.ts +++ b/Web/vite.config.ts @@ -31,6 +31,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => { vue(), vueJsx(), webUpdateNotice({ + versionType: 'build_timestamp', notificationConfig: { placement: 'topLeft', },