😎增加报表自定义查询功能
This commit is contained in:
parent
081e1c4b8e
commit
285c285fa5
@ -28,10 +28,10 @@
|
|||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" Aliases="BouncyCastleV2" />
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" Aliases="BouncyCastleV2" />
|
||||||
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.1.7" />
|
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.1.7" />
|
||||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.125" />
|
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.126" />
|
||||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.125" />
|
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.126" />
|
||||||
<PackageReference Include="Furion.Pure" Version="4.9.7.125" />
|
<PackageReference Include="Furion.Pure" Version="4.9.7.126" />
|
||||||
<PackageReference Include="Hardware.Info" Version="101.0.1.1" />
|
<PackageReference Include="Hardware.Info" Version="101.1.0" />
|
||||||
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
||||||
<PackageReference Include="IPTools.China" Version="1.6.0" />
|
<PackageReference Include="IPTools.China" Version="1.6.0" />
|
||||||
<PackageReference Include="IPTools.International" Version="1.6.0" />
|
<PackageReference Include="IPTools.International" Version="1.6.0" />
|
||||||
|
|||||||
@ -224,17 +224,18 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
|||||||
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=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=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=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=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=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=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=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=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=1310000000722, 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=1310000000723, 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=1310000000724, 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=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=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 },
|
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 },
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||||
|
//
|
||||||
|
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||||
|
//
|
||||||
|
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||||
|
|
||||||
|
namespace Admin.NET.Core.Service;
|
||||||
|
|
||||||
|
public class GenerateSQLInput
|
||||||
|
{
|
||||||
|
public List<ColumnsSQL> Columns { get; set; }
|
||||||
|
|
||||||
|
public List<ConditionsSQL> Conditions { get; set; }
|
||||||
|
|
||||||
|
public List<OrdersSQL> 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; }
|
||||||
|
}
|
||||||
@ -33,116 +33,6 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
|||||||
_codeGenStrategyFactory = codeGenStrategyFactory;
|
_codeGenStrategyFactory = codeGenStrategyFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取库列表 🔖
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DisplayName("获取库列表")]
|
|
||||||
public List<DbOutput> GetList()
|
|
||||||
{
|
|
||||||
var dbOutputs = new List<DbOutput>();
|
|
||||||
var configIds = App.GetOptions<DbConnectionOptions>().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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取可视化库表结构 🔖
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DisplayName("获取可视化库表结构")]
|
|
||||||
public VisualDbTable GetVisualDbTable()
|
|
||||||
{
|
|
||||||
var visualTableList = new List<VisualTable>();
|
|
||||||
var visualColumnList = new List<VisualColumn>();
|
|
||||||
var columnRelationList = new List<ColumnRelation>();
|
|
||||||
var dbOptions = App.GetOptions<DbConnectionOptions>().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 };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取字段列表 🔖
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName">表名</param>
|
|
||||||
/// <param name="configId">ConfigId</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DisplayName("获取字段列表")]
|
|
||||||
public List<DbColumnOutput> 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<List<DbColumnOutput>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取数据库数据类型列表 🔖
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DisplayName("获取数据库数据类型列表")]
|
|
||||||
public List<string> GetDbTypeList(string configId = SqlSugarConst.MainConfigId)
|
|
||||||
{
|
|
||||||
var db = _db.AsTenant().GetConnectionScope(configId);
|
|
||||||
return db.DbMaintenance.GetDbTypes().OrderBy(u => u).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加列 🔖
|
/// 增加列 🔖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -276,18 +166,6 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
|||||||
db.Ado.ExecuteCommand(sql.ToString());
|
db.Ado.ExecuteCommand(sql.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取表列表 🔖
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configId">ConfigId</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DisplayName("获取表列表")]
|
|
||||||
public List<DbTableInfo> GetTableList(string configId = SqlSugarConst.MainConfigId)
|
|
||||||
{
|
|
||||||
var db = _db.AsTenant().GetConnectionScope(configId);
|
|
||||||
return db.DbMaintenance.GetTableInfoList(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加表 🔖
|
/// 增加表 🔖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -360,6 +238,128 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取库列表 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("获取库列表")]
|
||||||
|
public List<DbOutput> GetList()
|
||||||
|
{
|
||||||
|
var dbOutputs = new List<DbOutput>();
|
||||||
|
var configIds = App.GetOptions<DbConnectionOptions>().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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取表列表 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configId">ConfigId</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("获取表列表")]
|
||||||
|
public List<DbTableInfo> GetTableList(string configId = SqlSugarConst.MainConfigId)
|
||||||
|
{
|
||||||
|
var db = _db.AsTenant().GetConnectionScope(configId);
|
||||||
|
return db.DbMaintenance.GetTableInfoList(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取字段列表 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tableName">表名</param>
|
||||||
|
/// <param name="configId">ConfigId</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("获取字段列表")]
|
||||||
|
public List<DbColumnOutput> 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<List<DbColumnOutput>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据库数据类型列表 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("获取数据库数据类型列表")]
|
||||||
|
public List<string> GetDbTypeList(string configId = SqlSugarConst.MainConfigId)
|
||||||
|
{
|
||||||
|
var db = _db.AsTenant().GetConnectionScope(configId);
|
||||||
|
return db.DbMaintenance.GetDbTypes().OrderBy(u => u).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取可视化库表结构 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("获取可视化库表结构")]
|
||||||
|
public VisualDbTable GetVisualDbTable()
|
||||||
|
{
|
||||||
|
var visualTableList = new List<VisualTable>();
|
||||||
|
var visualColumnList = new List<VisualColumn>();
|
||||||
|
var columnRelationList = new List<ColumnRelation>();
|
||||||
|
var dbOptions = App.GetOptions<DbConnectionOptions>().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 };
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建实体 🔖
|
/// 创建实体 🔖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -622,4 +622,75 @@ public class SysDatabaseService : IDynamicApiController, ITransient
|
|||||||
FileDownloadName = backupFileName
|
FileDownloadName = backupFileName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成SQL语句 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("生成SQL语句")]
|
||||||
|
public async Task<string> GenerateSQL(GenerateSQLInput input)
|
||||||
|
{
|
||||||
|
if (input.Columns == null || input.Columns.Count <= 0) throw Oops.Oh("至少需要设置一个列");
|
||||||
|
|
||||||
|
// 收集所有表名(从columns、conditions、orders中)
|
||||||
|
var tableNames = new HashSet<string>();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("执行SQL语句")]
|
||||||
|
public async Task<DataTable> ExecuteSQL(GenerateSQLInput input)
|
||||||
|
{
|
||||||
|
var sql = await GenerateSQL(input);
|
||||||
|
var dt = _db.Ado.GetDataTable(sql);
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
<PackageReference Include="Furion.Xunit" Version="4.9.7.125" />
|
<PackageReference Include="Furion.Xunit" Version="4.9.7.126" />
|
||||||
<PackageReference Include="Furion.Pure" Version="4.9.7.125">
|
<PackageReference Include="Furion.Pure" Version="4.9.7.126">
|
||||||
<ExcludeAssets>compile</ExcludeAssets>
|
<ExcludeAssets>compile</ExcludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="xunit.assert" Version="2.9.3" />
|
<PackageReference Include="xunit.assert" Version="2.9.3" />
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"name": "admin.net.pro",
|
"name": "admin.net.pro",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.4.33",
|
"version": "2.4.33",
|
||||||
"lastBuildTime": "2025.09.19",
|
"lastBuildTime": "2025.09.22",
|
||||||
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
||||||
"author": "zuohuaijun",
|
"author": "zuohuaijun",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"cropperjs": "^1.6.2",
|
"cropperjs": "^1.6.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
"element-plus": "^2.11.2",
|
"element-plus": "^2.11.3",
|
||||||
"exceljs": "^4.4.0",
|
"exceljs": "^4.4.0",
|
||||||
"flag-icons": "^7.5.0",
|
"flag-icons": "^7.5.0",
|
||||||
"franc": "^6.2.0",
|
"franc": "^6.2.0",
|
||||||
@ -81,8 +81,8 @@
|
|||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
"vue-signature-pad": "^3.0.2",
|
"vue-signature-pad": "^3.0.2",
|
||||||
"vue3-tree-org": "^4.2.2",
|
"vue3-tree-org": "^4.2.2",
|
||||||
"vxe-pc-ui": "^4.9.32",
|
"vxe-pc-ui": "^4.9.34",
|
||||||
"vxe-table": "^4.16.14",
|
"vxe-table": "^4.16.16",
|
||||||
"xe-utils": "^3.7.9",
|
"xe-utils": "^3.7.9",
|
||||||
"xlsx-js-style": "^1.2.0"
|
"xlsx-js-style": "^1.2.0"
|
||||||
},
|
},
|
||||||
@ -90,7 +90,7 @@
|
|||||||
"@iconify/vue": "^5.0.0",
|
"@iconify/vue": "^5.0.0",
|
||||||
"@plugin-web-update-notification/vite": "^2.0.2",
|
"@plugin-web-update-notification/vite": "^2.0.2",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^22.18.5",
|
"@types/node": "^22.18.6",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.44.0",
|
"@typescript-eslint/eslint-plugin": "^8.44.0",
|
||||||
@ -102,13 +102,13 @@
|
|||||||
"code-inspector-plugin": "^1.2.10",
|
"code-inspector-plugin": "^1.2.10",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.1",
|
||||||
"eslint": "^9.35.0",
|
"eslint": "^9.36.0",
|
||||||
"eslint-plugin-vue": "^10.4.0",
|
"eslint-plugin-vue": "^10.4.0",
|
||||||
"globals": "^16.4.0",
|
"globals": "^16.4.0",
|
||||||
"less": "^4.4.1",
|
"less": "^4.4.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"rollup-plugin-visualizer": "^6.0.3",
|
"rollup-plugin-visualizer": "^6.0.3",
|
||||||
"sass": "^1.92.1",
|
"sass": "^1.93.0",
|
||||||
"terser": "^5.44.0",
|
"terser": "^5.44.0",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.2",
|
||||||
"vite": "^7.1.6",
|
"vite": "^7.1.6",
|
||||||
|
|||||||
@ -17,11 +17,13 @@ import { Configuration } from '../configuration';
|
|||||||
// Some imports not used depending on template conditions
|
// Some imports not used depending on template conditions
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
|
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
|
||||||
|
import { AdminNETResultDataTable } from '../models';
|
||||||
import { AdminNETResultListDataInitItemOutput } from '../models';
|
import { AdminNETResultListDataInitItemOutput } from '../models';
|
||||||
import { AdminNETResultListDbColumnOutput } from '../models';
|
import { AdminNETResultListDbColumnOutput } from '../models';
|
||||||
import { AdminNETResultListDbOutput } from '../models';
|
import { AdminNETResultListDbOutput } from '../models';
|
||||||
import { AdminNETResultListDbTableInfo } from '../models';
|
import { AdminNETResultListDbTableInfo } from '../models';
|
||||||
import { AdminNETResultListString } from '../models';
|
import { AdminNETResultListString } from '../models';
|
||||||
|
import { AdminNETResultString } from '../models';
|
||||||
import { AdminNETResultTemplateContextOutput } from '../models';
|
import { AdminNETResultTemplateContextOutput } from '../models';
|
||||||
import { AdminNETResultVisualDbTable } from '../models';
|
import { AdminNETResultVisualDbTable } from '../models';
|
||||||
import { CreateEntityInput } from '../models';
|
import { CreateEntityInput } from '../models';
|
||||||
@ -30,6 +32,7 @@ import { DbColumnInput } from '../models';
|
|||||||
import { DbTableInput } from '../models';
|
import { DbTableInput } from '../models';
|
||||||
import { DeleteDbColumnInput } from '../models';
|
import { DeleteDbColumnInput } from '../models';
|
||||||
import { DeleteDbTableInput } from '../models';
|
import { DeleteDbTableInput } from '../models';
|
||||||
|
import { GenerateSQLInput } from '../models';
|
||||||
import { InitSeedDataInput } from '../models';
|
import { InitSeedDataInput } from '../models';
|
||||||
import { InitTableInput } from '../models';
|
import { InitTableInput } from '../models';
|
||||||
import { MoveDbColumnInput } from '../models';
|
import { MoveDbColumnInput } from '../models';
|
||||||
@ -476,6 +479,54 @@ export const SysDatabaseApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 执行SQL语句 🔖
|
||||||
|
* @param {GenerateSQLInput} [body]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiSysDatabaseExecuteSQLPost: async (body?: GenerateSQLInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
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 创建实体文件内容
|
* @summary 创建实体文件内容
|
||||||
@ -524,6 +575,54 @@ export const SysDatabaseApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 生成SQL语句 🔖
|
||||||
|
* @param {GenerateSQLInput} [body]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiSysDatabaseGenerateSQLPost: async (body?: GenerateSQLInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
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 初始化种子数据 🔖
|
* @summary 初始化种子数据 🔖
|
||||||
@ -1082,6 +1181,20 @@ export const SysDatabaseApiFp = function(configuration?: Configuration) {
|
|||||||
return axios.request(axiosRequestArgs);
|
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<AxiosResponse<AdminNETResultDataTable>>> {
|
||||||
|
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 创建实体文件内容
|
* @summary 创建实体文件内容
|
||||||
@ -1096,6 +1209,20 @@ export const SysDatabaseApiFp = function(configuration?: Configuration) {
|
|||||||
return axios.request(axiosRequestArgs);
|
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<AxiosResponse<AdminNETResultString>>> {
|
||||||
|
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 初始化种子数据 🔖
|
* @summary 初始化种子数据 🔖
|
||||||
@ -1319,6 +1446,16 @@ export const SysDatabaseApiFactory = function (configuration?: Configuration, ba
|
|||||||
async apiSysDatabaseDeleteTablePost(body?: DeleteDbTableInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
|
async apiSysDatabaseDeleteTablePost(body?: DeleteDbTableInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
|
||||||
return SysDatabaseApiFp(configuration).apiSysDatabaseDeleteTablePost(body, options).then((request) => request(axios, basePath));
|
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<AxiosResponse<AdminNETResultDataTable>> {
|
||||||
|
return SysDatabaseApiFp(configuration).apiSysDatabaseExecuteSQLPost(body, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 创建实体文件内容
|
* @summary 创建实体文件内容
|
||||||
@ -1329,6 +1466,16 @@ export const SysDatabaseApiFactory = function (configuration?: Configuration, ba
|
|||||||
async apiSysDatabaseGenerateEntityPost(body?: CreateEntityInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultTemplateContextOutput>> {
|
async apiSysDatabaseGenerateEntityPost(body?: CreateEntityInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultTemplateContextOutput>> {
|
||||||
return SysDatabaseApiFp(configuration).apiSysDatabaseGenerateEntityPost(body, options).then((request) => request(axios, basePath));
|
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<AxiosResponse<AdminNETResultString>> {
|
||||||
|
return SysDatabaseApiFp(configuration).apiSysDatabaseGenerateSQLPost(body, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 初始化种子数据 🔖
|
* @summary 初始化种子数据 🔖
|
||||||
@ -1526,6 +1673,17 @@ export class SysDatabaseApi extends BaseAPI {
|
|||||||
public async apiSysDatabaseDeleteTablePost(body?: DeleteDbTableInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
|
public async apiSysDatabaseDeleteTablePost(body?: DeleteDbTableInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
|
||||||
return SysDatabaseApiFp(this.configuration).apiSysDatabaseDeleteTablePost(body, options).then((request) => request(this.axios, this.basePath));
|
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<AxiosResponse<AdminNETResultDataTable>> {
|
||||||
|
return SysDatabaseApiFp(this.configuration).apiSysDatabaseExecuteSQLPost(body, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 创建实体文件内容
|
* @summary 创建实体文件内容
|
||||||
@ -1537,6 +1695,17 @@ export class SysDatabaseApi extends BaseAPI {
|
|||||||
public async apiSysDatabaseGenerateEntityPost(body?: CreateEntityInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultTemplateContextOutput>> {
|
public async apiSysDatabaseGenerateEntityPost(body?: CreateEntityInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultTemplateContextOutput>> {
|
||||||
return SysDatabaseApiFp(this.configuration).apiSysDatabaseGenerateEntityPost(body, options).then((request) => request(this.axios, this.basePath));
|
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<AxiosResponse<AdminNETResultString>> {
|
||||||
|
return SysDatabaseApiFp(this.configuration).apiSysDatabaseGenerateSQLPost(body, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 初始化种子数据 🔖
|
* @summary 初始化种子数据 🔖
|
||||||
|
|||||||
34
Web/src/api-services/system/models/columns-sql.ts
Normal file
34
Web/src/api-services/system/models/columns-sql.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* 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 ColumnsSQL
|
||||||
|
*/
|
||||||
|
export interface ColumnsSQL {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ColumnsSQL
|
||||||
|
*/
|
||||||
|
table?: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ColumnsSQL
|
||||||
|
*/
|
||||||
|
column?: string | null;
|
||||||
|
}
|
||||||
46
Web/src/api-services/system/models/conditions-sql.ts
Normal file
46
Web/src/api-services/system/models/conditions-sql.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* 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 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;
|
||||||
|
}
|
||||||
43
Web/src/api-services/system/models/generate-sqlinput.ts
Normal file
43
Web/src/api-services/system/models/generate-sqlinput.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Admin.NET 通用权限开发平台
|
||||||
|
* 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
|
||||||
|
*
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by the swagger code generator program.
|
||||||
|
* https://github.com/swagger-api/swagger-codegen.git
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ColumnsSQL } from './columns-sql';
|
||||||
|
import { ConditionsSQL } from './conditions-sql';
|
||||||
|
import { OrdersSQL } from './orders-sql';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface GenerateSQLInput
|
||||||
|
*/
|
||||||
|
export interface GenerateSQLInput {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array<ColumnsSQL>}
|
||||||
|
* @memberof GenerateSQLInput
|
||||||
|
*/
|
||||||
|
columns?: Array<ColumnsSQL> | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array<ConditionsSQL>}
|
||||||
|
* @memberof GenerateSQLInput
|
||||||
|
*/
|
||||||
|
conditions?: Array<ConditionsSQL> | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array<OrdersSQL>}
|
||||||
|
* @memberof GenerateSQLInput
|
||||||
|
*/
|
||||||
|
orders?: Array<OrdersSQL> | null;
|
||||||
|
}
|
||||||
@ -188,7 +188,9 @@ export * from './code-gen-scene-enum';
|
|||||||
export * from './column-custom-output';
|
export * from './column-custom-output';
|
||||||
export * from './column-output';
|
export * from './column-output';
|
||||||
export * from './column-relation';
|
export * from './column-relation';
|
||||||
|
export * from './columns-sql';
|
||||||
export * from './compare-info';
|
export * from './compare-info';
|
||||||
|
export * from './conditions-sql';
|
||||||
export * from './const-output';
|
export * from './const-output';
|
||||||
export * from './constructor-info';
|
export * from './constructor-info';
|
||||||
export * from './copy-role-input';
|
export * from './copy-role-input';
|
||||||
@ -278,6 +280,7 @@ export * from './gender-enum';
|
|||||||
export * from './generate-qrimage-input';
|
export * from './generate-qrimage-input';
|
||||||
export * from './generate-qrimage-output';
|
export * from './generate-qrimage-output';
|
||||||
export * from './generate-qrimage-un-limit-input';
|
export * from './generate-qrimage-un-limit-input';
|
||||||
|
export * from './generate-sqlinput';
|
||||||
export * from './generate-signature-input';
|
export * from './generate-signature-input';
|
||||||
export * from './generate-signature-output';
|
export * from './generate-signature-output';
|
||||||
export * from './generic-parameter-attributes';
|
export * from './generic-parameter-attributes';
|
||||||
@ -352,6 +355,7 @@ export * from './oauth-user-output';
|
|||||||
export * from './online-user';
|
export * from './online-user';
|
||||||
export * from './open-access-output';
|
export * from './open-access-output';
|
||||||
export * from './order-by-type';
|
export * from './order-by-type';
|
||||||
|
export * from './orders-sql';
|
||||||
export * from './page-code-gen-input';
|
export * from './page-code-gen-input';
|
||||||
export * from './page-config-input';
|
export * from './page-config-input';
|
||||||
export * from './page-dict-data-input';
|
export * from './page-dict-data-input';
|
||||||
|
|||||||
40
Web/src/api-services/system/models/orders-sql.ts
Normal file
40
Web/src/api-services/system/models/orders-sql.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* 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 OrdersSQL
|
||||||
|
*/
|
||||||
|
export interface OrdersSQL {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
* @memberof OrdersSQL
|
||||||
|
*/
|
||||||
|
table?: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
* @memberof OrdersSQL
|
||||||
|
*/
|
||||||
|
column?: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
* @memberof OrdersSQL
|
||||||
|
*/
|
||||||
|
sort?: number;
|
||||||
|
}
|
||||||
451
Web/src/views/system/reportCustomQuery/index.vue
Normal file
451
Web/src/views/system/reportCustomQuery/index.vue
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
<template>
|
||||||
|
<div class="reportCustomQuery-container">
|
||||||
|
<el-card shadow="hover" style="margin-bottom: 10px">
|
||||||
|
<!-- <template #header>
|
||||||
|
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Setting /> </el-icon>
|
||||||
|
<span> 条件配置 </span>
|
||||||
|
</template> -->
|
||||||
|
|
||||||
|
<el-divider>数据显示列配置</el-divider>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
|
<el-form-item label="表名">
|
||||||
|
<el-select v-model="state.selectedTables" multiple filterable @change="onTableChange">
|
||||||
|
<el-option v-for="item in state.dbTables" :key="item.name" :label="`${item.description ? item.description : ''}[${item.name}]`" :value="item.name" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
|
||||||
|
<el-form-item label="列名">
|
||||||
|
<el-select v-model="state.selectedColumns" multiple filterable @change="onColumnsChange">
|
||||||
|
<el-option
|
||||||
|
v-for="column in state.dbColumns"
|
||||||
|
:key="column.dbColumnName"
|
||||||
|
:label="`${column.tableDescription ? column.tableDescription : ''}.${column.columnDescription ? column.columnDescription : ''}[${column.tableName}.${column.dbColumnName}]`"
|
||||||
|
:value="`${column.tableName}.${column.dbColumnName}`"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="10" style="text-align: center">
|
||||||
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
|
<!-- 查询条件配置 -->
|
||||||
|
<el-divider>
|
||||||
|
查询条件配置
|
||||||
|
<el-button type="primary" icon="ele-Plus" plain circle @click="addCondition"></el-button>
|
||||||
|
<el-button type="danger" icon="ele-Delete" plain circle @click="clearCondition"></el-button>
|
||||||
|
</el-divider>
|
||||||
|
<div class="conditions-container">
|
||||||
|
<div v-for="(condition, index) in state.queryConditions" :key="index" class="condition-item">
|
||||||
|
<!-- 表选择项 -->
|
||||||
|
<el-select v-model="condition.table" @change="changeConditionTable(condition)" style="width: 400px">
|
||||||
|
<el-option v-for="item in state.dbTables" :key="item.name" :label="`${item.description ? item.description : ''}[${item.name}]`" :value="item.name" />
|
||||||
|
</el-select>
|
||||||
|
<!-- 列选择项 -->
|
||||||
|
<el-select v-model="condition.column" style="width: 400px" @change="changeConditionColumn(condition)">
|
||||||
|
<el-option
|
||||||
|
v-for="column in condition.columns"
|
||||||
|
:key="column.dbColumnName"
|
||||||
|
:label="`${column.columnDescription ? column.columnDescription : ''}[${column.dbColumnName}]`"
|
||||||
|
:value="`${column.tableName}.${column.dbColumnName}`"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<!-- 操作符选择项 -->
|
||||||
|
<el-select v-model="condition.operator" style="width: 250px">
|
||||||
|
<el-option label="等于" value="=" />
|
||||||
|
<el-option label="不等于" value="!=" />
|
||||||
|
<el-option label="大于" value=">" />
|
||||||
|
<el-option label="小于" value="<" />
|
||||||
|
<el-option label="大于等于" value=">=" />
|
||||||
|
<el-option label="小于等于" value="<=" />
|
||||||
|
<el-option label="包含" value="LIKE" />
|
||||||
|
</el-select>
|
||||||
|
<!-- 值填写项 -->
|
||||||
|
<el-input-number v-if="condition.dataType == 'bigint' || condition.dataType == 'int8'" v-model="condition.value" controls-position="right" class="w100" />
|
||||||
|
<el-date-picker v-else-if="condition.dataType == 'datetime' || condition.dataType == 'timestamp'" v-model="condition.value" type="datetime" class="w100" />
|
||||||
|
<el-input v-else v-model="condition.value" />
|
||||||
|
<!-- 删除按钮 -->
|
||||||
|
<el-button type="danger" icon="ele-CloseBold" plain circle @click="removeCondition(index)"></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
|
<!-- 数据排序配置 -->
|
||||||
|
<el-divider>
|
||||||
|
数据排序配置
|
||||||
|
<el-button type="primary" icon="ele-Plus" plain circle @click="addSortCondition"></el-button>
|
||||||
|
<el-button type="danger" icon="ele-Delete" plain circle @click="clearSortCondition"></el-button>
|
||||||
|
</el-divider>
|
||||||
|
<div class="conditions-container">
|
||||||
|
<div v-for="(sortCondition, index) in state.sortConditions" :key="index" class="condition-item">
|
||||||
|
<!-- 表选择项 -->
|
||||||
|
<el-select v-model="sortCondition.table" @change="changeConditionTable(sortCondition)">
|
||||||
|
<el-option v-for="item in state.dbTables" :key="item.name" :label="`${item.description ? item.description : ''}[${item.name}]`" :value="item.name" />
|
||||||
|
</el-select>
|
||||||
|
<!-- 列选择项 -->
|
||||||
|
<el-select v-model="sortCondition.column">
|
||||||
|
<el-option
|
||||||
|
v-for="column in sortCondition.columns"
|
||||||
|
:key="column.dbColumnName"
|
||||||
|
:label="`${column.columnDescription ? column.columnDescription : ''}[${column.dbColumnName}]`"
|
||||||
|
:value="`${column.tableName}.${column.dbColumnName}`"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<!-- 排序序号 -->
|
||||||
|
<el-input-number v-model="sortCondition.sortOrder" style="width: 180px" controls-position="right" />
|
||||||
|
<!-- 删除按钮 -->
|
||||||
|
<el-button type="danger" icon="ele-CloseBold" plain circle @click="removeSortCondition(index)"></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<el-row :gutter="10" style="text-align: center">
|
||||||
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
||||||
|
<el-button icon="ele-View" type="primary" plain @click="generateSQL">预览SQL</el-button>
|
||||||
|
<el-button icon="ele-Position" type="primary" @click="executeSQL">执行查询</el-button>
|
||||||
|
<el-button icon="ele-FolderOpened" @click="openSchema">打开方案</el-button>
|
||||||
|
<el-button icon="ele-DocumentCopy" @click="saveSchema">保存方案</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- SQL语句预览 -->
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="">
|
||||||
|
<el-input v-model="state.sqlString" type="textarea" :rows="5" disabled style="color: red" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 查询结果展示 - 直接显示表格 -->
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<template #header>
|
||||||
|
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Tickets /> </el-icon>
|
||||||
|
<span> 查询结果 </span>
|
||||||
|
</template>
|
||||||
|
<el-table :data="formattedTableData" style="width: 100%" height="calc(100% - 30px)" v-if="state.selectedColumnDetails.length > 0">
|
||||||
|
<el-table-column v-for="(column, index) in state.selectedColumnDetails" :key="index" :label="`${column.tableDescription}.${column.columnDescription}`" :prop="`col${index}`"> </el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 报表自定义查询 -->
|
||||||
|
<script lang="ts" setup name="sysReportCustomQuery">
|
||||||
|
import { reactive, onMounted, computed } from 'vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
// import { format } from 'sql-formatter';
|
||||||
|
|
||||||
|
import { getAPI } from '/@/utils/axios-utils';
|
||||||
|
import { SysDatabaseApi } from '/@/api-services/system/api';
|
||||||
|
import { DbTableInfo } from '/@/api-services/system/models';
|
||||||
|
|
||||||
|
// 定义状态
|
||||||
|
const state = reactive({
|
||||||
|
// 数据库表和列集合
|
||||||
|
dbTables: [] as Array<DbTableInfo>,
|
||||||
|
dbColumns: [] as any,
|
||||||
|
selectedTables: [] as any,
|
||||||
|
selectedColumns: [] as any,
|
||||||
|
selectedColumnDetails: [] as any,
|
||||||
|
// 查询条件配置
|
||||||
|
queryConditions: [] as Array<{
|
||||||
|
table: string;
|
||||||
|
column: string;
|
||||||
|
operator: string; // 操作符
|
||||||
|
value: string; // 值
|
||||||
|
columns: any;
|
||||||
|
dataType: string; // 列数据类型
|
||||||
|
}>,
|
||||||
|
// 数据排序配置
|
||||||
|
sortConditions: [] as Array<{
|
||||||
|
table: string;
|
||||||
|
column: string;
|
||||||
|
sortOrder: number;
|
||||||
|
columns: any;
|
||||||
|
}>,
|
||||||
|
// SQL语句
|
||||||
|
sqlString: 'select * from xxx',
|
||||||
|
// 查询结果
|
||||||
|
queryResults: [] as Array<{
|
||||||
|
columns: string[];
|
||||||
|
data: any[][];
|
||||||
|
}>,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面初始化
|
||||||
|
onMounted(async () => {
|
||||||
|
// 查询表列表
|
||||||
|
const res: any = await getAPI(SysDatabaseApi).apiSysDatabaseTableListConfigIdGet('1300000000001');
|
||||||
|
res.data.result.forEach((element: any) => {
|
||||||
|
// 排除zero_开头的表
|
||||||
|
if (!element.name.startsWith('zero_')) {
|
||||||
|
state.dbTables.push(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当选择表时,加载对应的列
|
||||||
|
const onTableChange = async () => {
|
||||||
|
state.dbColumns = [];
|
||||||
|
if (!state.selectedTables) return;
|
||||||
|
|
||||||
|
state.selectedTables.forEach(async (element: string) => {
|
||||||
|
// 获取当前选择表的详细项
|
||||||
|
const tableInfo = state.dbTables.find((table) => table.name === element);
|
||||||
|
const res: any = await getAPI(SysDatabaseApi).apiSysDatabaseColumnListTableNameConfigIdGet(element, '1300000000001');
|
||||||
|
if (res.data.result && Array.isArray(res.data.result)) {
|
||||||
|
res.data.result.forEach((newColumn: any) => {
|
||||||
|
const columnWithTableDesc = {
|
||||||
|
...newColumn,
|
||||||
|
tableDescription: tableInfo ? tableInfo.description : '', // 添加表描述
|
||||||
|
};
|
||||||
|
state.dbColumns.push(columnWithTableDesc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询条件表改变时
|
||||||
|
const changeConditionTable = async (condition: any) => {
|
||||||
|
const res: any = await getAPI(SysDatabaseApi).apiSysDatabaseColumnListTableNameConfigIdGet(condition.table, '1300000000001');
|
||||||
|
condition.columns = res.data.result;
|
||||||
|
condition.column = undefined;
|
||||||
|
condition.value = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询条件列改变时
|
||||||
|
const changeConditionColumn = async (condition: any) => {
|
||||||
|
// 获取当前列数据类型
|
||||||
|
var column = condition.columns.find((column: any) => column.tableName + '.' + column.dbColumnName == condition.column);
|
||||||
|
if (column) {
|
||||||
|
condition.dataType = column.dataType;
|
||||||
|
condition.value = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当列选择变化时触发,实现勾选与列表的关联
|
||||||
|
const onColumnsChange = () => {
|
||||||
|
// 清除之前的查询结果,确保下一次查询基于最新选择的列
|
||||||
|
state.sqlString = '';
|
||||||
|
state.selectedColumnDetails = [];
|
||||||
|
|
||||||
|
// 更新已选择列的完整信息
|
||||||
|
if (state.selectedColumns.length <= 0 || state.dbColumns.length <= 0) return;
|
||||||
|
state.selectedColumns.forEach((colFullName: string) => {
|
||||||
|
// 解析列名,格式为"表名.列名"
|
||||||
|
const [tableName, dbColumnName] = colFullName.split('.');
|
||||||
|
// 如果解析成功,在columns中查找匹配的项
|
||||||
|
if (tableName && dbColumnName) {
|
||||||
|
const matchedColumn = state.dbColumns.find((column: any) => column.tableName === tableName && column.dbColumnName === dbColumnName);
|
||||||
|
// 如果找到匹配项,添加到selectedColumnDetails
|
||||||
|
if (matchedColumn) {
|
||||||
|
state.selectedColumnDetails.push(matchedColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加查询条件
|
||||||
|
const addCondition = () => {
|
||||||
|
state.queryConditions.push({
|
||||||
|
table: '',
|
||||||
|
column: '',
|
||||||
|
operator: '=',
|
||||||
|
value: '',
|
||||||
|
columns: [],
|
||||||
|
dataType: '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除查询条件
|
||||||
|
const removeCondition = (index: number) => {
|
||||||
|
state.queryConditions.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清除所有查询条件
|
||||||
|
const clearCondition = () => {
|
||||||
|
state.queryConditions = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加排序条件
|
||||||
|
const addSortCondition = () => {
|
||||||
|
state.sortConditions.push({
|
||||||
|
table: '',
|
||||||
|
column: '',
|
||||||
|
sortOrder: 10,
|
||||||
|
columns: [],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除排序条件
|
||||||
|
const removeSortCondition = (index: number) => {
|
||||||
|
state.sortConditions.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清除所有排序条件
|
||||||
|
const clearSortCondition = () => {
|
||||||
|
state.sortConditions = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 预览SQL
|
||||||
|
const generateSQL = async () => {
|
||||||
|
var queryJson = {
|
||||||
|
columns: state.selectedColumnDetails
|
||||||
|
.filter((col: any) => state.selectedTables.includes(col.tableName)) // 只包含选中表的列
|
||||||
|
.map((col: any) => ({
|
||||||
|
table: col.tableName,
|
||||||
|
column: col.dbColumnName,
|
||||||
|
})),
|
||||||
|
conditions: state.queryConditions.map((cond) => {
|
||||||
|
return {
|
||||||
|
table: cond.table,
|
||||||
|
column: cond.column.includes('.') ? cond.column.split('.')[1] : cond.column,
|
||||||
|
operator: cond.operator,
|
||||||
|
value: cond.value,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
orders: state.sortConditions.map((sortCond) => {
|
||||||
|
return {
|
||||||
|
table: sortCond.table,
|
||||||
|
column: sortCond.column.includes('.') ? sortCond.column.split('.')[1] : sortCond.column,
|
||||||
|
sort: sortCond.sortOrder,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
var res = await getAPI(SysDatabaseApi).apiSysDatabaseGenerateSQLPost(queryJson);
|
||||||
|
state.sqlString = res.data.result ?? '';
|
||||||
|
return queryJson;
|
||||||
|
|
||||||
|
// // 格式化SQL语句
|
||||||
|
// state.sqlString = format(state.sqlString, {
|
||||||
|
// tabWidth: 4,
|
||||||
|
// useTabs: false,
|
||||||
|
// keywordCase: 'upper',
|
||||||
|
// dataTypeCase: 'upper',
|
||||||
|
// functionCase: 'upper',
|
||||||
|
// logicalOperatorNewline: 'before',
|
||||||
|
// language: 'transactsql',
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 执行SQL
|
||||||
|
const executeSQL = async () => {
|
||||||
|
var queryJson = await generateSQL();
|
||||||
|
var res = await getAPI(SysDatabaseApi).apiSysDatabaseExecuteSQLPost(queryJson);
|
||||||
|
console.log(res.data.result);
|
||||||
|
state.queryResults[0].data = res.data.result ?? [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将二维数组数据格式化为对象数组,以便 Element Plus 的表格组件使用
|
||||||
|
const formattedTableData = computed(() => {
|
||||||
|
if (!state.queryResults || !state.queryResults[0] || !state.queryResults[0].data) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回所有数据
|
||||||
|
return state.queryResults[0].data.map((row, rowIndex) => {
|
||||||
|
const formattedRow: Record<string, any> = {};
|
||||||
|
row.forEach((cell, cellIndex) => {
|
||||||
|
formattedRow[`col${cellIndex}`] = cell;
|
||||||
|
});
|
||||||
|
return formattedRow;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开方案
|
||||||
|
const openSchema = () => {
|
||||||
|
// 创建文件选择器
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = '.json';
|
||||||
|
|
||||||
|
input.onchange = (event) => {
|
||||||
|
const file = (event.target as HTMLInputElement).files?.[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (e) => {
|
||||||
|
try {
|
||||||
|
// 解析JSON文件内容
|
||||||
|
const schemaData = JSON.parse(e.target?.result as string);
|
||||||
|
if (schemaData.selectedTable) {
|
||||||
|
state.selectedTables = schemaData.selectedTable;
|
||||||
|
}
|
||||||
|
if (schemaData.selectedColumns) {
|
||||||
|
state.selectedColumns = schemaData.selectedColumns;
|
||||||
|
}
|
||||||
|
if (schemaData.queryConditions) {
|
||||||
|
state.queryConditions = schemaData.queryConditions;
|
||||||
|
}
|
||||||
|
if (schemaData.sortConditions) {
|
||||||
|
state.sortConditions = schemaData.sortConditions;
|
||||||
|
}
|
||||||
|
ElMessage.success('自定义查询方案加载成功');
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('自定义查询方案文件格式错误');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 触发文件选择对话框
|
||||||
|
input.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存方案
|
||||||
|
const saveSchema = () => {
|
||||||
|
if (state.queryConditions.length === 0) {
|
||||||
|
ElMessage.warning('请先进行配置');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 创建要保存的查询配置对象
|
||||||
|
const schemaData = {
|
||||||
|
selectedTable: state.selectedTables,
|
||||||
|
selectedColumns: state.selectedColumns,
|
||||||
|
queryConditions: state.queryConditions,
|
||||||
|
sortConditions: state.sortConditions,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 转换为JSON字符串
|
||||||
|
const jsonString = JSON.stringify(schemaData, null, 2);
|
||||||
|
|
||||||
|
// 创建Blob对象
|
||||||
|
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
// 设置文件名,使用表名和当前时间作为标识
|
||||||
|
const timestamp = new Date().toLocaleString('zh-CN').replace(/[\/\s:]/g, '-');
|
||||||
|
a.download = `自定义查询方案_${timestamp}.json`;
|
||||||
|
|
||||||
|
// 触发下载
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.conditions-container {
|
||||||
|
padding: 0 10px 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condition-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user