using System.Security.Claims;
using Admin.NET.Plugin.AiDOP.Dto.SmartOps;
using Admin.NET.Plugin.AiDOP.SmartOps;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Admin.NET.Plugin.AiDOP.Controllers;
///
/// KPI 计算配置(SQL 配置化)接口。**要求登录**(区别于其它 AiDOP 匿名接口)——SQL 编辑/发布是高危面。
/// tenant/权限不信任前端:租户由服务端按 moduleCode 解析;操作人取自 JWT。
///
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class AdoSmartOpsKpiCalcConfigController : ControllerBase
{
private readonly AdoSmartOpsKpiCalcConfigService _service;
private readonly AdoSmartOpsKpiBusinessInputService _businessInput;
private readonly AdoSmartOpsKpiRunLogQueryService _runLog;
public AdoSmartOpsKpiCalcConfigController(
AdoSmartOpsKpiCalcConfigService service,
AdoSmartOpsKpiBusinessInputService businessInput,
AdoSmartOpsKpiRunLogQueryService runLog)
{
_service = service;
_businessInput = businessInput;
_runLog = runLog;
}
private string Operator() =>
User?.FindFirstValue("RealName") ?? User?.FindFirstValue("Account") ?? User?.Identity?.Name ?? "unknown";
/// 某 KPI 的全部配置版本。
[HttpGet("by-metric/{metricCode}")]
public async Task GetByMetric(string metricCode, [FromQuery] string moduleCode)
{
if (string.IsNullOrWhiteSpace(moduleCode))
return BadRequest(new { message = "moduleCode 必填" });
var list = await _service.GetByMetricAsync(metricCode, moduleCode);
return Ok(list);
}
/// 已登记数据源列表。
[HttpGet("data-sources")]
public IActionResult DataSources() => Ok(_service.ListDataSources());
/// 新增草稿。
[HttpPost]
public async Task Create([FromBody] KpiCalcConfigUpsertDto dto)
{
if (string.IsNullOrWhiteSpace(dto.MetricCode) || string.IsNullOrWhiteSpace(dto.ModuleCode))
return BadRequest(new { message = "metricCode / moduleCode 必填" });
var created = await _service.CreateDraftAsync(dto, Operator());
return Ok(created);
}
/// 编辑草稿。
[HttpPut("{id:long}")]
public async Task Update(long id, [FromBody] KpiCalcConfigUpsertDto dto)
{
await _service.UpdateDraftAsync(id, dto, Operator());
return Ok(new { ok = true });
}
/// 删除草稿。
[HttpDelete("{id:long}")]
public async Task Delete(long id)
{
await _service.DeleteAsync(id);
return Ok(new { ok = true });
}
/// SQL 安全校验。
[HttpPost("validate")]
public IActionResult Validate([FromBody] KpiSqlValidateDto dto) => Ok(_service.Validate(dto.SqlScript));
/// 试算(不写正式 KPI 值;服务端重校验 + 只读执行)。
[HttpPost("preview")]
public async Task Preview([FromBody] KpiSqlPreviewDto dto, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(dto.MetricCode) || string.IsNullOrWhiteSpace(dto.ModuleCode))
return BadRequest(new { message = "metricCode / moduleCode 必填" });
var res = await _service.PreviewAsync(dto, ct);
return Ok(res);
}
/// 发布(事务:单生效版本)。
[HttpPost("{id:long}/publish")]
public async Task Publish(long id)
{
await _service.PublishAsync(id, Operator());
return Ok(new { ok = true });
}
/// 激活/回滚(把某已发布历史版本设为当前生效)。
[HttpPost("{id:long}/activate")]
public async Task Activate(long id)
{
await _service.ActivateAsync(id, Operator());
return Ok(new { ok = true });
}
/// 停用。
[HttpPost("{id:long}/retire")]
public async Task Retire(long id)
{
await _service.RetireAsync(id, Operator());
return Ok(new { ok = true });
}
/// 某 KPI 的业务来源与准备状态;无记录返回默认 PENDING_BUSINESS_FIELDS(IsPersisted=false)。
[HttpGet("business-input/{metricCode}")]
public async Task GetBusinessInput(string metricCode)
{
if (string.IsNullOrWhiteSpace(metricCode))
return BadRequest(new { message = "metricCode 必填" });
var dto = await _businessInput.GetAsync(metricCode);
return Ok(dto);
}
/// 保存业务来源登记(upsert);置 READY_FOR_CONFIG 时服务端强校验缺项。
[HttpPost("business-input")]
public async Task SaveBusinessInput([FromBody] KpiBusinessInputUpsertDto dto)
{
if (string.IsNullOrWhiteSpace(dto.MetricCode))
return BadRequest(new { message = "metricCode 必填" });
var saved = await _businessInput.UpsertAsync(dto, Operator());
return Ok(saved);
}
/// 某 KPI 的运行日志(分页、脱敏;租户后端解析)。
[HttpGet("run-log/{metricCode}")]
public async Task RunLog(
string metricCode,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] string? status = null,
[FromQuery] DateTime? startTime = null,
[FromQuery] DateTime? endTime = null)
{
if (string.IsNullOrWhiteSpace(metricCode))
return BadRequest(new { message = "metricCode 必填" });
var res = await _runLog.QueryAsync(new KpiRunLogQueryDto
{
MetricCode = metricCode,
Page = page,
PageSize = pageSize,
Status = status,
StartTime = startTime,
EndTime = endTime,
});
return Ok(res);
}
}