Pārlūkot izejas kodu

🤓1、增加hiprint打印模式 2、恢复volar插件前默认模式 3、升级所有依赖及其他调整

zuohuaijun 3 gadi atpakaļ
vecāks
revīzija
2b360d9fec
44 mainītis faili ar 3933 papildinājumiem un 469 dzēšanām
  1. 5 5
      Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj
  2. 49 0
      Admin.NET/Admin.NET.Core/Entity/SysPlugin.cs
  3. 42 0
      Admin.NET/Admin.NET.Core/Entity/SysPrint.cs
  4. 12 0
      Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
  5. 12 0
      Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs
  6. 31 0
      Admin.NET/Admin.NET.Core/Service/Plugin/Dto/PluginInput.cs
  7. 105 0
      Admin.NET/Admin.NET.Core/Service/Plugin/SysPluginService.cs
  8. 31 0
      Admin.NET/Admin.NET.Core/Service/Print/Dto/PrintInput.cs
  9. 73 0
      Admin.NET/Admin.NET.Core/Service/Print/SysPrintService.cs
  10. 1 1
      Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatPayService.cs
  11. 1 1
      Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatService.cs
  12. 1 1
      Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatUserService.cs
  13. 1 1
      Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs
  14. 12 0
      Admin.NET/Admin.NET.Core/Util/JsonSerializerProvider.cs
  15. 4 1
      Web/package.json
  16. 748 321
      Web/pnpm-lock.yaml
  17. 280 0
      Web/public/print-lock.css
  18. 2 0
      Web/src/api-services/api.ts
  19. 524 0
      Web/src/api-services/apis/sys-plugin-api.ts
  20. 362 0
      Web/src/api-services/apis/sys-print-api.ts
  21. 99 0
      Web/src/api-services/models/add-plugin-input.ts
  22. 93 0
      Web/src/api-services/models/add-print-input.ts
  23. 57 0
      Web/src/api-services/models/admin-result-sql-sugar-paged-list-sys-plugin.ts
  24. 57 0
      Web/src/api-services/models/admin-result-sql-sugar-paged-list-sys-print.ts
  25. 26 0
      Web/src/api-services/models/delete-plugin-input.ts
  26. 26 0
      Web/src/api-services/models/delete-print-input.ts
  27. 14 0
      Web/src/api-services/models/index.ts
  28. 62 0
      Web/src/api-services/models/page-plugin-input.ts
  29. 62 0
      Web/src/api-services/models/page-print-input.ts
  30. 63 0
      Web/src/api-services/models/sql-sugar-paged-list-sys-plugin.ts
  31. 63 0
      Web/src/api-services/models/sql-sugar-paged-list-sys-print.ts
  32. 99 0
      Web/src/api-services/models/sys-plugin.ts
  33. 93 0
      Web/src/api-services/models/sys-print.ts
  34. 99 0
      Web/src/api-services/models/update-plugin-input.ts
  35. 93 0
      Web/src/api-services/models/update-print-input.ts
  36. 0 17
      Web/src/globalComponents.d.ts
  37. 0 115
      Web/src/globalElementPlus.d.ts
  38. 2 2
      Web/src/main.ts
  39. 2 2
      Web/src/theme/element.scss
  40. 200 0
      Web/src/views/system/plugin/component/editPlugin.vue
  41. 131 0
      Web/src/views/system/plugin/index.vue
  42. 154 0
      Web/src/views/system/print/component/editPrint.vue
  43. 140 0
      Web/src/views/system/print/index.vue
  44. 2 2
      Web/src/views/system/user/component/userCenter.vue

+ 5 - 5
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -21,20 +21,20 @@
     <PackageReference Include="DotNetCore.Compile.Environment" Version="3.2.0" />
     <PackageReference Include="DotNetCore.Natasha.CSharp" Version="5.2.2.1" />
     <PackageReference Include="FluentEmail.Smtp" Version="3.0.2" />
-    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.14" />
-    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.14" />
-    <PackageReference Include="Furion.Pure" Version="4.8.8.14" />
+    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.17" />
+    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.17" />
+    <PackageReference Include="Furion.Pure" Version="4.8.8.17" />
     <PackageReference Include="IPTools.China" Version="1.6.0" />
     <PackageReference Include="Lazy.Captcha.Core" Version="2.0.3" />
     <PackageReference Include="Magicodes.IE.Excel" Version="2.7.4.4" />
     <PackageReference Include="Magicodes.IE.Pdf" Version="2.7.4.4" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.16" />
     <PackageReference Include="NEST" Version="7.17.5" />
-    <PackageReference Include="NewLife.Redis" Version="5.3.2023.401" />
+    <PackageReference Include="NewLife.Redis" Version="5.3.2023.512" />
     <PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.1.9" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="2.27.0" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="2.18.0" />
-    <PackageReference Include="SqlSugarCore" Version="5.1.4.72" />
+    <PackageReference Include="SqlSugarCore" Version="5.1.4.73" />
     <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.2" />
     <PackageReference Include="UAParser" Version="3.1.47" />
     <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />

+ 49 - 0
Admin.NET/Admin.NET.Core/Entity/SysPlugin.cs

@@ -0,0 +1,49 @@
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 系统动态插件表
+/// </summary>
+[SugarTable(null, "系统动态插件表")]
+[SystemTable]
+public class SysPlugin : EntityTenant
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    [SugarColumn(ColumnDescription = "名称", Length = 64)]
+    [Required, MaxLength(64)]
+    public virtual string Name { get; set; }
+
+    /// <summary>
+    /// 程序集名称
+    /// </summary>
+    [SugarColumn(ColumnDescription = "程序集名称", Length = 512)]
+    [Required, MaxLength(512)]
+    public virtual string AssemblyName { get; set; }
+
+    /// <summary>
+    /// C#代码
+    /// </summary>
+    [SugarColumn(ColumnDescription = "C#代码", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    [Required]
+    public virtual string CsharpCode { get; set; }
+
+    /// <summary>
+    /// 排序
+    /// </summary>
+    [SugarColumn(ColumnDescription = "排序")]
+    public int OrderNo { get; set; } = 100;
+
+    /// <summary>
+    /// 状态
+    /// </summary>
+    [SugarColumn(ColumnDescription = "状态")]
+    public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    [SugarColumn(ColumnDescription = "备注", Length = 128)]
+    [MaxLength(128)]
+    public string? Remark { get; set; }
+}

+ 42 - 0
Admin.NET/Admin.NET.Core/Entity/SysPrint.cs

@@ -0,0 +1,42 @@
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 系统打印模板表
+/// </summary>
+[SugarTable(null, "系统打印模板表")]
+[SystemTable]
+public class SysPrint : EntityTenant
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    [SugarColumn(ColumnDescription = "名称", Length = 64)]
+    [Required, MaxLength(64)]
+    public virtual string Name { get; set; }
+
+    /// <summary>
+    /// 打印模板
+    /// </summary>
+    [SugarColumn(ColumnDescription = "打印模板", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    [Required]
+    public virtual string Template { get; set; }
+
+    /// <summary>
+    /// 排序
+    /// </summary>
+    [SugarColumn(ColumnDescription = "排序")]
+    public int OrderNo { get; set; } = 100;
+
+    /// <summary>
+    /// 状态
+    /// </summary>
+    [SugarColumn(ColumnDescription = "状态")]
+    public StatusEnum Status { get; set; } = StatusEnum.Enable;
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    [SugarColumn(ColumnDescription = "备注", Length = 128)]
+    [MaxLength(128)]
+    public string? Remark { get; set; }
+}

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

@@ -511,6 +511,18 @@ public enum ErrorCodeEnum
     [ErrorCodeItemMetadata("禁止修改作业编号")]
     D1704,
 
+    /// <summary>
+    /// 已存在同名打印模板
+    /// </summary>
+    [ErrorCodeItemMetadata("已存在同名打印模板")]
+    D1800,
+
+    /// <summary>
+    /// 已存在同名功能插件
+    /// </summary>
+    [ErrorCodeItemMetadata("已存在同名功能插件")]
+    D1900,
+
     /// <summary>
     /// 已存在同名或同编码项目
     /// </summary>

+ 12 - 0
Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs

@@ -129,6 +129,18 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
             new SysMenu{ Id=1310000000394, Pid=1310000000391, Title="下载", Permission="sysFile:downloadFile", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1310000000395, Pid=1310000000391, Title="删除", Permission="sysFile:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
 
+            new SysMenu{ Id=1310000000401, Pid=1310000000301, Title="打印模板", Path="/platform/print", Name="sysPrint", Component="/system/print/index", Icon="ele-Printer", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=190 },
+            new SysMenu{ Id=1310000000402, Pid=1310000000401, Title="查询", Permission="sysPrint:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000403, Pid=1310000000401, Title="编辑", Permission="sysPrint:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000404, Pid=1310000000401, Title="增加", Permission="sysPrint:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000405, Pid=1310000000401, Title="删除", Permission="sysPrint:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+
+            new SysMenu{ Id=1310000000411, Pid=1310000000301, Title="动态插件", Path="/platform/plugin", Name="sysPlugin", Component="/system/plugin/index", Icon="ele-Connection", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=200 },
+            new SysMenu{ Id=1310000000412, Pid=1310000000411, Title="查询", Permission="sysPlugin:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000413, Pid=1310000000411, Title="编辑", Permission="sysPlugin:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000414, Pid=1310000000411, Title="增加", Permission="sysPlugin:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1310000000415, Pid=1310000000411, Title="删除", Permission="sysPlugin:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+
             new SysMenu{ Id=1310000000501, Pid=0, Title="日志管理", Path="/log", Name="log", Component="Layout", Icon="ele-DocumentCopy", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=1200 },
             new SysMenu{ Id=1310000000511, Pid=1310000000501, Title="访问日志", Path="/log/vislog", Name="sysVislog", Component="/system/log/vislog/index", Icon="ele-Document", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1310000000512, Pid=1310000000511, Title="查询", Permission="sysVislog:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },

+ 31 - 0
Admin.NET/Admin.NET.Core/Service/Plugin/Dto/PluginInput.cs

@@ -0,0 +1,31 @@
+namespace Admin.NET.Core.Service;
+
+public class PagePluginInput : BasePageInput
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 编码
+    /// </summary>
+    public string Code { get; set; }
+}
+
+public class AddPluginInput : SysPlugin
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    [Required(ErrorMessage = "功能名称不能为空")]
+    public override string Name { get; set; }
+}
+
+public class UpdatePluginInput : AddPluginInput
+{
+}
+
+public class DeletePluginInput : BaseIdInput
+{
+}

+ 105 - 0
Admin.NET/Admin.NET.Core/Service/Plugin/SysPluginService.cs

@@ -0,0 +1,105 @@
+namespace Admin.NET.Core.Service;
+
+/// <summary>
+/// 系统动态插件服务
+/// </summary>
+[ApiDescriptionSettings(Order = 245)]
+public class SysPluginService : IDynamicApiController, ITransient
+{
+    private readonly IDynamicApiRuntimeChangeProvider _provider;
+    private readonly SqlSugarRepository<SysPlugin> _sysPluginRep;
+
+    public SysPluginService(IDynamicApiRuntimeChangeProvider provider,
+        SqlSugarRepository<SysPlugin> sysPluginRep)
+    {
+        _provider = provider;
+        _sysPluginRep = sysPluginRep;
+    }
+
+    /// <summary>
+    /// 获取动态插件列表
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("获取动态插件列表")]
+    public async Task<SqlSugarPagedList<SysPlugin>> Page(PagePluginInput input)
+    {
+        return await _sysPluginRep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
+            .OrderBy(u => u.OrderNo)
+            .ToPagedListAsync(input.Page, input.PageSize);
+    }
+
+    /// <summary>
+    /// 增加动态插件
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Add"), HttpPost]
+    [DisplayName("增加动态插件")]
+    public async Task AddPos(AddPluginInput input)
+    {
+        var isExist = await _sysPluginRep.IsAnyAsync(u => u.Name == input.Name);
+        if (isExist)
+            throw Oops.Oh(ErrorCodeEnum.D1900);
+
+        await _sysPluginRep.InsertAsync(input.Adapt<SysPlugin>());
+    }
+
+    /// <summary>
+    /// 更新动态插件
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Update"), HttpPost]
+    [DisplayName("更新动态插件")]
+    public async Task UpdatePos(UpdatePluginInput input)
+    {
+        var isExist = await _sysPluginRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
+        if (isExist)
+            throw Oops.Oh(ErrorCodeEnum.D1900);
+
+        await _sysPluginRep.AsUpdateable(input.Adapt<SysPlugin>()).IgnoreColumns(true).ExecuteCommandAsync();
+    }
+
+    /// <summary>
+    /// 删除动态插件
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
+    [DisplayName("删除动态插件")]
+    public async Task DeletePos(DeletePluginInput input)
+    {
+        await _sysPluginRep.DeleteAsync(u => u.Id == input.Id);
+    }
+
+    /// <summary>
+    /// 添加动态程序集/接口
+    /// </summary>
+    /// <param name="csharpCode"></param>
+    /// <param name="assemblyName">程序集名称</param>
+    /// <returns></returns>
+    [DisplayName("添加动态程序集/接口")]
+    public string CompileAssembly([FromBody] string csharpCode, [FromQuery] string assemblyName = default)
+    {
+        // 编译 C# 代码并返回动态程序集
+        var dynamicAssembly = App.CompileCSharpClassCode(csharpCode, assemblyName);
+
+        // 将程序集添加进动态 WebAPI 应用部件
+        _provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
+
+        // 返回动态程序集名称
+        return dynamicAssembly.GetName().Name;
+    }
+
+    /// <summary>
+    /// 移除动态程序集/接口
+    /// </summary>
+    [ApiDescriptionSettings(Name = "RemoveAssembly"), HttpPost]
+    [DisplayName("移除动态程序集/接口")]
+    public void RemoveAssembly(string assemblyName)
+    {
+        _provider.RemoveAssembliesWithNotifyChanges(assemblyName);
+    }
+}

+ 31 - 0
Admin.NET/Admin.NET.Core/Service/Print/Dto/PrintInput.cs

@@ -0,0 +1,31 @@
+namespace Admin.NET.Core.Service;
+
+public class PagePrintInput : BasePageInput
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 编码
+    /// </summary>
+    public string Code { get; set; }
+}
+
+public class AddPrintInput : SysPrint
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    [Required(ErrorMessage = "模板名称不能为空")]
+    public override string Name { get; set; }
+}
+
+public class UpdatePrintInput : AddPrintInput
+{
+}
+
+public class DeletePrintInput : BaseIdInput
+{
+}

+ 73 - 0
Admin.NET/Admin.NET.Core/Service/Print/SysPrintService.cs

@@ -0,0 +1,73 @@
+namespace Admin.NET.Core.Service;
+
+/// <summary>
+/// 系统打印模板服务
+/// </summary>
+[ApiDescriptionSettings(Order = 305)]
+public class SysPrintService : IDynamicApiController, ITransient
+{
+    private readonly SqlSugarRepository<SysPrint> _sysPrintRep;
+
+    public SysPrintService(SqlSugarRepository<SysPrint> sysPrintRep)
+    {
+        _sysPrintRep = sysPrintRep;
+    }
+
+    /// <summary>
+    /// 获取打印模板列表
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("获取打印模板列表")]
+    public async Task<SqlSugarPagedList<SysPrint>> Page(PagePrintInput input)
+    {
+        return await _sysPrintRep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
+            .OrderBy(u => u.OrderNo)
+            .ToPagedListAsync(input.Page, input.PageSize);
+    }
+
+    /// <summary>
+    /// 增加打印模板
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Add"), HttpPost]
+    [DisplayName("增加打印模板")]
+    public async Task AddPos(AddPrintInput input)
+    {
+        var isExist = await _sysPrintRep.IsAnyAsync(u => u.Name == input.Name);
+        if (isExist)
+            throw Oops.Oh(ErrorCodeEnum.D1800);
+
+        await _sysPrintRep.InsertAsync(input.Adapt<SysPrint>());
+    }
+
+    /// <summary>
+    /// 更新打印模板
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Update"), HttpPost]
+    [DisplayName("更新打印模板")]
+    public async Task UpdatePos(UpdatePrintInput input)
+    {
+        var isExist = await _sysPrintRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
+        if (isExist)
+            throw Oops.Oh(ErrorCodeEnum.D1800);
+
+        await _sysPrintRep.AsUpdateable(input.Adapt<SysPrint>()).IgnoreColumns(true).ExecuteCommandAsync();
+    }
+
+    /// <summary>
+    /// 删除打印模板
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
+    [DisplayName("删除打印模板")]
+    public async Task DeletePos(DeletePrintInput input)
+    {
+        await _sysPrintRep.DeleteAsync(u => u.Id == input.Id);
+    }
+}

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatPayService.cs

@@ -3,7 +3,7 @@
 /// <summary>
 /// 微信支付服务
 /// </summary>
-[ApiDescriptionSettings(Order = 220)]
+[ApiDescriptionSettings(Order = 210)]
 public class SysWechatPayService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayUserRep;

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatService.cs

@@ -3,7 +3,7 @@
 /// <summary>
 /// 微信公众号服务
 /// </summary>
-[ApiDescriptionSettings(Order = 240)]
+[ApiDescriptionSettings(Order = 230)]
 public class SysWechatService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Wechat/SysWechatUserService.cs

@@ -3,7 +3,7 @@
 /// <summary>
 /// 微信账号服务
 /// </summary>
-[ApiDescriptionSettings(Order = 230)]
+[ApiDescriptionSettings(Order = 220)]
 public class SysWechatUserService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs

@@ -3,7 +3,7 @@
 /// <summary>
 /// 微信小程序服务
 /// </summary>
-[ApiDescriptionSettings(Order = 250)]
+[ApiDescriptionSettings(Order = 240)]
 public class SysWxOpenService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysWechatUser> _sysWechatUserRep;

+ 12 - 0
Admin.NET/Admin.NET.Core/Util/JsonSerializerProvider.cs

@@ -28,6 +28,18 @@ public class JsonSerializerProvider : IJsonSerializerProvider, ISingleton
         return JsonConvert.DeserializeObject<T>(json, (jsonSerializerOptions ?? GetSerializerOptions()) as JsonSerializerSettings);
     }
 
+    /// <summary>
+    /// 反序列化字符串
+    /// </summary>
+    /// <param name="json"></param>
+    /// <param name="returnType"></param>
+    /// <param name="jsonSerializerOptions"></param>
+    /// <returns></returns>
+    public object Deserialize(string json, Type returnType, object jsonSerializerOptions = null)
+    {
+        return JsonConvert.DeserializeObject(json, returnType, (jsonSerializerOptions ?? GetSerializerOptions()) as JsonSerializerSettings);
+    }
+
     /// <summary>
     /// 返回读取全局配置的 JSON 选项
     /// </summary>

+ 4 - 1
Web/package.json

@@ -46,7 +46,10 @@
 		"vue-router": "^4.1.6",
 		"vue-signature-pad": "^3.0.2",
 		"vue3-tree-org": "^4.1.1",
-		"xlsx-js-style": "^1.2.0"
+		"xlsx-js-style": "^1.2.0",
+		"sv-print": "^0.1.8",
+		"@sv-print/vue3": "^0.1.8",
+		"@sv-print/hiprint": "^0.1.8"
 	},
 	"devDependencies": {
 		"@types/lodash-es": "^4.17.7",

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 748 - 321
Web/pnpm-lock.yaml


+ 280 - 0
Web/public/print-lock.css

@@ -0,0 +1,280 @@
+@media print {
+  body {
+    margin: 0px;
+    padding: 0px;
+  }
+}
+
+@page {
+  margin: 0;
+}
+
+.hiprint-printPaper * {
+  box-sizing: border-box;
+  image-rendering: -webkit-optimize-contrast; /* 让图片/标尺稍微清楚一点 */
+}
+
+.hiprint-printPaper *:focus {
+  outline: -webkit-focus-ring-color auto 0px;
+}
+
+.hiprint-page-break-avoid {
+  page-break-after: avoid;
+}
+.hiprint-printPaper {
+  position: relative;
+  padding: 0 0 0 0;
+  page-break-after: always;
+  -webkit-user-select: none; /* Chrome/Safari/Opera */
+  -moz-user-select: none; /* Firefox */
+  user-select: none;
+  overflow-x: hidden;
+  overflow: hidden;
+}
+.hiprint-printPaper .hiprint-printPaper-content {
+  position: relative;
+}
+.hiprint-printPaper.design {
+  overflow: visible;
+}
+
+.hiprint-printTemplate .hiprint-printPanel {
+  page-break-after: always;
+}
+
+.hiprint-printPaper,
+hiprint-printPanel {
+  box-sizing: border-box;
+  border: 0px;
+}
+
+.hiprint-printPanel .hiprint-printPaper:last-child {
+  page-break-after: avoid;
+}
+
+.hiprint-printTemplate .hiprint-printPanel:last-child {
+  page-break-after: avoid;
+}
+
+.hiprint-printPaper .hideheaderLinetarget {
+  border-top: 0px dashed rgb(201, 190, 190) !important;
+}
+
+.hiprint-printPaper .hidefooterLinetarget {
+  border-top: 0px dashed rgb(201, 190, 190) !important;
+}
+
+.hiprint-printPaper.design {
+  border: 1px dashed rgba(170, 170, 170, 0.7);
+}
+
+.design .hiprint-printElement-table-content,
+.design .hiprint-printElement-longText-content {
+  overflow: hidden;
+  box-sizing: border-box;
+}
+
+.design .resize-panel {
+  box-sizing: border-box;
+  border: 1px dotted;
+}
+
+.hiprint-printElement-text {
+  background-color: transparent;
+  background-repeat: repeat;
+  padding: 0 0 0 0;
+  border: 0.75pt none rgb(0, 0, 0);
+  direction: ltr;
+  font-family: "SimSun";
+  font-size: 9pt;
+  font-style: normal;
+  font-weight: normal;
+  padding-bottom: 0pt;
+  padding-left: 0pt;
+  padding-right: 0pt;
+  padding-top: 0pt;
+  text-align: left;
+  text-decoration: none;
+  line-height: 9.75pt;
+  box-sizing: border-box;
+  word-wrap: break-word;
+  word-break: break-all;
+}
+
+.design .hiprint-printElement-text-content {
+  border: 1px dashed rgb(206, 188, 188);
+  box-sizing: border-box;
+}
+
+.hiprint-printElement-longText {
+  background-color: transparent;
+  background-repeat: repeat;
+  border: 0.75pt none rgb(0, 0, 0);
+  direction: ltr;
+  font-family: "SimSun";
+  font-size: 9pt;
+  font-style: normal;
+  font-weight: normal;
+  padding-bottom: 0pt;
+  padding-left: 0pt;
+  padding-right: 0pt;
+  padding-top: 0pt;
+  text-align: left;
+  text-decoration: none;
+  line-height: 9.75pt;
+  box-sizing: border-box;
+  word-wrap: break-word;
+  word-break: break-all;
+  /*white-space: pre-wrap*/
+}
+
+.hiprint-printElement-table {
+  background-color: transparent;
+  background-repeat: repeat;
+  color: rgb(0, 0, 0);
+  border-color: rgb(0, 0, 0);
+  border-style: none;
+  direction: ltr;
+  font-family: "SimSun";
+  font-size: 9pt;
+  font-style: normal;
+  font-weight: normal;
+  padding-bottom: 0pt;
+  padding-left: 0pt;
+  padding-right: 0pt;
+  padding-top: 0pt;
+  text-align: left;
+  text-decoration: none;
+  padding: 0 0 0 0;
+  box-sizing: border-box;
+  line-height: 9.75pt;
+}
+
+.hiprint-printElement-table thead {
+  background: #e8e8e8;
+  font-weight: 700;
+}
+
+.hiprint-printElement-tableTarget,
+.hiprint-printElement-tableTarget tr,
+.hiprint-printElement-tableTarget td {
+  border-color: rgb(0, 0, 0);
+  border-style: none;
+  /*border: 1px solid rgb(0,0,0);*/
+  font-weight: normal;
+  direction: ltr;
+  padding-bottom: 0pt;
+  padding-left: 4pt;
+  padding-right: 4pt;
+  padding-top: 0pt;
+  text-decoration: none;
+  vertical-align: middle;
+  box-sizing: border-box;
+  word-wrap: break-word;
+  word-break: break-all;
+  /*line-height: 9.75pt;
+    font-size: 9pt;*/
+}
+
+/*.hiprint-printElement-tableTarget tr,*/
+.hiprint-printElement-tableTarget td {
+  height: 18pt;
+}
+
+.hiprint-printPaper .hiprint-paperNumber {
+  font-size: 9pt;
+}
+
+.design .hiprint-printElement-table-handle {
+  position: absolute;
+  height: 12pt;
+  width: 12pt;
+  background: red;
+  z-index: 1;
+}
+
+.hiprint-printPaper .hiprint-paperNumber-disabled {
+  float: right !important;
+  right: 0 !important;
+  color: gainsboro !important;
+}
+
+.hiprint-printElement-vline,
+.hiprint-printElement-hline {
+  border: 0px none rgb(0, 0, 0);
+}
+.hiprint-printElement-vline {
+  border-left: 0.75pt solid #000;
+  border-right: 0px none rgb(0, 0, 0) !important;
+  border-bottom: 0px none rgb(0, 0, 0) !important;
+  border-top: 0px none rgb(0, 0, 0) !important;
+}
+
+.hiprint-printElement-hline {
+  border-top: 0.75pt solid #000;
+  border-right: 0px none rgb(0, 0, 0) !important;
+  border-bottom: 0px none rgb(0, 0, 0) !important;
+  border-left: 0px none rgb(0, 0, 0) !important;
+}
+
+.hiprint-printElement-oval,
+.hiprint-printElement-rect {
+  border: 0.75pt solid #000;
+}
+
+.hiprint-text-content-middle {
+  display: table;
+}
+.hiprint-text-content-middle > div {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+.hiprint-text-content-bottom {
+  display: table;
+}
+
+.hiprint-text-content-bottom > div {
+  display: table-cell;
+  vertical-align: bottom;
+}
+
+/*hi-grid-row */
+.hi-grid-row {
+  position: relative;
+  height: auto;
+  margin-right: 0;
+  margin-left: 0;
+  zoom: 1;
+  display: block;
+  box-sizing: border-box;
+}
+
+.hi-grid-row::after,
+.hi-grid-row::before {
+  display: table;
+  content: "";
+  box-sizing: border-box;
+}
+
+.hi-grid-col {
+  display: block;
+  box-sizing: border-box;
+  position: relative;
+  float: left;
+  flex: 0 0 auto;
+}
+
+.table-grid-row {
+  margin-left: -0pt;
+  margin-right: -0pt;
+}
+
+.tableGridColumnsGutterRow {
+  padding-left: 0pt;
+  padding-right: 0pt;
+}
+.hiprint-gridColumnsFooter {
+  text-align: left;
+  clear: both;
+}

+ 2 - 0
Web/src/api-services/api.ts

@@ -32,7 +32,9 @@ export * from './apis/sys-message-api';
 export * from './apis/sys-notice-api';
 export * from './apis/sys-online-user-api';
 export * from './apis/sys-org-api';
+export * from './apis/sys-plugin-api';
 export * from './apis/sys-pos-api';
+export * from './apis/sys-print-api';
 export * from './apis/sys-region-api';
 export * from './apis/sys-role-api';
 export * from './apis/sys-server-api';

+ 524 - 0
Web/src/api-services/apis/sys-plugin-api.ts

@@ -0,0 +1,524 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import globalAxios, { AxiosResponse, AxiosInstance, AxiosRequestConfig } from 'axios';
+import { Configuration } from '../configuration';
+// Some imports not used depending on template conditions
+// @ts-ignore
+import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
+import { AddPluginInput } from '../models';
+import { AdminResultSqlSugarPagedListSysPlugin } from '../models';
+import { AdminResultString } from '../models';
+import { DeletePluginInput } from '../models';
+import { PagePluginInput } from '../models';
+import { UpdatePluginInput } from '../models';
+/**
+ * SysPluginApi - axios parameter creator
+ * @export
+ */
+export const SysPluginApiAxiosParamCreator = function (configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 增加动态插件
+         * @param {AddPluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPluginAddPost: async (body?: AddPluginInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPlugin/add`;
+            // 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
+
+            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 添加动态程序集/接口
+         * @param {string} [body] 
+         * @param {string} [assemblyName] 程序集名称
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPluginCompileAssemblyPost: async (body?: string, assemblyName?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPlugin/compileAssembly`;
+            // 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
+
+            if (assemblyName !== undefined) {
+                localVarQueryParameter['assemblyName'] = assemblyName;
+            }
+
+            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 删除动态插件
+         * @param {DeletePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPluginDeletePost: async (body?: DeletePluginInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPlugin/delete`;
+            // 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
+
+            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 获取动态插件列表
+         * @param {PagePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPluginPagePost: async (body?: PagePluginInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPlugin/page`;
+            // 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
+
+            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 移除动态程序集/接口
+         * @param {string} assemblyName 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPluginRemoveAssemblyAssemblyNamePost: async (assemblyName: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // verify required parameter 'assemblyName' is not null or undefined
+            if (assemblyName === null || assemblyName === undefined) {
+                throw new RequiredError('assemblyName','Required parameter assemblyName was null or undefined when calling apiSysPluginRemoveAssemblyAssemblyNamePost.');
+            }
+            const localVarPath = `/api/sysPlugin/removeAssembly/{assemblyName}`
+                .replace(`{${"assemblyName"}}`, encodeURIComponent(String(assemblyName)));
+            // 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
+
+            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};
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 更新动态插件
+         * @param {UpdatePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPluginUpdatePost: async (body?: UpdatePluginInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPlugin/update`;
+            // 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
+
+            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,
+            };
+        },
+    }
+};
+
+/**
+ * SysPluginApi - functional programming interface
+ * @export
+ */
+export const SysPluginApiFp = function(configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 增加动态插件
+         * @param {AddPluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginAddPost(body?: AddPluginInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPluginApiAxiosParamCreator(configuration).apiSysPluginAddPost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 添加动态程序集/接口
+         * @param {string} [body] 
+         * @param {string} [assemblyName] 程序集名称
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginCompileAssemblyPost(body?: string, assemblyName?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultString>>> {
+            const localVarAxiosArgs = await SysPluginApiAxiosParamCreator(configuration).apiSysPluginCompileAssemblyPost(body, assemblyName, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 删除动态插件
+         * @param {DeletePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginDeletePost(body?: DeletePluginInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPluginApiAxiosParamCreator(configuration).apiSysPluginDeletePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 获取动态插件列表
+         * @param {PagePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginPagePost(body?: PagePluginInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSqlSugarPagedListSysPlugin>>> {
+            const localVarAxiosArgs = await SysPluginApiAxiosParamCreator(configuration).apiSysPluginPagePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 移除动态程序集/接口
+         * @param {string} assemblyName 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginRemoveAssemblyAssemblyNamePost(assemblyName: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPluginApiAxiosParamCreator(configuration).apiSysPluginRemoveAssemblyAssemblyNamePost(assemblyName, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 更新动态插件
+         * @param {UpdatePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginUpdatePost(body?: UpdatePluginInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPluginApiAxiosParamCreator(configuration).apiSysPluginUpdatePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+    }
+};
+
+/**
+ * SysPluginApi - factory interface
+ * @export
+ */
+export const SysPluginApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
+    return {
+        /**
+         * 
+         * @summary 增加动态插件
+         * @param {AddPluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginAddPost(body?: AddPluginInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPluginApiFp(configuration).apiSysPluginAddPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 添加动态程序集/接口
+         * @param {string} [body] 
+         * @param {string} [assemblyName] 程序集名称
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginCompileAssemblyPost(body?: string, assemblyName?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
+            return SysPluginApiFp(configuration).apiSysPluginCompileAssemblyPost(body, assemblyName, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 删除动态插件
+         * @param {DeletePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginDeletePost(body?: DeletePluginInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPluginApiFp(configuration).apiSysPluginDeletePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取动态插件列表
+         * @param {PagePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginPagePost(body?: PagePluginInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSqlSugarPagedListSysPlugin>> {
+            return SysPluginApiFp(configuration).apiSysPluginPagePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 移除动态程序集/接口
+         * @param {string} assemblyName 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginRemoveAssemblyAssemblyNamePost(assemblyName: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPluginApiFp(configuration).apiSysPluginRemoveAssemblyAssemblyNamePost(assemblyName, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 更新动态插件
+         * @param {UpdatePluginInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPluginUpdatePost(body?: UpdatePluginInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPluginApiFp(configuration).apiSysPluginUpdatePost(body, options).then((request) => request(axios, basePath));
+        },
+    };
+};
+
+/**
+ * SysPluginApi - object-oriented interface
+ * @export
+ * @class SysPluginApi
+ * @extends {BaseAPI}
+ */
+export class SysPluginApi extends BaseAPI {
+    /**
+     * 
+     * @summary 增加动态插件
+     * @param {AddPluginInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPluginApi
+     */
+    public async apiSysPluginAddPost(body?: AddPluginInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPluginApiFp(this.configuration).apiSysPluginAddPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 添加动态程序集/接口
+     * @param {string} [body] 
+     * @param {string} [assemblyName] 程序集名称
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPluginApi
+     */
+    public async apiSysPluginCompileAssemblyPost(body?: string, assemblyName?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
+        return SysPluginApiFp(this.configuration).apiSysPluginCompileAssemblyPost(body, assemblyName, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 删除动态插件
+     * @param {DeletePluginInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPluginApi
+     */
+    public async apiSysPluginDeletePost(body?: DeletePluginInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPluginApiFp(this.configuration).apiSysPluginDeletePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取动态插件列表
+     * @param {PagePluginInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPluginApi
+     */
+    public async apiSysPluginPagePost(body?: PagePluginInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSqlSugarPagedListSysPlugin>> {
+        return SysPluginApiFp(this.configuration).apiSysPluginPagePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 移除动态程序集/接口
+     * @param {string} assemblyName 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPluginApi
+     */
+    public async apiSysPluginRemoveAssemblyAssemblyNamePost(assemblyName: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPluginApiFp(this.configuration).apiSysPluginRemoveAssemblyAssemblyNamePost(assemblyName, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 更新动态插件
+     * @param {UpdatePluginInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPluginApi
+     */
+    public async apiSysPluginUpdatePost(body?: UpdatePluginInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPluginApiFp(this.configuration).apiSysPluginUpdatePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+}

+ 362 - 0
Web/src/api-services/apis/sys-print-api.ts

@@ -0,0 +1,362 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import globalAxios, { AxiosResponse, AxiosInstance, AxiosRequestConfig } from 'axios';
+import { Configuration } from '../configuration';
+// Some imports not used depending on template conditions
+// @ts-ignore
+import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
+import { AddPrintInput } from '../models';
+import { AdminResultSqlSugarPagedListSysPrint } from '../models';
+import { DeletePrintInput } from '../models';
+import { PagePrintInput } from '../models';
+import { UpdatePrintInput } from '../models';
+/**
+ * SysPrintApi - axios parameter creator
+ * @export
+ */
+export const SysPrintApiAxiosParamCreator = function (configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 增加打印模板
+         * @param {AddPrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPrintAddPost: async (body?: AddPrintInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPrint/add`;
+            // 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
+
+            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 删除打印模板
+         * @param {DeletePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPrintDeletePost: async (body?: DeletePrintInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPrint/delete`;
+            // 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
+
+            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 获取打印模板列表
+         * @param {PagePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPrintPagePost: async (body?: PagePrintInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPrint/page`;
+            // 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
+
+            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 更新打印模板
+         * @param {UpdatePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysPrintUpdatePost: async (body?: UpdatePrintInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysPrint/update`;
+            // 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
+
+            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,
+            };
+        },
+    }
+};
+
+/**
+ * SysPrintApi - functional programming interface
+ * @export
+ */
+export const SysPrintApiFp = function(configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 增加打印模板
+         * @param {AddPrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintAddPost(body?: AddPrintInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPrintApiAxiosParamCreator(configuration).apiSysPrintAddPost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 删除打印模板
+         * @param {DeletePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintDeletePost(body?: DeletePrintInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPrintApiAxiosParamCreator(configuration).apiSysPrintDeletePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 获取打印模板列表
+         * @param {PagePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintPagePost(body?: PagePrintInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSqlSugarPagedListSysPrint>>> {
+            const localVarAxiosArgs = await SysPrintApiAxiosParamCreator(configuration).apiSysPrintPagePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 更新打印模板
+         * @param {UpdatePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintUpdatePost(body?: UpdatePrintInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysPrintApiAxiosParamCreator(configuration).apiSysPrintUpdatePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+    }
+};
+
+/**
+ * SysPrintApi - factory interface
+ * @export
+ */
+export const SysPrintApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
+    return {
+        /**
+         * 
+         * @summary 增加打印模板
+         * @param {AddPrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintAddPost(body?: AddPrintInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPrintApiFp(configuration).apiSysPrintAddPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 删除打印模板
+         * @param {DeletePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintDeletePost(body?: DeletePrintInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPrintApiFp(configuration).apiSysPrintDeletePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取打印模板列表
+         * @param {PagePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintPagePost(body?: PagePrintInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSqlSugarPagedListSysPrint>> {
+            return SysPrintApiFp(configuration).apiSysPrintPagePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 更新打印模板
+         * @param {UpdatePrintInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysPrintUpdatePost(body?: UpdatePrintInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysPrintApiFp(configuration).apiSysPrintUpdatePost(body, options).then((request) => request(axios, basePath));
+        },
+    };
+};
+
+/**
+ * SysPrintApi - object-oriented interface
+ * @export
+ * @class SysPrintApi
+ * @extends {BaseAPI}
+ */
+export class SysPrintApi extends BaseAPI {
+    /**
+     * 
+     * @summary 增加打印模板
+     * @param {AddPrintInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPrintApi
+     */
+    public async apiSysPrintAddPost(body?: AddPrintInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPrintApiFp(this.configuration).apiSysPrintAddPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 删除打印模板
+     * @param {DeletePrintInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPrintApi
+     */
+    public async apiSysPrintDeletePost(body?: DeletePrintInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPrintApiFp(this.configuration).apiSysPrintDeletePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取打印模板列表
+     * @param {PagePrintInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPrintApi
+     */
+    public async apiSysPrintPagePost(body?: PagePrintInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSqlSugarPagedListSysPrint>> {
+        return SysPrintApiFp(this.configuration).apiSysPrintPagePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 更新打印模板
+     * @param {UpdatePrintInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysPrintApi
+     */
+    public async apiSysPrintUpdatePost(body?: UpdatePrintInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysPrintApiFp(this.configuration).apiSysPrintUpdatePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+}

+ 99 - 0
Web/src/api-services/models/add-plugin-input.ts

@@ -0,0 +1,99 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { StatusEnum } from './status-enum';
+/**
+ * 
+ * @export
+ * @interface AddPluginInput
+ */
+export interface AddPluginInput {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof AddPluginInput
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof AddPluginInput
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof AddPluginInput
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof AddPluginInput
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof AddPluginInput
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof AddPluginInput
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof AddPluginInput
+     */
+    tenantId?: number | null;
+    /**
+     * 程序集名称
+     * @type {string}
+     * @memberof AddPluginInput
+     */
+    assemblyName: string;
+    /**
+     * C#代码
+     * @type {string}
+     * @memberof AddPluginInput
+     */
+    csharpCode: string;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof AddPluginInput
+     */
+    orderNo?: number;
+    /**
+     * 
+     * @type {StatusEnum}
+     * @memberof AddPluginInput
+     */
+    status?: StatusEnum;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof AddPluginInput
+     */
+    remark?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof AddPluginInput
+     */
+    name: string;
+}

+ 93 - 0
Web/src/api-services/models/add-print-input.ts

@@ -0,0 +1,93 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { StatusEnum } from './status-enum';
+/**
+ * 
+ * @export
+ * @interface AddPrintInput
+ */
+export interface AddPrintInput {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof AddPrintInput
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof AddPrintInput
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof AddPrintInput
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof AddPrintInput
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof AddPrintInput
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof AddPrintInput
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof AddPrintInput
+     */
+    tenantId?: number | null;
+    /**
+     * 打印模板
+     * @type {string}
+     * @memberof AddPrintInput
+     */
+    template: string;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof AddPrintInput
+     */
+    orderNo?: number;
+    /**
+     * 
+     * @type {StatusEnum}
+     * @memberof AddPrintInput
+     */
+    status?: StatusEnum;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof AddPrintInput
+     */
+    remark?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof AddPrintInput
+     */
+    name: string;
+}

+ 57 - 0
Web/src/api-services/models/admin-result-sql-sugar-paged-list-sys-plugin.ts

@@ -0,0 +1,57 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { SqlSugarPagedListSysPlugin } from './sql-sugar-paged-list-sys-plugin';
+/**
+ * 全局返回结果
+ * @export
+ * @interface AdminResultSqlSugarPagedListSysPlugin
+ */
+export interface AdminResultSqlSugarPagedListSysPlugin {
+    /**
+     * 状态码
+     * @type {number}
+     * @memberof AdminResultSqlSugarPagedListSysPlugin
+     */
+    code?: number;
+    /**
+     * 类型success、warning、error
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysPlugin
+     */
+    type?: string | null;
+    /**
+     * 错误信息
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysPlugin
+     */
+    message?: string | null;
+    /**
+     * 
+     * @type {SqlSugarPagedListSysPlugin}
+     * @memberof AdminResultSqlSugarPagedListSysPlugin
+     */
+    result?: SqlSugarPagedListSysPlugin;
+    /**
+     * 附加数据
+     * @type {any}
+     * @memberof AdminResultSqlSugarPagedListSysPlugin
+     */
+    extras?: any | null;
+    /**
+     * 时间
+     * @type {Date}
+     * @memberof AdminResultSqlSugarPagedListSysPlugin
+     */
+    time?: Date;
+}

+ 57 - 0
Web/src/api-services/models/admin-result-sql-sugar-paged-list-sys-print.ts

@@ -0,0 +1,57 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { SqlSugarPagedListSysPrint } from './sql-sugar-paged-list-sys-print';
+/**
+ * 全局返回结果
+ * @export
+ * @interface AdminResultSqlSugarPagedListSysPrint
+ */
+export interface AdminResultSqlSugarPagedListSysPrint {
+    /**
+     * 状态码
+     * @type {number}
+     * @memberof AdminResultSqlSugarPagedListSysPrint
+     */
+    code?: number;
+    /**
+     * 类型success、warning、error
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysPrint
+     */
+    type?: string | null;
+    /**
+     * 错误信息
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysPrint
+     */
+    message?: string | null;
+    /**
+     * 
+     * @type {SqlSugarPagedListSysPrint}
+     * @memberof AdminResultSqlSugarPagedListSysPrint
+     */
+    result?: SqlSugarPagedListSysPrint;
+    /**
+     * 附加数据
+     * @type {any}
+     * @memberof AdminResultSqlSugarPagedListSysPrint
+     */
+    extras?: any | null;
+    /**
+     * 时间
+     * @type {Date}
+     * @memberof AdminResultSqlSugarPagedListSysPrint
+     */
+    time?: Date;
+}

+ 26 - 0
Web/src/api-services/models/delete-plugin-input.ts

@@ -0,0 +1,26 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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 DeletePluginInput
+ */
+export interface DeletePluginInput {
+    /**
+     * 主键Id
+     * @type {number}
+     * @memberof DeletePluginInput
+     */
+    id: number;
+}

+ 26 - 0
Web/src/api-services/models/delete-print-input.ts

@@ -0,0 +1,26 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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 DeletePrintInput
+ */
+export interface DeletePrintInput {
+    /**
+     * 主键Id
+     * @type {number}
+     * @memberof DeletePrintInput
+     */
+    id: number;
+}

+ 14 - 0
Web/src/api-services/models/index.ts

@@ -8,7 +8,9 @@ export * from './add-job-trigger-input';
 export * from './add-menu-input';
 export * from './add-notice-input';
 export * from './add-org-input';
+export * from './add-plugin-input';
 export * from './add-pos-input';
+export * from './add-print-input';
 export * from './add-region-input';
 export * from './add-role-input';
 export * from './add-subscribe-message-template-input';
@@ -62,6 +64,8 @@ export * from './admin-result-sql-sugar-paged-list-sys-log-vis';
 export * from './admin-result-sql-sugar-paged-list-sys-notice';
 export * from './admin-result-sql-sugar-paged-list-sys-notice-user';
 export * from './admin-result-sql-sugar-paged-list-sys-online-user';
+export * from './admin-result-sql-sugar-paged-list-sys-plugin';
+export * from './admin-result-sql-sugar-paged-list-sys-print';
 export * from './admin-result-sql-sugar-paged-list-sys-region';
 export * from './admin-result-sql-sugar-paged-list-sys-role';
 export * from './admin-result-sql-sugar-paged-list-sys-user';
@@ -108,7 +112,9 @@ export * from './delete-job-trigger-input';
 export * from './delete-menu-input';
 export * from './delete-notice-input';
 export * from './delete-org-input';
+export * from './delete-plugin-input';
 export * from './delete-pos-input';
+export * from './delete-print-input';
 export * from './delete-region-input';
 export * from './delete-role-input';
 export * from './delete-tenant-input';
@@ -149,6 +155,8 @@ export * from './page-job-input';
 export * from './page-log-input';
 export * from './page-notice-input';
 export * from './page-online-user-input';
+export * from './page-plugin-input';
+export * from './page-print-input';
 export * from './page-region-input';
 export * from './page-role-input';
 export * from './page-tenant-input';
@@ -174,6 +182,8 @@ export * from './sql-sugar-paged-list-sys-log-vis';
 export * from './sql-sugar-paged-list-sys-notice';
 export * from './sql-sugar-paged-list-sys-notice-user';
 export * from './sql-sugar-paged-list-sys-online-user';
+export * from './sql-sugar-paged-list-sys-plugin';
+export * from './sql-sugar-paged-list-sys-print';
 export * from './sql-sugar-paged-list-sys-region';
 export * from './sql-sugar-paged-list-sys-role';
 export * from './sql-sugar-paged-list-sys-user';
@@ -204,7 +214,9 @@ export * from './sys-notice';
 export * from './sys-notice-user';
 export * from './sys-online-user';
 export * from './sys-org';
+export * from './sys-plugin';
 export * from './sys-pos';
+export * from './sys-print';
 export * from './sys-region';
 export * from './sys-role';
 export * from './sys-user';
@@ -228,7 +240,9 @@ export * from './update-job-trigger-input';
 export * from './update-menu-input';
 export * from './update-notice-input';
 export * from './update-org-input';
+export * from './update-plugin-input';
 export * from './update-pos-input';
+export * from './update-print-input';
 export * from './update-region-input';
 export * from './update-role-input';
 export * from './update-tenant-input';

+ 62 - 0
Web/src/api-services/models/page-plugin-input.ts

@@ -0,0 +1,62 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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 PagePluginInput
+ */
+export interface PagePluginInput {
+    /**
+     * 当前页码
+     * @type {number}
+     * @memberof PagePluginInput
+     */
+    page?: number;
+    /**
+     * 页码容量
+     * @type {number}
+     * @memberof PagePluginInput
+     */
+    pageSize?: number;
+    /**
+     * 排序字段
+     * @type {string}
+     * @memberof PagePluginInput
+     */
+    field?: string | null;
+    /**
+     * 排序方向
+     * @type {string}
+     * @memberof PagePluginInput
+     */
+    order?: string | null;
+    /**
+     * 降序排序
+     * @type {string}
+     * @memberof PagePluginInput
+     */
+    descStr?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof PagePluginInput
+     */
+    name?: string | null;
+    /**
+     * 编码
+     * @type {string}
+     * @memberof PagePluginInput
+     */
+    code?: string | null;
+}

+ 62 - 0
Web/src/api-services/models/page-print-input.ts

@@ -0,0 +1,62 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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 PagePrintInput
+ */
+export interface PagePrintInput {
+    /**
+     * 当前页码
+     * @type {number}
+     * @memberof PagePrintInput
+     */
+    page?: number;
+    /**
+     * 页码容量
+     * @type {number}
+     * @memberof PagePrintInput
+     */
+    pageSize?: number;
+    /**
+     * 排序字段
+     * @type {string}
+     * @memberof PagePrintInput
+     */
+    field?: string | null;
+    /**
+     * 排序方向
+     * @type {string}
+     * @memberof PagePrintInput
+     */
+    order?: string | null;
+    /**
+     * 降序排序
+     * @type {string}
+     * @memberof PagePrintInput
+     */
+    descStr?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof PagePrintInput
+     */
+    name?: string | null;
+    /**
+     * 编码
+     * @type {string}
+     * @memberof PagePrintInput
+     */
+    code?: string | null;
+}

+ 63 - 0
Web/src/api-services/models/sql-sugar-paged-list-sys-plugin.ts

@@ -0,0 +1,63 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { SysPlugin } from './sys-plugin';
+/**
+ * 分页泛型集合
+ * @export
+ * @interface SqlSugarPagedListSysPlugin
+ */
+export interface SqlSugarPagedListSysPlugin {
+    /**
+     * 页码
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    page?: number;
+    /**
+     * 页容量
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    pageSize?: number;
+    /**
+     * 总条数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    total?: number;
+    /**
+     * 总页数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    totalPages?: number;
+    /**
+     * 当前页集合
+     * @type {Array<SysPlugin>}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    items?: Array<SysPlugin> | null;
+    /**
+     * 是否有上一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    hasPrevPage?: boolean;
+    /**
+     * 是否有下一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysPlugin
+     */
+    hasNextPage?: boolean;
+}

+ 63 - 0
Web/src/api-services/models/sql-sugar-paged-list-sys-print.ts

@@ -0,0 +1,63 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { SysPrint } from './sys-print';
+/**
+ * 分页泛型集合
+ * @export
+ * @interface SqlSugarPagedListSysPrint
+ */
+export interface SqlSugarPagedListSysPrint {
+    /**
+     * 页码
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    page?: number;
+    /**
+     * 页容量
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    pageSize?: number;
+    /**
+     * 总条数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    total?: number;
+    /**
+     * 总页数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    totalPages?: number;
+    /**
+     * 当前页集合
+     * @type {Array<SysPrint>}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    items?: Array<SysPrint> | null;
+    /**
+     * 是否有上一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    hasPrevPage?: boolean;
+    /**
+     * 是否有下一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysPrint
+     */
+    hasNextPage?: boolean;
+}

+ 99 - 0
Web/src/api-services/models/sys-plugin.ts

@@ -0,0 +1,99 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { StatusEnum } from './status-enum';
+/**
+ * 系统动态插件表
+ * @export
+ * @interface SysPlugin
+ */
+export interface SysPlugin {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof SysPlugin
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof SysPlugin
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof SysPlugin
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof SysPlugin
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof SysPlugin
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof SysPlugin
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof SysPlugin
+     */
+    tenantId?: number | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof SysPlugin
+     */
+    name: string;
+    /**
+     * 程序集名称
+     * @type {string}
+     * @memberof SysPlugin
+     */
+    assemblyName: string;
+    /**
+     * C#代码
+     * @type {string}
+     * @memberof SysPlugin
+     */
+    csharpCode: string;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof SysPlugin
+     */
+    orderNo?: number;
+    /**
+     * 
+     * @type {StatusEnum}
+     * @memberof SysPlugin
+     */
+    status?: StatusEnum;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof SysPlugin
+     */
+    remark?: string | null;
+}

+ 93 - 0
Web/src/api-services/models/sys-print.ts

@@ -0,0 +1,93 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { StatusEnum } from './status-enum';
+/**
+ * 系统打印模板表
+ * @export
+ * @interface SysPrint
+ */
+export interface SysPrint {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof SysPrint
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof SysPrint
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof SysPrint
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof SysPrint
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof SysPrint
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof SysPrint
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof SysPrint
+     */
+    tenantId?: number | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof SysPrint
+     */
+    name: string;
+    /**
+     * 打印模板
+     * @type {string}
+     * @memberof SysPrint
+     */
+    template: string;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof SysPrint
+     */
+    orderNo?: number;
+    /**
+     * 
+     * @type {StatusEnum}
+     * @memberof SysPrint
+     */
+    status?: StatusEnum;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof SysPrint
+     */
+    remark?: string | null;
+}

+ 99 - 0
Web/src/api-services/models/update-plugin-input.ts

@@ -0,0 +1,99 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { StatusEnum } from './status-enum';
+/**
+ * 
+ * @export
+ * @interface UpdatePluginInput
+ */
+export interface UpdatePluginInput {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof UpdatePluginInput
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof UpdatePluginInput
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof UpdatePluginInput
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof UpdatePluginInput
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof UpdatePluginInput
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof UpdatePluginInput
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof UpdatePluginInput
+     */
+    tenantId?: number | null;
+    /**
+     * 程序集名称
+     * @type {string}
+     * @memberof UpdatePluginInput
+     */
+    assemblyName: string;
+    /**
+     * C#代码
+     * @type {string}
+     * @memberof UpdatePluginInput
+     */
+    csharpCode: string;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof UpdatePluginInput
+     */
+    orderNo?: number;
+    /**
+     * 
+     * @type {StatusEnum}
+     * @memberof UpdatePluginInput
+     */
+    status?: StatusEnum;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof UpdatePluginInput
+     */
+    remark?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof UpdatePluginInput
+     */
+    name: string;
+}

+ 93 - 0
Web/src/api-services/models/update-print-input.ts

@@ -0,0 +1,93 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * 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.
+ */
+import { StatusEnum } from './status-enum';
+/**
+ * 
+ * @export
+ * @interface UpdatePrintInput
+ */
+export interface UpdatePrintInput {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof UpdatePrintInput
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof UpdatePrintInput
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof UpdatePrintInput
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof UpdatePrintInput
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof UpdatePrintInput
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof UpdatePrintInput
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof UpdatePrintInput
+     */
+    tenantId?: number | null;
+    /**
+     * 打印模板
+     * @type {string}
+     * @memberof UpdatePrintInput
+     */
+    template: string;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof UpdatePrintInput
+     */
+    orderNo?: number;
+    /**
+     * 
+     * @type {StatusEnum}
+     * @memberof UpdatePrintInput
+     */
+    status?: StatusEnum;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof UpdatePrintInput
+     */
+    remark?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof UpdatePrintInput
+     */
+    name: string;
+}

+ 0 - 17
Web/src/globalComponents.d.ts

@@ -1,17 +0,0 @@
-import SvgIcon from '/@/components/svgIcon/index.vue';
-
-import GridLayout from 'vue-grid-layout';
-import VueSignaturePad from 'vue-signature-pad';
-import Vue3TreeOrg from 'vue3-tree-org';
-
-// 用于 volar 插件的全局注册组件声明
-declare module 'vue' {
-	export interface GlobalComponents {
-		SvgIcon: typeof SvgIcon;
-		GridLayout: typeof GridLayout;
-		Vue3TreeOrg: typeof Vue3TreeOrg.Vue3TreeOrg;
-		VueSignaturePad: typeof VueSignaturePad;
-	}
-}
-
-export {};

+ 0 - 115
Web/src/globalElementPlus.d.ts

@@ -1,115 +0,0 @@
-// 来源:https://github.com/element-plus/element-plus/blob/dev/global.d.ts
-// 官方的写法不支持 vue 2.7 以上
-
-// 用于 volar 插件的全局注册组件声明
-declare module 'vue' {
-	export interface GlobalComponents {
-		ElAffix: typeof import('element-plus')['ElAffix'];
-		ElAlert: typeof import('element-plus')['ElAlert'];
-		ElAside: typeof import('element-plus')['ElAside'];
-		ElAutocomplete: typeof import('element-plus')['ElAutocomplete'];
-		ElAvatar: typeof import('element-plus')['ElAvatar'];
-		ElBacktop: typeof import('element-plus')['ElBacktop'];
-		ElBadge: typeof import('element-plus')['ElBadge'];
-		ElBreadcrumb: typeof import('element-plus')['ElBreadcrumb'];
-		ElBreadcrumbItem: typeof import('element-plus')['ElBreadcrumbItem'];
-		ElButton: typeof import('element-plus')['ElButton'];
-		ElButtonGroup: typeof import('element-plus')['ElButtonGroup'];
-		ElCalendar: typeof import('element-plus')['ElCalendar'];
-		ElCard: typeof import('element-plus')['ElCard'];
-		ElCarousel: typeof import('element-plus')['ElCarousel'];
-		ElCarouselItem: typeof import('element-plus')['ElCarouselItem'];
-		ElCascader: typeof import('element-plus')['ElCascader'];
-		ElCascaderPanel: typeof import('element-plus')['ElCascaderPanel'];
-		ElCheckbox: typeof import('element-plus')['ElCheckbox'];
-		ElCheckboxButton: typeof import('element-plus')['ElCheckboxButton'];
-		ElCheckboxGroup: typeof import('element-plus')['ElCheckboxGroup'];
-		ElCol: typeof import('element-plus')['ElCol'];
-		ElCollapse: typeof import('element-plus')['ElCollapse'];
-		ElCollapseItem: typeof import('element-plus')['ElCollapseItem'];
-		ElCollapseTransition: typeof import('element-plus')['ElCollapseTransition'];
-		ElColorPicker: typeof import('element-plus')['ElColorPicker'];
-		ElContainer: typeof import('element-plus')['ElContainer'];
-		ElConfigProvider: typeof import('element-plus')['ElConfigProvider'];
-		ElDatePicker: typeof import('element-plus')['ElDatePicker'];
-		ElDialog: typeof import('element-plus')['ElDialog'];
-		ElDivider: typeof import('element-plus')['ElDivider'];
-		ElDrawer: typeof import('element-plus')['ElDrawer'];
-		ElDropdown: typeof import('element-plus')['ElDropdown'];
-		ElDropdownItem: typeof import('element-plus')['ElDropdownItem'];
-		ElDropdownMenu: typeof import('element-plus')['ElDropdownMenu'];
-		ElEmpty: typeof import('element-plus')['ElEmpty'];
-		ElFooter: typeof import('element-plus')['ElFooter'];
-		ElForm: typeof import('element-plus')['ElForm'];
-		ElFormItem: typeof import('element-plus')['ElFormItem'];
-		ElHeader: typeof import('element-plus')['ElHeader'];
-		ElIcon: typeof import('element-plus')['ElIcon'];
-		ElImage: typeof import('element-plus')['ElImage'];
-		ElImageViewer: typeof import('element-plus')['ElImageViewer'];
-		ElInput: typeof import('element-plus')['ElInput'];
-		ElInputNumber: typeof import('element-plus')['ElInputNumber'];
-		ElLink: typeof import('element-plus')['ElLink'];
-		ElMain: typeof import('element-plus')['ElMain'];
-		ElMenu: typeof import('element-plus')['ElMenu'];
-		ElMenuItem: typeof import('element-plus')['ElMenuItem'];
-		ElMenuItemGroup: typeof import('element-plus')['ElMenuItemGroup'];
-		ElOption: typeof import('element-plus')['ElOption'];
-		ElOptionGroup: typeof import('element-plus')['ElOptionGroup'];
-		ElPageHeader: typeof import('element-plus')['ElPageHeader'];
-		ElPagination: typeof import('element-plus')['ElPagination'];
-		ElPopconfirm: typeof import('element-plus')['ElPopconfirm'];
-		ElPopper: typeof import('element-plus')['ElPopper'];
-		ElPopover: typeof import('element-plus')['ElPopover'];
-		ElProgress: typeof import('element-plus')['ElProgress'];
-		ElRadio: typeof import('element-plus')['ElRadio'];
-		ElRadioButton: typeof import('element-plus')['ElRadioButton'];
-		ElRadioGroup: typeof import('element-plus')['ElRadioGroup'];
-		ElRate: typeof import('element-plus')['ElRate'];
-		ElRow: typeof import('element-plus')['ElRow'];
-		ElScrollbar: typeof import('element-plus')['ElScrollbar'];
-		ElSelect: typeof import('element-plus')['ElSelect'];
-		ElSlider: typeof import('element-plus')['ElSlider'];
-		ElStep: typeof import('element-plus')['ElStep'];
-		ElSteps: typeof import('element-plus')['ElSteps'];
-		ElSubMenu: typeof import('element-plus')['ElSubMenu'];
-		ElSwitch: typeof import('element-plus')['ElSwitch'];
-		ElTabPane: typeof import('element-plus')['ElTabPane'];
-		ElTable: typeof import('element-plus')['ElTable'];
-		ElTableColumn: typeof import('element-plus')['ElTableColumn'];
-		ElTabs: typeof import('element-plus')['ElTabs'];
-		ElTag: typeof import('element-plus')['ElTag'];
-		ElText: typeof import('element-plus')['ElText'];
-		ElTimePicker: typeof import('element-plus')['ElTimePicker'];
-		ElTimeSelect: typeof import('element-plus')['ElTimeSelect'];
-		ElTimeline: typeof import('element-plus')['ElTimeline'];
-		ElTimelineItem: typeof import('element-plus')['ElTimelineItem'];
-		ElTooltip: typeof import('element-plus')['ElTooltip'];
-		ElTransfer: typeof import('element-plus')['ElTransfer'];
-		ElTree: typeof import('element-plus')['ElTree'];
-		ElTreeV2: typeof import('element-plus')['ElTreeV2'];
-		ElTreeSelect: typeof import('element-plus')['ElTreeSelect'];
-		ElUpload: typeof import('element-plus')['ElUpload'];
-		ElSpace: typeof import('element-plus')['ElSpace'];
-		ElSkeleton: typeof import('element-plus')['ElSkeleton'];
-		ElSkeletonItem: typeof import('element-plus')['ElSkeletonItem'];
-		ElStatistic: typeof import('element-plus')['ElStatistic'];
-		ElCheckTag: typeof import('element-plus')['ElCheckTag'];
-		ElDescriptions: typeof import('element-plus')['ElDescriptions'];
-		ElDescriptionsItem: typeof import('element-plus')['ElDescriptionsItem'];
-		ElResult: typeof import('element-plus')['ElResult'];
-		ElSelectV2: typeof import('element-plus')['ElSelectV2'];
-	}
-
-	interface ComponentCustomProperties {
-		$message: typeof import('element-plus')['ElMessage'];
-		$notify: typeof import('element-plus')['ElNotification'];
-		$msgbox: typeof import('element-plus')['ElMessageBox'];
-		$messageBox: typeof import('element-plus')['ElMessageBox'];
-		$alert: typeof import('element-plus')['ElMessageBox']['alert'];
-		$confirm: typeof import('element-plus')['ElMessageBox']['confirm'];
-		$prompt: typeof import('element-plus')['ElMessageBox']['prompt'];
-		$loading: typeof import('element-plus')['ElLoadingService'];
-	}
-}
-
-export {};

+ 2 - 2
Web/src/main.ts

@@ -13,7 +13,7 @@ import VueGridLayout from 'vue-grid-layout';
 import VForm3 from 'vform3-builds'; // VForm3表单设计
 import 'vform3-builds/dist/designer.style.css'; // VForm3表单设计样式
 import VueSignaturePad from 'vue-signature-pad'; // 电子签名
-import Vue3TreeOrg from 'vue3-tree-org'; // 组织架构图
+import vue3TreeOrg from 'vue3-tree-org'; // 组织架构图
 import 'vue3-tree-org/lib/vue3-tree-org.css'; // 组织架构图样式
 import 'animate.css'; // 动画库
 
@@ -22,4 +22,4 @@ const app = createApp(App);
 directive(app);
 other.elSvg(app);
 
-app.use(pinia).use(router).use(ElementPlus).use(i18n).use(VueGridLayout).use(VForm3).use(VueSignaturePad).use(Vue3TreeOrg).mount('#app');
+app.use(pinia).use(router).use(ElementPlus).use(i18n).use(VueGridLayout).use(VForm3).use(VueSignaturePad).use(vue3TreeOrg).mount('#app');

+ 2 - 2
Web/src/theme/element.scss

@@ -274,9 +274,9 @@
 	}
 }
 .el-dialog__body {
-	max-height: calc(90vh - 111px) !important;
+	max-height: calc(100vh - 85px) !important;
 	overflow-y: auto;
-	overflow-x: hidden;
+	overflow-x: auto;
 }
 .el-dialog__title{
 	font-size: 14px;

+ 200 - 0
Web/src/views/system/plugin/component/editPlugin.vue

@@ -0,0 +1,200 @@
+<template>
+	<div class="sys-plugin-container">
+		<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="769px">
+			<template #header>
+				<div style="color: #fff">
+					<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
+					<span> {{ props.title }} </span>
+				</div>
+			</template>
+			<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="80px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="上级菜单">
+							<el-cascader
+								:options="props.menuData"
+								:props="{ checkStrictly: true, emitPath: false, value: 'id', label: 'title' }"
+								placeholder="请选择上级菜单"
+								clearable
+								class="w100"
+								v-model="state.ruleForm.pid"
+							>
+								<template #default="{ node, data }">
+									<span>{{ data.title }}</span>
+									<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
+								</template>
+							</el-cascader>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="菜单类型" prop="type" :rules="[{ required: true, message: '菜单类型不能为空', trigger: 'blur' }]">
+							<el-radio-group v-model="state.ruleForm.type">
+								<el-radio :label="1">目录</el-radio>
+								<el-radio :label="2">菜单</el-radio>
+								<el-radio :label="3">按钮</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="菜单名称" prop="title" :rules="[{ required: true, message: '菜单名称不能为空', trigger: 'blur' }]">
+							<el-input v-model="state.ruleForm.title" placeholder="菜单名称" clearable />
+						</el-form-item>
+					</el-col>
+					<template v-if="state.ruleForm.type === 1 || state.ruleForm.type === 2">
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="路由名称">
+								<el-input v-model="state.ruleForm.name" placeholder="路由名称" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="路由路径">
+								<el-input v-model="state.ruleForm.path" placeholder="路由路径" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="组件路径">
+								<el-input v-model="state.ruleForm.component" placeholder="组件路径" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="菜单图标">
+								<IconSelector v-model="state.ruleForm.icon" placeholder="菜单图标" type="all" />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="重定向">
+								<el-input v-model="state.ruleForm.redirect" placeholder="重定向地址" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="链接地址">
+								<el-input v-model="state.ruleForm.outLink" placeholder="外链/内嵌时链接地址" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="菜单排序">
+								<el-input-number v-model="state.ruleForm.orderNo" placeholder="排序" class="w100" />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="是否隐藏">
+								<el-radio-group v-model="state.ruleForm.isHide">
+									<el-radio :label="true">隐藏</el-radio>
+									<el-radio :label="false">不隐藏</el-radio>
+								</el-radio-group>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="是否缓存">
+								<el-radio-group v-model="state.ruleForm.isKeepAlive">
+									<el-radio :label="true">缓存</el-radio>
+									<el-radio :label="false">不缓存</el-radio>
+								</el-radio-group>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="是否固定">
+								<el-radio-group v-model="state.ruleForm.isAffix">
+									<el-radio :label="true">固定</el-radio>
+									<el-radio :label="false">不固定</el-radio>
+								</el-radio-group>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="是否内嵌">
+								<el-radio-group v-model="state.ruleForm.isIframe">
+									<el-radio :label="true">内嵌</el-radio>
+									<el-radio :label="false">不内嵌</el-radio>
+								</el-radio-group>
+							</el-form-item>
+						</el-col>
+					</template>
+					<template v-if="state.ruleForm.type === 3">
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="权限标识">
+								<el-input v-model="state.ruleForm.permission" placeholder="权限标识" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="菜单排序">
+								<el-input-number v-model="state.ruleForm.orderNo" placeholder="排序" class="w100" />
+							</el-form-item>
+						</el-col>
+					</template>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="是否启用">
+							<el-radio-group v-model="state.ruleForm.status">
+								<el-radio :label="1">启用</el-radio>
+								<el-radio :label="2">不启用</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="备注">
+							<el-input v-model="state.ruleForm.remark" placeholder="请输入备注内容" clearable type="textarea" />
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel">取 消</el-button>
+					<el-button type="primary" @click="submit">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysEditPlugin">
+import { reactive, ref } from 'vue';
+import IconSelector from '/@/components/iconSelector/index.vue';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysMenuApi } from '/@/api-services/api';
+import { SysMenu, UpdateMenuInput } from '/@/api-services/models';
+
+const props = defineProps({
+	title: String,
+	menuData: Array<SysMenu>,
+});
+const emits = defineEmits(['handleQuery']);
+const ruleFormRef = ref();
+const state = reactive({
+	isShowDialog: false,
+	ruleForm: {} as UpdateMenuInput,
+});
+
+// 打开弹窗
+const openDialog = (row: any) => {
+	state.ruleForm = JSON.parse(JSON.stringify(row));
+	state.isShowDialog = true;
+};
+
+// 关闭弹窗
+const closeDialog = () => {
+	emits('handleQuery');
+	state.isShowDialog = false;
+};
+
+// 取消
+const cancel = () => {
+	state.isShowDialog = false;
+};
+
+// 提交
+const submit = () => {
+	ruleFormRef.value.validate(async (valid: boolean) => {
+		if (!valid) return;
+		if (state.ruleForm.id != undefined && state.ruleForm.id > 0) {
+			await getAPI(SysMenuApi).apiSysMenuUpdatePost(state.ruleForm);
+		} else {
+			await getAPI(SysMenuApi).apiSysMenuAddPost(state.ruleForm);
+		}
+		closeDialog();
+	});
+};
+
+// 导出对象
+defineExpose({ openDialog });
+</script>

+ 131 - 0
Web/src/views/system/plugin/index.vue

@@ -0,0 +1,131 @@
+<template>
+	<div class="sys-plugin-container">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
+				<el-form-item label="菜单名称" prop="title">
+					<el-input placeholder="菜单名称" clearable @keyup.enter="handleQuery" v-model="state.queryParams.title" />
+				</el-form-item>
+				<el-form-item label="类型" prop="type">
+					<el-select v-model="state.queryParams.type" placeholder="类型" clearable>
+						<el-option label="目录" :value="1" />
+						<el-option label="菜单" :value="2" />
+						<el-option label="按钮" :value="3" />
+					</el-select>
+				</el-form-item>
+				<el-form-item>
+					<el-button-group>
+						<el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'sysMenu:list'"> 查询 </el-button>
+						<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
+					</el-button-group>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" icon="ele-Plus" @click="openAddMenu" v-auth="'sysMenu:add'"> 新增 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+
+		<el-card class="full-table" shadow="hover" style="margin-top: 8px">
+			<el-table :data="state.menuData" v-loading="state.loading" row-key="id" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" border>
+				<el-table-column label="菜单名称" show-overflow-tooltip>
+					<template #default="scope">
+						<SvgIcon :name="scope.row.icon" />
+						<span class="ml10">{{ $t(scope.row.title) }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column label="类型" width="70" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag type="warning" v-if="scope.row.type === 1">目录</el-tag>
+						<el-tag v-else-if="scope.row.type === 2">菜单</el-tag>
+						<el-tag type="info" v-else>按钮</el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="path" label="路由路径" show-overflow-tooltip />
+				<el-table-column prop="component" label="组件路径" show-overflow-tooltip />
+				<el-table-column prop="permission" label="权限标识" show-overflow-tooltip />
+				<el-table-column prop="orderNo" label="排序" width="70" align="center" show-overflow-tooltip />
+				<el-table-column label="状态" width="80" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag type="success" v-if="scope.row.status === 1">启用</el-tag>
+						<el-tag type="danger" v-else>禁用</el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="createTime" label="修改时间" align="center" show-overflow-tooltip />
+				<el-table-column label="操作" width="140" fixed="right" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditMenu(scope.row)" v-auth="'sysMenu:update'"> 编辑 </el-button>
+						<el-button icon="ele-Delete" size="small" text type="danger" @click="delMenu(scope.row)" v-auth="'sysMenu:delete'"> 删除 </el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+		</el-card>
+
+		<EditMenu ref="editMenuRef" :title="state.editMenuTitle" :menuData="state.menuData" @handleQuery="handleQuery" />
+	</div>
+</template>
+
+<script lang="ts" setup name="sysPlugin">
+import { onMounted, reactive, ref } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import EditMenu from '/@/views/system/menu/component/editMenu.vue';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysMenuApi } from '/@/api-services/api';
+import { SysMenu } from '/@/api-services/models';
+
+const editMenuRef = ref<InstanceType<typeof EditMenu>>();
+const state = reactive({
+	loading: false,
+	menuData: [] as Array<SysMenu>,
+	queryParams: {
+		title: undefined,
+		type: undefined,
+	},
+	editMenuTitle: '',
+});
+
+onMounted(async () => {
+	handleQuery();
+});
+
+// 查询操作
+const handleQuery = async () => {
+	state.loading = true;
+	var res = await getAPI(SysMenuApi).apiSysMenuListGet(state.queryParams.title, state.queryParams.type);
+	state.menuData = res.data.result ?? [];
+	state.loading = false;
+};
+
+// 重置操作
+const resetQuery = () => {
+	state.queryParams.title = undefined;
+	state.queryParams.type = undefined;
+	handleQuery();
+};
+
+// 打开新增页面
+const openAddMenu = () => {
+	state.editMenuTitle = '添加菜单';
+	editMenuRef.value?.openDialog({ type: 2 });
+};
+
+// 打开编辑页面
+const openEditMenu = (row: any) => {
+	state.editMenuTitle = '编辑菜单';
+	editMenuRef.value?.openDialog(row);
+};
+
+// 删除当前行
+const delMenu = (row: any) => {
+	ElMessageBox.confirm(`确定删除菜单:【${row.title}】?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	})
+		.then(async () => {
+			await getAPI(SysMenuApi).apiSysMenuDeletePost({ id: row.id });
+			handleQuery();
+			ElMessage.success('删除成功');
+		})
+		.catch(() => {});
+};
+</script>

+ 154 - 0
Web/src/views/system/print/component/editPrint.vue

@@ -0,0 +1,154 @@
+<template>
+	<div class="sys-print-container">
+		<div class="printDialog">
+			<el-dialog v-model="state.isShowDialog" :show-close="false" :close-on-click-modal="false" fullscreen>
+				<Designer @onDesigned="onDesigned" style="margin: -20px -12px 0 -20px" />
+				<template #footer>
+					<span class="dialog-footer">
+						<el-button @click="cancel">取 消</el-button>
+						<el-button type="primary" @click="submit">保存模板</el-button>
+					</span>
+				</template>
+			</el-dialog>
+		</div>
+
+		<el-dialog v-model="state.showDialog2" draggable :close-on-click-modal="false" width="600px">
+			<template #header>
+				<div style="color: #fff">
+					<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
+					<span>{{ props.title }}</span>
+				</div>
+			</template>
+			<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="80px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="模板名称" prop="name" :rules="[{ required: true, message: '模板名称不能为空', trigger: 'blur' }]">
+							<el-input v-model="state.ruleForm.name" placeholder="模板名称" clearable />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="排序">
+							<el-input-number v-model="state.ruleForm.orderNo" placeholder="排序" class="w100" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="状态">
+							<el-radio-group v-model="state.ruleForm.status">
+								<el-radio :label="1">启用</el-radio>
+								<el-radio :label="2">禁用</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="备注">
+							<el-input v-model="state.ruleForm.remark" placeholder="请输入备注内容" clearable type="textarea" />
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel2">取 消</el-button>
+					<el-button type="primary" @click="submit2">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysEditPrint">
+import { reactive, ref } from 'vue';
+import 'sv-print/dist/style.css';
+import { Designer } from '@sv-print/vue3';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysPrintApi } from '/@/api-services/api';
+import { SysPrint, UpdatePrintInput } from '/@/api-services/models';
+
+const props = defineProps({
+	title: String,
+	printData: Array<SysPrint>,
+});
+const emits = defineEmits(['handleQuery']);
+let svPrint = ref();
+const ruleFormRef = ref();
+const state = reactive({
+	isShowDialog: false,
+	ruleForm: {} as UpdatePrintInput,
+	showDialog2: false,
+});
+
+// 打开弹窗
+const openDialog = (row: any) => {
+	state.ruleForm = JSON.parse(JSON.stringify(row));
+	state.isShowDialog = true;
+
+	if (svPrint.value != undefined) loadTemplate();
+};
+
+// 取消
+const cancel = () => {
+	state.isShowDialog = false;
+};
+
+// 提交
+const submit = async () => {
+	state.showDialog2 = true;
+	if (state.ruleForm.orderNo == undefined) state.ruleForm.orderNo = 100;
+	if (state.ruleForm.status == undefined) state.ruleForm.status = 1;
+};
+
+// 打印模板页面初始化
+const onDesigned = (e: any) => {
+	svPrint.value = e.detail;
+	console.log(e);
+
+	loadTemplate();
+};
+
+// 加载已有模板
+const loadTemplate = () => {
+	svPrint.value.printTemplate.clear();
+	if (JSON.stringify(state.ruleForm) !== '{}') {
+		// svPrint.value.designerUtils.options.authKey = "123456";
+		svPrint.value.designerUtils.options.autoConnect = false;
+		svPrint.value.designerUtils.options.theme = 'bumblebee';
+		svPrint.value.designerUtils.options.title = state.ruleForm.name;
+		svPrint.value.printTemplate.update(JSON.parse(state.ruleForm.template));
+	}
+};
+
+// 取消
+const cancel2 = () => {
+	state.showDialog2 = false;
+};
+
+// 提交
+const submit2 = async () => {
+	state.ruleForm.template = JSON.stringify(svPrint.value.printTemplate.getJson());
+	if (state.ruleForm.id != undefined && state.ruleForm.id > 0) {
+		await getAPI(SysPrintApi).apiSysPrintUpdatePost(state.ruleForm);
+	} else {
+		await getAPI(SysPrintApi).apiSysPrintAddPost(state.ruleForm);
+	}
+	cancel();
+	cancel2();
+	emits('handleQuery');
+};
+
+// 导出对象
+defineExpose({ openDialog });
+</script>
+
+<style lang="scss" scoped>
+.printDialog {
+	:deep(.el-dialog) {
+		.el-dialog__header {
+			display: none !important;
+		}
+		.el-dialog__body {
+			max-height: calc(100vh - 50px) !important;
+		}
+	}
+}
+</style>

+ 140 - 0
Web/src/views/system/print/index.vue

@@ -0,0 +1,140 @@
+<template>
+	<div class="sys-print-container">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
+				<el-form-item label="模板名称" prop="name">
+					<el-input placeholder="模板名称" clearable @keyup.enter="handleQuery" v-model="state.queryParams.name" />
+				</el-form-item>
+				<el-form-item>
+					<el-button-group>
+						<el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'sysPrint:page'"> 查询 </el-button>
+						<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
+					</el-button-group>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" icon="ele-Plus" @click="openAddPrint" v-auth="'sysPrint:add'"> 新增 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+
+		<el-card class="full-table" shadow="hover" style="margin-top: 8px">
+			<el-table :data="state.printData" style="width: 100%" v-loading="state.loading" border>
+				<el-table-column type="index" label="序号" width="55" align="center" fixed />
+				<el-table-column prop="name" label="名称" header-align="center" show-overflow-tooltip />
+				<!-- <el-table-column prop="template" label="模板" show-overflow-tooltip /> -->
+				<el-table-column prop="orderNo" label="排序" align="center" show-overflow-tooltip />
+				<el-table-column label="状态" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag type="success" v-if="scope.row.status === 1">启用</el-tag>
+						<el-tag type="danger" v-else>禁用</el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="createTime" label="修改时间" align="center" show-overflow-tooltip />
+				<el-table-column prop="remark" label="备注" header-align="center" show-overflow-tooltip />
+				<el-table-column label="操作" width="140" fixed="right" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditPrint(scope.row)" v-auth="'sysPrint:update'"> 编辑 </el-button>
+						<el-button icon="ele-Delete" size="small" text type="danger" @click="delPrint(scope.row)" v-auth="'sysPrint:delete'"> 删除 </el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<el-pagination
+				v-model:currentPage="state.tableParams.page"
+				v-model:page-size="state.tableParams.pageSize"
+				:total="state.tableParams.total"
+				:page-sizes="[10, 20, 50, 100]"
+				small
+				background
+				@size-change="handleSizeChange"
+				@current-change="handleCurrentChange"
+				layout="total, sizes, prev, pager, next, jumper"
+			/>
+		</el-card>
+
+		<EditPrint ref="editPrintRef" :title="state.editPrintTitle" @handleQuery="handleQuery" />
+	</div>
+</template>
+
+<script lang="ts" setup name="sysPrint">
+import { onMounted, reactive, ref } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import EditPrint from '/@/views/system/print/component/editPrint.vue';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysPrintApi } from '/@/api-services/api';
+import { SysPrint } from '/@/api-services/models';
+
+const editPrintRef = ref<InstanceType<typeof EditPrint>>();
+const state = reactive({
+	loading: false,
+	printData: [] as Array<SysPrint>,
+	queryParams: {
+		name: undefined,
+	},
+	tableParams: {
+		page: 1,
+		pageSize: 10,
+		total: 0 as any,
+	},
+	editPrintTitle: '',
+});
+
+onMounted(async () => {
+	handleQuery();
+});
+
+// 查询操作
+const handleQuery = async () => {
+	state.loading = true;
+	let params = Object.assign(state.queryParams, state.tableParams);
+	var res = await getAPI(SysPrintApi).apiSysPrintPagePost(params);
+	state.printData = res.data.result?.items ?? [];
+	state.tableParams.total = res.data.result?.total;
+	state.loading = false;
+};
+
+// 重置操作
+const resetQuery = () => {
+	state.queryParams.name = undefined;
+	handleQuery();
+};
+
+// 打开新增页面
+const openAddPrint = () => {
+	state.editPrintTitle = '添加打印模板';
+	editPrintRef.value?.openDialog({});
+};
+
+// 打开编辑页面
+const openEditPrint = (row: any) => {
+	state.editPrintTitle = '编辑打印模板';
+	editPrintRef.value?.openDialog(row);
+};
+
+// 删除当前行
+const delPrint = (row: any) => {
+	ElMessageBox.confirm(`确定删除打印模板:【${row.name}】?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	})
+		.then(async () => {
+			await getAPI(SysPrintApi).apiSysPrintDeletePost({ id: row.id });
+			handleQuery();
+			ElMessage.success('删除成功');
+		})
+		.catch(() => {});
+};
+
+// 改变页面容量
+const handleSizeChange = (val: number) => {
+	state.tableParams.pageSize = val;
+	handleQuery();
+};
+
+// 改变页码序号
+const handleCurrentChange = (val: number) => {
+	state.tableParams.page = val;
+	handleQuery();
+};
+</script>

+ 2 - 2
Web/src/views/system/user/component/userCenter.vue

@@ -168,7 +168,7 @@ import { useUserInfo } from '/@/stores/userInfo';
 import { base64ToFile } from '/@/utils/base64Conver';
 import OrgTree from '/@/views/system/user/component/orgTree.vue';
 import CropperDialog from '/@/components/cropper/index.vue';
-import VueSignaturePad from 'vue-signature-pad';
+import VueGridLayout from 'vue-grid-layout';
 
 import { clearAccessTokens, getAPI } from '/@/utils/axios-utils';
 import { SysFileApi, SysUserApi } from '/@/api-services/api';
@@ -178,7 +178,7 @@ const stores = useUserInfo();
 const { userInfos } = storeToRefs(stores);
 const uploadSignRef = ref<UploadInstance>();
 //const uploadAvatarRef = ref<UploadInstance>();
-const signaturePadRef = ref<InstanceType<typeof VueSignaturePad>>();
+const signaturePadRef = ref<InstanceType<typeof VueGridLayout>>();
 const ruleFormBaseRef = ref<InstanceType<typeof ElForm>>();
 const ruleFormPasswordRef = ref<InstanceType<typeof ElForm>>();
 const cropperDialogRef = ref<InstanceType<typeof CropperDialog>>();

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels