UniversalSourceListService.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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>?tenantId=</c> 读任意租户货源清单)。
  9. /// </summary>
  10. [ApiDescriptionSettings(Order = 280, Description = "通用-货源清单选择")]
  11. [Route("api/Universal")]
  12. [NonUnify]
  13. public class UniversalSourceListService : IDynamicApiController, ITransient
  14. {
  15. private const string C = "utf8mb4_general_ci";
  16. private readonly ISqlSugarClient _db;
  17. private readonly UserManager _userManager;
  18. public UniversalSourceListService(ISqlSugarClient db, UserManager userManager)
  19. {
  20. _db = db;
  21. _userManager = userManager;
  22. }
  23. [DisplayName("获取货源清单选择列表")]
  24. [HttpGet("source-list/page")]
  25. public async Task<object> GetPage([FromQuery] UniversalSourceListPageInput input)
  26. {
  27. var page = input.Page <= 0 ? 1 : input.Page;
  28. var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
  29. var offset = (page - 1) * pageSize;
  30. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  31. var pars = new List<SugarParameter>();
  32. var where = new List<string>
  33. {
  34. "sp.tenant_id = @TenantId",
  35. "(it.erp_cls=3 OR it.erp_cls=2)",
  36. "IFNULL(sp.quota_rate,0)>0",
  37. "IFNULL(sp.IsDeleted,0)=0"
  38. };
  39. if (!string.IsNullOrWhiteSpace(input.Number))
  40. {
  41. where.Add("it.number LIKE @Number");
  42. pars.Add(new SugarParameter("@Number", $"%{input.Number.Trim()}%"));
  43. }
  44. if (!string.IsNullOrWhiteSpace(input.IcitemName))
  45. {
  46. where.Add("sp.icitem_name LIKE @IcitemName");
  47. pars.Add(new SugarParameter("@IcitemName", $"%{input.IcitemName.Trim()}%"));
  48. }
  49. if (!string.IsNullOrWhiteSpace(input.SupplierNumber))
  50. {
  51. where.Add("sp.supplier_number LIKE @SupplierNumber");
  52. pars.Add(new SugarParameter("@SupplierNumber", $"%{input.SupplierNumber.Trim()}%"));
  53. }
  54. pars.Add(new SugarParameter("@TenantId", tenantId));
  55. var orderBy = BuildOrderBy(input.SortField, input.SortOrder);
  56. var fromSql = $"""
  57. FROM srm_purchase sp
  58. LEFT JOIN ic_item it ON sp.number = it.number AND (it.tenant_id = sp.tenant_id OR it.tenant_id IS NULL)
  59. LEFT JOIN ItemMaster im ON it.number = im.ItemNum AND (im.tenant_id = sp.tenant_id OR im.tenant_id IS NULL)
  60. WHERE {string.Join(" AND ", where)}
  61. """;
  62. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(DISTINCT sp.id) {fromSql}", pars);
  63. var list = await _db.Ado.SqlQueryAsync<UniversalSourceListOutput>(
  64. $"""
  65. SELECT DISTINCT
  66. sp.id AS Id,
  67. sp.tenant_id AS TenantId,
  68. sp.factory_id AS FactoryId,
  69. CAST(sp.icitem_id AS CHAR(30)) AS IcitemId,
  70. it.number AS Number,
  71. sp.icitem_name AS IcitemName,
  72. '原材料' AS ItemType,
  73. it.model AS Model,
  74. it.unit AS Unit,
  75. sp.supplier_type AS SupplierType,
  76. -- is_active 为 varchar(存“是/否”等),CAST AS SIGNED 会把“是”误判为 0;改按启用/停用编码集合归一为 1/0/NULL。
  77. CASE
  78. WHEN TRIM(LOWER(sp.is_active)) IN ('是','y','1','true') THEN 1
  79. WHEN TRIM(LOWER(sp.is_active)) IN ('否','n','0','false') THEN 0
  80. ELSE NULL
  81. END AS IsActive,
  82. sp.supplier_id AS SupplierId,
  83. sp.supplier_name AS SupplierName,
  84. sp.supplier_number AS SupplierNumber,
  85. sp.order_price AS OrderPrice,
  86. sp.currency_type AS CurrencyType,
  87. IFNULL(sp.taxrate,0) AS TaxRate,
  88. IFNULL(sp.tariff,0) AS Tariff,
  89. sp.freight AS Freight,
  90. sp.price_terms AS PriceTerms,
  91. sp.effective_date AS EffectiveDate,
  92. sp.expiring_date AS ExpiringDate,
  93. IFNULL(sp.quota_rate,0) AS QuotaRate,
  94. sp.lead_time AS LeadTime,
  95. sp.qty_min AS QtyMin,
  96. sp.packaging_qty AS PackagingQty,
  97. sp.order_rector_name AS OrderRectorName,
  98. sp.order_rector_num AS OrderRectorNum,
  99. CONCAT(IFNULL(it.number,''),IFNULL(sp.icitem_name,'')) AS Icitem,
  100. CONCAT(IFNULL(sp.supplier_name,''),IFNULL(sp.supplier_number,'')) AS Supplier,
  101. sp.IsRequireGoods AS IsRequireGoods,
  102. im.Location AS Location,
  103. im.UM AS Um,
  104. im.Rev AS Rev,
  105. im.Drawing AS Drawing
  106. {fromSql}
  107. ORDER BY {orderBy}
  108. LIMIT {pageSize} OFFSET {offset}
  109. """,
  110. pars);
  111. return new { total, page, pageSize, list };
  112. }
  113. private static string BuildOrderBy(string? sortField, string? sortOrder)
  114. {
  115. var dir = string.Equals(sortOrder, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
  116. return sortField?.ToLowerInvariant() switch
  117. {
  118. "number" => $"it.number {dir}",
  119. "icitemname" => $"sp.icitem_name {dir}",
  120. "suppliertype" => $"sp.supplier_type {dir}",
  121. "suppliernumber" => $"sp.supplier_number {dir}",
  122. "suppliername" => $"sp.supplier_name {dir}",
  123. "leadtime" => $"sp.lead_time {dir}",
  124. _ => "sp.id DESC"
  125. };
  126. }
  127. }