From 285c285fa5d64839c8beea159e2d4561eb46c52b Mon Sep 17 00:00:00 2001 From: zuohuaijun Date: Mon, 22 Sep 2025 00:36:27 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=98=8E=E5=A2=9E=E5=8A=A0=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8=E8=87=AA=E5=AE=9A=E4=B9=89=E6=9F=A5=E8=AF=A2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Admin.NET.Core/Admin.NET.Core.csproj | 8 +- .../SeedData/SysMenuSeedData.cs | 11 +- .../Service/DataBase/Dto/GenerateSQLInput.cs | 43 ++ .../Service/DataBase/SysDatabaseService.cs | 315 +++++++----- .../Admin.NET.Test/Admin.NET.Test.csproj | 4 +- Web/package.json | 14 +- .../system/apis/sys-database-api.ts | 169 +++++++ .../api-services/system/models/columns-sql.ts | 34 ++ .../system/models/conditions-sql.ts | 46 ++ .../system/models/generate-sqlinput.ts | 43 ++ Web/src/api-services/system/models/index.ts | 4 + .../api-services/system/models/orders-sql.ts | 40 ++ .../views/system/reportCustomQuery/index.vue | 451 ++++++++++++++++++ 13 files changed, 1042 insertions(+), 140 deletions(-) create mode 100644 Admin.NET/Admin.NET.Core/Service/DataBase/Dto/GenerateSQLInput.cs create mode 100644 Web/src/api-services/system/models/columns-sql.ts create mode 100644 Web/src/api-services/system/models/conditions-sql.ts create mode 100644 Web/src/api-services/system/models/generate-sqlinput.ts create mode 100644 Web/src/api-services/system/models/orders-sql.ts create mode 100644 Web/src/views/system/reportCustomQuery/index.vue diff --git a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj index 84f8e1bf..11f59527 100644 --- a/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj +++ b/Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj @@ -28,10 +28,10 @@ - - - - + + + + diff --git a/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs b/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs index 98bf5792..557d7cf9 100644 --- a/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs +++ b/Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs @@ -224,17 +224,18 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData new SysMenu{ Id=1310000000651, Pid=1310000000601, Title="接口压测", Path="/develop/stressTest", Name="sysStressTest", Component="/system/stressTest/index", Icon="ele-Compass", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2024-12-28 00:00:00"), OrderNo=150 }, new SysMenu{ Id=1310000000701, Pid=0, Title="报表开发", Path="/report", Name="report", Component="Layout", Icon="ele-Histogram", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=14000 }, - new SysMenu{ Id=1310000000711, Pid=1310000000701, Title="数据源配置", Path="/report/reportDataSource", Name="sysReportDataSource", Component="/system/reportDataSource/index", Icon="ele-Filter", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, + new SysMenu{ Id=1310000000711, Pid=1310000000701, Title="数据源配置", Path="/report/reportDataSource", Name="sysReportDataSource", Component="/system/reportDataSource/index", Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000712, Pid=1310000000711, Title="查询", Permission="sysReportDataSource/page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000713, Pid=1310000000711, Title="编辑", Permission="sysReportDataSource/update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000714, Pid=1310000000711, Title="增加", Permission="sysReportDataSource/add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000715, Pid=1310000000711, Title="删除", Permission="sysReportDataSource/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000716, Pid=1310000000711, Title="复制", Permission="sysReportDataSource/copy", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, new SysMenu{ Id=1310000000721, Pid=1310000000701, Title="报表配置", Path="/report/reportConfig", Name="sysReportConfig", Component="/system/reportConfig/index", Icon="ele-Document", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 }, - new SysMenu{ Id=1310000000731, Pid=1310000000721, Title="查询", Permission="sysReportConfig/page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, - new SysMenu{ Id=1310000000741, Pid=1310000000721, Title="编辑", Permission="sysReportConfig/update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, - new SysMenu{ Id=1310000000751, Pid=1310000000721, Title="增加", Permission="sysReportConfig/add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, - new SysMenu{ Id=1310000000761, Pid=1310000000721, Title="删除", Permission="sysReportConfig/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, + new SysMenu{ Id=1310000000722, Pid=1310000000721, Title="查询", Permission="sysReportConfig/page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, + new SysMenu{ Id=1310000000723, Pid=1310000000721, Title="编辑", Permission="sysReportConfig/update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, + new SysMenu{ Id=1310000000724, Pid=1310000000721, Title="增加", Permission="sysReportConfig/add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, + new SysMenu{ Id=1310000000725, Pid=1310000000721, Title="删除", Permission="sysReportConfig/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, + new SysMenu{ Id=1310000000731, Pid=1310000000701, Title="自定义查询", Path="/report/reportCustomQuery", Name="sysReportCustomQuery", Component="/system/reportCustomQuery/index", Icon="ele-DocumentCopy", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 }, new SysMenu{ Id=1320000000101, Pid=0, Title="帮助文档", Path="/doc", Name="doc", Component="Layout", Icon="ele-Notebook", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=15000 }, new SysMenu{ Id=1320000000111, Pid=1320000000101, Title="框架教程", Path="/doc/admin", Name="sysAdmin", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://adminnet.top/", Icon="ele-Guide", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, diff --git a/Admin.NET/Admin.NET.Core/Service/DataBase/Dto/GenerateSQLInput.cs b/Admin.NET/Admin.NET.Core/Service/DataBase/Dto/GenerateSQLInput.cs new file mode 100644 index 00000000..e17737fb --- /dev/null +++ b/Admin.NET/Admin.NET.Core/Service/DataBase/Dto/GenerateSQLInput.cs @@ -0,0 +1,43 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Core.Service; + +public class GenerateSQLInput +{ + public List Columns { get; set; } + + public List Conditions { get; set; } + + public List Orders { get; set; } +} + +public class ColumnsSQL +{ + public string Table { get; set; } + + public string Column { get; set; } +} + +public class ConditionsSQL +{ + public string Table { get; set; } + + public string Column { get; set; } + + public string Operator { get; set; } + + public string Value { get; set; } +} + +public class OrdersSQL +{ + public string Table { get; set; } + + public string Column { get; set; } + + public int Sort { get; set; } +} \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs b/Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs index fb41d18c..c5cfe322 100644 --- a/Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs +++ b/Admin.NET/Admin.NET.Core/Service/DataBase/SysDatabaseService.cs @@ -33,116 +33,6 @@ public class SysDatabaseService : IDynamicApiController, ITransient _codeGenStrategyFactory = codeGenStrategyFactory; } - /// - /// 获取库列表 🔖 - /// - /// - [DisplayName("获取库列表")] - public List GetList() - { - var dbOutputs = new List(); - var configIds = App.GetOptions().ConnectionConfigs.Select(u => u.ConfigId.ToString()).ToList(); - foreach (var config in configIds) - { - var db = _db.AsTenant().GetConnectionScope(config); - dbOutputs.Add(new DbOutput - { - ConfigId = config, - DbName = db.Ado.Connection.Database - }); - } - return dbOutputs; - } - - /// - /// 获取可视化库表结构 🔖 - /// - /// - [DisplayName("获取可视化库表结构")] - public VisualDbTable GetVisualDbTable() - { - var visualTableList = new List(); - var visualColumnList = new List(); - var columnRelationList = new List(); - var dbOptions = App.GetOptions().ConnectionConfigs.First(u => u.ConfigId.ToString() == SqlSugarConst.MainConfigId); - - // 遍历所有实体获取所有库表结构 - var random = new Random(); - var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)).ToList(); - foreach (var entityType in entityTypes) - { - var entityInfo = _db.EntityMaintenance.GetEntityInfoNoCache(entityType); - - var visualTable = new VisualTable - { - TableName = entityInfo.DbTableName, - TableComents = entityInfo.TableDescription + entityInfo.DbTableName, - X = random.Next(5000), - Y = random.Next(5000) - }; - visualTableList.Add(visualTable); - - foreach (EntityColumnInfo columnInfo in entityInfo.Columns) - { - var visualColumn = new VisualColumn - { - TableName = columnInfo.DbTableName, - ColumnName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(columnInfo.DbColumnName) : columnInfo.DbColumnName, - DataType = columnInfo.PropertyInfo.PropertyType.Name, - DataLength = columnInfo.Length.ToString(), - ColumnDescription = columnInfo.ColumnDescription, - }; - visualColumnList.Add(visualColumn); - - // 根据导航配置获取表之间关联关系 - if (columnInfo.Navigat != null) - { - var name1 = columnInfo.Navigat.GetName(); - var name2 = columnInfo.Navigat.GetName2(); - var targetColumnName = string.IsNullOrEmpty(name2) ? "Id" : name2; - var relation = new ColumnRelation - { - SourceTableName = columnInfo.DbTableName, - SourceColumnName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(name1) : name1, - Type = columnInfo.Navigat.GetNavigateType() == NavigateType.OneToOne ? "ONE_TO_ONE" : "ONE_TO_MANY", - TargetTableName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(columnInfo.DbColumnName) : columnInfo.DbColumnName, - TargetColumnName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(targetColumnName) : targetColumnName - }; - columnRelationList.Add(relation); - } - } - } - - return new VisualDbTable { VisualTableList = visualTableList, VisualColumnList = visualColumnList, ColumnRelationList = columnRelationList }; - } - - /// - /// 获取字段列表 🔖 - /// - /// 表名 - /// ConfigId - /// - [DisplayName("获取字段列表")] - public List GetColumnList(string tableName, string configId = SqlSugarConst.MainConfigId) - { - if (string.IsNullOrWhiteSpace(tableName)) return []; - - var db = _db.AsTenant().GetConnectionScope(configId); - return db.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt>(); - } - - /// - /// 获取数据库数据类型列表 🔖 - /// - /// - /// - [DisplayName("获取数据库数据类型列表")] - public List GetDbTypeList(string configId = SqlSugarConst.MainConfigId) - { - var db = _db.AsTenant().GetConnectionScope(configId); - return db.DbMaintenance.GetDbTypes().OrderBy(u => u).ToList(); - } - /// /// 增加列 🔖 /// @@ -276,18 +166,6 @@ public class SysDatabaseService : IDynamicApiController, ITransient db.Ado.ExecuteCommand(sql.ToString()); } - /// - /// 获取表列表 🔖 - /// - /// ConfigId - /// - [DisplayName("获取表列表")] - public List GetTableList(string configId = SqlSugarConst.MainConfigId) - { - var db = _db.AsTenant().GetConnectionScope(configId); - return db.DbMaintenance.GetTableInfoList(false); - } - /// /// 增加表 🔖 /// @@ -360,6 +238,128 @@ public class SysDatabaseService : IDynamicApiController, ITransient } } + /// + /// 获取库列表 🔖 + /// + /// + [DisplayName("获取库列表")] + public List GetList() + { + var dbOutputs = new List(); + var configIds = App.GetOptions().ConnectionConfigs.Select(u => u.ConfigId.ToString()).ToList(); + foreach (var config in configIds) + { + var db = _db.AsTenant().GetConnectionScope(config); + dbOutputs.Add(new DbOutput + { + ConfigId = config, + DbName = db.Ado.Connection.Database + }); + } + return dbOutputs; + } + + /// + /// 获取表列表 🔖 + /// + /// ConfigId + /// + [DisplayName("获取表列表")] + public List GetTableList(string configId = SqlSugarConst.MainConfigId) + { + var db = _db.AsTenant().GetConnectionScope(configId); + return db.DbMaintenance.GetTableInfoList(false); + } + + /// + /// 获取字段列表 🔖 + /// + /// 表名 + /// ConfigId + /// + [DisplayName("获取字段列表")] + public List GetColumnList(string tableName, string configId = SqlSugarConst.MainConfigId) + { + if (string.IsNullOrWhiteSpace(tableName)) return []; + + var db = _db.AsTenant().GetConnectionScope(configId); + return db.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt>(); + } + + /// + /// 获取数据库数据类型列表 🔖 + /// + /// + /// + [DisplayName("获取数据库数据类型列表")] + public List GetDbTypeList(string configId = SqlSugarConst.MainConfigId) + { + var db = _db.AsTenant().GetConnectionScope(configId); + return db.DbMaintenance.GetDbTypes().OrderBy(u => u).ToList(); + } + + /// + /// 获取可视化库表结构 🔖 + /// + /// + [DisplayName("获取可视化库表结构")] + public VisualDbTable GetVisualDbTable() + { + var visualTableList = new List(); + var visualColumnList = new List(); + var columnRelationList = new List(); + var dbOptions = App.GetOptions().ConnectionConfigs.First(u => u.ConfigId.ToString() == SqlSugarConst.MainConfigId); + + // 遍历所有实体获取所有库表结构 + var random = new Random(); + var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)).ToList(); + foreach (var entityType in entityTypes) + { + var entityInfo = _db.EntityMaintenance.GetEntityInfoNoCache(entityType); + + var visualTable = new VisualTable + { + TableName = entityInfo.DbTableName, + TableComents = entityInfo.TableDescription + entityInfo.DbTableName, + X = random.Next(5000), + Y = random.Next(5000) + }; + visualTableList.Add(visualTable); + + foreach (EntityColumnInfo columnInfo in entityInfo.Columns) + { + var visualColumn = new VisualColumn + { + TableName = columnInfo.DbTableName, + ColumnName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(columnInfo.DbColumnName) : columnInfo.DbColumnName, + DataType = columnInfo.PropertyInfo.PropertyType.Name, + DataLength = columnInfo.Length.ToString(), + ColumnDescription = columnInfo.ColumnDescription, + }; + visualColumnList.Add(visualColumn); + + // 根据导航配置获取表之间关联关系 + if (columnInfo.Navigat != null) + { + var name1 = columnInfo.Navigat.GetName(); + var name2 = columnInfo.Navigat.GetName2(); + var targetColumnName = string.IsNullOrEmpty(name2) ? "Id" : name2; + var relation = new ColumnRelation + { + SourceTableName = columnInfo.DbTableName, + SourceColumnName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(name1) : name1, + Type = columnInfo.Navigat.GetNavigateType() == NavigateType.OneToOne ? "ONE_TO_ONE" : "ONE_TO_MANY", + TargetTableName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(columnInfo.DbColumnName) : columnInfo.DbColumnName, + TargetColumnName = dbOptions.DbSettings.EnableUnderLine ? UtilMethods.ToUnderLine(targetColumnName) : targetColumnName + }; + columnRelationList.Add(relation); + } + } + } + + return new VisualDbTable { VisualTableList = visualTableList, VisualColumnList = visualColumnList, ColumnRelationList = columnRelationList }; + } + /// /// 创建实体 🔖 /// @@ -622,4 +622,75 @@ public class SysDatabaseService : IDynamicApiController, ITransient FileDownloadName = backupFileName }; } + + /// + /// 生成SQL语句 🔖 + /// + /// + /// + [DisplayName("生成SQL语句")] + public async Task GenerateSQL(GenerateSQLInput input) + { + if (input.Columns == null || input.Columns.Count <= 0) throw Oops.Oh("至少需要设置一个列"); + + // 收集所有表名(从columns、conditions、orders中) + var tableNames = new HashSet(); + foreach (var col in input.Columns) + tableNames.Add(col.Table); + foreach (var cond in input.Conditions) + tableNames.Add(cond.Table); + foreach (var ord in input.Orders) + tableNames.Add(ord.Table); + if (tableNames == null || tableNames.Count == 0) + throw Oops.Oh("至少需要一个表"); + + // 构建 SELECT 子句 + var selectItems = input.Columns.Select(u => $"{u.Table}.{u.Column}"); + var selectString = "SELECT " + string.Join(", ", selectItems); + + // 构建 FROM 子句 + var fromString = "FROM " + string.Join(", ", tableNames); + + // 组合SQL语句 + var sql = new StringBuilder(); + sql.Append(selectString); + sql.Append(" "); + sql.Append(fromString); + if (input.Conditions != null && input.Conditions.Count > 0) + { + // 构建WHERE子句 + var whereConditions = input.Conditions.Where(u => !string.IsNullOrWhiteSpace(u.Table) && !string.IsNullOrWhiteSpace(u.Column)).Select(u => + { + var valueStr = u.Value is string ? $"'{u.Value}'" : u.Value.ToString(); // 处理值:如果是字符串则需要加单引号 + return $"{u.Table}.{u.Column} {u.Operator} {valueStr}"; + }); + var whereString = "WHERE " + string.Join(" AND ", whereConditions); + + sql.Append(" "); + sql.Append(whereString); + } + if (input.Orders != null && input.Orders.Count > 0) + { + // 构建 ORDER BY 子句 + var orderItems = input.Orders.OrderBy(u => u.Sort).Where(u => !string.IsNullOrWhiteSpace(u.Table) && !string.IsNullOrWhiteSpace(u.Column)).Select(u => $"{u.Table}.{u.Column} ASC"); // 按照sort值从小到大排序,确定列的先后顺序 + var orderByString = "ORDER BY " + string.Join(", ", orderItems); + + sql.Append(" "); + sql.Append(orderByString); + } + return await Task.FromResult(sql.ToString()); + } + + /// + /// 执行SQL语句 🔖 + /// + /// + /// + [DisplayName("执行SQL语句")] + public async Task ExecuteSQL(GenerateSQLInput input) + { + var sql = await GenerateSQL(input); + var dt = _db.Ado.GetDataTable(sql); + return dt; + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Test/Admin.NET.Test.csproj b/Admin.NET/Admin.NET.Test/Admin.NET.Test.csproj index 612d79c1..75b31960 100644 --- a/Admin.NET/Admin.NET.Test/Admin.NET.Test.csproj +++ b/Admin.NET/Admin.NET.Test/Admin.NET.Test.csproj @@ -14,8 +14,8 @@ - - + + compile diff --git a/Web/package.json b/Web/package.json index ed1c9791..06145c20 100644 --- a/Web/package.json +++ b/Web/package.json @@ -2,7 +2,7 @@ "name": "admin.net.pro", "type": "module", "version": "2.4.33", - "lastBuildTime": "2025.09.19", + "lastBuildTime": "2025.09.22", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "author": "zuohuaijun", "license": "MIT", @@ -39,7 +39,7 @@ "cropperjs": "^1.6.2", "crypto-js": "^4.2.0", "echarts": "^6.0.0", - "element-plus": "^2.11.2", + "element-plus": "^2.11.3", "exceljs": "^4.4.0", "flag-icons": "^7.5.0", "franc": "^6.2.0", @@ -81,8 +81,8 @@ "vue-router": "^4.5.1", "vue-signature-pad": "^3.0.2", "vue3-tree-org": "^4.2.2", - "vxe-pc-ui": "^4.9.32", - "vxe-table": "^4.16.14", + "vxe-pc-ui": "^4.9.34", + "vxe-table": "^4.16.16", "xe-utils": "^3.7.9", "xlsx-js-style": "^1.2.0" }, @@ -90,7 +90,7 @@ "@iconify/vue": "^5.0.0", "@plugin-web-update-notification/vite": "^2.0.2", "@types/lodash-es": "^4.17.12", - "@types/node": "^22.18.5", + "@types/node": "^22.18.6", "@types/nprogress": "^0.2.3", "@types/sortablejs": "^1.15.8", "@typescript-eslint/eslint-plugin": "^8.44.0", @@ -102,13 +102,13 @@ "code-inspector-plugin": "^1.2.10", "colors": "^1.4.0", "dotenv": "^17.2.1", - "eslint": "^9.35.0", + "eslint": "^9.36.0", "eslint-plugin-vue": "^10.4.0", "globals": "^16.4.0", "less": "^4.4.1", "prettier": "^3.6.2", "rollup-plugin-visualizer": "^6.0.3", - "sass": "^1.92.1", + "sass": "^1.93.0", "terser": "^5.44.0", "typescript": "^5.9.2", "vite": "^7.1.6", diff --git a/Web/src/api-services/system/apis/sys-database-api.ts b/Web/src/api-services/system/apis/sys-database-api.ts index 76933671..7e98f2b0 100644 --- a/Web/src/api-services/system/apis/sys-database-api.ts +++ b/Web/src/api-services/system/apis/sys-database-api.ts @@ -17,11 +17,13 @@ import { Configuration } from '../configuration'; // Some imports not used depending on template conditions // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base'; +import { AdminNETResultDataTable } from '../models'; import { AdminNETResultListDataInitItemOutput } from '../models'; import { AdminNETResultListDbColumnOutput } from '../models'; import { AdminNETResultListDbOutput } from '../models'; import { AdminNETResultListDbTableInfo } from '../models'; import { AdminNETResultListString } from '../models'; +import { AdminNETResultString } from '../models'; import { AdminNETResultTemplateContextOutput } from '../models'; import { AdminNETResultVisualDbTable } from '../models'; import { CreateEntityInput } from '../models'; @@ -30,6 +32,7 @@ import { DbColumnInput } from '../models'; import { DbTableInput } from '../models'; import { DeleteDbColumnInput } from '../models'; import { DeleteDbTableInput } from '../models'; +import { GenerateSQLInput } from '../models'; import { InitSeedDataInput } from '../models'; import { InitTableInput } from '../models'; import { MoveDbColumnInput } from '../models'; @@ -476,6 +479,54 @@ export const SysDatabaseApiAxiosParamCreator = function (configuration?: Configu options: localVarRequestOptions, }; }, + /** + * + * @summary 执行SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + apiSysDatabaseExecuteSQLPost: async (body?: GenerateSQLInput, options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/sysDatabase/executeSQL`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, 'https://example.com'); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + // http bearer authentication required + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + localVarHeaderParameter["Authorization"] = "Bearer " + accessToken; + } + + localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + + const query = new URLSearchParams(localVarUrlObj.search); + for (const key in localVarQueryParameter) { + query.set(key, localVarQueryParameter[key]); + } + for (const key in options.params) { + query.set(key, options.params[key]); + } + localVarUrlObj.search = (new URLSearchParams(query)).toString(); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || ""); + + return { + url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, + options: localVarRequestOptions, + }; + }, /** * * @summary 创建实体文件内容 @@ -524,6 +575,54 @@ export const SysDatabaseApiAxiosParamCreator = function (configuration?: Configu options: localVarRequestOptions, }; }, + /** + * + * @summary 生成SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + apiSysDatabaseGenerateSQLPost: async (body?: GenerateSQLInput, options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/sysDatabase/generateSQL`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, 'https://example.com'); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + // http bearer authentication required + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + localVarHeaderParameter["Authorization"] = "Bearer " + accessToken; + } + + localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + + const query = new URLSearchParams(localVarUrlObj.search); + for (const key in localVarQueryParameter) { + query.set(key, localVarQueryParameter[key]); + } + for (const key in options.params) { + query.set(key, options.params[key]); + } + localVarUrlObj.search = (new URLSearchParams(query)).toString(); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || ""); + + return { + url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, + options: localVarRequestOptions, + }; + }, /** * * @summary 初始化种子数据 🔖 @@ -1082,6 +1181,20 @@ export const SysDatabaseApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, + /** + * + * @summary 执行SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysDatabaseExecuteSQLPost(body?: GenerateSQLInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { + const localVarAxiosArgs = await SysDatabaseApiAxiosParamCreator(configuration).apiSysDatabaseExecuteSQLPost(body, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; + return axios.request(axiosRequestArgs); + }; + }, /** * * @summary 创建实体文件内容 @@ -1096,6 +1209,20 @@ export const SysDatabaseApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, + /** + * + * @summary 生成SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysDatabaseGenerateSQLPost(body?: GenerateSQLInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { + const localVarAxiosArgs = await SysDatabaseApiAxiosParamCreator(configuration).apiSysDatabaseGenerateSQLPost(body, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; + return axios.request(axiosRequestArgs); + }; + }, /** * * @summary 初始化种子数据 🔖 @@ -1319,6 +1446,16 @@ export const SysDatabaseApiFactory = function (configuration?: Configuration, ba async apiSysDatabaseDeleteTablePost(body?: DeleteDbTableInput, options?: AxiosRequestConfig): Promise> { return SysDatabaseApiFp(configuration).apiSysDatabaseDeleteTablePost(body, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary 执行SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysDatabaseExecuteSQLPost(body?: GenerateSQLInput, options?: AxiosRequestConfig): Promise> { + return SysDatabaseApiFp(configuration).apiSysDatabaseExecuteSQLPost(body, options).then((request) => request(axios, basePath)); + }, /** * * @summary 创建实体文件内容 @@ -1329,6 +1466,16 @@ export const SysDatabaseApiFactory = function (configuration?: Configuration, ba async apiSysDatabaseGenerateEntityPost(body?: CreateEntityInput, options?: AxiosRequestConfig): Promise> { return SysDatabaseApiFp(configuration).apiSysDatabaseGenerateEntityPost(body, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary 生成SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysDatabaseGenerateSQLPost(body?: GenerateSQLInput, options?: AxiosRequestConfig): Promise> { + return SysDatabaseApiFp(configuration).apiSysDatabaseGenerateSQLPost(body, options).then((request) => request(axios, basePath)); + }, /** * * @summary 初始化种子数据 🔖 @@ -1526,6 +1673,17 @@ export class SysDatabaseApi extends BaseAPI { public async apiSysDatabaseDeleteTablePost(body?: DeleteDbTableInput, options?: AxiosRequestConfig) : Promise> { return SysDatabaseApiFp(this.configuration).apiSysDatabaseDeleteTablePost(body, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary 执行SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SysDatabaseApi + */ + public async apiSysDatabaseExecuteSQLPost(body?: GenerateSQLInput, options?: AxiosRequestConfig) : Promise> { + return SysDatabaseApiFp(this.configuration).apiSysDatabaseExecuteSQLPost(body, options).then((request) => request(this.axios, this.basePath)); + } /** * * @summary 创建实体文件内容 @@ -1537,6 +1695,17 @@ export class SysDatabaseApi extends BaseAPI { public async apiSysDatabaseGenerateEntityPost(body?: CreateEntityInput, options?: AxiosRequestConfig) : Promise> { return SysDatabaseApiFp(this.configuration).apiSysDatabaseGenerateEntityPost(body, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary 生成SQL语句 🔖 + * @param {GenerateSQLInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SysDatabaseApi + */ + public async apiSysDatabaseGenerateSQLPost(body?: GenerateSQLInput, options?: AxiosRequestConfig) : Promise> { + return SysDatabaseApiFp(this.configuration).apiSysDatabaseGenerateSQLPost(body, options).then((request) => request(this.axios, this.basePath)); + } /** * * @summary 初始化种子数据 🔖 diff --git a/Web/src/api-services/system/models/columns-sql.ts b/Web/src/api-services/system/models/columns-sql.ts new file mode 100644 index 00000000..846a95ed --- /dev/null +++ b/Web/src/api-services/system/models/columns-sql.ts @@ -0,0 +1,34 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * OpenAPI spec version: 1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + /** + * + * + * @export + * @interface ColumnsSQL + */ +export interface ColumnsSQL { + + /** + * @type {string} + * @memberof ColumnsSQL + */ + table?: string | null; + + /** + * @type {string} + * @memberof ColumnsSQL + */ + column?: string | null; +} diff --git a/Web/src/api-services/system/models/conditions-sql.ts b/Web/src/api-services/system/models/conditions-sql.ts new file mode 100644 index 00000000..f7657cb6 --- /dev/null +++ b/Web/src/api-services/system/models/conditions-sql.ts @@ -0,0 +1,46 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * OpenAPI spec version: 1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + /** + * + * + * @export + * @interface ConditionsSQL + */ +export interface ConditionsSQL { + + /** + * @type {string} + * @memberof ConditionsSQL + */ + table?: string | null; + + /** + * @type {string} + * @memberof ConditionsSQL + */ + column?: string | null; + + /** + * @type {string} + * @memberof ConditionsSQL + */ + operator?: string | null; + + /** + * @type {string} + * @memberof ConditionsSQL + */ + value?: string | null; +} diff --git a/Web/src/api-services/system/models/generate-sqlinput.ts b/Web/src/api-services/system/models/generate-sqlinput.ts new file mode 100644 index 00000000..0fb63923 --- /dev/null +++ b/Web/src/api-services/system/models/generate-sqlinput.ts @@ -0,0 +1,43 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * OpenAPI spec version: 1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +import { ColumnsSQL } from './columns-sql'; +import { ConditionsSQL } from './conditions-sql'; +import { OrdersSQL } from './orders-sql'; + /** + * + * + * @export + * @interface GenerateSQLInput + */ +export interface GenerateSQLInput { + + /** + * @type {Array} + * @memberof GenerateSQLInput + */ + columns?: Array | null; + + /** + * @type {Array} + * @memberof GenerateSQLInput + */ + conditions?: Array | null; + + /** + * @type {Array} + * @memberof GenerateSQLInput + */ + orders?: Array | null; +} diff --git a/Web/src/api-services/system/models/index.ts b/Web/src/api-services/system/models/index.ts index 11760ab4..6c27238f 100644 --- a/Web/src/api-services/system/models/index.ts +++ b/Web/src/api-services/system/models/index.ts @@ -188,7 +188,9 @@ export * from './code-gen-scene-enum'; export * from './column-custom-output'; export * from './column-output'; export * from './column-relation'; +export * from './columns-sql'; export * from './compare-info'; +export * from './conditions-sql'; export * from './const-output'; export * from './constructor-info'; export * from './copy-role-input'; @@ -278,6 +280,7 @@ export * from './gender-enum'; export * from './generate-qrimage-input'; export * from './generate-qrimage-output'; export * from './generate-qrimage-un-limit-input'; +export * from './generate-sqlinput'; export * from './generate-signature-input'; export * from './generate-signature-output'; export * from './generic-parameter-attributes'; @@ -352,6 +355,7 @@ export * from './oauth-user-output'; export * from './online-user'; export * from './open-access-output'; export * from './order-by-type'; +export * from './orders-sql'; export * from './page-code-gen-input'; export * from './page-config-input'; export * from './page-dict-data-input'; diff --git a/Web/src/api-services/system/models/orders-sql.ts b/Web/src/api-services/system/models/orders-sql.ts new file mode 100644 index 00000000..b6288f06 --- /dev/null +++ b/Web/src/api-services/system/models/orders-sql.ts @@ -0,0 +1,40 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * OpenAPI spec version: 1.0.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + /** + * + * + * @export + * @interface OrdersSQL + */ +export interface OrdersSQL { + + /** + * @type {string} + * @memberof OrdersSQL + */ + table?: string | null; + + /** + * @type {string} + * @memberof OrdersSQL + */ + column?: string | null; + + /** + * @type {number} + * @memberof OrdersSQL + */ + sort?: number; +} diff --git a/Web/src/views/system/reportCustomQuery/index.vue b/Web/src/views/system/reportCustomQuery/index.vue new file mode 100644 index 00000000..ff8ab446 --- /dev/null +++ b/Web/src/views/system/reportCustomQuery/index.vue @@ -0,0 +1,451 @@ + + + + + +