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

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("Connection", "keep-alive");
Response.Headers.Append("X-Accel-Buffering", "no"); // Nginx
var channel = _sseChannelManager.Register(id);
var deepThinkingChannel = _sseDeepThinkingChannelManager.Register(id);
try

View File

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

View File

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

View File

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

View File

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

View File

@ -9,24 +9,21 @@ using Furion.Localization;
namespace Admin.NET.Core.Service;
/// <summary>
/// 报表数据源服务
/// 系统报表数据源服务
/// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表数据源")]
public class SysReportDataSourceService : IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<SysReportDataSource> _rep;
private readonly SqlSugarRepository<SysReportDataSource> _reportDataSourceRep;
private readonly SqlSugarRepository<SysTenant> _tenantRep;
private readonly ISqlSugarClient _db;
/// <summary>
/// 报表数据源服务构造函数
/// </summary>
public SysReportDataSourceService(SqlSugarRepository<SysReportDataSource> rep,
public SysReportDataSourceService(SqlSugarRepository<SysReportDataSource> reportDataSourceRep,
SqlSugarRepository<SysTenant> tenantRep,
ISqlSugarClient db
)
{
_rep = rep;
_reportDataSourceRep = reportDataSourceRep;
_tenantRep = tenantRep;
_db = db;
}
@ -39,7 +36,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("获取报表数据源分页列表")]
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()))
.Select(u => new SysReportDataSource(), true)
.OrderBuilder(input)
@ -60,11 +57,11 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("增加报表数据源")]
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)
throw Oops.Bah(ErrorCodeEnum.C1000);
await _rep.InsertAsync(input.Adapt<SysReportDataSource>());
await _reportDataSourceRep.InsertAsync(input.Adapt<SysReportDataSource>());
}
/// <summary>
@ -77,7 +74,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("更新报表数据源")]
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)
throw Oops.Bah(ErrorCodeEnum.C1000);
@ -90,7 +87,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
// updateEntity.ConnectionString = entity.ConnectionString;
// }
await _rep.UpdateAsync(updateEntity);
await _reportDataSourceRep.UpdateAsync(updateEntity);
}
/// <summary>
@ -103,7 +100,7 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
[DisplayName("删除报表数据源")]
public async Task Delete(BaseIdInput input)
{
await _rep.DeleteAsync(u => u.Id == input.Id);
await _reportDataSourceRep.DeleteAsync(u => u.Id == input.Id);
}
/// <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)
{
list.Add(new SysReportDataSourceDetail
@ -171,7 +168,6 @@ public class SysReportDataSourceService : IDynamicApiController, ITransient
/// <summary>
/// 获取报表数据源列表
/// </summary>
[ApiDescriptionSettings(Name = "GetDataSourceList"), HttpGet]
[DisplayName("获取报表数据源列表")]
public async Task<List<ReportDataSourceOutput>> GetDataSourceList()
{

View File

@ -7,30 +7,26 @@
namespace Admin.NET.Core.Service;
/// <summary>
/// 报表分组服务
/// 系统报表分组服务
/// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表分组")]
public class SysReportGroupService : IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<SysReportGroup> _rep;
private readonly SqlSugarRepository<SysReportGroup> _reportGroupRep;
/// <summary>
/// 报表分组服务构造函数
/// </summary>
public SysReportGroupService(SqlSugarRepository<SysReportGroup> rep)
public SysReportGroupService(SqlSugarRepository<SysReportGroup> reportGroupRep)
{
_rep = rep;
_reportGroupRep = reportGroupRep;
}
/// <summary>
/// 获取报表分组列表
/// </summary>
/// <returns></returns>
[ApiDescriptionSettings(Name = "GetList"), HttpGet]
[DisplayName("获取报表分组列表")]
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>
@ -42,11 +38,11 @@ public class SysReportGroupService : IDynamicApiController, ITransient
[DisplayName("增加报表分组")]
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)
throw Oops.Bah(ErrorCodeEnum.C1003);
await _rep.InsertAsync(input.Adapt<SysReportGroup>());
await _reportGroupRep.InsertAsync(input.Adapt<SysReportGroup>());
}
/// <summary>
@ -59,11 +55,11 @@ public class SysReportGroupService : IDynamicApiController, ITransient
[DisplayName("更新报表分组")]
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)
throw Oops.Bah(ErrorCodeEnum.C1003);
await _rep.UpdateAsync(input.Adapt<SysReportGroup>());
await _reportGroupRep.UpdateAsync(input.Adapt<SysReportGroup>());
}
/// <summary>
@ -76,6 +72,6 @@ public class SysReportGroupService : IDynamicApiController, ITransient
[DisplayName("删除报表分组")]
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;
/// <summary>
/// 首字母小写(驼峰样式)Converter
/// 首字母小写(驼峰样式)转换
/// </summary>
public class CamelCaseValueConverter : JsonConverter
{

View File

@ -77,6 +77,49 @@ export const SysReportDataSourceApiAxiosParamCreator = function (configuration?:
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
@ -125,49 +168,6 @@ export const SysReportDataSourceApiAxiosParamCreator = function (configuration?:
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
@ -289,13 +289,12 @@ export const SysReportDataSourceApiFp = function(configuration?: Configuration)
},
/**
*
* @summary
* @param {BaseIdInput} [body]
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceDeletePost(body, options);
async apiSysReportDataSourceDataSourceListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>>> {
const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceDataSourceListGet(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
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.
* @throws {RequiredError}
*/
async apiSysReportDataSourceGetDataSourceListGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListReportDataSourceOutput>>> {
const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceGetDataSourceListGet(options);
async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysReportDataSourceApiAxiosParamCreator(configuration).apiSysReportDataSourceDeletePost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
@ -361,6 +361,15 @@ export const SysReportDataSourceApiFactory = function (configuration?: Configura
async apiSysReportDataSourceAddPost(body?: AddReportDataSourceInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
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
@ -371,15 +380,6 @@ export const SysReportDataSourceApiFactory = function (configuration?: Configura
async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
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
@ -421,6 +421,16 @@ export class SysReportDataSourceApi extends BaseAPI {
public async apiSysReportDataSourceAddPost(body?: AddReportDataSourceInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
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
@ -432,16 +442,6 @@ export class SysReportDataSourceApi extends BaseAPI {
public async apiSysReportDataSourceDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<template>
<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>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
@ -95,7 +95,7 @@
</template>
<template #toolbar_tools> </template>
</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-col :span="11">{{ item.name }}</el-col>
<el-col :span="13">{{ item.description }}</el-col>
@ -117,19 +117,20 @@
<script setup lang="ts" name="sysReportConfigEditForm">
import { computed, onMounted, reactive, ref } from 'vue';
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 { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { useI18n } from 'vue-i18n';
import * as monaco from 'monaco-editor';
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import { format } from 'sql-formatter';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
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 props = defineProps({
@ -394,7 +395,7 @@ const rules = computed(() => {
onMounted(() => {
getAPI(SysReportDataSourceApi)
.apiSysReportDataSourceGetDataSourceListGet()
.apiSysReportDataSourceDataSourceListGet()
.then((result) => {
if (result.data.type !== 'success') {
return;
@ -403,7 +404,7 @@ onMounted(() => {
state.dataSourceList = result.data.result!;
});
getAPI(SysReportGroupApi)
.apiSysReportGroupGetListGet()
.apiSysReportGroupListGet()
.then((res) => {
state.groupList = res.data.result!;
});
@ -561,6 +562,7 @@ const remove = async (grid: InstanceType<typeof VxeGrid>): Promise<void> => {
//
defineExpose({ openDialog });
</script>
<style lang="scss" scoped>
:deep(.el-dialog__body) {
height: calc(100vh - 18px) !important;
@ -587,6 +589,7 @@ defineExpose({ openDialog });
flex: 1;
}
</style>
<style lang="scss">
.sys-report-config-param-build-in-card-header {
padding: 8px;

View File

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

View File

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

View File

@ -12,18 +12,20 @@
</el-card>
</div>
</template>
<script setup lang="ts" name="sysReportView">
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 { VxeGridInstance, VxeGridPropTypes, VxeTableDefines, VxeTablePropTypes } from 'vxe-table';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { SysReportField, SysReportLayoutConfig, SysReportParam } from '/@/api-services';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import TableSearch from '/@/components/table/search.vue';
// 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();
@ -227,4 +229,5 @@ const convertSysReportParamToTableSearchType = (column: SysReportParam) => {
} as TableSearchType;
};
</script>
<style scoped lang="scss"></style>

View File

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

View File

@ -21,13 +21,13 @@
</el-form-item>
</el-col>
<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-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item :label="$t('备注')" prop="memo">
<el-input v-model="state.ruleForm.memo" clearable />
<el-form-item :label="$t('备注')">
<el-input v-model="state.ruleForm.remark" clearable />
</el-form-item>
</el-col>
</el-row>
@ -44,11 +44,13 @@
<script setup lang="ts" name="sysReportDataSourceEditForm">
import { reactive, ref } from 'vue';
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 { getAPI } from '/@/utils/axios-utils';
import { SysReportDataSourceApi } from '/@/api-services/api';
import { UpdateReportDataSourceInput } from '/@/api-services/models';
const props = defineProps({
title: String,
});

View File

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