😎优化报表开发相关代码(菜单种子做了调整,升级时已有菜单数据要重新生成)

This commit is contained in:
zuohuaijun 2025-06-27 01:02:41 +08:00
parent 30081ce83d
commit 8f29ef4ecc
24 changed files with 322 additions and 313 deletions

View File

@ -32,7 +32,7 @@ public class SseService : ControllerBase
Response.Headers.Append("Cache-Control", "no-cache"); Response.Headers.Append("Cache-Control", "no-cache");
Response.Headers.Append("Connection", "keep-alive"); Response.Headers.Append("Connection", "keep-alive");
Response.Headers.Append("X-Accel-Buffering", "no"); // Nginx Response.Headers.Append("X-Accel-Buffering", "no"); // Nginx
var channel = _sseChannelManager.Register(id); var channel = _sseChannelManager.Register(id);
var deepThinkingChannel = _sseDeepThinkingChannelManager.Register(id); var deepThinkingChannel = _sseDeepThinkingChannelManager.Register(id);
try try

View File

@ -7,22 +7,24 @@
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 报表配置 /// 系统报表配置
/// </summary> /// </summary>
[SugarTable(null, "报表配置")] [SugarTable(null, "系统报表配置")]
[SysTable] [SysTable]
public class SysReportConfig : EntityBase public class SysReportConfig : EntityBase
{ {
/// <summary> /// <summary>
/// 名称 /// 名称
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "名称", Length = 255)] [SugarColumn(ColumnDescription = "名称", Length = 254)]
[MaxLength(254)]
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// 描述 /// 描述
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "描述", Length = 500)] [SugarColumn(ColumnDescription = "描述", Length = 512)]
[MaxLength(512)]
public string? Description { get; set; } public string? Description { get; set; }
/// <summary> /// <summary>
@ -34,7 +36,7 @@ public class SysReportConfig : EntityBase
/// <summary> /// <summary>
/// 数据源 /// 数据源
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "数据源")] [SugarColumn(ColumnDescription = "数据源", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string? DataSource { get; set; } public string? DataSource { get; set; }
/// <summary> /// <summary>
@ -58,19 +60,22 @@ public class SysReportConfig : EntityBase
/// <summary> /// <summary>
/// 接口地址 /// 接口地址
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "接口地址", Length = 4000)] [SugarColumn(ColumnDescription = "接口地址", Length = 1024)]
[MaxLength(1024)]
public string? ApiUrl { get; set; } public string? ApiUrl { get; set; }
/// <summary> /// <summary>
/// 接口请求方式 /// 接口请求方式
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "接口请求方式", Length = 10)] [SugarColumn(ColumnDescription = "接口请求方式", Length = 16)]
[MaxLength(16)]
public string? ApiHttpMethod { get; set; } public string? ApiHttpMethod { get; set; }
/// <summary> /// <summary>
/// 接口参数 /// 接口参数
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "接口参数", Length = 4000)] [SugarColumn(ColumnDescription = "接口参数", Length = 1024)]
[MaxLength(1024)]
public string? ApiParams { get; set; } public string? ApiParams { get; set; }
/// <summary> /// <summary>

View File

@ -7,33 +7,37 @@
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 报表数据源 /// 系统报表数据源
/// </summary> /// </summary>
[SugarTable(null, "报表数据源")] [SugarTable(null, "系统报表数据源")]
[SysTable] [SysTable]
public class SysReportDataSource : EntityBase public class SysReportDataSource : EntityBase
{ {
/// <summary> /// <summary>
/// 名称 /// 名称
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "名称", Length = 255)] [SugarColumn(ColumnDescription = "名称", Length = 254)]
[MaxLength(254)]
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// 数据库类型 /// 数据库类型
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "数据库类型", Length = 20)] [SugarColumn(ColumnDescription = "数据库类型", Length = 32)]
[MaxLength(32)]
public string DbType { get; set; } public string DbType { get; set; }
/// <summary> /// <summary>
/// 连接字符串 /// 连接字符串
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "连接字符串", Length = 2000)] [SugarColumn(ColumnDescription = "连接字符串", Length = 512)]
[MaxLength(512)]
public string ConnectionString { get; set; } public string ConnectionString { get; set; }
/// <summary> /// <summary>
/// 备注 /// 备注
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "备注", Length = 500)] [SugarColumn(ColumnDescription = "备注", Length = 128)]
public string? Memo { get; set; } [MaxLength(128)]
public string? Remark { get; set; }
} }

View File

@ -7,21 +7,23 @@
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 报表分组 /// 系统报表分组
/// </summary> /// </summary>
[SugarTable(null, "报表分组")] [SugarTable(null, "系统报表分组")]
[SysTable] [SysTable]
public class SysReportGroup : EntityBase public class SysReportGroup : EntityBase
{ {
/// <summary> /// <summary>
/// 编码 /// 编码
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "编码", Length = 80)] [SugarColumn(ColumnDescription = "编码", Length = 64)]
[MaxLength(64)]
public string Number { get; set; } public string Number { get; set; }
/// <summary> /// <summary>
/// 名称 /// 名称
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "名称", Length = 255)] [SugarColumn(ColumnDescription = "名称", Length = 254)]
[MaxLength(254)]
public string Name { get; set; } public string Name { get; set; }
} }

View File

@ -211,24 +211,25 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
new SysMenu{ Id=1310000000641, Pid=1310000000601, Title="系统接口", Path="/develop/api", Name="sysApi", Component="layout/routerView/iframe", IsIframe=true, OutLink="http://localhost:5005", Icon="ele-Help", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 }, new SysMenu{ Id=1310000000641, Pid=1310000000601, Title="系统接口", Path="/develop/api", Name="sysApi", Component="layout/routerView/iframe", IsIframe=true, OutLink="http://localhost:5005", Icon="ele-Help", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
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="/doc", Name="doc", Component="Layout", Icon="ele-Notebook", 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="/doc/admin", Name="sysAdmin", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://adminnet.top/", Icon="ele-Sunny", 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-Filter", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000721, Pid=1310000000701, Title="SqlSugar", Path="/doc/SqlSugar", Name="sysSqlSugar", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://www.donet5.com/Home/Doc", Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 }, 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=1310000000801, Pid=0, Title="关于项目", Path="/about", Name="about", Component="/about/index", Icon="ele-InfoFilled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2023-03-12 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-Sunny", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1320000000121, Pid=1320000000101, Title="SqlSugar", Path="/doc/SqlSugar", Name="sysSqlSugar", Component="layout/routerView/link", IsIframe=false, IsKeepAlive=false, OutLink="https://www.donet5.com/Home/Doc", Icon="ele-Coin", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
new SysMenu{ Id=1310000000901, Pid=0, Title="报表开发", Path="/report", Name="report", Component="Layout", Icon="iconfont icon-ico_shuju", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=14500 }, new SysMenu{ Id=1320000000201, Pid=0, Title="关于项目", Path="/about", Name="about", Component="/about/index", Icon="ele-InfoFilled", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2023-03-12 00:00:00"), OrderNo=16000 },
new SysMenu{ Id=1310000000911, Pid=1310000000901, Title="数据源配置", Path="/report/sysReportDataSource", Name="sysReportDataSource", Component="/system/reportDataSource/index", Icon="ele-Document", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000912, Pid=1310000000911, Title="查询", Permission="sysReportDataSource/page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 }, ];
new SysMenu{ Id=1310000000913, Pid=1310000000911, Title="编辑", Permission="sysReportDataSource/update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000914, Pid=1310000000911, Title="增加", Permission="sysReportDataSource/add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000915, Pid=1310000000911, Title="删除", Permission="sysReportDataSource/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000916, Pid=1310000000911, Title="复制", Permission="sysReportDataSource/copy", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000921, Pid=1310000000901, Title="报表配置", Path="/report/sysReportConfig", 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=1310000000922, Pid=1310000000921, Title="查询", Permission="sysReportConfig/page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000923, Pid=1310000000921, Title="编辑", Permission="sysReportConfig/update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000924, Pid=1310000000921, Title="增加", Permission="sysReportConfig/v", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000925, Pid=1310000000921, Title="删除", Permission="sysReportConfig/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
];
} }
} }

View File

@ -48,7 +48,7 @@ public class ReportConfigParseSqlInput
/// <summary> /// <summary>
/// 执行参数 /// 执行参数
/// </summary> /// </summary>
public Dictionary<string, object> ExecParams { get; set; } = new(); public Dictionary<string, object> ExecParams { get; set; } = [];
} }
/// <summary> /// <summary>
@ -59,5 +59,5 @@ public class ReportConfigExecuteSqlScriptInput : BaseIdInput
/// <summary> /// <summary>
/// 执行参数 /// 执行参数
/// </summary> /// </summary>
public Dictionary<string, object> ExecParams { get; set; } = new(); public Dictionary<string, object> ExecParams { get; set; } = [];
} }

View File

@ -7,26 +7,23 @@
namespace Admin.NET.Core.Service; namespace Admin.NET.Core.Service;
/// <summary> /// <summary>
/// 报表配置服务 /// 系统报表配置服务
/// </summary> /// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表配置")] [ApiDescriptionSettings(Order = 500, Description = "报表配置")]
public class SysReportConfigService : IDynamicApiController, ITransient public class SysReportConfigService : IDynamicApiController, ITransient
{ {
private readonly SqlSugarRepository<SysReportConfig> _rep; private readonly SqlSugarRepository<SysReportConfig> _reportConfigRep;
private readonly SysReportDataSourceService _sysReportDataSourceService; private readonly SysReportDataSourceService _sysReportDataSourceService;
private readonly SysTenantService _sysTenantService; private readonly SysTenantService _sysTenantService;
private readonly UserManager _userManager; private readonly UserManager _userManager;
/// <summary> public SysReportConfigService(SqlSugarRepository<SysReportConfig> reportConfigRep,
/// 报表配置服务构造函数
/// </summary>
public SysReportConfigService(SqlSugarRepository<SysReportConfig> rep,
SysReportDataSourceService sysReportDataSourceService, SysReportDataSourceService sysReportDataSourceService,
SysTenantService sysTenantService, SysTenantService sysTenantService,
UserManager userManager UserManager userManager
) )
{ {
_rep = rep; _reportConfigRep = reportConfigRep;
_sysReportDataSourceService = sysReportDataSourceService; _sysReportDataSourceService = sysReportDataSourceService;
_sysTenantService = sysTenantService; _sysTenantService = sysTenantService;
_userManager = userManager; _userManager = userManager;
@ -40,13 +37,13 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[DisplayName("获取报表配置分页列表")] [DisplayName("获取报表配置分页列表")]
public async Task<SqlSugarPagedList<ReportConfigOutput>> Page(PageReportConfigInput input) public async Task<SqlSugarPagedList<ReportConfigOutput>> Page(PageReportConfigInput input)
{ {
return await _rep.AsQueryable() return await _reportConfigRep.AsQueryable()
.LeftJoin<SysReportGroup>((c, g) => c.GroupId == g.Id) .LeftJoin<SysReportGroup>((u, a) => u.GroupId == a.Id)
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), (c, g) => c.Name.Contains(input.Name.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.Name), (u, a) => u.Name.Contains(input.Name.Trim()))
.WhereIF(input.GroupId is > 0, (c, g) => c.GroupId == input.GroupId) .WhereIF(input.GroupId is > 0, (u, a) => u.GroupId == input.GroupId)
.Select((c, g) => new ReportConfigOutput .Select((u, a) => new ReportConfigOutput
{ {
GroupName = g.Name GroupName = a.Name
}, true) }, true)
.OrderBuilder(input) .OrderBuilder(input)
.ToPagedListAsync(input.Page, input.PageSize); .ToPagedListAsync(input.Page, input.PageSize);
@ -61,11 +58,11 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[DisplayName("增加报表配置")] [DisplayName("增加报表配置")]
public async Task Add(AddReportConfigInput input) public async Task Add(AddReportConfigInput input)
{ {
var isExist = await _rep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id); var isExist = await _reportConfigRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
if (isExist) if (isExist)
throw Oops.Bah(ErrorCodeEnum.C1000); throw Oops.Bah(ErrorCodeEnum.C1000);
await _rep.InsertAsync(input.Adapt<SysReportConfig>()); await _reportConfigRep.InsertAsync(input.Adapt<SysReportConfig>());
} }
/// <summary> /// <summary>
@ -78,11 +75,11 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[DisplayName("更新报表配置")] [DisplayName("更新报表配置")]
public async Task Update(UpdateReportConfigInput input) public async Task Update(UpdateReportConfigInput input)
{ {
var isExist = await _rep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id); var isExist = await _reportConfigRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
if (isExist) if (isExist)
throw Oops.Bah(ErrorCodeEnum.C1000); throw Oops.Bah(ErrorCodeEnum.C1000);
await _rep.UpdateAsync(input.Adapt<SysReportConfig>()); await _reportConfigRep.UpdateAsync(input.Adapt<SysReportConfig>());
} }
/// <summary> /// <summary>
@ -95,7 +92,7 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[DisplayName("删除报表配置")] [DisplayName("删除报表配置")]
public async Task Delete(BaseIdInput input) public async Task Delete(BaseIdInput input)
{ {
await _rep.DeleteAsync(u => u.Id == input.Id); await _reportConfigRep.DeleteAsync(u => u.Id == input.Id);
} }
/// <summary> /// <summary>
@ -108,10 +105,7 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[DisplayName("复制报表配置")] [DisplayName("复制报表配置")]
public async Task Copy(BaseIdInput input) public async Task Copy(BaseIdInput input)
{ {
var entity = await _rep.GetFirstAsync(u => u.Id == input.Id); var entity = await _reportConfigRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Bah(ErrorCodeEnum.D1002);
if (entity == null)
throw Oops.Bah(ErrorCodeEnum.D1002);
entity.Id = YitIdHelper.NextId(); entity.Id = YitIdHelper.NextId();
entity.Name = $"{entity.Name} - 副本"; entity.Name = $"{entity.Name} - 副本";
entity.CreateTime = DateTime.Now; entity.CreateTime = DateTime.Now;
@ -132,14 +126,14 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[DisplayName("获取报表布局配置")] [DisplayName("获取报表布局配置")]
public SysReportLayoutConfig GetLayoutConfig([FromQuery] BaseIdInput input) public SysReportLayoutConfig GetLayoutConfig([FromQuery] BaseIdInput input)
{ {
var entity = _rep.GetFirst(u => u.Id == input.Id); var entity = _reportConfigRep.GetFirst(u => u.Id == input.Id);
if (entity == null) throw Oops.Bah(ErrorCodeEnum.D1002); return entity == null
? throw Oops.Bah(ErrorCodeEnum.D1002)
return new SysReportLayoutConfig : new SysReportLayoutConfig
{ {
Fields = string.IsNullOrEmpty(entity.Fields) ? [] : JSON.Deserialize<List<SysReportField>>(entity.Fields), Fields = string.IsNullOrEmpty(entity.Fields) ? [] : JSON.Deserialize<List<SysReportField>>(entity.Fields),
Params = string.IsNullOrEmpty(entity.Params) ? [] : JSON.Deserialize<List<SysReportParam>>(entity.Params), Params = string.IsNullOrEmpty(entity.Params) ? [] : JSON.Deserialize<List<SysReportParam>>(entity.Params),
}; };
} }
/// <summary> /// <summary>
@ -169,16 +163,12 @@ public class SysReportConfigService : IDynamicApiController, ITransient
[UnifySerializerSetting("CamelCaseDictionaryKey")] [UnifySerializerSetting("CamelCaseDictionaryKey")]
public async Task<List<Dictionary<string, object>>> ExecuteSqlScript(ReportConfigExecuteSqlScriptInput input) public async Task<List<Dictionary<string, object>>> ExecuteSqlScript(ReportConfigExecuteSqlScriptInput input)
{ {
var entity = await _rep.GetFirstAsync(u => u.Id == input.Id); var entity = await _reportConfigRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Bah(ErrorCodeEnum.D1002);
if (entity == null) throw Oops.Bah(ErrorCodeEnum.D1002);
if (entity.DsType != ReportConfigDsTypeEnum.Sql) if (entity.DsType != ReportConfigDsTypeEnum.Sql)
throw Oops.Bah(ErrorCodeEnum.C1001); throw Oops.Bah(ErrorCodeEnum.C1001);
var layoutConfig = GetLayoutConfig(input); var layoutConfig = GetLayoutConfig(input);
var execParams = new Dictionary<string, object>(input.ExecParams); var execParams = new Dictionary<string, object>(input.ExecParams);
// 补充没有传入的参数,如果传入 null则填充空字符串不为 null sqlsugar 才会构造参数 // 补充没有传入的参数,如果传入 null则填充空字符串不为 null sqlsugar 才会构造参数
foreach (var param in layoutConfig.Params) foreach (var param in layoutConfig.Params)
{ {

View File

@ -9,24 +9,21 @@ using Furion.Localization;
namespace Admin.NET.Core.Service; namespace Admin.NET.Core.Service;
/// <summary> /// <summary>
/// 报表数据源服务 /// 系统报表数据源服务
/// </summary> /// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表数据源")] [ApiDescriptionSettings(Order = 500, Description = "报表数据源")]
public class SysReportDataSourceService : IDynamicApiController, ITransient public class SysReportDataSourceService : IDynamicApiController, ITransient
{ {
private readonly SqlSugarRepository<SysReportDataSource> _rep; private readonly SqlSugarRepository<SysReportDataSource> _reportDataSourceRep;
private readonly SqlSugarRepository<SysTenant> _tenantRep; private readonly SqlSugarRepository<SysTenant> _tenantRep;
private readonly ISqlSugarClient _db; private readonly ISqlSugarClient _db;
/// <summary> public SysReportDataSourceService(SqlSugarRepository<SysReportDataSource> reportDataSourceRep,
/// 报表数据源服务构造函数
/// </summary>
public SysReportDataSourceService(SqlSugarRepository<SysReportDataSource> rep,
SqlSugarRepository<SysTenant> tenantRep, SqlSugarRepository<SysTenant> tenantRep,
ISqlSugarClient db ISqlSugarClient db
) )
{ {
_rep = rep; _reportDataSourceRep = reportDataSourceRep;
_tenantRep = tenantRep; _tenantRep = tenantRep;
_db = db; _db = db;
} }
@ -39,7 +36,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("获取报表数据源分页列表")] [DisplayName("获取报表数据源分页列表")]
public async Task<SqlSugarPagedList<SysReportDataSource>> Page(PageReportDataSourceInput input) public async Task<SqlSugarPagedList<SysReportDataSource>> Page(PageReportDataSourceInput input)
{ {
var list = await _rep.AsQueryable() var list = await _reportDataSourceRep.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim()))
.Select(u => new SysReportDataSource(), true) .Select(u => new SysReportDataSource(), true)
.OrderBuilder(input) .OrderBuilder(input)
@ -60,11 +57,11 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("增加报表数据源")] [DisplayName("增加报表数据源")]
public async Task Add(AddReportDataSourceInput input) public async Task Add(AddReportDataSourceInput input)
{ {
var isExist = await _rep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id); var isExist = await _reportDataSourceRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
if (isExist) if (isExist)
throw Oops.Bah(ErrorCodeEnum.C1000); throw Oops.Bah(ErrorCodeEnum.C1000);
await _rep.InsertAsync(input.Adapt<SysReportDataSource>()); await _reportDataSourceRep.InsertAsync(input.Adapt<SysReportDataSource>());
} }
/// <summary> /// <summary>
@ -77,7 +74,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("更新报表数据源")] [DisplayName("更新报表数据源")]
public async Task Update(UpdateReportDataSourceInput input) public async Task Update(UpdateReportDataSourceInput input)
{ {
var isExist = await _rep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id); var isExist = await _reportDataSourceRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.Id);
if (isExist) if (isExist)
throw Oops.Bah(ErrorCodeEnum.C1000); throw Oops.Bah(ErrorCodeEnum.C1000);
@ -90,7 +87,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
// updateEntity.ConnectionString = entity.ConnectionString; // updateEntity.ConnectionString = entity.ConnectionString;
// } // }
await _rep.UpdateAsync(updateEntity); await _reportDataSourceRep.UpdateAsync(updateEntity);
} }
/// <summary> /// <summary>
@ -103,7 +100,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("删除报表数据源")] [DisplayName("删除报表数据源")]
public async Task Delete(BaseIdInput input) public async Task Delete(BaseIdInput input)
{ {
await _rep.DeleteAsync(u => u.Id == input.Id); await _reportDataSourceRep.DeleteAsync(u => u.Id == input.Id);
} }
/// <summary> /// <summary>
@ -150,7 +147,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
} }
// 用户自定义 // 用户自定义
var dsList = await _rep.GetListAsync(); var dsList = await _reportDataSourceRep.GetListAsync();
foreach (var ds in dsList) foreach (var ds in dsList)
{ {
list.Add(new SysReportDataSourceDetail list.Add(new SysReportDataSourceDetail
@ -171,7 +168,6 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
/// <summary> /// <summary>
/// 获取报表数据源列表 /// 获取报表数据源列表
/// </summary> /// </summary>
[ApiDescriptionSettings(Name = "GetDataSourceList"), HttpGet]
[DisplayName("获取报表数据源列表")] [DisplayName("获取报表数据源列表")]
public async Task<List<ReportDataSourceOutput>> GetDataSourceList() public async Task<List<ReportDataSourceOutput>> GetDataSourceList()
{ {

View File

@ -7,30 +7,26 @@
namespace Admin.NET.Core.Service; namespace Admin.NET.Core.Service;
/// <summary> /// <summary>
/// 报表分组服务 /// 系统报表分组服务
/// </summary> /// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表分组")] [ApiDescriptionSettings(Order = 500, Description = "报表分组")]
public class SysReportGroupService : IDynamicApiController, ITransient public class SysReportGroupService : IDynamicApiController, ITransient
{ {
private readonly SqlSugarRepository<SysReportGroup> _rep; private readonly SqlSugarRepository<SysReportGroup> _reportGroupRep;
/// <summary> public SysReportGroupService(SqlSugarRepository<SysReportGroup> reportGroupRep)
/// 报表分组服务构造函数
/// </summary>
public SysReportGroupService(SqlSugarRepository<SysReportGroup> rep)
{ {
_rep = rep; _reportGroupRep = reportGroupRep;
} }
/// <summary> /// <summary>
/// 获取报表分组列表 /// 获取报表分组列表
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[ApiDescriptionSettings(Name = "GetList"), HttpGet]
[DisplayName("获取报表分组列表")] [DisplayName("获取报表分组列表")]
public async Task<List<SysReportGroup>> GetList() public async Task<List<SysReportGroup>> GetList()
{ {
return await _rep.AsQueryable().OrderBy(u => u.Number).ToListAsync(); return await _reportGroupRep.AsQueryable().OrderBy(u => u.Number).ToListAsync();
} }
/// <summary> /// <summary>
@ -42,11 +38,11 @@ public class SysReportGroupService : IDynamicApiController, ITransient
[DisplayName("增加报表分组")] [DisplayName("增加报表分组")]
public async Task Add(AddReportGroupInput input) public async Task Add(AddReportGroupInput input)
{ {
var isExist = await _rep.IsAnyAsync(u => u.Number == input.Number && u.Id != input.Id); var isExist = await _reportGroupRep.IsAnyAsync(u => u.Number == input.Number && u.Id != input.Id);
if (isExist) if (isExist)
throw Oops.Bah(ErrorCodeEnum.C1003); throw Oops.Bah(ErrorCodeEnum.C1003);
await _rep.InsertAsync(input.Adapt<SysReportGroup>()); await _reportGroupRep.InsertAsync(input.Adapt<SysReportGroup>());
} }
/// <summary> /// <summary>
@ -59,11 +55,11 @@ public class SysReportGroupService : IDynamicApiController, ITransient
[DisplayName("更新报表分组")] [DisplayName("更新报表分组")]
public async Task Update(UpdateReportGroupInput input) public async Task Update(UpdateReportGroupInput input)
{ {
var isExist = await _rep.IsAnyAsync(u => u.Number == input.Number && u.Id != input.Id); var isExist = await _reportGroupRep.IsAnyAsync(u => u.Number == input.Number && u.Id != input.Id);
if (isExist) if (isExist)
throw Oops.Bah(ErrorCodeEnum.C1003); throw Oops.Bah(ErrorCodeEnum.C1003);
await _rep.UpdateAsync(input.Adapt<SysReportGroup>()); await _reportGroupRep.UpdateAsync(input.Adapt<SysReportGroup>());
} }
/// <summary> /// <summary>
@ -76,6 +72,6 @@ public class SysReportGroupService : IDynamicApiController, ITransient
[DisplayName("删除报表分组")] [DisplayName("删除报表分组")]
public async Task Delete(BaseIdInput input) public async Task Delete(BaseIdInput input)
{ {
await _rep.DeleteAsync(u => u.Id == input.Id); await _reportGroupRep.DeleteAsync(u => u.Id == input.Id);
} }
} }

View File

@ -10,7 +10,7 @@ using Newtonsoft.Json.Serialization;
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 首字母小写(驼峰样式)Converter /// 首字母小写(驼峰样式)转换
/// </summary> /// </summary>
public class CamelCaseValueConverter : JsonConverter public class CamelCaseValueConverter : JsonConverter
{ {

View File

@ -77,6 +77,49 @@ export const SysReportDataSourceApiAxiosParamCreator = function (configuration?:
options: localVarRequestOptions, options: localVarRequestOptions,
}; };
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysReportDataSourceDataSourceListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysReportDataSource/dataSourceList`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/** /**
* *
* @summary * @summary
@ -125,49 +168,6 @@ export const SysReportDataSourceApiAxiosParamCreator = function (configuration?:
options: localVarRequestOptions, options: localVarRequestOptions,
}; };
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysReportDataSourceGetDataSourceListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysReportDataSource/getDataSourceList`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/** /**
* *
* @summary * @summary
@ -289,13 +289,12 @@ export const SysReportDataSourceApiFp = function(configuration?: Configuration)
}, },
/** /**
* *
* @summary * @summary
* @param {BaseIdInput} [body]
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> { async apiSysReportDataSourceDataSourceListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>>> {
const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceDeletePost(body, options); const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceDataSourceListGet(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs); return axios.request(axiosRequestArgs);
@ -303,12 +302,13 @@ export const SysReportDataSourceApiFp = function(configuration?: Configuration)
}, },
/** /**
* *
* @summary * @summary
* @param {BaseIdInput} [body]
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async apiSysReportDataSourceGetDataSourceListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>>> { async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceGetDataSourceListGet(options); const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceDeletePost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs); return axios.request(axiosRequestArgs);
@ -361,6 +361,15 @@ export const SysReportDataSourceApiFactory = function (configuration?: Configura
async apiSysReportDataSourceAddPost(body?: AddReportDataSourceInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> { async apiSysReportDataSourceAddPost(body?: AddReportDataSourceInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysReportDataSourceApiFp(configuration).apiSysReportDataSourceAddPost(body, options).then((request) => request(axios, basePath)); return SysReportDataSourceApiFp(configuration).apiSysReportDataSourceAddPost(body, options).then((request) => request(axios, basePath));
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysReportDataSourceDataSourceListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>> {
return SysReportDataSourceApiFp(configuration).apiSysReportDataSourceDataSourceListGet(options).then((request) => request(axios, basePath));
},
/** /**
* *
* @summary * @summary
@ -371,15 +380,6 @@ export const SysReportDataSourceApiFactory = function (configuration?: Configura
async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> { async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysReportDataSourceApiFp(configuration).apiSysReportDataSourceDeletePost(body, options).then((request) => request(axios, basePath)); return SysReportDataSourceApiFp(configuration).apiSysReportDataSourceDeletePost(body, options).then((request) => request(axios, basePath));
}, },
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysReportDataSourceGetDataSourceListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>> {
return SysReportDataSourceApiFp(configuration).apiSysReportDataSourceGetDataSourceListGet(options).then((request) => request(axios, basePath));
},
/** /**
* *
* @summary * @summary
@ -421,6 +421,16 @@ export class SysReportDataSourceApi extends BaseAPI {
public async apiSysReportDataSourceAddPost(body?: AddReportDataSourceInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> { public async apiSysReportDataSourceAddPost(body?: AddReportDataSourceInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysReportDataSourceApiFp(this.configuration).apiSysReportDataSourceAddPost(body, options).then((request) => request(this.axios, this.basePath)); return SysReportDataSourceApiFp(this.configuration).apiSysReportDataSourceAddPost(body, options).then((request) => request(this.axios, this.basePath));
} }
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysReportDataSourceApi
*/
public async apiSysReportDataSourceDataSourceListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>> {
return SysReportDataSourceApiFp(this.configuration).apiSysReportDataSourceDataSourceListGet(options).then((request) => request(this.axios, this.basePath));
}
/** /**
* *
* @summary * @summary
@ -432,16 +442,6 @@ export class SysReportDataSourceApi extends BaseAPI {
public async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> { public async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysReportDataSourceApiFp(this.configuration).apiSysReportDataSourceDeletePost(body, options).then((request) => request(this.axios, this.basePath)); return SysReportDataSourceApiFp(this.configuration).apiSysReportDataSourceDeletePost(body, options).then((request) => request(this.axios, this.basePath));
} }
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysReportDataSourceApi
*/
public async apiSysReportDataSourceGetDataSourceListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>> {
return SysReportDataSourceApiFp(this.configuration).apiSysReportDataSourceGetDataSourceListGet(options).then((request) => request(this.axios, this.basePath));
}
/** /**
* *
* @summary * @summary

View File

@ -129,8 +129,8 @@ export const SysReportGroupApiAxiosParamCreator = function (configuration?: Conf
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
apiSysReportGroupGetListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => { apiSysReportGroupListGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysReportGroup/getList`; const localVarPath = `/api/sysReportGroup/list`;
// use dummy base URL string because the URL constructor only accepts absolute URLs. // use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com'); const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions; let baseOptions;
@ -257,8 +257,8 @@ export const SysReportGroupApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async apiSysReportGroupGetListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysReportGroup>>> { async apiSysReportGroupListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysReportGroup>>> {
const localVarAxiosArgs = await SysReportGroupApiAxiosParamCreator(configuration).apiSysReportGroupGetListGet(options); const localVarAxiosArgs = await SysReportGroupApiAxiosParamCreator(configuration).apiSysReportGroupListGet(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs); return axios.request(axiosRequestArgs);
@ -313,8 +313,8 @@ export const SysReportGroupApiFactory = function (configuration?: Configuration,
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async apiSysReportGroupGetListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysReportGroup>> { async apiSysReportGroupListGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysReportGroup>> {
return SysReportGroupApiFp(configuration).apiSysReportGroupGetListGet(options).then((request) => request(axios, basePath)); return SysReportGroupApiFp(configuration).apiSysReportGroupListGet(options).then((request) => request(axios, basePath));
}, },
/** /**
* *
@ -365,8 +365,8 @@ export class SysReportGroupApi extends BaseAPI {
* @throws {RequiredError} * @throws {RequiredError}
* @memberof SysReportGroupApi * @memberof SysReportGroupApi
*/ */
public async apiSysReportGroupGetListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysReportGroup>> { public async apiSysReportGroupListGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysReportGroup>> {
return SysReportGroupApiFp(this.configuration).apiSysReportGroupGetListGet(options).then((request) => request(this.axios, this.basePath)); return SysReportGroupApiFp(this.configuration).apiSysReportGroupListGet(options).then((request) => request(this.axios, this.basePath));
} }
/** /**
* *

View File

@ -114,5 +114,5 @@ export interface AddReportDataSourceInput {
* @type {string} * @type {string}
* @memberof AddReportDataSourceInput * @memberof AddReportDataSourceInput
*/ */
memo?: string | null; remark?: string | null;
} }

View File

@ -13,7 +13,7 @@
*/ */
/** /**
* *
* *
* @export * @export
* @interface SysReportDataSource * @interface SysReportDataSource
@ -114,5 +114,5 @@ export interface SysReportDataSource {
* @type {string} * @type {string}
* @memberof SysReportDataSource * @memberof SysReportDataSource
*/ */
memo?: string | null; remark?: string | null;
} }

View File

@ -13,7 +13,7 @@
*/ */
/** /**
* *
* *
* @export * @export
* @interface SysReportGroup * @interface SysReportGroup

View File

@ -114,5 +114,5 @@ export interface UpdateReportDataSourceInput {
* @type {string} * @type {string}
* @memberof UpdateReportDataSourceInput * @memberof UpdateReportDataSourceInput
*/ */
memo?: string | null; remark?: string | null;
} }

View File

@ -2,8 +2,7 @@
<div style="flex: 1; background: #f3f4f6; overflow: auto"> <div style="flex: 1; background: #f3f4f6; overflow: auto">
<el-container> <el-container>
<!-- 侧边栏 --> <!-- 侧边栏 -->
<el-aside v-show="!isFold" :class="isFold ? 'sidebar-fold' : 'expand-sidebar'" <el-aside v-show="!isFold" :class="isFold ? 'sidebar-fold' : 'expand-sidebar'" style="background: #f3f4f6; border-right: 1px solid #f0f0f0; display: flex; flex-direction: column">
style="background: #f3f4f6; border-right: 1px solid #f0f0f0; display: flex; flex-direction: column">
<div class="chat-action"> <div class="chat-action">
<el-tooltip :content="$t('message.chat.newChat')" placement="top"> <el-tooltip :content="$t('message.chat.newChat')" placement="top">
<div class="chat-action-item" @click.stop="handleNewChat"> <div class="chat-action-item" @click.stop="handleNewChat">
@ -16,23 +15,28 @@
</div> </div>
</el-tooltip> </el-tooltip>
</div> </div>
<div <div style="display: flex; flex-direction: column; align-items: center; padding-bottom: 8px; padding-top: 0px; margin-top: 0px">
style="display: flex; flex-direction: column; align-items: center; padding-bottom: 8px; padding-top: 0px; margin-top: 0px"> <el-avatar :size="60" style="background-color: #f3f4f6" src="/chat.png" fit="fill" class="avatar-with-shadow" />
<el-avatar :size="60" style="background-color: #f3f4f6" src="/chat.png" fit="fill" <div style="margin-top: 10px; font-weight: bold; font-size: 18px; color: #333">{{ $t('message.chat.title') }}</div>
class="avatar-with-shadow" />
<div style="margin-top: 10px; font-weight: bold; font-size: 18px; color: #333">{{
$t('message.chat.title') }}</div>
</div> </div>
<div style="flex: 1; overflow-y: auto; width: 100%"> <div style="flex: 1; overflow-y: auto; width: 100%">
<div style="display: flex; flex-direction: column; gap: 12px; height: 100%"> <div style="display: flex; flex-direction: column; gap: 12px; height: 100%">
<Conversations style="border-radius: 0%; width: 255px" v-model:active="activeHistoryKey" <Conversations
:items="sideBarHistoryList" row-key="key" :show-tooltip="true" showToTopBtn style="border-radius: 0%; width: 255px"
:label-max-width="210" :load-more="loadMoreHistoryItems" v-model:active="activeHistoryKey"
:load-more-loading="isHistoryListLoading" showBuiltInMenu @change="handleChange"> :items="sideBarHistoryList"
row-key="key"
:show-tooltip="true"
showToTopBtn
:label-max-width="210"
:load-more="loadMoreHistoryItems"
:load-more-loading="isHistoryListLoading"
showBuiltInMenu
@change="handleChange"
>
<template #menu="{ item }"> <template #menu="{ item }">
<div class="menu-buttons"> <div class="menu-buttons">
<el-button v-for="menuItem in actionMenuItems" :key="menuItem.key" link <el-button v-for="menuItem in actionMenuItems" :key="menuItem.key" link size="default" @click="handleMenuClick(menuItem.key, item)">
size="default" @click="handleMenuClick(menuItem.key, item)">
<el-icon v-if="menuItem.icon"> <el-icon v-if="menuItem.icon">
<component :is="menuItem.icon" /> <component :is="menuItem.icon" />
</el-icon> </el-icon>
@ -47,7 +51,8 @@
<!-- 主体内容 --> <!-- 主体内容 -->
<el-container> <el-container>
<el-main style=" <el-main
style="
flex: 1; flex: 1;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -60,12 +65,12 @@
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
background: #fff; background: #fff;
"> "
>
<div class="main_action_toolbar" style="position: absolute; top: 0px; width: 500px; left: 20px"> <div class="main_action_toolbar" style="position: absolute; top: 0px; width: 500px; left: 20px">
<div v-if="isFold" class="chat-action-item main_action_item"> <div v-if="isFold" class="chat-action-item main_action_item">
<el-tooltip :content="$t('message.chat.expandChat')" placement="top"> <el-tooltip :content="$t('message.chat.expandChat')" placement="top">
<Expand style="width: 1.5em; height: 1.5em; color: #333" <Expand style="width: 1.5em; height: 1.5em; color: #333" @click.stop="handleExpandChat" />
@click.stop="handleExpandChat" />
</el-tooltip> </el-tooltip>
</div> </div>
<div v-if="isFold" class="chat-action-item main_action_item" @click="handleNewChat"> <div v-if="isFold" class="chat-action-item main_action_item" @click="handleNewChat">
@ -83,12 +88,10 @@
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item v-for="item in modellList.models" :key="item.modelName" <el-dropdown-item v-for="item in modellList.models" :key="item.modelName" @click="handleChangeModel(item)">
@click="handleChangeModel(item)">
<div class="model-item"> <div class="model-item">
<span>{{ item.providerName }}/{{ item.modelName }}</span> <span>{{ item.providerName }}/{{ item.modelName }}</span>
<el-icon v-if="item.modelName == modellList.currentModel" <el-icon v-if="item.modelName == modellList.currentModel" style="color: #409eff">
style="color: #409eff">
<Select /> <Select />
</el-icon> </el-icon>
</div> </div>
@ -99,33 +102,21 @@
</div> </div>
</div> </div>
<div v-if="isNew" class="new_chat_title"> <div v-if="isNew" class="new_chat_title">
<div style="margin-top: 60px; font-size: 36px; font-weight: bold; letter-spacing: 2px">Hello, {{ <div style="margin-top: 60px; font-size: 36px; font-weight: bold; letter-spacing: 2px">Hello, {{ userName }}</div>
userName }} <div style="margin-top: 20px; width: 100%; text-align: center; color: #999; font-size: 16px; font-weight: bold; letter-spacing: 2px">
</div>
<div
style="margin-top: 20px; width: 100%; text-align: center; color: #999; font-size: 16px; font-weight: bold; letter-spacing: 2px">
{{ $t('message.chat.subTitle') }} {{ $t('message.chat.subTitle') }}
</div> </div>
</div> </div>
<div v-else class="chat_content"> <div v-else class="chat_content">
<BubbleList class="chat_content_list" ref="chatRef" :list="chatList" maxHeight="100%" <BubbleList class="chat_content_list" ref="chatRef" :list="chatList" maxHeight="100%" style="padding: 0 60px 100px 60px" @complete="handleBubbleComplete" :triggerIndices="triggerIndices">
style="padding: 0 60px 100px 60px" @complete="handleBubbleComplete"
:triggerIndices="triggerIndices">
<template #header="{ item }"> <template #header="{ item }">
<div v-if="item.role == 'assistant' && deepThinkingVisible && item.key == chatList[chatList.length - 1].key" <div v-if="item.role == 'assistant' && deepThinkingVisible && item.key == chatList[chatList.length - 1].key" class="header-wrapper">
class="header-wrapper"> <Thinking max-width="100%" buttonWidth="250px" autoCollapse :content="deepThinkingMessage" :status="deepThinkingStatus" backgroundColor="#fff9e6" color="#000">
<Thinking max-width="100%" buttonWidth="250px" autoCollapse
:content="deepThinkingMessage" :status="deepThinkingStatus"
backgroundColor="#fff9e6" color="#000">
<template #label="{ status }"> <template #label="{ status }">
<span v-if="status === 'start'">{{ $t('message.chat.startThinking') <span v-if="status === 'start'">{{ $t('message.chat.startThinking') }}</span>
}}</span> <span v-else-if="status === 'thinking'">{{ $t('message.chat.thinking') }}</span>
<span v-else-if="status === 'thinking'">{{ $t('message.chat.thinking') <span v-else-if="status === 'end'">{{ $t('message.chat.thinkingDone') }}</span>
}}</span> <span v-else-if="status === 'error'">{{ $t('message.chat.thinkingFailed') }}</span>
<span v-else-if="status === 'end'">{{ $t('message.chat.thinkingDone')
}}</span>
<span v-else-if="status === 'error'">{{ $t('message.chat.thinkingFailed')
}}</span>
</template> </template>
<template #content="{ content }"> <template #content="{ content }">
<span> <span>
@ -137,15 +128,12 @@
</template> </template>
<template #footer="{ item }"> <template #footer="{ item }">
<div v-if="item.role == 'assistant'" class="footer-container"> <div v-if="item.role == 'assistant'" class="footer-container">
<el-button type="info" text :icon="CopyDocument" size="small" <el-button type="info" text :icon="CopyDocument" size="small" @click="handleCopy(item)" />
@click="handleCopy(item)" />
<el-button type="info" text size="small"> <el-button type="info" text size="small">
<el-icon v-if="!isPlaying || playAudioKey != item.key" <el-icon v-if="!isPlaying || playAudioKey != item.key" @click="handlePlay(item)">
@click="handlePlay(item)">
<VideoPlay /> <VideoPlay />
</el-icon> </el-icon>
<el-icon v-if="isPlaying && playAudioKey == item.key" <el-icon v-if="isPlaying && playAudioKey == item.key" @click="handlePause(item)">
@click="handlePause(item)">
<VideoPause /> <VideoPause />
</el-icon> </el-icon>
</el-button> </el-button>
@ -154,9 +142,18 @@
</BubbleList> </BubbleList>
</div> </div>
<div :class="isNew ? 'chat_new_input_style' : 'chat_edit_input_style'"> <div :class="isNew ? 'chat_new_input_style' : 'chat_edit_input_style'">
<sender ref="senderRef" variant="updown" clearable allow-speech :loading="isSenderLoading" <sender
:read-only="isSenderLoading" :auto-size="{ minRows: 1, maxRows: 5 }" v-model="senderInput" ref="senderRef"
@submit="handleSend" :placeholder="$t('message.chat.inputPlaceholder')"> variant="updown"
clearable
allow-speech
:loading="isSenderLoading"
:read-only="isSenderLoading"
:auto-size="{ minRows: 1, maxRows: 5 }"
v-model="senderInput"
@submit="handleSend"
:placeholder="$t('message.chat.inputPlaceholder')"
>
<template #prefix> <template #prefix>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap"> <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
<el-button round plain> <el-button round plain>
@ -165,9 +162,11 @@
</el-icon> </el-icon>
</el-button> </el-button>
<div :class="{ isDeepThinking }" <div
:class="{ isDeepThinking }"
style="display: flex; align-items: center; gap: 4px; padding: 4px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px" style="display: flex; align-items: center; gap: 4px; padding: 4px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px"
@click="handleDeepThinking"> @click="handleDeepThinking"
>
<el-icon> <el-icon>
<ElementPlus /> <ElementPlus />
</el-icon> </el-icon>
@ -188,12 +187,10 @@
<div class="ai-rename-icon ai-rename-drag" @mousedown="startDrag"> <div class="ai-rename-icon ai-rename-drag" @mousedown="startDrag">
<el-avatar :size="48" src="/chat.png" /> <el-avatar :size="48" src="/chat.png" />
</div> </div>
<el-input v-model="renameInput" @keyup.enter="confirmRename" ref="renameInputRef" <el-input v-model="renameInput" @keyup.enter="confirmRename" ref="renameInputRef" class="ai-rename-input" />
class="ai-rename-input" />
</div> </div>
<div class="ai-dialog-footer"> <div class="ai-dialog-footer">
<el-button @click="cancelRename" class="ai-btn-cancel">{{ $t('message.chat.cancel') <el-button @click="cancelRename" class="ai-btn-cancel">{{ $t('message.chat.cancel') }}</el-button>
}}</el-button>
<el-button type="primary" @click="confirmRename" class="ai-btn-confirm"> <el-button type="primary" @click="confirmRename" class="ai-btn-confirm">
{{ $t('message.chat.confirm') }} {{ $t('message.chat.confirm') }}
</el-button> </el-button>
@ -302,13 +299,13 @@ const initSSEConnection = () => {
monitorSSEConnectionHandler = setInterval(() => { monitorSSEConnectionHandler = setInterval(() => {
isSSEConnectionClosed = Date.now() - lastSseConnectionTime > SSE_CONNECTION_TIMEOUT; isSSEConnectionClosed = Date.now() - lastSseConnectionTime > SSE_CONNECTION_TIMEOUT;
if (isSSEConnectionClosed) { if (isSSEConnectionClosed) {
console.log("SSE connection timed out, reconnecting"); console.log('SSE connection timed out, reconnecting');
try { try {
initSSEConnectionCore(); initSSEConnectionCore();
} catch (err) { } catch (err) {
console.log("SSE connection timed out, reconnecting failed", err); console.log('SSE connection timed out, reconnecting failed', err);
} }
} }
}, SSE_CONNECTION_TIMEOUT); }, SSE_CONNECTION_TIMEOUT);
}; };
@ -318,7 +315,7 @@ const checkSSEConnectionStatus = () => {
return false; return false;
} }
return true; return true;
} };
// sse // sse
const initSSEConnectionCore = () => { const initSSEConnectionCore = () => {
closeSSEConnection(); closeSSEConnection();
@ -368,12 +365,10 @@ const initSSEConnectionCore = () => {
lastSseConnectionTime = Date.now(); lastSseConnectionTime = Date.now();
}); });
eventSource.onerror = () => { eventSource.onerror = () => {
console.log('SSE connection error'); console.log('SSE connection error');
}; };
eventSource.onopen = (event) => { eventSource.onopen = (event) => {
console.log('SSE connection opened:', event); console.log('SSE connection opened:', event);
}; };
@ -671,8 +666,6 @@ const loadMoreHistoryItems = async () => {
isHistoryListLoading.value = false; isHistoryListLoading.value = false;
}; };
const handleMenuClick = (menuKey: string, item: any) => { const handleMenuClick = (menuKey: string, item: any) => {
switch (menuKey) { switch (menuKey) {
case 'rename': case 'rename':

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="90%"> <el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" fullscreen>
<template #header> <template #header>
<div style="color: #fff"> <div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon> <el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
@ -95,7 +95,7 @@
</template> </template>
<template #toolbar_tools> </template> <template #toolbar_tools> </template>
</vxe-grid> </vxe-grid>
<el-card style="margin-left: 4px" :header="$t('内置参数')" headerClass="sys-report-config-param-build-in-card-header"> <el-card shadow="hover" style="margin-left: 4px" :header="$t('内置参数')" headerClass="sys-report-config-param-build-in-card-header">
<el-row style="width: 240px" v-for="(item, index) in buildInParams" :key="index"> <el-row style="width: 240px" v-for="(item, index) in buildInParams" :key="index">
<el-col :span="11">{{ item.name }}</el-col> <el-col :span="11">{{ item.name }}</el-col>
<el-col :span="13">{{ item.description }}</el-col> <el-col :span="13">{{ item.description }}</el-col>
@ -117,19 +117,20 @@
<script setup lang="ts" name="sysReportConfigEditForm"> <script setup lang="ts" name="sysReportConfigEditForm">
import { computed, onMounted, reactive, ref } from 'vue'; import { computed, onMounted, reactive, ref } from 'vue';
import { ElInput, ElMessage } from 'element-plus'; import { ElInput, ElMessage } from 'element-plus';
import { getAPI } from '/@/utils/axios-utils';
import { ReportConfigDsTypeEnum, ReportDataSourceOutput, SysReportField, SysReportGroup, SysReportParam, UpdateReportConfigInput } from '/@/api-services';
import { SysReportConfigApi, SysReportDataSourceApi, SysReportGroupApi } from '/@/api-services/api';
import { VxeGrid } from 'vxe-table'; import { VxeGrid } from 'vxe-table';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import { format } from 'sql-formatter'; import { format } from 'sql-formatter';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { sqlSugarDbTypes } from '../inputCtrlType'; import { sqlSugarDbTypes } from '../inputCtrlType';
import { getAPI } from '/@/utils/axios-utils';
import { SysReportConfigApi, SysReportDataSourceApi, SysReportGroupApi } from '/@/api-services/api';
import { ReportConfigDsTypeEnum, ReportDataSourceOutput, SysReportField, SysReportGroup, SysReportParam, UpdateReportConfigInput } from '/@/api-services/models';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps({ const props = defineProps({
@ -394,7 +395,7 @@ const rules = computed(() => {
onMounted(() => { onMounted(() => {
getAPI(SysReportDataSourceApi) getAPI(SysReportDataSourceApi)
.apiSysReportDataSourceGetDataSourceListGet() .apiSysReportDataSourceDataSourceListGet()
.then((result) => { .then((result) => {
if (result.data.type !== 'success') { if (result.data.type !== 'success') {
return; return;
@ -403,7 +404,7 @@ onMounted(() => {
state.dataSourceList = result.data.result!; state.dataSourceList = result.data.result!;
}); });
getAPI(SysReportGroupApi) getAPI(SysReportGroupApi)
.apiSysReportGroupGetListGet() .apiSysReportGroupListGet()
.then((res) => { .then((res) => {
state.groupList = res.data.result!; state.groupList = res.data.result!;
}); });
@ -561,6 +562,7 @@ const remove = async (grid: InstanceType<typeof VxeGrid>): Promise<void> => {
// //
defineExpose({ openDialog }); defineExpose({ openDialog });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-dialog__body) { :deep(.el-dialog__body) {
height: calc(100vh - 18px) !important; height: calc(100vh - 18px) !important;
@ -587,6 +589,7 @@ defineExpose({ openDialog });
flex: 1; flex: 1;
} }
</style> </style>
<style lang="scss"> <style lang="scss">
.sys-report-config-param-build-in-card-header { .sys-report-config-param-build-in-card-header {
padding: 8px; padding: 8px;

View File

@ -31,9 +31,10 @@
<script setup lang="ts" name="sysReportGroupEditForm"> <script setup lang="ts" name="sysReportGroupEditForm">
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { getAPI } from '/@/utils/axios-utils'; import { getAPI } from '/@/utils/axios-utils';
import { UpdateReportGroupInput } from '/@/api-services';
import { SysReportGroupApi } from '/@/api-services/api'; import { SysReportGroupApi } from '/@/api-services/api';
import { UpdateReportGroupInput } from '/@/api-services/models';
const props = defineProps({ const props = defineProps({
title: String, title: String,

View File

@ -7,7 +7,7 @@
<template v-slot:dropdown> <template v-slot:dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="del" :icon="Minus">{{ $t('删除分组') }}</el-dropdown-item> <el-dropdown-item command="del" :icon="Minus">{{ $t('删除分组') }}</el-dropdown-item>
<el-dropdown-item command="refresh" :icon="RefreshRight">{{ $t('刷新') }}</el-dropdown-item> <el-dropdown-item command="refresh" :icon="RefreshRight">{{ $t('刷新分组') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@ -30,17 +30,21 @@
</div> </div>
</el-scrollbar> </el-scrollbar>
</el-card> </el-card>
<EditReportGroup ref="editReportGroup" :title="state.title" @handleQuery="handleQuery"></EditReportGroup> <EditReportGroup ref="editReportGroup" :title="state.title" @handleQuery="handleQuery"></EditReportGroup>
</div> </div>
</template> </template>
<script setup lang="ts" name="sysReportGroup"> <script setup lang="ts" name="sysReportGroup">
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import EditReportGroup from './editReportGroup.vue';
import { Minus, RefreshRight } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox, ElTree } from 'element-plus'; import { ElMessage, ElMessageBox, ElTree } from 'element-plus';
import { Minus, RefreshRight } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import EditReportGroup from './editReportGroup.vue';
import { getAPI } from '/@/utils/axios-utils'; import { getAPI } from '/@/utils/axios-utils';
import { SysReportGroup, SysReportGroupApi } from '/@/api-services'; import { SysReportGroup, SysReportGroupApi } from '/@/api-services';
import { useI18n } from 'vue-i18n';
const { t } = useI18n(); const { t } = useI18n();
@ -68,7 +72,7 @@ onMounted(() => {
const getGroupTree = () => { const getGroupTree = () => {
state.isLoading = true; state.isLoading = true;
getAPI(SysReportGroupApi) getAPI(SysReportGroupApi)
.apiSysReportGroupGetListGet() .apiSysReportGroupListGet()
.then((res) => { .then((res) => {
getTree(res.data.result ?? []); getTree(res.data.result ?? []);
let rootGroup = [{ id: 0, label: t('全部'), value: 0, children: [] }]; let rootGroup = [{ id: 0, label: t('全部'), value: 0, children: [] }];
@ -147,6 +151,7 @@ const handleQuery = () => {
getGroupTree(); getGroupTree();
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.group-panel { .group-panel {
background-color: var(--el-fill-color-blank); background-color: var(--el-fill-color-blank);
@ -156,6 +161,7 @@ const handleQuery = () => {
.group-panel-buttonGroup { .group-panel-buttonGroup {
width: 100%; width: 100%;
padding: 5px 0 10px 0;
} }
.group-panel-tree { .group-panel-tree {

View File

@ -12,18 +12,20 @@
</el-card> </el-card>
</div> </div>
</template> </template>
<script setup lang="ts" name="sysReportView"> <script setup lang="ts" name="sysReportView">
import { onBeforeMount, reactive, ref, watch } from 'vue'; import { onBeforeMount, reactive, ref, watch } from 'vue';
import { VxeGridInstance, VxeGridPropTypes, VxeTableDefines, VxeTablePropTypes } from 'vxe-table';
import TableSearch from '/@/components/table/search.vue';
import { SysReportConfigApi } from '/@/api-services/api';
import { getAPI } from '/@/utils/axios-utils';
import { downloadByData, getFileName } from '/@/utils/download';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { VxeGridInstance, VxeGridPropTypes, VxeTableDefines, VxeTablePropTypes } from 'vxe-table';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { SysReportField, SysReportLayoutConfig, SysReportParam } from '/@/api-services'; import TableSearch from '/@/components/table/search.vue';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook'; // import { downloadByData, getFileName } from '/@/utils/download';
import { getAPI } from '/@/utils/axios-utils';
import { SysReportConfigApi } from '/@/api-services/api';
import { SysReportField, SysReportLayoutConfig, SysReportParam } from '/@/api-services/models';
const { t } = useI18n(); const { t } = useI18n();
@ -227,4 +229,5 @@ const convertSysReportParamToTableSearchType = (column: SysReportParam) => {
} as TableSearchType; } as TableSearchType;
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -60,24 +60,29 @@
</el-card> </el-card>
</pane> </pane>
</splitpanes> </splitpanes>
<EditReportConfig ref="editRef" :title="state.title" @handleQuery="handleQuery" /> <EditReportConfig ref="editRef" :title="state.title" @handleQuery="handleQuery" />
</div> </div>
</template> </template>
<script setup lang="ts" name="sysReportConfig"> <script setup lang="ts" name="sysReportConfig">
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table'; import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook'; import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { Local } from '/@/utils/storage'; import { Local } from '/@/utils/storage';
import ReportGroupPanel from './component/reportGroupPanel/index.vue'; import { useRouter } from 'vue-router';
import EditReportConfig from '/@/views/system/reportConfig/component/editReportConfig.vue'; import { useI18n } from 'vue-i18n';
import { Splitpanes, Pane } from 'splitpanes'; import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css'; import 'splitpanes/dist/splitpanes.css';
import ReportGroupPanel from './component/reportGroupPanel/index.vue';
import EditReportConfig from '/@/views/system/reportConfig/component/editReportConfig.vue';
import ModifyRecord from '/@/components/table/modifyRecord.vue'; import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { useI18n } from 'vue-i18n';
import { getAPI } from '/@/utils/axios-utils'; import { getAPI } from '/@/utils/axios-utils';
import { PageReportConfigInput, ReportConfigDsTypeEnum, ReportConfigOutput, ReportDataSourceOutput, SysReportConfigApi, SysReportDataSourceApi, SysReportGroup } from '/@/api-services'; import { SysReportConfigApi, SysReportDataSourceApi } from '/@/api-services/api';
import { useRouter } from 'vue-router'; import { PageReportConfigInput, ReportConfigDsTypeEnum, ReportConfigOutput, ReportDataSourceOutput, SysReportGroup } from '/@/api-services/models';
const { t } = useI18n(); const { t } = useI18n();
@ -100,18 +105,6 @@ const state = reactive({
dataSourceList: [] as ReportDataSourceOutput[], dataSourceList: [] as ReportDataSourceOutput[],
}); });
onMounted(() => {
getAPI(SysReportDataSourceApi)
.apiSysReportDataSourceGetDataSourceListGet()
.then((result) => {
if (result.data.type !== 'success') {
return;
}
state.dataSourceList = result.data.result!;
});
});
// //
const localPageParamKey = 'localPageParam:sysReportConfig'; const localPageParamKey = 'localPageParam:sysReportConfig';
// //
@ -121,10 +114,11 @@ const options = useVxeTable<ReportConfigOutput>(
name: '报表数据源', name: '报表数据源',
columns: [ columns: [
{ field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' }, { field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' },
{ field: 'name', title: '名称', width: 200, showOverflow: 'tooltip' }, { field: 'name', title: '名称', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'dsType', title: '数据源类型', width: 100, showOverflow: 'tooltip', slots: { default: 'row_dsType' } }, { field: 'dsType', title: '数据源类型', minWidth: 100, showOverflow: 'tooltip', slots: { default: 'row_dsType' } },
{ field: 'dataSource', title: '数据源', width: 200, showOverflow: 'tooltip', slots: { default: 'row_dataSource' } }, { field: 'dataSource', title: '数据源', showOverflow: 'tooltip', slots: { default: 'row_dataSource' } },
{ field: 'groupName', title: '分组名称', width: 150, showOverflow: 'tooltip' }, { field: 'groupName', title: '分组名称', showOverflow: 'tooltip' },
{ field: 'record', title: '修改记录', width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } }, { field: 'record', title: '修改记录', width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 200, showOverflow: true, slots: { default: 'row_buttons' } }, { field: 'buttons', title: '操作', fixed: 'right', width: 200, showOverflow: true, slots: { default: 'row_buttons' } },
], ],
@ -139,14 +133,21 @@ const options = useVxeTable<ReportConfigOutput>(
pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize }, pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize },
// //
toolbarConfig: { export: false, print: false }, toolbarConfig: { export: false, print: false },
columnConfig: {
width: 120, //
},
} }
); );
// //
onMounted(() => { onMounted(() => {
getAPI(SysReportDataSourceApi)
.apiSysReportDataSourceDataSourceListGet()
.then((result) => {
if (result.data.type !== 'success') {
return;
}
state.dataSourceList = result.data.result!;
});
state.localPageParam = Local.get(localPageParamKey) || state.localPageParam; state.localPageParam = Local.get(localPageParamKey) || state.localPageParam;
}); });
@ -227,11 +228,13 @@ const copy = (row: any) => {
ElMessage.success(t('复制成功')); ElMessage.success(t('复制成功'));
}); });
}; };
/** 预览 */ /** 预览 */
const preview = (row: any) => { const preview = (row: any) => {
router.push(`/report/view/${row.id}/${encodeURIComponent(row.name)}`); router.push(`/report/view/${row.id}/${encodeURIComponent(row.name)}`);
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.pane-left { .pane-left {
display: flex; display: flex;

View File

@ -21,13 +21,13 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item :label="$t('连接字符串')" prop="connectionString"> <el-form-item :label="$t('连接字符串')">
<el-input v-model="state.ruleForm.connectionString" type="textarea" :autosize="{ minRows: 6 }" :placeholder="$t('编辑时置空则不更新值')" /> <el-input v-model="state.ruleForm.connectionString" type="textarea" :autosize="{ minRows: 6 }" :placeholder="$t('编辑时置空则不更新值')" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item :label="$t('备注')" prop="memo"> <el-form-item :label="$t('备注')">
<el-input v-model="state.ruleForm.memo" clearable /> <el-input v-model="state.ruleForm.remark" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -44,11 +44,13 @@
<script setup lang="ts" name="sysReportDataSourceEditForm"> <script setup lang="ts" name="sysReportDataSourceEditForm">
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { ElInput } from 'element-plus'; import { ElInput } from 'element-plus';
import { getAPI } from '/@/utils/axios-utils';
import { UpdateReportDataSourceInput } from '/@/api-services';
import { SysReportDataSourceApi } from '/@/api-services/api';
import { sqlSugarDbTypes } from '.././sqlSugarDbType'; import { sqlSugarDbTypes } from '.././sqlSugarDbType';
import { getAPI } from '/@/utils/axios-utils';
import { SysReportDataSourceApi } from '/@/api-services/api';
import { UpdateReportDataSourceInput } from '/@/api-services/models';
const props = defineProps({ const props = defineProps({
title: String, title: String,
}); });

View File

@ -48,22 +48,27 @@
</template> </template>
</vxe-grid> </vxe-grid>
</el-card> </el-card>
<EditReportDataSource ref="editRef" :title="state.title" @handleQuery="handleQuery" /> <EditReportDataSource ref="editRef" :title="state.title" @handleQuery="handleQuery" />
</div> </div>
</template> </template>
<script setup lang="ts" name="sysReportDataSource"> <script setup lang="ts" name="sysReportDataSource">
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table'; import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook'; import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { Local } from '/@/utils/storage'; import { Local } from '/@/utils/storage';
import { useI18n } from 'vue-i18n';
import EditReportDataSource from '/@/views/system/reportDataSource/component/editReportDataSource.vue'; import EditReportDataSource from '/@/views/system/reportDataSource/component/editReportDataSource.vue';
import ModifyRecord from '/@/components/table/modifyRecord.vue'; import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { useI18n } from 'vue-i18n';
import { getAPI } from '/@/utils/axios-utils';
import { PageReportDataSourceInput, SysReportDataSource, SysReportDataSourceApi } from '/@/api-services';
import { sqlSugarDbTypes } from './sqlSugarDbType'; import { sqlSugarDbTypes } from './sqlSugarDbType';
import { getAPI } from '/@/utils/axios-utils';
import { SysReportDataSourceApi } from '/@/api-services/api';
import { PageReportDataSourceInput, SysReportDataSource } from '/@/api-services/models';
const { t } = useI18n(); const { t } = useI18n();
const xGrid = ref<VxeGridInstance>(); const xGrid = ref<VxeGridInstance>();
@ -88,10 +93,11 @@ const options = useVxeTable<SysReportDataSource>(
name: '报表数据源', name: '报表数据源',
columns: [ columns: [
{ field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' }, { field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' },
{ field: 'name', title: '名称', width: 200, showOverflow: 'tooltip' }, { field: 'name', title: '名称', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'dbType', title: '数据库类型', width: 100, showOverflow: 'tooltip', slots: { default: 'row_dbType' } }, { field: 'dbType', title: '数据库类型', minWidth: 100, showOverflow: 'tooltip', slots: { default: 'row_dbType' } },
{ field: 'connectionString', title: '连接字符串', width: 400, showOverflow: 'tooltip' }, { field: 'connectionString', title: '连接字符串', minWidth: 400, showOverflow: 'tooltip' },
{ field: 'memo', title: '备注', width: 200, showOverflow: 'tooltip' }, { field: 'memo', title: '备注', showOverflow: 'tooltip' },
{ field: 'record', title: '修改记录', width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } }, { field: 'record', title: '修改记录', width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 100, showOverflow: true, slots: { default: 'row_buttons' } }, { field: 'buttons', title: '操作', fixed: 'right', width: 100, showOverflow: true, slots: { default: 'row_buttons' } },
], ],
@ -106,9 +112,6 @@ const options = useVxeTable<SysReportDataSource>(
pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize }, pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize },
// //
toolbarConfig: { export: false, print: false }, toolbarConfig: { export: false, print: false },
columnConfig: {
width: 120, //
},
} }
); );
@ -177,4 +180,5 @@ const gridEvents: VxeGridListeners<SysReportDataSource> = {
}, },
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>