lichunlei hai 3 semanas
achega
b170b80e05
Modificáronse 100 ficheiros con 9606 adicións e 0 borrados
  1. 139 0
      .drone.yml
  2. 4 0
      .gitignore
  3. 53 0
      .vscode/launch.json
  4. 42 0
      .vscode/tasks.json
  5. 100 0
      App/App.cs
  6. 25 0
      App/InternalApp.cs
  7. 32 0
      Attribute/AppServiceAttribute.cs
  8. 35 0
      Attribute/LogAttribute.cs
  9. 93 0
      Base/AppSettings.cs
  10. 59 0
      Base/GlobalConstant.cs
  11. 150 0
      Common/Cache/CacheHelper.cs
  12. 17 0
      Common/Cache/RedisServer.cs
  13. 1215 0
      Common/Function.cs
  14. 37 0
      Common/JsonConverterUtil.cs
  15. 167 0
      Common/JwtUtil.cs
  16. 48 0
      Common/StringConverter.cs
  17. 142 0
      Common/Tools.cs
  18. 134 0
      Common/dbconn.cs
  19. 145 0
      Constant/Helper/DateTimeHelper.cs
  20. 84 0
      Constant/HttpStatus.cs
  21. 125 0
      Controllers/Admin/AppSourceSetController.cs
  22. 164 0
      Controllers/Admin/AppSourceVersionController.cs
  23. 142 0
      Controllers/AppBottomNavsController.cs
  24. 136 0
      Controllers/AppReportRecordController.cs
  25. 142 0
      Controllers/AppVersionController.cs
  26. 245 0
      Controllers/Base/BaseController.cs
  27. 51 0
      Controllers/Base/HomeController.cs
  28. 139 0
      Controllers/Client/AppController.cs
  29. 48 0
      Controllers/Client/OssController.cs
  30. 180 0
      Controllers/FileUpdateInfoController.cs
  31. 265 0
      Controllers/PageUpdateInfoController.cs
  32. BIN=BIN
      DLL/Aliyun.OSS.dll
  33. 87 0
      Extensions/AppServiceExtensions.cs
  34. 41 0
      Extensions/EntityExtension.cs
  35. 446 0
      Extensions/Extension.Convert.cs
  36. 86 0
      Extensions/Extension.Enum.cs
  37. 18 0
      Extensions/Extension.Exception.cs
  38. 110 0
      Extensions/Extension.Linq.cs
  39. 44 0
      Extensions/Extension.Validate.cs
  40. 245 0
      Extensions/HttpContextExtension.cs
  41. 24 0
      Extensions/IPRateExtension.cs
  42. 35 0
      Extensions/RequestLimitExtension.cs
  43. 232 0
      Extensions/StringExtension.cs
  44. 92 0
      Filters/ActionPermissionFilter.cs
  45. 148 0
      Filters/AuthorizationFilter.cs
  46. 281 0
      Filters/GlobalActionMonitor.cs
  47. 76 0
      Filters/VerifyAttribute.cs
  48. 3 0
      GlobalUsing.cs
  49. 157 0
      Middleware/GlobalExceptionMiddleware.cs
  50. 127 0
      Model/Base/ApiResult.cs
  51. 137 0
      Model/Base/OptionsSetting.cs
  52. 46 0
      Model/Base/PagedInfo.cs
  53. 37 0
      Model/Base/PagerInfo.cs
  54. 45 0
      Model/Base/SysBase.cs
  55. 44 0
      Model/Base/TokenModel.cs
  56. 115 0
      Model/Base/UserConstants.cs
  57. 11 0
      Model/Customer/AppResultJson.cs
  58. 197 0
      Model/Database/AppBottomNavs.cs
  59. 108 0
      Model/Database/AppReportRecord.cs
  60. 148 0
      Model/Database/AppSourceSet.cs
  61. 71 0
      Model/Database/AppSourceVersion.cs
  62. 120 0
      Model/Database/AppVersion.cs
  63. 92 0
      Model/Database/FileUpdateInfo.cs
  64. 211 0
      Model/Database/PageUpdateInfo.cs
  65. 136 0
      Model/Dto/AppBottomNavsAddDto.cs
  66. 26 0
      Model/Dto/AppBottomNavsListDto.cs
  67. 20 0
      Model/Dto/AppBottomNavsQueryDto.cs
  68. 129 0
      Model/Dto/AppBottomNavsUpdateDto.cs
  69. 109 0
      Model/Dto/AppSourceSetDto.cs
  70. 43 0
      Model/Dto/AppSourceVersionDto.cs
  71. 62 0
      Model/Dto/AppVersionAddDto.cs
  72. 24 0
      Model/Dto/AppVersionLastDto.cs
  73. 26 0
      Model/Dto/AppVersionListDto.cs
  74. 20 0
      Model/Dto/AppVersionQueryDto.cs
  75. 62 0
      Model/Dto/AppVersionUpdateDto.cs
  76. 21 0
      Model/Dto/Base/OssUploadDto.cs
  77. 27 0
      Model/Dto/Client/AppAppBottomNavsDto.cs
  78. 42 0
      Model/Dto/Client/AppPageInfoDto.cs
  79. 27 0
      Model/Dto/Client/AppStaticFilesDto.cs
  80. 26 0
      Model/Dto/CopyDto.cs
  81. 33 0
      Model/Dto/FileUpdateInfoAddDto.cs
  82. 26 0
      Model/Dto/FileUpdateInfoListDto.cs
  83. 20 0
      Model/Dto/FileUpdateInfoQueryDto.cs
  84. 21 0
      Model/Dto/FileUpdateInfoUpVersionDto.cs
  85. 39 0
      Model/Dto/FileUpdateInfoUpdateDto.cs
  86. 31 0
      Model/Dto/FileUpdateInfoUpdateFileDto.cs
  87. 25 0
      Model/Dto/MakeAppInitDataDto.cs
  88. 131 0
      Model/Dto/PageUpdateInfoAddDto.cs
  89. 38 0
      Model/Dto/PageUpdateInfoListDto.cs
  90. 20 0
      Model/Dto/PageUpdateInfoQueryDto.cs
  91. 20 0
      Model/Dto/PageUpdateInfoUpVersionDto.cs
  92. 143 0
      Model/Dto/PageUpdateInfoUpdateDto.cs
  93. 32 0
      Model/Dto/PageUpdateInfoUpdateTemplateDto.cs
  94. 63 0
      Model/Enums/BusinessType.cs
  95. 15 0
      Model/Enums/MenuStatus.cs
  96. 19 0
      Model/Enums/MenuType.cs
  97. 4 0
      Model/Enums/ProteryConstant.cs
  98. 40 0
      Model/Enums/StoreType.cs
  99. 48 0
      Model/Exception/CustomException.cs
  100. 46 0
      Model/Exception/ResultCode.cs

+ 139 - 0
.drone.yml

@@ -0,0 +1,139 @@
+kind: pipeline
+type: docker
+name: app-manager-prod
+
+volumes: # 声明数据卷
+  - name: targetDir
+    host:
+      path: /app-manager
+
+clone:
+  disable: false # 启用代码拉取
+
+steps:
+  - name: build-project
+    image: mcr.microsoft.com/dotnet/sdk:7.0
+    pull: if-not-exists
+    depends_on: [clone] # 依赖的步骤
+    volumes: # 挂载数据卷
+      - name: targetDir
+        path: /drone/src/dist/
+    commands: # 执行命令
+      - echo '' > ~/.nuget/NuGet/NuGet.Config
+      - echo '<?xml version="1.0" encoding="utf-8"?><configuration><packageSources><add key="nuget.org" value="https://nuget.cdn.azure.cn/v3/index.json" protocolVersion="3" /></packageSources></configuration>' > ~/.nuget/NuGet/NuGet.Config
+      - rm -rf /drone/src/dist/*
+      - dotnet publish -c release -o ./publish -r linux-x64
+      - cp -r ./publish/* /drone/src/dist # 复制文件
+    when:
+      status:
+        - success # 当前步骤成功时执行
+  - name: scp-project
+    image: appleboy/drone-scp
+    pull: if-not-exists
+    depends_on: [build-project] # 依赖的步骤
+    volumes: # 挂载数据卷
+      - name: targetDir # 数据卷名称
+        path: /app-manager # 容器内目录 绝对路径
+    settings:
+      host:
+        from_secret: app-manager-host-a
+      username:
+        from_secret: username
+      password:
+        from_secret: userpwd
+      port: 22
+      command_timeout: 2m
+      target: /home/ABServer/deploy-ready/
+      source:
+        - echo ====开始拷贝=======
+        - /app-manager/*
+        - echo ====结束拷贝=======
+      when:
+        status:
+          - success # 当前步骤成功时执行
+
+  - name: deploy-project
+    image: appleboy/drone-ssh
+    pull: if-not-exists
+    depends_on: [scp-project] # 依赖的步骤
+    settings:
+      host:
+        from_secret: app-manager-host-a
+      username:
+        from_secret: username
+      password:
+        from_secret: userpwd
+      port: 22
+      command_timeout: 2m
+      script:
+        - echo ====备份线上文件=======
+        - cp -r /home/ABServer/webroot/app-manager /home/ABServer/deploy-bak/
+        - echo ====开始部署=======
+        - cd /home/ABServer/
+        - cp -r /home/ABServer/deploy-ready/app-manager /home/ABServer/webroot/
+        - docker restart app-manager
+        - echo ====等待容器启动=======
+        - sleep 10 # 等待容器启动
+        - echo ====部署成功=======
+      when:
+        status:
+          - success # 当前步骤成功时执行
+  - name: scp-project-b
+    image: appleboy/drone-scp
+    pull: if-not-exists
+    depends_on: [deploy-project] # 依赖的步骤
+    volumes: # 挂载数据卷
+      - name: targetDir # 数据卷名称
+        path: /app-manager # 容器内目录 绝对路径
+    settings:
+      host:
+        from_secret: app-manager-host-b
+      username:
+        from_secret: username
+      password:
+        from_secret: userpwd
+      port: 22
+      command_timeout: 10m
+      target: /home/ABServer/deploy-ready/
+      source:
+        - echo ====开始拷贝=======
+        - /app-manager/*
+        - echo ====结束拷贝=======
+      when:
+        status:
+          - success # 当前步骤成功时执行
+
+  - name: deploy-project-b
+    image: appleboy/drone-ssh
+    pull: if-not-exists
+    depends_on: [scp-project-b] # 依赖的步骤
+    settings:
+      host:
+        from_secret: app-manager-host-b
+      username:
+        from_secret: username
+      password:
+        from_secret: userpwd
+      port: 22
+      command_timeout: 10m
+      script:
+        - echo ====备份线上文件=======
+        - cp -r /home/ABServer/webroot/app-manager /home/ABServer/deploy-bak/app-manager
+        - echo ====开始部署=======
+        - cd /home/ABServer/
+        - cp -r /home/ABServer/deploy-ready/app-manager /home/ABServer/webroot/
+        - docker restart app-manager
+        # - docker restart nodeServer1
+        - echo ====部署成功=======
+      when:
+        status:
+          - success # 当前步骤成功时执行
+
+trigger:
+  branch:
+    - release-app-manager
+  event:
+    - push
+  #排除合并请求
+  exclude:
+    - ref: refs/pull/*

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+/bin
+/publish
+/obj
+.DS_Store

+ 53 - 0
.vscode/launch.json

@@ -0,0 +1,53 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [{
+            "name": ".NET Core Launch (web)",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build",
+            "program": "${workspaceFolder}/bin/Debug/net7.0/OmegaConfig.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}",
+            "stopAtEntry": false,
+            "serverReadyAction": {
+                "action": "openExternally",
+                "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)"
+            },
+            "env": {
+                "ASPNETCORE_ENVIRONMENT": "Development"
+            },
+            "sourceFileMap": {
+                "/Views": "${workspaceFolder}/Views"
+            }
+        },
+        {
+            "name": ".NET Core Launch (pro)",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build",
+            "program": "${workspaceFolder}/bin/Debug/net7.0/OmegaConfig.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}",
+            "stopAtEntry": false,
+            "serverReadyAction": {
+                "action": "openExternally",
+                "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)"
+            },
+            "env": {
+                "ASPNETCORE_ENVIRONMENT": "Production"
+            },
+            "sourceFileMap": {
+                "/Views": "${workspaceFolder}/Views"
+            }
+        },
+        {
+            "name": ".NET Core Attach",
+            "type": "coreclr",
+            "request": "attach",
+            "processId": "${command:pickProcess}"
+        }
+    ]
+}

+ 42 - 0
.vscode/tasks.json

@@ -0,0 +1,42 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "build",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/OmegaConfig.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary"
+            ],
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "publish",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "publish",
+                "${workspaceFolder}/OmegaConfig.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary"
+            ],
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "watch",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "watch",
+                "run",
+                "${workspaceFolder}/OmegaConfig.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary"
+            ],
+            "problemMatcher": "$msCompile"
+        }
+    ]
+}

+ 100 - 0
App/App.cs

@@ -0,0 +1,100 @@
+using Infrastructure.Model;
+using Microsoft.Extensions.Options;
+using System.Security.Claims;
+
+namespace Infrastructure
+{
+    public static class App
+    {
+        /// <summary>
+        /// 全局配置文件
+        /// </summary>
+        public static OptionsSetting OptionsSetting => CatchOrDefault(() => ServiceProvider?.GetService<IOptions<OptionsSetting>>()?.Value);
+
+        /// <summary>
+        /// 服务提供器
+        /// </summary>
+        public static IServiceProvider ServiceProvider => InternalApp.ServiceProvider;
+        /// <summary>
+        /// 获取请求上下文
+        /// </summary>
+        public static HttpContext HttpContext => CatchOrDefault(() => ServiceProvider?.GetService<IHttpContextAccessor>()?.HttpContext);
+        /// <summary>
+        /// 获取请求上下文用户
+        /// </summary>
+        public static ClaimsPrincipal User => HttpContext?.User;
+        /// <summary>
+        /// 获取用户名
+        /// </summary>
+        public static string UserName => User?.Identity?.Name;
+        /// <summary>
+        /// 获取Web主机环境
+        /// </summary>
+        public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment; 
+        /// <summary>
+        /// 获取全局配置
+        /// </summary>
+        public static IConfiguration Configuration => CatchOrDefault(() => InternalApp.Configuration, new ConfigurationBuilder().Build());
+        /// <summary>
+        /// 获取请求生命周期的服务
+        /// </summary>
+        /// <typeparam name="TService"></typeparam>
+        /// <returns></returns>
+        public static TService GetService<TService>()
+            where TService : class
+        {
+            return GetService(typeof(TService)) as TService;
+        }
+
+        /// <summary>
+        /// 获取请求生命周期的服务
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static object GetService(Type type)
+        {
+            return ServiceProvider.GetService(type);
+        }
+
+        /// <summary>
+        /// 获取请求生命周期的服务
+        /// </summary>
+        /// <typeparam name="TService"></typeparam>
+        /// <returns></returns>
+        public static TService GetRequiredService<TService>()
+            where TService : class
+        {
+            return GetRequiredService(typeof(TService)) as TService;
+        }
+
+        /// <summary>
+        /// 获取请求生命周期的服务
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static object GetRequiredService(Type type)
+        {
+            return ServiceProvider.GetRequiredService(type);
+        }
+
+        /// <summary>
+        /// 处理获取对象异常问题
+        /// </summary>
+        /// <typeparam name="T">类型</typeparam>
+        /// <param name="action">获取对象委托</param>
+        /// <param name="defaultValue">默认值</param>
+        /// <returns>T</returns>
+        private static T CatchOrDefault<T>(Func<T> action, T defaultValue = null)
+            where T : class
+        {
+            try
+            {
+                return action();
+            }
+            catch
+            {
+                return defaultValue ?? null;
+            }
+        }
+    }
+}

+ 25 - 0
App/InternalApp.cs

@@ -0,0 +1,25 @@
+namespace Infrastructure
+{
+    public static class InternalApp
+    {
+        /// <summary>
+        /// 应用服务
+        /// </summary>
+        public static IServiceProvider ServiceProvider;
+
+        /// <summary>
+        /// 全局配置构建器
+        /// </summary>
+        public static IConfiguration Configuration;
+
+        /// <summary>
+        /// 获取Web主机环境
+        /// </summary>
+        public static IWebHostEnvironment WebHostEnvironment;
+
+        /// <summary>
+        /// 获取泛型主机环境
+        /// </summary>
+        //public static IHostEnvironment HostEnvironment;
+    }
+}

+ 32 - 0
Attribute/AppServiceAttribute.cs

@@ -0,0 +1,32 @@
+namespace Attribute
+{
+    /// <summary>
+    /// 参考地址:https://www.cnblogs.com/kelelipeng/p/10643556.html
+    /// 标记服务
+    /// 如何使用?
+    /// 1、如果服务是本身 直接在类上使用[AppService]
+    /// 2、如果服务是接口 在类上使用 [AppService(ServiceType = typeof(实现接口))]
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+    public class AppServiceAttribute : System.Attribute
+    {
+        /// <summary>
+        /// 服务声明周期
+        /// 不给默认值的话注册的是AddSingleton
+        /// </summary>
+        public LifeTime ServiceLifetime { get; set; } = LifeTime.Scoped;
+        /// <summary>
+        /// 指定服务类型
+        /// </summary>
+        public Type ServiceType { get; set; }
+        /// <summary>
+        /// 是否可以从第一个接口获取服务类型
+        /// </summary>
+        public bool InterfaceServiceType { get; set; }
+    }
+
+    public enum LifeTime
+    {
+        Transient, Scoped, Singleton
+    }
+}

+ 35 - 0
Attribute/LogAttribute.cs

@@ -0,0 +1,35 @@
+using Enums;
+
+namespace Attribute
+{
+    /// <summary>
+    /// 自定义操作日志记录注解
+    /// </summary>
+    public class LogAttribute : System.Attribute
+    {
+        public string Title { get; set; }
+        public BusinessType BusinessType { get; set; }
+        /// <summary>
+        /// 是否保存请求数据
+        /// </summary>
+        public bool IsSaveRequestData { get; set; } = true;
+        /// <summary>
+        /// 是否保存返回数据
+        /// </summary>
+        public bool IsSaveResponseData { get; set; } = true;
+
+        public LogAttribute() { }
+
+        public LogAttribute(string name)
+        {
+            Title = name;
+        }
+        public LogAttribute(string name, BusinessType businessType, bool saveRequestData = true, bool saveResponseData = true)
+        {
+            Title = name;
+            BusinessType = businessType;
+            IsSaveRequestData = saveRequestData;
+            IsSaveResponseData = saveResponseData;
+        }
+    }
+}

+ 93 - 0
Base/AppSettings.cs

@@ -0,0 +1,93 @@
+namespace Base
+{
+    public class AppSettings
+    {
+        static IConfiguration Configuration { get; set; }
+
+        public AppSettings(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        /// <summary>
+        /// 封装要操作的字符
+        /// </summary>
+        /// <param name="sections">节点配置</param>
+        /// <returns></returns>
+        public static string App(params string[] sections)
+        {
+            try
+            {
+                if (sections.Any())
+                {
+                    return Configuration[string.Join(":", sections)];
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+
+            return "";
+        }
+
+        /// <summary>
+        /// 递归获取配置信息数组
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="sections"></param>
+        /// <returns></returns>
+        public static List<T> App<T>(params string[] sections)
+        {
+            List<T> list = new();
+            try
+            {
+                if (Configuration != null && sections.Any())
+                {
+                    Configuration.Bind(string.Join(":", sections), list);
+                }
+            }
+            catch
+            {
+                return list;
+            }
+            return list;
+        }
+        public static T Bind<T>(string key, T t)
+        {
+            Configuration.Bind(key, t);
+            return t;
+        }
+
+
+        public static T GetAppConfig<T>(string key, T defaultValue = default)
+        {
+            T setting = (T)Convert.ChangeType(Configuration[key], typeof(T));
+            var value = setting;
+            if (setting == null)
+                value = defaultValue;
+            return value;
+        }
+
+        /// <summary>
+        /// 获取配置文件 
+        /// </summary>
+        /// <param name="key">eg: WeChat:Token</param>
+        /// <returns></returns>
+        public static string GetConfig(string key)
+        {
+            return Configuration[key];
+        }
+
+        /// <summary>
+        /// 获取配置节点并转换成指定类型
+        /// </summary>
+        /// <typeparam name="T">节点类型</typeparam>
+        /// <param name="key">节点路径</param>
+        /// <returns>节点类型实例</returns>
+        public static T Get<T>(string key)
+        {
+            return Configuration.GetSection(key).Get<T>();
+        }
+    }
+}

+ 59 - 0
Base/GlobalConstant.cs

@@ -0,0 +1,59 @@
+namespace Base
+{
+    /// <summary>
+    /// 全局静态常量
+    /// </summary>
+    public class GlobalConstant
+    {
+        /// <summary>
+        /// 管理员权限
+        /// </summary>
+        public static string AdminPerm = "*:*:*";
+        /// <summary>
+        /// 管理员角色
+        /// </summary>
+        public static string AdminRole = "ROLE_ADMIN";
+        /// <summary>
+        /// 开发版本API映射路径
+        /// </summary>
+        public static string DevApiProxy = "/dev-api/";
+        /// <summary>
+        /// 用户权限缓存key
+        /// </summary>
+        public static string UserPermKEY = "CACHE-USER-PERM";
+
+        /// <summary>
+        /// 欢迎语
+        /// </summary>
+        public static string[] WelcomeMessages = new string[] {
+            "祝你开心每一天!",
+            "忙碌了一周,停一停脚步!",
+            "世间美好,与你环环相扣!",
+            "永远相信美好的事情即将发生!",
+            "每一天,遇见更好的自己!",
+            "保持热爱,奔赴山海!",
+            "生活明朗,万物可爱!",
+            "愿每一天醒来都是美好的开始!",
+            "没有希望的地方,就没有奋斗!",
+            "我最珍贵的时光都行走在路上!",
+            "成功,往往住在失败的隔壁!",
+            "人只要不失去方向,就不会失去自己!",
+            "每条堵住的路,都有一个出口!",
+            "没有谁能击垮你,除非你自甘堕落!",
+            "微笑着的人并非没有痛苦!",
+            "生活变的再糟糕,也不妨碍我变得更好!",
+            "你要悄悄努力,然后惊艳众人!",
+            "人与人之间最大的信任是精诚相见",
+            "人生就像爬坡,要一步一步来。",
+            "今天的目标完成了吗?",
+            "高效工作,告别996",
+            "销售是从别人拒绝开始的!"
+        };
+
+
+
+
+        public static string ApiKey = "CBTU1dD4Kd5pyiGWTsI10jRQ3SvKusSV";
+        public static string ApiIv = "DYgjCEIMVrj2W9xN";
+    }
+}

+ 150 - 0
Common/Cache/CacheHelper.cs

@@ -0,0 +1,150 @@
+using Microsoft.Extensions.Caching.Memory;
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Reflection;
+
+namespace Common
+{
+    public class CacheHelper
+    {
+        public static MemoryCache Cache { get; set; }
+        static CacheHelper()
+        {
+            Cache = new MemoryCache(new MemoryCacheOptions
+            {
+                //SizeLimit = 1024
+            });
+        }
+
+        /// <summary>
+        /// 获取缓存
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        public static T GetCache<T>(string key) where T : class
+        {
+            if (key == null)
+                throw new ArgumentNullException(nameof(key));
+            //return Cache.Get(key) as T; //或者
+            return Cache.Get<T>(key);
+        }
+
+        /// <summary>
+        /// 获取缓存
+        /// </summary>
+        /// <param name="CacheKey"></param>
+        /// <returns></returns>
+        public static object GetCache(string CacheKey)
+        {
+            return Cache.Get<object>(CacheKey);
+        }
+
+        public static object Get(string CacheKey)
+        {
+            return Cache.Get(CacheKey);
+        }
+
+        /// <summary>
+        /// 设置缓存,永久缓存
+        /// </summary>
+        /// <param name="CacheKey">key</param>
+        /// <param name="objObject">值</param>
+        public static object SetCache(string CacheKey, object objObject)
+        {
+            return Cache.Set(CacheKey, objObject);
+        }
+
+        /// <summary>
+        /// 设置缓存
+        /// </summary>
+        /// <param name="CacheKey">key</param>
+        /// <param name="objObject">值</param>
+        /// <param name="Timeout">过期时间(分钟)</param>
+        public static object SetCache(string CacheKey, object objObject, int Timeout)
+        {
+            return Cache.Set(CacheKey, objObject, DateTime.Now.AddMinutes(Timeout));
+        }
+
+        /// <summary>
+        /// 设置缓存(秒)
+        /// </summary>
+        /// <param name="CacheKey">key</param>
+        /// <param name="objObject">值</param>
+        /// <param name="Timeout">过期时间(秒)</param>
+        public static void SetCaches(string CacheKey, object objObject, int Timeout)
+        {
+            Cache.Set(CacheKey, objObject, DateTime.Now.AddSeconds(Timeout));
+        }
+
+        /// <summary>
+        /// 设置缓存
+        /// </summary>
+        /// <param name="CacheKey">key</param>
+        /// <param name="objObject">值</param>
+        /// <param name="absoluteExpiration">过期时间</param>
+        /// <param name="slidingExpiration">过期时间间隔</param>
+        public static object SetCache(string CacheKey, object objObject, DateTime absoluteExpiration, TimeSpan slidingExpiration)
+        {
+            return Cache.Set(CacheKey, objObject, absoluteExpiration);
+        }
+
+        /// <summary>
+        /// 设定绝对的过期时间
+        /// </summary>
+        /// <param name="CacheKey"></param>
+        /// <param name="objObject"></param>
+        /// <param name="Seconds">超过多少秒后过期</param>
+        public static void SetCacheDateTime(string CacheKey, object objObject, long Seconds)
+        {
+            Cache.Set(CacheKey, objObject, DateTime.Now.AddSeconds(Seconds));
+        }
+
+        /// <summary>
+        /// 删除缓存
+        /// </summary>
+        /// <param name="key">key</param>
+        public static void Remove(string key)
+        {
+            Cache.Remove(key);
+        }
+
+        /// <summary>
+        /// 验证缓存项是否存在
+        /// </summary>
+        /// <param name="key">缓存Key</param>
+        /// <returns></returns>
+        public static bool Exists(string key)
+        {
+            if (key == null)
+                throw new ArgumentNullException(nameof(key));
+            return Cache.TryGetValue(key, out _);
+        }
+
+
+        /// <summary>
+        /// 获取所有缓存键
+        /// </summary>
+        /// <returns></returns>
+        public static List<string> GetCacheKeys()
+        {
+            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
+            //var entries = Cache.GetType().GetField("_entries", flags).GetValue(Cache);
+
+            //.net7需要这样写 
+            var coherentState = Cache.GetType().GetField("_coherentState", flags).GetValue(Cache);
+            var entries = coherentState.GetType().GetField("_entries", flags).GetValue(coherentState);
+
+            var keys = new List<string>();
+            if (entries is not IDictionary cacheItems) return keys;
+            foreach (DictionaryEntry cacheItem in cacheItems)
+            {
+                keys.Add(cacheItem.Key.ToString());
+                //Console.WriteLine("缓存key=" +cacheItem.Key);
+            }
+            return keys;
+        }
+    }
+}
+

+ 17 - 0
Common/Cache/RedisServer.cs

@@ -0,0 +1,17 @@
+using Base;
+using CSRedis;
+
+namespace Common
+{
+    public class RedisServer
+    {
+        public static CSRedisClient Cache;
+        public static CSRedisClient Session;
+
+        public static void Initalize()
+        {
+            Cache = new CSRedisClient(AppSettings.GetConfig("RedisServer:Cache"));
+            Session = new CSRedisClient(AppSettings.GetConfig("RedisServer:Session"));
+        }
+    }
+}

+ 1215 - 0
Common/Function.cs

@@ -0,0 +1,1215 @@
+using System;
+using System.Data;
+using System.Web;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Net.Mail;
+using System.Net;
+using LitJson;
+using Microsoft.AspNetCore.Http;
+using ThoughtWorks.QRCode.Codec;
+using System.Linq;
+using System.IO;
+
+namespace Common
+{
+    public class Function
+    {
+
+        /// <summary>
+        /// hmacSha1算法加密(生成长度40)
+        /// </summary>
+        /// <param name="encryptText">加密明文</param>
+        /// <param name="encryptKey">加密密钥</param>
+        /// <returns></returns>
+        public static string hmacSha1(string encryptText, string encryptKey)
+        {
+            HMACSHA1 myHMACSHA1 = new HMACSHA1(Encoding.UTF8.GetBytes(encryptKey));
+            byte[] RstRes = myHMACSHA1.ComputeHash(Encoding.UTF8.GetBytes(encryptText));
+
+            StringBuilder EnText = new StringBuilder();
+            foreach (byte Byte in RstRes)
+            {
+                EnText.AppendFormat("{0:x2}", Byte);
+            }
+            return EnText.ToString();
+        }
+
+        public static string hmacmd5(string encryptText, string encryptKey)
+        {
+            HMACMD5 myHMACSHA1 = new HMACMD5(Encoding.UTF8.GetBytes(encryptKey));
+            byte[] RstRes = myHMACSHA1.ComputeHash(Encoding.UTF8.GetBytes(encryptText));
+
+            StringBuilder EnText = new StringBuilder();
+            foreach (byte Byte in RstRes)
+            {
+                EnText.AppendFormat("{0:x2}", Byte);
+            }
+            return EnText.ToString();
+        }
+
+
+        /// <summary>
+        /// MD5 32位加密字符串
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static string MD5_32(string str)
+        {
+            string cl = str + "@$1212#";
+            string pwd = "";
+            MD5 md5 = MD5.Create();//实例化一个md5对像
+            // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 
+            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
+            // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
+            for (int i = 0; i < s.Length; i++)
+            {
+                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 
+                pwd = pwd + s[i].ToString("X").ToLower().PadLeft(2, '0');
+            }
+            return pwd;
+        }
+
+        public static string MD532(string str)
+        {
+            string cl = str;
+            string pwd = "";
+            MD5 md5 = MD5.Create();//实例化一个md5对像
+            // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 
+            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
+            // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
+            for (int i = 0; i < s.Length; i++)
+            {
+                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 
+                pwd = pwd + s[i].ToString("X").ToLower().PadLeft(2, '0');
+            }
+            return pwd;
+        }
+        /// <summary>
+        /// 获取MD5值
+        /// </summary>
+        /// <param name="str">加密的字符串</param>
+        /// <returns>返回MD5值</returns>
+        public static string MD5_16(string str)
+        {
+            return MD5_32(str).Substring(8, 16);
+        }
+        /// <summary>
+        /// 写日志(错误报告)
+        /// </summary>
+        /// <param name="str"></param>
+        public static void WriteLog(string str)
+        {
+            try
+            {
+                string path = getPath("/log/message/" + DateTime.Now.Year.ToString() + "/" + DateTime.Now.Month.ToString() + "/" + DateTime.Now.Day.ToString() + "/");
+                if (!Directory.Exists(path))
+                {
+                    Directory.CreateDirectory(path);
+                }
+                StreamWriter sw = File.AppendText(path + "content.log");
+                sw.WriteLine(str);
+                sw.Flush();
+                sw.Dispose();
+            }
+            catch
+            { }
+        }
+        /// <summary>
+        /// 写日志(错误报告)
+        /// </summary>
+        /// <param name="str"></param>
+        public static void WriteLog(string str, string filename)
+        {
+            try
+            {
+                string path = getPath("/log/" + filename + "/" + DateTime.Now.Year.ToString() + "/" + DateTime.Now.Month.ToString() + "/" + DateTime.Now.Day.ToString() + "/");
+                if (!Directory.Exists(path))
+                {
+                    Directory.CreateDirectory(path);
+                }
+                StreamWriter sw = File.AppendText(path + "content.log");
+                sw.WriteLine(str);
+                sw.Flush();
+                sw.Dispose();
+            }
+            catch
+            { }
+        }
+
+        public static void WriteLog(string path_str, string file_name, string page_content)
+        {
+            try
+            {
+                string path = getPath(path_str);
+                if (!Directory.Exists(path))
+                {
+                    Directory.CreateDirectory(path);
+                }
+                StreamWriter sw = File.AppendText(path + "/" + file_name);
+                sw.WriteLine(page_content);
+                sw.Flush();
+                sw.Dispose();
+            }
+            catch
+            { }
+        }
+
+        /// <summary>
+        /// 过滤html代码
+        /// </summary>
+        /// <param name="Htmlstring"></param>
+        public static string NoHTML(string Htmlstring) //去除HTML标记
+        {
+            if (Htmlstring == null || Htmlstring == string.Empty)
+            {
+                return "";
+            }
+            Htmlstring = Regex.Replace(Htmlstring, @"<script[^>]*?>.*?</script>", "", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
+            //Htmlstring = Regex.Replace(Htmlstring, @"([\r\n])[\s]+", "", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"-->", "", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"<!--.*", "", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(iexcl|#161);", "\xa1", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(cent|#162);", "\xa2", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(pound|#163);", "\xa3", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&(copy|#169);", "\xa9", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&#(\d+);", "", RegexOptions.IgnoreCase);
+            Htmlstring = Regex.Replace(Htmlstring, @"&.*?;", "", RegexOptions.IgnoreCase);
+
+            Htmlstring = Htmlstring.Replace("<", "〈");
+            Htmlstring = Htmlstring.Replace(">", "〉");
+            //Htmlstring = Htmlstring.Replace("\r\n", "");
+            //Htmlstring = HttpContext.Current.Server.HtmlEncode(Htmlstring).Trim();
+
+            return Htmlstring;
+        }
+
+        public static bool IsIncludeChinese(string str)
+        {
+            Regex r = new Regex(@"[\u4E00-\u9FA5]", RegexOptions.IgnoreCase);
+            if (r.IsMatch(str))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public static bool IsInt(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return false;
+            }
+            Regex rCode = new Regex("^\\d+$");
+            if (!rCode.IsMatch(numberString))
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        public static string CheckInt(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return "0";
+            }
+            Regex rCode = new Regex("^\\d+$");
+            if (!rCode.IsMatch(numberString))
+            {
+                return "0";
+            }
+            else
+            {
+                return numberString;
+            }
+        }
+
+        public static DateTime CheckDateTime(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return DateTime.Now;
+            }
+            DateTime result;
+            if (DateTime.TryParse(numberString, out result))
+            {
+                return result;
+            }
+            else
+            {
+                return DateTime.Now;
+            }
+        }
+
+        public static bool ChkDateTime(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return false;
+            }
+            DateTime result;
+            if (DateTime.TryParse(numberString, out result))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public static string CheckNull(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return "";
+            }
+            else
+            {
+                return numberString;
+            }
+        }
+
+        public static string CheckUrl(string str)
+        {
+            if (str == null || str == string.Empty)
+            {
+                return "";
+            }
+            Regex rCode = new Regex(@"((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?");
+            if (!rCode.IsMatch(str))
+            {
+                return "";
+            }
+            else
+            {
+                return str;
+            }
+        }
+
+        public static string CheckEmail(string str)
+        {
+            if (str == null || str == string.Empty)
+            {
+                return "";
+            }
+            Regex rCode = new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
+            if (!rCode.IsMatch(str))
+            {
+                return "";
+            }
+            else
+            {
+                return str;
+            }
+        }
+
+        public static string CheckMobile(string str)
+        {
+            if (str == null || str == string.Empty)
+            {
+                return "";
+            }
+            Regex rCode = new Regex(@"^1[3456789]\d{9}$");
+            if (!rCode.IsMatch(str))
+            {
+                return "";
+            }
+            else
+            {
+                return str;
+            }
+        }
+
+        public static string CheckIdCard(string str)
+        {
+            if (str == null || str == string.Empty)
+            {
+                return "";
+            }
+            Regex rCode = new Regex(@"^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$");
+            if (!rCode.IsMatch(str))
+            {
+                return "";
+            }
+            else
+            {
+                return str;
+            }
+        }
+
+        public static bool IsNum(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return false;
+            }
+            Regex rCode = new Regex(@"^\d+(\.\d+)?$");
+            if (!rCode.IsMatch(numberString))
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        public static string CheckNum(string numberString)
+        {
+            if (string.IsNullOrEmpty(numberString))
+            {
+                return "0";
+            }
+            Regex rCode = new Regex(@"^\d+(\.\d+)?$");
+            if (!rCode.IsMatch(numberString))
+            {
+                return "0";
+            }
+            else
+            {
+                return numberString;
+            }
+        }
+
+        public static string CheckString(string str)
+        {
+            if (string.IsNullOrEmpty(str))
+            {
+                return "";
+            }
+            str = str.Replace("'", "&acute;");
+            str = str.Replace("\"", "&quot;");
+            //str = str.Replace(" ", "&nbsp;");
+            str = str.Replace("<", "&lt;");
+            str = str.Replace(">", "&gt;");
+            str = str.Replace("(", "(");
+            str = str.Replace(")", ")");
+            str = ToDBC(str);
+            return str;
+        }
+
+        public static string unCheckString(string str)
+        {
+            if (str == null || str == string.Empty)
+            {
+                return "";
+            }
+            str = str.Replace("&acute;", "'");
+            str = str.Replace("&quot;", "\"");
+            //str = str.Replace("&nbsp;", " ");
+            str = str.Replace("&lt;", "<");
+            str = str.Replace("&gt;", ">");
+            str = str.Replace("(", "(");
+            str = str.Replace(")", ")");
+            return str;
+        }
+
+        public static string CheckString2(string str)
+        {
+            if (str == null || str == string.Empty)
+            {
+                return "";
+            }
+            str = ToDBC(str);
+            str = Regex.Replace(str, @"<script.*?>[\s\S]*?</script>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<script.*?>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<object.*?>[\s\S]*?</object>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<object.*?>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<iframe.*?>[\s\S]*?</iframe>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<frameset.*?>[\s\S]*?</frameset>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<frameset.*?>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<frame.*?>[\s\S]*?</frame>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<frame.*?>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<form.*?>[\s\S]*?</form>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<input.*?>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<select.*?>[\s\S]*?</select>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<textarea.*?>[\s\S]*?</textarea>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<button.*?>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<noframes.*?>[\s\S]*?</noframes>", "", RegexOptions.IgnoreCase);
+            str = Regex.Replace(str, @"<noframes.*?>", "", RegexOptions.IgnoreCase);
+            return str;
+        }
+
+        public static string GetSession(HttpContext context, string strName)
+        {
+            var value = context.Session.GetString(strName);
+            if (string.IsNullOrEmpty(value))
+            {
+                value = "";
+            }
+            return value;
+        }
+
+        public static void WriteSession(HttpContext context, string strName, string strValue)
+        {
+            context.Session.SetString(strName, strValue);
+        }
+
+        public static void DelSession(HttpContext context, string strName)
+        {
+            context.Session.Remove(strName);
+        }
+
+        public static string rootIndex = System.AppDomain.CurrentDomain.BaseDirectory;
+        private static string Read(string absoluteFileLocation)
+        {
+            string result = "";
+            if (System.IO.File.Exists(absoluteFileLocation))
+            {
+                using (FileStream fs = new FileStream(absoluteFileLocation, FileMode.Open, FileAccess.Read))
+                {
+                    using (StreamReader sr = new StreamReader(fs, System.Text.Encoding.UTF8))
+                    {
+                        try
+                        {
+                            result = sr.ReadToEnd();
+                            //dbconn.InsertCache(absoluteFileLocation, result, 30);
+                        }
+                        catch
+                        { }
+                    }
+                }
+            }
+            return result;
+        }
+
+        public static string getPath(string path_str)
+        {
+            string result = AppContext.BaseDirectory + path_str;
+            return result;
+        }
+
+        public static string ReadInstance(string path_str)
+        {
+            //string path = System.IO.Path.Combine(rootIndex, path_str).Replace('/', System.IO.Path.DirectorySeparatorChar);
+            string path = getPath(path_str);
+            string content = "";
+            content = Read(path);
+            return content;
+        }
+        public static string ReadInstanceNoAuth(string path_str)
+        {
+            //string path = System.IO.Path.Combine(rootIndex, path_str).Replace('/', System.IO.Path.DirectorySeparatorChar);
+            string path = getPath(path_str);
+            string content = "";
+            content = Read(path);
+            return content;
+        }
+
+        public static string ReadInstanceByFull(string path_str)
+        {
+            string content = "";
+            content = Read(path_str);
+            return content;
+        }
+
+        public static void WritePage(string path_str, string file_name, string page_content)
+        {
+            try
+            {
+                string path = getPath(path_str);
+                if (!Directory.Exists(path))
+                {
+                    Directory.CreateDirectory(path);
+                }
+                Encoding nobom = new UTF8Encoding(false, false);
+                StreamWriter sw = new StreamWriter(path + "/" + file_name, false, nobom);
+                sw.Write(page_content);
+                sw.Flush();
+                sw.Dispose();
+            }
+            catch
+            { }
+        }
+
+        public static void WritePageFullPath(string path_str, string file_name, string page_content)
+        {
+            try
+            {
+                if (!Directory.Exists(path_str))
+                {
+                    Directory.CreateDirectory(path_str);
+                }
+                Encoding nobom = new UTF8Encoding(false, false);
+                StreamWriter sw = new StreamWriter(path_str + file_name, false, nobom);
+                sw.Write(page_content);
+                sw.Flush();
+                sw.Dispose();
+            }
+            catch
+            { }
+        }
+
+        public static void send_email(string mailTitle, string mailTo, string mailContent, string file_path, string host, int port, string username, string pwd, string displayname)
+        {
+            try
+            {
+                MailAddress from = new MailAddress(username, displayname); //邮件的发件人
+                MailMessage mail = new MailMessage();
+                //设置邮件的标题
+                mail.Subject = mailTitle;
+                mail.SubjectEncoding = Encoding.UTF8;
+                //设置邮件的发件人
+                //Pass:如果不想显示自己的邮箱地址,这里可以填符合mail格式的任意名称,真正发mail的用户不在这里设定,这个仅仅只做显示用
+                mail.From = from;
+                //设置邮件的收件人
+                string address = "";
+                string displayName = "";
+                /**/
+                /*  这里这样写是因为可能发给多个联系人,每个地址用 ; 号隔开
+                一般从地址簿中直接选择联系人的时候格式都会是 :用户名1 < mail1 >; 用户名2 < mail 2>; 
+                因此就有了下面一段逻辑不太好的代码
+                如果永远都只需要发给一个收件人那么就简单了 mail.To.Add("收件人mail");
+                */
+                string[] mailNames = (mailTo + ";").Split(';');
+                foreach (string name in mailNames)
+                {
+                    if (name != string.Empty)
+                    {
+                        if (name.IndexOf('<') > 0)
+                        {
+                            displayName = name.Substring(0, name.IndexOf('<'));
+                            address = name.Substring(name.IndexOf('<') + 1).Replace('>', ' ');
+                        }
+                        else
+                        {
+                            displayName = string.Empty;
+                            address = name.Substring(name.IndexOf('<') + 1).Replace('>', ' ');
+                        }
+                        mail.To.Add(new MailAddress(address, displayName));
+                    }
+                }
+
+                //设置邮件的抄送收件人
+                //这个就简单多了,如果不想快点下岗重要文件还是CC一份给领导比较好
+                //mail.CC.Add(new MailAddress("Manage@hotmail.com", "尊敬的领导"));
+
+                //设置邮件的内容
+                mail.Body = mailContent;
+                //设置邮件的格式
+                mail.BodyEncoding = Encoding.UTF8;
+                mail.IsBodyHtml = true;
+                //设置邮件的发送级别
+                mail.Priority = MailPriority.Normal;
+                //设置邮件的附件,将在客户端选择的附件先上传到服务器保存一个,然后加入到mail中
+                //string fileName = file_path;
+                //fileName = "D:/UpFile/" + fileName.Substring(fileName.LastIndexOf("/") + 1);
+                //txtUpFile.PostedFile.SaveAs(fileName); // 将文件保存至服务器
+                //mail.Attachments.Add(new Attachment(fileName));
+                mail.DeliveryNotificationOptions = DeliveryNotificationOptions.OnSuccess;
+                SmtpClient client = new SmtpClient();
+                //设置用于 SMTP 事务的主机的名称,填IP地址也可以了
+                //client.Host = "smtp.163.com";
+                client.Host = host;
+                //设置用于 SMTP 事务的端口,默认的是 25
+                //client.Port = 25;
+                client.Port = port;
+                client.UseDefaultCredentials = false;
+                client.EnableSsl = true;
+                //这里才是真正的邮箱登陆名和密码,比如我的邮箱地址是 hbgx@hotmail, 我的用户名为 hbgx ,我的密码是 xgbh
+                client.Credentials = new System.Net.NetworkCredential(username, pwd);
+                client.DeliveryMethod = SmtpDeliveryMethod.Network;
+                client.Send(mail);
+            }
+            catch (Exception ex)
+            {
+                Function.WriteLog(ex.ToString());
+            }
+        }
+
+        public static string GetWebRequest(string url)
+        {
+            return GetWebRequest(url, new Dictionary<string, string>());
+        }
+
+        public static string GetWebRequest(string url, Dictionary<string, string> header)
+        {
+            string result = "";
+            try
+            {
+                HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(url);
+                webReq.Method = "GET";
+                webReq.KeepAlive = true;
+                webReq.Timeout = 1200000;
+                webReq.ContentType = "text/html";//application/x-www-form-urlencoded
+                if (header.Count > 0)
+                {
+                    foreach (string key in header.Keys)
+                    {
+                        webReq.Headers.Add(key, header[key]);
+                    }
+                }
+                webReq.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
+                using (HttpWebResponse response = (HttpWebResponse)webReq.GetResponse())
+                {
+                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
+                    {
+                        result = reader.ReadToEnd();
+                        //function.WriteLog(context.Request.QueryString["mobile"] + "  " + reader.ReadToEnd());
+                    }
+                    if (response != null)
+                        response.Close();
+                }
+            }
+            catch (Exception ex)
+            {
+                result = ex.ToString();
+            }
+            return result;
+        }
+
+        public static string get_Random(int num)
+        {
+            string[] str = new string[num];
+            string serverCode = "";
+            //生成随机生成器 
+            Random random = new Random(GetRandomSeed());
+            for (int i = 0; i < num; i++)
+            {
+                str[i] = random.Next(10).ToString().Substring(0, 1);
+            }
+            foreach (string s in str)
+            {
+                serverCode += s;
+            }
+            return serverCode;
+        }
+
+        public static int get_Random(int min, int max)
+        {
+            int serverCode = 0;
+            Random random = new Random(GetRandomSeed());
+            serverCode = random.Next(max - min) + min;
+            return serverCode;
+        }
+
+        public static string get_Random_string(int count)
+        {
+            string str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+            string result = "";
+            for (int i = 0; i < count; i++)
+            {
+                Random r = new Random(GetRandomSeed());
+                int serverCode = r.Next(str.Length - 0) + 0;
+                result += str.Substring(serverCode, 1);
+            }
+            return result;
+        }
+
+        public static int GetRandomSeed()
+        {
+            //字节数组,用于存储
+            byte[] bytes = new byte[4];
+            //创建加密服务,实现加密随机数生成器
+            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
+            //加密数据存入字节数组
+            rng.GetBytes(bytes);
+            //转成整型数据返回,作为随机数生成种子
+            return BitConverter.ToInt32(bytes, 0);
+        }
+
+        public static string get_weekday(DateTime date)
+        {
+            string[] week = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
+            return week[(int)date.DayOfWeek];
+        }
+
+        public static string get_substr(string s, int length)
+        {
+            byte[] bytes = System.Text.Encoding.Unicode.GetBytes(s);
+            int n = 0;  //  表示当前的字节数
+            int i = 0;  //  要截取的字节数
+            for (; i < bytes.GetLength(0) && n < length; i++)
+            {
+                //  偶数位置,如0、2、4等,为UCS2编码中两个字节的第一个字节
+                if (i % 2 == 0)
+                {
+                    n++;      //  在UCS2第一个字节时n加1
+                }
+                else
+                {
+                    //  当UCS2编码的第二个字节大于0时,该UCS2字符为汉字,一个汉字算两个字节
+                    if (bytes[i] > 0)
+                    {
+                        n++;
+                    }
+                }
+            }
+            //  如果i为奇数时,处理成偶数
+            if (i % 2 == 1)
+            {
+                //  该UCS2字符是汉字时,去掉这个截一半的汉字 
+                if (bytes[i] > 0)
+                    i = i - 1;
+                //  该UCS2字符是字母或数字,则保留该字符
+                else
+                    i = i + 1;
+            }
+            return System.Text.Encoding.Unicode.GetString(bytes, 0, i);
+        }
+
+        public static DateTime ConvertIntDateTime(double d)
+        {
+            DateTime time = DateTime.MinValue;
+            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
+            time = startTime.AddSeconds(d);
+            return time;
+        }
+
+        public static DateTime ConvertIntDateTimeMini(long TimeStamp)
+        {
+            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); // 当地时区
+            return startTime.AddTicks(TimeStamp * 10000);
+        }
+
+        public static int ConvertDateTimeInt(DateTime time)
+        {
+            double intResult = 0;
+            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
+            TimeSpan ts = time - startTime;
+            intResult = Math.Round(ts.TotalSeconds, 0);
+            return int.Parse(intResult.ToString());
+        }
+
+        public static long GetCurTimestamp()
+        {
+            var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
+            long times = Convert.ToInt64(ts.TotalMilliseconds);
+            return times;
+        }
+
+        public static DateTime checkDateTimeNull(DateTime? datetime)
+        {
+            if (datetime != null)
+            {
+                return datetime.Value;
+            }
+            return DateTime.Now;
+        }
+
+        public static bool IsDate(string datetime)
+        {
+            DateTime check = DateTime.Now;
+            return DateTime.TryParse(datetime + " 00:00:00", out check);
+        }
+
+        public static bool IsDateTime(string datetime)
+        {
+            DateTime check = DateTime.Now;
+            return DateTime.TryParse(datetime, out check);
+        }
+
+        /// <summary>  
+        /// 获取时间戳  
+        /// </summary>  
+        /// <returns></returns>  
+        public static string getTimeStamp()
+        {
+            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
+            return Convert.ToInt64(ts.TotalSeconds).ToString();
+        }
+
+        public static string get_timespan(DateTime s, string show_type)
+        {
+            string result = get_timespan(s, DateTime.Now, show_type);
+            return result;
+        }
+
+        public static string get_timespan(DateTime s, DateTime e, string show_type)
+        {
+            string result = "";
+            if (e > s)
+            {
+                int total = 0;
+                TimeSpan ts = e - s;
+                switch (show_type)
+                {
+                    case "d":
+                        result = ts.Days.ToString() + "天";
+                        break;
+                    case "h":
+                        if (ts.Days > 0)
+                        {
+                            total += ts.Days * 24;
+                        }
+                        total += ts.Hours;
+                        result = total.ToString() + "小时";
+                        break;
+                    case "m":
+                        if (ts.Days > 0)
+                        {
+                            total += ts.Days * 24 * 60;
+                        }
+                        if (ts.Hours > 0)
+                        {
+                            total += ts.Hours * 60;
+                        }
+                        total += ts.Hours;
+                        result = total.ToString() + "分钟";
+                        break;
+                    case "s":
+                        if (ts.Days > 0)
+                        {
+                            total += ts.Days * 24 * 60 * 60;
+                        }
+                        if (ts.Hours > 0)
+                        {
+                            total += ts.Hours * 60 * 60;
+                        }
+                        if (ts.Minutes > 0)
+                        {
+                            total += ts.Hours * 60;
+                        }
+                        total += ts.Hours;
+                        result = total.ToString() + "秒";
+                        break;
+                    case "time":
+                        if (ts.Days > 1)
+                        {
+                            result = s.ToString("yyyy-MM-dd");
+                        }
+                        else
+                        {
+                            if (ts.Days > 0)
+                            {
+                                result += ts.Days + "天";
+                            }
+                            if (ts.Hours > 0)
+                            {
+                                result += ts.Hours + "小时";
+                            }
+                            if (ts.Minutes > 0)
+                            {
+                                result += ts.Minutes + "分钟";
+                            }
+                            if (string.IsNullOrEmpty(result))
+                            {
+                                result = "刚刚";
+                            }
+                            else
+                            {
+                                result += "前";
+                            }
+                        }
+                        break;
+                    default: break;
+                }
+            }
+            return result;
+        }
+
+        // 半角转全角
+        public static string ToSBC(string input)
+        {
+            char[] c = input.ToCharArray();
+            for (int i = 0; i < c.Length; i++)
+            {
+                if (c[i] == 32)
+                {
+                    c[i] = (char)12288;
+                    continue;
+                }
+                if (c[i] < 127)
+                    c[i] = (char)(c[i] + 65248);
+            }
+            return new string(c);
+        }
+
+        // 全角转半角
+        public static string ToDBC(string input)
+        {
+            char[] c = input.ToCharArray();
+            for (int i = 0; i < c.Length; i++)
+            {
+                if (c[i] == 12288)
+                {
+                    c[i] = (char)32;
+                    continue;
+                }
+                if (c[i] > 65280 && c[i] < 65375)
+                    c[i] = (char)(c[i] - 65248);
+            }
+            return new string(c);
+        }
+
+        public static string PostWebRequest(string postUrl, string paramData, string ContentType = "application/x-www-form-urlencoded")
+        {
+            //return PostWebRequest(postUrl, paramData, new Dictionary<string, string>());
+            string ret = string.Empty;
+            try
+            {
+                byte[] postData = Encoding.UTF8.GetBytes(paramData);
+                // 设置提交的相关参数 
+                HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
+                Encoding myEncoding = Encoding.UTF8;
+                request.Method = "POST";
+                request.KeepAlive = false;
+                request.AllowAutoRedirect = true;
+                request.ContentType = ContentType;
+                //request.ContentType = "multipart/form-data; boundary=" + boundary;
+                request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR  3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)";
+                request.ContentLength = postData.Length;
+
+                // 提交请求数据 
+                System.IO.Stream outputStream = request.GetRequestStream();
+                outputStream.Write(postData, 0, postData.Length);
+                outputStream.Close();
+
+                HttpWebResponse response;
+                Stream responseStream;
+                StreamReader reader;
+                string srcString;
+                response = request.GetResponse() as HttpWebResponse;
+                responseStream = response.GetResponseStream();
+                reader = new System.IO.StreamReader(responseStream, Encoding.UTF8);
+                srcString = reader.ReadToEnd();
+                ret = srcString;   //返回值赋值
+                reader.Close();
+            }
+            catch (Exception ex)
+            {
+                ret = "fail";
+                WriteLog(ex.ToString(), "PostWebRequest");
+            }
+            return ret;
+        }
+
+        public static string PostWebRequest(string postUrl, string paramData, Dictionary<string, string> header, string ContentType = "application/x-www-form-urlencoded")
+        {
+            //return PostWebRequest(postUrl, paramData, new Dictionary<string, string>());
+            string ret = string.Empty;
+            try
+            {
+                byte[] postData = Encoding.UTF8.GetBytes(paramData);
+                // 设置提交的相关参数 
+                HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
+                Encoding myEncoding = Encoding.UTF8;
+                request.Method = "POST";
+                request.KeepAlive = false;
+                request.AllowAutoRedirect = true;
+                request.ContentType = ContentType;
+                //request.ContentType = "multipart/form-data; boundary=" + boundary;
+                request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR  3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)";
+                request.ContentLength = postData.Length;
+                if (header.Count > 0)
+                {
+                    foreach (string key in header.Keys)
+                    {
+                        request.Headers.Add(key, header[key]);
+                    }
+                }
+
+                // 提交请求数据 
+                System.IO.Stream outputStream = request.GetRequestStream();
+                outputStream.Write(postData, 0, postData.Length);
+                outputStream.Close();
+
+                HttpWebResponse response;
+                Stream responseStream;
+                StreamReader reader;
+                string srcString;
+                response = request.GetResponse() as HttpWebResponse;
+                responseStream = response.GetResponseStream();
+                reader = new System.IO.StreamReader(responseStream, Encoding.UTF8);
+                srcString = reader.ReadToEnd();
+                ret = srcString;   //返回值赋值
+                reader.Close();
+            }
+            catch (Exception ex)
+            {
+                ret = "fail";
+                WriteLog(ex.ToString(), "PostWebRequest");
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// 从ftp服务器上获得文件夹列表
+        /// </summary>
+        /// <param name="RequedstPath">服务器下的相对路径</param>
+        /// <returns></returns>
+        public static List<string> GetFtpDirctoryList(string path, string username, string password)
+        {
+            List<string> strs = new List<string>();
+            try
+            {
+                string uri = path;   //目标路径 path为服务器地址
+                FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
+                // ftp用户名和密码
+                reqFTP.Credentials = new NetworkCredential(username, password);
+                reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
+                WebResponse response = reqFTP.GetResponse();
+                StreamReader reader = new StreamReader(response.GetResponseStream());//中文文件名
+ 
+                string line = reader.ReadLine();
+                while (line != null)
+                {
+                    if (line.Contains("<DIR>"))
+                    {
+                        string msg = line.Substring(line.LastIndexOf("<DIR>") + 5).Trim();
+                        strs.Add(msg);
+                    }
+                    line = reader.ReadLine();
+                }
+                reader.Close();
+                response.Close();
+                return strs;
+            }
+            catch (Exception ex)
+            {
+                Function.WriteLog(DateTime.Now + ":" + ex.ToString(), "从ftp服务器上获得文件夹列表异常");
+            }
+            return strs;
+        }
+ 
+        /// <summary>
+        /// 从ftp服务器上获得文件列表
+        /// </summary>
+        /// <param name="RequedstPath">服务器下的相对路径</param>
+        /// <returns></returns>
+        public static List<string> GetFtpFileList(string path, string username, string password)
+        {
+            List<string> strs = new List<string>();
+            try
+            {
+                string uri = path;   //目标路径 path为服务器地址
+                FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
+                // ftp用户名和密码
+                reqFTP.Credentials = new NetworkCredential(username, password);
+                reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
+                WebResponse response = reqFTP.GetResponse();
+                StreamReader reader = new StreamReader(response.GetResponseStream());//中文文件名
+ 
+                string line = reader.ReadLine();
+                while (line != null)
+                {
+                    if (!line.Contains("<DIR>"))
+                    {
+                        string msg = line.Substring(39).Trim();
+                        strs.Add(msg);
+                    }
+                    line = reader.ReadLine();
+                }
+                reader.Close();
+                response.Close();
+                return strs;
+            }
+            catch (Exception ex)
+            {
+                Function.WriteLog(DateTime.Now + ":" + ex.ToString(), "从ftp服务器上获得文件列表异常");
+            }
+            return strs;
+        }
+        //从ftp服务器上下载文件
+        public static string FtpDownload(string path, string fileName, string username, string password)
+        {
+            FtpWebRequest reqFTP;
+            string savePath = "";
+            try
+            {
+                string filePath = getPath("/FtpDownloadFile/" + fileName);
+                FileStream outputStream = new FileStream(filePath, FileMode.Create);
+                reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(path + fileName));
+                reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
+                reqFTP.UseBinary = true;
+                reqFTP.Credentials = new NetworkCredential(username, password);
+                reqFTP.UsePassive = false;
+                FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
+                Stream ftpStream = response.GetResponseStream();
+                long cl = response.ContentLength;
+                int bufferSize = 2048;
+                int readCount;
+                byte[] buffer = new byte[bufferSize];
+                readCount = ftpStream.Read(buffer, 0, bufferSize);
+                while (readCount > 0)
+                {
+                    outputStream.Write(buffer, 0, readCount);
+                    readCount = ftpStream.Read(buffer, 0, bufferSize);
+                }
+                ftpStream.Close();
+                outputStream.Close();
+                response.Close();
+                savePath = "/FtpDownloadFile/" + fileName;
+            }
+            catch (Exception ex)
+            {
+                Function.WriteLog(DateTime.Now + ":" + ex.ToString(), "从ftp服务器上下载文件异常");
+            }
+            return savePath;
+        } 
+
+        public static string base64StringToImage(string base64String, string path, string filename)
+        {
+            string fullpath = getPath(path);
+            if (!System.IO.Directory.Exists(fullpath))
+            {
+                System.IO.Directory.CreateDirectory(fullpath);
+            }
+            byte[] arr = Convert.FromBase64String(base64String);
+            System.IO.File.WriteAllBytes(fullpath + filename, arr);
+            return path + filename;
+        }
+
+        public static String BuildQueryString(SortedList<String, String> kvp)
+        {
+            return String.Join("&", kvp.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
+        }
+
+
+
+        #region 获取网络文件内容
+
+        public static string GetNetFileContent(string url)
+        {
+            string textContent = "";     
+            using (var client = new WebClient())
+            {
+                try
+                {
+                    textContent = client.DownloadString(url); // 通过 DownloadString 方法获取网页内容
+                }
+                catch (Exception ex)
+                {
+                    WriteLog(DateTime.Now.ToString() + "\n" + url + "\n" + ex.ToString() + "\n\n", "获取网络文件内容异常");
+                }
+            }
+            return textContent;
+        }
+
+        public static byte[] GetNetFileData(string url)
+        {
+            byte[] textContent = new byte[] { };
+            using (var client = new WebClient())
+            {
+                try
+                {
+                    textContent = client.DownloadData(url); // 通过 DownloadString 方法获取网页内容
+                }
+                catch (Exception ex)
+                {
+                    WriteLog(DateTime.Now.ToString() + "\n" + ex.ToString() + "\n\n", "获取网络文件流异常");
+                }
+            }
+            return textContent;
+        }
+
+        #endregion
+    }
+}

+ 37 - 0
Common/JsonConverterUtil.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Util
+{
+    public class JsonConverterUtil
+    {
+        public class DateTimeNullConverter : JsonConverter<DateTime?>
+        {
+            public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+                => string.IsNullOrEmpty(reader.GetString()) ? default : ParseDateTime(reader.GetString());
+
+            public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
+                => writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm:ss"));
+        }
+
+        public class DateTimeConverter : JsonConverter<DateTime>
+        {
+            public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+            {
+                var dateTime = ParseDateTime(reader.GetString());
+                return dateTime == null ? DateTime.MinValue : dateTime.Value;
+            }
+
+            public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
+                => writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
+        }
+
+        public static DateTime? ParseDateTime(string dateStr)
+        {
+            if (System.Text.RegularExpressions.Regex.IsMatch(dateStr, @"^\d{4}[/-]") && DateTime.TryParse(dateStr, null, System.Globalization.DateTimeStyles.AssumeLocal, out var dateVal))
+                return dateVal;
+            return null;
+        }
+    }
+}

+ 167 - 0
Common/JwtUtil.cs

@@ -0,0 +1,167 @@
+using Base;
+using Extensions;
+using Infrastructure.Model;
+using Microsoft.IdentityModel.Tokens;
+using Model.Base;
+using Newtonsoft.Json;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+
+namespace Util
+{
+    /// <summary>
+    /// 2023-8-29已从WebApi移至此
+    /// </summary>
+    public class JwtUtil
+    {
+        /// <summary>
+        /// 获取用户身份信息
+        /// </summary>
+        /// <param name="httpContext"></param>
+        /// <returns></returns>
+        public static TokenModel GetLoginUser(HttpContext httpContext)
+        {
+            string token = httpContext.GetToken();
+
+            if (!string.IsNullOrEmpty(token))
+            {
+                return ValidateJwtToken(ParseToken(token));
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 生成token
+        /// </summary>
+        /// <param name="claims"></param>
+        /// <returns></returns>
+        public static string GenerateJwtToken(List<Claim> claims)
+        {
+            JwtSettings jwtSettings = new();
+            AppSettings.Bind("JwtSettings", jwtSettings);
+
+            var authTime = DateTime.Now;
+            var expiresAt = authTime.AddMinutes(jwtSettings.Expire);
+            var tokenHandler = new JwtSecurityTokenHandler();
+            var key = Encoding.ASCII.GetBytes(jwtSettings.SecretKey);
+            claims.Add(new Claim("Audience", jwtSettings.Audience));
+            claims.Add(new Claim("Issuer", jwtSettings.Issuer));
+
+            var tokenDescriptor = new SecurityTokenDescriptor
+            {
+                Subject = new ClaimsIdentity(claims),
+                Issuer = jwtSettings.Issuer,
+                Audience = jwtSettings.Audience,
+                IssuedAt = authTime,//token生成时间
+                Expires = expiresAt,
+                //NotBefore = authTime,
+                TokenType = jwtSettings.TokenType,
+                //对称秘钥,签名证书
+                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
+            };
+            var token = tokenHandler.CreateToken(tokenDescriptor);
+            return tokenHandler.WriteToken(token);
+        }
+        /// <summary>
+        /// 验证Token
+        /// </summary>
+        /// <returns></returns>
+        public static TokenValidationParameters ValidParameters()
+        {
+            JwtSettings jwtSettings = new();
+            AppSettings.Bind("JwtSettings", jwtSettings);
+
+            if (jwtSettings == null || jwtSettings.SecretKey.IsEmpty())
+            {
+                throw new Exception("JwtSettings获取失败");
+            }
+            var key = Encoding.ASCII.GetBytes(jwtSettings.SecretKey);
+
+            var tokenDescriptor = new TokenValidationParameters
+            {
+                ValidateIssuerSigningKey = true,
+                ValidateIssuer = true,
+                ValidateAudience = true,
+                ValidIssuer = jwtSettings.Issuer,
+                ValidAudience = jwtSettings.Audience,
+                IssuerSigningKey = new SymmetricSecurityKey(key),
+                ValidateLifetime = true,//是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
+                ClockSkew = TimeSpan.FromSeconds(30)
+                //RequireExpirationTime = true,//过期时间
+            };
+            return tokenDescriptor;
+        }
+        /// <summary>
+        /// 从令牌中获取数据声明
+        /// </summary>
+        /// <param name="token">令牌</param>
+        /// <returns></returns>
+        public static JwtSecurityToken? ParseToken(string token)
+        {
+            var tokenHandler = new JwtSecurityTokenHandler();
+            var validateParameter = ValidParameters();
+            token = token.Replace("Bearer ", "");
+            try
+            {
+                tokenHandler.ValidateToken(token, validateParameter, out SecurityToken validatedToken);
+
+                return tokenHandler.ReadJwtToken(token);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                // return null if validation fails
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// jwt token校验
+        /// </summary>
+        /// <param name="jwtSecurityToken"></param>
+        /// <returns></returns>
+        public static TokenModel? ValidateJwtToken(JwtSecurityToken jwtSecurityToken)
+        {
+            try
+            {
+                if (jwtSecurityToken == null) return null;
+                IEnumerable<Claim> claims = jwtSecurityToken?.Claims;
+                TokenModel loginUser = null;
+
+                var userData = claims.FirstOrDefault(x => x.Type == ClaimTypes.UserData)?.Value;
+                if (userData != null)
+                {
+                    loginUser = JsonConvert.DeserializeObject<TokenModel>(userData);
+                    loginUser.ExpireTime = jwtSecurityToken.ValidTo;
+                }
+                return loginUser;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return null;
+            }
+        }
+
+        /// <summary>
+        ///组装Claims
+        /// </summary>
+        /// <param name="user"></param>
+        /// <returns></returns>
+        public static List<Claim> AddClaims(TokenModel user)
+        {
+            var claims = new List<Claim>()
+                {
+                    new(ClaimTypes.PrimarySid, user.userId.ToString()),
+                    new(ClaimTypes.NameIdentifier, user.userId.ToString()),
+                    new(ClaimTypes.Name, user.username),
+                    new(ClaimTypes.GroupSid, user.deptId.ToString()),
+                    new(ClaimTypes.UserData, JsonConvert.SerializeObject(user))
+                };
+
+            return claims;
+        }
+
+    }
+}

+ 48 - 0
Common/StringConverter.cs

@@ -0,0 +1,48 @@
+using System;
+using System.Buffers;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+
+namespace Util
+{
+    /// <summary>
+    /// Json任何类型读取到字符串属性
+    /// 因为 System.Text.Json 必须严格遵守类型一致,当非字符串读取到字符属性时报错:
+    /// The JSON value could not be converted to System.String.
+    /// </summary>
+    public class StringConverter : System.Text.Json.Serialization.JsonConverter<string>
+    {
+        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        {
+            if (reader.TokenType == JsonTokenType.String)
+            {
+                return reader.GetString();
+            }
+            else
+            {
+                //非字符类型,返回原生内容
+                return GetRawPropertyValue(reader);
+            }
+
+            throw new JsonException();
+        }
+
+        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+        {
+            writer.WriteStringValue(value);
+        }
+        /// <summary>
+        /// 非字符类型,返回原生内容
+        /// </summary>
+        /// <param name="jsonReader"></param>
+        /// <returns></returns>
+        private static string GetRawPropertyValue(Utf8JsonReader jsonReader)
+        {
+            ReadOnlySpan<byte> utf8Bytes = jsonReader.HasValueSequence ?
+            jsonReader.ValueSequence.ToArray() :
+            jsonReader.ValueSpan;
+            return Encoding.UTF8.GetString(utf8Bytes);
+        }
+    }
+}

+ 142 - 0
Common/Tools.cs

@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Common
+{
+    public class Tools
+    {
+        /// <summary>
+        /// 要分割的字符串 eg: 1,3,10,00
+        /// </summary>
+        /// <param name="str"></param>
+        /// <param name="split">分割的字符串</param>
+        /// <returns></returns>
+        public static long[] SpitLongArrary(string str, char split = ',')
+        {
+            if (string.IsNullOrEmpty(str)) { return Array.Empty<long>(); }
+            str = str.TrimStart(split).TrimEnd(split);
+            string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries);
+            long[] infoIdss = Array.ConvertAll(strIds, s => long.Parse(s));
+            return infoIdss;
+        }
+
+        public static int[] SpitIntArrary(string str, char split = ',')
+        {
+            if (string.IsNullOrEmpty(str)) { return Array.Empty<int>(); }
+            string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries);
+            int[] infoIdss = Array.ConvertAll(strIds, s => int.Parse(s));
+            return infoIdss;
+        }
+        public static T[] SplitAndConvert<T>(string input, char split = ',')
+        {
+            if (string.IsNullOrEmpty(input)) { return Array.Empty<T>(); }
+            string[] parts = input.Split(split, (char)StringSplitOptions.RemoveEmptyEntries);
+            T[] result =  Array.ConvertAll(parts, s => (T)Convert.ChangeType(s, typeof(T)));
+            //for (int i = 0; i < parts.Length; i++)
+            //{
+            //    result[i] = (T)Convert.ChangeType(parts[i], typeof(T));
+            //}
+
+            return result;
+        }
+
+        /// <summary>
+        /// 根据日期获取星期几
+        /// </summary>
+        public static string GetWeekByDate(DateTime dt)
+        {
+            var day = new[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
+            return day[Convert.ToInt32(dt.DayOfWeek.ToString("d"))];
+        }
+
+        /// <summary>
+        /// 得到这个月的第几周
+        /// </summary>
+        /// <param name="daytime">年月日</param>
+        /// <returns>传递过来的时间是第几周</returns>
+        public static int GetWeekNumInMonth(DateTime daytime)
+        {
+            int dayInMonth = daytime.Day;
+            //本月第一天
+            DateTime firstDay = daytime.AddDays(1 - daytime.Day);
+            //本月第一天是周几
+            int weekday = (int)firstDay.DayOfWeek == 0 ? 7 : (int)firstDay.DayOfWeek;
+            //本月第一周有几天
+            int firstWeekEndDay = 7 - (weekday - 1);
+            //当前日期和第一周之差
+            int diffday = dayInMonth - firstWeekEndDay;
+            diffday = diffday > 0 ? diffday : 1;
+            //当前是第几周,如果整除7就减一天
+            int weekNumInMonth = ((diffday % 7) == 0
+                ? (diffday / 7 - 1)
+                : (diffday / 7)) + 1 + (dayInMonth > firstWeekEndDay ? 1 : 0);
+            return weekNumInMonth;
+        }
+        /// <summary>
+        /// 判断一个字符串是否为url
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static bool IsUrl(string str)
+        {
+            try
+            {
+                string Url = @"^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$";
+                return Regex.IsMatch(str, Url);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return false;
+            }
+        }
+        public static bool CheckUserName(string str)
+        {
+            try
+            {
+                string rg = @"^[a-z][a-z0-9-_]*$";
+                return Regex.IsMatch(str, rg);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 计算密码强度
+        /// </summary>
+        /// <param name="password">密码字符串</param>
+        /// <returns></returns>
+        public static bool PasswordStrength(string password)
+        {
+            //空字符串强度值为0
+            if (string.IsNullOrEmpty(password)) return false;
+
+            //字符统计
+            int iNum = 0, iLtt = 0, iSym = 0;
+            foreach (char c in password)
+            {
+                if (c >= '0' && c <= '9') iNum++;
+                else if (c >= 'a' && c <= 'z') iLtt++;
+                else if (c >= 'A' && c <= 'Z') iLtt++;
+                else iSym++;
+            }
+
+            if (iLtt == 0 && iSym == 0) return false; //纯数字密码
+            if (iNum == 0 && iLtt == 0) return false; //纯符号密码
+            if (iNum == 0 && iSym == 0) return false; //纯字母密码
+
+            if (password.Length >= 6 && password.Length < 16) return true;//长度不大于6的密码
+
+            if (iLtt == 0) return true; //数字和符号构成的密码
+            if (iSym == 0) return true; //数字和字母构成的密码
+            if (iNum == 0) return true; //字母和符号构成的密码
+
+            return true; //由数字、字母、符号构成的密码
+        }
+    }
+}

+ 134 - 0
Common/dbconn.cs

@@ -0,0 +1,134 @@
+using System;
+using System.Data;
+using System.Text;
+using System.Security.Cryptography;
+using Microsoft.Extensions.Caching.Memory;
+using System.IO;
+
+namespace Common
+{
+    public class Dbconn
+    {        
+        public static void InsertCache(string key, object val)
+        {
+            new MemoryCache(new MemoryCacheOptions()).Set(key, val, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(10)));
+        }
+
+        public static void InsertCache(string key, object val, int minutes)
+        {
+            new MemoryCache(new MemoryCacheOptions()).Set(key, val, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(minutes)));
+        }
+
+        public static void InsertCache(string key, object val, DateTime endtime)
+        {
+            new MemoryCache(new MemoryCacheOptions()).Set(key, val);
+        }
+
+        /// <summary>
+        /// des解密
+        /// </summary>
+        /// <param name="content"></param>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        public static string DesDecrypt(string content, string key = "yun1mu23")
+        {
+            try
+            {
+                content = content.Replace(" ", "+");
+                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
+                byte[] inputByteArray = Convert.FromBase64String(content);
+                des.Key = ASCIIEncoding.ASCII.GetBytes(key);
+                des.IV = ASCIIEncoding.ASCII.GetBytes(key);
+                MemoryStream ms = new MemoryStream();
+                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
+                cs.Write(inputByteArray, 0, inputByteArray.Length);
+                cs.FlushFinalBlock();
+                return System.Text.Encoding.Default.GetString(ms.ToArray());
+            }
+            catch (Exception ex)
+            {
+                Function.WriteLog(DateTime.Now.ToString() + "\r\n" + content + "\r\n" + ex.ToString(), "des解密异常");
+                return "{}";
+            }
+        }
+
+        public static string DesEncrypt(string content, string key = "yun1mu23")
+        {
+            try
+            {
+                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
+                byte[] inputByteArray = System.Text.Encoding.Default.GetBytes(content);
+                des.Key = ASCIIEncoding.ASCII.GetBytes(key);
+                des.IV = ASCIIEncoding.ASCII.GetBytes(key);
+                MemoryStream ms = new MemoryStream();
+                CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
+                cs.Write(inputByteArray, 0, inputByteArray.Length);
+                cs.FlushFinalBlock();
+                return Convert.ToBase64String(ms.ToArray());
+            }
+            catch (Exception ex)
+            {
+                Function.WriteLog(DateTime.Now.ToString() + "\r\n" + content + "\r\n" + ex.ToString(), "des加密异常");
+                return "{}";
+            }
+        }
+
+        public static string Encrypt3DES(string a_strString, string Key3des = "yun1mu23")
+        {
+            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
+            DES.Key = Encoding.UTF8.GetBytes(Key3des);
+            DES.Mode = CipherMode.ECB;
+            DES.Padding = PaddingMode.PKCS7;
+            ICryptoTransform DESEncrypt = DES.CreateEncryptor();
+            byte[] Buffer = Encoding.UTF8.GetBytes(a_strString);
+            return Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
+        }
+
+        public static string Decrypt3DES(string a_strString, string Key3des = "yun1mu23")
+        {
+            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
+            DES.Key = Encoding.UTF8.GetBytes(Key3des);
+            DES.Mode = CipherMode.ECB;
+            DES.Padding = PaddingMode.Zeros;
+            ICryptoTransform DESDecrypt = DES.CreateDecryptor();
+            byte[] Buffer = Convert.FromBase64String(a_strString);
+            return UTF8Encoding.UTF8.GetString(DESDecrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
+        }
+
+
+        public static string AesEncrypt(string str, string key, string iv)
+        {
+            if (string.IsNullOrEmpty(str)) return null;
+            Byte[] toEncryptArray = Encoding.UTF8.GetBytes(str);
+
+            System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
+            {
+                Key = Encoding.UTF8.GetBytes(key),
+                IV = Encoding.UTF8.GetBytes(iv),
+                Mode = System.Security.Cryptography.CipherMode.CBC,
+                Padding = System.Security.Cryptography.PaddingMode.PKCS7
+            };
+            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateEncryptor();
+            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
+            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
+        }
+
+        public static string AesDecrypt(string str, string key, string iv)
+        {
+            if (string.IsNullOrEmpty(str)) return null;
+            Byte[] toEncryptArray = Convert.FromBase64String(str);
+
+            System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
+            {
+                Key = Encoding.UTF8.GetBytes(key),
+                IV = Encoding.UTF8.GetBytes(iv),
+                Mode = System.Security.Cryptography.CipherMode.CBC,
+                Padding = System.Security.Cryptography.PaddingMode.PKCS7
+            };
+
+            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateDecryptor();
+            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
+            return Encoding.UTF8.GetString(resultArray);
+        }
+    }
+}

+ 145 - 0
Constant/Helper/DateTimeHelper.cs

@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Infrastructure
+{
+    public class DateTimeHelper
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="dateTime"></param>
+        /// <returns></returns>
+        public static DateTime GetBeginTime(DateTime? dateTime, int days = 0)
+        {
+            if (dateTime == DateTime.MinValue || dateTime == null)
+            {
+                return DateTime.Now.AddDays(days);
+            }
+            return dateTime ?? DateTime.Now;
+        }
+        #region 时间戳转换
+
+        /// <summary>
+        ///  时间戳转本地时间-时间戳精确到秒
+        /// </summary> 
+        public static DateTime ToLocalTimeDateBySeconds(long unix)
+        {
+            var dto = DateTimeOffset.FromUnixTimeSeconds(unix);
+            return dto.ToLocalTime().DateTime;
+        }
+
+        /// <summary>
+        ///  时间转时间戳Unix-时间戳精确到秒
+        /// </summary> 
+        public static long ToUnixTimestampBySeconds(DateTime dt)
+        {
+            DateTimeOffset dto = new DateTimeOffset(dt);
+            return dto.ToUnixTimeSeconds();
+        }
+
+        /// <summary>
+        ///  时间戳转本地时间-时间戳精确到毫秒
+        /// </summary> 
+        public static DateTime ToLocalTimeDateByMilliseconds(long unix)
+        {
+            var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix);
+            return dto.ToLocalTime().DateTime;
+        }
+
+        /// <summary>
+        ///  时间转时间戳Unix-时间戳精确到毫秒
+        /// </summary> 
+        public static long ToUnixTimestampByMilliseconds(DateTime dt)
+        {
+            DateTimeOffset dto = new DateTimeOffset(dt);
+            return dto.ToUnixTimeMilliseconds();
+        }
+
+        #endregion
+
+        #region 毫秒转天时分秒
+        /// <summary>
+        /// 毫秒转天时分秒
+        /// </summary>
+        /// <param name="ms"></param>
+        /// <returns></returns>
+        public static string FormatTime(long ms)
+        {
+            int ss = 1000;
+            int mi = ss * 60;
+            int hh = mi * 60;
+            int dd = hh * 24;
+
+            long day = ms / dd;
+            long hour = (ms - day * dd) / hh;
+            long minute = (ms - day * dd - hour * hh) / mi;
+            long second = (ms - day * dd - hour * hh - minute * mi) / ss;
+            long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
+
+            string sDay = day < 10 ? "0" + day : "" + day; //天
+            string sHour = hour < 10 ? "0" + hour : "" + hour;//小时
+            string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
+            string sSecond = second < 10 ? "0" + second : "" + second;//秒
+            string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
+            sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond;
+
+            return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond);
+        }
+        #endregion
+
+        #region 获取unix时间戳
+        /// <summary>
+        /// 获取unix时间戳(毫秒)
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static long GetUnixTimeStamp(DateTime dt)
+        {
+            long unixTime = ((DateTimeOffset)dt).ToUnixTimeMilliseconds();
+            return unixTime;
+        }
+
+        public static long GetUnixTimeSeconds(DateTime dt)
+        {
+            long unixTime = ((DateTimeOffset)dt).ToUnixTimeSeconds();
+            return unixTime;
+        }
+        #endregion
+
+        #region 获取日期天的最小时间
+        public static DateTime GetDayMinDate(DateTime dt)
+        {
+            DateTime min = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0);
+            return min;
+        }
+        #endregion
+
+        #region 获取日期天的最大时间
+        public static DateTime GetDayMaxDate(DateTime dt)
+        {
+            DateTime max = new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59);
+            return max;
+        }
+        #endregion
+
+        #region 获取日期天的最大时间
+        public static string FormatDateTime(DateTime? dt)
+        {
+            if (dt != null)
+            {
+                if (dt.Value.Year == DateTime.Now.Year)
+                {
+                    return dt.Value.ToString("MM-dd HH:mm");
+                }
+                else
+                {
+                    return dt.Value.ToString("yyyy-MM-dd HH:mm");
+                }
+            }
+            return string.Empty;
+        }
+        #endregion
+    }
+}

+ 84 - 0
Constant/HttpStatus.cs

@@ -0,0 +1,84 @@
+namespace Infrastructure.Constant
+{
+    public class HttpStatus
+    {
+        /// <summary>
+        /// 操作成功
+        /// </summary>
+        public static readonly int SUCCESS = 200;
+        /// <summary>
+        /// 对象创建成功
+        /// </summary>
+        public static readonly int CREATED = 201;
+
+        /// <summary>
+        /// 请求已经被接受
+        /// </summary>
+        public static readonly int ACCEPTED = 202;
+
+        /// <summary>
+        /// 操作已经执行成功,但是没有返回数据
+        /// </summary>
+        public static readonly int NO_CONTENT = 204;
+
+        /// <summary>
+        /// 资源已被移除
+        /// </summary>
+        public static readonly int MOVED_PERM = 301;
+
+        /// <summary>
+        /// 重定向
+        /// </summary>
+        public static readonly int SEE_OTHER = 303;
+
+        /// <summary>
+        /// 资源没有被修改
+        /// </summary>
+        public static readonly int NOT_MODIFIED = 304;
+
+        /// <summary>
+        /// 参数列表错误(缺少,格式不匹配)
+        /// </summary>
+        public static readonly int BAD_REQUEST = 400;
+
+        /// <summary>
+        /// 未授权
+        /// </summary>
+        public static readonly int UNAUTHORIZED = 401;
+
+        /// <summary>
+        /// 访问受限,授权过期
+        /// </summary>
+        public static readonly int FORBIDDEN = 403;
+
+        /// <summary>
+        /// 资源,服务未找到
+        /// </summary>
+        public static readonly int NOT_FOUND = 404;
+
+        /// <summary>
+        /// 不允许的http方法
+        /// </summary>
+        public static readonly int BAD_METHOD = 405;
+
+        /// <summary>
+        /// 资源冲突,或者资源被锁
+        /// </summary>
+        public static readonly int CONFLICT = 409;
+
+        /// <summary>
+        /// 不支持的数据,媒体类型
+        /// </summary>
+        public static readonly int UNSUPPORTED_TYPE = 415;
+
+        /// <summary>
+        /// 系统内部错误
+        /// </summary>
+        public static readonly int ERROR = 500;
+
+        /// <summary>
+        /// 接口未实现
+        /// </summary>
+        public static readonly int NOT_IMPLEMENTED = 501;
+    }
+}

+ 125 - 0
Controllers/Admin/AppSourceSetController.cs

@@ -0,0 +1,125 @@
+using Vo;
+using Microsoft.AspNetCore.Mvc;
+using Model;
+using Services;
+using Model.Base;
+using Vo.Admin;
+using Mapster;
+using Infrastructure;
+using Dto;
+
+
+namespace Controllers.Admin
+{
+    /// <summary>
+    /// AppSourceSet)Controller
+    /// </summary>
+    // [Route("${Router}$")]
+    // [ApiExplorerSettings(GroupName = "AppSourceSet")]
+    public class AppSourceSetController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IAppSourceSetService _AppSourceSetService;
+
+
+        public AppSourceSetController(IAppSourceSetService AppSourceSetService)
+        {
+            _AppSourceSetService = AppSourceSetService;
+
+        }
+
+          /// <param name="page">分页参数</param>
+        /// <summary>
+        /// 列表
+        /// </summary>
+        /// <param name="page">分页对象</param>
+        /// <param name="param">参数请求体</param>
+        /// <returns>列表</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceSet/getAppSourceSetList")]
+        public IActionResult getAppSourceSetList([FromQuery] PagerInfo page, [FromQuery] AppSourceSet param)
+        {
+            var response = _AppSourceSetService.getAppSourceSetList(page, param);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 详情
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>详情</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceSet/getAppSourceSetQuery")]
+        public IActionResult getAppSourceSetQuery([FromQuery] AppSourceSet param)
+        {
+            var response = _AppSourceSetService.GetFirst(m => m.id == param.id).Adapt<GetAppSourceSetQueryVo>();
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 同步文件
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>同步文件</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceSet/sycnFile")]
+        public IActionResult sycnFile([FromQuery] PageUpdateInfoUpdateTemplateDto parm)
+        {
+            var set = _AppSourceSetService.GetFirst(m => m.kind == parm.kind && m.projectId == parm.projectId);
+            _AppSourceSetService.sycnOssFile(set, parm.appVersion);
+            return SUCCESS("ok");
+        }
+
+
+        /// <summary>
+        /// 添加
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>添加</returns>
+        [HttpPost]
+        [Route("/v1/api/AppSourceSet/addAppSourceSet")]
+        public IActionResult addAppSourceSet([FromBody] AppSourceSetDto param)
+        {
+            var modal = param.Adapt<AppSourceSet>().ToCreate(HttpContext);
+            var response = _AppSourceSetService.InsertReturnIdentity(modal);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>修改</returns>
+        [HttpPut]
+        [Route("/v1/api/AppSourceSet/updateAppSourceSet")]
+        public IActionResult updateAppSourceSet([FromBody] AppSourceSet param)
+        {
+            var modal = param.Adapt<AppSourceSet>().ToCreate(HttpContext);
+            var response = _AppSourceSetService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="id">ID</param>
+        /// <returns>删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/AppSourceSet/deleteAppSourceSet/{id}")]
+        public IActionResult deleteAppSourceSet(int id)
+        {
+            var response = _AppSourceSetService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+
+    }
+}

+ 164 - 0
Controllers/Admin/AppSourceVersionController.cs

@@ -0,0 +1,164 @@
+using Vo;
+using Microsoft.AspNetCore.Mvc;
+using Model;
+using Services;
+using Model.Base;
+using Vo.Admin;
+using Mapster;
+using Infrastructure;
+using Common;
+using Dto;
+
+
+namespace Controllers.Admin
+{
+    /// <summary>
+    /// AppSourceVersion)Controller
+    /// </summary>
+    // [Route("${Router}$")]
+    // [ApiExplorerSettings(GroupName = "AppSourceVersion")]
+    public class AppSourceVersionController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IAppSourceSetService _AppSourceSetService;
+        private readonly IAppSourceVersionService _AppSourceVersionService;
+
+
+        public AppSourceVersionController(IAppSourceVersionService AppSourceVersionService, IAppSourceSetService AppSourceSetService)
+        {
+            _AppSourceVersionService = AppSourceVersionService;
+            _AppSourceSetService = AppSourceSetService;
+
+        }
+
+          /// <param name="page">分页参数</param>
+        /// <summary>
+        /// 列表
+        /// </summary>
+        /// <param name="page">分页对象</param>
+        /// <param name="param">参数请求体</param>
+        /// <returns>列表</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceVersion/getAppSourceVersionList")]
+        public IActionResult getAppSourceVersionList([FromQuery] PagerInfo page, [FromQuery] AppSourceVersion param)
+        {
+            var response = _AppSourceVersionService.getAppSourceVersionList(page, param.sourceId);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 详情
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>详情</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceVersion/getAppSourceVersionQuery")]
+        public IActionResult getAppSourceVersionQuery([FromQuery] AppSourceVersion param)
+        {
+            var response = _AppSourceVersionService.GetFirst(m => m.id == param.id).Adapt<GetAppSourceVersionQueryVo>();
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 添加
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>添加</returns>
+        [HttpPost]
+        [Route("/v1/api/AppSourceVersion/addAppSourceVersion")]
+        public IActionResult addAppSourceVersion([FromBody] AppSourceVersionDto param)
+        {
+            var modal = param.Adapt<AppSourceVersion>().ToCreate(HttpContext);
+            var response = _AppSourceVersionService.InsertReturnIdentity(modal);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>修改</returns>
+        [HttpPut]
+        [Route("/v1/api/AppSourceVersion/updateAppSourceVersion")]
+        public IActionResult updateAppSourceVersion([FromBody] AppSourceVersion param)
+        {
+            var modal = param.Adapt<AppSourceVersion>().ToCreate(HttpContext);
+            var response = _AppSourceVersionService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="id">ID</param>
+        /// <returns>删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/AppSourceVersion/deleteAppSourceVersion/{id}")]
+        public IActionResult deleteAppSourceVersion(int id)
+        {
+            var response = _AppSourceVersionService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+        /// <summary>
+        /// 配置文件
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>配置文件</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceVersion/getAppSourceVersionSetFile")]
+        public IActionResult getAppSourceVersionSetFile([FromQuery] AppSourceVersion param)
+        {
+            Dictionary<string, string> obj = new Dictionary<string, string>();
+            var version = _AppSourceVersionService.GetFirst(m => m.id == param.id);
+            if(version != null)
+            {
+                var set = _AppSourceSetService.GetFirst(m => m.id == version.sourceId);
+                if(set != null)
+                {
+                    string androidUrl = Function.GetWebRequest("https://filemaker.kexiaoshuang.com/noauth/pageinfo?c=android&v=" + version.appVersion + "&k=" + set.kind + "&p=" + set.projectId);
+                    string appleUrl = Function.GetWebRequest("https://filemaker.kexiaoshuang.com/noauth/pageinfo?c=ios&v=" + version.appVersion + "&k=" + set.kind + "&p=" + set.projectId);
+                    obj.Add("androidUrl", androidUrl);
+                    obj.Add("appleUrl", appleUrl);
+                }
+            }
+            return SUCCESS(obj);
+        }
+
+
+        /// <summary>
+        /// 资源文件
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>资源文件</returns>
+        [HttpGet]
+        [Route("/v1/api/AppSourceVersion/getAppSourceVersionSourceFile")]
+        public IActionResult getAppSourceVersionSourceFile([FromQuery] AppSourceVersion param)
+        {
+            Dictionary<string, string> obj = new Dictionary<string, string>();
+            var version = _AppSourceVersionService.GetFirst(m => m.id == param.id);
+            if(version != null)
+            {
+                var set = _AppSourceSetService.GetFirst(m => m.id == version.sourceId);
+                if(set != null)
+                {
+                    string staticUrl = Function.GetWebRequest("https://filemaker.kexiaoshuang.com/noauth/static?v=" + version.appVersion + "&k=" + set.kind + "&p=" + set.projectId);
+                    obj.Add("staticUrl", staticUrl);
+                }
+            }
+            return SUCCESS(obj);
+        }
+
+
+
+
+    }
+}

+ 142 - 0
Controllers/AppBottomNavsController.cs

@@ -0,0 +1,142 @@
+using Attribute;
+using Common;
+using Dto;
+using Vo;
+using Enums;
+using Filters;
+using Infrastructure;
+using Infrastructure.Model;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Middleware;
+using Model;
+using Services;
+using Model.Base;
+
+namespace Controllers
+{
+    /// <summary>
+    /// AppBottomNavs)Controller
+    /// </summary>
+    // [Route("AppBottomNavs")]
+    // [ApiExplorerSettings(GroupName = "AppBottomNavs")]
+    public class AppBottomNavsController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IAppBottomNavsService _AppBottomNavsService;
+
+
+        public AppBottomNavsController(IAppBottomNavsService AppBottomNavsService)
+        {
+            _AppBottomNavsService = AppBottomNavsService;
+
+        }
+
+        /// <summary>
+        /// app底部导航列表
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app底部导航列表</returns>
+        [HttpGet]
+        [Route("/v1/api/AppBottomNavs/list")]
+        public IActionResult List([FromQuery] AppBottomNavsListDto parm)
+        {
+            var response = _AppBottomNavsService.List(parm);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app底部导航详情
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app底部导航详情</returns>
+        [HttpGet]
+        [Route("/v1/api/AppBottomNavs/query")]
+        public IActionResult Query([FromQuery] AppBottomNavsQueryDto parm)
+        {
+            var response = _AppBottomNavsService.Queryable()
+                .First(x => x.id == parm.id)
+                .Adapt<AppBottomNavsQueryVo>() ?? new AppBottomNavsQueryVo();
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app底部导航添加
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app底部导航添加</returns>
+        [HttpPost]
+        [Route("/v1/api/AppBottomNavs/add")]
+        public IActionResult Add([FromBody] AppBottomNavsAddDto parm)
+        {
+            var modal = parm.Adapt<AppBottomNavs>().ToCreate(HttpContext);
+            var response = _AppBottomNavsService.Add(modal);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app底部导航修改
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app底部导航修改</returns>
+        [HttpPut]
+        [Route("/v1/api/AppBottomNavs/update")]
+        public IActionResult Update([FromBody] AppBottomNavsUpdateDto parm)
+        {
+            Function.WriteLog(Newtonsoft.Json.JsonConvert.SerializeObject(parm), "app底部导航修改");
+            var modal = parm.Adapt<AppBottomNavs>().ToUpdate(HttpContext);
+            var response = _AppBottomNavsService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app底部导航删除
+        /// </summary>
+        /// <param name="Id">ID</param>
+        /// <returns>app底部导航删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/AppBottomNavs/delete/{id}")]
+        public IActionResult Delete(int id)
+        {
+            var response = _AppBottomNavsService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 复制
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>复制</returns>
+        [HttpPost]
+        [Route("/v1/api/AppBottomNavs/copy")]
+        public IActionResult Copy([FromBody] CopyDto parm)
+        {
+            _AppBottomNavsService.DeleteForCopy(parm);
+            _AppBottomNavsService.Copy(parm);
+            return SUCCESS("复制成功");
+        }
+
+
+
+
+
+
+    }
+}

+ 136 - 0
Controllers/AppReportRecordController.cs

@@ -0,0 +1,136 @@
+using Vo;
+using Microsoft.AspNetCore.Mvc;
+using Model;
+using Services;
+using Model.Base;
+using Vo.Admin;
+using Mapster;
+using Infrastructure;
+
+
+namespace Controllers.Admin
+{
+    /// <summary>
+    /// AppReportRecord)Controller
+    /// </summary>
+    // [Route("${Router}$")]
+    // [ApiExplorerSettings(GroupName = "AppReportRecord")]
+    public class AppReportRecordController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IAppReportRecordService _AppReportRecordService;
+
+
+        public AppReportRecordController(IAppReportRecordService AppReportRecordService)
+        {
+            _AppReportRecordService = AppReportRecordService;
+
+        }
+
+          /// <param name="page">分页参数</param>
+        /// <summary>
+        /// 列表
+        /// </summary>
+        /// <param name="page">分页对象</param>
+        /// <param name="param">参数请求体</param>
+        /// <returns>列表</returns>
+        [HttpGet]
+        [Route("/v1/api/AppReportRecord/getAppReportRecordList")]
+        public IActionResult getAppReportRecordList([FromQuery] PagerInfo page, [FromQuery] AppReportRecord param)
+        {
+            var response = _AppReportRecordService.getAppReportRecordList(page, param);
+            return SUCCESS(response);
+        }
+        [HttpGet]
+        [Route("/noauth/tt")]
+        public IActionResult tt([FromQuery] PagerInfo page, [FromQuery] AppReportRecord param)
+        {
+            var response = _AppReportRecordService.getAppReportRecordList(page, param);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 详情
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>详情</returns>
+        [HttpGet]
+        [Route("/v1/api/AppReportRecord/getAppReportRecordQuery")]
+        public IActionResult getAppReportRecordQuery([FromQuery] AppReportRecord param)
+        {
+            var response = _AppReportRecordService.GetFirst(m => m.id == param.id).Adapt<GetAppReportRecordQueryVo>();
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 添加
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>添加</returns>
+        [HttpPost]
+        [Route("/v1/api/AppReportRecord/addAppReportRecord")]
+        public IActionResult addAppReportRecord([FromBody] AppReportRecord param)
+        {
+            param.createTime = DateTime.Now;
+            var modal = param.Adapt<AppReportRecord>().ToCreate(HttpContext);
+            var response = _AppReportRecordService.Insertable(modal).SplitTable().ExecuteReturnSnowflakeId();
+            return SUCCESS(response);
+        }
+        [HttpGet]
+        [Route("/noauth/aa")]
+        public IActionResult aa(DateTime t)
+        {
+            var modal = new AppReportRecord()
+            {
+                createTime = t,
+                appVersion = "1",
+                userTag = "1",
+                pageTitle = "1",
+                pageUrl = "1",
+                userSysInfo = "1",
+                deviceSize = "1",
+                reportType = "1",
+                reportData = "1",
+            };
+            var response = _AppReportRecordService.Insertable(modal).SplitTable().ExecuteReturnSnowflakeId();
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="param">参数请求体</param>
+        /// <returns>修改</returns>
+        [HttpPut]
+        [Route("/v1/api/AppReportRecord/updateAppReportRecord")]
+        public IActionResult updateAppReportRecord([FromBody] AppReportRecord param)
+        {
+            var modal = param.Adapt<AppReportRecord>().ToCreate(HttpContext);
+            var response = _AppReportRecordService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="id">ID</param>
+        /// <returns>删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/AppReportRecord/deleteAppReportRecord/{id}")]
+        public IActionResult deleteAppReportRecord(int id)
+        {
+            var response = _AppReportRecordService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+
+    }
+}

+ 142 - 0
Controllers/AppVersionController.cs

@@ -0,0 +1,142 @@
+using Attribute;
+using Common;
+using Dto;
+using Vo;
+using Enums;
+using Filters;
+using Infrastructure;
+using Infrastructure.Model;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Middleware;
+using Model;
+using Services;
+using Model.Base;
+
+namespace Controllers
+{
+    /// <summary>
+    /// AppVersion)Controller
+    /// </summary>
+    // [Route("AppVersion")]
+    // [ApiExplorerSettings(GroupName = "AppVersion")]
+    public class AppVersionController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IAppVersionService _AppVersionService;
+
+
+        public AppVersionController(IAppVersionService AppVersionService)
+        {
+            _AppVersionService = AppVersionService;
+
+        }
+
+        /// <summary>
+        /// app版本管理列表
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app版本管理列表</returns>
+        [HttpGet]
+        [Route("/v1/api/AppVersion/list")]
+        public IActionResult List([FromQuery] AppVersionListDto parm)
+        {
+            var response = _AppVersionService.List(parm);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app版本管理详情
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app版本管理详情</returns>
+        [HttpGet]
+        [Route("/v1/api/AppVersion/query")]
+        public IActionResult Query([FromQuery] AppVersionQueryDto parm)
+        {
+            var response = _AppVersionService.Queryable()
+                .First(x => x.id == parm.id)
+                .Adapt<AppVersionQueryVo>() ?? new AppVersionQueryVo();
+            return SUCCESS(response);
+        }
+
+        /// <summary>
+        /// app版本管理详情
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app版本管理详情</returns>
+        [HttpGet]
+        [Route("/v1/api/AppVersion/last")]
+        public IActionResult Last([FromQuery] AppVersionLastDto parm)
+        {
+            if(string.IsNullOrEmpty(parm.kind)) parm.kind = "creater";
+            var response = _AppVersionService.Queryable()
+                .Where(x => x.terminalKind == parm.terminalKind && x.kind == parm.kind)
+                .OrderByDescending(x => x.versionNum)
+                .First()
+                .Adapt<AppVersionQueryVo>() ?? new AppVersionQueryVo();
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app版本管理添加
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app版本管理添加</returns>
+        [HttpPost]
+        [Route("/v1/api/AppVersion/add")]
+        public IActionResult Add([FromBody] AppVersionAddDto parm)
+        {
+            var modal = parm.Adapt<AppVersion>().ToCreate(HttpContext);
+            var response = _AppVersionService.Add(modal);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app版本管理修改
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>app版本管理修改</returns>
+        [HttpPut]
+        [Route("/v1/api/AppVersion/update")]
+        public IActionResult Update([FromBody] AppVersionUpdateDto parm)
+        {
+            var modal = parm.Adapt<AppVersion>().ToUpdate(HttpContext);
+            var response = _AppVersionService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// app版本管理删除
+        /// </summary>
+        /// <param name="Id">ID</param>
+        /// <returns>app版本管理删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/AppVersion/delete/{id}")]
+        public IActionResult Delete(int id)
+        {
+            var response = _AppVersionService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+
+
+
+    }
+}

+ 245 - 0
Controllers/Base/BaseController.cs

@@ -0,0 +1,245 @@
+using Common;
+using Extensions;
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using MiniExcelLibs;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using System.Web;
+
+namespace Controllers
+{
+    /// <summary>
+    /// web层通用数据处理
+    /// </summary>
+    //[ApiController]
+    public class BaseController : Controller
+    {
+        public static string TIME_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";
+
+        /// <summary>
+        /// 返回成功封装
+        /// </summary>
+        /// <param name="data"></param>
+        /// <param name="timeFormatStr"></param>
+        /// <returns></returns>
+        protected IActionResult SUCCESS(object data, string timeFormatStr = "yyyy-MM-dd HH:mm:ss")
+        {
+            string jsonStr = GetJsonStr(GetApiResult(data != null ? ResultCode.SUCCESS : ResultCode.NO_DATA, data), timeFormatStr);
+            return Content(jsonStr, "application/json");
+        }
+
+        /// <summary>
+        /// json输出带时间格式的
+        /// </summary>
+        /// <param name="apiResult"></param>
+        /// <returns></returns>
+        protected IActionResult ToResponse(ApiResult apiResult)
+        {
+            string jsonStr = GetJsonStr(apiResult, TIME_FORMAT_FULL);
+
+            return Content(jsonStr, "application/json");
+        }
+
+        protected IActionResult ToResponse(long rows, string timeFormatStr = "yyyy-MM-dd HH:mm:ss")
+        {
+            string jsonStr = GetJsonStr(ToJson(rows), timeFormatStr);
+
+            return Content(jsonStr, "application/json");
+        }
+
+        protected IActionResult ToResponse(ResultCode resultCode, string msg = "")
+        {
+            return ToResponse(new ApiResult((int)resultCode, msg));
+        }
+
+        /// <summary>
+        /// 导出Excel
+        /// </summary>
+        /// <param name="path">完整文件路径</param>
+        /// <param name="fileName">带扩展文件名</param>
+        /// <returns></returns>
+        protected IActionResult ExportExcel(string path, string fileName)
+        {
+            //var webHostEnvironment = App.WebHostEnvironment;
+            if (!Path.Exists(path))
+            {
+                throw new CustomException(fileName + "文件不存在");
+            }
+            var stream = System.IO.File.OpenRead(path);  //创建文件流
+
+            Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
+            return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", HttpUtility.UrlEncode(fileName));
+        }
+
+        /// <summary>
+        /// 下载文件
+        /// </summary>
+        /// <param name="path"></param>
+        /// <param name="fileName">文件名,一定要带扩展名</param>
+        /// <returns></returns>
+        protected IActionResult DownFile(string path, string fileName)
+        {
+            if (!System.IO.File.Exists(path))
+            {
+                return NotFound();
+            }
+            var stream = System.IO.File.OpenRead(path);  //创建文件流
+            Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
+            return File(stream, "application/octet-stream", HttpUtility.UrlEncode(fileName));
+        }
+
+        #region 方法
+
+        /// <summary>
+        /// 响应返回结果
+        /// </summary>
+        /// <param name="rows">受影响行数</param>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        protected ApiResult ToJson(long rows, object? data = null)
+        {
+            return rows > 0 ? ApiResult.Success("success", data) : GetApiResult(ResultCode.FAIL);
+        }
+
+        /// <summary>
+        /// 全局Code使用
+        /// </summary>
+        /// <param name="resultCode"></param>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        protected ApiResult GetApiResult(ResultCode resultCode, object? data = null)
+        {
+            var msg = resultCode.GetDescription();
+
+            return new ApiResult((int)resultCode, msg, data);
+        }
+        protected ApiResult Success()
+        {
+            return GetApiResult(ResultCode.SUCCESS);
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="apiResult"></param>
+        /// <param name="timeFormatStr"></param>
+        /// <returns></returns>
+        private static string GetJsonStr(ApiResult apiResult, string timeFormatStr)
+        {
+            if (string.IsNullOrEmpty(timeFormatStr))
+            {
+                timeFormatStr = TIME_FORMAT_FULL;
+            }
+            var serializerSettings = new JsonSerializerSettings
+            {
+                // 设置为驼峰命名
+                ContractResolver = new CamelCasePropertyNamesContractResolver(),
+                DateFormatString = timeFormatStr
+            };
+
+            return JsonConvert.SerializeObject(apiResult, Formatting.None, serializerSettings);
+        }
+        #endregion
+
+        /// <summary>
+        /// 导出Excel
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="list"></param>
+        /// <param name="sheetName"></param>
+        /// <param name="fileName"></param>
+        protected string ExportExcel<T>(List<T> list, string sheetName, string fileName)
+        {
+            return ExportExcelMini(list, sheetName, fileName).Item1;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="list"></param>
+        /// <param name="sheetName"></param>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        protected (string, string) ExportExcelMini<T>(List<T> list, string sheetName, string fileName)
+        {
+            IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment));
+            string sFileName = $"{fileName}{DateTime.Now:MM-dd-HHmmss}.xlsx";
+            string fullPath = Path.Combine(webHostEnvironment.WebRootPath, "export", sFileName);
+
+            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
+
+            MiniExcel.SaveAs(fullPath, list, sheetName: sheetName);
+            return (sFileName, fullPath);
+        }
+
+        /// <summary>
+        /// 导出多个工作表(Sheet)
+        /// </summary>
+        /// <param name="sheets"></param>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        protected (string, string) ExportExcelMini(Dictionary<string, object> sheets, string fileName)
+        {
+            IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment));
+            string sFileName = $"{fileName}{DateTime.Now:MM-dd-HHmmss}.xlsx";
+            string fullPath = Path.Combine(webHostEnvironment.WebRootPath, "export", sFileName);
+
+            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
+
+            MiniExcel.SaveAs(fullPath, sheets);
+            return (sFileName, fullPath);
+        }
+
+        /// <summary>
+        /// 下载导入模板
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="list">空数据类型集合</param>
+        /// <param name="fileName">下载文件名</param>
+        /// <returns></returns>
+        protected (string, string) DownloadImportTemplate<T>(List<T> list, string fileName)
+        {
+            IWebHostEnvironment webHostEnvironment = App.WebHostEnvironment;
+            string sFileName = $"{fileName}.xlsx";
+            string fullPath = Path.Combine(webHostEnvironment.WebRootPath, "ImportTemplate", sFileName);
+
+            //不存在模板创建模板
+            if (!Directory.Exists(fullPath))
+            {
+                Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
+            }
+            if (!Path.Exists(fullPath))
+            {
+                MiniExcel.SaveAs(fullPath, list, overwriteFile: true);
+            }
+            return (sFileName, fullPath);
+        }
+
+        /// <summary>
+        /// 下载指定文件模板
+        /// </summary>
+        /// <param name="fileName">下载文件名</param>
+        /// <returns></returns>
+        protected (string, string) DownloadImportTemplate(string fileName)
+        {
+            IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment));
+            string sFileName = $"{fileName}.xlsx";
+            string fullPath = Path.Combine(webHostEnvironment.WebRootPath, "ImportTemplate", sFileName);
+
+            return (sFileName, fullPath);
+        }
+
+        #region 接口通用DES解密
+
+        protected string DesDecrypt(string content)
+        {
+            content = HttpUtility.UrlDecode(content);
+            return Dbconn.DesDecrypt(content, "&L^kg4N9");
+        }
+
+        #endregion
+    }
+}

+ 51 - 0
Controllers/Base/HomeController.cs

@@ -0,0 +1,51 @@
+using Attribute;
+using Base;
+using Common;
+using Dto;
+using Enums;
+using Filters;
+using Infrastructure;
+using Infrastructure.Model;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Middleware;
+using Model;
+using Model.Base;
+using Services;
+using Util;
+
+namespace Controllers
+{
+    /// <summary>
+    /// 主界面Controller
+    /// </summary>
+    
+    [Route("/")]
+    public class HomeController : BaseController
+    {
+
+        private readonly IAppSourceSetService _AppSourceSetService;
+
+        public HomeController(IAppSourceSetService AppSourceSetService)
+        {
+            _AppSourceSetService = AppSourceSetService;
+        }
+
+        [Route("/noauth/test1")]
+        public string test1()
+        {
+            _AppSourceSetService.sycnOssFile(new AppSourceSet()
+            {
+                kind = "creater",
+                projectId = 203,
+                host = "laikeba-uni.oss-cn-chengdu.aliyuncs.com",
+                bucketName = "test-ossforteam",
+                endPoint = "oss-cn-chengdu.aliyuncs.com",
+                accessKeyId = "LTAI5tJsPaNzqCSMCPwb8zfz",
+                accessKeySecret = "efM31Up75fQcgZ32U6xvAciagceQae",
+                path = "MERCHANT_APP",
+            }, "2.0.0");
+            return "ok";
+        }
+    }
+}

+ 139 - 0
Controllers/Client/AppController.cs

@@ -0,0 +1,139 @@
+using Attribute;
+using Common;
+using Dto;
+using Vo;
+using Enums;
+using Filters;
+using Infrastructure;
+using Infrastructure.Model;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Middleware;
+using Model;
+using Services.Client;
+using Model.Base;
+using Base;
+
+namespace Controllers
+{
+    /// <summary>
+    /// App)Controller
+    /// </summary>
+    // [Route("app")]
+    // [ApiExplorerSettings(GroupName = "App")]
+    public class AppController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IAppBottomNavsService _AppBottomNavsService;
+        private readonly IFileUpdateInfoService _FileUpdateInfoService;
+        private readonly IPageUpdateInfoService _PageUpdateInfoService;
+
+
+        public AppController(IAppBottomNavsService AppBottomNavsService,IFileUpdateInfoService FileUpdateInfoService,IPageUpdateInfoService PageUpdateInfoService)
+        {
+            _AppBottomNavsService = AppBottomNavsService;
+            _FileUpdateInfoService = FileUpdateInfoService;
+            _PageUpdateInfoService = PageUpdateInfoService;
+
+        }
+
+        /// <summary>
+        /// APP底部导航列表
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>APP底部导航列表</returns>
+        [HttpGet]
+        [Route("/v1/config/app/appBottomNavs")]
+        public IActionResult AppBottomNavs([FromQuery] AppAppBottomNavsDto parm)
+        {
+            string kind = Function.CheckNull(parm.kind);
+            if(kind.Contains("/"))
+            {
+                string[] data = kind.Split('/');
+                parm.kind = data[0];
+                parm.appVersion = data[1];
+            }
+            var response = _AppBottomNavsService.AppBottomNavs(parm);
+            response.Extra = new Dictionary<string, object>();
+            response.Extra.Add("greyStyle", "");
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// APP静态资源
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>APP静态资源</returns>
+        [HttpGet]
+        [Route("/v1/config/app/staticFiles")]
+        public IActionResult StaticFiles([FromQuery] AppStaticFilesDto parm)
+        {
+            string kind = Function.CheckNull(parm.kind);
+            if(kind.Contains("/"))
+            {
+                string[] data = kind.Split('/');
+                parm.kind = data[0];
+                parm.appVersion = data[1];
+            }
+            var response = _FileUpdateInfoService.StaticFiles(parm);
+            OssConfigs ossConfigs = new();
+            AppSettings.Bind("OssConfigs", ossConfigs);
+            foreach(var sub in response.Records)
+            {
+                sub.downloadUrl = ossConfigs.Host + "skin/app/" + parm.kind + "/" + sub.path + sub.fileName;
+                sub.dataId = Function.MD5_16(sub.id.ToString() + "123890");
+            }
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// APP页面数据检查
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>APP页面数据检查</returns>
+        [HttpGet]
+        [Route("/v1/config/app/pageInfo")]
+        public IActionResult PageInfo([FromQuery] AppPageInfoDto parm)
+        {
+            string kind = Function.CheckNull(parm.kind);
+            if(kind.Contains("/"))
+            {
+                string[] data = kind.Split('/');
+                parm.kind = data[0];
+                parm.appVersion = data[1];
+            }
+            OssConfigs ossConfigs = new();
+            AppSettings.Bind("OssConfigs", ossConfigs);
+            string modulePath = parm.modulePath + ".html";
+            var response = _PageUpdateInfoService.Queryable()
+                .First(x => x.modulePath == modulePath && x.appVersion == parm.appVersion && x.kind == parm.kind)
+                .Adapt<AppPageInfoVo>() ?? new AppPageInfoVo();
+            response.dataId = Function.MD5_16(response.id.ToString() + "123890");
+            if (parm.moduleVersion < response.moduleVersion)
+            {
+                string PagePath = "template/app/" + kind + "/" + response.modulePath;
+                string pageContent = Function.GetNetFileContent(ossConfigs.Host + PagePath);
+                response.moduleContent = pageContent; //模板内容
+            }
+            else
+            {
+                response.moduleContent = ""; //模板内容
+            }
+            return SUCCESS(response);
+        }
+
+
+
+
+
+
+    }
+}

+ 48 - 0
Controllers/Client/OssController.cs

@@ -0,0 +1,48 @@
+using Dto;
+using Vo;
+using Microsoft.AspNetCore.Mvc;
+using Aliyun.OSS;
+using System.Text;
+using System.Security.Cryptography;
+using Services.Base;
+
+namespace Controllers
+{
+    /// <summary>
+    /// App)Controller
+    /// </summary>
+    // [Route("app")]
+    // [ApiExplorerSettings(GroupName = "App")]
+    public class OssController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IOssService _OssService;
+
+
+        public OssController(IOssService OssService)
+        {
+            _OssService = OssService;
+        }
+
+        /// <summary>
+        /// 前端上传oss返回参数
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>前端上传oss返回参数</returns>
+        [HttpGet]
+        [Route("/v1/config/oss/uploadinfo")]
+        public IActionResult uploadInfo(OssUploadDto param)
+        {
+            var response = _OssService.uploadInfo(param);
+            return SUCCESS(response);
+        }
+
+
+
+
+
+
+    }
+}

+ 180 - 0
Controllers/FileUpdateInfoController.cs

@@ -0,0 +1,180 @@
+using Attribute;
+using Common;
+using Dto;
+using Vo;
+using Enums;
+using Filters;
+using Infrastructure;
+using Infrastructure.Model;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Middleware;
+using Model;
+using Services;
+using Model.Base;
+using Base;
+
+namespace Controllers
+{
+    /// <summary>
+    /// FileUpdateInfo)Controller
+    /// </summary>
+    // [Route("FileUpdateInfo")]
+    // [ApiExplorerSettings(GroupName = "FileUpdateInfo")]
+    public class FileUpdateInfoController : BaseController
+    {
+        /// <summary>
+        /// api分组接口
+        /// </summary>
+        private readonly IFileUpdateInfoService _FileUpdateInfoService;
+        private readonly IAppSourceSetService _AppSourceSetService;
+
+
+        public FileUpdateInfoController(IFileUpdateInfoService FileUpdateInfoService, IAppSourceSetService AppSourceSetService)
+        {
+            _FileUpdateInfoService = FileUpdateInfoService;
+            _AppSourceSetService = AppSourceSetService;
+        }
+
+        /// <summary>
+        /// 资源文件更新信息列表
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>资源文件更新信息列表</returns>
+        [HttpGet]
+        [Route("/v1/api/FileUpdateInfo/list")]
+        public IActionResult List([FromQuery] FileUpdateInfoListDto parm, [FromQuery] PagerInfo page)
+        {
+            var response = _FileUpdateInfoService.List(parm, page);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 资源文件更新信息详情
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>资源文件更新信息详情</returns>
+        [HttpGet]
+        [Route("/v1/api/FileUpdateInfo/query")]
+        public IActionResult Query([FromQuery] FileUpdateInfoQueryDto parm)
+        {
+            var response = _FileUpdateInfoService.Queryable()
+                .First(x => x.id == parm.id)
+                .Adapt<FileUpdateInfoQueryVo>() ?? new FileUpdateInfoQueryVo();
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 资源文件更新信息添加
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>资源文件更新信息添加</returns>
+        [HttpPost]
+        [Route("/v1/api/FileUpdateInfo/add")]
+        public IActionResult Add([FromBody] FileUpdateInfoAddDto parm)
+        {
+            var modal = parm.Adapt<FileUpdateInfo>().ToCreate(HttpContext);
+            var response = _FileUpdateInfoService.Add(modal);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 资源文件更新信息修改
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>资源文件更新信息修改</returns>
+        [HttpPut]
+        [Route("/v1/api/FileUpdateInfo/update")]
+        public IActionResult Update([FromBody] FileUpdateInfoUpdateDto parm)
+        {
+            var modal = parm.Adapt<FileUpdateInfo>().ToUpdate(HttpContext);
+            var response = _FileUpdateInfoService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 资源文件更新信息删除
+        /// </summary>
+        /// <param name="Id">ID</param>
+        /// <returns>资源文件更新信息删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/FileUpdateInfo/delete/{id}")]
+        public IActionResult Delete(int id)
+        {
+            var response = _FileUpdateInfoService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 资源文件更新信息刷新文件
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>资源文件更新信息刷新文件</returns>
+        [HttpGet]
+        [Route("/v1/api/FileUpdateInfo/updateFile")]
+        public IActionResult UpdateFile([FromQuery] FileUpdateInfoUpdateFileDto parm)
+        {
+            // parm.projectId = 203;
+            var set = _AppSourceSetService.GetFirst(m => m.kind == parm.kind && m.projectId == parm.projectId);
+            // _AppSourceSetService.sycnOssFile(set, parm.appVersion);
+            _FileUpdateInfoService.UpdateFile(parm, set);
+            return SUCCESS("ok");
+        }
+
+
+
+
+        /// <summary>
+        /// 资源文件更新信息更新版本号
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>资源文件更新信息更新版本号</returns>
+        [HttpPut]
+        [Route("/v1/api/FileUpdateInfo/upVersion")]
+        public IActionResult UpVersion([FromBody] FileUpdateInfoUpVersionDto parm)
+        {
+            var modal = _FileUpdateInfoService.GetFirst(m => m.id == parm.id);
+            modal.versionNum += 1;
+            var response = _FileUpdateInfoService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 复制
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>复制</returns>
+        [HttpPost]
+        [Route("/v1/api/FileUpdateInfo/copy")]
+        public IActionResult Copy([FromBody] CopyDto parm)
+        {
+            _FileUpdateInfoService.DeleteForCopy(parm);
+            _FileUpdateInfoService.Copy(parm);
+            return SUCCESS("复制成功");
+        }
+
+
+
+
+
+
+    }
+}

+ 265 - 0
Controllers/PageUpdateInfoController.cs

@@ -0,0 +1,265 @@
+using Attribute;
+using Common;
+using Dto;
+using Vo;
+using Enums;
+using Filters;
+using Infrastructure;
+using Infrastructure.Model;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Middleware;
+using Model;
+using Services;
+using Model.Base;
+using System.IO.Compression;
+
+namespace Controllers
+{
+    /// <summary>
+    /// PageUpdateInfo)Controller
+    /// </summary>
+    // [Route("PageUpdateInfo")]
+    // [ApiExplorerSettings(GroupName = "PageUpdateInfo")]
+    public class PageUpdateInfoController : BaseController
+    {
+        private readonly IPageUpdateInfoService _PageUpdateInfoService;
+        private readonly IAppBottomNavsService _AppBottomNavsService;
+        private readonly IFileUpdateInfoService _FileUpdateInfoService;
+        private readonly IAppSourceSetService _AppSourceSetService;
+
+
+        public PageUpdateInfoController(IPageUpdateInfoService PageUpdateInfoService, IAppBottomNavsService AppBottomNavsService, IFileUpdateInfoService FileUpdateInfoService, IAppSourceSetService AppSourceSetService)
+        {
+            _PageUpdateInfoService = PageUpdateInfoService;
+            _AppBottomNavsService = AppBottomNavsService;
+            _FileUpdateInfoService = FileUpdateInfoService;
+            _AppSourceSetService = AppSourceSetService;
+        }
+
+        /// <summary>
+        /// 页面模板更新信息列表
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板更新信息列表</returns>
+        [HttpGet]
+        [Route("/v1/api/PageUpdateInfo/list")]
+        public IActionResult List([FromQuery] PageUpdateInfoListDto parm, [FromQuery] PagerInfo page)
+        {
+            var response = _PageUpdateInfoService.List(parm, page);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 页面模板更新信息详情
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板更新信息详情</returns>
+        [HttpGet]
+        [Route("/v1/api/PageUpdateInfo/query")]
+        public IActionResult Query([FromQuery] PageUpdateInfoQueryDto parm)
+        {
+            var response = _PageUpdateInfoService.Queryable()
+                .First(x => x.id == parm.id)
+                .Adapt<PageUpdateInfoQueryVo>() ?? new PageUpdateInfoQueryVo();
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 页面模板更新信息添加
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板更新信息添加</returns>
+        [HttpPost]
+        [Route("/v1/api/PageUpdateInfo/add")]
+        public IActionResult Add([FromBody] PageUpdateInfoAddDto parm)
+        {
+            var modal = parm.Adapt<PageUpdateInfo>().ToCreate(HttpContext);
+            var response = _PageUpdateInfoService.Add(modal);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 页面模板更新信息修改
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板更新信息修改</returns>
+        [HttpPut]
+        [Route("/v1/api/PageUpdateInfo/update")]
+        public IActionResult Update([FromBody] PageUpdateInfoUpdateDto parm)
+        {
+            var modal = parm.Adapt<PageUpdateInfo>().ToUpdate(HttpContext);
+            var response = _PageUpdateInfoService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 页面模板更新信息删除
+        /// </summary>
+        /// <param name="Id">ID</param>
+        /// <returns>页面模板更新信息删除</returns>
+        [HttpDelete]
+        [Route("/v1/api/PageUpdateInfo/delete/{id}")]
+        public IActionResult Delete(int id)
+        {
+            var response = _PageUpdateInfoService.Delete(id);
+            return SUCCESS(response);
+        }
+
+
+
+
+        /// <summary>
+        /// 页面模板更新信息刷新文件
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板更新信息刷新文件</returns>
+        [HttpGet]
+        [Route("/v1/api/PageUpdateInfo/updateTemplate")]
+        public IActionResult UpdateTemplate([FromQuery] PageUpdateInfoUpdateTemplateDto parm)
+        {
+            // parm.projectId = 203;
+            var set = _AppSourceSetService.GetFirst(m => m.kind == parm.kind && m.projectId == parm.projectId);
+            // _AppSourceSetService.sycnOssFile(set, parm.appVersion);
+            _PageUpdateInfoService.UpdateTemplate(parm, set);
+            return SUCCESS("ok");
+        }
+
+
+
+
+        /// <summary>
+        /// 页面模板更新信息更新版本号码
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板更新信息更新版本号码</returns>
+        [HttpPut]
+        [Route("/v1/api/PageUpdateInfo/upVersion")]
+        public IActionResult UpVersion([FromBody] PageUpdateInfoUpVersionDto parm)
+        {
+            var modal = _PageUpdateInfoService.GetFirst(m => m.id == parm.id);
+            modal.moduleVersion += 1;
+            var response = _PageUpdateInfoService.Update(modal, true);
+            return SUCCESS(response);
+        }
+
+
+
+
+
+        /// <summary>
+        /// 生成APP配置文件
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>生成APP配置文件</returns>
+        [HttpGet]
+        [Route("/noauth/SystemSet/makeAppInitData")]
+        public string makeAppInitData([FromQuery] MakeAppInitDataDto parm)
+        {
+            string AppInfoList = _AppBottomNavsService.makeAppInitData(parm.kind, parm.appVersion);
+            // Function.WriteLog(AppInfoList);
+            string FileInfoList = _FileUpdateInfoService.makeAppInitData(parm.kind, parm.appVersion);
+            string PageInfoList = _PageUpdateInfoService.makeAppInitData(parm.kind, parm.appVersion);
+            return AppInfoList + "#cut#" + FileInfoList + "#cut#" + PageInfoList;
+        }
+
+        [HttpGet]
+        [Route("/noauth/reg")]
+        public IActionResult Register(string v = "4.4.0", string k = "creater", string c = "")
+        {
+            string appini = makeAppInitData(new MakeAppInitDataDto()
+            {
+                kind = k,
+                appVersion = v,
+            }); //Function.GetWebRequest("http://" + url + "/noauth/SystemSet/makeAppInitData?kind=" + k + "&appVersion=" + v);
+            if (!string.IsNullOrEmpty(appini))
+            {
+                if (appini.Contains("#cut#"))
+                {
+                    string[] appinidata = appini.Split(new string[] { "#cut#" }, StringSplitOptions.None);
+                    string AppInfoList = appinidata[0];
+                    string SystemSet = appinidata[1];
+                    string PageInfoList = appinidata[2];
+                    string GotoPages = appinidata[3];
+                    string LibFile = appinidata[4];
+                    AppInfoList = System.Text.RegularExpressions.Regex.Unescape(AppInfoList);
+                    SystemSet = System.Text.RegularExpressions.Regex.Unescape(SystemSet);
+                    PageInfoList = System.Text.RegularExpressions.Regex.Unescape(PageInfoList);
+                    GotoPages = System.Text.RegularExpressions.Regex.Unescape(GotoPages);
+                    LibFile = System.Text.RegularExpressions.Regex.Unescape(LibFile);
+
+                    string startPath = "";
+                    string zipPath = "";
+                    if(c == "ios")
+                    {
+                        Function.WritePage("ini", "AppInfoList.ini", AppInfoList);
+                        Function.WritePage("ini", "SystemSet.ini", SystemSet);
+                        Function.WritePage("ini", "PageInfoList.ini", PageInfoList);
+                        Function.WritePage("ini", "GotoPages.ini", GotoPages);
+                        Function.WritePage("ini", "LibFile.ini", LibFile);
+                        startPath = Function.getPath("ini");
+                        zipPath = Function.getPath("ini.zip");
+                    }
+                    else
+                    {
+                        Function.WritePage("txt", "AppInfoList.txt", AppInfoList);
+                        Function.WritePage("txt", "SystemSet.txt", SystemSet);
+                        Function.WritePage("txt", "PageInfoList.txt", PageInfoList);
+                        Function.WritePage("txt", "GotoPages.txt", GotoPages);
+                        Function.WritePage("txt", "LibFile.txt", LibFile);
+                        startPath = Function.getPath(path_str: "txt");
+                        zipPath = Function.getPath("txt.zip");
+                    }
+
+                    if(System.IO.File.Exists(zipPath))
+                    {
+                        System.IO.File.Delete(zipPath);
+                    }
+                    ZipFile.CreateFromDirectory(startPath, zipPath);
+
+                    var stream = System.IO.File.OpenRead(zipPath);
+                    return File(stream, "text/plain", Path.GetFileName(zipPath));
+                }
+            }
+            return Content("fail");
+        }
+
+        
+        /// <summary>
+        /// 页面模板复制
+        /// </summary>
+        /// <param name="parm">请求参数</param>
+        /// <returns>页面模板复制</returns>
+        [HttpPost]
+        [Route("/v1/api/PageUpdateInfo/copy")]
+        public IActionResult Copy([FromBody] CopyDto parm)
+        {
+            _PageUpdateInfoService.DeleteForCopy(parm);
+            _PageUpdateInfoService.Copy(parm);
+            return SUCCESS("复制成功");
+        }
+
+
+        [Route("/noauth/test")]
+        public string test()
+        {
+            string str = "[{\"title\":\"首页\",\"normalIcon\":\"/static/images/tab-icon1-no@3x.png\",\"selectIcon\":\"/static/images/tab-icon1-active1@3x.png\",\"normalTextColor\":\"999999\",\"selectTextColor\":\"333333\",\"pageName\":\"index1\",\"NoUrlMessage\":\"\",\"backgroudColor\":\"FFFFFF\",\"statusBarColor\":\"true\",\"showTitle\":true},{\"title\":\"工作台\",\"normalIcon\":\"/static/images/tab-icon2-no@3x.png\",\"selectIcon\":\"/static/images/tab-icon2-active1@3x.png\",\"normalTextColor\":\"999999\",\"selectTextColor\":\"333333\",\"pageName\":\"work-center1\",\"NoUrlMessage\":null,\"backgroudColor\":\"FFFFFF\",\"statusBarColor\":\"true\",\"showTitle\":true},{\"title\":\"消息\",\"normalIcon\":\"/static/images/tab-icon3-no@3x.png\",\"selectIcon\":\"/static/images/tab-icon3-active1@3x.png\",\"normalTextColor\":\"999999\",\"selectTextColor\":\"333333\",\"pageName\":\"notice-center1\",\"NoUrlMessage\":null,\"backgroudColor\":\"FFFFFF\",\"statusBarColor\":\"true\",\"showTitle\":false},{\"title\":\"我的\",\"normalIcon\":\"/static/images/tab-icon4-no@3x.png\",\"selectIcon\":\"/static/images/tab-icon4-active1@3x.png\",\"normalTextColor\":\"999999\",\"selectTextColor\":\"333333\",\"pageName\":\"user-center1\",\"NoUrlMessage\":null,\"backgroudColor\":\"FFFFFF\",\"statusBarColor\":\"true\",\"showTitle\":true}]";
+            return Dbconn.Encrypt3DES(str, "*ga34|^7");
+        }
+
+
+
+    }
+}

BIN=BIN
DLL/Aliyun.OSS.dll


+ 87 - 0
Extensions/AppServiceExtensions.cs

@@ -0,0 +1,87 @@
+using Attribute;
+using Base;
+using Services;
+using Services.Base;
+using System.Reflection;
+
+namespace Infrastructure
+{
+    /// <summary>
+    /// App服务注册
+    /// </summary>
+    public static class AppServiceExtensions
+    {
+        /// <summary>
+        /// 注册引用程序域中所有有AppService标记的类的服务
+        /// </summary>
+        /// <param name="services"></param>
+        public static void AddAppService(this IServiceCollection services)
+        {
+            // var cls = AppSettings.Get<string[]>("InjectClass");
+            // if (cls == null || cls.Length <= 0)
+            // {
+            //     throw new Exception("请更新appsettings类");
+            // }
+            // foreach (var item in cls)
+            // {
+            //     Register(services, item);
+            // }
+
+            //必须注册的service
+            // services.AddTransient<ISysOperLogService, SysOperLogService>();
+            services.AddTransient<IAppReportRecordService, AppReportRecordService>();
+            services.AddTransient<IAppSourceSetService, AppSourceSetService>();
+            services.AddTransient<IAppSourceVersionService, AppSourceVersionService>();
+
+            services.AddTransient<IAppVersionService, AppVersionService>();
+            services.AddTransient<IAppBottomNavsService, AppBottomNavsService>();
+            services.AddTransient<IPageUpdateInfoService, PageUpdateInfoService>();
+            services.AddTransient<IFileUpdateInfoService, FileUpdateInfoService>();
+            services.AddTransient<IOssService, OssService>();
+            services.AddTransient<Services.Client.IAppBottomNavsService, Services.Client.AppBottomNavsService>();
+            services.AddTransient<Services.Client.IPageUpdateInfoService, Services.Client.PageUpdateInfoService>();
+            services.AddTransient<Services.Client.IFileUpdateInfoService, Services.Client.FileUpdateInfoService>();
+        }
+
+        private static void Register(IServiceCollection services, string item)
+        {
+            Assembly assembly = Assembly.Load(item);
+            foreach (var type in assembly.GetTypes())
+            {
+                var serviceAttribute = type.GetCustomAttribute<AppServiceAttribute>();
+
+                if (serviceAttribute != null)
+                {
+                    var serviceType = serviceAttribute.ServiceType;
+                    //情况1 适用于依赖抽象编程,注意这里只获取第一个
+                    if (serviceType == null && serviceAttribute.InterfaceServiceType)
+                    {
+                        serviceType = type.GetInterfaces().FirstOrDefault();
+                    }
+                    //情况2 不常见特殊情况下才会指定ServiceType,写起来麻烦
+                    if (serviceType == null)
+                    {
+                        serviceType = type;
+                    }
+
+                    switch (serviceAttribute.ServiceLifetime)
+                    {
+                        case LifeTime.Singleton:
+                            services.AddSingleton(serviceType, type);
+                            break;
+                        case LifeTime.Scoped:
+                            services.AddScoped(serviceType, type);
+                            break;
+                        case LifeTime.Transient:
+                            services.AddTransient(serviceType, type);
+                            break;
+                        default:
+                            services.AddTransient(serviceType, type);
+                            break;
+                    }
+                    //System.Console.WriteLine($"注册:{serviceType}");
+                }
+            }
+        }
+    }
+}

+ 41 - 0
Extensions/EntityExtension.cs

@@ -0,0 +1,41 @@
+using System.Reflection;
+using Extensions;
+
+namespace Infrastructure
+{
+    public static class EntityExtension
+    {
+        public static TSource ToCreate<TSource>(this TSource source, HttpContext? context = null)
+        {
+            var types = source?.GetType();
+            if (types == null || context == null) return source;
+            BindingFlags flag = BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance;
+
+            // types.GetProperty("CreateTime", flag)?.SetValue(source, DateTime.Now, null);
+            // types.GetProperty("AddTime", flag)?.SetValue(source, DateTime.Now, null);
+            // types.GetProperty("CreateBy", flag)?.SetValue(source, context.GetName(), null);
+            // types.GetProperty("Create_by", flag)?.SetValue(source, context.GetName(), null);
+            // types.GetProperty("UserId", flag)?.SetValue(source, context.GetUId(), null);
+            // types.GetProperty("DeptId", flag)?.SetValue(source, context.GetDeptId(), null);
+            types.GetProperty("createTime", flag)?.SetValue(source, DateTime.Now, null);
+
+            return source;
+        }
+
+        public static TSource ToUpdate<TSource>(this TSource source, HttpContext? context = null)
+        {
+            var types = source?.GetType();
+            if (types == null || context == null) return source;
+            BindingFlags flag = BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance;
+
+            // types.GetProperty("UpdateTime", flag)?.SetValue(source, DateTime.Now, null);
+            // types.GetProperty("Update_time", flag)?.SetValue(source, DateTime.Now, null);
+            // types.GetProperty("UpdateBy", flag)?.SetValue(source, context.GetName(), null);
+            // types.GetProperty("Update_by", flag)?.SetValue(source, context.GetName(), null);
+            types.GetProperty("updateTime", flag)?.SetValue(source, DateTime.Now, null);
+
+            return source;
+        }
+
+    }
+}

+ 446 - 0
Extensions/Extension.Convert.cs

@@ -0,0 +1,446 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Extensions
+{
+    public static partial class Extensions
+    {
+        #region 转换为long
+        /// <summary>
+        /// 将object转换为long,若转换失败,则返回0。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static long ParseToLong(this object obj)
+        {
+            try
+            {
+                return long.Parse(obj.ToString());
+            }
+            catch
+            {
+                return 0L;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为long,若转换失败,则返回指定值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <param name="defaultValue"></param>
+        /// <returns></returns>
+        public static long ParseToLong(this string str, long defaultValue)
+        {
+            try
+            {
+                return long.Parse(str);
+            }
+            catch
+            {
+                return defaultValue;
+            }
+        }
+        #endregion
+
+        #region 转换为int
+        /// <summary>
+        /// 将object转换为int,若转换失败,则返回0。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static int ParseToInt(this object str)
+        {
+            try
+            {
+                return Convert.ToInt32(str);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为int,若转换失败,则返回指定值。不抛出异常。 
+        /// null返回默认值
+        /// </summary>
+        /// <param name="str"></param>
+        /// <param name="defaultValue"></param>
+        /// <returns></returns>
+        public static int ParseToInt(this object str, int defaultValue)
+        {
+            if (str == null)
+            {
+                return defaultValue;
+            }
+            try
+            {
+                return Convert.ToInt32(str);
+            }
+            catch
+            {
+                return defaultValue;
+            }
+        }
+        #endregion
+
+        #region 转换为short
+        /// <summary>
+        /// 将object转换为short,若转换失败,则返回0。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static short ParseToShort(this object obj)
+        {
+            try
+            {
+                return short.Parse(obj.ToString());
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为short,若转换失败,则返回指定值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static short ParseToShort(this object str, short defaultValue)
+        {
+            try
+            {
+                return short.Parse(str.ToString());
+            }
+            catch
+            {
+                return defaultValue;
+            }
+        }
+        #endregion
+
+        #region 转换为demical
+        /// <summary>
+        /// 将object转换为demical,若转换失败,则返回指定值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static decimal ParseToDecimal(this object str, decimal defaultValue)
+        {
+            try
+            {
+                return decimal.Parse(str.ToString());
+            }
+            catch
+            {
+                return defaultValue;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为demical,若转换失败,则返回0。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static decimal ParseToDecimal(this object str)
+        {
+            try
+            {
+                return decimal.Parse(str.ToString());
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+        #endregion
+
+        #region 转化为bool
+        /// <summary>
+        /// 将object转换为bool,若转换失败,则返回false。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static bool ParseToBool(this object str)
+        {
+            try
+            {
+                return bool.Parse(str.ToString());
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为bool,若转换失败,则返回指定值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static bool ParseToBool(this object str, bool result)
+        {
+            try
+            {
+                return bool.Parse(str.ToString());
+            }
+            catch
+            {
+                return result;
+            }
+        }
+        #endregion
+
+        #region 转换为float
+        /// <summary>
+        /// 将object转换为float,若转换失败,则返回0。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static float ParseToFloat(this object str)
+        {
+            try
+            {
+                return float.Parse(str.ToString());
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为float,若转换失败,则返回指定值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static float ParseToFloat(this object str, float result)
+        {
+            try
+            {
+                return float.Parse(str.ToString());
+            }
+            catch
+            {
+                return result;
+            }
+        }
+        #endregion
+
+        #region 转换为Guid
+        /// <summary>
+        /// 将string转换为Guid,若转换失败,则返回Guid.Empty。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static Guid ParseToGuid(this string str)
+        {
+            try
+            {
+                return new Guid(str);
+            }
+            catch
+            {
+                return Guid.Empty;
+            }
+        }
+        #endregion
+
+        #region 转换为DateTime
+        /// <summary>
+        /// 将string转换为DateTime,若转换失败,则返回日期最小值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static DateTime ParseToDateTime(this string str)
+        {
+            try
+            {
+                if (string.IsNullOrWhiteSpace(str))
+                {
+                    return DateTime.MinValue;
+                }
+                if (str.Contains("-") || str.Contains("/"))
+                {
+                    return DateTime.Parse(str);
+                }
+                else
+                {
+                    int length = str.Length;
+                    switch (length)
+                    {
+                        case 4:
+                            return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
+                        case 6:
+                            return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
+                        case 8:
+                            return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
+                        case 10:
+                            return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
+                        case 12:
+                            return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
+                        case 14:
+                            return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+                        default:
+                            return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+                    }
+                }
+            }
+            catch
+            {
+                return DateTime.MinValue;
+            }
+        }
+
+        /// <summary>
+        /// 将string转换为DateTime,若转换失败,则返回默认值。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <param name="defaultValue"></param>
+        /// <returns></returns>
+        public static DateTime ParseToDateTime(this string str, DateTime? defaultValue)
+        {
+            try
+            {
+                if (string.IsNullOrWhiteSpace(str))
+                {
+                    return defaultValue.GetValueOrDefault();
+                }
+                if (str.Contains("-") || str.Contains("/"))
+                {
+                    return DateTime.Parse(str);
+                }
+                else
+                {
+                    int length = str.Length;
+                    switch (length)
+                    {
+                        case 4:
+                            return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
+                        case 6:
+                            return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
+                        case 8:
+                            return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
+                        case 10:
+                            return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
+                        case 12:
+                            return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
+                        case 14:
+                            return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+                        default:
+                            return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
+                    }
+                }
+            }
+            catch
+            {
+                return defaultValue.GetValueOrDefault();
+            }
+        }
+        #endregion
+
+        #region 转换为string
+        /// <summary>
+        /// 将object转换为string,若转换失败,则返回""。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static string ParseToString(this object obj)
+        {
+            try
+            {
+                if (obj == null)
+                {
+                    return string.Empty;
+                }
+                else
+                {
+                    return obj.ToString();
+                }
+            }
+            catch
+            {
+                return string.Empty;
+            }
+        }
+        public static string ParseToStrings<T>(this object obj)
+        {
+            try
+            {
+                var list = obj as IEnumerable<T>;
+                if (list != null)
+                {
+                    return string.Join(",", list);
+                }
+                else
+                {
+                    return obj.ToString();
+                }
+            }
+            catch
+            {
+                return string.Empty;
+            }
+
+        }
+        #endregion
+
+        #region 转换为double
+        /// <summary>
+        /// 将object转换为double,若转换失败,则返回0。不抛出异常。  
+        /// </summary>
+        /// <param name="obj"></param>
+        /// <returns></returns>
+        public static double ParseToDouble(this object obj)
+        {
+            try
+            {
+                return double.Parse(obj.ToString());
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 将object转换为double,若转换失败,则返回指定值。不抛出异常。  
+        /// </summary>
+        /// <param name="str"></param>
+        /// <param name="defaultValue"></param>
+        /// <returns></returns>
+        public static double ParseToDouble(this object str, double defaultValue)
+        {
+            try
+            {
+                return double.Parse(str.ToString());
+            }
+            catch
+            {
+                return defaultValue;
+            }
+        }
+        #endregion
+
+        #region 强制转换类型
+        /// <summary>
+        /// 强制转换类型
+        /// </summary>
+        /// <typeparam name="TResult"></typeparam>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static IEnumerable<TResult> CastSuper<TResult>(this IEnumerable source)
+        {
+            foreach (object item in source)
+            {
+                yield return (TResult)Convert.ChangeType(item, typeof(TResult));
+            }
+        }
+        #endregion
+    }
+}

+ 86 - 0
Extensions/Extension.Enum.cs

@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace Extensions
+{
+    public static partial class Extensions
+    {
+        #region 枚举成员转成dictionary类型
+        /// <summary>
+        /// 转成dictionary类型
+        /// </summary>
+        /// <param name="enumType"></param>
+        /// <returns></returns>
+        public static Dictionary<int, string> EnumToDictionary(this Type enumType)
+        {
+            Dictionary<int, string> dictionary = new Dictionary<int, string>();
+            Type typeDescription = typeof(DescriptionAttribute);
+            FieldInfo[] fields = enumType.GetFields();
+            int sValue = 0;
+            string sText = string.Empty;
+            foreach (FieldInfo field in fields)
+            {
+                if (field.FieldType.IsEnum)
+                {
+                    sValue = ((int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null));
+                    object[] arr = field.GetCustomAttributes(typeDescription, true);
+                    if (arr.Length > 0)
+                    {
+                        DescriptionAttribute da = (DescriptionAttribute)arr[0];
+                        sText = da.Description;
+                    }
+                    else
+                    {
+                        sText = field.Name;
+                    }
+                    dictionary.Add(sValue, sText);
+                }
+            }
+            return dictionary;
+        }
+        /// <summary>
+        /// 枚举成员转成键值对Json字符串
+        /// </summary>
+        /// <param name="enumType"></param>
+        /// <returns></returns>
+        //public static string EnumToDictionaryString(this Type enumType)
+        //{
+        //    List<KeyValuePair<int, string>> dictionaryList = EnumToDictionary(enumType).ToList();
+        //    var sJson = JsonConvert.SerializeObject(dictionaryList);
+        //    return sJson;
+        //}
+        #endregion
+
+        #region 获取枚举的描述
+        /// <summary>
+        /// 获取枚举值对应的描述
+        /// </summary>
+        /// <param name="enumType"></param>
+        /// <returns></returns>
+        public static string GetDescription(this System.Enum enumType)
+        {
+            FieldInfo EnumInfo = enumType.GetType().GetField(enumType.ToString());
+            if (EnumInfo != null)
+            {
+                DescriptionAttribute[] EnumAttributes = (DescriptionAttribute[])EnumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
+                if (EnumAttributes.Length > 0)
+                {
+                    return EnumAttributes[0].Description;
+                }
+            }
+            return enumType.ToString();
+        }
+        #endregion
+
+        #region 根据值获取枚举的描述
+        public static string GetDescriptionByEnum<T>(this object obj)
+        {
+            var tEnum = System.Enum.Parse(typeof(T), obj.ParseToString()) as System.Enum;
+            var description = tEnum.GetDescription();
+            return description;
+        }
+        #endregion
+    }
+}

+ 18 - 0
Extensions/Extension.Exception.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Extensions
+{
+    public static partial class Extensions
+    {
+        public static Exception GetOriginalException(this Exception ex)
+        {
+            if (ex.InnerException == null) return ex;
+
+            return ex.InnerException.GetOriginalException();
+        }
+    }
+}

+ 110 - 0
Extensions/Extension.Linq.cs

@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Extensions
+{
+    public static class LinqExtensions
+    {
+        public static Expression Property(this Expression expression, string propertyName)
+        {
+            return Expression.Property(expression, propertyName);
+        }
+        public static Expression AndAlso(this Expression left, Expression right)
+        {
+            return Expression.AndAlso(left, right);
+        }
+        public static Expression Call(this Expression instance, string methodName, params Expression[] arguments)
+        {
+            return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments);
+        }
+        public static Expression GreaterThan(this Expression left, Expression right)
+        {
+            return Expression.GreaterThan(left, right);
+        }
+        public static Expression<T> ToLambda<T>(this Expression body, params ParameterExpression[] parameters)
+        {
+            return Expression.Lambda<T>(body, parameters);
+        }
+
+        public static Expression<Func<T, bool>> True<T>() { return param => true; }
+
+        public static Expression<Func<T, bool>> False<T>() { return param => false; }
+
+        /// <summary>
+        /// 组合And
+        /// </summary>
+        /// <returns></returns>
+        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
+        {
+            return first.Compose(second, Expression.AndAlso);
+        }
+        /// <summary>
+        /// 组合Or
+        /// </summary>
+        /// <returns></returns>
+        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
+        {
+            return first.Compose(second, Expression.OrElse);
+        }
+
+        /// <summary>
+        /// Combines the first expression with the second using the specified merge function.
+        /// </summary>
+        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
+        {
+            var map = first.Parameters
+                .Select((f, i) => new { f, s = second.Parameters[i] })
+                .ToDictionary(p => p.s, p => p.f);
+            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
+            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
+        }
+
+        /// <summary>
+        /// ParameterRebinder
+        /// </summary>
+        private class ParameterRebinder : ExpressionVisitor
+        {
+            /// <summary>
+            /// The ParameterExpression map
+            /// </summary>
+            readonly Dictionary<ParameterExpression, ParameterExpression> map;
+            /// <summary>
+            /// Initializes a new instance of the <see cref="ParameterRebinder"/> class.
+            /// </summary>
+            /// <param name="map">The map.</param>
+            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
+            {
+                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
+            }
+            /// <summary>
+            /// Replaces the parameters.
+            /// </summary>
+            /// <param name="map">The map.</param>
+            /// <param name="exp">The exp.</param>
+            /// <returns>Expression</returns>
+            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
+            {
+                return new ParameterRebinder(map).Visit(exp);
+            }
+            /// <summary>
+            /// Visits the parameter.
+            /// </summary>
+            /// <param name="p">The p.</param>
+            /// <returns>Expression</returns>
+            protected override Expression VisitParameter(ParameterExpression p)
+            {
+                ParameterExpression replacement;
+
+                if (map.TryGetValue(p, out replacement))
+                {
+                    p = replacement;
+                }
+                return base.VisitParameter(p);
+            }
+        }
+    }
+}

+ 44 - 0
Extensions/Extension.Validate.cs

@@ -0,0 +1,44 @@
+//using Microsoft.AspNetCore.Http;
+
+namespace Extensions
+{
+    public static partial class Extensions
+    {
+        public static bool IsEmpty(this object value)
+        {
+            if (value != null && !string.IsNullOrEmpty(value.ParseToString()))
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+        public static bool IsNotEmpty(this object value)
+        {
+            return !IsEmpty(value);
+        }
+        public static bool IsNullOrZero(this object value)
+        {
+            if (value == null || value.ParseToString().Trim() == "0")
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        //public static bool IsAjaxRequest(this HttpRequest request)
+        //{
+        //    if (request == null)
+        //        throw new ArgumentNullException("request");
+
+        //    if (request.Headers != null)
+        //        return request.Headers["X-Requested-With"] == "XMLHttpRequest";
+        //    return false;
+        //}
+    }
+}

+ 245 - 0
Extensions/HttpContextExtension.cs

@@ -0,0 +1,245 @@
+using System.Security.Claims;
+using System.Text;
+using System.Text.RegularExpressions;
+using Base;
+using Extensions;
+using IPTools.Core;
+using Model.Base;
+using UAParser;
+using Util;
+
+namespace Extensions
+{
+    /// <summary>
+    /// HttpContext扩展类
+    /// </summary>
+    public static partial class HttpContextExtension
+    {
+        /// <summary>
+        /// 是否是ajax请求
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public static bool IsAjaxRequest(this HttpRequest request)
+        {
+            if (request == null)
+            {
+                throw new ArgumentNullException(nameof(request));
+            }
+
+            //return request.Headers.ContainsKey("X-Requested-With") &&
+            //       request.Headers["X-Requested-With"].Equals("XMLHttpRequest");
+
+            return request.Headers["X-Requested-With"] == "XMLHttpRequest" || request.Headers != null && request.Headers["X-Requested-With"] == "XMLHttpRequest";
+        }
+
+        /// <summary>
+        /// 获取客户端IP
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static string GetClientUserIp(this HttpContext context)
+        {
+            if (context == null) return "";
+            var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+            if (string.IsNullOrEmpty(result))
+            {
+                result = context.Connection.RemoteIpAddress?.ToString();
+            }
+            if (string.IsNullOrEmpty(result))
+                throw new Exception("获取IP失败");
+
+            if (result.Contains("::1"))
+                result = "127.0.0.1";
+
+            result = result.Replace("::ffff:", "");
+            result = result.Split(':')?.FirstOrDefault() ?? "127.0.0.1";
+            result = IsIP(result) ? result : "127.0.0.1";
+            return result;
+        }
+
+        /// <summary>
+        /// 判断是否IP
+        /// </summary>
+        /// <param name="ip"></param>
+        /// <returns></returns>
+        public static bool IsIP(string ip)
+        {
+            return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
+        }
+
+        /// <summary>
+        /// 获取登录用户id
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static long GetUId(this HttpContext context)
+        {
+            TokenModel loginUser = JwtUtil.GetLoginUser(context);
+            return loginUser.userId;
+            // var uid = context.User.FindFirstValue(ClaimTypes.PrimarySid);
+            // return !string.IsNullOrEmpty(uid) ? long.Parse(uid) : 0;
+        }
+
+        /// <summary>
+        /// 获取部门id
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static long GetDeptId(this HttpContext context)
+        {
+            var deptId = context.User.FindFirstValue(ClaimTypes.GroupSid);
+            return !string.IsNullOrEmpty(deptId) ? long.Parse(deptId) : 0;
+        }
+
+        /// <summary>
+        /// 获取登录用户名
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static string GetName(this HttpContext context)
+        {
+            var uid = context.User?.Identity?.Name;
+
+            return uid;
+        }
+
+        /// <summary>
+        /// 判断是否是管理员
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static bool IsAdmin(this HttpContext context)
+        {
+            var userName = context.GetName();
+            return userName == GlobalConstant.AdminRole;
+        }
+
+        /// <summary>
+        /// ClaimsIdentity
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static IEnumerable<ClaimsIdentity> GetClaims(this HttpContext context)
+        {
+            return context.User?.Identities;
+        }
+        //public static int GetRole(this HttpContext context)
+        //{
+        //    var roleid = context.User.FindFirstValue(ClaimTypes.Role) ?? "0";
+
+        //    return int.Parse(roleid);
+        //}
+
+        public static string GetUserAgent(this HttpContext context)
+        {
+            return context.Request.Headers["User-Agent"];
+        }
+
+        /// <summary>
+        /// 获取请求令牌
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static string GetToken(this HttpContext context)
+        {
+            return context.Request.Headers["Authorization"];
+        }
+
+        /// <summary>
+        /// 获取请求Url
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static string GetRequestUrl(this HttpContext context)
+        {
+            return context != null ? context.Request.Path.Value : "";
+        }
+
+        /// <summary>
+        /// 获取请求参数
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static string GetQueryString(this HttpContext context)
+        {
+            return context != null ? context.Request.QueryString.Value : "";
+        }
+
+        /// <summary>
+        /// 获取body请求参数
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static string GetBody(this HttpContext context)
+        {
+            context.Request.EnableBuffering();
+            //context.Request.Body.Seek(0, SeekOrigin.Begin);
+            //using var reader = new StreamReader(context.Request.Body, Encoding.UTF8);
+            ////需要使用异步方式才能获取
+            //return reader.ReadToEndAsync().Result;
+            string body = string.Empty;
+            var buffer = new MemoryStream();
+            context.Request.Body.Seek(0, SeekOrigin.Begin);
+            context.Request.Body.CopyToAsync(buffer);
+            buffer.Position = 0;
+            try
+            {
+                using StreamReader streamReader = new(buffer, Encoding.UTF8);
+                body = streamReader.ReadToEndAsync().Result;
+            }
+            finally
+            {
+                buffer?.Dispose();
+            }
+            return body;
+        }
+
+        /// <summary>
+        /// 获取浏览器信息
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public static ClientInfo GetClientInfo(this HttpContext context)
+        {
+            var str = context.GetUserAgent();
+            var uaParser = Parser.GetDefault();
+            ClientInfo c = uaParser.Parse(str);
+
+            return c;
+        }
+
+        /// <summary>
+        /// 根据IP获取地理位置
+        /// </summary>
+        /// <returns></returns>
+        public static string GetIpInfo(string IP)
+        {
+            var ipInfo = IpTool.Search(IP);
+            return ipInfo?.Province + "-" + ipInfo?.City + "-" + ipInfo?.NetworkOperator;
+        }
+
+        /// <summary>
+        /// 设置请求参数
+        /// </summary>
+        /// <param name="reqMethod"></param>
+        /// <param name="context"></param>
+        public static string GetRequestValue(this HttpContext context, string reqMethod)
+        {
+            string param = string.Empty;
+
+            if (HttpMethods.IsPost(reqMethod) || HttpMethods.IsPut(reqMethod) || HttpMethods.IsDelete(reqMethod))
+            {
+                param = context.GetBody();
+                string regex = "(?<=\"password\":\")[^\",]*";
+                param = Regex.Replace(param, regex, "***");
+            }
+            if (param.IsEmpty())
+            {
+                param = context.GetQueryString();
+            }
+            return param;
+        }
+    }
+
+}

+ 24 - 0
Extensions/IPRateExtension.cs

@@ -0,0 +1,24 @@
+using AspNetCoreRateLimit;
+
+namespace Extensions
+{
+    public static class IPRateExtension
+    {
+        public static void AddIPRate(this IServiceCollection services, IConfiguration configuration)
+        {
+            if (services == null) throw new ArgumentNullException(nameof(services));
+
+            //从appsettings.json中加载常规配置,IpRateLimiting与配置文件中节点对应
+            services.Configure<IpRateLimitOptions>(configuration.GetSection("IpRateLimiting"));
+
+            //从appsettings.json中加载Ip规则
+            services.Configure<IpRateLimitPolicies>(configuration.GetSection("IpRateLimitPolicies"));
+            //注入计数器和规则存储
+            services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
+            services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
+            //配置(解析器、计数器密钥生成器)
+            services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
+            services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();
+        }
+    }
+}

+ 35 - 0
Extensions/RequestLimitExtension.cs

@@ -0,0 +1,35 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Extensions
+{
+    public static class RequestLimitExtension
+    {
+        /// <summary>
+        /// 请求body大小设置
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="configuration"></param>
+        public static void AddRequestLimit(this IServiceCollection services, IConfiguration configuration)
+        {
+            var sizeM = configuration.GetSection("upload:requestLimitSize").Get<int>();
+            services.Configure<FormOptions>(x =>
+            {
+                x.MultipartBodyLengthLimit = sizeM * 1024 * 1024;
+                x.MemoryBufferThreshold = sizeM * 1024 * 1024;
+                x.ValueLengthLimit = int.MaxValue;
+            });
+            services.Configure<KestrelServerOptions>(options =>
+            {
+                options.Limits.MaxRequestBodySize = sizeM * 1024 * 1024;
+            });
+            services.Configure<IISServerOptions>(options =>
+            {
+                options.MaxRequestBodySize = sizeM * 1024 * 1024; // 设置最大请求体大小为500MB
+            });
+        }
+    }
+}

+ 232 - 0
Extensions/StringExtension.cs

@@ -0,0 +1,232 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Extensions
+{
+    public static class StringExtension
+    {
+
+        /// <summary>
+        /// SQL条件拼接
+        /// </summary>
+        /// <param name="str"></param>
+        /// <param name="condition"></param>
+        /// <returns></returns>
+        public static string If(this string str, bool condition)
+        {
+            return condition ? str : string.Empty;
+        }
+        /// <summary>
+        /// 判断是否为空
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static bool IfNotEmpty(this string str)
+        {
+            return !string.IsNullOrEmpty(str);
+        }
+
+        /// <summary>
+        /// 注意:如果替换的旧值中有特殊符号,替换将会失败,解决办法 例如特殊符号是“(”:  要在调用本方法前加oldValue=oldValue.Replace("(","//(");
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="oldValue"></param>
+        /// <param name="newValue"></param>
+        /// <returns></returns>
+        public static string ReplaceFirst(this string input, string oldValue, string newValue)
+        {
+            Regex regEx = new Regex(oldValue, RegexOptions.Multiline);
+            return regEx.Replace(input, newValue == null ? "" : newValue, 1);
+        }
+
+        /// <summary>
+        /// 骆驼峰转下划线
+        /// </summary>
+        /// <param name="name"></param>
+        /// <returns></returns>
+        public static string ToSmallCamelCase(string name)
+        {
+            var stringBuilder = new StringBuilder();
+            stringBuilder.Append(name.Substring(0, 1).ToLower());
+
+            for (var i = 0; i < name.Length; i++)
+            {
+                if (i == 0)
+                {
+                    stringBuilder.Append(name.Substring(0, 1).ToLower());
+                }
+                else
+                {
+                    if (name[i] >= 'A' && name[i] <= 'Z')
+                    {
+                        stringBuilder.Append($"_{name.Substring(i, 1).ToLower()}");
+                    }
+                    else
+                    {
+                        stringBuilder.Append(name[i]);
+                    }
+                }
+            }
+
+            return stringBuilder.ToString();
+        }
+
+        /// <summary>
+        /// 下划线命名转驼峰命名
+        /// </summary>
+        /// <param name="underscore"></param>
+        /// <returns></returns>
+        public static string UnderScoreToCamelCase(this string underscore)
+        {
+            string[] ss = underscore.Split("_");
+            if (ss.Length == 1)
+            {
+                return underscore;
+            }
+
+            StringBuilder sb = new();
+            sb.Append(ss[0]);
+            for (int i = 1; i < ss.Length; i++)
+            {
+                sb.Append(ss[i].FirstUpperCase());
+            }
+
+            return sb.ToString();
+        }
+
+        /// <summary>
+        /// 首字母转大写
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static string FirstUpperCase(this string str)
+        {
+            return string.IsNullOrEmpty(str) ? str : str[..1].ToUpper() + str[1..];
+        }
+
+        /// <summary>
+        /// 首字母转小写
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static string FirstLowerCase(this string str)
+        {
+            return string.IsNullOrEmpty(str) ? str : str.Substring(0, 1).ToLower() + str[1..];
+        }
+
+        /// <summary>
+        /// 截取指定字符串中间内容
+        /// </summary>
+        /// <param name="sourse"></param>
+        /// <param name="startstr"></param>
+        /// <param name="endstr"></param>
+        /// <returns></returns>
+        public static string SubStringBetween(this string sourse, string startstr, string endstr)
+        {
+            string result = string.Empty;
+            int startindex, endindex;
+            try
+            {
+                startindex = sourse.IndexOf(startstr);
+                if (startindex == -1)
+                    return result;
+                string tmpstr = sourse[(startindex + startstr.Length)..];
+                endindex = tmpstr.IndexOf(endstr);
+                if (endindex == -1)
+                    return result;
+                result = tmpstr.Remove(endindex);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("MidStrEx Err:" + ex.Message);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 转换为Pascal风格-每一个单词的首字母大写
+        /// </summary>
+        /// <param name="fieldName">字段名</param>
+        /// <param name="fieldDelimiter">分隔符</param>
+        /// <returns></returns>
+        public static string ConvertToPascal(this string fieldName, string fieldDelimiter)
+        {
+            string result = string.Empty;
+            if (fieldName.Contains(fieldDelimiter))
+            {
+                //全部小写
+                string[] array = fieldName.ToLower().Split(fieldDelimiter.ToCharArray());
+                foreach (var t in array)
+                {
+                    //首字母大写
+                    result += t.Substring(0, 1).ToUpper() + t[1..];
+                }
+            }
+            else if (string.IsNullOrWhiteSpace(fieldName))
+            {
+                result = fieldName;
+            }
+            else if (fieldName.Length == 1)
+            {
+                result = fieldName.ToUpper();
+            }
+            else if (fieldName.Length == CountUpper(fieldName))
+            {
+                result = fieldName[..1].ToUpper() + fieldName[1..].ToLower();
+            }
+            else
+            {
+                result = fieldName[..1].ToUpper() + fieldName[1..];
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 大写字母个数
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        public static int CountUpper(this string str)
+        {
+            int count1 = 0;
+            char[] chars = str.ToCharArray();
+            foreach (char num in chars)
+            {
+                if (num >= 'A' && num <= 'Z')
+                {
+                    count1++;
+                }
+                //else if (num >= 'a' && num <= 'z')
+                //{
+                //    count2++;
+                //}
+            }
+            return count1;
+        }
+
+        /// <summary>
+        /// 转换为Camel风格-第一个单词小写,其后每个单词首字母大写
+        /// </summary>
+        /// <param name="fieldName">字段名</param>
+        /// <param name="fieldDelimiter">分隔符</param>
+        /// <returns></returns>
+        public static string ConvertToCamel(this string fieldName, string fieldDelimiter)
+        {
+            //先Pascal
+            string result = ConvertToPascal(fieldName, fieldDelimiter);
+            //然后首字母小写
+            if (result.Length == 1)
+            {
+                result = result.ToLower();
+            }
+            else
+            {
+                result = result[..1].ToLower() + result[1..];
+            }
+
+            return result;
+        }
+    }
+}

+ 92 - 0
Filters/ActionPermissionFilter.cs

@@ -0,0 +1,92 @@
+using Base;
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Model;
+using Model.Base;
+using Services;
+using Util;
+
+namespace Middleware
+{
+    /// <summary>
+    /// API授权判断
+    /// </summary>
+    public class ActionPermissionFilter : ActionFilterAttribute//, IAsyncActionFilter
+    {
+        private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+        /// <summary>
+        /// 权限字符串,例如 system:user:view
+        /// </summary>
+        public string Permission { get; set; } = string.Empty;
+        /// <summary>
+        /// 角色字符串,例如 common,admin
+        /// </summary>
+        public string RolePermi { get; set; } = string.Empty;
+        private bool HasPermi { get; set; }
+        public ActionPermissionFilter() { }
+        public ActionPermissionFilter(string permission)
+        {
+            Permission = permission;
+            HasPermi = !string.IsNullOrEmpty(Permission);
+        }
+
+        /// <summary>
+        /// 执行Action前校验是否有权限访问
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="next"></param>
+        /// <returns></returns>
+        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+        {
+            TokenModel info = JwtUtil.GetLoginUser(context.HttpContext);
+
+            if (info != null && info?.userId > 0)
+            {
+                long userId = info.userId;
+                List<string> perms = CacheService.GetUserPerms(GlobalConstant.UserPermKEY + userId);
+                List<string> rolePerms = info.RoleIds;
+
+                if (perms == null)
+                {
+                    // var sysPermissionService = App.GetService<ISysPermissionService>();
+                    // perms = sysPermissionService.List();
+
+                    // CacheService.SetUserPerms(GlobalConstant.UserPermKEY + userId, perms);
+                }
+
+                if (perms.Exists(f => f.Equals(GlobalConstant.AdminPerm)))
+                {
+                    HasPermi = true;
+                }
+                else if (rolePerms.Exists(f => f.Equals(GlobalConstant.AdminRole)))
+                {
+                    HasPermi = true;
+                }
+                else if (!string.IsNullOrEmpty(Permission))
+                {
+                    HasPermi = perms.Exists(f => f.ToLower() == Permission.ToLower());
+                }
+                if (!HasPermi && !string.IsNullOrEmpty(RolePermi))
+                {
+                    HasPermi = info.RoleIds.Contains(RolePermi);
+                }
+                var url = context.HttpContext.Request.Path;
+                if (!HasPermi && !Permission.Equals("common"))
+                {
+                    logger.Info($"用户{info.username}没有权限访问{url},当前权限[{Permission}]");
+                    JsonResult result = new(new ApiResult((int)ResultCode.FORBIDDEN, $"你当前没有权限访问,请联系管理员", url))
+                    {
+                        ContentType = "application/json",
+                    };
+                    context.HttpContext.Response.StatusCode = 403;
+                    context.Result = result;
+                }
+            }
+
+            return base.OnActionExecutionAsync(context, next);
+        }
+    }
+}

+ 148 - 0
Filters/AuthorizationFilter.cs

@@ -0,0 +1,148 @@
+using System.Text;
+using System.Web;
+using Common;
+using Extensions;
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Services;
+
+//本命名空间暂时先不改,改动比较大2023年9月2日
+namespace Filters
+{
+    /// <summary>
+    /// </summary>
+    public class AuthorizationFilter : IAuthorizationFilter
+    {
+        
+        public AuthorizationFilter()
+        {
+        }
+
+        /// <summary>
+        /// </summary>
+        /// <param name="context"></param>
+        public void OnAuthorization(AuthorizationFilterContext context)
+        {
+            // var request = context.HttpContext.Request;
+            // if(!request.Path.Value.ToLower().Contains("noauth/"))
+            // {
+            //     string content = "";
+            //     if(context.HttpContext.Request.Method.ToLower() == "get")
+            //     {
+            //         content = context.HttpContext.GetQueryString();
+            //         content = GetParam(content, "value");
+            //         content = HttpUtility.UrlDecode(content);
+            //         content = Decrypt(content);
+            //         content = HttpUtility.UrlDecode(content);
+            //         if(!string.IsNullOrEmpty(content))
+            //         {
+            //             Dictionary<string, object> dic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(content);
+
+            //             string queryString = "";
+            //             var parameters = context.ActionDescriptor.Parameters;
+            //             foreach(var parameter in parameters)
+            //             {
+            //                 string parameterName = parameter.Name;
+            //                 Type objectType = parameter.ParameterType;
+            //                 if(objectType.FullName != "System.String")
+            //                 {
+            //                     System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(objectType);
+            //                     var entry = assembly.CreateInstance(objectType.FullName);
+            //                     Type type = entry.GetType();
+            //                     System.Reflection.PropertyInfo[] propertyInfos = type.GetProperties();
+            //                     for (int i = 0; i < propertyInfos.Length; i++)
+            //                     {
+            //                         foreach (string key in dic.Keys)
+            //                         {
+            //                             if (propertyInfos[i].Name == key)
+            //                             {
+            //                                 object value = dic[key];
+            //                                 string ParameterType = propertyInfos[i].GetMethod.ReturnParameter.ParameterType.Name;
+            //                                 if (ParameterType == "Int32")
+            //                                 {
+            //                                     if(value == null || value == "") value = "0";
+            //                                     value = Convert.ToInt32(value);
+            //                                 }
+            //                                 else if (ParameterType == "Int64[]")
+            //                                 {
+            //                                     value = Tools.SpitLongArrary(Newtonsoft.Json.JsonConvert.SerializeObject(value).Replace("[", "").Replace("]", "").Trim('"'), ',');
+            //                                 }
+            //                                 else if (ParameterType == "Int32[]")
+            //                                 {
+            //                                     value = Tools.SpitIntArrary(Newtonsoft.Json.JsonConvert.SerializeObject(value).Replace("[", "").Replace("]", "").Trim('"'), ',');
+            //                                 }
+            //                                 else if (ParameterType == "List`1")
+            //                                 {
+            //                                     string val = Newtonsoft.Json.JsonConvert.SerializeObject(value).Replace("[", "").Replace("]", "").Trim('"');
+            //                                     value = Tools.SpitLongArrary(val, ',').ToList();
+            //                                 }
+            //                                 if(value.ToString() == "-1") value = -1;
+            //                                 if(value.ToString() == "[]") value = "";
+            //                                 queryString += key + "=" + value.ToString() + "&";
+            //                                 break;
+            //                             }
+            //                         }
+            //                     }
+            //                 }
+            //             }
+
+            //             request.QueryString = new QueryString("?" + queryString.TrimEnd('&'));
+            //         }
+            //     }
+            //     else if(context.HttpContext.Request.Method.ToLower() == "delete")
+            //     {
+            //         string path = request.Path.Value;
+            //         string value = path.Substring(path.LastIndexOf("/") + 1);
+            //         path = path.Substring(0, path.LastIndexOf("/") + 1);
+            //         value = Decrypt(value);
+            //         path += value;
+            //         request.Path = new PathString(path);
+            //         request.RouteValues["id"] = value;
+            //     }
+            //     else
+            //     {
+            //         content = context.HttpContext.GetBody();
+            //         content = Decrypt(content);
+            //         //{"username":"admin","password":"000000"}
+            //         request.Body = new MemoryStream(Encoding.UTF8.GetBytes(content));
+
+            //         //验证登录接口
+            //         if(request.Path.Value.EndsWith("/oauth2/token"))
+            //         {
+            //             var scope = request.Query["scope"].ToString();
+            //             var grantType = request.Query["grant_type"].ToString();
+            //             bool checkLogin = SysLoginService.CheckLogin(scope, grantType, context.HttpContext.GetToken().Replace("Basic ", ""));
+            //             if(!checkLogin)
+            //             {
+            //                 string msg = $"请求访问失败,无法访问系统资源";
+            //                 context.Result = new JsonResult(ApiResult.Error(ResultCode.DENY, msg));
+            //             }
+            //         }
+            //     }
+            // }
+        }
+
+        // public string Decrypt(string str)
+        // {
+        //     str = str.Trim('"');
+        //     str = Encoding.UTF8.GetString(Convert.FromBase64String(str));
+        //     return Dbconn.AesDecrypt(str, Base.GlobalConstant.ApiKey, Base.GlobalConstant.ApiIv);
+        // }
+
+        // public string GetParam(string content, string key)
+        // {
+        //     if(content.StartsWith("?")) content = content.Substring(1);
+        //     string[] data = content.Split('&');
+        //     foreach(string sub in data)
+        //     {
+        //         if(sub.StartsWith(key + "="))
+        //         {
+        //             return sub.Substring(sub.IndexOf("=") + 1);
+        //         }
+        //     }
+        //     return "";
+        // }
+    }
+}

+ 281 - 0
Filters/GlobalActionMonitor.cs

@@ -0,0 +1,281 @@
+using Attribute;
+using Base;
+using Common;
+using Extensions;
+using Infrastructure;
+using Infrastructure.Model;
+using IPTools.Core;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Diagnostics;
+using Microsoft.AspNetCore.Mvc.Filters;
+using NLog;
+using System.Text;
+using System.Web;
+
+namespace Middleware
+{
+    public class GlobalActionMonitor : ActionFilterAttribute
+    {
+        static readonly Logger logger = LogManager.GetCurrentClassLogger();
+        // private readonly ISysOperLogService OperLogService;
+        public GlobalActionMonitor()
+        {
+            // OperLogService = operLogService;
+        }
+
+        /// <summary>
+        /// Action请求前
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="next"></param>
+        /// <returns></returns>
+        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+        {
+            // if(!context.HttpContext.Request.Path.Value.ToLower().Contains("noauth/"))
+            // {
+            //     string content = "";
+            //     if(context.HttpContext.Request.Method.ToLower() == "get")
+            //     {
+            //         content = context.HttpContext.GetQueryString();
+            //         content = content.Substring(content.IndexOf("?") + 1);
+            //         if(!string.IsNullOrEmpty(content))
+            //         {
+            //             string jsonString = "";
+            //             string[] dataList = content.Split('&');
+            //             foreach(string sub in dataList)
+            //             {
+            //                 string[] item = sub.Split('=');
+            //                 jsonString += "\"" + item[0] + "\":\"" + item[1] + "\",";
+            //             }
+            //             content = "{" + jsonString.TrimEnd(',') + "}";
+            //         }
+            //     }
+            //     else if(context.HttpContext.Request.Method.ToLower() == "delete")
+            //     {
+            //         string path = context.HttpContext.Request.Path.Value;
+            //         content = path.Substring(path.LastIndexOf("/") + 1);
+            //     }
+            //     else
+            //     {
+            //         content = context.HttpContext.GetBody();
+            //     }
+            //     if(!string.IsNullOrEmpty(content))
+            //     {                
+            //         if(content.Contains("{") && content.Contains("}") && content != "{}")
+            //         {
+            //             Dictionary<string, object> dictionary = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(content);
+            //             if(context.ActionDescriptor.Parameters.Count > 0)
+            //             {
+            //                 var parameters = context.ActionDescriptor.Parameters;
+            //                 foreach(var parameter in parameters)
+            //                 {
+            //                     string parameterName = parameter.Name;
+            //                     Type objectType = parameter.ParameterType;
+            //                     if(objectType.FullName != "System.String")
+            //                     {
+            //                         System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(objectType);
+            //                         var entry = assembly.CreateInstance(objectType.FullName);
+            //                         Type type = entry.GetType();
+            //                         System.Reflection.PropertyInfo[] propertyInfos = type.GetProperties();
+            //                         for (int i = 0; i < propertyInfos.Length; i++)
+            //                         {
+            //                             foreach (string key in dictionary.Keys)
+            //                             {
+            //                                 if (propertyInfos[i].Name == key)
+            //                                 {
+            //                                     object value = dictionary[key];
+            //                                     string ParameterType = propertyInfos[i].GetMethod.ReturnParameter.ParameterType.Name;
+            //                                     if (ParameterType == "Int32")
+            //                                     {
+            //                                         if(value == null || value == "") value = "0";
+            //                                         value = Convert.ToInt32(value);
+            //                                     }
+            //                                     else if (ParameterType == "Int64")
+            //                                     {
+            //                                         if(value == null || value == "") value = "0";
+            //                                         value = Convert.ToInt64(value);
+            //                                     }
+            //                                     else if(ParameterType == "Boolean")
+            //                                     {
+            //                                         if(value == null || value == "") value = false;
+            //                                     }
+            //                                     else if (ParameterType == "Int64[]")
+            //                                     {
+            //                                         value = Tools.SpitLongArrary(Newtonsoft.Json.JsonConvert.SerializeObject(value).Replace("[", "").Replace("]", "").Trim('"'), ',');
+            //                                     }
+            //                                     else if (ParameterType == "Int32[]")
+            //                                     {
+            //                                         value = Tools.SpitIntArrary(Newtonsoft.Json.JsonConvert.SerializeObject(value).Replace("[", "").Replace("]", "").Trim('"'), ',');
+            //                                     }
+            //                                     else if (ParameterType == "List`1")
+            //                                     {
+            //                                         string val = Newtonsoft.Json.JsonConvert.SerializeObject(value).Replace("[", "").Replace("]", "").Trim('"');
+            //                                         value = Tools.SpitLongArrary(val, ',').ToList();
+            //                                     }
+            //                                     if(value == null) value = "";
+            //                                     if(value.ToString() == "-1") value = -1;
+            //                                     if(value.ToString() == "[]") value = "";
+            //                                     propertyInfos[i].SetValue(entry, value, null);
+            //                                     break;
+            //                                 }
+            //                             }
+            //                         }
+            //                         if(context.ActionArguments.ContainsKey(parameterName))
+            //                         {
+            //                             context.ActionArguments[parameterName] = entry;
+            //                         }
+            //                         else
+            //                         {
+            //                             context.ActionArguments.Add(parameterName, entry);
+            //                         }
+            //                     }
+            //                 }
+            //             }
+            //         }
+            //         else
+            //         {
+            //             string ParamName = context.ActionDescriptor.Parameters[0].Name;
+            //             if(context.ActionArguments.ContainsKey(ParamName))
+            //             {
+            //                 context.ActionArguments[ParamName] = Convert.ToInt32(content);
+            //             }
+            //             else
+            //             {
+            //                 context.ActionArguments.Add(ParamName, Convert.ToInt32(content));
+            //             }
+            //         }
+            //     }
+            //     else
+            //     {
+            //         if(context.ActionDescriptor.Parameters.Count > 0)
+            //         {
+            //             string ParamName = context.ActionArguments.Keys.First();
+            //             object ParamValue = context.ActionArguments.Values.First();
+            //             // ParamValue = DesDecrypt(ParamValue.ToString());
+            //             if(ParamValue.GetType() == typeof(int))
+            //             {
+            //                 ParamValue = (int)ParamValue;
+            //             }
+            //             if(context.ActionArguments.ContainsKey(ParamName))
+            //             {
+            //                 context.ActionArguments[ParamName] = ParamValue;
+            //             }
+            //             else
+            //             {
+            //                 context.ActionArguments.Add(ParamName, ParamValue);
+            //             }
+            //         }
+            //     }
+            // }
+            string msg = string.Empty;
+            var values = context.ModelState.Values;
+            foreach (var item in values)
+            {
+                foreach (var err in item.Errors)
+                {
+                    if (!string.IsNullOrEmpty(msg))
+                    {
+                        msg += " | ";
+                    }
+
+                    msg += err.ErrorMessage;
+                }
+            }
+            if (!string.IsNullOrEmpty(msg))
+            {
+                ApiResult response = new((int)ResultCode.PARAM_ERROR, msg);                
+                context.Result = new JsonResult(response);
+            }
+            return base.OnActionExecutionAsync(context, next);
+        }
+
+        /// <summary>
+        /// OnActionExecuted是在Action中的代码执行之后运行的方法。
+        /// </summary>
+        /// <param name="context"></param>
+        public override void OnResultExecuted(ResultExecutedContext context)
+        {
+            if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return;
+
+            //获得注解信息
+            LogAttribute logAttribute = GetLogAttribute(controllerActionDescriptor);
+            if (logAttribute == null) return;
+
+            try
+            {
+                string method = context.HttpContext.Request.Method.ToUpper();
+                // 获取当前的用户
+                string userName = context.HttpContext.GetName() ?? context.HttpContext.Request.Headers["userName"];
+                string jsonResult = string.Empty;
+                if (context.Result is ContentResult result && result.ContentType == "application/json")
+                {
+                    jsonResult = result.Content.Replace("\r\n", "").Trim();
+                }
+                if (context.Result is JsonResult result2)
+                {
+                    jsonResult = result2.Value?.ToString();
+                }
+                //获取当前执行方法的类名
+                //string className =  System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
+                //获取当前成员的名称
+                //string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
+                string controller = context.RouteData.Values["Controller"].ToString();
+                string action = context.RouteData.Values["Action"].ToString();
+
+                string ip = HttpContextExtension.GetClientUserIp(context.HttpContext);
+                var ip_info = IpTool.Search(ip);
+
+                // SysOperLog sysOperLog = new()
+                // {
+                //     Status = 0,
+                //     OperName = userName,
+                //     OperIp = ip,
+                //     OperUrl = HttpContextExtension.GetRequestUrl(context.HttpContext),
+                //     RequestMethod = method,
+                //     JsonResult = jsonResult,
+                //     OperLocation = HttpContextExtension.GetIpInfo(ip),
+                //     Method = controller + "." + action + "()",
+                //     //Elapsed = _stopwatch.ElapsedMilliseconds,
+                //     OperTime = DateTime.Now,
+                //     OperParam = HttpContextExtension.GetRequestValue(context.HttpContext, method)
+                // };
+
+                if (logAttribute != null)
+                {
+                    // sysOperLog.Title = logAttribute?.Title;
+                    // sysOperLog.BusinessType = (int)logAttribute.BusinessType;
+                    // sysOperLog.OperParam = logAttribute.IsSaveRequestData ? sysOperLog.OperParam : "";
+                    // sysOperLog.JsonResult = logAttribute.IsSaveResponseData ? sysOperLog.JsonResult : "";
+                }
+
+                LogEventInfo ei = new(NLog.LogLevel.Info, "GlobalActionMonitor", "");
+
+                ei.Properties["jsonResult"] = !HttpMethods.IsGet(method) ? jsonResult : "";
+                // ei.Properties["requestParam"] = sysOperLog.OperParam;
+                ei.Properties["user"] = userName;
+                logger.Log(ei);
+
+                // OperLogService.InsertOperlog(sysOperLog);
+            }
+            catch (Exception ex)
+            {
+                logger.Error(ex, $"记录操作日志出错了#{ex.Message}");
+            }
+        }
+
+        private LogAttribute GetLogAttribute(ControllerActionDescriptor controllerActionDescriptor)
+        {
+            var attribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
+                .FirstOrDefault(a => a.GetType().Equals(typeof(LogAttribute)));
+
+            return attribute as LogAttribute;
+        }
+
+        private string DesDecrypt(string content)
+        {
+            content = HttpUtility.UrlDecode(content);
+            return Dbconn.DesDecrypt(content, AppSettings.GetConfig("ApiKey"));
+        }
+    }
+}

+ 76 - 0
Filters/VerifyAttribute.cs

@@ -0,0 +1,76 @@
+using System.Web;
+using Common;
+using Extensions;
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Model.Base;
+using Util;
+
+//本命名空间暂时先不改,改动比较大2023年9月2日
+namespace Filters
+{
+    /// <summary>
+    /// 授权校验访问
+    /// 如果跳过授权登录在Action 或controller加上 AllowAnonymousAttribute
+    /// </summary>
+    [AttributeUsage(AttributeTargets.All)]
+    public class VerifyAttribute : System.Attribute, IAuthorizationFilter
+    {
+        private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+        /// <summary>
+        /// 只判断token是否正确,不判断权限
+        /// 如果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别,ActionPermissionFilter作权限处理
+        /// </summary>
+        /// <param name="context"></param>
+        public void OnAuthorization(AuthorizationFilterContext context)
+        {
+            var noNeedCheck = false;
+            if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
+            {
+                noNeedCheck = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
+                  .Any(a => a.GetType().Equals(typeof(AllowAnonymousAttribute)));
+            }
+
+            if (noNeedCheck) return;
+
+            string ip = HttpContextExtension.GetClientUserIp(context.HttpContext);
+            string url = context.HttpContext.Request.Path;
+            var isAuthed = context.HttpContext.User.Identity.IsAuthenticated;
+            string osType = context.HttpContext.Request.Headers["os"];
+            //使用jwt token校验2020-11-21
+            TokenModel loginUser = JwtUtil.GetLoginUser(context.HttpContext);
+            if (loginUser != null)
+            {
+                var nowTime = DateTime.UtcNow;
+                TimeSpan ts = loginUser.ExpireTime - nowTime;
+
+                //Console.WriteLine($"jwt到期剩余:{ts.TotalMinutes}分,{ts.TotalSeconds}秒");
+
+                var CK = "token_" + loginUser.userId;
+                if (!CacheHelper.Exists(CK) && ts.TotalMinutes < 5)
+                {
+                    var newToken = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser));
+                    
+                    CacheHelper.SetCache(CK, CK, 1);
+                    //移动端不加下面这个获取不到自定义Header
+                    if (osType != null)
+                    {
+                        context.HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "X-Refresh-Token");
+                    }
+                    logger.Info($"刷新token,userName={loginUser.username},token={newToken}");
+                    context.HttpContext.Response.Headers.Add("X-Refresh-Token", newToken);
+                }
+            }
+            if (loginUser == null)
+            {
+                string msg = $"请求访问[{url}]失败,无法访问系统资源";
+                //logger.Info(msg);
+                context.Result = new JsonResult(ApiResult.Error(ResultCode.DENY, msg));
+            }
+        }
+    }
+}

+ 3 - 0
GlobalUsing.cs

@@ -0,0 +1,3 @@
+global using System;
+global using System.Collections.Generic;
+global using SqlSugar;

+ 157 - 0
Middleware/GlobalExceptionMiddleware.cs

@@ -0,0 +1,157 @@
+using Attribute;
+using Common;
+using Extensions;
+using Infrastructure;
+using Infrastructure.Model;
+using IPTools.Core;
+using Microsoft.AspNetCore.Http.Features;
+using Model;
+using NLog;
+using Services;
+using System.Text.Encodings.Web;
+using textJson = System.Text.Json;
+
+namespace Middleware
+{
+    /// <summary>
+    /// 全局异常处理中间件
+    /// 调用 app.UseMiddlewareGlobalExceptionMiddleware>();
+    /// </summary>
+    public class GlobalExceptionMiddleware
+    {
+        private readonly RequestDelegate next;
+        // private readonly ISysOperLogService SysOperLogService;
+
+        static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+        public GlobalExceptionMiddleware(RequestDelegate next)
+        {
+            this.next = next;
+            // this.SysOperLogService = sysOperLog;
+        }
+
+        public async Task Invoke(HttpContext context)
+        {
+            try
+            {
+                // 设置允许跨域的域名、方法等
+                // context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
+                // context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+                // context.Response.Headers.Add("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization");
+
+                // 如果请求方法是预检请求(OPTIONS),则直接返回成功状态码
+                if (context.Request.Method == "OPTIONS")
+                {
+                    context.Response.StatusCode = 200;
+                    await context.Response.WriteAsync("OK");
+                    return;
+                }
+
+                await next(context);
+            }
+            catch (Exception ex)
+            {
+                await HandleExceptionAsync(context, ex);
+            }
+        }
+
+        private async Task HandleExceptionAsync(HttpContext context, Exception ex)
+        {
+            NLog.LogLevel logLevel = NLog.LogLevel.Info;
+            int code = (int)ResultCode.GLOBAL_ERROR;
+            string msg;
+            string error = string.Empty;
+            bool notice = true;
+            //自定义异常
+            if (ex is CustomException customException)
+            {
+                code = customException.Code;
+                msg = customException.Message;
+                error = customException.LogMsg;
+                notice = customException.Notice;
+            }
+            else if (ex is ArgumentException)//参数异常
+            {
+                code = (int)ResultCode.PARAM_ERROR;
+                msg = ex.Message;
+            }
+            else
+            {
+                msg = "服务器好像出了点问题,请联系系统管理员...";
+                error = $"{ex.Message}";
+                Function.WriteLog(DateTime.Now.ToString() + "\n500错误:" + ex.ToString(), "Global全局异常");
+                logLevel = NLog.LogLevel.Error;
+                context.Response.StatusCode = 500;
+            }
+            var options = new textJson.JsonSerializerOptions
+            {
+                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
+                PropertyNamingPolicy = textJson.JsonNamingPolicy.CamelCase,
+                WriteIndented = true
+            };
+
+            ApiResult apiResult = new(code, msg);
+            string responseResult = textJson.JsonSerializer.Serialize(apiResult, options);
+            // string ip = HttpContextExtension.GetClientUserIp(context);
+            // var ip_info = IpTool.Search(ip);
+
+            // SysOperLog sysOperLog = new()
+            // {
+            //     Status = 1,
+            //     // OperIp = ip,
+            //     OperUrl = HttpContextExtension.GetRequestUrl(context),
+            //     RequestMethod = context.Request.Method,
+            //     JsonResult = responseResult,
+            //     ErrorMsg = string.IsNullOrEmpty(error) ? msg : error,
+            //     OperName = HttpContextExtension.GetName(context),
+            //     // OperLocation = ip_info.Province + " " + ip_info.City,
+            //     OperTime = DateTime.Now,
+            //     OperParam = HttpContextExtension.GetRequestValue(context, context.Request.Method)
+            // };
+            var endpoint = GetEndpoint(context);
+            if (endpoint != null)
+            {
+                var logAttribute = endpoint.Metadata.GetMetadata<LogAttribute>();
+                if (logAttribute != null)
+                {
+                    // sysOperLog.BusinessType = (int)logAttribute.BusinessType;
+                    // sysOperLog.Title = logAttribute?.Title;
+                    // sysOperLog.OperParam = logAttribute.IsSaveRequestData ? sysOperLog.OperParam : "";
+                    // sysOperLog.JsonResult = logAttribute.IsSaveResponseData ? sysOperLog.JsonResult : "";
+                }
+            }
+            LogEventInfo ei = new(logLevel, "GlobalExceptionMiddleware", error)
+            {
+                Exception = ex,
+                Message = error
+            };
+            ei.Properties["status"] = 1;//走正常返回都是通过走GlobalExceptionFilter不通过
+            ei.Properties["jsonResult"] = responseResult;
+            // ei.Properties["requestParam"] = sysOperLog.OperParam;
+            // ei.Properties["user"] = sysOperLog.OperName;
+
+            Logger.Log(ei);
+            context.Response.ContentType = "text/json;charset=utf-8";
+            await context.Response.WriteAsync(responseResult, System.Text.Encoding.UTF8);
+
+            // string errorMsg = $"> 操作人:{sysOperLog.OperName}" +
+            //     $"\n> 操作地区:{sysOperLog.OperIp}({sysOperLog.OperLocation})" +
+            //     $"\n> 操作模块:{sysOperLog.Title}" +
+            //     $"\n> 操作地址:{sysOperLog.OperUrl}" +
+            //     $"\n> 错误信息:{msg}\n\n> {error}";
+
+            // SysOperLogService.InsertOperlog(sysOperLog);
+            if (!notice) return;
+        }
+
+        public static Endpoint GetEndpoint(HttpContext context)
+        {
+            if (context == null)
+            {
+                throw new ArgumentNullException(nameof(context));
+            }
+
+            return context.Features.Get<IEndpointFeature>()?.Endpoint;
+        }
+    }
+}

+ 127 - 0
Model/Base/ApiResult.cs

@@ -0,0 +1,127 @@
+using Infrastructure.Constant;
+using System.Collections.Generic;
+
+namespace Infrastructure.Model
+{
+    public class ApiResult : Dictionary<string, object>
+    {
+        /// <summary>
+        /// 状态码
+        /// </summary>
+        public static readonly string CODE_TAG = "status";
+
+        /// <summary>
+        /// 返回内容
+        /// </summary>
+        public static readonly string MSG_TAG = "msg";
+
+        /// <summary>
+        /// 数据对象
+        /// </summary>
+        public static readonly string DATA_TAG = "data";
+
+        /// <summary>
+        /// 初始化一个新创建的APIResult对象,使其表示一个空消息
+        /// </summary>
+        public ApiResult()
+        {
+        }
+
+        /// <summary>
+        /// 初始化一个新创建的 ApiResult 对象
+        /// </summary>
+        /// <param name="code"></param>
+        /// <param name="msg"></param>
+        public ApiResult(int code, string msg)
+        {
+            Add(CODE_TAG, code);
+            Add(MSG_TAG, msg);
+        }
+
+        /// <summary>
+        /// 初始化一个新创建的 ApiResult 对象
+        /// </summary>
+        /// <param name="code"></param>
+        /// <param name="msg"></param>
+        /// <param name="data"></param>
+        public ApiResult(int code, string msg, object data)
+        {
+            Add(CODE_TAG, code);
+            Add(MSG_TAG, msg);
+            if (data != null)
+            {
+                Add(DATA_TAG, data);
+            }
+        }
+
+        /// <summary>
+        /// 返回成功消息
+        /// </summary>
+        /// < returns > 成功消息 </ returns >
+        public static ApiResult Success() { return new ApiResult(HttpStatus.SUCCESS, "success"); }
+
+        /// <summary>
+        /// 返回成功消息
+        /// </summary>
+        /// <param name="data"></param>
+        /// <returns> 成功消息 </returns >
+        public static ApiResult Success(object data) { return new ApiResult(HttpStatus.SUCCESS, "success", data); }
+
+        /// <summary>
+        /// 返回成功消息
+        /// </summary>
+        /// <param name="msg">返回内容</param>
+        /// <returns>成功消息</returns>
+        public static ApiResult Success(string msg) { return new ApiResult(HttpStatus.SUCCESS, msg, null); }
+
+        /// <summary>
+        /// 返回成功消息
+        /// </summary>
+        /// <param name="msg">返回内容</param>
+        /// <param name="data">数据对象</param>
+        /// <returns>成功消息</returns>
+        public static ApiResult Success(string msg, object data) { return new ApiResult(HttpStatus.SUCCESS, msg, data); }
+
+        public static ApiResult Error(ResultCode code, string msg = "")
+        {
+            return Error((int)code, msg);
+        }
+
+        /// <summary>
+        /// 返回失败消息
+        /// </summary>
+        /// <param name="code"></param>
+        /// <param name="msg"></param>
+        /// <returns></returns>
+        public static ApiResult Error(int code, string msg) { return new ApiResult(code, msg); }
+
+        /// <summary>
+        /// 返回失败消息
+        /// </summary>
+        /// <param name="msg"></param>
+        /// <returns></returns>
+        public static ApiResult Error(string msg) { return new ApiResult((int)ResultCode.CUSTOM_ERROR, msg); }
+
+
+        /// <summary>
+        /// 是否为成功消息
+        /// </summary>
+        /// <returns></returns>
+        public bool IsSuccess()
+        {
+            return HttpStatus.SUCCESS == (int)this[CODE_TAG];
+        }
+
+        /// <summary>
+        /// 方便链式调用
+        /// </summary>
+        /// <param name="key"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public ApiResult Put(string key, object value)
+        {
+            Add(key, value);
+            return this;
+        }
+    }
+}

+ 137 - 0
Model/Base/OptionsSetting.cs

@@ -0,0 +1,137 @@
+using System.Collections.Generic;
+
+namespace Infrastructure.Model
+{
+    /// <summary>
+    /// 获取配置文件POCO实体类
+    /// </summary>
+    public class OptionsSetting
+    {
+        /// <summary>
+        /// 是否单点登录
+        /// </summary>
+        public bool SingleLogin { get; set; }
+        /// <summary>
+        /// 是否演示模式
+        /// </summary>
+        public bool DemoMode { get; set; }
+        /// <summary>
+        /// 初始化db
+        /// </summary>
+        public bool InitDb { get; set; }
+        public MailOptions MailOptions { get; set; }
+        public Upload Upload { get; set; }
+        public OssConfigs ossConfigs { get; set; }
+        public JwtSettings JwtSettings { get; set; }
+        public CodeGen CodeGen { get; set; }
+        public List<DbConfigs> DbConfigs { get; set; }
+        public DbConfigs CodeGenDbConfig { get; set; }
+    }
+    /// <summary>
+    /// 发送邮件数据配置
+    /// </summary>
+    public class MailOptions
+    {
+        public string FromName { get; set; }
+        public string FromEmail { get; set; }
+        public string Password { get; set; }
+        public string Smtp { get; set; }
+        public int Port { get; set; }
+        public bool UseSsl { get; set; }
+        public string Signature { get; set; }
+    }
+    /// <summary>
+    /// 上传
+    /// </summary>
+    public class Upload
+    {
+        public string UploadUrl { get; set; }
+        public string LocalSavePath { get; set; }
+        public int MaxSize { get; set; }
+        public string[] NotAllowedExt { get; set; } = new string[0];
+    }
+    /// <summary>
+    /// 阿里云存储
+    /// </summary>
+    public class ALIYUN_OSS
+    {
+        public string REGIONID { get; set; }
+        public string KEY { get; set; }
+        public string SECRET { get; set; }
+        public string BucketName { get; set; }
+        public string DomainUrl { get; set; }
+        public int MaxSize { get; set; } = 100;
+    }
+
+    /// <summary>
+    /// Jwt
+    /// </summary>
+    public class JwtSettings
+    {
+        /// <summary>
+        /// token是谁颁发的
+        /// </summary>
+        public string Issuer { get; set; }
+        /// <summary>
+        /// token可以给那些客户端使用
+        /// </summary>
+        public string Audience { get; set; }
+        /// <summary>
+        /// 加密的key(SecretKey必须大于16个,是大于,不是大于等于)
+        /// </summary>
+        public string SecretKey { get; set; }
+        /// <summary>
+        /// token时间(分)
+        /// </summary>
+        public int Expire { get; set; } = 1440;
+        /// <summary>
+        /// 刷新token时长
+        /// </summary>
+        public int RefreshTokenTime { get; set; }
+        /// <summary>
+        /// token类型
+        /// </summary>
+        public string TokenType { get; set; } = "Bearer";
+    }
+
+    public class CodeGen
+    {
+        public bool ShowApp { get; set; }
+        public bool AutoPre { get; set; }
+        public string VuePath { get; set; }
+        public string Author { get; set; }
+        public string TablePrefix { get; set; }
+        public string ModuleName { get; set; }
+        public int FrontTpl { get; set; }
+        public CsharpTypeArr CsharpTypeArr { get; set; }
+    }
+
+    public class DbConfigs
+    {
+        public string Conn { get; set; }
+        public int DbType { get; set; }
+        public string ConfigId { get; set; }
+        public bool IsAutoCloseConnection { get; set; }
+        public string DbName { get; set; }
+    }
+
+    public class CsharpTypeArr
+    {
+        public string[] String { get; set; }
+        public string[] Int { get; set; }
+        public string[] Long { get; set; }
+        public string[] DateTime { get; set; }
+        public string[] Float { get; set; }
+        public string[] Decimal { get; set; }
+        public string[] Bool { get; set; }
+    }
+
+    public class OssConfigs
+    {
+        public string Host { get; set; }
+        public string Endpoint { get; set; }
+        public string Key { get; set; }
+        public string Secret { get; set; }
+        public string BucketName { get; set; }
+    }
+}

+ 46 - 0
Model/Base/PagedInfo.cs

@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+
+namespace Model.Base
+{
+    /// <summary>
+    /// 分页参数
+    /// </summary>
+    public class PagedInfo<T>
+    {
+        /// <summary>
+        /// 每页行数
+        /// </summary>
+        public int PageSize { get; set; } = 10;
+        /// <summary>
+        /// 当前页
+        /// </summary>
+        public int PageIndex { get; set; } = 1;
+        /// <summary>
+        /// 总记录数
+        /// </summary>
+        public int Total { get; set; }
+        /// <summary>
+        /// 总页数
+        /// </summary>
+        public int TotalPage
+        {
+            get
+            {
+                if (Total > 0)
+                {
+                    return Total % this.PageSize == 0 ? Total / this.PageSize : Total / this.PageSize + 1;
+                }
+                else
+                {
+                    return 0;
+                }
+            }
+            set { }
+        }
+        public List<T> Records { get; set; }
+        public Dictionary<string, object> Extra { get; set; } = new Dictionary<string, object>();
+        public PagedInfo()
+        {
+        }
+    }
+}

+ 37 - 0
Model/Base/PagerInfo.cs

@@ -0,0 +1,37 @@
+namespace Model.Base
+{
+    public class PagerInfo
+    {
+        /// <summary>
+        /// 当前页码
+        /// </summary>
+        public int pageNum { get; set; }
+        /// <summary>
+        /// 每页显示多少条
+        /// </summary>
+        public int pageSize { get; set; }
+        /// <summary>
+        /// 总记录数
+        /// </summary>
+        public int totalNum { get; set; }
+        /// <summary>
+        /// 排序字段
+        /// </summary>
+        public string sort { get; set; } = string.Empty;
+        /// <summary>
+        /// 排序类型,前端传入的是"ascending","descending"
+        /// </summary>
+        public string sortType { get; set; } = string.Empty;
+        public PagerInfo()
+        {
+            pageNum = 1;
+            pageSize = 20;
+        }
+
+        public PagerInfo(int page = 1, int pageSize = 20)
+        {
+            pageNum = page;
+            pageSize = pageSize;
+        }
+    }
+}

+ 45 - 0
Model/Base/SysBase.cs

@@ -0,0 +1,45 @@
+using MiniExcelLibs.Attributes;
+using Newtonsoft.Json;
+
+namespace Model
+{
+    //[EpplusTable(PrintHeaders = true, AutofitColumns = true, AutoCalculate = true, ShowTotal = true)]
+    public class SysBase
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        [SugarColumn(ColumnDescription = "排序", DefaultValue = "0", ColumnName = "sort")]
+        public int Sort { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态", DefaultValue = "0", ColumnName = "status")]
+        public int Status { get; set; }
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", DefaultValue = "0", ColumnName = "version")]
+        public int Version { get; set; }
+
+        /// <summary>
+        /// 发布时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "发布时间", ColumnName = "create_date")]
+        public DateTime? CreateDate { get; set; }
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_date")]
+        public DateTime? UpdateDate { get; set; }
+    }
+}

+ 44 - 0
Model/Base/TokenModel.cs

@@ -0,0 +1,44 @@
+namespace Model.Base
+{
+    public class TokenModel
+    {
+        public long userId { get; set; }
+        public long deptId { get; set; }
+        public string username { get; set; }
+        /// <summary>
+        /// 角色集合
+        /// </summary>
+        public List<string> RoleIds { get; set; }
+        /// <summary>
+        /// 角色集合(数据权限过滤使用)
+        /// </summary>
+        public List<Roles> Roles { get; set; }
+        /// <summary>
+        /// Jwt过期时间
+        /// </summary>
+        public DateTime ExpireTime { get; set; }
+        /// <summary>
+        /// 权限集合
+        /// </summary>
+        //public List<string> Permissions { get; set; } = new List<string>();
+        public TokenModel()
+        {
+        }
+
+        public TokenModel(TokenModel info, List<Roles> roles)
+        {
+            userId = info.userId;
+            username = info.username;
+            deptId = info.deptId;
+            Roles = roles;
+            RoleIds = roles.Select(f => f.RoleKey).ToList();
+        }
+    }
+
+    public class Roles
+    {
+        public long RoleId { get; set; }
+        public string RoleKey { get; set; }
+        public int DataScope { get; set; }
+    }
+}

+ 115 - 0
Model/Base/UserConstants.cs

@@ -0,0 +1,115 @@
+namespace Model
+{
+    public class UserConstants
+    {
+        /// <summary>
+        /// 平台内系统用户的唯一标志
+        /// </summary>
+        public static string SYS_USER = "SYS_USER";
+
+        /// <summary>
+        /// 正常状态
+        /// </summary>
+        public static string NORMAL = "0";
+
+        /// <summary>
+        /// 异常状态
+        /// </summary>
+        public static string EXCEPTION = "1";
+
+        /// <summary>
+        /// 用户封禁状态
+        /// </summary>
+        public static string USER_DISABLE = "1";
+
+        /// <summary>
+        /// 角色封禁状态
+        /// </summary>
+        public static string ROLE_DISABLE = "1";
+
+        /// <summary>
+        /// 部门正常状态
+        /// </summary>
+        public static int DEPT_NORMAL = 0;
+
+        /// <summary>
+        /// 部门停用状态
+        /// </summary>
+        public static string DEPT_DISABLE = "1";
+
+        /// <summary>
+        /// 字典正常状态
+        /// </summary>
+        public static string DICT_NORMAL = "0";
+
+        /// <summary>
+        /// 是否为系统默认(是)
+        /// </summary>
+        public static string YES = "Y";
+
+        /// <summary>
+        /// 是否菜单外链(是)
+        /// </summary>
+        public static string YES_FRAME = "1";
+
+        /// <summary>
+        /// 是否菜单外链(否)
+        /// </summary>
+        public static string NO_FRAME = "0";
+
+        /// <summary>
+        /// 菜单类型(目录)
+        /// </summary>
+        public static string TYPE_DIR = "M";
+
+        /// <summary>
+        /// 菜单类型(菜单)
+        /// </summary>
+        public static string TYPE_MENU = "C";
+
+        /// <summary>
+        /// 菜单类型(按钮)
+        /// </summary>
+        public static string TYPE_BUTTON = "F";
+
+        ///// <summary>
+        ///// 菜单类型(链接)
+        ///// </summary>
+        //public static string TYPE_LINK = "L";
+
+        /// <summary>
+        /// Layout组件标识
+        /// </summary>
+        public static string LAYOUT = "Layout";
+
+        /// <summary>
+        /// ParentView组件标识
+        /// </summary>
+        public static string PARENT_VIEW = "ParentView";
+
+        /// <summary>
+        /// InnerLink组件标识
+        /// </summary>
+        public static string INNER_LINK = "InnerLink";
+
+        /// <summary>
+        /// 校验返回结果码
+        /// </summary>
+        public static string UNIQUE = "0";
+        public static string NOT_UNIQUE = "1";
+
+        /// <summary>
+        /// http请求
+        /// </summary>
+        public static string HTTP = "http://";
+
+        /// <summary>
+        /// https请求
+        /// </summary>
+        public static string HTTPS = "https://";
+        /// <summary>
+        /// www主域
+        /// </summary>
+        public static string WWW = "www.";
+    }
+}

+ 11 - 0
Model/Customer/AppResultJson.cs

@@ -0,0 +1,11 @@
+namespace Model.Customer
+{
+    public class AppResultJson
+    {
+        public string Info { get; set; }
+        public object Data { get; set; }
+        public object Other { get; set; }
+        public string Status { get; set; }
+        public int Timestamp { get; set; }
+    }
+}

+ 197 - 0
Model/Database/AppBottomNavs.cs

@@ -0,0 +1,197 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// app底部导航 app_bottom_navs
+    /// </summary>
+    [SugarTable("app_bottom_navs", "app底部导航")]
+    [Tenant("0")]
+    public class AppBottomNavs
+    {
+        /// <summary>
+        /// 标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "标题", Length = 10, ColumnName = "title")]
+        public string title { get; set; }
+
+
+        /// <summary>
+        /// 选中图标
+        /// </summary>
+        [SugarColumn(ColumnDescription = "选中图标", Length = 200, ColumnName = "select_icon")]
+        public string selectIcon { get; set; }
+
+
+        /// <summary>
+        /// 未选中图标
+        /// </summary>
+        [SugarColumn(ColumnDescription = "未选中图标", Length = 200, ColumnName = "normal_icon")]
+        public string normalIcon { get; set; }
+
+
+        /// <summary>
+        /// 选中文字颜色
+        /// </summary>
+        [SugarColumn(ColumnDescription = "选中文字颜色", Length = 6, ColumnName = "select_text_color")]
+        public string selectTextColor { get; set; }
+
+
+        /// <summary>
+        /// 未选中文字颜色
+        /// </summary>
+        [SugarColumn(ColumnDescription = "未选中文字颜色", Length = 6, ColumnName = "normal_text_color")]
+        public string normalTextColor { get; set; }
+
+
+        /// <summary>
+        /// 关联页面文件
+        /// </summary>
+        [SugarColumn(ColumnDescription = "关联页面文件", Length = 50, ColumnName = "page_name")]
+        public string pageName { get; set; }
+
+
+        /// <summary>
+        /// 空页面提示信息
+        /// </summary>
+        [SugarColumn(ColumnDescription = "空页面提示信息", Length = 50, ColumnName = "no_page_hint")]
+        public string noPageHint { get; set; }
+
+
+        /// <summary>
+        /// 背景色
+        /// </summary>
+        [SugarColumn(ColumnDescription = "背景色", Length = 6, ColumnName = "backgroud_color")]
+        public string backgroudColor { get; set; }
+
+
+        /// <summary>
+        /// 按钮样式
+        /// </summary>
+        [SugarColumn(ColumnDescription = "按钮样式", Length = 30, ColumnName = "style")]
+        public string style { get; set; }
+
+
+        /// <summary>
+        /// 滚动图片
+        /// </summary>
+        [SugarColumn(ColumnDescription = "滚动图片", Length = 300, ColumnName = "scroller_animation_images")]
+        public string scrollerAnimationImages { get; set; }
+
+
+        /// <summary>
+        /// PAG文件
+        /// </summary>
+        [SugarColumn(ColumnDescription = "PAG文件", Length = 200, ColumnName = "pag_path")]
+        public string pagPath { get; set; }
+
+
+        /// <summary>
+        /// 是否显示标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否显示标题", ColumnName = "show_title")]
+        public bool showTitle { get; set; }
+
+
+        /// <summary>
+        /// pag文件路径
+        /// </summary>
+        [SugarColumn(ColumnDescription = "pag文件路径", Length = 200, ColumnName = "pag_local_path")]
+        public string pagLocalPath { get; set; }
+
+
+        /// <summary>
+        /// pag默认图标
+        /// </summary>
+        [SugarColumn(ColumnDescription = "pag默认图标", Length = 200, ColumnName = "pag_default_icon")]
+        public string pagDefaultIcon { get; set; }
+
+
+        /// <summary>
+        /// 图标尺寸
+        /// </summary>
+        [SugarColumn(ColumnDescription = "图标尺寸", ColumnName = "icon_size")]
+        public int iconSize { get; set; }
+
+
+        /// <summary>
+        /// 状态栏底色
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态栏底色", Length = 50, ColumnName = "status_bar_color")]
+        public string statusBarColor { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态", ColumnName = "status")]
+        public int status { get; set; }
+
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        [SugarColumn(ColumnDescription = "排序", ColumnName = "sort")]
+        public int sort { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_date")]
+        public DateTime? createDate { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_date")]
+        public DateTime? updateDate { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [SugarColumn(ColumnDescription = "分类", Length = 50, ColumnName = "kind")]
+        public string kind { get; set; }
+
+
+        /// <summary>
+        /// 是否PAG
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否PAG", ColumnName = "pag_flag")]
+        public bool pagFlag { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "模板版本号", Length = 50, ColumnName = "app_version")]
+        public string appVersion { get; set; }
+
+
+        /// <summary>
+        /// 自定义分类
+        /// </summary>
+        [SugarColumn(ColumnDescription = "自定义分类", Length = 50, ColumnName = "customer_kind")]
+        public string customerKind { get; set; }
+
+
+
+    }
+}

+ 108 - 0
Model/Database/AppReportRecord.cs

@@ -0,0 +1,108 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// app上报记录 app_report_record
+    /// </summary>
+    [SplitTable(SplitType.Month)]
+    [SugarTable("app_report_record_{year}{month}{day}", "app上报记录")]
+    [Tenant("0")]
+    public class AppReportRecord
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, ColumnName = "id")]
+        public long id { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 删除标记
+        /// </summary>
+        [SugarColumn(ColumnDescription = "删除标记", ColumnName = "del_flag")]
+        public int delFlag { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SplitField]
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_time")]
+        public DateTime? createTime { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_time")]
+        public DateTime? updateTime { get; set; }
+
+
+        /// <summary>
+        /// 上报版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "上报版本号", Length = 20, ColumnName = "app_version")]
+        public string? appVersion { get; set; }
+
+
+        /// <summary>
+        /// 用户标识
+        /// </summary>
+        [SugarColumn(ColumnDescription = "用户标识", Length = 50, ColumnName = "user_tag")]
+        public string? userTag { get; set; }
+
+
+        /// <summary>
+        /// 页面标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "页面标题", Length = 50, ColumnName = "page_title")]
+        public string? pageTitle { get; set; }
+
+
+        /// <summary>
+        /// 页面地址
+        /// </summary>
+        [SugarColumn(ColumnDescription = "页面地址", Length = 200, ColumnName = "page_url")]
+        public string? pageUrl { get; set; }
+
+
+        /// <summary>
+        /// 用户系统信息
+        /// </summary>
+        [SugarColumn(ColumnDescription = "用户系统信息", ColumnName = "user_sys_info")]
+        public string? userSysInfo { get; set; }
+
+
+        /// <summary>
+        /// 设备尺寸
+        /// </summary>
+        [SugarColumn(ColumnDescription = "设备尺寸", Length = 50, ColumnName = "device_size")]
+        public string? deviceSize { get; set; }
+
+
+        /// <summary>
+        /// 上报类型
+        /// </summary>
+        [SugarColumn(ColumnDescription = "上报类型", Length = 50, ColumnName = "report_type")]
+        public string? reportType { get; set; }
+
+
+        /// <summary>
+        /// 上报数据
+        /// </summary>
+        [SugarColumn(ColumnDescription = "上报数据", ColumnName = "report_data")]
+        public string? reportData { get; set; }
+
+
+
+    }
+}

+ 148 - 0
Model/Database/AppSourceSet.cs

@@ -0,0 +1,148 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// 资源配置 app_source_set
+    /// </summary>
+    [SugarTable("app_source_set", "资源配置")]
+    [Tenant("0")]
+    public class AppSourceSet
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 删除标记
+        /// </summary>
+        [SugarColumn(ColumnDescription = "删除标记", ColumnName = "del_flag")]
+        public int delFlag { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_time")]
+        public DateTime? createTime { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_time")]
+        public DateTime? updateTime { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [SugarColumn(ColumnDescription = "分类", Length = 50, ColumnName = "kind")]
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 项目
+        /// </summary>
+        [SugarColumn(ColumnDescription = "项目", ColumnName = "project_id")]
+        public int projectId { get; set; }
+
+
+        /// <summary>
+        /// 主机头
+        /// </summary>
+        [SugarColumn(ColumnDescription = "主机头", Length = 100, ColumnName = "host")]
+        public string? host { get; set; }
+
+
+        /// <summary>
+        /// 容器名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "容器名", Length = 50, ColumnName = "bucket_name")]
+        public string? bucketName { get; set; }
+
+
+        /// <summary>
+        /// 终端地址
+        /// </summary>
+        [SugarColumn(ColumnDescription = "终端地址", Length = 100, ColumnName = "end_point")]
+        public string? endPoint { get; set; }
+
+
+        /// <summary>
+        /// 阿里云ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "阿里云ID", Length = 50, ColumnName = "access_key_id")]
+        public string? accessKeyId { get; set; }
+
+
+        /// <summary>
+        /// 阿里云密钥
+        /// </summary>
+        [SugarColumn(ColumnDescription = "阿里云密钥", Length = 50, ColumnName = "access_key_secret")]
+        public string? accessKeySecret { get; set; }
+
+
+        /// <summary>
+        /// 目录名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "目录名", Length = 100, ColumnName = "path")]
+        public string? path { get; set; }
+
+
+        /// <summary>
+        /// 来源主机头
+        /// </summary>
+        [SugarColumn(ColumnDescription = "来源主机头", Length = 100, ColumnName = "source_host")]
+        public string? sourceHost { get; set; }
+
+
+        /// <summary>
+        /// 来源容器名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "来源容器名", Length = 50, ColumnName = "source_bucket_name")]
+        public string? sourceBucketName { get; set; }
+
+
+        /// <summary>
+        /// 来源终端地址
+        /// </summary>
+        [SugarColumn(ColumnDescription = "来源终端地址", Length = 100, ColumnName = "source_end_point")]
+        public string? sourceEndPoint { get; set; }
+
+
+        /// <summary>
+        /// 来源阿里云ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "来源阿里云ID", Length = 50, ColumnName = "source_access_key_id")]
+        public string? sourceAccessKeyId { get; set; }
+
+
+        /// <summary>
+        /// 来源阿里云密钥
+        /// </summary>
+        [SugarColumn(ColumnDescription = "来源阿里云密钥", Length = 50, ColumnName = "source_access_key_secret")]
+        public string? sourceAccessKeySecret { get; set; }
+
+
+        /// <summary>
+        /// 来源目录名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "来源目录名", Length = 100, ColumnName = "source_path")]
+        public string? sourcePath { get; set; }
+
+
+
+    }
+}

+ 71 - 0
Model/Database/AppSourceVersion.cs

@@ -0,0 +1,71 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// 资源版本配置 app_source_version
+    /// </summary>
+    [SugarTable("app_source_version", "资源版本配置")]
+    [Tenant("0")]
+    public class AppSourceVersion
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 删除标记
+        /// </summary>
+        [SugarColumn(ColumnDescription = "删除标记", ColumnName = "del_flag")]
+        public int delFlag { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_time")]
+        public DateTime? createTime { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_time")]
+        public DateTime? updateTime { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", Length = 20, ColumnName = "app_version")]
+        public string? appVersion { get; set; }
+
+
+        /// <summary>
+        /// 所属资源ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "所属资源ID", ColumnName = "source_id")]
+        public int sourceId { get; set; }
+
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        [SugarColumn(ColumnDescription = "备注", Length = 200, ColumnName = "note")]
+        public string? note { get; set; }
+
+
+
+    }
+}

+ 120 - 0
Model/Database/AppVersion.cs

@@ -0,0 +1,120 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// app版本管理 app_version
+    /// </summary>
+    [SugarTable("app_version", "app版本管理")]
+    [Tenant("0")]
+    public class AppVersion
+    {
+        /// <summary>
+        /// 终端类型
+        /// </summary>
+        [SugarColumn(ColumnDescription = "终端类型", Length = 10, ColumnName = "terminal_kind")]
+        public string terminalKind { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", Length = 20, ColumnName = "version_num")]
+        public string versionNum { get; set; }
+
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "标题", Length = 50, ColumnName = "title")]
+        public string title { get; set; }
+
+
+        /// <summary>
+        /// 更新信息
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新信息", Length = 200, ColumnName = "info")]
+        public string info { get; set; }
+
+
+        /// <summary>
+        /// 确定按钮文字
+        /// </summary>
+        [SugarColumn(ColumnDescription = "确定按钮文字", Length = 10, ColumnName = "confirm_text")]
+        public string confirmText { get; set; }
+
+
+        /// <summary>
+        /// 取消按钮文字
+        /// </summary>
+        [SugarColumn(ColumnDescription = "取消按钮文字", Length = 10, ColumnName = "cancel_text")]
+        public string cancelText { get; set; }
+
+
+        /// <summary>
+        /// 更新地址
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新地址", Length = 500, ColumnName = "download_url")]
+        public string downloadUrl { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态", ColumnName = "status")]
+        public int status { get; set; }
+
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        [SugarColumn(ColumnDescription = "排序", ColumnName = "sort")]
+        public int sort { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_date")]
+        public DateTime? createDate { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_date")]
+        public DateTime? updateDate { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [SugarColumn(ColumnDescription = "分类", Length = 50, ColumnName = "kind")]
+        public string kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "模板版本号", Length = 50, ColumnName = "app_version")]
+        public string appVersion { get; set; }
+
+
+
+    }
+}

+ 92 - 0
Model/Database/FileUpdateInfo.cs

@@ -0,0 +1,92 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// 资源文件更新信息 file_update_info
+    /// </summary>
+    [SugarTable("file_update_info", "资源文件更新信息")]
+    [Tenant("0")]
+    public class FileUpdateInfo
+    {
+        /// <summary>
+        /// 更新版本
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新版本", ColumnName = "version_num")]
+        public int versionNum { get; set; }
+
+
+        /// <summary>
+        /// 路径
+        /// </summary>
+        [SugarColumn(ColumnDescription = "路径", Length = 200, ColumnName = "path")]
+        public string path { get; set; }
+
+
+        /// <summary>
+        /// 文件名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "文件名", Length = 50, ColumnName = "file_name")]
+        public string fileName { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态", ColumnName = "status")]
+        public int status { get; set; }
+
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        [SugarColumn(ColumnDescription = "排序", ColumnName = "sort")]
+        public int sort { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_date")]
+        public DateTime? createDate { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_date")]
+        public DateTime? updateDate { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [SugarColumn(ColumnDescription = "分类", Length = 50, ColumnName = "kind")]
+        public string kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "模板版本号", Length = 50, ColumnName = "app_version")]
+        public string appVersion { get; set; }
+
+
+
+    }
+}

+ 211 - 0
Model/Database/PageUpdateInfo.cs

@@ -0,0 +1,211 @@
+using Mapster;
+
+
+namespace Model
+{
+    /// <summary>
+    /// 页面模板更新信息 page_update_info
+    /// </summary>
+    [SugarTable("page_update_info", "页面模板更新信息")]
+    [Tenant("0")]
+    public class PageUpdateInfo
+    {
+        /// <summary>
+        /// 模板更新版本
+        /// </summary>
+        [SugarColumn(ColumnDescription = "模板更新版本", ColumnName = "module_version")]
+        public int moduleVersion { get; set; }
+
+
+        /// <summary>
+        /// 模板路径
+        /// </summary>
+        [SugarColumn(ColumnDescription = "模板路径", Length = 200, ColumnName = "module_path")]
+        public string modulePath { get; set; }
+
+
+        /// <summary>
+        /// 背景色
+        /// </summary>
+        [SugarColumn(ColumnDescription = "背景色", Length = 6, ColumnName = "backgroud_color")]
+        public string backgroudColor { get; set; }
+
+
+        /// <summary>
+        /// 前景色
+        /// </summary>
+        [SugarColumn(ColumnDescription = "前景色", Length = 6, ColumnName = "text_color")]
+        public string textColor { get; set; }
+
+
+        /// <summary>
+        /// 苹果状态栏
+        /// </summary>
+        [SugarColumn(ColumnDescription = "苹果状态栏", Length = 10, ColumnName = "status_bar_style")]
+        public string statusBarStyle { get; set; }
+
+
+        /// <summary>
+        /// 是否显示头部
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否显示头部", ColumnName = "show_title")]
+        public bool showTitle { get; set; }
+
+
+        /// <summary>
+        /// 顶部标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "顶部标题", Length = 50, ColumnName = "title")]
+        public string title { get; set; }
+
+
+        /// <summary>
+        /// 是否显示滚动条
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否显示滚动条", ColumnName = "show_scroll_bar")]
+        public bool showScrollBar { get; set; }
+
+
+        /// <summary>
+        /// 是否侧滑返回
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否侧滑返回", ColumnName = "skid_flag")]
+        public bool skidFlag { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮1
+        /// </summary>
+        [SugarColumn(ColumnDescription = "左侧按钮1", Length = 100, ColumnName = "left_btn_1")]
+        public string leftBtn1 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮2
+        /// </summary>
+        [SugarColumn(ColumnDescription = "左侧按钮2", Length = 50, ColumnName = "left_btn_2")]
+        public string leftBtn2 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮1
+        /// </summary>
+        [SugarColumn(ColumnDescription = "右侧按钮1", Length = 50, ColumnName = "right_btn_1")]
+        public string rightBtn1 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮2
+        /// </summary>
+        [SugarColumn(ColumnDescription = "右侧按钮2", Length = 50, ColumnName = "right_btn_2")]
+        public string rightBtn2 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮1点击事件
+        /// </summary>
+        [SugarColumn(ColumnDescription = "左侧按钮1点击事件", ColumnName = "left_action_1")]
+        public string leftAction1 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮2点击事件
+        /// </summary>
+        [SugarColumn(ColumnDescription = "左侧按钮2点击事件", ColumnName = "left_action_2")]
+        public string leftAction2 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮1点击事件
+        /// </summary>
+        [SugarColumn(ColumnDescription = "右侧按钮1点击事件", ColumnName = "right_action_1")]
+        public string rightAction1 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮2点击事件
+        /// </summary>
+        [SugarColumn(ColumnDescription = "右侧按钮2点击事件", ColumnName = "right_action_2")]
+        public string rightAction2 { get; set; }
+
+
+        /// <summary>
+        /// 下级页面
+        /// </summary>
+        [SugarColumn(ColumnDescription = "下级页面", Length = 500, ColumnName = "goto_pages")]
+        public string gotoPages { get; set; }
+
+
+        /// <summary>
+        /// 是否强制更新
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否强制更新", ColumnName = "must_update")]
+        public bool mustUpdate { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "ID", IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        [SugarColumn(ColumnDescription = "状态", ColumnName = "status")]
+        public int status { get; set; }
+
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        [SugarColumn(ColumnDescription = "排序", ColumnName = "sort")]
+        public int sort { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "版本号", ColumnName = "version")]
+        public int version { get; set; }
+
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "创建时间", ColumnName = "create_date")]
+        public DateTime? createDate { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "更新时间", ColumnName = "update_date")]
+        public DateTime? updateDate { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [SugarColumn(ColumnDescription = "分类", Length = 50, ColumnName = "kind")]
+        public string kind { get; set; }
+
+
+        /// <summary>
+        /// 是否读取网页标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否读取网页标题", ColumnName = "web_title")]
+        public bool webTitle { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "模板版本号", Length = 50, ColumnName = "app_version")]
+        public string appVersion { get; set; }
+
+
+
+    }
+}

+ 136 - 0
Model/Dto/AppBottomNavsAddDto.cs

@@ -0,0 +1,136 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class AppBottomNavsAddDto
+    {
+        /// <summary>
+        /// 标题
+        /// </summary>
+        [Required(ErrorMessage = "标题不能为空")]
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 选中图标
+        /// </summary>
+        public string? selectIcon { get; set; }
+
+
+        /// <summary>
+        /// 未选中图标
+        /// </summary>
+        public string? normalIcon { get; set; }
+
+
+        /// <summary>
+        /// 选中文字颜色
+        /// </summary>
+        public string? selectTextColor { get; set; }
+
+
+        /// <summary>
+        /// 未选中文字颜色
+        /// </summary>
+        public string? normalTextColor { get; set; }
+
+
+        /// <summary>
+        /// 关联页面文件
+        /// </summary>
+        public string? pageName { get; set; }
+
+
+        /// <summary>
+        /// 空页面提示信息
+        /// </summary>
+        public string? noPageHint { get; set; }
+
+
+        /// <summary>
+        /// 背景色
+        /// </summary>
+        public string? backgroudColor { get; set; }
+
+
+        /// <summary>
+        /// 按钮样式
+        /// </summary>
+        public string? style { get; set; }
+
+
+        /// <summary>
+        /// 滚动图片
+        /// </summary>
+        public string? scrollerAnimationImages { get; set; }
+
+
+        /// <summary>
+        /// PAG文件
+        /// </summary>
+        public string? pagPath { get; set; }
+
+
+        /// <summary>
+        /// 是否显示标题
+        /// </summary>
+        public bool showTitle { get; set; }
+
+
+        /// <summary>
+        /// pag文件路径
+        /// </summary>
+        public string? pagLocalPath { get; set; }
+
+
+        /// <summary>
+        /// pag默认图标
+        /// </summary>
+        public string? pagDefaultIcon { get; set; }
+
+
+        /// <summary>
+        /// 图标尺寸
+        /// </summary>
+        public int iconSize { get; set; }
+
+
+        /// <summary>
+        /// 状态栏底色
+        /// </summary>
+        public string? statusBarColor { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [Required(ErrorMessage = "分类不能为空")]
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 是否PAG
+        /// </summary>
+        public bool pagFlag { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string appVersion { get; set; }
+
+
+        /// <summary>
+        /// 自定义分类
+        /// </summary>
+        public string? customerKind { get; set; }
+
+
+
+    }
+}

+ 26 - 0
Model/Dto/AppBottomNavsListDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 列表
+    /// </summary>
+    public class AppBottomNavsListDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 20 - 0
Model/Dto/AppBottomNavsQueryDto.cs

@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 详情
+    /// </summary>
+    public class AppBottomNavsQueryDto
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 129 - 0
Model/Dto/AppBottomNavsUpdateDto.cs

@@ -0,0 +1,129 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public class AppBottomNavsUpdateDto
+    {
+        /// <summary>
+        /// 标题
+        /// </summary>
+        [Required(ErrorMessage = "标题不能为空")]
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 选中图标
+        /// </summary>
+        public string? selectIcon { get; set; }
+
+
+        /// <summary>
+        /// 未选中图标
+        /// </summary>
+        public string? normalIcon { get; set; }
+
+
+        /// <summary>
+        /// 选中文字颜色
+        /// </summary>
+        public string? selectTextColor { get; set; }
+
+
+        /// <summary>
+        /// 未选中文字颜色
+        /// </summary>
+        public string? normalTextColor { get; set; }
+
+
+        /// <summary>
+        /// 关联页面文件
+        /// </summary>
+        public string? pageName { get; set; }
+
+
+        /// <summary>
+        /// 空页面提示信息
+        /// </summary>
+        public string? noPageHint { get; set; }
+
+
+        /// <summary>
+        /// 背景色
+        /// </summary>
+        public string? backgroudColor { get; set; }
+
+
+        /// <summary>
+        /// 按钮样式
+        /// </summary>
+        public string? style { get; set; }
+
+
+        /// <summary>
+        /// 滚动图片
+        /// </summary>
+        public string? scrollerAnimationImages { get; set; }
+
+
+        /// <summary>
+        /// PAG文件
+        /// </summary>
+        public string? pagPath { get; set; }
+
+
+        /// <summary>
+        /// 是否显示标题
+        /// </summary>
+        public bool showTitle { get; set; }
+
+
+        /// <summary>
+        /// pag文件路径
+        /// </summary>
+        public string? pagLocalPath { get; set; }
+
+
+        /// <summary>
+        /// pag默认图标
+        /// </summary>
+        public string? pagDefaultIcon { get; set; }
+
+
+        /// <summary>
+        /// 图标尺寸
+        /// </summary>
+        public int iconSize { get; set; }
+
+
+        /// <summary>
+        /// 状态栏底色
+        /// </summary>
+        public string? statusBarColor { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 是否PAG
+        /// </summary>
+        public bool pagFlag { get; set; }
+
+
+        /// <summary>
+        /// 自定义分类
+        /// </summary>
+        public string? customerKind { get; set; }
+
+
+
+    }
+}

+ 109 - 0
Model/Dto/AppSourceSetDto.cs

@@ -0,0 +1,109 @@
+using Mapster;
+
+
+namespace Dto
+{
+    /// <summary>
+    /// 资源配置 app_source_set
+    /// </summary>
+    public class AppSourceSetDto
+    {
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime? createTime { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public DateTime? updateTime { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 项目
+        /// </summary>
+        public int projectId { get; set; }
+
+
+        /// <summary>
+        /// 主机头
+        /// </summary>
+        public string? host { get; set; }
+
+
+        /// <summary>
+        /// 容器名
+        /// </summary>
+        public string? bucketName { get; set; }
+
+
+        /// <summary>
+        /// 终端地址
+        /// </summary>
+        public string? endPoint { get; set; }
+
+
+        /// <summary>
+        /// 阿里云ID
+        /// </summary>
+        public string? accessKeyId { get; set; }
+
+
+        /// <summary>
+        /// 阿里云密钥
+        /// </summary>
+        public string? accessKeySecret { get; set; }
+
+
+        /// <summary>
+        /// 目录名
+        /// </summary>
+        public string? path { get; set; }
+
+
+        /// <summary>
+        /// 来源主机头
+        /// </summary>
+        public string? sourceHost { get; set; }
+
+
+        /// <summary>
+        /// 来源容器名
+        /// </summary>
+        public string? sourceBucketName { get; set; }
+
+
+        /// <summary>
+        /// 来源终端地址
+        /// </summary>
+        public string? sourceEndPoint { get; set; }
+
+
+        /// <summary>
+        /// 来源阿里云ID
+        /// </summary>
+        public string? sourceAccessKeyId { get; set; }
+
+
+        /// <summary>
+        /// 来源阿里云密钥
+        /// </summary>
+        public string? sourceAccessKeySecret { get; set; }
+
+
+        /// <summary>
+        /// 来源目录名
+        /// </summary>
+        public string? sourcePath { get; set; }
+
+
+
+    }
+}

+ 43 - 0
Model/Dto/AppSourceVersionDto.cs

@@ -0,0 +1,43 @@
+using Mapster;
+
+
+namespace Dto
+{
+    /// <summary>
+    /// 资源版本配置 app_source_version
+    /// </summary>
+    public class AppSourceVersionDto
+    {
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime? createTime { get; set; }
+
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public DateTime? updateTime { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+        /// <summary>
+        /// 所属资源ID
+        /// </summary>
+        public int sourceId { get; set; }
+
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string? note { get; set; }
+
+
+
+    }
+}

+ 62 - 0
Model/Dto/AppVersionAddDto.cs

@@ -0,0 +1,62 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class AppVersionAddDto
+    {
+        /// <summary>
+        /// 终端类型
+        /// </summary>
+        public string? terminalKind { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        public string? versionNum { get; set; }
+
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 更新信息
+        /// </summary>
+        public string? info { get; set; }
+
+
+        /// <summary>
+        /// 确定按钮文字
+        /// </summary>
+        public string? confirmText { get; set; }
+
+
+        /// <summary>
+        /// 取消按钮文字
+        /// </summary>
+        public string? cancelText { get; set; }
+
+
+        /// <summary>
+        /// 更新地址
+        /// </summary>
+        public string? downloadUrl { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+
+    }
+}

+ 24 - 0
Model/Dto/AppVersionLastDto.cs

@@ -0,0 +1,24 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 详情
+    /// </summary>
+    public class AppVersionLastDto
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        public string terminalKind { get; set; }
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+    }
+}

+ 26 - 0
Model/Dto/AppVersionListDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 列表
+    /// </summary>
+    public class AppVersionListDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 20 - 0
Model/Dto/AppVersionQueryDto.cs

@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 详情
+    /// </summary>
+    public class AppVersionQueryDto
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 62 - 0
Model/Dto/AppVersionUpdateDto.cs

@@ -0,0 +1,62 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public class AppVersionUpdateDto
+    {
+        /// <summary>
+        /// 终端类型
+        /// </summary>
+        public string? terminalKind { get; set; }
+
+
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        public string? versionNum { get; set; }
+
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 更新信息
+        /// </summary>
+        public string? info { get; set; }
+
+
+        /// <summary>
+        /// 确定按钮文字
+        /// </summary>
+        public string? confirmText { get; set; }
+
+
+        /// <summary>
+        /// 取消按钮文字
+        /// </summary>
+        public string? cancelText { get; set; }
+
+
+        /// <summary>
+        /// 更新地址
+        /// </summary>
+        public string? downloadUrl { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 21 - 0
Model/Dto/Base/OssUploadDto.cs

@@ -0,0 +1,21 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 底部导航列表
+    /// </summary>
+    public class OssUploadDto
+    {
+        /// <summary>
+        /// 上传文件路径
+        /// </summary>
+        [Required(ErrorMessage = "文件上传路径不能为空")]
+        public string dir { get; set; }
+
+
+
+    }
+}

+ 27 - 0
Model/Dto/Client/AppAppBottomNavsDto.cs

@@ -0,0 +1,27 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 底部导航列表
+    /// </summary>
+    public class AppAppBottomNavsDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [Required(ErrorMessage = "分类不能为空")]
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 42 - 0
Model/Dto/Client/AppPageInfoDto.cs

@@ -0,0 +1,42 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 页面数据检查
+    /// </summary>
+    public class AppPageInfoDto
+    {
+        /// <summary>
+        /// 模板更新版本
+        /// </summary>
+        [Required(ErrorMessage = "模板更新版本不能为空")]
+        [RegularExpression(@"^\d+$", ErrorMessage = "模板更新版本格式有误")]
+        public int moduleVersion { get; set; }
+
+
+        /// <summary>
+        /// 模板路径
+        /// </summary>
+        [Required(ErrorMessage = "模板路径不能为空")]
+        public string? modulePath { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [Required(ErrorMessage = "分类不能为空")]
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 27 - 0
Model/Dto/Client/AppStaticFilesDto.cs

@@ -0,0 +1,27 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 静态资源
+    /// </summary>
+    public class AppStaticFilesDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        [Required(ErrorMessage = "分类不能为空")]
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 26 - 0
Model/Dto/CopyDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 详情
+    /// </summary>
+    public class CopyDto
+    {
+        /// <summary>
+        /// 原始版本
+        /// </summary>
+        public string sourceVersion { get; set; }
+
+
+        /// <summary>
+        /// 新建版本
+        /// </summary>
+        public string addVersion { get; set; }
+
+
+
+    }
+}

+ 33 - 0
Model/Dto/FileUpdateInfoAddDto.cs

@@ -0,0 +1,33 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class FileUpdateInfoAddDto
+    {
+        /// <summary>
+        /// 更新版本
+        /// </summary>
+        public int versionNum { get; set; }
+
+
+        /// <summary>
+        /// 路径
+        /// </summary>
+        [Required(ErrorMessage = "路径不能为空")]
+        public string? path { get; set; }
+
+
+        /// <summary>
+        /// 文件名
+        /// </summary>
+        public string? fileName { get; set; }
+
+
+
+    }
+}

+ 26 - 0
Model/Dto/FileUpdateInfoListDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 列表
+    /// </summary>
+    public class FileUpdateInfoListDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 20 - 0
Model/Dto/FileUpdateInfoQueryDto.cs

@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 详情
+    /// </summary>
+    public class FileUpdateInfoQueryDto
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 21 - 0
Model/Dto/FileUpdateInfoUpVersionDto.cs

@@ -0,0 +1,21 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 更新版本号
+    /// </summary>
+    public class FileUpdateInfoUpVersionDto
+    {
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 39 - 0
Model/Dto/FileUpdateInfoUpdateDto.cs

@@ -0,0 +1,39 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public class FileUpdateInfoUpdateDto
+    {
+        /// <summary>
+        /// 更新版本
+        /// </summary>
+        public int versionNum { get; set; }
+
+
+        /// <summary>
+        /// 路径
+        /// </summary>
+        [Required(ErrorMessage = "路径不能为空")]
+        public string? path { get; set; }
+
+
+        /// <summary>
+        /// 文件名
+        /// </summary>
+        public string? fileName { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 31 - 0
Model/Dto/FileUpdateInfoUpdateFileDto.cs

@@ -0,0 +1,31 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 刷新文件
+    /// </summary>
+    public class FileUpdateInfoUpdateFileDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+        /// <summary>
+        /// 项目
+        /// </summary>
+        public int? projectId { get; set; }
+
+
+    }
+}

+ 25 - 0
Model/Dto/MakeAppInitDataDto.cs

@@ -0,0 +1,25 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public class MakeAppInitDataDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+    }
+}

+ 131 - 0
Model/Dto/PageUpdateInfoAddDto.cs

@@ -0,0 +1,131 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class PageUpdateInfoAddDto
+    {
+        /// <summary>
+        /// 模板更新版本
+        /// </summary>
+        [Required(ErrorMessage = "模板更新版本不能为空")]
+        [RegularExpression(@"^\d+$", ErrorMessage = "模板更新版本格式有误")]
+        public int moduleVersion { get; set; }
+
+
+        /// <summary>
+        /// 模板路径
+        /// </summary>
+        [Required(ErrorMessage = "模板路径不能为空")]
+        public string? modulePath { get; set; }
+
+
+        /// <summary>
+        /// 背景色
+        /// </summary>
+        public string? backgroudColor { get; set; }
+
+
+        /// <summary>
+        /// 前景色
+        /// </summary>
+        public string? textColor { get; set; }
+
+
+        /// <summary>
+        /// 苹果状态栏
+        /// </summary>
+        public string? statusBarStyle { get; set; }
+
+
+        /// <summary>
+        /// 是否显示头部
+        /// </summary>
+        public bool showTitle { get; set; }
+
+
+        /// <summary>
+        /// 顶部标题
+        /// </summary>
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 是否显示滚动条
+        /// </summary>
+        public bool showScrollBar { get; set; }
+
+
+        /// <summary>
+        /// 是否侧滑返回
+        /// </summary>
+        public bool skidFlag { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮1
+        /// </summary>
+        public string? leftBtn1 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮2
+        /// </summary>
+        public string? leftBtn2 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮1
+        /// </summary>
+        public string? rightBtn1 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮2
+        /// </summary>
+        public string? rightBtn2 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮1点击事件
+        /// </summary>
+        public string? leftAction1 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮2点击事件
+        /// </summary>
+        public string? leftAction2 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮1点击事件
+        /// </summary>
+        public string? rightAction1 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮2点击事件
+        /// </summary>
+        public string? rightAction2 { get; set; }
+
+
+        /// <summary>
+        /// 下级页面
+        /// </summary>
+        public string? gotoPages { get; set; }
+
+
+        /// <summary>
+        /// 是否强制更新
+        /// </summary>
+        public bool mustUpdate { get; set; }
+
+
+
+    }
+}

+ 38 - 0
Model/Dto/PageUpdateInfoListDto.cs

@@ -0,0 +1,38 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 列表
+    /// </summary>
+    public class PageUpdateInfoListDto
+    {
+        /// <summary>
+        /// 模板路径
+        /// </summary>
+        public string? modulePath { get; set; }
+
+
+        /// <summary>
+        /// 顶部标题
+        /// </summary>
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+
+    }
+}

+ 20 - 0
Model/Dto/PageUpdateInfoQueryDto.cs

@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 详情
+    /// </summary>
+    public class PageUpdateInfoQueryDto
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 20 - 0
Model/Dto/PageUpdateInfoUpVersionDto.cs

@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 更新版本号码
+    /// </summary>
+    public class PageUpdateInfoUpVersionDto
+    {
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+
+    }
+}

+ 143 - 0
Model/Dto/PageUpdateInfoUpdateDto.cs

@@ -0,0 +1,143 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public class PageUpdateInfoUpdateDto
+    {
+        /// <summary>
+        /// 模板更新版本
+        /// </summary>
+        [Required(ErrorMessage = "模板更新版本不能为空")]
+        [RegularExpression(@"^\d+$", ErrorMessage = "模板更新版本格式有误")]
+        public int moduleVersion { get; set; }
+
+
+        /// <summary>
+        /// 模板路径
+        /// </summary>
+        [Required(ErrorMessage = "模板路径不能为空")]
+        public string? modulePath { get; set; }
+
+
+        /// <summary>
+        /// 背景色
+        /// </summary>
+        public string? backgroudColor { get; set; }
+
+
+        /// <summary>
+        /// 前景色
+        /// </summary>
+        public string? textColor { get; set; }
+
+
+        /// <summary>
+        /// 苹果状态栏
+        /// </summary>
+        public string? statusBarStyle { get; set; }
+
+
+        /// <summary>
+        /// 是否显示头部
+        /// </summary>
+        public bool showTitle { get; set; }
+
+
+        /// <summary>
+        /// 顶部标题
+        /// </summary>
+        public string? title { get; set; }
+
+
+        /// <summary>
+        /// 是否显示滚动条
+        /// </summary>
+        public bool showScrollBar { get; set; }
+
+
+        /// <summary>
+        /// 是否侧滑返回
+        /// </summary>
+        public bool skidFlag { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮1
+        /// </summary>
+        public string? leftBtn1 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮2
+        /// </summary>
+        public string? leftBtn2 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮1
+        /// </summary>
+        public string? rightBtn1 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮2
+        /// </summary>
+        public string? rightBtn2 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮1点击事件
+        /// </summary>
+        public string? leftAction1 { get; set; }
+
+
+        /// <summary>
+        /// 左侧按钮2点击事件
+        /// </summary>
+        public string? leftAction2 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮1点击事件
+        /// </summary>
+        public string? rightAction1 { get; set; }
+
+
+        /// <summary>
+        /// 右侧按钮2点击事件
+        /// </summary>
+        public string? rightAction2 { get; set; }
+
+
+        /// <summary>
+        /// 下级页面
+        /// </summary>
+        public string? gotoPages { get; set; }
+
+
+        /// <summary>
+        /// 是否强制更新
+        /// </summary>
+        public bool mustUpdate { get; set; }
+
+
+        /// <summary>
+        /// ID
+        /// </summary>
+        public int id { get; set; }
+
+
+        /// <summary>
+        /// 是否读取网页标题
+        /// </summary>
+        public bool webTitle { get; set; }
+
+
+
+    }
+}

+ 32 - 0
Model/Dto/PageUpdateInfoUpdateTemplateDto.cs

@@ -0,0 +1,32 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Model.Base;
+
+namespace Dto
+{
+    /// <summary>
+    /// 刷新文件
+    /// </summary>
+    public class PageUpdateInfoUpdateTemplateDto
+    {
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public string? kind { get; set; }
+
+
+        /// <summary>
+        /// 模板版本号
+        /// </summary>
+        public string? appVersion { get; set; }
+
+
+        /// <summary>
+        /// 项目
+        /// </summary>
+        public int? projectId { get; set; }
+
+
+
+    }
+}

+ 63 - 0
Model/Enums/BusinessType.cs

@@ -0,0 +1,63 @@
+namespace Enums
+{
+    /// <summary>
+    /// 业务操作类型 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据
+    /// </summary>
+    public enum BusinessType
+    {
+        /// <summary>
+        /// 其它
+        /// </summary>
+        OTHER = 0,
+
+        /// <summary>
+        /// 新增
+        /// </summary>
+        INSERT = 1,
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        UPDATE = 2,
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        DELETE = 3,
+
+        /// <summary>
+        /// 授权
+        /// </summary>
+        GRANT = 4,
+
+        /// <summary>
+        /// 导出
+        /// </summary>
+        EXPORT = 5,
+
+        /// <summary>
+        /// 导入
+        /// </summary>
+        IMPORT = 6,
+
+        /// <summary>
+        /// 强退
+        /// </summary>
+        FORCE = 7,
+
+        /// <summary>
+        /// 生成代码
+        /// </summary>
+        GENCODE = 8,
+
+        /// <summary>
+        /// 清空数据
+        /// </summary>
+        CLEAN = 9,
+
+        /// <summary>
+        /// 下载
+        /// </summary>
+        DOWNLOAD = 10,
+    }
+}

+ 15 - 0
Model/Enums/MenuStatus.cs

@@ -0,0 +1,15 @@
+using System.ComponentModel;
+
+namespace Enums
+{
+    /// <summary>
+    /// 菜单状态(0正常 1停用)
+    /// </summary>
+    public enum MenuStatus
+    {
+        [Description("正常")]
+        正常 = 0,
+        [Description("停用")]
+        停用 = 1,
+    }
+}

+ 19 - 0
Model/Enums/MenuType.cs

@@ -0,0 +1,19 @@
+using System.ComponentModel;
+
+namespace Enums
+{
+    /// <summary>
+    /// M目录 C菜单 F按钮 L链接
+    /// </summary>
+    public enum MenuType
+    {
+        [Description("目录")]
+        M,
+        [Description("菜单")]
+        C,
+        [Description("按钮")]
+        F,
+        [Description("链接")]
+        L
+    }
+}

+ 4 - 0
Model/Enums/ProteryConstant.cs

@@ -0,0 +1,4 @@
+public enum ProteryConstant
+{
+    NOTNULL = 0
+}

+ 40 - 0
Model/Enums/StoreType.cs

@@ -0,0 +1,40 @@
+using System.ComponentModel;
+
+namespace Enums
+{
+    /// <summary>
+    /// 文件存储位置
+    /// </summary>
+    public enum StoreType
+    {
+        /// <summary>
+        /// 本地
+        /// </summary>
+        [Description("本地")]
+        LOCAL = 1,
+
+        /// <summary>
+        /// 阿里云
+        /// </summary>
+        [Description("阿里云")]
+        ALIYUN = 2,
+
+        /// <summary>
+        /// 腾讯云
+        /// </summary>
+        [Description("腾讯云")]
+        TENCENT = 3,
+
+        /// <summary>
+        /// 七牛
+        /// </summary>
+        [Description("七牛云")]
+        QINIU = 4,
+
+        /// <summary>
+        /// 远程
+        /// </summary>
+        [Description("远程")]
+        REMOTE = 5
+    }
+}

+ 48 - 0
Model/Exception/CustomException.cs

@@ -0,0 +1,48 @@
+using System;
+
+namespace Infrastructure
+{
+    public class CustomException : Exception
+    {
+        public int Code { get; set; }
+        /// <summary>
+        /// 前端提示语
+        /// </summary>
+        public string Msg { get; set; }
+        /// <summary>
+        /// 记录到日志的详细内容
+        /// </summary>
+        public string LogMsg { get; set; }
+        /// <summary>
+        /// 是否通知
+        /// </summary>
+        public bool Notice { get; set; } = true;
+
+        public CustomException(string msg) : base(msg)
+        {
+        }
+        public CustomException(int code, string msg) : base(msg)
+        {
+            Code = code;
+            Msg = msg;
+        }
+
+        public CustomException(ResultCode resultCode, string msg, bool notice = true) : base(msg)
+        {
+            Code = (int)resultCode;
+            Notice = notice;
+        }
+
+        /// <summary>
+        /// 自定义异常
+        /// </summary>
+        /// <param name="resultCode"></param>
+        /// <param name="msg"></param>
+        /// <param name="errorMsg">用于记录详细日志到输出介质</param>
+        public CustomException(ResultCode resultCode, string msg, object errorMsg) : base(msg)
+        {
+            Code = (int)resultCode;
+            LogMsg = errorMsg.ToString();
+        }
+    }
+}

+ 46 - 0
Model/Exception/ResultCode.cs

@@ -0,0 +1,46 @@
+using System.ComponentModel;
+
+namespace Infrastructure
+{
+    public enum ResultCode
+    {
+        [Description("success")]
+        SUCCESS = 1,
+
+        [Description("没有更多数据")]
+        NO_DATA = 210,
+
+        [Description("参数错误")]
+        PARAM_ERROR = 101,
+
+        [Description("验证码错误")]
+        CAPTCHA_ERROR = 103,
+
+        [Description("登录错误")]
+        LOGIN_ERROR = 105,
+
+        [Description("操作失败")]
+        FAIL = 100,
+
+        [Description("服务端出错啦")]
+        GLOBAL_ERROR = 500,
+
+        [Description("自定义异常")]
+        CUSTOM_ERROR = 110,
+
+        [Description("非法请求")]
+        INVALID_REQUEST = 116,
+
+        [Description("授权失败")]
+        OAUTH_FAIL = 201,
+
+        [Description("未授权")]
+        DENY = 401,
+
+        [Description("授权访问失败")]
+        FORBIDDEN = 403,
+
+        [Description("Bad Request")]
+        BAD_REQUEST = 400
+    }
+}

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio