AdoSmartOpsKpiCalcConfigController.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using System.Security.Claims;
  2. using Admin.NET.Plugin.AiDOP.Dto.SmartOps;
  3. using Admin.NET.Plugin.AiDOP.SmartOps;
  4. using Microsoft.AspNetCore.Authorization;
  5. using Microsoft.AspNetCore.Mvc;
  6. namespace Admin.NET.Plugin.AiDOP.Controllers;
  7. /// <summary>
  8. /// KPI 计算配置(SQL 配置化)接口。**要求登录**(区别于其它 AiDOP 匿名接口)——SQL 编辑/发布是高危面。
  9. /// tenant/权限不信任前端:租户由服务端按 moduleCode 解析;操作人取自 JWT。
  10. /// </summary>
  11. [ApiController]
  12. [Route("api/[controller]")]
  13. [Authorize]
  14. public class AdoSmartOpsKpiCalcConfigController : ControllerBase
  15. {
  16. private readonly AdoSmartOpsKpiCalcConfigService _service;
  17. private readonly AdoSmartOpsKpiBusinessInputService _businessInput;
  18. private readonly AdoSmartOpsKpiRunLogQueryService _runLog;
  19. public AdoSmartOpsKpiCalcConfigController(
  20. AdoSmartOpsKpiCalcConfigService service,
  21. AdoSmartOpsKpiBusinessInputService businessInput,
  22. AdoSmartOpsKpiRunLogQueryService runLog)
  23. {
  24. _service = service;
  25. _businessInput = businessInput;
  26. _runLog = runLog;
  27. }
  28. private string Operator() =>
  29. User?.FindFirstValue("RealName") ?? User?.FindFirstValue("Account") ?? User?.Identity?.Name ?? "unknown";
  30. /// <summary>某 KPI 的全部配置版本。</summary>
  31. [HttpGet("by-metric/{metricCode}")]
  32. public async Task<IActionResult> GetByMetric(string metricCode, [FromQuery] string moduleCode)
  33. {
  34. if (string.IsNullOrWhiteSpace(moduleCode))
  35. return BadRequest(new { message = "moduleCode 必填" });
  36. var list = await _service.GetByMetricAsync(metricCode, moduleCode);
  37. return Ok(list);
  38. }
  39. /// <summary>已登记数据源列表。</summary>
  40. [HttpGet("data-sources")]
  41. public IActionResult DataSources() => Ok(_service.ListDataSources());
  42. /// <summary>新增草稿。</summary>
  43. [HttpPost]
  44. public async Task<IActionResult> Create([FromBody] KpiCalcConfigUpsertDto dto)
  45. {
  46. if (string.IsNullOrWhiteSpace(dto.MetricCode) || string.IsNullOrWhiteSpace(dto.ModuleCode))
  47. return BadRequest(new { message = "metricCode / moduleCode 必填" });
  48. var created = await _service.CreateDraftAsync(dto, Operator());
  49. return Ok(created);
  50. }
  51. /// <summary>编辑草稿。</summary>
  52. [HttpPut("{id:long}")]
  53. public async Task<IActionResult> Update(long id, [FromBody] KpiCalcConfigUpsertDto dto)
  54. {
  55. await _service.UpdateDraftAsync(id, dto, Operator());
  56. return Ok(new { ok = true });
  57. }
  58. /// <summary>删除草稿。</summary>
  59. [HttpDelete("{id:long}")]
  60. public async Task<IActionResult> Delete(long id)
  61. {
  62. await _service.DeleteAsync(id);
  63. return Ok(new { ok = true });
  64. }
  65. /// <summary>SQL 安全校验。</summary>
  66. [HttpPost("validate")]
  67. public IActionResult Validate([FromBody] KpiSqlValidateDto dto) => Ok(_service.Validate(dto.SqlScript));
  68. /// <summary>试算(不写正式 KPI 值;服务端重校验 + 只读执行)。</summary>
  69. [HttpPost("preview")]
  70. public async Task<IActionResult> Preview([FromBody] KpiSqlPreviewDto dto, CancellationToken ct)
  71. {
  72. if (string.IsNullOrWhiteSpace(dto.MetricCode) || string.IsNullOrWhiteSpace(dto.ModuleCode))
  73. return BadRequest(new { message = "metricCode / moduleCode 必填" });
  74. var res = await _service.PreviewAsync(dto, ct);
  75. return Ok(res);
  76. }
  77. /// <summary>发布(事务:单生效版本)。</summary>
  78. [HttpPost("{id:long}/publish")]
  79. public async Task<IActionResult> Publish(long id)
  80. {
  81. await _service.PublishAsync(id, Operator());
  82. return Ok(new { ok = true });
  83. }
  84. /// <summary>激活/回滚(把某已发布历史版本设为当前生效)。</summary>
  85. [HttpPost("{id:long}/activate")]
  86. public async Task<IActionResult> Activate(long id)
  87. {
  88. await _service.ActivateAsync(id, Operator());
  89. return Ok(new { ok = true });
  90. }
  91. /// <summary>停用。</summary>
  92. [HttpPost("{id:long}/retire")]
  93. public async Task<IActionResult> Retire(long id)
  94. {
  95. await _service.RetireAsync(id, Operator());
  96. return Ok(new { ok = true });
  97. }
  98. /// <summary>某 KPI 的业务来源与准备状态;无记录返回默认 PENDING_BUSINESS_FIELDS(IsPersisted=false)。</summary>
  99. [HttpGet("business-input/{metricCode}")]
  100. public async Task<IActionResult> GetBusinessInput(string metricCode)
  101. {
  102. if (string.IsNullOrWhiteSpace(metricCode))
  103. return BadRequest(new { message = "metricCode 必填" });
  104. var dto = await _businessInput.GetAsync(metricCode);
  105. return Ok(dto);
  106. }
  107. /// <summary>保存业务来源登记(upsert);置 READY_FOR_CONFIG 时服务端强校验缺项。</summary>
  108. [HttpPost("business-input")]
  109. public async Task<IActionResult> SaveBusinessInput([FromBody] KpiBusinessInputUpsertDto dto)
  110. {
  111. if (string.IsNullOrWhiteSpace(dto.MetricCode))
  112. return BadRequest(new { message = "metricCode 必填" });
  113. var saved = await _businessInput.UpsertAsync(dto, Operator());
  114. return Ok(saved);
  115. }
  116. /// <summary>某 KPI 的运行日志(分页、脱敏;租户后端解析)。</summary>
  117. [HttpGet("run-log/{metricCode}")]
  118. public async Task<IActionResult> RunLog(
  119. string metricCode,
  120. [FromQuery] int page = 1,
  121. [FromQuery] int pageSize = 20,
  122. [FromQuery] string? status = null,
  123. [FromQuery] DateTime? startTime = null,
  124. [FromQuery] DateTime? endTime = null)
  125. {
  126. if (string.IsNullOrWhiteSpace(metricCode))
  127. return BadRequest(new { message = "metricCode 必填" });
  128. var res = await _runLog.QueryAsync(new KpiRunLogQueryDto
  129. {
  130. MetricCode = metricCode,
  131. Page = page,
  132. PageSize = pageSize,
  133. Status = status,
  134. StartTime = startTime,
  135. EndTime = endTime,
  136. });
  137. return Ok(res);
  138. }
  139. }