WorkOrderProgressDashboardService.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. namespace Admin.NET.Plugin.AiDOP.Production;
  2. /// <summary>
  3. /// 工单执行进度看板(列表)📊
  4. /// 路由前缀:<c>/api/Production/work-order-progress/...</c>
  5. /// </summary>
  6. [ApiDescriptionSettings(Order = 266, Description = "工单执行进度看板")]
  7. [Route("api/Production")]
  8. [AllowAnonymous]
  9. [NonUnify]
  10. public class WorkOrderProgressDashboardService : IDynamicApiController, ITransient
  11. {
  12. private readonly ISqlSugarClient _db;
  13. private readonly UserManager _userManager;
  14. public WorkOrderProgressDashboardService(ISqlSugarClient db, UserManager userManager)
  15. {
  16. _db = db;
  17. _userManager = userManager;
  18. }
  19. /// <summary>工单执行进度看板分页列表</summary>
  20. [DisplayName("工单执行进度看板列表")]
  21. [HttpGet("work-order-progress/list")]
  22. public async Task<object> GetList([FromQuery] WorkOrderProgressDashboardListInput input)
  23. {
  24. const string C = "utf8mb4_general_ci";
  25. var tenantId = AidopTenantHelper.Resolve(App.HttpContext);
  26. var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
  27. var innerWhere = new List<string>
  28. {
  29. "IFNULL(wm.Status,'') <> ''",
  30. "wm.tenant_id = @TenantId"
  31. };
  32. if (!string.IsNullOrWhiteSpace(input.WorkOrd))
  33. {
  34. innerWhere.Add($"(wm.WorkOrd COLLATE {C}) LIKE @WorkOrd");
  35. pars.Add(new SugarParameter("@WorkOrd", $"%{input.WorkOrd.Trim()}%"));
  36. }
  37. if (!string.IsNullOrWhiteSpace(input.ItemNum))
  38. {
  39. innerWhere.Add($"(wm.ItemNum COLLATE {C}) = @ItemNum");
  40. pars.Add(new SugarParameter("@ItemNum", input.ItemNum.Trim()));
  41. }
  42. if (!string.IsNullOrWhiteSpace(input.OrdDateFrom))
  43. {
  44. innerWhere.Add("DATE(wm.OrdDate) >= @OrdDateFrom");
  45. pars.Add(new SugarParameter("@OrdDateFrom", input.OrdDateFrom.Trim()));
  46. }
  47. var baseSql = BuildListBaseSql(string.Join(" AND ", innerWhere), C);
  48. var offset = (input.Page - 1) * input.PageSize;
  49. var total = await _db.Ado.GetIntAsync(
  50. $"SELECT COUNT(*) FROM ({baseSql}) AS t", pars);
  51. var list = await _db.Ado.SqlQueryAsync<WorkOrderProgressDashboardListRow>(
  52. $"SELECT * FROM ({baseSql}) AS t ORDER BY t.OrdDate DESC, t.Id DESC LIMIT {input.PageSize} OFFSET {offset}",
  53. pars);
  54. return new { total, page = input.Page, pageSize = input.PageSize, list };
  55. }
  56. /// <summary>看板侧工序行匹配:工单号 + 主表租户。</summary>
  57. private static string KanbanRoutingMatch(string C) =>
  58. $"r.WorkOrd COLLATE {C} = wm.WorkOrd COLLATE {C} AND NULLIF(r.tenant_id, 0) = wm.tenant_id";
  59. private static string BuildListBaseSql(string innerWhere, string C) => $"""
  60. SELECT
  61. wm.RecID AS Id,
  62. wm.WorkOrd AS WorkOrd,
  63. wm.Typed AS Typed,
  64. wm.`Domain` AS `Domain`,
  65. defaultLine.Workshop AS Workshop,
  66. wm.OrdDate AS OrdDate,
  67. wm.DueDate AS DueDate,
  68. wm.ItemNum AS ItemNum,
  69. im.Descr AS Descr,
  70. im.Descr1 AS Descr1,
  71. IFNULL(wm.QtyOrded, 0) AS QtyOrded,
  72. IFNULL(wm.QtyCompleted, 0) AS QtyCompleted,
  73. IFNULL(wm.QtyOrded, 0) - IFNULL(wm.QtyCompleted, 0) AS NoCompleted,
  74. mo.MaterialSituation AS MaterialSituation,
  75. LOWER(wm.Status) AS Status,
  76. CASE
  77. WHEN IFNULL(wm.QtyOrded, 0) = 0 THEN 0
  78. ELSE ROUND(100.0 * IFNULL(wm.QtyCompleted, 0) / wm.QtyOrded, 4)
  79. END AS Progress,
  80. {WorkOrderExecutionProgressSql.Columns("wm", "curOp", "lastOp", "opAgg")}
  81. FROM WorkOrdMaster wm
  82. LEFT JOIN ItemMaster im
  83. ON wm.ItemNum COLLATE {C} = im.ItemNum COLLATE {C}
  84. AND wm.`Domain` COLLATE {C} = im.`Domain` COLLATE {C}
  85. AND (im.tenant_id = wm.tenant_id OR wm.tenant_id IS NULL)
  86. LEFT JOIN mes_morder mo
  87. ON wm.WorkOrd COLLATE {C} = mo.morder_no COLLATE {C}
  88. AND wm.`Domain` COLLATE {C} = mo.factory_id COLLATE {C}
  89. AND mo.tenant_id = wm.tenant_id
  90. {WorkOrderExecutionProgressSql.Laterals(KanbanRoutingMatch(C))}
  91. LEFT JOIN LATERAL (
  92. SELECT psd0.`Line` AS `Line`
  93. FROM PeriodSequenceDet psd0
  94. WHERE psd0.ItemNum COLLATE {C} = wm.ItemNum COLLATE {C}
  95. AND psd0.`Domain` COLLATE {C} = wm.`Domain` COLLATE {C}
  96. LIMIT 1
  97. ) AS psd ON TRUE
  98. LEFT JOIN LATERAL (
  99. SELECT lm.Workshop AS Workshop
  100. FROM LineMaster lm
  101. WHERE lm.`Line` COLLATE {C} = psd.`Line` COLLATE {C}
  102. AND lm.`Domain` COLLATE {C} = wm.`Domain` COLLATE {C}
  103. LIMIT 1
  104. ) AS defaultLine ON TRUE
  105. WHERE {innerWhere}
  106. """;
  107. }