S1MdpMonitorService.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. namespace Admin.NET.Plugin.AiDOP.Order;
  2. /// <summary>
  3. /// S1 MDP 运行监控。
  4. ///
  5. /// 【租户安全边界】需认证访问(已移除类级 <c>[AllowAnonymous]</c>);租户一律经
  6. /// <c>AidopTenantScope.ResolveOrThrow</c> 从认证后 JWT 解析,无有效租户即拒绝,
  7. /// 不读前端 tenantId、无默认回退(原实现:类级匿名 + 直接取 <c>_userManager.TenantId</c>,
  8. /// 匿名时退化为 <c>tenant_id = 0</c> 平台行)。租户行与平台行可见性语义(<c>BuildMdpRunLogTenantWhere</c>)不变。
  9. /// </summary>
  10. [ApiDescriptionSettings(Order = 321, Description = "S1 MDP运行监控")]
  11. [Route("api/Order")]
  12. [NonUnify]
  13. public class S1MdpMonitorService : IDynamicApiController, ITransient
  14. {
  15. private const string JobCode = "S1_MDP_SYNC_TRANSFORM";
  16. private readonly ISqlSugarClient _db;
  17. private readonly UserManager _userManager;
  18. public S1MdpMonitorService(ISqlSugarClient db, UserManager userManager)
  19. {
  20. _db = db;
  21. _userManager = userManager;
  22. }
  23. [DisplayName("S1 MDP最近运行状态")]
  24. [HttpGet("s1-mdp-monitor/latest")]
  25. public async Task<object> GetLatest()
  26. {
  27. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  28. return await _db.Ado.SqlQuerySingleAsync<S1MdpRunLogRow>(
  29. $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE job_code=@JobCode AND {MdpMonitorService.BuildMdpRunLogTenantWhere(tenantId)} ORDER BY start_time DESC, id DESC LIMIT 1",
  30. new SugarParameter("@JobCode", JobCode),
  31. new SugarParameter("@TenantId", tenantId))
  32. ?? new S1MdpRunLogRow();
  33. }
  34. [DisplayName("S1 MDP运行日志列表")]
  35. [HttpGet("s1-mdp-monitor/list")]
  36. public async Task<object> GetList([FromQuery] S1MdpMonitorListInput input)
  37. {
  38. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  39. var page = input.Page <= 0 ? 1 : input.Page;
  40. var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
  41. var offset = (page - 1) * pageSize;
  42. var where = new List<string> { "job_code=@JobCode", MdpMonitorService.BuildMdpRunLogTenantWhere(tenantId) };
  43. var pars = new List<SugarParameter> { new("@JobCode", JobCode), new("@TenantId", tenantId) };
  44. if (!string.IsNullOrWhiteSpace(input.BatchId))
  45. {
  46. where.Add("batch_id LIKE @BatchId");
  47. pars.Add(new SugarParameter("@BatchId", $"%{input.BatchId.Trim()}%"));
  48. }
  49. if (!string.IsNullOrWhiteSpace(input.Status))
  50. {
  51. where.Add("status=@Status");
  52. pars.Add(new SugarParameter("@Status", input.Status.Trim().ToUpperInvariant()));
  53. }
  54. if (input.StartTime.HasValue)
  55. {
  56. where.Add("start_time >= @StartTime");
  57. pars.Add(new SugarParameter("@StartTime", input.StartTime.Value));
  58. }
  59. if (input.EndTime.HasValue)
  60. {
  61. where.Add("start_time <= @EndTime");
  62. pars.Add(new SugarParameter("@EndTime", input.EndTime.Value));
  63. }
  64. var whereSql = string.Join(" AND ", where);
  65. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(1) FROM mdp_transform_run_log WHERE {whereSql}", pars);
  66. var list = await _db.Ado.SqlQueryAsync<S1MdpRunLogRow>(
  67. $"""
  68. {SelectColumnsSql()}
  69. FROM mdp_transform_run_log
  70. WHERE {whereSql}
  71. ORDER BY start_time DESC, id DESC
  72. LIMIT {pageSize} OFFSET {offset}
  73. """,
  74. pars);
  75. return new { total, page, pageSize, list };
  76. }
  77. [DisplayName("S1 MDP运行日志详情")]
  78. [HttpGet("s1-mdp-monitor/detail/{id}")]
  79. public async Task<object> GetDetail(long id)
  80. {
  81. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  82. var row = await _db.Ado.SqlQuerySingleAsync<S1MdpRunLogRow>(
  83. $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE id=@Id AND job_code=@JobCode AND {MdpMonitorService.BuildMdpRunLogTenantWhere(tenantId)} LIMIT 1",
  84. new SugarParameter("@Id", id),
  85. new SugarParameter("@JobCode", JobCode),
  86. new SugarParameter("@TenantId", tenantId));
  87. return row ?? throw Oops.Oh("运行日志不存在");
  88. }
  89. private static string SelectColumnsSql()
  90. {
  91. return """
  92. SELECT id AS Id, tenant_id AS TenantId, job_code AS JobCode, job_name AS JobName, trigger_type AS TriggerType,
  93. batch_id AS BatchId, status AS Status, start_time AS StartTime, end_time AS EndTime, duration_ms AS DurationMs,
  94. stage_rows AS StageRows, standard_rows AS StandardRows, dwd_rows AS DwdRows,
  95. error_message AS ErrorMessage, summary_json AS SummaryJson, create_time AS CreateTime, update_time AS UpdateTime
  96. """;
  97. }
  98. }
  99. public sealed class S1MdpMonitorListInput
  100. {
  101. public string? BatchId { get; set; }
  102. public string? Status { get; set; }
  103. public DateTime? StartTime { get; set; }
  104. public DateTime? EndTime { get; set; }
  105. public int Page { get; set; } = 1;
  106. public int PageSize { get; set; } = 10;
  107. }
  108. public sealed class S1MdpRunLogRow
  109. {
  110. public long Id { get; set; }
  111. public long TenantId { get; set; }
  112. public string? JobCode { get; set; }
  113. public string? JobName { get; set; }
  114. public string? TriggerType { get; set; }
  115. public string? BatchId { get; set; }
  116. public string? Status { get; set; }
  117. public DateTime? StartTime { get; set; }
  118. public DateTime? EndTime { get; set; }
  119. public int? DurationMs { get; set; }
  120. public int? StageRows { get; set; }
  121. public int? StandardRows { get; set; }
  122. public int? DwdRows { get; set; }
  123. public string? ErrorMessage { get; set; }
  124. public string? SummaryJson { get; set; }
  125. public DateTime? CreateTime { get; set; }
  126. public DateTime? UpdateTime { get; set; }
  127. }