Explorar o código

feat: 🤖新增模板管理模块

喵你个旺呀 hai 1 ano
pai
achega
6b79b54da5
Modificáronse 29 ficheiros con 2973 adicións e 1 borrados
  1. 57 0
      Admin.NET/Admin.NET.Core/Entity/SysTemplate.cs
  2. 12 0
      Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
  3. 7 0
      Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs
  4. 103 0
      Admin.NET/Admin.NET.Core/Service/Template/Dto/SysTemplateInput.cs
  5. 12 0
      Admin.NET/Admin.NET.Core/Service/Template/Dto/SysTemplateOutput.cs
  6. 178 0
      Admin.NET/Admin.NET.Core/Service/Template/SysTemplateService.cs
  7. 1 1
      Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs
  8. 2 0
      Web/src/api-services/api.ts
  9. 388 0
      Web/src/api-services/apis/alipay-api.ts
  10. 720 0
      Web/src/api-services/apis/sys-template-api.ts
  11. 110 0
      Web/src/api-services/models/add-template-input.ts
  12. 57 0
      Web/src/api-services/models/admin-result-sql-sugar-paged-list-sys-template.ts
  13. 57 0
      Web/src/api-services/models/admin-result-sys-template.ts
  14. 44 0
      Web/src/api-services/models/alipay-pre-create-input.ts
  15. 83 0
      Web/src/api-services/models/alipay-trade-page-pay-input.ts
  16. 68 0
      Web/src/api-services/models/ext-user-info.ts
  17. 80 0
      Web/src/api-services/models/extend-params.ts
  18. 15 0
      Web/src/api-services/models/index.ts
  19. 33 0
      Web/src/api-services/models/invoice-info.ts
  20. 38 0
      Web/src/api-services/models/invoice-key-info.ts
  21. 94 0
      Web/src/api-services/models/page-template-input.ts
  22. 32 0
      Web/src/api-services/models/pro-view-template-input.ts
  23. 32 0
      Web/src/api-services/models/render-template-input.ts
  24. 63 0
      Web/src/api-services/models/sql-sugar-paged-list-sys-template.ts
  25. 110 0
      Web/src/api-services/models/sys-template.ts
  26. 110 0
      Web/src/api-services/models/update-template-input.ts
  27. 168 0
      Web/src/views/system/template/component/editTemplate.vue
  28. 141 0
      Web/src/views/system/template/component/previewDialog.vue
  29. 158 0
      Web/src/views/system/template/index.vue

+ 57 - 0
Admin.NET/Admin.NET.Core/Entity/SysTemplate.cs

@@ -0,0 +1,57 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 系统模板表
+/// </summary>
+[SysTable]
+[SugarTable(null, "系统模板表")]
+[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc, IsUnique = true)]
+[SugarIndex("index_{table}_G", nameof(GroupName), OrderByType.Asc)]
+public partial class SysTemplate : EntityTenant
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    [MaxLength(128)]
+    [SugarColumn(ColumnDescription = "名称", Length = 128)]
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 编码
+    /// </summary>
+    [MaxLength(128)]
+    [SugarColumn(ColumnDescription = "编码", Length = 128)]
+    public string Code { get; set; }
+
+    /// <summary>
+    /// 分组名称
+    /// </summary>
+    [MaxLength(32)]
+    [SugarColumn(ColumnDescription = "分组名称", Length = 32)]
+    public string GroupName { get; set; }
+
+    /// <summary>
+    /// 模板内容
+    /// </summary>
+    [SugarColumn(ColumnDescription = "模板内容", ColumnDataType = StaticConfig.CodeFirst_BigString)]
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    [MaxLength(128)]
+    [SugarColumn(ColumnDescription = "备注", Length = 128)]
+    public virtual string? Remark { get; set; }
+
+    /// <summary>
+    /// 排序
+    /// </summary>
+    [SugarColumn(ColumnDescription = "排序")]
+    public virtual int OrderNo { get; set; } = 100;
+}

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

@@ -721,6 +721,18 @@ public enum ErrorCodeEnum
     [ErrorCodeItemMetadata("注册方案名称已存在")]
     D2101,
 
+    /// <summary>
+    /// 已存在同名模板
+    /// </summary>
+    [ErrorCodeItemMetadata("已存在同名模板")]
+    T1000,
+
+    /// <summary>
+    /// 已存在相同编码模板
+    /// </summary>
+    [ErrorCodeItemMetadata("已存在相同编码模板")]
+    T1001,
+
     /// <summary>
     /// 禁止删除存在关联租户的应用
     /// </summary>

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

@@ -131,6 +131,13 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
             new SysMenu{ Id=1300300050801, Pid=1300300050101, Title="编辑字典值", Permission="sysDictData:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1300300050901, Pid=1300300050101, Title="字典迁移", Permission="sysDictType:move", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
 
+            new SysMenu{ Id=1300300051101, Pid=1300300000101, Title="模板管理", Path="/platform/template", Name="sysTemplate", Component="/system/template/index", Icon="ele-Collection", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=135 },
+            new SysMenu{ Id=1300300051201, Pid=1300300051101, Title="查询", Permission="sysTemplate:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1300300051301, Pid=1300300051101, Title="编辑", Permission="sysTemplate:update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1300300051401, Pid=1300300051101, Title="增加", Permission="sysTemplate:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1300300051501, Pid=1300300051101, Title="删除", Permission="sysTemplate:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+            new SysMenu{ Id=1300300051601, Pid=1300300051101, Title="预览", Permission="sysTemplate:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
+
             new SysMenu{ Id=1300300060101, Pid=1300300000101, Title="任务调度", Path="/platform/job", Name="sysJob", Component="/system/job/index", Icon="ele-AlarmClock", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
             new SysMenu{ Id=1300300060201, Pid=1300300060101, Title="查询", Permission="sysJob:pageJobDetail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
             new SysMenu{ Id=1300300060301, Pid=1300300060101, Title="编辑", Permission="sysJob:updateJobDetail", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },

+ 103 - 0
Admin.NET/Admin.NET.Core/Service/Template/Dto/SysTemplateInput.cs

@@ -0,0 +1,103 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+// 
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+// 
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core.Service;
+
+public class PageTemplateInput : BasePageInput
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 编码
+    /// </summary>
+    public string Code { get; set; }
+
+    /// <summary>
+    /// 分组名称
+    /// </summary>
+    public string GroupName { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    public long TenantId { get; set; }
+}
+
+/// <summary>
+/// 新增模板输入参数
+/// </summary>
+public class AddTemplateInput : SysTemplate
+{
+    /// <summary>
+    /// 名称
+    /// </summary>
+    [Required(ErrorMessage = "名称不能为空")]
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 编码
+    /// </summary>
+    [Required(ErrorMessage = "编码不能为空")]
+    public string Code { get; set; }
+
+    /// <summary>
+    /// 分组名称
+    /// </summary>
+    [Required(ErrorMessage = "分组名称不能为空")]
+    public string GroupName { get; set; }
+
+    /// <summary>
+    /// 模板内容
+    /// </summary>
+    [Required(ErrorMessage = "内容名称不能为空")]
+    public string Content { get; set; }
+}
+
+/// <summary>
+/// 更新模板输入参数
+/// </summary>
+public class UpdateTemplateInput : AddTemplateInput
+{
+    /// <summary>
+    /// 主键Id
+    /// </summary>
+    [Required(ErrorMessage = "Id不能为空")]
+    [DataValidation(ValidationTypes.Numeric)]
+    public virtual long Id { get; set; }
+}
+
+/// <summary>
+/// 预览模板输入参数
+/// </summary>
+public class ProViewTemplateInput : BaseIdInput
+{
+    /// <summary>
+    /// 渲染参数
+    /// </summary>
+    [Required(ErrorMessage = "渲染参数不能为空")]
+    public object Data { get; set; }
+}
+
+/// <summary>
+/// 模板渲染输入参数
+/// </summary>
+public class RenderTemplateInput
+{
+    /// <summary>
+    /// 模板内容
+    /// </summary>
+    [Required(ErrorMessage = "内容名称不能为空")]
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 渲染参数
+    /// </summary>
+    [Required(ErrorMessage = "渲染参数不能为空")]
+    public object Data { get; set; }
+}

+ 12 - 0
Admin.NET/Admin.NET.Core/Service/Template/Dto/SysTemplateOutput.cs

@@ -0,0 +1,12 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core.Service;
+
+public class SysTemplateOutput
+{
+
+}

+ 178 - 0
Admin.NET/Admin.NET.Core/Service/Template/SysTemplateService.cs

@@ -0,0 +1,178 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core.Service;
+
+/// <summary>
+/// 系统模板服务 🧩
+/// </summary>
+[ApiDescriptionSettings(Order = 305)]
+public class SysTemplateService : IDynamicApiController, ITransient
+{
+    private readonly SqlSugarRepository<SysTemplate> _sysTemplateRep;
+    private readonly UserManager _userManager;
+    private readonly IViewEngine _viewEngine;
+
+    public SysTemplateService(
+        SqlSugarRepository<SysTemplate> sysTemplateRep,
+        IViewEngine viewEngine,
+        UserManager userManager)
+    {
+        _sysTemplateRep = sysTemplateRep;
+        _userManager = userManager;
+        _viewEngine = viewEngine;
+    }
+
+    /// <summary>
+    /// 获取模板列表 📑
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [ApiDescriptionSettings]
+    [DisplayName("获取模板列表")]
+    public async Task<SqlSugarPagedList<SysTemplate>> Page(PageTemplateInput input)
+    {
+        return await _sysTemplateRep.AsQueryable()
+            .WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), u => u.GroupName.Contains(input.GroupName))
+            .WhereIF(_userManager.SuperAdmin && input.TenantId > 0, u => u.TenantId == input.TenantId)
+            .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
+            .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code))
+            .OrderBy(u => new { u.OrderNo, u.Id })
+            .ToPagedListAsync(input.Page, input.PageSize);
+    }
+
+    /// <summary>
+    /// 获取模板 📑
+    /// </summary>
+    /// <param name="code"></param>
+    /// <returns></returns>
+    [DisplayName("获取模板")]
+    [ApiDescriptionSettings]
+    public async Task<SysTemplate> GetTemplate(string code)
+    {
+        return await _sysTemplateRep.GetFirstAsync(u => u.Name == code);
+    }
+
+    /// <summary>
+    /// 预览模板内容 📑
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("预览模板内容")]
+    [ApiDescriptionSettings]
+    public async Task<string> ProView(ProViewTemplateInput input)
+    {
+        var template = await _sysTemplateRep.GetFirstAsync(u => u.Id == input.Id);
+        return await RenderAsync(template.Content, input.Data);
+    }
+
+    /// <summary>
+    /// 增加模板 📑
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("增加模板")]
+    [ApiDescriptionSettings(Name = "Add"), HttpPost]
+    public async Task AddTemplate(AddTemplateInput input)
+    {
+        var isExist = await _sysTemplateRep.IsAnyAsync(u => u.Name == input.Name);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.T1000);
+
+        isExist = await _sysTemplateRep.IsAnyAsync(u => u.Code == input.Code);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.T1001);
+
+        await _sysTemplateRep.InsertAsync(input.Adapt<SysTemplate>());
+    }
+
+    /// <summary>
+    /// 更新模板 📑
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("更新模板")]
+    [ApiDescriptionSettings(Name = "Update"), HttpPost]
+    public async Task UpdateTemplate(UpdateTemplateInput input)
+    {
+        var isExist = await _sysTemplateRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.T1000);
+
+        isExist = await _sysTemplateRep.IsAnyAsync(u => u.Code == input.Code && u.Id != input.Id);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.T1001);
+
+        await _sysTemplateRep.AsUpdateable(input.Adapt<SysTemplate>()).IgnoreColumns(true).ExecuteCommandAsync();
+    }
+
+    /// <summary>
+    /// 删除模板 📑
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("删除模板")]
+    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
+    public async Task DeleteTemplate(BaseIdInput input)
+    {
+        await _sysTemplateRep.DeleteAsync(u => u.Id == input.Id);
+    }
+
+    /// <summary>
+    /// 获取分组列表 🔖
+    /// </summary>
+    /// <returns></returns>
+    [ApiDescriptionSettings]
+    [DisplayName("获取分组列表")]
+    public async Task<List<string>> GetGroupList()
+    {
+        return await _sysTemplateRep.AsQueryable()
+            .GroupBy(u => u.GroupName)
+            .Select(u => u.GroupName).ToListAsync();
+    }
+
+    /// <summary>
+    /// 渲染模板内容 📑
+    /// </summary>
+    /// <param name="input"></param>
+    /// <returns></returns>
+    [DisplayName("渲染模板内容")]
+    [ApiDescriptionSettings, HttpPost]
+    public async Task<string> Render(RenderTemplateInput input)
+    {
+        return await RenderAsync(input.Content, input.Data);
+    }
+
+    /// <summary>
+    /// 渲染模板内容 📑
+    /// </summary>
+    /// <param name="content"></param>
+    /// <param name="data"></param>
+    /// <returns></returns>
+    [NonAction]
+    public async Task<string> RenderAsync(string content, object data)
+    {
+        return await _viewEngine.RunCompileFromCachedAsync(Regex.Replace(content, "@\\((.*?)\\)", "@(Model.$1)"), data, builderAction: builder =>
+        {
+            builder.AddAssemblyReferenceByName("System.Text.RegularExpressions");
+            builder.AddAssemblyReferenceByName("System.Collections");
+            builder.AddAssemblyReferenceByName("System.Linq");
+
+            builder.AddUsing("System.Text.RegularExpressions");
+            builder.AddUsing("System.Collections.Generic");
+            builder.AddUsing("System.Linq");
+        });
+    }
+
+    /// <summary>
+    /// 根据编码渲染模板内容
+    /// </summary>
+    /// <param name="code"></param>
+    /// <param name="data"></param>
+    /// <returns></returns>
+    [NonAction]
+    public async Task<string> RenderByCode(string code, Dictionary<string, object> data)
+    {
+        var template = await _sysTemplateRep.GetFirstAsync(u => u.Code == code);
+        return await RenderAsync(template.Content, data);
+    }
+}

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs

@@ -325,7 +325,7 @@ public class SysTenantService : IDynamicApiController, ITransient
 
         var platformMenu = allMenuList.First(u => u.Type == MenuTypeEnum.Dir && u.Title == "平台管理");
         menuList.Add(platformMenu);
-        menuList.AddRange(allMenuList.ToChildList(u => u.Id, u => u.Pid, u => u.Pid == platformMenu.Id && new[] { "菜单管理", "字典管理", "系统配置" }.Contains(u.Title)));
+        menuList.AddRange(allMenuList.ToChildList(u => u.Id, u => u.Pid, u => u.Pid == platformMenu.Id && new[] { "菜单管理", "字典管理", "模板管理", "系统配置" }.Contains(u.Title)));
         var dictMenu = menuList.First(u => u.Type == MenuTypeEnum.Menu && u.Title == "字典管理");
         menuList = menuList.Where(u => u.Pid != dictMenu.Id || !new[] { "编辑", "删除" }.Contains(u.Title)).ToList();
 

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

@@ -11,6 +11,7 @@
  * https://github.com/swagger-api/swagger-codegen.git
  * Do not edit the class manually.
  */export * from './apis/apijsonapi';
+export * from './apis/alipay-api';
 export * from './apis/sys-auth-api';
 export * from './apis/sys-cache-api';
 export * from './apis/sys-code-gen-api';
@@ -46,6 +47,7 @@ export * from './apis/sys-role-api';
 export * from './apis/sys-schedule-api';
 export * from './apis/sys-server-api';
 export * from './apis/sys-sms-api';
+export * from './apis/sys-template-api';
 export * from './apis/sys-tenant-api';
 export * from './apis/sys-update-api';
 export * from './apis/sys-user-api';

+ 388 - 0
Web/src/api-services/apis/alipay-api.ts

@@ -0,0 +1,388 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+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 { AdminResultString } from '../models';
+import { AlipayPreCreateInput } from '../models';
+import { AlipayTradePagePayInput } from '../models';
+/**
+ * AlipayApi - axios parameter creator
+ * @export
+ */
+export const AlipayApiAxiosParamCreator = function (configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 交易预创建
+         * @param {AlipayPreCreateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiAlipayAlipayPreCreatePost: async (body?: AlipayPreCreateInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/alipay/alipayPreCreate`;
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 统一收单下单并支付页面接口
+         * @param {AlipayTradePagePayInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiAlipayAlipayTradePagePayPost: async (body?: AlipayTradePagePayInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/alipay/alipayTradePagePay`;
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 获取授权信息
+         * @param {string} [userId] 用户Id
+         * @param {string} [authCode] 授权码
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiAlipayGetAuthInfoGet: async (userId?: string, authCode?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/alipay/getAuthInfo`;
+            // 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: 'GET', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            if (userId !== undefined) {
+                localVarQueryParameter['UserId'] = userId;
+            }
+
+            if (authCode !== undefined) {
+                localVarQueryParameter['AuthCode'] = authCode;
+            }
+
+            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 {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiAlipayNotifyPost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/alipay/notify`;
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            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,
+            };
+        },
+    }
+};
+
+/**
+ * AlipayApi - functional programming interface
+ * @export
+ */
+export const AlipayApiFp = function(configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 交易预创建
+         * @param {AlipayPreCreateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayAlipayPreCreatePost(body?: AlipayPreCreateInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultString>>> {
+            const localVarAxiosArgs = await AlipayApiAxiosParamCreator(configuration).apiAlipayAlipayPreCreatePost(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 {AlipayTradePagePayInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayAlipayTradePagePayPost(body?: AlipayTradePagePayInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultString>>> {
+            const localVarAxiosArgs = await AlipayApiAxiosParamCreator(configuration).apiAlipayAlipayTradePagePayPost(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} [userId] 用户Id
+         * @param {string} [authCode] 授权码
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayGetAuthInfoGet(userId?: string, authCode?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await AlipayApiAxiosParamCreator(configuration).apiAlipayGetAuthInfoGet(userId, authCode, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 支付回调
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayNotifyPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultString>>> {
+            const localVarAxiosArgs = await AlipayApiAxiosParamCreator(configuration).apiAlipayNotifyPost(options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+    }
+};
+
+/**
+ * AlipayApi - factory interface
+ * @export
+ */
+export const AlipayApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
+    return {
+        /**
+         * 
+         * @summary 交易预创建
+         * @param {AlipayPreCreateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayAlipayPreCreatePost(body?: AlipayPreCreateInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
+            return AlipayApiFp(configuration).apiAlipayAlipayPreCreatePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 统一收单下单并支付页面接口
+         * @param {AlipayTradePagePayInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayAlipayTradePagePayPost(body?: AlipayTradePagePayInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
+            return AlipayApiFp(configuration).apiAlipayAlipayTradePagePayPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取授权信息
+         * @param {string} [userId] 用户Id
+         * @param {string} [authCode] 授权码
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayGetAuthInfoGet(userId?: string, authCode?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return AlipayApiFp(configuration).apiAlipayGetAuthInfoGet(userId, authCode, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 支付回调
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiAlipayNotifyPost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
+            return AlipayApiFp(configuration).apiAlipayNotifyPost(options).then((request) => request(axios, basePath));
+        },
+    };
+};
+
+/**
+ * AlipayApi - object-oriented interface
+ * @export
+ * @class AlipayApi
+ * @extends {BaseAPI}
+ */
+export class AlipayApi extends BaseAPI {
+    /**
+     * 
+     * @summary 交易预创建
+     * @param {AlipayPreCreateInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof AlipayApi
+     */
+    public async apiAlipayAlipayPreCreatePost(body?: AlipayPreCreateInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
+        return AlipayApiFp(this.configuration).apiAlipayAlipayPreCreatePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 统一收单下单并支付页面接口
+     * @param {AlipayTradePagePayInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof AlipayApi
+     */
+    public async apiAlipayAlipayTradePagePayPost(body?: AlipayTradePagePayInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
+        return AlipayApiFp(this.configuration).apiAlipayAlipayTradePagePayPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取授权信息
+     * @param {string} [userId] 用户Id
+     * @param {string} [authCode] 授权码
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof AlipayApi
+     */
+    public async apiAlipayGetAuthInfoGet(userId?: string, authCode?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return AlipayApiFp(this.configuration).apiAlipayGetAuthInfoGet(userId, authCode, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 支付回调
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof AlipayApi
+     */
+    public async apiAlipayNotifyPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
+        return AlipayApiFp(this.configuration).apiAlipayNotifyPost(options).then((request) => request(this.axios, this.basePath));
+    }
+}

+ 720 - 0
Web/src/api-services/apis/sys-template-api.ts

@@ -0,0 +1,720 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+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 { AddTemplateInput } from '../models';
+import { AdminResultListString } from '../models';
+import { AdminResultSqlSugarPagedListSysTemplate } from '../models';
+import { AdminResultString } from '../models';
+import { AdminResultSysTemplate } from '../models';
+import { BaseIdInput } from '../models';
+import { PageTemplateInput } from '../models';
+import { ProViewTemplateInput } from '../models';
+import { RenderTemplateInput } from '../models';
+import { UpdateTemplateInput } from '../models';
+/**
+ * SysTemplateApi - axios parameter creator
+ * @export
+ */
+export const SysTemplateApiAxiosParamCreator = function (configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 增加模板 📑
+         * @param {AddTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateAddPost: async (body?: AddTemplateInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/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
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 删除模板 📑
+         * @param {BaseIdInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateDeletePost: async (body?: BaseIdInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/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
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 获取分组列表 🔖
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateGroupListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/groupList`;
+            // 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: 'GET', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            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 {PageTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplatePagePost: async (body?: PageTemplateInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/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
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 预览模板内容 📑
+         * @param {ProViewTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateProViewPost: async (body?: ProViewTemplateInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/proView`;
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 渲染模板内容 📑
+         * @param {RenderTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateRenderPost: async (body?: RenderTemplateInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/render`;
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * 
+         * @summary 获取模板 📑
+         * @param {string} code 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateTemplateCodeGet: async (code: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // verify required parameter 'code' is not null or undefined
+            if (code === null || code === undefined) {
+                throw new RequiredError('code','Required parameter code was null or undefined when calling apiSysTemplateTemplateCodeGet.');
+            }
+            const localVarPath = `/api/sysTemplate/template/{code}`
+                .replace(`{${"code"}}`, encodeURIComponent(String(code)));
+            // 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: 'GET', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            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 {UpdateTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysTemplateUpdatePost: async (body?: UpdateTemplateInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            const localVarPath = `/api/sysTemplate/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
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
+            localVarRequestOptions.data =  needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
+    }
+};
+
+/**
+ * SysTemplateApi - functional programming interface
+ * @export
+ */
+export const SysTemplateApiFp = function(configuration?: Configuration) {
+    return {
+        /**
+         * 
+         * @summary 增加模板 📑
+         * @param {AddTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateAddPost(body?: AddTemplateInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateAddPost(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 {BaseIdInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateDeletePost(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 {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateGroupListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultListString>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateGroupListGet(options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 获取模板列表 📑
+         * @param {PageTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplatePagePost(body?: PageTemplateInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSqlSugarPagedListSysTemplate>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplatePagePost(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 {ProViewTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateProViewPost(body?: ProViewTemplateInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultString>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateProViewPost(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 {RenderTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateRenderPost(body?: RenderTemplateInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultString>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateRenderPost(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} code 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateTemplateCodeGet(code: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSysTemplate>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateTemplateCodeGet(code, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+        /**
+         * 
+         * @summary 更新模板 📑
+         * @param {UpdateTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateUpdatePost(body?: UpdateTemplateInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysTemplateApiAxiosParamCreator(configuration).apiSysTemplateUpdatePost(body, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
+    }
+};
+
+/**
+ * SysTemplateApi - factory interface
+ * @export
+ */
+export const SysTemplateApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
+    return {
+        /**
+         * 
+         * @summary 增加模板 📑
+         * @param {AddTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateAddPost(body?: AddTemplateInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateAddPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 删除模板 📑
+         * @param {BaseIdInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateDeletePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取分组列表 🔖
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateGroupListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultListString>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateGroupListGet(options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取模板列表 📑
+         * @param {PageTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplatePagePost(body?: PageTemplateInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSqlSugarPagedListSysTemplate>> {
+            return SysTemplateApiFp(configuration).apiSysTemplatePagePost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 预览模板内容 📑
+         * @param {ProViewTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateProViewPost(body?: ProViewTemplateInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateProViewPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 渲染模板内容 📑
+         * @param {RenderTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateRenderPost(body?: RenderTemplateInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateRenderPost(body, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 获取模板 📑
+         * @param {string} code 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateTemplateCodeGet(code: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSysTemplate>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateTemplateCodeGet(code, options).then((request) => request(axios, basePath));
+        },
+        /**
+         * 
+         * @summary 更新模板 📑
+         * @param {UpdateTemplateInput} [body] 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysTemplateUpdatePost(body?: UpdateTemplateInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysTemplateApiFp(configuration).apiSysTemplateUpdatePost(body, options).then((request) => request(axios, basePath));
+        },
+    };
+};
+
+/**
+ * SysTemplateApi - object-oriented interface
+ * @export
+ * @class SysTemplateApi
+ * @extends {BaseAPI}
+ */
+export class SysTemplateApi extends BaseAPI {
+    /**
+     * 
+     * @summary 增加模板 📑
+     * @param {AddTemplateInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateAddPost(body?: AddTemplateInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateAddPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 删除模板 📑
+     * @param {BaseIdInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateDeletePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取分组列表 🔖
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateGroupListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultListString>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateGroupListGet(options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取模板列表 📑
+     * @param {PageTemplateInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplatePagePost(body?: PageTemplateInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSqlSugarPagedListSysTemplate>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplatePagePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 预览模板内容 📑
+     * @param {ProViewTemplateInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateProViewPost(body?: ProViewTemplateInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateProViewPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 渲染模板内容 📑
+     * @param {RenderTemplateInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateRenderPost(body?: RenderTemplateInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateRenderPost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 获取模板 📑
+     * @param {string} code 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateTemplateCodeGet(code: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSysTemplate>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateTemplateCodeGet(code, options).then((request) => request(this.axios, this.basePath));
+    }
+    /**
+     * 
+     * @summary 更新模板 📑
+     * @param {UpdateTemplateInput} [body] 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysTemplateApi
+     */
+    public async apiSysTemplateUpdatePost(body?: UpdateTemplateInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysTemplateApiFp(this.configuration).apiSysTemplateUpdatePost(body, options).then((request) => request(this.axios, this.basePath));
+    }
+}

+ 110 - 0
Web/src/api-services/models/add-template-input.ts

@@ -0,0 +1,110 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 新增模板输入参数
+ * @export
+ * @interface AddTemplateInput
+ */
+export interface AddTemplateInput {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof AddTemplateInput
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof AddTemplateInput
+     */
+    createTime?: Date;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof AddTemplateInput
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof AddTemplateInput
+     */
+    createUserId?: number | null;
+    /**
+     * 创建者姓名
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    createUserName?: string | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof AddTemplateInput
+     */
+    updateUserId?: number | null;
+    /**
+     * 修改者姓名
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    updateUserName?: string | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof AddTemplateInput
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof AddTemplateInput
+     */
+    tenantId?: number | null;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    remark?: string | null;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof AddTemplateInput
+     */
+    orderNo?: number;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    name: string;
+    /**
+     * 编码
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    code: string;
+    /**
+     * 分组名称
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    groupName: string;
+    /**
+     * 模板内容
+     * @type {string}
+     * @memberof AddTemplateInput
+     */
+    content: string;
+}

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

@@ -0,0 +1,57 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { SqlSugarPagedListSysTemplate } from './sql-sugar-paged-list-sys-template';
+/**
+ * 全局返回结果
+ * @export
+ * @interface AdminResultSqlSugarPagedListSysTemplate
+ */
+export interface AdminResultSqlSugarPagedListSysTemplate {
+    /**
+     * 状态码
+     * @type {number}
+     * @memberof AdminResultSqlSugarPagedListSysTemplate
+     */
+    code?: number;
+    /**
+     * 类型success、warning、error
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysTemplate
+     */
+    type?: string | null;
+    /**
+     * 错误信息
+     * @type {string}
+     * @memberof AdminResultSqlSugarPagedListSysTemplate
+     */
+    message?: string | null;
+    /**
+     * 
+     * @type {SqlSugarPagedListSysTemplate}
+     * @memberof AdminResultSqlSugarPagedListSysTemplate
+     */
+    result?: SqlSugarPagedListSysTemplate;
+    /**
+     * 附加数据
+     * @type {any}
+     * @memberof AdminResultSqlSugarPagedListSysTemplate
+     */
+    extras?: any | null;
+    /**
+     * 时间
+     * @type {Date}
+     * @memberof AdminResultSqlSugarPagedListSysTemplate
+     */
+    time?: Date;
+}

+ 57 - 0
Web/src/api-services/models/admin-result-sys-template.ts

@@ -0,0 +1,57 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { SysTemplate } from './sys-template';
+/**
+ * 全局返回结果
+ * @export
+ * @interface AdminResultSysTemplate
+ */
+export interface AdminResultSysTemplate {
+    /**
+     * 状态码
+     * @type {number}
+     * @memberof AdminResultSysTemplate
+     */
+    code?: number;
+    /**
+     * 类型success、warning、error
+     * @type {string}
+     * @memberof AdminResultSysTemplate
+     */
+    type?: string | null;
+    /**
+     * 错误信息
+     * @type {string}
+     * @memberof AdminResultSysTemplate
+     */
+    message?: string | null;
+    /**
+     * 
+     * @type {SysTemplate}
+     * @memberof AdminResultSysTemplate
+     */
+    result?: SysTemplate;
+    /**
+     * 附加数据
+     * @type {any}
+     * @memberof AdminResultSysTemplate
+     */
+    extras?: any | null;
+    /**
+     * 时间
+     * @type {Date}
+     * @memberof AdminResultSysTemplate
+     */
+    time?: Date;
+}

+ 44 - 0
Web/src/api-services/models/alipay-pre-create-input.ts

@@ -0,0 +1,44 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 
+ * @export
+ * @interface AlipayPreCreateInput
+ */
+export interface AlipayPreCreateInput {
+    /**
+     * 商户订单号
+     * @type {string}
+     * @memberof AlipayPreCreateInput
+     */
+    outTradeNo: string;
+    /**
+     * 订单总金额
+     * @type {string}
+     * @memberof AlipayPreCreateInput
+     */
+    totalAmount: string;
+    /**
+     * 订单标题
+     * @type {string}
+     * @memberof AlipayPreCreateInput
+     */
+    subject: string;
+    /**
+     * 超时时间
+     * @type {string}
+     * @memberof AlipayPreCreateInput
+     */
+    timeoutExpress?: string | null;
+}

+ 83 - 0
Web/src/api-services/models/alipay-trade-page-pay-input.ts

@@ -0,0 +1,83 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { ExtUserInfo } from './ext-user-info';
+import { ExtendParams } from './extend-params';
+import { InvoiceInfo } from './invoice-info';
+/**
+ * 统一收单下单并支付页面接口输入参数
+ * @export
+ * @interface AlipayTradePagePayInput
+ */
+export interface AlipayTradePagePayInput {
+    /**
+     * 商户订单号
+     * @type {string}
+     * @memberof AlipayTradePagePayInput
+     */
+    outTradeNo: string;
+    /**
+     * 订单总金额
+     * @type {string}
+     * @memberof AlipayTradePagePayInput
+     */
+    totalAmount: string;
+    /**
+     * 订单标题
+     * @type {string}
+     * @memberof AlipayTradePagePayInput
+     */
+    subject: string;
+    /**
+     * 
+     * @type {string}
+     * @memberof AlipayTradePagePayInput
+     */
+    body?: string | null;
+    /**
+     * 超时时间
+     * @type {string}
+     * @memberof AlipayTradePagePayInput
+     */
+    timeoutExpress?: string | null;
+    /**
+     * 二维码宽度
+     * @type {number}
+     * @memberof AlipayTradePagePayInput
+     */
+    qrcodeWidth: number;
+    /**
+     * 
+     * @type {ExtendParams}
+     * @memberof AlipayTradePagePayInput
+     */
+    extendParams?: ExtendParams;
+    /**
+     * 商户业务数据
+     * @type {{ [key: string]: any; }}
+     * @memberof AlipayTradePagePayInput
+     */
+    businessParams?: { [key: string]: any; } | null;
+    /**
+     * 
+     * @type {InvoiceInfo}
+     * @memberof AlipayTradePagePayInput
+     */
+    invoiceInfo?: InvoiceInfo;
+    /**
+     * 
+     * @type {ExtUserInfo}
+     * @memberof AlipayTradePagePayInput
+     */
+    extUserInfo?: ExtUserInfo;
+}

+ 68 - 0
Web/src/api-services/models/ext-user-info.ts

@@ -0,0 +1,68 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 
+ * @export
+ * @interface ExtUserInfo
+ */
+export interface ExtUserInfo {
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    certNo?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    certType?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    fixBuyer?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    identityHash?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    minAge?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    mobile?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    name?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtUserInfo
+     */
+    needCheckInfo?: string | null;
+}

+ 80 - 0
Web/src/api-services/models/extend-params.ts

@@ -0,0 +1,80 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 
+ * @export
+ * @interface ExtendParams
+ */
+export interface ExtendParams {
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    cardType?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    creditExtInfo?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    hbFqNum?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    hbFqSellerPercent?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    industryRefluxInfo?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    royaltyFreeze?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    specifiedSellerName?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    sysServiceProviderId?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    tcInstallmentOrderId?: string | null;
+    /**
+     * 
+     * @type {string}
+     * @memberof ExtendParams
+     */
+    tradeComponentOrderId?: string | null;
+}

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

@@ -17,6 +17,7 @@ export * from './add-role-input';
 export * from './add-schedule-input';
 export * from './add-subscribe-message-template-input';
 export * from './add-sys-ldap-input';
+export * from './add-template-input';
 export * from './add-tenant-input';
 export * from './add-user-input';
 export * from './add-user-reg-way-input';
@@ -88,6 +89,7 @@ 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-template';
 export * from './admin-result-sql-sugar-paged-list-sys-wechat-pay';
 export * from './admin-result-sql-sugar-paged-list-sys-wechat-user';
 export * from './admin-result-sql-sugar-paged-list-tenant-output';
@@ -106,6 +108,7 @@ export * from './admin-result-sys-log-ex';
 export * from './admin-result-sys-log-op';
 export * from './admin-result-sys-print';
 export * from './admin-result-sys-schedule';
+export * from './admin-result-sys-template';
 export * from './admin-result-sys-user';
 export * from './admin-result-sys-wechat-pay';
 export * from './admin-result-sys-wechat-refund';
@@ -115,6 +118,8 @@ export * from './admin-result-wechat-pay-para-output';
 export * from './admin-result-wechat-pay-transaction-output';
 export * from './admin-result-wx-open-id-output';
 export * from './admin-result-wx-phone-output';
+export * from './alipay-pre-create-input';
+export * from './alipay-trade-page-pay-input';
 export * from './api-output';
 export * from './assembly';
 export * from './backup-output';
@@ -192,6 +197,8 @@ export * from './event-attributes';
 export * from './event-info';
 export * from './export-proc-by-tmpinput';
 export * from './export-proc-input';
+export * from './ext-user-info';
+export * from './extend-params';
 export * from './field-attributes';
 export * from './field-info';
 export * from './filter';
@@ -213,6 +220,8 @@ export * from './idisposable';
 export * from './isite';
 export * from './info-save-input';
 export * from './int-ptr';
+export * from './invoice-info';
+export * from './invoice-key-info';
 export * from './jtoken';
 export * from './job-create-type-enum';
 export * from './job-detail-input';
@@ -264,6 +273,7 @@ export * from './page-plugin-input';
 export * from './page-print-input';
 export * from './page-region-input';
 export * from './page-role-input';
+export * from './page-template-input';
 export * from './page-tenant-input';
 export * from './page-user-input';
 export * from './page-user-reg-way-input';
@@ -272,8 +282,10 @@ export * from './parameter-attributes';
 export * from './parameter-info';
 export * from './platform-type-enum';
 export * from './print-type-enum';
+export * from './pro-view-template-input';
 export * from './property-attributes';
 export * from './property-info';
+export * from './render-template-input';
 export * from './reset-pwd-user-input';
 export * from './restore-input';
 export * from './role-input';
@@ -314,6 +326,7 @@ 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-template';
 export * from './sql-sugar-paged-list-sys-wechat-pay';
 export * from './sql-sugar-paged-list-sys-wechat-user';
 export * from './sql-sugar-paged-list-tenant-output';
@@ -356,6 +369,7 @@ export * from './sys-print';
 export * from './sys-region';
 export * from './sys-role';
 export * from './sys-schedule';
+export * from './sys-template';
 export * from './sys-user';
 export * from './sys-user-ext-org';
 export * from './sys-user-ldap';
@@ -396,6 +410,7 @@ export * from './update-region-input';
 export * from './update-role-input';
 export * from './update-schedule-input';
 export * from './update-sys-ldap-input';
+export * from './update-template-input';
 export * from './update-tenant-input';
 export * from './update-user-input';
 export * from './update-user-reg-way-input';

+ 33 - 0
Web/src/api-services/models/invoice-info.ts

@@ -0,0 +1,33 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { InvoiceKeyInfo } from './invoice-key-info';
+/**
+ * 
+ * @export
+ * @interface InvoiceInfo
+ */
+export interface InvoiceInfo {
+    /**
+     * 
+     * @type {string}
+     * @memberof InvoiceInfo
+     */
+    details?: string | null;
+    /**
+     * 
+     * @type {InvoiceKeyInfo}
+     * @memberof InvoiceInfo
+     */
+    keyInfo?: InvoiceKeyInfo;
+}

+ 38 - 0
Web/src/api-services/models/invoice-key-info.ts

@@ -0,0 +1,38 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 
+ * @export
+ * @interface InvoiceKeyInfo
+ */
+export interface InvoiceKeyInfo {
+    /**
+     * 
+     * @type {string}
+     * @memberof InvoiceKeyInfo
+     */
+    invoiceMerchantName?: string | null;
+    /**
+     * 
+     * @type {boolean}
+     * @memberof InvoiceKeyInfo
+     */
+    isSupportInvoice?: boolean;
+    /**
+     * 
+     * @type {string}
+     * @memberof InvoiceKeyInfo
+     */
+    taxNum?: string | null;
+}

+ 94 - 0
Web/src/api-services/models/page-template-input.ts

@@ -0,0 +1,94 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { Filter } from './filter';
+import { Search } from './search';
+/**
+ * 
+ * @export
+ * @interface PageTemplateInput
+ */
+export interface PageTemplateInput {
+    /**
+     * 
+     * @type {Search}
+     * @memberof PageTemplateInput
+     */
+    search?: Search;
+    /**
+     * 模糊查询关键字
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    keyword?: string | null;
+    /**
+     * 
+     * @type {Filter}
+     * @memberof PageTemplateInput
+     */
+    filter?: Filter;
+    /**
+     * 当前页码
+     * @type {number}
+     * @memberof PageTemplateInput
+     */
+    page?: number;
+    /**
+     * 页码容量
+     * @type {number}
+     * @memberof PageTemplateInput
+     */
+    pageSize?: number;
+    /**
+     * 排序字段
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    field?: string | null;
+    /**
+     * 排序方向
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    order?: string | null;
+    /**
+     * 降序排序
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    descStr?: string | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    name?: string | null;
+    /**
+     * 编码
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    code?: string | null;
+    /**
+     * 分组名称
+     * @type {string}
+     * @memberof PageTemplateInput
+     */
+    groupName?: string | null;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof PageTemplateInput
+     */
+    tenantId?: number;
+}

+ 32 - 0
Web/src/api-services/models/pro-view-template-input.ts

@@ -0,0 +1,32 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 预览模板输入参数
+ * @export
+ * @interface ProViewTemplateInput
+ */
+export interface ProViewTemplateInput {
+    /**
+     * 主键Id
+     * @type {number}
+     * @memberof ProViewTemplateInput
+     */
+    id: number;
+    /**
+     * 渲染参数
+     * @type {any}
+     * @memberof ProViewTemplateInput
+     */
+    data: any;
+}

+ 32 - 0
Web/src/api-services/models/render-template-input.ts

@@ -0,0 +1,32 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 模板渲染输入参数
+ * @export
+ * @interface RenderTemplateInput
+ */
+export interface RenderTemplateInput {
+    /**
+     * 模板内容
+     * @type {string}
+     * @memberof RenderTemplateInput
+     */
+    content: string;
+    /**
+     * 渲染参数
+     * @type {any}
+     * @memberof RenderTemplateInput
+     */
+    data: any;
+}

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

@@ -0,0 +1,63 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+import { SysTemplate } from './sys-template';
+/**
+ * 分页泛型集合
+ * @export
+ * @interface SqlSugarPagedListSysTemplate
+ */
+export interface SqlSugarPagedListSysTemplate {
+    /**
+     * 页码
+     * @type {number}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    page?: number;
+    /**
+     * 页容量
+     * @type {number}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    pageSize?: number;
+    /**
+     * 总条数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    total?: number;
+    /**
+     * 总页数
+     * @type {number}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    totalPages?: number;
+    /**
+     * 当前页集合
+     * @type {Array<SysTemplate>}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    items?: Array<SysTemplate> | null;
+    /**
+     * 是否有上一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    hasPrevPage?: boolean;
+    /**
+     * 是否有下一页
+     * @type {boolean}
+     * @memberof SqlSugarPagedListSysTemplate
+     */
+    hasNextPage?: boolean;
+}

+ 110 - 0
Web/src/api-services/models/sys-template.ts

@@ -0,0 +1,110 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 系统模板表
+ * @export
+ * @interface SysTemplate
+ */
+export interface SysTemplate {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof SysTemplate
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof SysTemplate
+     */
+    createTime?: Date;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof SysTemplate
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof SysTemplate
+     */
+    createUserId?: number | null;
+    /**
+     * 创建者姓名
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    createUserName?: string | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof SysTemplate
+     */
+    updateUserId?: number | null;
+    /**
+     * 修改者姓名
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    updateUserName?: string | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof SysTemplate
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof SysTemplate
+     */
+    tenantId?: number | null;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    name?: string | null;
+    /**
+     * 编码
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    code?: string | null;
+    /**
+     * 分组名称
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    groupName?: string | null;
+    /**
+     * 模板内容
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    content?: string | null;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof SysTemplate
+     */
+    remark?: string | null;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof SysTemplate
+     */
+    orderNo?: number;
+}

+ 110 - 0
Web/src/api-services/models/update-template-input.ts

@@ -0,0 +1,110 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET 通用权限开发平台
+ * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
+ *
+ * OpenAPI spec version: 1.0.0
+ * 
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 更新模板输入参数
+ * @export
+ * @interface UpdateTemplateInput
+ */
+export interface UpdateTemplateInput {
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof UpdateTemplateInput
+     */
+    createTime?: Date;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof UpdateTemplateInput
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof UpdateTemplateInput
+     */
+    createUserId?: number | null;
+    /**
+     * 创建者姓名
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    createUserName?: string | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof UpdateTemplateInput
+     */
+    updateUserId?: number | null;
+    /**
+     * 修改者姓名
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    updateUserName?: string | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof UpdateTemplateInput
+     */
+    isDelete?: boolean;
+    /**
+     * 租户Id
+     * @type {number}
+     * @memberof UpdateTemplateInput
+     */
+    tenantId?: number | null;
+    /**
+     * 备注
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    remark?: string | null;
+    /**
+     * 排序
+     * @type {number}
+     * @memberof UpdateTemplateInput
+     */
+    orderNo?: number;
+    /**
+     * 名称
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    name: string;
+    /**
+     * 编码
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    code: string;
+    /**
+     * 分组名称
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    groupName: string;
+    /**
+     * 模板内容
+     * @type {string}
+     * @memberof UpdateTemplateInput
+     */
+    content: string;
+    /**
+     * 主键Id
+     * @type {number}
+     * @memberof UpdateTemplateInput
+     */
+    id: number;
+}

+ 168 - 0
Web/src/views/system/template/component/editTemplate.vue

@@ -0,0 +1,168 @@
+<template>
+	<div class="sys-config-container">
+		<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="700px">
+			<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="60">
+				<el-tabs v-model="state.selectedTabName">
+					<el-tab-pane label="基础信息" name="1" style="height: 550px; overflow-y: auto; overflow-x: hidden">
+						<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="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<el-form-item label="编码" prop="code" :rules="[{ required: true, message: '编码不能为空', trigger: 'blur' }]">
+									<el-input v-model="state.ruleForm.code" placeholder="编码" clearable />
+								</el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<el-form-item label="分组" prop="groupName" :rules="[{ required: true, message: '分组不能为空', trigger: 'blur' }]">
+									<el-input v-model="state.ruleForm.groupName" 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="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-tab-pane>
+					<el-tab-pane label="模板内容" name="2" style="height: 550px; overflow-y: auto; overflow-x: hidden">
+						<el-row :gutter="5">
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<el-form-item label="内容" prop="content" :rules="[{ required: true, message: '内容不能为空', trigger: 'blur' }]">
+									<el-radio-group v-model="state.contentType">
+										<el-radio :value="1">富文本</el-radio>
+										<el-radio :value="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="内容" prop="content" :rules="[{ required: true, message: '内容不能为空', trigger: 'blur' }]">
+									<Editor v-model:get-html="state.ruleForm.content" v-if="state.contentType == 1" height="150px" />
+									<el-input v-model="state.ruleForm.content" v-else type="textarea" rows="15" show-word-limit></el-input>
+								</el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" style="user-select: none;">
+								<el-row :gutter="5">
+									<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" title="双击删除参数项">
+										<el-form-item label="预览参数">
+											<el-button icon="ele-Plus" text @click="() => state.renderData.push([])"></el-button>
+										</el-form-item>
+									</el-col>
+									<el-col v-for="(item, index) in state.renderData" :key="index" :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb5" @dblclick="() => state.renderData.splice(index, 1)">
+										<el-row :gutter="5">
+											<el-col :span="8">
+												<el-input v-model="item[0]" :placeholder="'参数名' + (index + 1)"/>
+											</el-col>
+											<el-col :span="16">
+												<el-input v-model="item[1]" :placeholder="'参数值' + (index + 1)"/>
+											</el-col>
+										</el-row>
+									</el-col>
+								</el-row>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<el-form-item label="预览结果:" label-width="75" label-position="left" />
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<span v-html="state.result"></span>
+							</el-col>
+						</el-row>
+					</el-tab-pane>
+				</el-tabs>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel">取 消</el-button>
+					<el-button @click="showPreView" v-reclick="3000">预览</el-button>
+					<el-button type="primary" @click="submit" v-reclick="2000">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysEditConfig">
+import { reactive, ref } from 'vue';
+import { getAPI } from '/@/utils/axios-utils';
+import { SysTemplateApi } from '/@/api-services/api';
+import { UpdateTemplateInput } from '/@/api-services/models';
+import Editor from "/@/components/editor/index.vue";
+
+const props = defineProps({
+	title: String,
+});
+const ruleFormRef = ref();
+const emits = defineEmits(['updateData']);
+const state = reactive({
+	isShowDialog: false,
+	selectedTabName: "1",
+	renderData: [] as any,
+	result: '' as any,
+	contentType: 1,
+	ruleForm: {} as UpdateTemplateInput,
+});
+
+const getRenderData = () => {
+	const data = {} as any;
+	state.renderData.forEach((e: [string, string]) => data[e[0]] = e[1]);
+	return data;
+}
+
+const getRenderContent = async () => {
+	const res = await getAPI(SysTemplateApi).apiSysTemplateRenderPost({ content: state.ruleForm.content, data: getRenderData() })
+	state.result = res.data.result;
+}
+
+const showPreView = () => {
+	getRenderContent();
+	state.selectedTabName = '2';
+}
+
+// 打开弹窗
+const openDialog = (row: any) => {
+	state.ruleForm = JSON.parse(JSON.stringify(row));
+	state.selectedTabName = "1";
+	state.isShowDialog = true;
+	ruleFormRef.value?.resetFields();
+};
+
+// 关闭弹窗
+const closeDialog = () => {
+	emits('updateData');
+	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(SysTemplateApi).apiSysTemplateUpdatePost(state.ruleForm);
+		} else {
+			await getAPI(SysTemplateApi).apiSysTemplateAddPost(state.ruleForm);
+		}
+		closeDialog();
+	});
+};
+
+// 导出对象
+defineExpose({ openDialog });
+</script>

+ 141 - 0
Web/src/views/system/template/component/previewDialog.vue

@@ -0,0 +1,141 @@
+<template>
+	<div class="sys-codeGenPreview-container">
+		<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="70%">
+			<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>
+			<div :class="[state.current?.endsWith('.cs') ? 'cs-style' : state.current?.endsWith('.vue') ? 'vue-style' : 'js-style']">
+				<el-segmented v-model="state.current" :options="state.options" block @change="handleChange">
+					<template #default="{ item }">
+						<div class="pd4">
+							<SvgIcon :name="item.icon" class="mb4" />
+							<div>{{ item.value }}</div>
+						</div>
+					</template>
+				</el-segmented>
+			</div>
+			<div ref="monacoEditorRef" style="width: 100%; height: 700px;" v-loading="state.loading"></div>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button icon="ele-Close" @click="cancel">关 闭</el-button>
+					<el-button icon="ele-CopyDocument" type="primary" @click="handleCopy">复 制</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysPreviewCode">
+import { reactive, ref, nextTick, toRaw } from 'vue';
+import * as monaco from 'monaco-editor';
+import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
+import commonFunction from '/@/utils/commonFunction';
+
+import { getAPI } from '/@/utils/axios-utils';
+import {SysTemplateApi} from "/@/api-services";
+const { copyText } = commonFunction();
+
+const props = defineProps({
+	title: String,
+});
+const monacoEditorRef = ref();
+const state = reactive({
+	isShowDialog: false,
+	options: [] as any, // 分段器的选项
+	current: '', // 选中的分段
+	codes: [] as any, // 预览的代码
+  loading: true
+});
+
+// 防止 monaco 报黄
+self.MonacoEnvironment = {
+	getWorker: (_: string, label: string) => new EditorWorker(),
+};
+
+// 初始化monacoEditor对象
+var monacoEditor: any = null;
+const initMonacoEditor = () => {
+	monacoEditor = monaco.editor.create(monacoEditorRef.value, {
+		theme: 'vs-dark', // 主题 vs vs-dark hc-black
+		value: '', // 默认显示的值
+		language: 'text',
+		formatOnPaste: true,
+		wordWrap: 'on', // 自动换行,注意大小写
+		wrappingIndent: 'indent',
+		folding: true, // 是否折叠
+		foldingHighlight: true, // 折叠等高线
+		foldingStrategy: 'indentation', // 折叠方式  auto | indentation
+		showFoldingControls: 'always', // 是否一直显示折叠 always | mouSEOver
+		disableLayerHinting: true, // 等宽优化
+		emptySelectionClipboard: false, // 空选择剪切板
+		selectionClipboard: false, // 选择剪切板
+		automaticLayout: true, // 自动布局
+		codeLens: false, // 代码镜头
+		scrollBeyondLastLine: false, // 滚动完最后一行后再滚动一屏幕
+		colorDecorators: true, // 颜色装饰器
+		accessibilitySupport: 'auto', // 辅助功能支持  "auto" | "off" | "on"
+		lineNumbers: 'on', // 行号 取值: "on" | "off" | "relative" | "interval" | function
+		lineNumbersMinChars: 5, // 行号最小字符   number
+		//enableSplitViewResizing: false,
+		readOnly: false, // 是否只读  取值 true | false
+	});
+};
+
+// 打开弹窗
+const openDialog = async (row: any) => {
+  state.loading = true;
+  try {
+    state.isShowDialog = true;
+    const { data } = await getAPI(SysTemplateApi).apiSysTemplateProViewPost({
+	    id: row.id,
+	    data: {
+	    }
+    });
+    state.codes = data.result ?? [];
+    state.options = Object.keys(data.result ?? []).map((fileName: string) => ({
+      value: fileName,
+      icon: fileName?.endsWith('.cs') ? 'fa fa-hashtag' : fileName?.endsWith('.vue') ? 'fa fa-vimeo' : 'fa fa-file-code-o',
+    }));
+    state.current = state.options?.[0]?.value ?? '';
+  }  catch (e) { /* empty */ }
+  state.loading = false;
+	if (monacoEditor == null) initMonacoEditor();
+	// 防止取不到
+	nextTick(() => {
+		monacoEditor.setValue(state.codes[state.current]);
+	});
+};
+
+// 分段器改变时切换代码
+const handleChange = (current: any) => {
+	monacoEditor.setValue(state.codes[current]);
+};
+
+// 取消
+const cancel = () => {
+	state.isShowDialog = false;
+};
+
+//复制代码
+const handleCopy = () => {
+	copyText(state.codes[state.current]);
+};
+
+// 导出对象
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.cs-style .el-segmented {
+	--el-segmented-item-selected-bg-color: #5c2d91;
+}
+.vue-style .el-segmented {
+	--el-segmented-item-selected-bg-color: #42b883;
+}
+.js-style .el-segmented {
+	--el-segmented-item-selected-bg-color: #e44d26;
+}
+</style>

+ 158 - 0
Web/src/views/system/template/index.vue

@@ -0,0 +1,158 @@
+<template>
+	<div class="sys-config-container">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<TableSearch :search="tb.tableData.search" @search="onSearch" />
+		</el-card>
+		<el-card class="full-table" shadow="hover" style="margin-top: 5px">
+			<Table ref="tableRef" v-bind="tb.tableData" :getData="getData" @sortHeader="onSortHeader" border>
+				<template #command>
+					<el-button type="primary" icon="ele-Plus" @click="openAddTemplate" v-auth="'sysConfig:add'"> 新增 </el-button>
+				</template>
+				<template #remark="scope">
+					<ModifyRecord :data="scope.row" />
+				</template>
+				<template #action="scope">
+					<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditTemplate(scope.row)" v-auth="'sysConfig:update'"> 编辑 </el-button>
+					<el-button icon="ele-Delete" size="small" text type="danger" @click="delTemplate(scope.row)" v-auth="'sysConfig:delete'" :disabled="scope.row.sysFlag === 1"> 删除 </el-button>
+				</template>
+			</Table>
+		</el-card>
+		<EditTemplate ref="editTemplateRef" :title="state.editTemplateTitle" :groupList="state.groupList" @updateData="updateData" />
+	</div>
+</template>
+
+<script lang="ts" setup name="sysConfig">
+import { onMounted, reactive, ref, defineAsyncComponent, nextTick } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import { getAPI } from '/@/utils/axios-utils';
+import { SysTemplateApi } from "/@/api-services";
+import { EmptyObjectType, RefType } from '/@/types/global';
+import ModifyRecord from '/@/components/table/modifyRecord.vue';
+import EditTemplate from './component/editTemplate.vue';
+
+// 引入组件
+const TableSearch = defineAsyncComponent(() => import('/@/components/table/search.vue'));
+const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'));
+const editTemplateRef = ref<InstanceType<typeof EditTemplate>>();
+const tableRef = ref<RefType>();
+
+const state = reactive({
+	editTemplateTitle: '',
+	selectlist: [] as EmptyObjectType[],
+	groupList: [] as Array<String>,
+});
+
+const tb = reactive<TableDemoState>({
+	tableData: {
+		// 表头内容(必传,注意格式)
+		columns: [
+			{ prop: 'name', minWidth: 150, label: '模板名称', headerAlign: 'center', sortable: 'custom', isCheck: true, hideCheck: true },
+			{ prop: 'code', minWidth: 150, label: '模板编码', headerAlign: 'center', toolTip: true, sortable: 'custom', isCheck: true },
+			{ prop: 'groupName', width: 120, label: '分组编码', align: 'center', sortable: 'custom', isCheck: true },
+			{ prop: 'orderNo', width: 80, label: '排序', align: 'center', sortable: 'custom', isCheck: true },
+			{ prop: 'remark', width: 100, label: '修改记录', align: 'center', headerAlign: 'center', showOverflowTooltip: true, isCheck: true },
+			{ prop: 'action', width: 140, label: '操作', type: 'action', align: 'center', isCheck: true, fixed: 'right', hideCheck: true },
+		],
+		// 配置项(必传)
+		config: {
+			isStripe: true, // 是否显示表格斑马纹
+			isBorder: false, // 是否显示表格边框
+			isSerialNo: true, // 是否显示表格序号
+			isSelection: false, // 是否勾选表格多选
+			showSelection: false, //是否显示表格多选
+			pageSize: 50, // 每页条数
+			hideExport: true, //是否隐藏导出按钮
+		},
+		// 搜索表单,动态生成(传空数组时,将不显示搜索,type有3种类型:input,date,select)
+		search: [
+			{ label: '名称', prop: 'name', placeholder: '搜索模板名称', required: false, type: 'input' },
+			{ label: '编码', prop: 'code', placeholder: '搜索模板编码', required: false, type: 'input' },
+		],
+		param: {},
+		defaultSort: {
+			prop: 'orderNo',
+			order: 'ascending',
+		},
+	},
+});
+const getData = (param: any) => {
+	return getAPI(SysTemplateApi)
+		.apiSysTemplatePagePost(param)
+		.then((res) => {
+			return res.data;
+		});
+};
+
+// 拖动显示列排序回调
+const onSortHeader = (data: object[]) => {
+	tb.tableData.columns = data;
+};
+
+// 搜索点击时表单回调
+const onSearch = (data: EmptyObjectType) => {
+	tb.tableData.param = Object.assign({}, tb.tableData.param, { ...data });
+	nextTick(() => {
+		tableRef.value.pageReset();
+	});
+};
+
+// 获取分组列表
+const getGroupList = async () => {
+	const res = await getAPI(SysTemplateApi).apiSysTemplateGroupListGet();
+	const groupSearch = {
+		label: '分组编码',
+		prop: 'groupName',
+		placeholder: '请选择',
+		required: false,
+		type: 'select',
+		options: [],
+	} as TableSearchType;
+	state.groupList = res.data.result ?? [];
+	res.data.result?.forEach((item) => {
+		groupSearch.options?.push({ label: item, value: item });
+	});
+	let group = tb.tableData.search.filter((item) => {
+		return item.prop == 'groupCode';
+	});
+	if (group.length == 0) {
+		tb.tableData.search.push(groupSearch);
+	} else {
+		group[0] = groupSearch;
+	}
+};
+
+onMounted(async () => {
+	getGroupList();
+});
+
+// 更新数据
+const updateData = () => {
+	tableRef.value.handleList();
+	getGroupList();
+};
+
+// 打开新增页面
+const openAddTemplate = () => {
+	state.editTemplateTitle = '添加模板';
+	editTemplateRef.value?.openDialog({ sysFlag: 2, orderNo: 100 });
+};
+
+// 打开编辑页面
+const openEditTemplate = (row: any) => {
+	state.editTemplateTitle = '编辑模板';
+	editTemplateRef.value?.openDialog(row);
+};
+
+// 删除
+const delTemplate = (row: any) => {
+	ElMessageBox.confirm(`确定删除模板:【${row.name}】?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	}).then(async () => {
+			await getAPI(SysTemplateApi).apiSysTemplateDeletePost({ id: row.id });
+			tableRef.value.handleList();
+			ElMessage.success('删除成功');
+	}).catch(() => {});
+};
+</script>