using Admin.NET.Plugin.AiDOP.Dto.S8; using Admin.NET.Plugin.AiDOP.Infrastructure; using Admin.NET.Plugin.AiDOP.Service.S8; namespace Admin.NET.Plugin.AiDOP.Controllers.S8; [ApiController] [Route("api/aidop/s8/dashboard")] [NonUnify] public class AdoS8DashboardController : ControllerBase { private readonly S8DashboardService _svc; private readonly S8DashboardCellDataService _cellSvc; private readonly S8DashboardCellConfigService _cfgSvc; private readonly S8TrustedScopeResolver _scope; public AdoS8DashboardController( S8DashboardService svc, S8DashboardCellDataService cellSvc, S8DashboardCellConfigService cfgSvc, S8TrustedScopeResolver scope) { _svc = svc; _cellSvc = cellSvc; _cfgSvc = cfgSvc; _scope = scope; } // S8-TENANT-FACTORY-P0-CLOSURE-1:以下 tenantId / factoryId 入参 // Compatibility-only. Security scope is resolved server-side. [HttpGet("overview")] public async Task OverviewAsync( [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1, [FromQuery] DateTime? beginTime = null, [FromQuery] DateTime? endTime = null, [FromQuery] string? severity = null, [FromQuery] string? period = null) { _ = tenantId; _ = factoryId; var scope = await _scope.ResolveAsync(); return Ok(await _svc.GetOverviewAsync(scope.TenantId, scope.FactoryId, beginTime, endTime, severity, period)); } [HttpGet("trends")] public async Task TrendsAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1, [FromQuery] int days = 14, [FromQuery] string? period = null) { _ = tenantId; _ = factoryId; var scope = await _scope.ResolveAsync(); return Ok(await _svc.GetTrendsAsync(scope.TenantId, scope.FactoryId, days, period)); } [HttpGet("distributions")] public async Task DistributionsAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1, [FromQuery] string? period = null) { _ = tenantId; _ = factoryId; var scope = await _scope.ResolveAsync(); return Ok(await _svc.GetDistributionsAsync(scope.TenantId, scope.FactoryId, period)); } [HttpGet("quick-exceptions")] public async Task QuickExceptionsAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1, [FromQuery] string mode = "latest") { _ = tenantId; _ = factoryId; var scope = await _scope.ResolveAsync(); return Ok(await _svc.GetQuickExceptionsAsync(scope.TenantId, scope.FactoryId, mode)); } [HttpGet("dept-backlog")] public async Task DeptBacklogAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1, [FromQuery] string? period = null) { _ = tenantId; _ = factoryId; var scope = await _scope.ResolveAsync(); return Ok(await _svc.GetDeptBacklogAsync(scope.TenantId, scope.FactoryId, period)); } [HttpGet("dim-trends")] public async Task DimTrendsAsync( [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1, [FromQuery] string dim = "object", [FromQuery] int days = 14, [FromQuery] string? period = null) { _ = tenantId; _ = factoryId; var scope = await _scope.ResolveAsync(); return Ok(await _svc.GetDimTrendsAsync(scope.TenantId, scope.FactoryId, dim, days, period)); } /// /// 按配置获取单个大屏卡片的数据。配置来源 ado_s8_dashboard_cell_config。 /// [HttpGet("cell-data")] public async Task CellDataAsync([FromQuery] AdoS8CellDataQueryDto q) { try { var scope = await _scope.ResolveAsync(); q.TenantId = scope.TenantId; q.FactoryId = scope.FactoryId; return Ok(await _cellSvc.GetAsync(q)); } catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); } } /// /// 按页面编码获取大屏页面结构配置(G-09 一期:四屏启动渲染入口)。 /// 只返回 enabled=true 的 cell,按 layout_area + sort_no 排序。 /// 不替代 cell-data,不触发 ado_s8_exception 查询。 /// [HttpGet("page-config")] public async Task PageConfigAsync([FromQuery] AdoS8PageConfigQueryDto q) { try { var scope = await _scope.ResolveAsync(); q.TenantId = scope.TenantId; q.FactoryId = scope.FactoryId; return Ok(await _cfgSvc.GetPageConfigAsync(q)); } catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); } } }