using Admin.NET.Core; using Admin.NET.Plugin.AiDOP.Dto.SmartOps; using Admin.NET.Plugin.AiDOP.Entity; using SqlSugar; namespace Admin.NET.Plugin.AiDOP.SmartOps; /// /// KPI 计算运行日志查询(只读、分页、脱敏)。租户由 MetricCode 解析,不信任前端; /// 输出仅可展示字段,不返回 SQL 明文 / 参数快照 / 连接串;错误摘要截断。 /// public sealed class AdoSmartOpsKpiRunLogQueryService : ITransient { private const int DefaultPageSize = 20; private const int MaxPageSize = 100; private const int ErrorMessageMaxLen = 300; private readonly ISqlSugarClient _db; public AdoSmartOpsKpiRunLogQueryService(ISqlSugarClient db) { _db = db; } public async Task QueryAsync(KpiRunLogQueryDto dto) { if (string.IsNullOrWhiteSpace(dto.MetricCode)) throw Oops.Bah("metricCode 必填"); var moduleCode = AdoSmartOpsKpiBusinessInputService.ResolveModuleCode(dto.MetricCode); var tenantId = AdoSmartOpsKpiCalcConfigService.ResolveKpiTenantId(moduleCode); var page = dto.Page <= 0 ? 1 : dto.Page; var pageSize = dto.PageSize <= 0 ? DefaultPageSize : Math.Min(dto.PageSize, MaxPageSize); var status = string.IsNullOrWhiteSpace(dto.Status) ? null : dto.Status.Trim().ToUpperInvariant(); RefAsync total = 0; var rows = await _db.Queryable().ClearFilter() .Where(x => x.MetricCode == dto.MetricCode && x.TenantId == tenantId) .WhereIF(status != null, x => x.Status == status) .WhereIF(dto.StartTime != null, x => x.StartedAt >= dto.StartTime!.Value) .WhereIF(dto.EndTime != null, x => x.StartedAt <= dto.EndTime!.Value) .OrderBy(x => x.StartedAt, OrderByType.Desc) .ToPageListAsync(page, pageSize, total); return new KpiRunLogPageDto { Total = total.Value, Page = page, PageSize = pageSize, List = rows.Select(ToItem).ToList(), }; } private static KpiRunLogItemDto ToItem(AdoSmartOpsKpiCalcRunLog e) => new() { Id = e.Id, BatchId = e.BatchId, MetricCode = e.MetricCode, EngineType = e.EngineType, VersionNo = e.VersionNo, DataSourceCode = e.DataSourceCode, BizDate = e.BizDate.ToString("yyyy-MM-dd"), StartedAt = e.StartedAt.ToString("yyyy-MM-dd HH:mm:ss"), DurationMs = e.DurationMs, Status = e.Status, RowCount = e.RowCount, MetricValue = e.MetricValue, ErrorCode = e.ErrorCode, ErrorMessage = Truncate(e.ErrorMessage, ErrorMessageMaxLen), TriggerType = e.TriggerType, }; private static string? Truncate(string? s, int max) => string.IsNullOrEmpty(s) ? s : (s.Length <= max ? s : s.Substring(0, max) + "…"); }