Просмотр исходного кода

Merge branch 'v2' of https://gitee.com/zuohuaijun/Admin.NET into v2-2025616

hwjmyz 10 месяцев назад
Родитель
Сommit
be46dcd62c
45 измененных файлов с 1882 добавлено и 510 удалено
  1. 10 10
      Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj
  2. 6 0
      Admin.NET/Admin.NET.Core/Entity/SysCodeGenConfig.cs
  3. 13 20
      Admin.NET/Admin.NET.Core/Entity/SysFile.cs
  4. 1 1
      Admin.NET/Admin.NET.Core/Entity/SysUser.cs
  5. 6 0
      Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
  6. 23 0
      Admin.NET/Admin.NET.Core/Service/CodeGen/CustomViewEngine.cs
  7. 4 0
      Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/CodeGenConfig.cs
  8. 5 0
      Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/ColumnOuput.cs
  9. 1 0
      Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs
  10. 6 4
      Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs
  11. 27 0
      Admin.NET/Admin.NET.Core/Service/DataBase/Dto/DbColumnInput.cs
  12. 104 1
      Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs
  13. 4 4
      Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs
  14. 0 23
      Admin.NET/Admin.NET.Core/Service/File/Dto/FileInput.cs
  15. 41 38
      Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs
  16. 46 0
      Admin.NET/Admin.NET.Core/Service/Server/SysServerService.cs
  17. 1 1
      Admin.NET/Admin.NET.Core/Service/Wechat/SysWxOpenService.cs
  18. 1 1
      Admin.NET/Admin.NET.Core/Utils/CommonUtil.cs
  19. 1 1
      Admin.NET/Admin.NET.Test/Admin.NET.Test.csproj
  20. 1 1
      Admin.NET/Admin.NET.Web.Core/Admin.NET.Web.Core.csproj
  21. 14 5
      Admin.NET/Admin.NET.Web.Core/Startup.cs
  22. 5 5
      Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Entity.cs.vm
  23. 7 3
      Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm
  24. 7 7
      Web/package.json
  25. 16 139
      Web/src/api-services/apis/sys-file-api.ts
  26. 89 53
      Web/src/api-services/apis/sys-sms-api.ts
  27. 69 65
      Web/src/api-services/models/db-column-input.ts
  28. 0 30
      Web/src/api-services/models/delete-file-input.ts
  29. 0 1
      Web/src/api-services/models/index.ts
  30. 8 0
      Web/src/api-services/models/login-user-output.ts
  31. 0 16
      Web/src/api-services/models/sys-file-upload-file-body.ts
  32. 11 19
      Web/src/api-services/models/sys-file.ts
  33. 39 35
      Web/src/api-services/models/update-db-column-input.ts
  34. 0 8
      Web/src/api-services/models/upload-file-from-base64-input.ts
  35. 25 0
      Web/src/api/system/admin.ts
  36. 1 3
      Web/src/views/system/codeGen/index.vue
  37. 8 0
      Web/src/views/system/database/component/addColumn.vue
  38. 6 1
      Web/src/views/system/database/component/addTable.vue
  39. 5 0
      Web/src/views/system/database/component/editColumn.vue
  40. 53 5
      Web/src/views/system/database/index.vue
  41. 21 8
      Web/src/views/system/dict/index.vue
  42. 1194 0
      Web/src/views/system/server/new.vue
  43. 1 1
      Web/src/views/system/weChatPay/index.vue
  44. 1 1
      Web/src/views/system/weChatUser/index.vue
  45. 1 0
      Web/vite.config.ts

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

@@ -19,9 +19,9 @@
     <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.4.0" />
     <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
     <PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.6" />
-    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.82" />
-    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.82" />
-    <PackageReference Include="Furion.Pure" Version="4.9.7.82" />
+    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.85" />
+    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.85" />
+    <PackageReference Include="Furion.Pure" Version="4.9.7.85" />
 	<PackageReference Include="Hardware.Info" Version="101.0.1.1" />
     <PackageReference Include="Hashids.net" Version="1.7.0" />
     <PackageReference Include="IPTools.China" Version="1.6.0" />
@@ -41,12 +41,12 @@
     <PackageReference Include="SixLabors.ImageSharp.Web" Version="3.1.5" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="3.10.0" />
     <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.12.0" />
-    <PackageReference Include="SqlSugarCore" Version="5.1.4.195" />
+    <PackageReference Include="SqlSugarCore" Version="5.1.4.196" />
     <PackageReference Include="SSH.NET" Version="2025.0.0" />
-    <PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.5" />
+    <PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.6" />
     <PackageReference Include="System.Net.Http" Version="4.3.4" />
     <PackageReference Include="System.Private.Uri" Version="4.3.2" />
-    <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1254" />
+    <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1259" />
     <PackageReference Include="UAParser" Version="3.1.47" />
     <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
     <PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" />
@@ -66,11 +66,11 @@
     <PackageReference Include="AspNet.Security.OAuth.Gitee" Version="9.4.0" />
     <PackageReference Include="AspNet.Security.OAuth.Weixin" Version="9.4.0" />
     <PackageReference Include="Lazy.Captcha.Core" Version="2.1.0" />
-    <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.5" />
-    <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.5" />
-    <PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.5" />
-    <PackageReference Include="XiHan.Framework.Utils" Version="0.9.10" />
+    <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.6" />
+    <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.6" />
+    <PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.6" />
 	<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.5.1" />
+	<PackageReference Include="XiHan.Framework.Utils" Version="0.9.13-preview.6" />
   </ItemGroup>
 
 </Project>

+ 6 - 0
Admin.NET/Admin.NET.Core/Entity/SysCodeGenConfig.cs

@@ -68,6 +68,12 @@ public partial class SysCodeGenConfig : EntityBase
     public string? NetType { get; set; }
 
     /// <summary>
+    /// 字段数据默认值
+    /// </summary>
+    [SugarColumn(ColumnDescription = "默认值")]
+    public string? DefaultValue { get; set; }
+
+    /// <summary>
     /// 作用类型(字典)
     /// </summary>
     [SugarColumn(ColumnDescription = "作用类型", Length = 64)]

+ 13 - 20
Admin.NET/Admin.NET.Core/Entity/SysFile.cs

@@ -77,35 +77,28 @@ public partial class SysFile : EntityBaseTenantOrg
     public string? FileMd5 { get; set; }
 
     /// <summary>
-    /// 关联对象名称(如子对象)
+    /// 文件类别
     /// </summary>
-    [SugarColumn(ColumnDescription = "关联对象名称", Length = 128)]
+    [SugarColumn(ColumnDescription = "文件类别", Length = 128)]
     [MaxLength(128)]
-    public string? RelationName { get; set; }
+    public virtual string? FileType { get; set; }
 
     /// <summary>
-    /// 关联对象Id
+    /// 文件别名
     /// </summary>
-    [SugarColumn(ColumnDescription = "关联对象Id")]
-    public long? RelationId { get; set; }
-
-    /// <summary>
-    /// 所属Id(如主对象)
-    /// </summary>
-    [SugarColumn(ColumnDescription = "所属Id")]
-    public long? BelongId { get; set; }
-
-    /// <summary>
-    /// 文件类别
-    /// </summary>
-    [SugarColumn(ColumnDescription = "文件类别", Length = 128)]
+    [SugarColumn(ColumnDescription = "文件别名", Length = 128)]
     [MaxLength(128)]
-    public string? FileType { get; set; }
+    public string? FileAlias { get; set; }
 
     /// <summary>
     /// 是否公开
-    /// 若为true则所有人都可以查看,默认只有自己或有权限的可以查看
     /// </summary>
     [SugarColumn(ColumnDescription = "是否公开")]
-    public bool IsPublic { get; set; } = false;
+    public virtual bool IsPublic { get; set; } = false;
+
+    /// <summary>
+    /// 业务数据Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "业务数据Id")]
+    public long? DataId { get; set; }
 }

+ 1 - 1
Admin.NET/Admin.NET.Core/Entity/SysUser.cs

@@ -126,7 +126,7 @@ public partial class SysUser : EntityBaseTenantOrg
 
     /// <summary>
     /// 毕业院校
-    /// </summary>COLLEGE
+    /// </summary>
     [SugarColumn(ColumnDescription = "毕业院校", Length = 128)]
     [MaxLength(128)]
     public string? College { get; set; }

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

@@ -590,6 +590,12 @@ public enum ErrorCodeEnum
     D8004,
 
     /// <summary>
+    /// 无效的文件名
+    /// </summary>
+    [ErrorCodeItemMetadata("无效的文件名")]
+    D8005,
+
+    /// <summary>
     /// 已存在同名或同编码参数配置
     /// </summary>
     [ErrorCodeItemMetadata("已存在同名或同编码参数配置")]

+ 23 - 0
Admin.NET/Admin.NET.Core/Service/CodeGen/CustomViewEngine.cs

@@ -100,6 +100,11 @@ public class CustomViewEngine : ViewEngineModel
     public string InjectServiceArgs => InjectServiceMap.Count > 0 ? ", " + string.Join(", ", InjectServiceMap.Select(kv => $"{kv.Key} {kv.Value}")) : "";
 
     /// <summary>
+    /// 默认值列表
+    /// </summary>
+    public List<CodeGenConfig> DefaultValueList { get; set; }
+    
+    /// <summary>
     /// 判断字段是否为状态字段
     /// </summary>
     /// <param name="column"></param>
@@ -144,6 +149,24 @@ public class CustomViewEngine : ViewEngineModel
         var orderNo = TableField.FirstOrDefault(c => c.NetType.TrimEnd('?') == "int" && c.PropertyName == nameof(SysUser.OrderNo));
         if (status != null) content += $"{status.LowerPropertyName}: {(int)StatusEnum.Enable},";
         if (orderNo != null) content += $"{orderNo.LowerPropertyName}: 100,";
+                foreach (var item in DefaultValueList)
+        {
+            if (!string.IsNullOrWhiteSpace(item.DefaultValue))
+            {
+                switch (item.EffectType)
+                {
+                    case "InputNumber":
+                        content += $"{item.LowerPropertyName}: {item.DefaultValue},";
+                        break;
+                    case "Switch":
+                        content += $"{item.LowerPropertyName}: {(item.DefaultValue=="1"?true.ToString().ToLower():false.ToString().ToLower())},";
+                        break;
+                    default:
+                        content += $"{item.LowerPropertyName}: '{item.DefaultValue}',";
+                        break;
+                }
+            }
+        }
         return content;
     }
 }

+ 4 - 0
Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/CodeGenConfig.cs

@@ -62,6 +62,10 @@ public class CodeGenConfig
     public string DataType { get; set; }
 
     /// <summary>
+    /// 字段数据默认值
+    /// </summary>
+    public string DefaultValue { get; set; }
+    /// <summary>
     /// 可空.NET类型
     /// </summary>
     public string NullableNetType => Regex.IsMatch(NetType ?? "", "(.*?Enum|bool|char|int|long|double|float|decimal)[?]?") ? NetType.TrimEnd('?') + "?" : NetType;

+ 5 - 0
Admin.NET/Admin.NET.Core/Service/CodeGen/Dto/ColumnOuput.cs

@@ -32,6 +32,11 @@ public class ColumnOuput
     public string DataType { get; set; }
 
     /// <summary>
+    /// 字段数据默认值
+    /// </summary>
+    public string DefaultValue { get; set; }
+
+    /// <summary>
     /// 是否为主键
     /// </summary>
     public bool IsPrimarykey { get; set; }

+ 1 - 0
Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenConfigService.cs

@@ -115,6 +115,7 @@ public class SysCodeGenConfigService : IDynamicApiController, ITransient
             codeGenConfig.ColumnLength = tableColumn.ColumnLength;// 长度
             codeGenConfig.ColumnComment = tableColumn.ColumnComment;
             codeGenConfig.NetType = tableColumn.NetType;
+            codeGenConfig.DefaultValue = tableColumn.DefaultValue;
             codeGenConfig.WhetherRetract = YesNoEnum.N.ToString();
 
             // 生成代码时,主键并不是必要输入项,故一定要排除主键字段

+ 6 - 4
Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs

@@ -94,11 +94,11 @@ public class SysCodeGenService : IDynamicApiController, ITransient
         await _db.Updateable(codeGen).ExecuteCommandAsync();
 
         // 仅当数据表名称发生了变化,才更新配置表
-        if (oldRecord.TableName != input.TableName)
-        {
+        //if (oldRecord.TableName != input.TableName)
+        //{
             await _codeGenConfigService.DeleteCodeGenConfig(codeGen.Id);
             _codeGenConfigService.AddList(GetColumnList(input.Adapt<AddCodeGenInput>()), codeGen);
-        }
+        //}
     }
 
     /// <summary>
@@ -246,7 +246,8 @@ public class SysCodeGenService : IDynamicApiController, ITransient
             ColumnKey = u.IsPrimarykey.ToString(),
             NetType = CodeGenUtil.ConvertDataType(u, provider.CurrentConnectionConfig.DbType),
             DataType = CodeGenUtil.ConvertDataType(u, provider.CurrentConnectionConfig.DbType),
-            ColumnComment = string.IsNullOrWhiteSpace(u.ColumnDescription) ? u.DbColumnName : u.ColumnDescription
+            ColumnComment = string.IsNullOrWhiteSpace(u.ColumnDescription) ? u.DbColumnName : u.ColumnDescription,
+            DefaultValue = u.DefaultValue,
         }).ToList();
 
         // 获取实体的属性信息,赋值给PropertyName属性(CodeFirst模式应以PropertyName为实际使用名称)
@@ -433,6 +434,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient
             AddUpdateFieldList = tableFieldList.Where(u => u.WhetherAddUpdate == "Y").ToList(),
             ApiTreeFieldList = tableFieldList.Where(u => u.EffectType == "ApiTreeSelector").ToList(),
             DropdownFieldList = tableFieldList.Where(u => u.EffectType is "ForeignKey" or "ApiTreeSelector").ToList(),
+            DefaultValueList = tableFieldList.Where(u => u.DefaultValue!=null && u.DefaultValue.Length>0).ToList(),
 
             HasJoinTable = joinTableList.Count > 0,
             HasDictField = tableFieldList.Any(u => u.EffectType == "DictSelector"),

+ 27 - 0
Admin.NET/Admin.NET.Core/Service/DataBase/Dto/DbColumnInput.cs

@@ -27,6 +27,8 @@ public class DbColumnInput
     public int IsPrimarykey { get; set; }
 
     public int DecimalDigits { get; set; }
+
+    public string DefaultValue { get; set; }
 }
 
 public class UpdateDbColumnInput
@@ -40,6 +42,31 @@ public class UpdateDbColumnInput
     public string OldColumnName { get; set; }
 
     public string Description { get; set; }
+
+    public string DefaultValue { get; set; }
+}
+
+public class MoveDbColumnInput
+{
+    /// <summary>
+    /// 数据库配置ID
+    /// </summary>
+    public string ConfigId { get; set; }
+
+    /// <summary>
+    /// 目标表名
+    /// </summary>
+    public string TableName { get; set; }
+
+    /// <summary>
+    ///要移动的列名
+    /// </summary>
+    public string ColumnName { get; set; }
+
+    /// <summary>
+    /// 移动到该列后方(为空时移动到首列)
+    /// </summary>
+    public string AfterColumnName { get; set; }
 }
 
 public class DeleteDbColumnInput

+ 104 - 1
Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs

@@ -144,7 +144,12 @@ public class SysDatabaseService : IDynamicApiController, ITransient
             DataType = input.DataType
         };
         var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
-        db.DbMaintenance.AddColumn(input.TableName, column);
+        db.DbMaintenance.AddColumn(input.TableName, column);        
+        // 默认值直接添加报错
+        if (!string.IsNullOrWhiteSpace(input.DefaultValue))
+        {
+            db.DbMaintenance.AddDefaultValue(input.TableName, column.DbColumnName, input.DefaultValue);
+        }
         db.DbMaintenance.AddColumnRemark(input.DbColumnName, input.TableName, input.ColumnDescription);
         if (column.IsPrimarykey) db.DbMaintenance.AddPrimaryKey(input.TableName, input.DbColumnName);
     }
@@ -171,12 +176,104 @@ public class SysDatabaseService : IDynamicApiController, ITransient
     {
         var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
         db.DbMaintenance.RenameColumn(input.TableName, input.OldColumnName, input.ColumnName);
+        if (!string.IsNullOrWhiteSpace(input.DefaultValue))
+        {
+            db.DbMaintenance.AddDefaultValue(input.TableName, input.ColumnName, input.DefaultValue);
+        }
         if (db.DbMaintenance.IsAnyColumnRemark(input.ColumnName, input.TableName))
+        { 
             db.DbMaintenance.DeleteColumnRemark(input.ColumnName, input.TableName);
+        }
+
         db.DbMaintenance.AddColumnRemark(input.ColumnName, input.TableName, string.IsNullOrWhiteSpace(input.Description) ? input.ColumnName : input.Description);
     }
 
     /// <summary>
+    /// 移动列位置 🔖
+    /// </summary>
+    /// <param name="input"></param>
+    [ApiDescriptionSettings(Name = "MoveColumn"), HttpPost]
+    [DisplayName("移动列")]
+    public void MoveColumn(MoveDbColumnInput input)
+    {
+        var db = _db.AsTenant().GetConnectionScope(input.ConfigId);
+        var dbMaintenance = db.DbMaintenance;
+
+        var dbType = db.CurrentConnectionConfig.DbType;
+
+        var columns = dbMaintenance.GetColumnInfosByTableName(input.TableName, false);
+        var targetColumn = columns.FirstOrDefault(c =>
+            c.DbColumnName.Equals(input.ColumnName, StringComparison.OrdinalIgnoreCase));
+
+        if (targetColumn == null)
+            throw new Exception($"列 {input.ColumnName} 在表 {input.TableName} 中不存在");
+
+        switch (dbType)
+        {
+            case SqlSugar.DbType.MySql:
+                MoveColumnInMySQL(db, input.TableName, input.ColumnName, input.AfterColumnName);
+                break;
+            default:
+                throw new NotSupportedException($"暂不支持 {dbType} 数据库的列移动操作");
+        }
+    }
+
+    /// <summary>
+    /// 获取列定义
+    /// </summary>
+    /// <param name="db"></param>
+    /// <param name="tableName"></param>
+    /// <param name="columnName"></param>
+    /// <param name="noDefault"></param>
+    /// <returns></returns>
+    /// <exception cref="Exception"></exception>
+    private string GetColumnDefinitionInMySQL(ISqlSugarClient db, string tableName, string columnName,bool noDefault = false)
+    {
+        var columnDef = db.Ado.SqlQuery<dynamic>(
+            $"SHOW FULL COLUMNS FROM `{tableName}` WHERE Field = '{columnName}'"
+        ).FirstOrDefault();
+
+        if (columnDef == null)
+            throw new Exception($"Column {columnName} not found");
+
+        var definition = new StringBuilder();
+        definition.Append($"`{columnName}` ");  // 列名
+        definition.Append($"{columnDef.Type} "); // 数据类型
+
+        // 处理约束条件
+        definition.Append(columnDef.Null == "YES" ? "NULL " : "NOT NULL ");
+        if (columnDef.Default != null && !noDefault)
+            definition.Append($"DEFAULT '{columnDef.Default}' ");
+        if (!string.IsNullOrEmpty(columnDef.Extra))
+            definition.Append($"{columnDef.Extra} ");
+        if (!string.IsNullOrEmpty(columnDef.Comment))
+            definition.Append($"COMMENT '{columnDef.Comment.Replace("'", "''")}'");
+
+        return definition.ToString();
+
+    }
+    /// <summary>
+    /// MySQL 列移动实现
+    /// </summary>
+    /// <param name="db"></param>
+    /// <param name="tableName"></param>
+    /// <param name="columnName"></param>
+    /// <param name="afterColumnName"></param>
+    private void MoveColumnInMySQL(ISqlSugarClient db, string tableName, string columnName, string afterColumnName)
+    {
+        var definition = GetColumnDefinitionInMySQL(db, tableName, columnName);
+        var sql = new StringBuilder();
+        sql.Append($"ALTER TABLE `{tableName}` MODIFY COLUMN {definition}");
+
+        if (string.IsNullOrEmpty(afterColumnName))
+            sql.Append(" FIRST");
+        else
+            sql.Append($" AFTER `{afterColumnName}`");
+
+        db.Ado.ExecuteCommand(sql.ToString());
+    }
+
+    /// <summary>
     /// 获取表列表 🔖
     /// </summary>
     /// <param name="configId">ConfigId</param>
@@ -218,6 +315,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
                 IsNullable = u.IsNullable == 1,
                 DecimalDigits = u.DecimalDigits,
                 ColumnDescription = u.ColumnDescription,
+                DefaultValue = u.DefaultValue,
             });
         });
         db.CodeFirst.InitTables(typeBuilder.BuilderType());
@@ -289,6 +387,11 @@ public class SysDatabaseService : IDynamicApiController, ITransient
         List<DbColumnInfo> dbColumnInfos = db.DbMaintenance.GetColumnInfosByTableName(input.TableName, false);
         dbColumnInfos.ForEach(u =>
         {
+            if (u.DbColumnName.ToUpper() == u.DbColumnName)
+            {
+                //字段全是大写的, 这种情况下生成的代码会有问题(即对 DOB 这样的字段,生成的前端代码为 dOB, 而数据序列化到前端又成了 dob,导致bug),因此抛出异常,不允许。
+                throw new Exception($"错误:{u.DbColumnName} 字段全是大写字母,这样生成的代码会有bug!请更改为大写字母开头的驼峰式命名!");
+            }
             u.PropertyName = config.DbSettings.EnableUnderLine ? CodeGenUtil.CamelColumnName(u.DbColumnName, dbColumnNames) : u.DbColumnName; // 转下划线后的列名需要再转回来
             u.DataType = CodeGenUtil.ConvertDataType(u, config.DbType);
         });

+ 4 - 4
Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs

@@ -35,12 +35,12 @@ public class SysDictTypeService : IDynamicApiController, ITransient
     [DisplayName("获取字典类型分页列表")]
     public async Task<SqlSugarPagedList<SysDictType>> Page(PageDictTypeInput input)
     {
-        return await _sysDictTypeRep.AsQueryable()
+        var query = _sysDictTypeRep.AsQueryable()
             .WhereIF(!_userManager.SuperAdmin, u => u.IsTenant == YesNoEnum.Y)
             .WhereIF(!string.IsNullOrEmpty(input.Code?.Trim()), u => u.Code.Contains(input.Code))
-            .WhereIF(!string.IsNullOrEmpty(input.Name?.Trim()), u => u.Name.Contains(input.Name))
-            .OrderBy(u => new { u.OrderNo, u.Code })
-            .ToPagedListAsync(input.Page, input.PageSize);
+            .WhereIF(!string.IsNullOrEmpty(input.Name?.Trim()), u => u.Name.Contains(input.Name));
+            //.OrderBy(u => new { u.OrderNo, u.Code })
+        return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
     }
 
     /// <summary>

+ 0 - 23
Admin.NET/Admin.NET.Core/Service/File/Dto/FileInput.cs

@@ -37,14 +37,6 @@ public class PageFileInput : BasePageInput
     public DateTime? EndTime { get; set; }
 }
 
-public class FileInput : BaseIdInput
-{
-}
-
-public class DeleteFileInput : BaseIdInput
-{
-}
-
 /// <summary>
 /// 上传文件
 /// </summary>
@@ -67,16 +59,6 @@ public class UploadFileInput
     public bool IsPublic { get; set; } = false;
 
     /// <summary>
-    /// 文件路径
-    /// </summary>
-    public string Path { get; set; }
-
-    /// <summary>
-    /// 文件保存路径
-    /// </summary>
-    public string SavePath { get; set; }
-
-    /// <summary>
     /// 允许格式:.jpeg.jpg.png.bmp.gif.tif
     /// </summary>
     public string AllowSuffix { get; set; }
@@ -101,11 +83,6 @@ public class UploadFileFromBase64Input
     /// 文件类型( "image/jpeg",)
     /// </summary>
     public string ContentType { get; set; }
-
-    /// <summary>
-    /// 保存路径
-    /// </summary>
-    public string Path { get; set; }
 }
 
 /// <summary>

+ 41 - 38
Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs

@@ -5,6 +5,8 @@
 // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
 
 using Aliyun.OSS.Util;
+using Furion.AspNetCore;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
 
 namespace Admin.NET.Core.Service;
 
@@ -167,7 +169,7 @@ public class SysFileService : IDynamicApiController, ITransient
     /// <returns></returns>
     [ApiDescriptionSettings(Name = "Delete"), HttpPost]
     [DisplayName("删除文件")]
-    public async Task DeleteFile(DeleteFileInput input)
+    public async Task DeleteFile(BaseIdInput input)
     {
         var file = await _sysFileRep.GetByIdAsync(input.Id) ?? throw Oops.Oh($"文件不存在");
         await _sysFileRep.DeleteAsync(file);
@@ -207,7 +209,7 @@ public class SysFileService : IDynamicApiController, ITransient
     /// <param name="ids"></param>
     /// <returns></returns>
     [DisplayName("根据文件Id集合获取文件")]
-    public async Task<List<SysFile>> GetFileByIds([FromQuery] List<long> ids)
+    public async Task<List<SysFile>> GetFileByIds([FromQuery][FlexibleArray<long>] List<long> ids)
     {
         return await _sysFileRep.AsQueryable().Where(u => ids.Contains(u.Id)).ToListAsync();
     }
@@ -231,11 +233,14 @@ public class SysFileService : IDynamicApiController, ITransient
     /// 上传文件 🔖
     /// </summary>
     /// <param name="input"></param>
+    /// <param name="targetPath">存储目标路径</param>
     /// <returns></returns>
     [DisplayName("上传文件")]
-    public async Task<SysFile> UploadFile([FromForm] UploadFileInput input)
+    public async Task<SysFile> UploadFile([FromForm] UploadFileInput input, [BindNever] string targetPath = "")
     {
-        if (input.File == null) throw Oops.Oh(ErrorCodeEnum.D8000);
+        if (input.File == null || input.File.Length <= 0) throw Oops.Oh(ErrorCodeEnum.D8000);
+
+        if (input.File.FileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) throw Oops.Oh(ErrorCodeEnum.D8005);
 
         // 判断是否重复上传的文件
         var sizeKb = input.File.Length / 1024; // 大小KB
@@ -277,7 +282,7 @@ public class SysFileService : IDynamicApiController, ITransient
         //if (!VerifyFileExtensionName.IsSameType(file.OpenReadStream(), suffix)) throw Oops.Oh(ErrorCodeEnum.D8001);
 
         // 文件存储位置
-        var path = string.IsNullOrWhiteSpace(input.SavePath) ? _uploadOptions.Path : input.SavePath;
+        var path = string.IsNullOrWhiteSpace(targetPath) ? _uploadOptions.Path : targetPath;
         path = path.ParseToDateTimeForRep();
 
         var newFile = input.Adapt<SysFile>();
@@ -304,7 +309,7 @@ public class SysFileService : IDynamicApiController, ITransient
     [DisplayName("上传头像")]
     public async Task<SysFile> UploadAvatar([Required] IFormFile file)
     {
-        var sysFile = await UploadFile(new UploadFileInput { File = file, AllowSuffix = _imageType, SavePath = "upload/avatar" });
+        var sysFile = await UploadFile(new UploadFileInput { File = file, AllowSuffix = _imageType }, "upload/avatar");
 
         var sysUserRep = _sysFileRep.ChangeRepository<SqlSugarRepository<SysUser>>();
         var user = await sysUserRep.GetByIdAsync(_userManager.UserId);
@@ -313,7 +318,7 @@ public class SysFileService : IDynamicApiController, ITransient
         if (!string.IsNullOrWhiteSpace(user.Avatar))
         {
             var fileId = Path.GetFileNameWithoutExtension(user.Avatar);
-            await DeleteFile(new DeleteFileInput { Id = long.Parse(fileId) });
+            await DeleteFile(new BaseIdInput { Id = long.Parse(fileId) });
         }
 
         return sysFile;
@@ -327,7 +332,7 @@ public class SysFileService : IDynamicApiController, ITransient
     [DisplayName("上传电子签名")]
     public async Task<SysFile> UploadSignature([Required] IFormFile file)
     {
-        var sysFile = await UploadFile(new UploadFileInput { File = file, AllowSuffix = _imageType, SavePath = "upload/signature" });
+        var sysFile = await UploadFile(new UploadFileInput { File = file, AllowSuffix = _imageType }, "upload/signature");
 
         var sysUserRep = _sysFileRep.ChangeRepository<SqlSugarRepository<SysUser>>();
         var user = await sysUserRep.GetByIdAsync(_userManager.UserId);
@@ -335,51 +340,49 @@ public class SysFileService : IDynamicApiController, ITransient
         if (!string.IsNullOrWhiteSpace(user.Signature) && user.Signature.EndsWith(".png"))
         {
             var fileId = Path.GetFileNameWithoutExtension(user.Signature);
-            await DeleteFile(new DeleteFileInput { Id = long.Parse(fileId) });
+            await DeleteFile(new BaseIdInput { Id = long.Parse(fileId) });
         }
         await sysUserRep.UpdateAsync(u => new SysUser() { Signature = sysFile.Url }, u => u.Id == user.Id);
         return sysFile;
     }
 
+    #region 统一实体与文件关联时,业务应用实体只需要定义一个SysFile集合导航属性,业务增加和更新、删除分别调用即可
+
     /// <summary>
-    /// 修改附件关联对象 🔖
+    /// 更新文件的业务数据Id
     /// </summary>
-    /// <param name="ids"></param>
-    /// <param name="relationName"></param>
-    /// <param name="relationId"></param>
-    /// <param name="belongId"></param>
+    /// <param name="dataId"></param>
+    /// <param name="sysFiles"></param>
     /// <returns></returns>
     [NonAction]
-    public async Task<int> UpdateRelation(List<long> ids, string relationName, long relationId, long belongId = 0)
+    public async Task UpdateFileByDataId(long dataId, List<SysFile> sysFiles)
     {
-        if (ids == null || ids.Count == 0)
-            return 0;
-        return await _sysFileRep.AsUpdateable()
-            .SetColumns(u => u.RelationName == relationName)
-            .SetColumns(u => u.RelationId == relationId)
-            .SetColumns(u => u.BelongId == belongId)
-            .Where(u => ids.Contains(u.Id))
-            .ExecuteCommandAsync();
+        var newFileIds = sysFiles.Select(u => u.Id).ToList();
+
+        // 求文件Id差集并删除(无效文件)
+        var tmpFiles = await _sysFileRep.GetListAsync(u => u.DataId == dataId);
+        var tmpFileIds = tmpFiles.Select(u => u.Id).ToList();
+        var deleteFileIds = tmpFileIds.Except(newFileIds);
+        foreach (var fileId in deleteFileIds)
+            await DeleteFile(new BaseIdInput() { Id = fileId });
+
+        await _sysFileRep.UpdateAsync(u => new SysFile() { DataId = dataId }, u => newFileIds.Contains(u.Id));
     }
 
     /// <summary>
-    /// 根据关联查询附件 🔖
+    /// 删除业务数据对应的文件
     /// </summary>
-    /// <param name="input"></param>
+    /// <param name="dataId"></param>
     /// <returns></returns>
-    /// <exception cref="ArgumentNullException"></exception>
-    [DisplayName("根据关联查询附件")]
-    public async Task<List<SysFile>> GetRelationFiles([FromQuery] RelationQueryInput input)
+    [NonAction]
+    public async Task DeteleFileByDataId(long dataId)
     {
-        return await _sysFileRep.AsQueryable()
-            .WhereIF(input.RelationId is > 0, u => u.RelationId == input.RelationId)
-            .WhereIF(input.BelongId is > 0, u => u.BelongId == input.BelongId.Value)
-            .WhereIF(!string.IsNullOrWhiteSpace(input.RelationName), u => u.RelationName == input.RelationName)
-            .WhereIF(!string.IsNullOrWhiteSpace(input.FileTypes), u => input.GetFileTypeBS().Contains(u.FileType))
-            .Select(u => new SysFile
-            {
-                Url = SqlFunc.MergeString("/api/sysFile/Preview/", u.Id.ToString()),
-            }, true)
-           .ToListAsync();
+        // 删除冗余无效的物理文件
+        var tmpFiles = await _sysFileRep.GetListAsync(u => u.DataId == dataId);
+        foreach (var file in tmpFiles)
+            await _customFileProvider.DeleteFileAsync(file);
+        await _sysFileRep.AsDeleteable().Where(u => u.DataId == dataId).ExecuteCommandAsync();
     }
+
+    #endregion 统一实体与文件关联时,业务应用实体只需要定义一个SysFile集合导航属性,业务增加和更新、删除分别调用即可
 }

+ 46 - 0
Admin.NET/Admin.NET.Core/Service/Server/SysServerService.cs

@@ -4,6 +4,15 @@
 //
 // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
 
+#if NET9_0_OR_GREATER
+
+using XiHan.Framework.Utils.HardwareInfos;
+using XiHan.Framework.Utils.Reflections;
+using XiHan.Framework.Utils.Runtime;
+using ReflectionHelper = XiHan.Framework.Utils.Reflections.ReflectionHelper;
+
+#endif // NET9_0_OR_GREATER
+
 namespace Admin.NET.Core.Service;
 
 /// <summary>
@@ -16,6 +25,43 @@ public class SysServerService : IDynamicApiController, ITransient
     {
     }
 
+#if NET9_0_OR_GREATER
+
+    /// <summary>
+    /// 获取服务器硬件信息
+    /// </summary>
+    /// <returns></returns>
+    [DisplayName("获取服务器硬件信息")]
+    public SystemHardwareInfo HardwareInfo()
+    {
+        var hardwareInfo = HardwareInfoManager.GetSystemHardwareInfo();
+        return hardwareInfo;
+    }
+
+    /// <summary>
+    /// 获取服务器运行时信息
+    /// </summary>
+    /// <returns></returns>
+    [DisplayName("获取服务器运行时信息")]
+    public SystemRuntimeInfo RuntimeInfo()
+    {
+        var systemRuntimeInfo = RuntimeInfoManger.GetSystemRuntimeInfo();
+        return systemRuntimeInfo;
+    }
+
+    /// <summary>
+    /// 获取框架主要程序集
+    /// </summary>
+    /// <returns></returns>
+    [DisplayName("获取框架主要程序集")]
+    public List<NuGetPackage> NuGetPackagesInfo()
+    {
+        var nuGetPackages = ReflectionHelper.GetNuGetPackages("Admin.NET");
+        return nuGetPackages;
+    }
+
+#endif // NET9_0_OR_GREATER
+
     /// <summary>
     /// 获取服务器配置信息 🔖
     /// </summary>

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

@@ -149,7 +149,7 @@ public class SysWxOpenService : IDynamicApiController, ITransient
         if (wxUser == null)
             throw Oops.Oh("未找到用户上传失败");
 
-        var res = await _sysFileService.UploadFile(new UploadFileInput { File = input.File, FileType = input.FileType, Path = input.Path });
+        var res = await _sysFileService.UploadFile(new UploadFileInput { File = input.File, FileType = input.FileType }, "upload/wechatAvatar");
         wxUser.Avatar = res.Url;
         await _sysWechatUserRep.AsUpdateable(wxUser).IgnoreColumns(true).ExecuteCommandAsync();
 

+ 1 - 1
Admin.NET/Admin.NET.Core/Utils/CommonUtil.cs

@@ -284,7 +284,7 @@ public static class CommonUtil
         var res = await importer.Import<T>(filePath);
 
         // 删除文件
-        _ = SysFileService.DeleteFile(new DeleteFileInput { Id = newFile.Id });
+        _ = SysFileService.DeleteFile(new BaseIdInput { Id = newFile.Id });
 
         if (res == null)
             throw Oops.Oh("导入数据为空");

+ 1 - 1
Admin.NET/Admin.NET.Test/Admin.NET.Test.csproj

@@ -12,7 +12,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-      <PackageReference Include="Furion.Xunit" Version="4.9.7.82" />
+      <PackageReference Include="Furion.Xunit" Version="4.9.7.85" />
       <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
       <PackageReference Include="Selenium.Support" Version="4.33.0" />
       <PackageReference Include="Selenium.WebDriver" Version="4.33.0" />

+ 1 - 1
Admin.NET/Admin.NET.Web.Core/Admin.NET.Web.Core.csproj

@@ -11,7 +11,7 @@
 
   <ItemGroup>
     <PackageReference Include="IGeekFan.AspNetCore.Knife4jUI" Version="0.0.16" />
-    <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.5" />
+    <PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.6" />
   </ItemGroup>
 
   <ItemGroup>

+ 14 - 5
Admin.NET/Admin.NET.Web.Core/Startup.cs

@@ -247,13 +247,13 @@ public class Startup : AppStartup
             options.EnableForHttps = true;
             options.Providers.Add<BrotliCompressionProvider>();
             options.Providers.Add<GzipCompressionProvider>();
-            options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
-            {
+            options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
+            [
                     "text/html; charset=utf-8",
                     "application/xhtml+xml",
                     "application/atom+xml",
                     "image/svg+xml"
-             });
+             ]);
         });
 
         // 注册虚拟文件系统服务
@@ -330,11 +330,20 @@ public class Startup : AppStartup
         // 任务调度看板
         app.UseScheduleUI(options =>
         {
-            options.RequestPath = "/schedule";  // 必须以 / 开头且不以 / 结尾
-            options.DisableOnProduction = true; // 生产环境关闭
+            options.RequestPath = "/schedule"; // 必须以 / 开头且不以 / 结尾
+            options.DisableOnProduction = true; // 是否在生产环境关闭
             options.DisplayEmptyTriggerJobs = true; // 是否显示空作业触发器的作业
             options.DisplayHead = false; // 是否显示页头
             options.DefaultExpandAllJobs = false; // 是否默认展开所有作业
+            options.EnableDirectoryBrowsing = false; // 是否启用目录浏览
+            options.Title = "定时任务看板"; // 自定义看板标题
+
+            options.LoginHandle = async (username, password, httpContext) =>
+            {
+                var res = await httpContext.RequestServices.GetRequiredService<SysAuthService>().SwaggerSubmitUrl(new SpecificationAuth { UserName = username, Password = password });
+                return res == 200;
+            };
+            options.LoginSessionKey = "schedule_session_key"; // 登录客户端存储的 Session 键
         });
 
         // 配置Swagger-Knife4UI(路由前缀一致代表独立,不同则代表共存)

+ 5 - 5
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Entity.cs.vm

@@ -29,17 +29,17 @@ public partial class @(Model.EntityName) @Model.BaseClassName
         propSuffix += $", Length = {column.Length}, DecimalDigits={column.DecimalDigits}";
     }
     
+    if(!string.IsNullOrWhiteSpace(column.DefaultValue)){
+        propSuffix +=$", DefaultValue = \"{column.DefaultValue}\"";
+    }
+
     @:/// <summary>
     @:/// @column.ColumnDescription
     @:/// </summary>
     if(!column.IsNullable){
     @:[Required]
     }
-    var DefaultValue="";
-    if(!string.IsNullOrWhiteSpace(column.DefaultValue)){
-    DefaultValue=$", DefaultValue = \"{column.DefaultValue}\"";
-    }
-    @:[SugarColumn(ColumnName = "@column.DbColumnName", ColumnDescription = "@column.ColumnDescription"@DefaultValue@propSuffix)]
+    @:[SugarColumn(ColumnName = "@column.DbColumnName", ColumnDescription = "@column.ColumnDescription"@propSuffix)]
     @:public virtual @column.DataType @column.PropertyName { get; set; }
     @:
 }

+ 7 - 3
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm

@@ -19,7 +19,7 @@ namespace @(Model.NameSpace);
 /// @(Model.BusName)服务 🧩
 /// </summary>
 [ApiDescriptionSettings(@(Model.ProjectLastName)Const.GroupName, Order = 100)]
-public class @(Model.ClassName)Service : IDynamicApiController, ITransient
+public partial class @(Model.ClassName)Service : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<@(Model.ClassName)> _@(Model.LowerClassName)Rep;
     @foreach(var kv in Model.InjectServiceMap) {
@@ -65,7 +65,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
             } else if (column.NetType.TrimEnd('?') == "int" || column.NetType.TrimEnd('?') == "long") {
             @:.WhereIF(input.@(column.PropertyName) != null, u => u.@(column.PropertyName) @(column.QueryType) input.@(column.PropertyName))
             } else if (column.NetType.TrimEnd('?').EndsWith("Enum")) {
-            @:.WhereIF(input.@(column.PropertyName).HasValue, u => u.@(column.PropertyName) == input.@(column.PropertyName))
+            @:.WhereIF(input.@(column.PropertyName).HasValue, u => u.@(column.PropertyName) == (int)input.@(column.PropertyName))
             } else if (column.NetType.TrimEnd('?') == "DateTime" && column.QueryType == "~") {
             @:.WhereIF(input.@(column.PropertyName)Range?.Length == 2, u => u.@(column.PropertyName) >= input.@(column.PropertyName)Range[0] && u.@(column.PropertyName) <= input.@(column.PropertyName)Range[1])
             }
@@ -80,7 +80,11 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
             @:.Select((@joinTableName) => new @(Model.ClassName)Output
             @:{
             foreach (var column in Model.TableField) {
+                if(column.NetType.TrimEnd('?').EndsWith("Enum")) {
+                @:@(column.PropertyName) = (@(column.NetType))u.@(column.PropertyName),
+                }else{
                 @:@(column.PropertyName) = u.@(column.PropertyName),
+                }
                 if (column.EffectType == "ForeignKey" || column.EffectType == "ApiTreeSelector") {
                 @:@(column.ExtendedPropertyName) = @column.GetDisplayColumn(column.LowerPropertyNameTrimEndId),
                 }
@@ -204,7 +208,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
     @:[ApiDescriptionSettings(Name = "Upload@(column.PropertyName)"), HttpPost]
     @:public async Task<SysFile> Upload@(column.PropertyName)([Required] IFormFile file)
     @:{
-        @:return await _sysFileService.UploadFile(new UploadFileInput { File = file, SavePath = "upload/@(Model.ClassName)/@(column.PropertyName)" }); 
+        @:return await _sysFileService.UploadFile(new UploadFileInput { File = file },"upload/@(Model.ClassName)/@(column.PropertyName)"); 
     @:}
     }
     @if (Model.DropdownFieldList.Count > 0) {

+ 7 - 7
Web/package.json

@@ -2,7 +2,7 @@
 	"name": "admin.net",
 	"type": "module",
 	"version": "2.4.33",
-	"lastBuildTime": "2025.06.08",
+	"lastBuildTime": "2025.06.12",
 	"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
 	"author": "zuohuaijun",
 	"license": "MIT",
@@ -18,8 +18,8 @@
 	},
 	"dependencies": {
 		"@element-plus/icons-vue": "^2.3.1",
-		"@logicflow/core": "^2.0.14",
-		"@logicflow/extension": "^2.0.19",
+		"@logicflow/core": "^2.0.15",
+		"@logicflow/extension": "^2.0.20",
 		"@microsoft/signalr": "^8.0.7",
 		"@vue-office/docx": "^1.6.3",
 		"@vue-office/excel": "^1.7.14",
@@ -80,8 +80,8 @@
 		"@types/node": "^22.15.30",
 		"@types/nprogress": "^0.2.3",
 		"@types/sortablejs": "^1.15.8",
-		"@typescript-eslint/eslint-plugin": "^8.32.1",
-		"@typescript-eslint/parser": "^8.32.1",
+		"@typescript-eslint/eslint-plugin": "^8.34.0",
+		"@typescript-eslint/parser": "^8.34.0",
 		"@vitejs/plugin-vue": "^5.2.4",
 		"@vitejs/plugin-vue-jsx": "^4.2.0",
 		"@vue/compiler-sfc": "^3.5.14",
@@ -92,8 +92,8 @@
 		"less": "^4.3.0",
 		"prettier": "^3.5.3",
 		"rollup-plugin-visualizer": "^6.0.3",
-		"sass": "^1.89.0",
-		"terser": "^5.41.0",
+		"sass": "^1.89.2",
+		"terser": "^5.42.0",
 		"typescript": "^5.8.3",
 		"vite": "^6.3.5",
 		"vite-plugin-cdn-import": "^1.0.1",

+ 16 - 139
Web/src/api-services/apis/sys-file-api.ts

@@ -23,7 +23,7 @@ import { AdminResultListTreeNode } from '../models';
 import { AdminResultSqlSugarPagedListSysFile } from '../models';
 import { AdminResultString } from '../models';
 import { AdminResultSysFile } from '../models';
-import { DeleteFileInput } from '../models';
+import { BaseIdInput } from '../models';
 import { PageFileInput } from '../models';
 import { SysFile } from '../models';
 import { UploadFileFromBase64Input } from '../models';
@@ -36,11 +36,11 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
         /**
          * 
          * @summary 删除文件 🔖
-         * @param {DeleteFileInput} [body] 
+         * @param {BaseIdInput} [body] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        apiSysFileDeletePost: async (body?: DeleteFileInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        apiSysFileDeletePost: async (body?: BaseIdInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             const localVarPath = `/api/sysFile/delete`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@@ -415,69 +415,6 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
         },
         /**
          * 
-         * @summary 根据关联查询附件 🔖
-         * @param {string} [relationName] 关联对象名称
-         * @param {number} [relationId] 关联对象Id
-         * @param {string} [fileTypes] 文件类型:多个以\&quot;,\&quot;分割
-         * @param {number} [belongId] 所属Id
-         * @param {*} [options] Override http request option.
-         * @throws {RequiredError}
-         */
-        apiSysFileRelationFilesGet: async (relationName?: string, relationId?: number, fileTypes?: string, belongId?: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/api/sysFile/relationFiles`;
-            // use dummy base URL string because the URL constructor only accepts absolute URLs.
-            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
-            let baseOptions;
-            if (configuration) {
-                baseOptions = configuration.baseOptions;
-            }
-            const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
-            const localVarHeaderParameter = {} as any;
-            const localVarQueryParameter = {} as any;
-
-            // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
-
-            if (relationName !== undefined) {
-                localVarQueryParameter['RelationName'] = relationName;
-            }
-
-            if (relationId !== undefined) {
-                localVarQueryParameter['RelationId'] = relationId;
-            }
-
-            if (fileTypes !== undefined) {
-                localVarQueryParameter['FileTypes'] = fileTypes;
-            }
-
-            if (belongId !== undefined) {
-                localVarQueryParameter['BelongId'] = belongId;
-            }
-
-            const query = new URLSearchParams(localVarUrlObj.search);
-            for (const key in localVarQueryParameter) {
-                query.set(key, localVarQueryParameter[key]);
-            }
-            for (const key in options.params) {
-                query.set(key, options.params[key]);
-            }
-            localVarUrlObj.search = (new URLSearchParams(query)).toString();
-            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
-            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
-
-            return {
-                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
-                options: localVarRequestOptions,
-            };
-        },
-        /**
-         * 
          * @summary 更新文件 🔖
          * @param {SysFile} [body] 
          * @param {*} [options] Override http request option.
@@ -630,13 +567,11 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
          * @param {Blob} [file] 
          * @param {string} [fileType] 
          * @param {boolean} [isPublic] 
-         * @param {string} [path] 
-         * @param {string} [savePath] 
          * @param {string} [allowSuffix] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, isPublic?: boolean, path?: string, savePath?: string, allowSuffix?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, isPublic?: boolean, allowSuffix?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             const localVarPath = `/api/sysFile/uploadFile`;
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@@ -671,14 +606,6 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
                 localVarFormParams.append('IsPublic', isPublic as any);
             }
 
-            if (path !== undefined) { 
-                localVarFormParams.append('Path', path as any);
-            }
-
-            if (savePath !== undefined) { 
-                localVarFormParams.append('SavePath', savePath as any);
-            }
-
             if (allowSuffix !== undefined) { 
                 localVarFormParams.append('AllowSuffix', allowSuffix as any);
             }
@@ -818,11 +745,11 @@ export const SysFileApiFp = function(configuration?: Configuration) {
         /**
          * 
          * @summary 删除文件 🔖
-         * @param {DeleteFileInput} [body] 
+         * @param {BaseIdInput} [body] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysFileDeletePost(body?: DeleteFileInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+        async apiSysFileDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
             const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileDeletePost(body, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
@@ -928,23 +855,6 @@ export const SysFileApiFp = function(configuration?: Configuration) {
         },
         /**
          * 
-         * @summary 根据关联查询附件 🔖
-         * @param {string} [relationName] 关联对象名称
-         * @param {number} [relationId] 关联对象Id
-         * @param {string} [fileTypes] 文件类型:多个以\&quot;,\&quot;分割
-         * @param {number} [belongId] 所属Id
-         * @param {*} [options] Override http request option.
-         * @throws {RequiredError}
-         */
-        async apiSysFileRelationFilesGet(relationName?: string, relationId?: number, fileTypes?: string, belongId?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultListSysFile>>> {
-            const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileRelationFilesGet(relationName, relationId, fileTypes, belongId, options);
-            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
-                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
-                return axios.request(axiosRequestArgs);
-            };
-        },
-        /**
-         * 
          * @summary 更新文件 🔖
          * @param {SysFile} [body] 
          * @param {*} [options] Override http request option.
@@ -991,14 +901,12 @@ export const SysFileApiFp = function(configuration?: Configuration) {
          * @param {Blob} [file] 
          * @param {string} [fileType] 
          * @param {boolean} [isPublic] 
-         * @param {string} [path] 
-         * @param {string} [savePath] 
          * @param {string} [allowSuffix] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, isPublic?: boolean, path?: string, savePath?: string, allowSuffix?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSysFile>>> {
-            const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadFilePostForm(file, fileType, isPublic, path, savePath, allowSuffix, options);
+        async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, isPublic?: boolean, allowSuffix?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultSysFile>>> {
+            const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadFilePostForm(file, fileType, isPublic, allowSuffix, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -1044,11 +952,11 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
         /**
          * 
          * @summary 删除文件 🔖
-         * @param {DeleteFileInput} [body] 
+         * @param {BaseIdInput} [body] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysFileDeletePost(body?: DeleteFileInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+        async apiSysFileDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
             return SysFileApiFp(configuration).apiSysFileDeletePost(body, options).then((request) => request(axios, basePath));
         },
         /**
@@ -1122,19 +1030,6 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
         },
         /**
          * 
-         * @summary 根据关联查询附件 🔖
-         * @param {string} [relationName] 关联对象名称
-         * @param {number} [relationId] 关联对象Id
-         * @param {string} [fileTypes] 文件类型:多个以\&quot;,\&quot;分割
-         * @param {number} [belongId] 所属Id
-         * @param {*} [options] Override http request option.
-         * @throws {RequiredError}
-         */
-        async apiSysFileRelationFilesGet(relationName?: string, relationId?: number, fileTypes?: string, belongId?: number, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultListSysFile>> {
-            return SysFileApiFp(configuration).apiSysFileRelationFilesGet(relationName, relationId, fileTypes, belongId, options).then((request) => request(axios, basePath));
-        },
-        /**
-         * 
          * @summary 更新文件 🔖
          * @param {SysFile} [body] 
          * @param {*} [options] Override http request option.
@@ -1169,14 +1064,12 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
          * @param {Blob} [file] 
          * @param {string} [fileType] 
          * @param {boolean} [isPublic] 
-         * @param {string} [path] 
-         * @param {string} [savePath] 
          * @param {string} [allowSuffix] 
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, isPublic?: boolean, path?: string, savePath?: string, allowSuffix?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSysFile>> {
-            return SysFileApiFp(configuration).apiSysFileUploadFilePostForm(file, fileType, isPublic, path, savePath, allowSuffix, options).then((request) => request(axios, basePath));
+        async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, isPublic?: boolean, allowSuffix?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultSysFile>> {
+            return SysFileApiFp(configuration).apiSysFileUploadFilePostForm(file, fileType, isPublic, allowSuffix, options).then((request) => request(axios, basePath));
         },
         /**
          * 
@@ -1211,12 +1104,12 @@ export class SysFileApi extends BaseAPI {
     /**
      * 
      * @summary 删除文件 🔖
-     * @param {DeleteFileInput} [body] 
+     * @param {BaseIdInput} [body] 
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysFileApi
      */
-    public async apiSysFileDeletePost(body?: DeleteFileInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+    public async apiSysFileDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
         return SysFileApiFp(this.configuration).apiSysFileDeletePost(body, options).then((request) => request(this.axios, this.basePath));
     }
     /**
@@ -1297,20 +1190,6 @@ export class SysFileApi extends BaseAPI {
     }
     /**
      * 
-     * @summary 根据关联查询附件 🔖
-     * @param {string} [relationName] 关联对象名称
-     * @param {number} [relationId] 关联对象Id
-     * @param {string} [fileTypes] 文件类型:多个以\&quot;,\&quot;分割
-     * @param {number} [belongId] 所属Id
-     * @param {*} [options] Override http request option.
-     * @throws {RequiredError}
-     * @memberof SysFileApi
-     */
-    public async apiSysFileRelationFilesGet(relationName?: string, relationId?: number, fileTypes?: string, belongId?: number, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultListSysFile>> {
-        return SysFileApiFp(this.configuration).apiSysFileRelationFilesGet(relationName, relationId, fileTypes, belongId, options).then((request) => request(this.axios, this.basePath));
-    }
-    /**
-     * 
      * @summary 更新文件 🔖
      * @param {SysFile} [body] 
      * @param {*} [options] Override http request option.
@@ -1348,15 +1227,13 @@ export class SysFileApi extends BaseAPI {
      * @param {Blob} [file] 
      * @param {string} [fileType] 
      * @param {boolean} [isPublic] 
-     * @param {string} [path] 
-     * @param {string} [savePath] 
      * @param {string} [allowSuffix] 
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysFileApi
      */
-    public async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, isPublic?: boolean, path?: string, savePath?: string, allowSuffix?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSysFile>> {
-        return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, isPublic, path, savePath, allowSuffix, options).then((request) => request(this.axios, this.basePath));
+    public async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, isPublic?: boolean, allowSuffix?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultSysFile>> {
+        return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, isPublic, allowSuffix, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 

+ 89 - 53
Web/src/api-services/apis/sys-sms-api.ts

@@ -28,17 +28,23 @@ export const SysSmsApiAxiosParamCreator = function (configuration?: Configuratio
         /**
          * 
          * @summary 阿里云发送短信 📨
-         * @param {string} phoneNumber 
+         * @param {string} phoneNumber 手机号
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        apiSysSmsAliyunSendSmsPhoneNumberPost: async (phoneNumber: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost: async (phoneNumber: string, templateId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             // verify required parameter 'phoneNumber' is not null or undefined
             if (phoneNumber === null || phoneNumber === undefined) {
-                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsAliyunSendSmsPhoneNumberPost.');
+                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost.');
+            }
+            // verify required parameter 'templateId' is not null or undefined
+            if (templateId === null || templateId === undefined) {
+                throw new RequiredError('templateId','Required parameter templateId was null or undefined when calling apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost.');
             }
-            const localVarPath = `/api/sysSms/aliyunSendSms/{phoneNumber}`
-                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)));
+            const localVarPath = `/api/sysSms/aliyunSendSms/{phoneNumber}/{templateId}`
+                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)))
+                .replace(`{${"templateId"}}`, encodeURIComponent(String(templateId)));
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -77,22 +83,28 @@ export const SysSmsApiAxiosParamCreator = function (configuration?: Configuratio
         /**
          * 
          * @summary 发送短信模板
-         * @param {any} body 
-         * @param {string} phoneNumber 
+         * @param {any} body 短信内容
+         * @param {string} phoneNumber 手机号
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        apiSysSmsAliyunSendSmsTemplatePhoneNumberPost: async (body: any, phoneNumber: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost: async (body: any, phoneNumber: string, templateId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             // verify required parameter 'body' is not null or undefined
             if (body === null || body === undefined) {
-                throw new RequiredError('body','Required parameter body was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberPost.');
+                throw new RequiredError('body','Required parameter body was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost.');
             }
             // verify required parameter 'phoneNumber' is not null or undefined
             if (phoneNumber === null || phoneNumber === undefined) {
-                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberPost.');
+                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost.');
             }
-            const localVarPath = `/api/sysSms/aliyunSendSmsTemplate/{phoneNumber}`
-                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)));
+            // verify required parameter 'templateId' is not null or undefined
+            if (templateId === null || templateId === undefined) {
+                throw new RequiredError('templateId','Required parameter templateId was null or undefined when calling apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost.');
+            }
+            const localVarPath = `/api/sysSms/aliyunSendSmsTemplate/{phoneNumber}/{templateId}`
+                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)))
+                .replace(`{${"templateId"}}`, encodeURIComponent(String(templateId)));
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -136,16 +148,22 @@ export const SysSmsApiAxiosParamCreator = function (configuration?: Configuratio
          * 
          * @summary 发送短信 📨
          * @param {string} phoneNumber 
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        apiSysSmsSendSmsPhoneNumberPost: async (phoneNumber: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        apiSysSmsSendSmsPhoneNumberTemplateIdPost: async (phoneNumber: string, templateId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             // verify required parameter 'phoneNumber' is not null or undefined
             if (phoneNumber === null || phoneNumber === undefined) {
-                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsSendSmsPhoneNumberPost.');
+                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsSendSmsPhoneNumberTemplateIdPost.');
+            }
+            // verify required parameter 'templateId' is not null or undefined
+            if (templateId === null || templateId === undefined) {
+                throw new RequiredError('templateId','Required parameter templateId was null or undefined when calling apiSysSmsSendSmsPhoneNumberTemplateIdPost.');
             }
-            const localVarPath = `/api/sysSms/sendSms/{phoneNumber}`
-                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)));
+            const localVarPath = `/api/sysSms/sendSms/{phoneNumber}/{templateId}`
+                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)))
+                .replace(`{${"templateId"}}`, encodeURIComponent(String(templateId)));
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -185,16 +203,22 @@ export const SysSmsApiAxiosParamCreator = function (configuration?: Configuratio
          * 
          * @summary 腾讯云发送短信 📨
          * @param {string} phoneNumber 
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        apiSysSmsTencentSendSmsPhoneNumberPost: async (phoneNumber: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+        apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost: async (phoneNumber: string, templateId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             // verify required parameter 'phoneNumber' is not null or undefined
             if (phoneNumber === null || phoneNumber === undefined) {
-                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsTencentSendSmsPhoneNumberPost.');
+                throw new RequiredError('phoneNumber','Required parameter phoneNumber was null or undefined when calling apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost.');
+            }
+            // verify required parameter 'templateId' is not null or undefined
+            if (templateId === null || templateId === undefined) {
+                throw new RequiredError('templateId','Required parameter templateId was null or undefined when calling apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost.');
             }
-            const localVarPath = `/api/sysSms/tencentSendSms/{phoneNumber}`
-                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)));
+            const localVarPath = `/api/sysSms/tencentSendSms/{phoneNumber}/{templateId}`
+                .replace(`{${"phoneNumber"}}`, encodeURIComponent(String(phoneNumber)))
+                .replace(`{${"templateId"}}`, encodeURIComponent(String(templateId)));
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, 'https://example.com');
             let baseOptions;
@@ -290,12 +314,13 @@ export const SysSmsApiFp = function(configuration?: Configuration) {
         /**
          * 
          * @summary 阿里云发送短信 📨
-         * @param {string} phoneNumber 
+         * @param {string} phoneNumber 手机号
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber, options);
+        async apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -304,13 +329,14 @@ export const SysSmsApiFp = function(configuration?: Configuration) {
         /**
          * 
          * @summary 发送短信模板
-         * @param {any} body 
-         * @param {string} phoneNumber 
+         * @param {any} body 短信内容
+         * @param {string} phoneNumber 手机号
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body: any, phoneNumber: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body, phoneNumber, options);
+        async apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost(body: any, phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost(body, phoneNumber, templateId, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -320,11 +346,12 @@ export const SysSmsApiFp = function(configuration?: Configuration) {
          * 
          * @summary 发送短信 📨
          * @param {string} phoneNumber 
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsSendSmsPhoneNumberPost(phoneNumber, options);
+        async apiSysSmsSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -334,11 +361,12 @@ export const SysSmsApiFp = function(configuration?: Configuration) {
          * 
          * @summary 腾讯云发送短信 📨
          * @param {string} phoneNumber 
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsTencentSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
-            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsTencentSendSmsPhoneNumberPost(phoneNumber, options);
+        async apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysSmsApiAxiosParamCreator(configuration).apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options);
             return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
                 const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
                 return axios.request(axiosRequestArgs);
@@ -370,43 +398,47 @@ export const SysSmsApiFactory = function (configuration?: Configuration, basePat
         /**
          * 
          * @summary 阿里云发送短信 📨
-         * @param {string} phoneNumber 
+         * @param {string} phoneNumber 手机号
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysSmsApiFp(configuration).apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(axios, basePath));
+        async apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysSmsApiFp(configuration).apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options).then((request) => request(axios, basePath));
         },
         /**
          * 
          * @summary 发送短信模板
-         * @param {any} body 
-         * @param {string} phoneNumber 
+         * @param {any} body 短信内容
+         * @param {string} phoneNumber 手机号
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body: any, phoneNumber: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysSmsApiFp(configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body, phoneNumber, options).then((request) => request(axios, basePath));
+        async apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost(body: any, phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysSmsApiFp(configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost(body, phoneNumber, templateId, options).then((request) => request(axios, basePath));
         },
         /**
          * 
          * @summary 发送短信 📨
          * @param {string} phoneNumber 
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysSmsApiFp(configuration).apiSysSmsSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(axios, basePath));
+        async apiSysSmsSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysSmsApiFp(configuration).apiSysSmsSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options).then((request) => request(axios, basePath));
         },
         /**
          * 
          * @summary 腾讯云发送短信 📨
          * @param {string} phoneNumber 
+         * @param {string} templateId 短信模板id
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          */
-        async apiSysSmsTencentSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
-            return SysSmsApiFp(configuration).apiSysSmsTencentSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(axios, basePath));
+        async apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysSmsApiFp(configuration).apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options).then((request) => request(axios, basePath));
         },
         /**
          * 
@@ -431,47 +463,51 @@ export class SysSmsApi extends BaseAPI {
     /**
      * 
      * @summary 阿里云发送短信 📨
-     * @param {string} phoneNumber 
+     * @param {string} phoneNumber 手机号
+     * @param {string} templateId 短信模板id
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysSmsApi
      */
-    public async apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysSmsApiFp(this.configuration).apiSysSmsAliyunSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(this.axios, this.basePath));
+    public async apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysSmsApiFp(this.configuration).apiSysSmsAliyunSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 
      * @summary 发送短信模板
-     * @param {any} body 
-     * @param {string} phoneNumber 
+     * @param {any} body 短信内容
+     * @param {string} phoneNumber 手机号
+     * @param {string} templateId 短信模板id
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysSmsApi
      */
-    public async apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body: any, phoneNumber: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysSmsApiFp(this.configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberPost(body, phoneNumber, options).then((request) => request(this.axios, this.basePath));
+    public async apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost(body: any, phoneNumber: string, templateId: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysSmsApiFp(this.configuration).apiSysSmsAliyunSendSmsTemplatePhoneNumberTemplateIdPost(body, phoneNumber, templateId, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 
      * @summary 发送短信 📨
      * @param {string} phoneNumber 
+     * @param {string} templateId 短信模板id
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysSmsApi
      */
-    public async apiSysSmsSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysSmsApiFp(this.configuration).apiSysSmsSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(this.axios, this.basePath));
+    public async apiSysSmsSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysSmsApiFp(this.configuration).apiSysSmsSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 
      * @summary 腾讯云发送短信 📨
      * @param {string} phoneNumber 
+     * @param {string} templateId 短信模板id
      * @param {*} [options] Override http request option.
      * @throws {RequiredError}
      * @memberof SysSmsApi
      */
-    public async apiSysSmsTencentSendSmsPhoneNumberPost(phoneNumber: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
-        return SysSmsApiFp(this.configuration).apiSysSmsTencentSendSmsPhoneNumberPost(phoneNumber, options).then((request) => request(this.axios, this.basePath));
+    public async apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost(phoneNumber: string, templateId: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysSmsApiFp(this.configuration).apiSysSmsTencentSendSmsPhoneNumberTemplateIdPost(phoneNumber, templateId, options).then((request) => request(this.axios, this.basePath));
     }
     /**
      * 

+ 69 - 65
Web/src/api-services/models/db-column-input.ts

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

+ 0 - 30
Web/src/api-services/models/delete-file-input.ts

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

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

@@ -171,7 +171,6 @@ export * from './delete-db-column-input';
 export * from './delete-db-table-input';
 export * from './delete-dict-data-input';
 export * from './delete-dict-type-input';
-export * from './delete-file-input';
 export * from './delete-job-detail-input';
 export * from './delete-job-trigger-input';
 export * from './delete-menu-input';

+ 8 - 0
Web/src/api-services/models/login-user-output.ts

@@ -170,4 +170,12 @@ export interface LoginUserOutput {
      * @memberof LoginUserOutput
      */
     tenantId?: number | null;
+
+    /**
+     * 当前切换到的租户Id
+     *
+     * @type {number}
+     * @memberof LoginUserOutput
+     */
+    currentTenantId?: number | null;
 }

+ 0 - 16
Web/src/api-services/models/sys-file-upload-file-body.ts

@@ -45,22 +45,6 @@ export interface SysFileUploadFileBody {
     isPublic?: boolean;
 
     /**
-     * 文件路径
-     *
-     * @type {string}
-     * @memberof SysFileUploadFileBody
-     */
-    path?: string;
-
-    /**
-     * 文件保存路径
-     *
-     * @type {string}
-     * @memberof SysFileUploadFileBody
-     */
-    savePath?: string;
-
-    /**
      * 允许格式:.jpeg.jpg.png.bmp.gif.tif
      *
      * @type {string}

+ 11 - 19
Web/src/api-services/models/sys-file.ts

@@ -165,42 +165,34 @@ export interface SysFile {
     fileMd5?: string | null;
 
     /**
-     * 关联对象名称(如子对象)
+     * 文件类别
      *
      * @type {string}
      * @memberof SysFile
      */
-    relationName?: string | null;
-
-    /**
-     * 关联对象Id
-     *
-     * @type {number}
-     * @memberof SysFile
-     */
-    relationId?: number | null;
+    fileType?: string | null;
 
     /**
-     * 所属Id(如主对象)
+     * 文件别名
      *
-     * @type {number}
+     * @type {string}
      * @memberof SysFile
      */
-    belongId?: number | null;
+    fileAlias?: string | null;
 
     /**
-     * 文件类别
+     * 是否公开
      *
-     * @type {string}
+     * @type {boolean}
      * @memberof SysFile
      */
-    fileType?: string | null;
+    isPublic?: boolean;
 
     /**
-     * 是否公开  若为true则所有人都可以查看,默认只有自己或有权限的可以查看
+     * 业务数据Id
      *
-     * @type {boolean}
+     * @type {number}
      * @memberof SysFile
      */
-    isPublic?: boolean;
+    dataId?: number | null;
 }

+ 39 - 35
Web/src/api-services/models/update-db-column-input.ts

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

+ 0 - 8
Web/src/api-services/models/upload-file-from-base64-input.ts

@@ -43,12 +43,4 @@ export interface UploadFileFromBase64Input {
      * @memberof UploadFileFromBase64Input
      */
     contentType?: string | null;
-
-    /**
-     * 保存路径
-     *
-     * @type {string}
-     * @memberof UploadFileFromBase64Input
-     */
-    path?: string | null;
 }

+ 25 - 0
Web/src/api/system/admin.ts

@@ -2,6 +2,9 @@ import request from '/@/utils/request';
 enum Api {
 	DictTypeDataList = '/api/sysDictData/DataList',
 	AllDictList = '/api/sysDictType/AllDictList',
+	HardwareInfo = '/api/sysServer/hardwareInfo',
+	RuntimeInfo = '/api/sysServer/runtimeInfo',
+	NuGetPackagesInfo = '/api/sysServer/nuGetPackagesInfo',
 }
 
 // 根据字典类型编码获取字典值集合
@@ -17,3 +20,25 @@ export const getAllDictList = () =>
 		url: `${Api.AllDictList}`,
 		method: 'get',
 	});
+
+	// 获取硬件信息
+export const getHardwareInfo = () =>
+	request({
+		url: `${Api.HardwareInfo}`,
+		method: 'post',
+	});
+
+// 获取运行时信息
+export const getRuntimeInfo = () =>
+	request({
+		url: `${Api.RuntimeInfo}`,
+		method: 'post',
+	});
+
+// 获取NuGet包信息
+export const getNuGetPackagesInfo = () =>
+	request({
+		url: `${Api.NuGetPackagesInfo}`,
+		method: 'post',
+	});
+

+ 1 - 3
Web/src/views/system/codeGen/index.vue

@@ -192,9 +192,7 @@ const syncCodeGen = async (row: any) => {
     cancelButtonText: '取消',
     type: 'warning',
   }).then(async () => {
-    await getAPI(SysCodeGenApi).apiSysCodeGenDeletePost([{ id: row.id }]);
-    row.id = undefined;
-    await getAPI(SysCodeGenApi).apiSysCodeGenAddPost(row);
+	await getAPI(SysCodeGenApi).apiSysCodeGenUpdatePost(row);
     handleQuery();
     ElMessage.success('同步成功');
   }).catch(() => {});

+ 8 - 0
Web/src/views/system/database/component/addColumn.vue

@@ -57,6 +57,11 @@
 							<el-input-number v-model="state.ruleForm.decimalDigits" class="w100" controls-position="right" />
 						</el-form-item>
 					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="默认值" prop="defaultValue">
+							<el-input v-model="state.ruleForm.defaultValue" placeholder="默认值" clearable />
+						</el-form-item>
+					</el-col>
 				</el-row>
 			</el-form>
 			<template #footer>
@@ -87,6 +92,9 @@ const state = reactive({
 // 打开弹窗
 const openDialog = (addRow: DbColumnInput) => {
 	state.ruleForm = addRow;
+	if (state.ruleForm.length === 0) {
+		state.ruleForm.length = 32;
+	}
 	state.isShowDialog = true;
 	ruleFormRef.value?.resetFields();
 };

+ 6 - 1
Web/src/views/system/database/component/addTable.vue

@@ -24,7 +24,7 @@
 			</el-form>
 			<el-divider content-position="left">数据列信息</el-divider>
 			<el-table :data="state.tableData" style="width: 100%" max-height="400">
-				<el-table-column prop="dbColumnName" label="字段名" width="220" fixed>
+				<el-table-column prop="dbColumnName" label="字段名" width="200" fixed>
 					<template #default="scope">
 						<el-input v-model="scope.row.dbColumnName" autocomplete="off" />
 					</template>
@@ -71,6 +71,11 @@
 					<template #default="scope">
 						<el-input-number v-model="scope.row.decimalDigits" controls-position="right" class="w100" />
 					</template>
+				</el-table-column>				
+				<el-table-column prop="defaultValue" label="默认值" width="90">
+					<template #default="scope">
+						<el-input v-model="scope.row.defaultValue" autocomplete="off" />
+					</template>
 				</el-table-column>
 				<el-table-column label="操作" min-width="200" align="center" fixed="right">
 					<template #default="scope">

+ 5 - 0
Web/src/views/system/database/component/editColumn.vue

@@ -19,6 +19,11 @@
 							<el-input v-model="state.ruleForm.description" placeholder="描述" clearable type="textarea" />
 						</el-form-item>
 					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="默认值" prop="defaultValue">
+							<el-input v-model="state.ruleForm.defaultValue" placeholder="默认值" clearable />
+						</el-form-item>
+					</el-col>
 				</el-row>
 			</el-form>
 			<template #footer>

+ 53 - 5
Web/src/views/system/database/index.vue

@@ -59,10 +59,12 @@
 				<el-table-column prop="decimalDigits" label="精度" width="70" align="center" show-overflow-tooltip />
 				<el-table-column prop="defaultValue" label="默认值" align="center" show-overflow-tooltip />
 				<el-table-column prop="columnDescription" label="描述" header-align="center" show-overflow-tooltip />
-				<el-table-column label="操作" width="145" fixed="right" align="center" show-overflow-tooltip>
+				<el-table-column label="操作" width="195" fixed="right" align="center" show-overflow-tooltip>
 					<template #default="scope">
-						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditColumn(scope.row)"> 编辑 </el-button>
-						<el-button icon="ele-Delete" size="small" text type="danger" @click="delColumn(scope.row)"> 删除 </el-button>
+						<el-button icon="ele-Top" size="small" text type="primary" @click="moveColumn(scope.row, 'up')" :disabled="scope.$index === 0" title="上移"></el-button>
+						<el-button icon="ele-Bottom" size="small" text type="primary" @click="moveColumn(scope.row, 'down')" :disabled="scope.$index === state.columnData.length - 1" title="下移"></el-button>
+						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditColumn(scope.row)">编辑</el-button>
+						<el-button icon="ele-Delete" size="small" text type="danger" @click="delColumn(scope.row)">删除</el-button>
 					</template>
 				</el-table-column>
 			</el-table>
@@ -90,7 +92,7 @@ import GenSeedData from '/@/views/system/database/component/genSeedData.vue';
 
 import { getAPI } from '/@/utils/axios-utils';
 import { SysDatabaseApi, SysCodeGenApi } from '/@/api-services/api';
-import { DbColumnOutput, DbTableInfo, DbColumnInput, DeleteDbTableInput, DeleteDbColumnInput } from '/@/api-services/models';
+import { DbColumnOutput, DbTableInfo, DbColumnInput, DeleteDbTableInput, DeleteDbColumnInput, MoveDbColumnInput } from '/@/api-services/models';
 
 const editTableRef = ref<InstanceType<typeof EditTable>>();
 const editColumnRef = ref<InstanceType<typeof EditColumn>>();
@@ -240,6 +242,7 @@ const openEditColumn = (row: any) => {
 		columnName: row.dbColumnName,
 		oldColumnName: row.dbColumnName,
 		description: row.columnDescription,
+		defaultValue: row.defaultValue,
 	};
 	editColumnRef.value?.openDialog(column);
 };
@@ -311,12 +314,57 @@ const delColumn = (row: any) => {
 				dbColumnName: row.dbColumnName,
 			};
 			await getAPI(SysDatabaseApi).apiSysDatabaseDeleteColumnPost(eleteDbColumnInput);
-			handleQueryTable();
+			handleQueryColumn();
 			ElMessage.success('列删除成功');
 		})
 		.catch(() => {});
 };
 
+const moveColumn = (row: any, direction: 'up' | 'down') => {
+	const { columnData, tableName, configId } = state;
+	const currentIndex = columnData.findIndex((item) => item.dbColumnName === row.dbColumnName);
+
+	// 边界检查与反馈
+	if (direction === 'up' && currentIndex === 0) {
+		ElMessage.warning('已处于首位,无法上移');
+		return;
+	}
+	if (direction === 'down' && currentIndex === columnData.length - 1) {
+		ElMessage.warning('已处于末位,无法下移');
+		return;
+	}
+
+	// 计算目标位置
+	const targetIndex = direction === 'up' ? currentIndex - 1 : currentIndex + 1;
+	const targetColumn = columnData[targetIndex];
+	const columnName = direction === 'up' ? targetColumn.dbColumnName : row.dbColumnName;
+	const afterColumnName = direction === 'up' ? row.dbColumnName : targetColumn.dbColumnName;
+
+	ElMessageBox.confirm(`确定将列【${row.dbColumnName}】${direction === 'up' ? '上移' : '下移'}?`, '操作确认', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	}).then(async () => {
+			try {
+				const moveParams: MoveDbColumnInput = {
+					configId,
+					tableName,
+					columnName,
+					afterColumnName,
+				};
+
+				// 调用API
+				await getAPI(SysDatabaseApi).apiSysDatabaseMoveColumnPost(moveParams);
+
+				handleQueryColumn();
+				ElMessage.success('列位置已更新');
+			} catch (error: any) {
+				ElMessage.error(`操作失败: ${error.message || '未知错误'}`);
+			}
+		})
+		.catch(() => {});
+};
+
 // 可视化表
 const visualTable = () => {
 	if (state.configId == '') {

+ 21 - 8
Web/src/views/system/dict/index.vue

@@ -10,6 +10,9 @@
 						<el-form-item label="名称">
 							<el-input v-model="state.queryDictTypeParams.name" @keyup.enter.native="handleDictTypeQuery" placeholder="字典名称" clearable />
 						</el-form-item>
+						<el-form-item label="编码">
+							<el-input v-model="state.queryDictTypeParams.code" @keyup.enter.native="handleDictTypeQuery" placeholder="字典编码" clearable />
+						</el-form-item>
 						<el-form-item>
 							<el-button-group>
 								<el-button type="primary" icon="ele-Search" @click="handleDictTypeQuery" v-auth="'sysDictType:page'"> 查询 </el-button>
@@ -21,26 +24,26 @@
 						</el-form-item>
 					</el-form>
 
-					<el-table :data="state.dictTypeData" style="width: 100%" v-loading="state.typeLoading" @row-click="handleDictType" highlight-current-row border>
-						<el-table-column type="index" label="序号" width="55" align="center" />
-						<el-table-column prop="name" label="字典名称" min-width="120" header-align="center" show-overflow-tooltip />
-						<el-table-column prop="code" label="字典编码" min-width="140" header-align="center" show-overflow-tooltip />
-						<el-table-column prop="sysFlag" label="系统内置" min-width="70" align="center" show-overflow-tooltip v-if="userInfo.accountType === AccountTypeEnum.NUMBER_999">
+					<el-table :data="state.dictTypeData" style="width: 100%" v-loading="state.typeLoading" @row-click="handleDictType" highlight-current-row @sort-change="sortChangeDityType" border>
+						<el-table-column type="index" label="序号" width="55" align="center" sortable='custom' />
+						<el-table-column prop="name" label="字典名称" min-width="120" header-align="center" sortable='custom' show-overflow-tooltip />
+						<el-table-column prop="code" label="字典编码" min-width="140" header-align="center" sortable='custom' show-overflow-tooltip />
+						<el-table-column prop="sysFlag" label="系统内置" min-width="90" align="center" sortable='custom' show-overflow-tooltip v-if="userInfo.accountType === AccountTypeEnum.NUMBER_999">
 							<template #default="scope">
                 <g-sys-dict v-model="scope.row.sysFlag" code="YesNoEnum" />
 							</template>
 						</el-table-column>
-						<el-table-column prop="isTenant" label="租户字典" min-width="70" align="center" show-overflow-tooltip v-if="userInfo.accountType === AccountTypeEnum.NUMBER_999">
+						<el-table-column prop="isTenant" label="租户字典" min-width="90" align="center"  sortable='custom'  show-overflow-tooltip v-if="userInfo.accountType === AccountTypeEnum.NUMBER_999">
 							<template #default="scope">
                 <g-sys-dict v-model="scope.row.isTenant" code="YesNoEnum" />
 							</template>
 						</el-table-column>
-						<el-table-column prop="status" label="状态" width="70" align="center" show-overflow-tooltip>
+						<el-table-column prop="status" label="状态" width="80" align="center"  sortable='custom'  show-overflow-tooltip>
 							<template #default="scope">
                 <g-sys-dict v-model="scope.row.status" code="StatusEnum" />
 							</template>
 						</el-table-column>
-						<el-table-column prop="orderNo" label="排序" width="60" align="center" show-overflow-tooltip />
+						<el-table-column prop="orderNo" label="排序" width="80" align="center"  sortable='custom'  show-overflow-tooltip />
 						<el-table-column label="修改记录" width="100" align="center" show-overflow-tooltip>
 							<template #default="scope">
 								<ModifyRecord :data="scope.row" />
@@ -181,6 +184,9 @@ const state = reactive({
 		page: 1,
 		pageSize: 50,
 		total: 0 as any,
+		field: 'orderNo',
+		order: 'ascending', // 排序方向
+		descStr: 'descending', // 降序排序的关键字符
 	},
 	queryDictDataParams: {
     label: undefined,
@@ -220,6 +226,13 @@ const handleDictDataQuery = async () => {
 	state.loading = false;
 };
 
+// 列排序
+const sortChangeDityType = async (column: any) => {
+  state.tableDictTypeParams.field = column.prop;
+  state.tableDictTypeParams.order = column.order;
+  await handleDictTypeQuery();
+};
+
 // 点击表格
 const handleDictType = (row: any, event: any, column: any) => {
 	openDictDataDialog(row);

+ 1194 - 0
Web/src/views/system/server/new.vue

@@ -0,0 +1,1194 @@
+<template>
+	<div class="device-info-container">
+		<!-- 系统概览卡片 -->
+		<el-row :gutter="16" style="margin-bottom: 16px">
+			<el-col :span="24">
+				<el-card class="overview-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-monitor"></i>
+							<span>系统概览</span>
+							<span class="status-text">运行正常</span>
+						</div>
+					</template>
+					<div class="overview-content">
+						<div class="overview-item">
+							<div class="overview-icon cpu-icon">
+								<i class="el-icon-cpu"></i>
+							</div>
+							<div class="overview-text">
+								<div class="overview-title">处理器</div>
+								<div class="overview-value">{{ deviceInfo.cpuInfo.processorName }}</div>
+								<div class="overview-subtitle">{{ deviceInfo.cpuInfo.physicalCoreCount }}核 {{ deviceInfo.cpuInfo.logicalCoreCount }}线程</div>
+							</div>
+						</div>
+						<div class="overview-item">
+							<div class="overview-icon ram-icon">
+								<i class="el-icon-film"></i>
+							</div>
+							<div class="overview-text">
+								<div class="overview-title">内存</div>
+								<div class="overview-value">{{ deviceInfo.ramInfo.totalSpace }}</div>
+								<div class="overview-subtitle">使用率 {{ deviceInfo.ramInfo.usagePercentage }}%</div>
+							</div>
+						</div>
+						<div class="overview-item">
+							<div class="overview-icon os-icon">
+								<i class="el-icon-monitor"></i>
+							</div>
+							<div class="overview-text">
+								<div class="overview-title">操作系统</div>
+								<div class="overview-value">{{ deviceInfo.systemInfo.osDescription }}</div>
+								<div class="overview-subtitle">{{ deviceInfo.systemInfo.osArchitecture }} 架构</div>
+							</div>
+						</div>
+						<div class="overview-item">
+							<div class="overview-icon framework-icon">
+								<i class="el-icon-guide"></i>
+							</div>
+							<div class="overview-text">
+								<div class="overview-title">运行框架</div>
+								<div class="overview-value">{{ deviceInfo.systemInfo.frameworkDescription }}</div>
+								<div class="overview-subtitle">{{ deviceInfo.systemInfo.machineName }}</div>
+							</div>
+						</div>
+						<div class="overview-item">
+							<div class="overview-icon time-icon">
+								<i class="el-icon-time"></i>
+							</div>
+							<div class="overview-text">
+								<div class="overview-title">运行时间</div>
+								<div class="overview-value">{{ deviceInfo.systemUptime }}</div>
+								<div class="overview-subtitle">系统稳定运行</div>
+							</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- CPU和内存性能 -->
+		<el-row :gutter="16" style="margin-bottom: 16px">
+			<el-col :md="12" :sm="24">
+				<el-card class="performance-card cpu-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-cpu"></i>
+							<span>CPU 性能</span>
+						</div>
+					</template>
+					<div class="performance-content">
+						<div class="performance-chart">
+							<el-progress type="dashboard" :percentage="deviceInfo.cpuInfo.usagePercentage" :color="getCpuColor(deviceInfo.cpuInfo.usagePercentage)" :width="180" :stroke-width="12">
+								<template #default>
+									<div class="progress-content">
+										<div class="progress-value">{{ deviceInfo.cpuInfo.usagePercentage }}%</div>
+										<div class="progress-label">CPU使用率</div>
+									</div>
+								</template>
+							</el-progress>
+						</div>
+						<div class="performance-details">
+							<div class="detail-item">
+								<span class="detail-label">处理器架构:</span>
+								<span class="detail-value">{{ deviceInfo.cpuInfo.processorArchitecture }}</span>
+							</div>
+							<div class="detail-item">
+								<span class="detail-label">基础频率:</span>
+								<span class="detail-value">{{ deviceInfo.cpuInfo.baseClockSpeed }} GHz</span>
+							</div>
+							<div class="detail-item">
+								<span class="detail-label">缓存大小:</span>
+								<span class="detail-value">{{ deviceInfo.cpuInfo.cacheSize }}</span>
+							</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+			<el-col :md="12" :sm="24">
+				<el-card class="performance-card ram-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-memory-card"></i>
+							<span>内存使用</span>
+						</div>
+					</template>
+					<div class="performance-content">
+						<div class="performance-chart">
+							<el-progress type="dashboard" :percentage="deviceInfo.ramInfo.usagePercentage" :color="getRamColor(deviceInfo.ramInfo.usagePercentage)" :width="180" :stroke-width="12">
+								<template #default>
+									<div class="progress-content">
+										<div class="progress-value">{{ deviceInfo.ramInfo.usagePercentage.toFixed(1) }}%</div>
+										<div class="progress-label">内存使用</div>
+									</div>
+								</template>
+							</el-progress>
+						</div>
+						<div class="performance-details">
+							<div class="detail-item">
+								<span class="detail-label">总内存:</span>
+								<span class="detail-value">{{ deviceInfo.ramInfo.totalSpace }}</span>
+							</div>
+							<div class="detail-item">
+								<span class="detail-label">已使用:</span>
+								<span class="detail-value">{{ deviceInfo.ramInfo.usedSpace }}</span>
+							</div>
+							<div class="detail-item">
+								<span class="detail-label">可用:</span>
+								<span class="detail-value">{{ deviceInfo.ramInfo.freeSpace }}</span>
+							</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- 磁盘信息 -->
+		<el-row :gutter="16" style="margin-bottom: 16px">
+			<el-col :span="24">
+				<el-card class="disk-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-files"></i>
+							<span>磁盘使用情况</span>
+						</div>
+					</template>
+					<el-row :gutter="16">
+						<el-col :md="12" :sm="24" v-for="disk in deviceInfo.diskInfos" :key="disk.diskName">
+							<div class="disk-item">
+								<div class="disk-header">
+									<div class="disk-name">{{ disk.diskName }}</div>
+									<div class="disk-type">{{ disk.typeName }}</div>
+								</div>
+								<div class="disk-content">
+									<div class="disk-chart">
+										<el-progress type="circle" :percentage="parseFloat(disk.usedPercentage)" :color="getDiskColor(disk.availableRate)" :width="120" :stroke-width="8">
+											<template #default>
+												<div class="disk-progress-content">
+													<div class="disk-usage">{{ disk.usedPercentage }}%</div>
+													<div class="disk-label">已使用</div>
+												</div>
+											</template>
+										</el-progress>
+									</div>
+									<div class="disk-details">
+										<div class="disk-detail-item">
+											<span class="detail-label">总容量:</span>
+											<span class="detail-value">{{ disk.totalSpace }}</span>
+										</div>
+										<div class="disk-detail-item">
+											<span class="detail-label">已使用:</span>
+											<span class="detail-value">{{ disk.usedSpace }}</span>
+										</div>
+										<div class="disk-detail-item">
+											<span class="detail-label">可用空间:</span>
+											<span class="detail-value">{{ disk.freeSpace }}</span>
+										</div>
+									</div>
+								</div>
+							</div>
+						</el-col>
+					</el-row>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- GPU信息 -->
+		<el-row :gutter="16" style="margin-bottom: 16px">
+			<el-col :span="24">
+				<el-card class="gpu-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-view"></i>
+							<span>显卡信息</span>
+						</div>
+					</template>
+					<el-row :gutter="16">
+						<el-col :md="12" :sm="24" v-for="(gpu, index) in deviceInfo.gpuInfos" :key="index">
+							<div class="gpu-item">
+								<div class="gpu-header">
+									<div class="gpu-name">{{ gpu.name }}</div>
+									<el-tag :type="gpu.status === 'OK' ? 'success' : 'danger'" size="small">
+										{{ gpu.status }}
+									</el-tag>
+								</div>
+								<div class="gpu-details">
+									<div class="gpu-detail-item">
+										<span class="detail-label">显存:</span>
+										<span class="detail-value">{{ gpu.memorySize }}</span>
+									</div>
+									<div class="gpu-detail-item">
+										<span class="detail-label">驱动版本:</span>
+										<span class="detail-value">{{ gpu.driverVersion || 'N/A' }}</span>
+									</div>
+									<div class="gpu-detail-item">
+										<span class="detail-label">分辨率:</span>
+										<span class="detail-value">{{ gpu.videoModeDescription }}</span>
+									</div>
+								</div>
+							</div>
+						</el-col>
+					</el-row>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- 网络信息 -->
+		<el-row :gutter="16" style="margin-bottom: 16px">
+			<el-col :span="24">
+				<el-card class="network-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-connection"></i>
+							<span>网络适配器</span>
+							<span class="status-text">{{ getActiveNetworks().length }} 个活跃</span>
+						</div>
+					</template>
+					<div class="network-content">
+						<el-collapse v-model="activeNetworkNames" accordion>
+							<el-collapse-item v-for="network in getActiveNetworks()" :key="network.name" :name="network.name">
+								<template #title>
+									<div class="network-title">
+										<div class="network-status">
+											<i :class="getNetworkStatusIcon(network.operationalStatus)"></i>
+											<span class="network-name">{{ network.name }}</span>
+										</div>
+										<div class="network-type">
+											<el-tag size="small" :type="getNetworkTypeColor(network.type)">
+												{{ network.type }}
+											</el-tag>
+										</div>
+									</div>
+								</template>
+								<div class="network-details">
+									<el-row :gutter="16">
+										<el-col :md="12" :sm="24">
+											<div class="network-info">
+												<div class="network-detail-item">
+													<span class="detail-label">描述:</span>
+													<span class="detail-value">{{ network.description }}</span>
+												</div>
+												<div class="network-detail-item">
+													<span class="detail-label">物理地址:</span>
+													<span class="detail-value">{{ network.physicalAddress || 'N/A' }}</span>
+												</div>
+												<div class="network-detail-item">
+													<span class="detail-label">速度:</span>
+													<span class="detail-value">{{ network.speed }}</span>
+												</div>
+												<div class="network-detail-item" v-if="network.iPv4Addresses && network.iPv4Addresses.length > 0">
+													<span class="detail-label">IPv4地址:</span>
+													<div class="ip-addresses">
+														<el-tag v-for="ip in network.iPv4Addresses" :key="ip.address" size="small" class="ip-tag">
+															{{ ip.address }}
+														</el-tag>
+													</div>
+												</div>
+											</div>
+										</el-col>
+										<el-col :md="12" :sm="24" v-if="network.statistics">
+											<div class="network-statistics">
+												<h4>网络统计</h4>
+												<div class="stats-grid">
+													<div class="stat-item">
+														<div class="stat-label">接收字节</div>
+														<div class="stat-value">{{ formatBytes(network.statistics.bytesReceived) }}</div>
+													</div>
+													<div class="stat-item">
+														<div class="stat-label">发送字节</div>
+														<div class="stat-value">{{ formatBytes(network.statistics.bytesSent) }}</div>
+													</div>
+													<div class="stat-item">
+														<div class="stat-label">接收包数</div>
+														<div class="stat-value">{{ network.statistics.packetsReceived.toLocaleString() }}</div>
+													</div>
+													<div class="stat-item">
+														<div class="stat-label">发送包数</div>
+														<div class="stat-value">{{ network.statistics.packetsSent.toLocaleString() }}</div>
+													</div>
+												</div>
+											</div>
+										</el-col>
+									</el-row>
+								</div>
+							</el-collapse-item>
+						</el-collapse>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- 主板信息 -->
+		<el-row :gutter="16" style="margin-bottom: 16px">
+			<el-col :span="24">
+				<el-card class="board-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-cpu"></i>
+							<span>主板信息</span>
+						</div>
+					</template>
+					<div class="board-content">
+						<div class="board-item">
+							<span class="detail-label">制造商:</span>
+							<span class="detail-value">{{ deviceInfo.boardInfo.manufacturer }}</span>
+						</div>
+						<div class="board-item">
+							<span class="detail-label">产品型号:</span>
+							<span class="detail-value">{{ deviceInfo.boardInfo.product }}</span>
+						</div>
+						<div class="board-item">
+							<span class="detail-label">版本:</span>
+							<span class="detail-value">{{ deviceInfo.boardInfo.version }}</span>
+						</div>
+						<div class="board-item">
+							<span class="detail-label">序列号:</span>
+							<span class="detail-value">{{ deviceInfo.boardInfo.serialNumber }}</span>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- 系统信息 -->
+		<el-row :gutter="16">
+			<el-col :span="24">
+				<el-card class="system-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-setting"></i>
+							<span>系统信息</span>
+						</div>
+					</template>
+					<div class="system-content">
+						<div class="system-item">
+							<span class="detail-label">操作系统:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.osDescription }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">系统版本:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.osVersion }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">系统架构:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.osArchitecture }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">运行框架:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.frameworkDescription }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">机器名称:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.machineName }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">当前用户:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.userName }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">系统启动时间:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.systemStartTime }}</span>
+						</div>
+						<div class="system-item">
+							<span class="detail-label">进程启动时间:</span>
+							<span class="detail-value">{{ deviceInfo.systemInfo.processStartTime }}</span>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- NuGet包信息 -->
+		<el-row :gutter="16">
+			<el-col :span="24">
+				<el-card class="nuget-card" shadow="hover">
+					<template #header>
+						<div class="card-header">
+							<i class="el-icon-collection"></i>
+							<span>NuGet 包信息</span>
+							<span class="status-text">{{ deviceInfo.nugetPackages.length }} 个包</span>
+						</div>
+					</template>
+					<div class="nuget-content">
+						<div v-for="pkg in deviceInfo.nugetPackages" :key="pkg.packageName" class="package-item">
+							<el-tag round>
+								<div class="package-info">
+									<div class="package-name">{{ pkg.packageName }}</div>
+									<div class="package-version">v{{ pkg.packageVersion }}</div>
+								</div>
+							</el-tag>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+	</div>
+</template>
+
+<script lang="ts" setup name="deviceInfo">
+import { ref, reactive, onMounted } from 'vue';
+import { getHardwareInfo, getRuntimeInfo, getNuGetPackagesInfo } from '/@/api/system/admin';
+
+// 网络接口类型定义
+interface NetworkInfo {
+	name: string;
+	description: string;
+	type: string;
+	operationalStatus: string;
+	speed: string;
+	physicalAddress: string;
+	supportsMulticast: boolean;
+	isReceiveOnly: boolean;
+	dnsAddresses: string[];
+	gatewayAddresses: string[];
+	dhcpServerAddresses: string[];
+	iPv4Addresses: Array<{
+		address: string;
+		subnetMask: string;
+		prefixLength: number;
+	}>;
+	iPv6Addresses: Array<{
+		address: string;
+		subnetMask: string;
+		prefixLength: number;
+	}>;
+	statistics?: {
+		bytesReceived: number;
+		bytesSent: number;
+		packetsReceived: number;
+		packetsSent: number;
+		incomingPacketsDiscarded: number;
+		outgoingPacketsDiscarded: number;
+		incomingPacketsWithErrors: number;
+		outgoingPacketsWithErrors: number;
+	};
+}
+
+// 设备信息数据
+const deviceInfo = reactive<any>({
+	cpuInfo: {
+		processorName: '',
+		processorArchitecture: '',
+		physicalCoreCount: 0,
+		logicalCoreCount: 0,
+		baseClockSpeed: 0,
+		cacheSize: '',
+		usagePercentage: 0,
+	},
+	ramInfo: {
+		totalSpace: '',
+		usedSpace: '',
+		freeSpace: '',
+		usagePercentage: 0,
+	},
+	diskInfos: [],
+	networkInfos: [],
+	gpuInfos: [],
+	boardInfo: {
+		manufacturer: '',
+		product: '',
+		version: '',
+		serialNumber: '',
+	},
+	systemUptime: '',
+	systemInfo: {
+		osDescription: '',
+		osVersion: '',
+		osArchitecture: '',
+		frameworkDescription: '',
+		machineName: '',
+		userName: '',
+		systemStartTime: '',
+		processStartTime: '',
+	},
+	nugetPackages: [],
+});
+
+const activeNetworkNames = ref('');
+
+// 格式化字节数为可读格式
+const formatBytes = (bytes: number) => {
+	if (bytes === 0) return '0 B';
+	const k = 1024;
+	const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+	const i = Math.floor(Math.log(bytes) / Math.log(k));
+	return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+};
+
+// 获取硬件信息
+const getHardwareInfoData = async () => {
+	try {
+		// 并行获取硬件信息、运行时信息和 NuGet 包信息
+		const [hardwareRes, runtimeRes, nugetRes] = await Promise.all([getHardwareInfo(), getRuntimeInfo(), getNuGetPackagesInfo()]);
+
+		const hardwareData = hardwareRes.data.result;
+		const runtimeData = runtimeRes.data.result;
+		const nugetPackages = nugetRes.data.result;
+
+		// 处理CPU信息
+		Object.assign(deviceInfo.cpuInfo, {
+			processorName: hardwareData.cpuInfo.processorName,
+			processorArchitecture: hardwareData.cpuInfo.processorArchitecture,
+			physicalCoreCount: hardwareData.cpuInfo.physicalCoreCount,
+			logicalCoreCount: hardwareData.cpuInfo.logicalCoreCount,
+			baseClockSpeed: hardwareData.cpuInfo.baseClockSpeed,
+			cacheSize: formatBytes(hardwareData.cpuInfo.cacheBytes || 0),
+			usagePercentage: hardwareData.cpuInfo.usagePercentage,
+		});
+
+		// 处理内存信息
+		Object.assign(deviceInfo.ramInfo, {
+			totalSpace: formatBytes(hardwareData.ramInfo.totalBytes),
+			usedSpace: formatBytes(hardwareData.ramInfo.usedBytes),
+			freeSpace: formatBytes(hardwareData.ramInfo.freeBytes),
+			usagePercentage: hardwareData.ramInfo.usagePercentage,
+		});
+
+		// 处理磁盘信息
+		deviceInfo.diskInfos = hardwareData.diskInfos.map((disk: any) => ({
+			diskName: disk.diskName,
+			typeName: disk.typeName,
+			totalSpace: formatBytes(disk.totalSpace),
+			usedSpace: formatBytes(disk.usedSpace),
+			freeSpace: formatBytes(disk.freeSpace),
+			availableRate: disk.availableRate,
+			usedPercentage: ((disk.usedSpace / disk.totalSpace) * 100).toFixed(1),
+		}));
+
+		// 处理网络信息
+		deviceInfo.networkInfos = hardwareData.networkInfos;
+
+		// 处理GPU信息
+		deviceInfo.gpuInfos = hardwareData.gpuInfos.map((gpu: any) => ({
+			name: gpu.name,
+			description: gpu.description,
+			vendor: gpu.vendor,
+			deviceId: gpu.deviceId,
+			busInfo: gpu.busInfo,
+			driverVersion: gpu.driverVersion,
+			memorySize: gpu.memoryBytes ? formatBytes(gpu.memoryBytes) : 'N/A',
+			videoModeDescription: gpu.videoModeDescription,
+			status: gpu.status,
+		}));
+
+		// 处理主板信息
+		Object.assign(deviceInfo.boardInfo, {
+			manufacturer: hardwareData.boardInfo.manufacturer,
+			product: hardwareData.boardInfo.product,
+			version: hardwareData.boardInfo.version,
+			serialNumber: hardwareData.boardInfo.serialNumber,
+		});
+
+		// 处理系统运行时间和其他系统信息
+		deviceInfo.systemUptime = runtimeData.runningTime || runtimeData.runtimeInfo.systemUptime;
+
+		// 添加系统信息到deviceInfo(可选)
+		deviceInfo.systemInfo = {
+			osDescription: runtimeData.runtimeInfo.osDescription,
+			osVersion: runtimeData.runtimeInfo.osVersion,
+			osArchitecture: runtimeData.runtimeInfo.osArchitecture,
+			frameworkDescription: runtimeData.runtimeInfo.frameworkDescription,
+			machineName: runtimeData.runtimeInfo.machineName,
+			userName: runtimeData.runtimeInfo.userName,
+			systemStartTime: runtimeData.runtimeInfo.systemStartTime,
+			processStartTime: runtimeData.runtimeInfo.processStartTime,
+		};
+
+		// 处理 NuGet 包信息
+		deviceInfo.nugetPackages = nugetPackages.map((pkg: any) => ({
+			packageName: pkg.packageName,
+			packageVersion: pkg.packageVersion,
+		}));
+	} catch (error) {
+		console.error('获取硬件信息失败:', error);
+		// 设置默认值,避免页面崩溃
+		deviceInfo.systemUptime = '获取失败';
+	}
+};
+
+// 获取活跃网络
+const getActiveNetworks = () => {
+	return deviceInfo.networkInfos.filter(
+		(network: NetworkInfo) =>
+			network.operationalStatus === 'Up' && !network.name.includes('WFP') && !network.name.includes('QoS') && !network.name.includes('Filter') && !network.name.includes('vSwitch')
+	);
+};
+
+// 获取网络状态图标
+const getNetworkStatusIcon = (status: string) => {
+	switch (status) {
+		case 'Up':
+			return 'el-icon-success network-status-up';
+		case 'Down':
+			return 'el-icon-error network-status-down';
+		default:
+			return 'el-icon-warning network-status-unknown';
+	}
+};
+
+// 获取网络类型颜色
+const getNetworkTypeColor = (type: string) => {
+	switch (type) {
+		case 'Ethernet':
+			return 'primary';
+		case 'Wireless80211':
+			return 'success';
+		case 'Loopback':
+			return 'info';
+		default:
+			return 'warning';
+	}
+};
+
+// 获取CPU使用率颜色
+const getCpuColor = (percentage: number) => {
+	if (percentage < 50) return '#67c23a';
+	if (percentage < 80) return '#e6a23c';
+	return '#f56c6c';
+};
+
+// 获取内存使用率颜色
+const getRamColor = (percentage: number) => {
+	if (percentage < 60) return '#409eff';
+	if (percentage < 80) return '#e6a23c';
+	return '#f56c6c';
+};
+
+// 获取磁盘使用率颜色
+const getDiskColor = (availablePercentage: number) => {
+	const usedPercentage = 100 - availablePercentage;
+	if (usedPercentage < 70) return '#67c23a';
+	if (usedPercentage < 90) return '#e6a23c';
+	return '#f56c6c';
+};
+
+onMounted(() => {
+	console.log('设备信息页面已加载');
+	getHardwareInfoData();
+});
+</script>
+
+<style lang="scss" scoped>
+.device-info-container {
+	padding: 16px;
+	background: #f5f7fa;
+	min-height: 100vh;
+}
+
+.card-header {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	font-weight: 600;
+
+	i {
+		margin-right: 8px;
+		font-size: 18px;
+	}
+
+	> span:first-of-type {
+		flex: 1;
+	}
+}
+
+.status-text {
+	font-size: 12px;
+	color: #67c23a;
+	flex-shrink: 0;
+}
+
+// 概览卡片
+.overview-card {
+	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+	color: white;
+
+	:deep(.el-card__header) {
+		background: rgba(255, 255, 255, 0.1);
+		border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+		color: white;
+	}
+}
+
+.overview-content {
+	display: flex;
+	justify-content: space-around;
+	flex-wrap: wrap;
+	gap: 20px;
+}
+
+.overview-item {
+	display: flex;
+	align-items: center;
+	gap: 16px;
+	min-width: 200px;
+	flex: 1;
+	min-height: 80px;
+	max-height: 103px;
+}
+
+.overview-icon {
+	width: 60px;
+	height: 60px;
+	border-radius: 50%;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	font-size: 24px;
+	background: rgba(255, 255, 255, 0.2);
+	flex-shrink: 0;
+}
+
+.overview-text {
+	flex: 1;
+	min-width: 0;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	min-height: 72px;
+	max-height: 95px;
+
+	.overview-title {
+		font-size: 14px;
+		opacity: 0.8;
+		margin-bottom: 4px;
+		line-height: 1.2;
+		height: 17px;
+		display: flex;
+		align-items: center;
+	}
+
+	.overview-value {
+		font-size: 18px;
+		font-weight: 600;
+		margin-bottom: 4px;
+		word-break: break-word;
+		line-height: 1.3;
+		min-height: 23px;
+		max-height: 46px;
+		display: -webkit-box;
+		-webkit-line-clamp: 2;
+		-webkit-box-orient: vertical;
+		overflow: hidden;
+		text-overflow: ellipsis;
+	}
+
+	.overview-subtitle {
+		font-size: 12px;
+		opacity: 0.7;
+		line-height: 1.2;
+		height: 15px;
+		display: flex;
+		align-items: center;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+	}
+}
+
+// 性能卡片
+.performance-card {
+	&.cpu-card {
+		border-left: 4px solid #e6a23c;
+	}
+
+	&.ram-card {
+		border-left: 4px solid #409eff;
+	}
+}
+
+.performance-content {
+	display: flex;
+	align-items: center;
+	gap: 24px;
+}
+
+.performance-chart {
+	flex-shrink: 0;
+}
+
+.progress-content {
+	text-align: center;
+
+	.progress-value {
+		font-size: 24px;
+		font-weight: 600;
+		color: #303133;
+	}
+
+	.progress-label {
+		font-size: 12px;
+		color: #909399;
+		margin-top: 4px;
+	}
+}
+
+.performance-details {
+	flex: 1;
+}
+
+.detail-item {
+	display: flex;
+	justify-content: space-between;
+	padding: 8px 0;
+	border-bottom: 1px solid #f0f0f0;
+
+	&:last-child {
+		border-bottom: none;
+	}
+}
+
+.detail-label {
+	color: #606266;
+	font-size: 14px;
+}
+
+.detail-value {
+	color: #303133;
+	font-weight: 500;
+	font-size: 14px;
+}
+
+// 磁盘卡片
+.disk-card {
+	border-left: 4px solid #67c23a;
+}
+
+.disk-item {
+	background: #f8f9fa;
+	border-radius: 8px;
+	padding: 16px;
+	margin-bottom: 16px;
+
+	&:last-child {
+		margin-bottom: 0;
+	}
+}
+
+.disk-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	margin-bottom: 16px;
+}
+
+.disk-name {
+	font-size: 18px;
+	font-weight: 600;
+	color: #303133;
+}
+
+.disk-type {
+	color: #909399;
+	font-size: 14px;
+}
+
+.disk-content {
+	display: flex;
+	align-items: center;
+	gap: 24px;
+}
+
+.disk-chart {
+	flex-shrink: 0;
+}
+
+.disk-progress-content {
+	text-align: center;
+
+	.disk-usage {
+		font-size: 16px;
+		font-weight: 600;
+		color: #303133;
+	}
+
+	.disk-label {
+		font-size: 12px;
+		color: #909399;
+	}
+}
+
+.disk-details {
+	flex: 1;
+}
+
+.disk-detail-item {
+	display: flex;
+	justify-content: space-between;
+	padding: 6px 0;
+	border-bottom: 1px solid #e4e7ed;
+
+	&:last-child {
+		border-bottom: none;
+	}
+}
+
+// GPU卡片
+.gpu-card {
+	border-left: 4px solid #f56c6c;
+}
+
+.gpu-item {
+	background: #f8f9fa;
+	border-radius: 8px;
+	padding: 16px;
+	margin-bottom: 16px;
+
+	&:last-child {
+		margin-bottom: 0;
+	}
+}
+
+.gpu-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	margin-bottom: 12px;
+}
+
+.gpu-name {
+	font-size: 16px;
+	font-weight: 600;
+	color: #303133;
+	flex: 1;
+	margin-right: 12px;
+}
+
+.gpu-details {
+	display: grid;
+	gap: 8px;
+}
+
+.gpu-detail-item {
+	display: flex;
+	justify-content: space-between;
+	padding: 4px 0;
+}
+
+// 网络卡片
+.network-card {
+	border-left: 4px solid #909399;
+}
+
+.network-title {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	width: 100%;
+	padding-right: 16px;
+}
+
+.network-status {
+	display: flex;
+	align-items: center;
+	gap: 8px;
+}
+
+.network-name {
+	font-weight: 500;
+}
+
+.network-status-up {
+	color: #67c23a;
+}
+
+.network-status-down {
+	color: #f56c6c;
+}
+
+.network-status-unknown {
+	color: #e6a23c;
+}
+
+.network-details {
+	padding: 16px 0;
+}
+
+.network-info {
+	.network-detail-item {
+		margin-bottom: 12px;
+
+		&:last-child {
+			margin-bottom: 0;
+		}
+	}
+}
+
+.ip-addresses {
+	margin-top: 4px;
+}
+
+.ip-tag {
+	margin-right: 8px;
+	margin-bottom: 4px;
+}
+
+.network-statistics {
+	h4 {
+		margin: 0 0 16px 0;
+		color: #303133;
+	}
+}
+
+.stats-grid {
+	display: grid;
+	grid-template-columns: 1fr 1fr;
+	gap: 12px;
+}
+
+.stat-item {
+	background: #f0f2f5;
+	padding: 12px;
+	border-radius: 6px;
+	text-align: center;
+}
+
+.stat-label {
+	font-size: 12px;
+	color: #909399;
+	margin-bottom: 4px;
+}
+
+.stat-value {
+	font-size: 14px;
+	font-weight: 600;
+	color: #303133;
+}
+
+// 主板卡片
+.board-card {
+	border-left: 4px solid #973399;
+}
+
+.board-content {
+	display: grid;
+	grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+	gap: 16px;
+}
+
+.board-item {
+	display: flex;
+	justify-content: space-between;
+	padding: 12px;
+	background: #f8f9fa;
+	border-radius: 6px;
+}
+
+// 系统信息卡片
+.system-card {
+	border-left: 4px solid #409eff;
+}
+
+.system-content {
+	display: grid;
+	grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+	gap: 16px;
+}
+
+.system-item {
+	display: flex;
+	justify-content: space-between;
+	padding: 12px;
+	background: #f8f9fa;
+	border-radius: 6px;
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+	.overview-content {
+		flex-direction: column;
+	}
+
+	.overview-item {
+		min-width: 100%;
+	}
+
+	.performance-content {
+		flex-direction: column;
+		text-align: center;
+	}
+
+	.disk-content {
+		flex-direction: column;
+		text-align: center;
+	}
+
+	.stats-grid {
+		grid-template-columns: 1fr;
+	}
+
+	.board-content {
+		grid-template-columns: 1fr;
+	}
+}
+
+// 动画效果
+.el-card {
+	transition:
+		transform 0.3s ease,
+		box-shadow 0.3s ease;
+
+	&:hover {
+		transform: translateY(-2px);
+		box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
+	}
+}
+
+.el-progress {
+	:deep(.el-progress__text) {
+		color: inherit !important;
+	}
+}
+
+:deep(.el-collapse-item__header) {
+	padding-left: 0;
+	padding-right: 16px;
+}
+
+:deep(.el-collapse-item__content) {
+	padding-bottom: 16px;
+}
+
+// NuGet包信息卡片样式
+.nuget-card {
+	border-left: 4px solid #409eff;
+	margin-top: 16px;
+}
+
+.nuget-content {
+	padding: 8px;
+	display: flex;
+	flex-wrap: wrap;
+	gap: 8px;
+}
+
+.package-item {
+	display: inline-block;
+	margin: 4px;
+	text-align: left;
+}
+
+.package-info {
+	display: inline-flex;
+	align-items: center;
+	gap: 4px;
+}
+
+.package-name {
+	font-family: 'Consolas', monospace;
+}
+
+.package-version {
+	color: #909399;
+	font-size: 9px;
+}
+
+:deep(.el-tag) {
+	--el-tag-bg-color: var(--el-color-primary-light-9);
+	--el-tag-border-color: var(--el-color-primary-light-8);
+	--el-tag-hover-color: var(--el-color-primary);
+
+	&:hover {
+		background-color: var(--el-color-primary-light-8);
+	}
+}
+</style>

+ 1 - 1
Web/src/views/system/weChatPay/index.vue

@@ -130,7 +130,7 @@
 	</div>
 </template>
 
-<script setup lang="ts" name="weChatPay">
+<script setup lang="ts" name="sysWechatPay">
 import { ref, nextTick, onMounted, reactive } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import QRCode from 'qrcodejs2-fixes';

+ 1 - 1
Web/src/views/system/weChatUser/index.vue

@@ -67,7 +67,7 @@
 	</div>
 </template>
 
-<script lang="ts" setup name="weChatUser">
+<script lang="ts" setup name="sysWechatUser">
 import { onMounted, reactive, ref } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import EditWeChatUser from '/@/views/system/weChatUser/component/editWeChatUser.vue';

+ 1 - 0
Web/vite.config.ts

@@ -16,6 +16,7 @@ const pathResolve = (dir: string) => {
 const alias: Record<string, string> = {
 	'/@': pathResolve('./src/'),
 	'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js',
+	'ezuikit-js': pathResolve('node_modules/ezuikit-js/ezuikit.js'), 
 };
 
 const viteConfig = defineConfig((mode: ConfigEnv) => {