UniversalWorkOrderService.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. namespace Admin.NET.Plugin.AiDOP.Universal;
  2. /// <summary>
  3. /// 通用工单选择服务
  4. ///
  5. /// 【租户安全边界】需认证访问(已移除类级 <c>[AllowAnonymous]</c>);
  6. /// 租户一律经 <c>AidopTenantScope.ResolveOrThrow</c> 从认证后 JWT 解析,
  7. /// 无有效租户即拒绝,不读前端 tenantId、无默认回退(原实现:类级匿名 +
  8. /// 直接取 <c>_userManager.TenantId</c>,匿名时 TenantId=0 查不到有效数据但端点仍暴露)。
  9. /// </summary>
  10. [ApiDescriptionSettings(Order = 281, Description = "通用-工单选择")]
  11. [Route("api/Universal")]
  12. [NonUnify]
  13. public class UniversalWorkOrderService : IDynamicApiController, ITransient
  14. {
  15. private readonly ISqlSugarClient _db;
  16. private readonly UserManager _userManager;
  17. public UniversalWorkOrderService(ISqlSugarClient db, UserManager userManager)
  18. {
  19. _db = db;
  20. _userManager = userManager;
  21. }
  22. [DisplayName("获取工单选择列表")]
  23. [HttpGet("work-order/page")]
  24. public async Task<object> GetPage([FromQuery] UniversalWorkOrderPageInput input)
  25. {
  26. var page = input.Page <= 0 ? 1 : input.Page;
  27. var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
  28. var offset = (page - 1) * pageSize;
  29. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  30. var where = new List<string>
  31. {
  32. "a.tenant_id = @TenantId",
  33. "a.Status!='c'",
  34. // 只展示:至少存在一个“外协工序+供应商”尚未生成 PW 采购单的工单
  35. @"EXISTS (
  36. SELECT 1
  37. FROM WorkOrdRouting r
  38. INNER JOIN RoutingOpDetail d ON r.Op = d.Op AND r.ItemNum = d.RoutingCode AND d.tenant_id = @TenantId
  39. WHERE r.WorkOrd = a.WorkOrd
  40. AND r.tenant_id = @TenantId
  41. AND r.ProcessOut = 1
  42. AND IFNULL(TRIM(d.SupplierCode),'') <> ''
  43. AND NOT EXISTS (
  44. SELECT 1 FROM PurOrdMaster p
  45. WHERE p.WorkOrd = a.WorkOrd AND p.tenant_id = @TenantId AND p.Supp = d.SupplierCode AND p.Potype = 'PW'
  46. )
  47. )"
  48. };
  49. var pars = new List<SugarParameter> { new SugarParameter("@TenantId", tenantId) };
  50. if (!string.IsNullOrWhiteSpace(input.WorkOrd))
  51. {
  52. where.Add("a.WorkOrd LIKE @WorkOrd");
  53. pars.Add(new SugarParameter("@WorkOrd", $"%{input.WorkOrd.Trim()}%"));
  54. }
  55. var fromSql = $"""
  56. FROM WorkOrdMaster a
  57. LEFT JOIN ItemMaster b ON a.ItemNum=b.ItemNum AND b.tenant_id=@TenantId
  58. WHERE {string.Join(" AND ", where)}
  59. """;
  60. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(1) {fromSql}", pars);
  61. var list = await _db.Ado.SqlQueryAsync<UniversalWorkOrderOutput>(
  62. $"""
  63. SELECT
  64. a.recid AS Id,
  65. a.Batch AS Batch,
  66. a.Drawing AS Drawing,
  67. a.Typed AS Typed,
  68. a.WorkOrd AS WorkOrd,
  69. a.OrdDate AS OrdDate,
  70. a.DueDate AS DueDate,
  71. a.ItemNum AS ItemNum,
  72. a.Project AS Project,
  73. a.QtyOrded AS QtyOrded,
  74. a.QtyCompleted AS QtyCompleted,
  75. a.Remark AS Remark,
  76. LOWER(a.Status) AS Status,
  77. a.WoTyped AS WoTyped,
  78. b.Descr AS Descr,
  79. b.Descr1 AS Descr1,
  80. a.lbrvar AS Lbrvar
  81. {fromSql}
  82. ORDER BY {BuildOrderBy(input.SortField, input.SortOrder)}
  83. LIMIT {pageSize} OFFSET {offset}
  84. """,
  85. pars);
  86. return new { total, page, pageSize, list };
  87. }
  88. private static string BuildOrderBy(string? sortField, string? sortOrder)
  89. {
  90. var dir = string.Equals(sortOrder, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
  91. return sortField?.ToLowerInvariant() switch
  92. {
  93. "workord" => $"a.WorkOrd {dir}",
  94. "itemnum" => $"a.ItemNum {dir}",
  95. "descr" => $"b.Descr {dir}",
  96. "orddate" => $"a.OrdDate {dir}",
  97. _ => "a.RecID DESC"
  98. };
  99. }
  100. }