AidopKanbanController.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. using Admin.NET.Core;
  2. using Admin.NET.Plugin.AiDOP.Entity;
  3. using Admin.NET.Plugin.AiDOP.Infrastructure;
  4. using SqlSugar;
  5. namespace Admin.NET.Plugin.AiDOP.Controllers;
  6. [ApiController]
  7. [Route("api/[controller]")]
  8. [AllowAnonymous]
  9. [NonUnify]
  10. public partial class AidopKanbanController : ControllerBase
  11. {
  12. private readonly ISqlSugarClient _db;
  13. public AidopKanbanController(ISqlSugarClient db)
  14. {
  15. _db = db;
  16. }
  17. [HttpGet("home-l1")]
  18. public async Task<IActionResult> GetHomeL1([FromQuery] long factoryId = 1)
  19. {
  20. var tenantId = AidopTenantHelper.GetTenantId(HttpContext);
  21. const string sql = """
  22. SELECT v.module_code AS ModuleCode, v.metric_code AS MetricCode,
  23. v.metric_value AS MetricValue, v.target_value AS TargetValue,
  24. v.status_color AS StatusColor, v.trend_flag AS TrendFlag,
  25. k.Direction, k.YellowThreshold, k.RedThreshold
  26. FROM ado_s9_kpi_value_l1_day v
  27. LEFT JOIN ado_smart_ops_kpi_master k
  28. ON k.MetricCode = v.metric_code COLLATE utf8mb4_general_ci AND k.TenantId = v.tenant_id
  29. WHERE v.tenant_id=@tenantId AND v.factory_id=@factoryId AND v.is_deleted=0
  30. AND v.biz_date = (SELECT MAX(biz_date) FROM ado_s9_kpi_value_l1_day
  31. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0)
  32. ORDER BY v.module_code
  33. """;
  34. var raw = await _db.Ado.SqlQueryAsync<HomeL1RawDto>(sql, new { tenantId, factoryId });
  35. var rows = raw.Select(r => new HomeL1Dto
  36. {
  37. ModuleCode = r.ModuleCode,
  38. MetricCode = r.MetricCode,
  39. MetricValue = r.MetricValue,
  40. TargetValue = r.TargetValue,
  41. TrendFlag = r.TrendFlag,
  42. StatusColor = AidopS4KpiMerge.AchievementLevel(
  43. r.MetricValue, r.TargetValue,
  44. r.Direction ?? "higher_is_better",
  45. r.YellowThreshold, r.RedThreshold)
  46. }).ToList();
  47. return Ok(rows);
  48. }
  49. [HttpGet("s8-alerts")]
  50. public async Task<IActionResult> GetS8Alerts([FromQuery] long factoryId = 1)
  51. {
  52. var tenantId = AidopTenantHelper.GetTenantId(HttpContext);
  53. const string sql = """
  54. SELECT DATE_FORMAT(alert_time, '%H:%i') AS Time,
  55. IFNULL(SUBSTRING_INDEX(metric_code, '_', 1), 'S8') AS Module,
  56. IFNULL(message, '异常告警') AS Message,
  57. IFNULL(level_code, 'medium') AS LevelCode
  58. FROM ado_s8_alert_record
  59. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0
  60. ORDER BY alert_time DESC
  61. LIMIT 6
  62. """;
  63. var rows = await _db.Ado.SqlQueryAsync<S8AlertDto>(sql, new { tenantId, factoryId });
  64. return Ok(rows.Select(x => new
  65. {
  66. time = x.Time,
  67. module = x.Module,
  68. message = x.Message,
  69. level = x.LevelCode,
  70. levelLabel = x.LevelCode switch
  71. {
  72. "critical" => "严重",
  73. "high" => "高",
  74. "medium" => "中",
  75. _ => "一般"
  76. }
  77. }));
  78. }
  79. [HttpGet("module-detail")]
  80. public async Task<IActionResult> GetModuleDetail([FromQuery] string moduleCode = "S1", [FromQuery] long factoryId = 1)
  81. {
  82. var tenantId = AidopTenantHelper.GetTenantId(HttpContext);
  83. moduleCode = string.IsNullOrWhiteSpace(moduleCode) ? "S1" : moduleCode.ToUpperInvariant();
  84. const string l2Sql = """
  85. SELECT module_code AS ModuleCode, metric_code AS MetricCode, metric_code AS MetricName, metric_value AS MetricValue,
  86. target_value AS TargetValue, status_color AS StatusColor, trend_flag AS TrendFlag, NULL AS StatDate
  87. FROM ado_s9_kpi_value_l2_day
  88. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0 AND module_code=@moduleCode
  89. ORDER BY id DESC, metric_code
  90. LIMIT 30
  91. """;
  92. const string l3Sql = """
  93. SELECT module_code AS ModuleCode, metric_code AS MetricCode, metric_code AS MetricName, metric_value AS MetricValue,
  94. target_value AS TargetValue, status_color AS StatusColor, trend_flag AS TrendFlag, NULL AS StatDate
  95. FROM ado_s9_kpi_value_l3_day
  96. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0 AND module_code=@moduleCode
  97. ORDER BY id DESC, metric_code
  98. LIMIT 60
  99. """;
  100. const string alertSql = """
  101. SELECT DATE_FORMAT(alert_time, '%H:%i:%s') AS Time,
  102. IFNULL(level_code, 'medium') AS LevelCode,
  103. IFNULL(message, '异常告警') AS Message
  104. FROM ado_s8_alert_record
  105. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0
  106. AND (UPPER(IFNULL(module_code,''))=@moduleCode OR UPPER(IFNULL(SUBSTRING_INDEX(metric_code, '_', 1), ''))=@moduleCode)
  107. ORDER BY alert_time DESC
  108. LIMIT 20
  109. """;
  110. const string l2FallbackSql = """
  111. SELECT '' AS ModuleCode, metric_code AS MetricCode, metric_code AS MetricName, metric_value AS MetricValue,
  112. target_value AS TargetValue, status_color AS StatusColor, trend_flag AS TrendFlag, NULL AS StatDate
  113. FROM ado_s9_kpi_value_l2_day
  114. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0
  115. ORDER BY id DESC
  116. LIMIT 30
  117. """;
  118. const string l3FallbackSql = """
  119. SELECT '' AS ModuleCode, metric_code AS MetricCode, metric_code AS MetricName, metric_value AS MetricValue,
  120. target_value AS TargetValue, status_color AS StatusColor, trend_flag AS TrendFlag, NULL AS StatDate
  121. FROM ado_s9_kpi_value_l3_day
  122. WHERE tenant_id=@tenantId AND factory_id=@factoryId AND is_deleted=0
  123. ORDER BY id DESC
  124. LIMIT 60
  125. """;
  126. var l2 = new List<KpiDetailDto>();
  127. var l3 = new List<KpiDetailDto>();
  128. var alerts = new List<S8AlertDto>();
  129. try { l2 = await _db.Ado.SqlQueryAsync<KpiDetailDto>(l2Sql, new { moduleCode, tenantId, factoryId }); }
  130. catch { l2 = await _db.Ado.SqlQueryAsync<KpiDetailDto>(l2FallbackSql, new { tenantId, factoryId }); }
  131. try { l3 = await _db.Ado.SqlQueryAsync<KpiDetailDto>(l3Sql, new { moduleCode, tenantId, factoryId }); }
  132. catch { l3 = await _db.Ado.SqlQueryAsync<KpiDetailDto>(l3FallbackSql, new { tenantId, factoryId }); }
  133. try { alerts = await _db.Ado.SqlQueryAsync<S8AlertDto>(alertSql, new { moduleCode, tenantId, factoryId }); }
  134. catch { alerts = new List<S8AlertDto>(); }
  135. return Ok(new
  136. {
  137. moduleCode,
  138. l2,
  139. l3,
  140. alerts = alerts.Select(x => new
  141. {
  142. time = x.Time,
  143. message = x.Message,
  144. level = x.LevelCode
  145. })
  146. });
  147. }
  148. /// <summary>
  149. /// 智慧运营看板基础查询下拉:产品、订单号、产线(来自 Demo 业务表;无租户列时忽略 tenant/factory)。
  150. /// </summary>
  151. [HttpGet("smart-ops-filter-options")]
  152. public async Task<IActionResult> GetSmartOpsFilterOptions([FromQuery] long factoryId = 1)
  153. {
  154. _ = factoryId;
  155. var products = new HashSet<string>(StringComparer.Ordinal);
  156. var orderNos = new HashSet<string>(StringComparer.Ordinal);
  157. var lines = new HashSet<string>(StringComparer.Ordinal);
  158. try
  159. {
  160. var op = await _db.Queryable<AdoOrder>()
  161. .Where(x => x.Product != null && x.Product != "")
  162. .Select(x => x.Product)
  163. .Distinct()
  164. .ToListAsync();
  165. foreach (var s in op.Where(s => !string.IsNullOrWhiteSpace(s)))
  166. products.Add(s.Trim());
  167. }
  168. catch
  169. {
  170. // ignored
  171. }
  172. try
  173. {
  174. var on = await _db.Queryable<AdoOrder>()
  175. .Where(x => x.OrderNo != null && x.OrderNo != "")
  176. .Select(x => x.OrderNo)
  177. .Distinct()
  178. .ToListAsync();
  179. foreach (var s in on.Where(s => !string.IsNullOrWhiteSpace(s)))
  180. orderNos.Add(s.Trim());
  181. }
  182. catch
  183. {
  184. // ignored
  185. }
  186. try
  187. {
  188. var woP = await _db.Queryable<AdoWorkOrder>()
  189. .Where(x => x.Product != null && x.Product != "")
  190. .Select(x => x.Product)
  191. .Distinct()
  192. .ToListAsync();
  193. foreach (var s in woP.Where(s => !string.IsNullOrWhiteSpace(s)))
  194. products.Add(s.Trim());
  195. var wc = await _db.Queryable<AdoWorkOrder>()
  196. .Where(x => x.WorkCenter != null && x.WorkCenter != "")
  197. .Select(x => x.WorkCenter)
  198. .Distinct()
  199. .ToListAsync();
  200. foreach (var s in wc.Where(s => !string.IsNullOrWhiteSpace(s)))
  201. lines.Add(s.Trim());
  202. }
  203. catch
  204. {
  205. // ignored
  206. }
  207. try
  208. {
  209. var pn = await _db.Queryable<AdoPlan>()
  210. .Where(x => x.ProductName != null && x.ProductName != "")
  211. .Select(x => x.ProductName)
  212. .Distinct()
  213. .ToListAsync();
  214. foreach (var s in pn.Where(s => !string.IsNullOrWhiteSpace(s)))
  215. products.Add(s.Trim());
  216. }
  217. catch
  218. {
  219. // ignored
  220. }
  221. return Ok(new
  222. {
  223. products = products.OrderBy(x => x, StringComparer.Ordinal).ToList(),
  224. orderNos = orderNos.OrderBy(x => x, StringComparer.Ordinal).ToList(),
  225. productionLines = lines.OrderBy(x => x, StringComparer.Ordinal).ToList()
  226. });
  227. }
  228. private sealed class HomeL1Dto
  229. {
  230. public string? ModuleCode { get; set; }
  231. public string? MetricCode { get; set; }
  232. public decimal? MetricValue { get; set; }
  233. public decimal? TargetValue { get; set; }
  234. public string? StatusColor { get; set; }
  235. public string? TrendFlag { get; set; }
  236. }
  237. private sealed class HomeL1RawDto
  238. {
  239. public string? ModuleCode { get; set; }
  240. public string? MetricCode { get; set; }
  241. public decimal? MetricValue { get; set; }
  242. public decimal? TargetValue { get; set; }
  243. public string? StatusColor { get; set; }
  244. public string? TrendFlag { get; set; }
  245. public string? Direction { get; set; }
  246. public decimal? YellowThreshold { get; set; }
  247. public decimal? RedThreshold { get; set; }
  248. }
  249. private sealed class S8AlertDto
  250. {
  251. public string? Time { get; set; }
  252. public string? Module { get; set; }
  253. public string? Message { get; set; }
  254. public string? LevelCode { get; set; }
  255. }
  256. private sealed class KpiDetailDto
  257. {
  258. public string? ModuleCode { get; set; }
  259. public string? MetricCode { get; set; }
  260. public string? MetricName { get; set; }
  261. public decimal? MetricValue { get; set; }
  262. public decimal? TargetValue { get; set; }
  263. public string? StatusColor { get; set; }
  264. public string? TrendFlag { get; set; }
  265. public DateTime? StatDate { get; set; }
  266. }
  267. }