ScheduleExceptionService.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. using Yitter.IdGenerator;
  2. namespace Admin.NET.Plugin.AiDOP.Production;
  3. /// <summary>
  4. /// 排产异常记录服务 🏭
  5. /// 路由前缀:/api/Production/schedule-exception/...
  6. /// </summary>
  7. [ApiDescriptionSettings(Order = 267, Description = "排产异常记录")]
  8. [Route("api/Production")]
  9. [AllowAnonymous]
  10. [NonUnify]
  11. public class ScheduleExceptionService : IDynamicApiController, ITransient
  12. {
  13. private const string C = "utf8mb4_general_ci";
  14. private readonly ISqlSugarClient _db;
  15. private readonly SqlSugarRepository<ScheduleExceptionMaster> _rep;
  16. private readonly UserManager _userManager;
  17. public ScheduleExceptionService(ISqlSugarClient db, SqlSugarRepository<ScheduleExceptionMaster> rep, UserManager userManager)
  18. {
  19. _db = db;
  20. _rep = rep;
  21. _userManager = userManager;
  22. }
  23. // ══════════════════════════════════════════════════════════════
  24. // 列表 GET /api/Production/schedule-exception/list
  25. // ══════════════════════════════════════════════════════════════
  26. /// <summary>排产异常分页列表(ScheduleExceptionMaster + ItemMaster.Descr1)</summary>
  27. [DisplayName("排产异常记录列表")]
  28. [HttpGet("schedule-exception/list")]
  29. public async Task<object> GetList([FromQuery] ScheduleExceptionListInput input)
  30. {
  31. var tenantId = _userManager.TenantId;
  32. var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
  33. var inner = new List<string> { "sm.tenant_id = @TenantId" };
  34. if (!string.IsNullOrWhiteSpace(input.OptTime))
  35. {
  36. inner.Add($"(CAST(sm.OptTime AS CHAR(50)) COLLATE {C}) LIKE @OptTimeLike");
  37. pars.Add(new SugarParameter("@OptTimeLike", $"%{input.OptTime.Trim()}%"));
  38. }
  39. if (!string.IsNullOrWhiteSpace(input.WorkOrd))
  40. {
  41. inner.Add($"(sm.WorkOrd COLLATE {C}) LIKE @WorkOrd");
  42. pars.Add(new SugarParameter("@WorkOrd", $"%{input.WorkOrd.Trim()}%"));
  43. }
  44. if (!string.IsNullOrWhiteSpace(input.ItemNum))
  45. {
  46. inner.Add($"(sm.ItemNum COLLATE {C}) = @ItemNumEq");
  47. pars.Add(new SugarParameter("@ItemNumEq", input.ItemNum.Trim()));
  48. }
  49. var baseSql = BuildListBaseSql(string.Join(" AND ", inner));
  50. var offset = (input.Page - 1) * input.PageSize;
  51. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(*) FROM ({baseSql}) AS t", pars);
  52. var list = await _db.Ado.SqlQueryAsync<ScheduleExceptionListRow>(
  53. $"SELECT * FROM ({baseSql}) AS t ORDER BY t.Id DESC LIMIT {input.PageSize} OFFSET {offset}", pars);
  54. return new { total, page = input.Page, pageSize = input.PageSize, list };
  55. }
  56. private static string BuildListBaseSql(string innerWhere)
  57. {
  58. const string coll = "utf8mb4_general_ci";
  59. return $"""
  60. SELECT
  61. sm.RecID AS Id,
  62. sm.`Domain` AS Domain,
  63. sm.OptTime AS OptTime,
  64. sm.WorkOrd AS WorkOrd,
  65. sm.ItemNum AS ItemNum,
  66. im.Descr1 AS Descr1,
  67. sm.Remark AS Remark,
  68. sm.Type AS Type
  69. FROM ScheduleExceptionMaster sm
  70. LEFT JOIN ItemMaster im
  71. ON (sm.`Domain` COLLATE {coll}) = (im.`Domain` COLLATE {coll})
  72. AND (sm.ItemNum COLLATE {coll}) = (im.ItemNum COLLATE {coll})
  73. WHERE {innerWhere}
  74. """;
  75. }
  76. // ══════════════════════════════════════════════════════════════
  77. // 详情 GET /api/Production/schedule-exception/{id}
  78. // ══════════════════════════════════════════════════════════════
  79. /// <summary>排产异常详情</summary>
  80. [DisplayName("排产异常记录详情")]
  81. [HttpGet("schedule-exception/{id:long}")]
  82. public async Task<object> GetDetail(long id)
  83. {
  84. var tenantId = _userManager.TenantId;
  85. var e = await _rep.GetFirstAsync(u => u.RecID == id && u.TenantId == tenantId)
  86. ?? throw Oops.Oh("记录不存在");
  87. return new
  88. {
  89. id = e.RecID,
  90. domain = e.Domain,
  91. workOrd = e.WorkOrd,
  92. itemNum = e.ItemNum,
  93. remark = e.Remark,
  94. type = e.Type,
  95. optTime = e.OptTime,
  96. createTime = e.CreateTime
  97. };
  98. }
  99. // ══════════════════════════════════════════════════════════════
  100. // 保存 POST /api/Production/schedule-exception/save
  101. // ══════════════════════════════════════════════════════════════
  102. /// <summary>保存排产异常(新增或编辑)</summary>
  103. [DisplayName("保存排产异常记录")]
  104. [ApiDescriptionSettings(Name = "SaveScheduleException"), HttpPost("schedule-exception/save")]
  105. public async Task<object> Save([FromBody] ScheduleExceptionSaveInput input)
  106. {
  107. var tenantId = _userManager.TenantId;
  108. if (input.Id is null or 0)
  109. {
  110. var entity = new ScheduleExceptionMaster
  111. {
  112. RecID = YitIdHelper.NextId(),
  113. Domain = input.Domain.Trim(),
  114. WorkOrd = input.WorkOrd.Trim(),
  115. ItemNum = input.ItemNum.Trim(),
  116. Remark = input.Remark?.Trim(),
  117. Type = input.Type?.Trim(),
  118. OptTime = input.OptTime ?? DateTime.Now,
  119. CreateTime = input.CreateTime ?? DateTime.Now,
  120. TenantId = tenantId
  121. };
  122. await _rep.InsertAsync(entity);
  123. return new { id = entity.RecID, message = "新增成功" };
  124. }
  125. var exist = await _rep.GetFirstAsync(u => u.RecID == input.Id!.Value && u.TenantId == tenantId)
  126. ?? throw Oops.Oh("记录不存在");
  127. exist.Domain = input.Domain.Trim();
  128. exist.WorkOrd = input.WorkOrd.Trim();
  129. exist.ItemNum = input.ItemNum.Trim();
  130. exist.Remark = input.Remark?.Trim();
  131. exist.Type = input.Type?.Trim();
  132. if (input.OptTime.HasValue) exist.OptTime = input.OptTime;
  133. if (input.CreateTime.HasValue) exist.CreateTime = input.CreateTime;
  134. await _rep.UpdateAsync(exist);
  135. return new { id = exist.RecID, message = "编辑成功" };
  136. }
  137. // ══════════════════════════════════════════════════════════════
  138. // 删除 POST /api/Production/schedule-exception/delete/{id}
  139. // ══════════════════════════════════════════════════════════════
  140. /// <summary>删除排产异常</summary>
  141. [DisplayName("删除排产异常记录")]
  142. [HttpPost("schedule-exception/delete/{id:long}")]
  143. public async Task<object> Delete(long id)
  144. {
  145. var tenantId = _userManager.TenantId;
  146. var n = await _db.Ado.ExecuteCommandAsync(
  147. "DELETE FROM ScheduleExceptionMaster WHERE RecID = @Id AND tenant_id = @TenantId",
  148. new List<SugarParameter> { new("@Id", id), new("@TenantId", tenantId) });
  149. if (n == 0)
  150. throw Oops.Oh("记录不存在");
  151. return new { message = "删除成功" };
  152. }
  153. private sealed class ScheduleExceptionListRow
  154. {
  155. public long Id { get; set; }
  156. public string? Domain { get; set; }
  157. public DateTime? OptTime { get; set; }
  158. public string? WorkOrd { get; set; }
  159. public string? ItemNum { get; set; }
  160. public string? Descr1 { get; set; }
  161. public string? Remark { get; set; }
  162. public string? Type { get; set; }
  163. }
  164. }