AdoS8ExceptionsController.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using Admin.NET.Plugin.AiDOP.Dto.S8;
  2. using Admin.NET.Plugin.AiDOP.Infrastructure;
  3. using Admin.NET.Plugin.AiDOP.Service.S8;
  4. namespace Admin.NET.Plugin.AiDOP.Controllers.S8;
  5. [ApiController]
  6. [Route("api/aidop/s8/exceptions")]
  7. [NonUnify]
  8. public class AdoS8ExceptionsController : ControllerBase
  9. {
  10. private readonly S8ExceptionService _exceptionSvc;
  11. private readonly S8TaskFlowService _taskFlowSvc;
  12. private readonly S8DecisionService _decisionSvc;
  13. private readonly S8TrustedScopeResolver _scope;
  14. public AdoS8ExceptionsController(
  15. S8ExceptionService exceptionSvc,
  16. S8TaskFlowService taskFlowSvc,
  17. S8DecisionService decisionSvc,
  18. S8TrustedScopeResolver scope)
  19. {
  20. _exceptionSvc = exceptionSvc;
  21. _taskFlowSvc = taskFlowSvc;
  22. _decisionSvc = decisionSvc;
  23. _scope = scope;
  24. }
  25. [HttpGet]
  26. public async Task<IActionResult> GetPagedAsync([FromQuery] AdoS8ExceptionQueryDto q)
  27. {
  28. // S8-TENANT-FACTORY-P0-CLOSURE-1:作用域一律服务端解析,覆盖客户端传入值。
  29. var scope = await _scope.ResolveAsync();
  30. q.TenantId = scope.TenantId;
  31. q.FactoryId = scope.FactoryId;
  32. var (total, list) = await _exceptionSvc.GetPagedAsync(q);
  33. return Ok(new { total, page = q.Page, pageSize = q.PageSize, list });
  34. }
  35. [HttpGet("filter-options")]
  36. public async Task<IActionResult> GetFilterOptionsAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1)
  37. {
  38. // Compatibility-only. Security scope is resolved server-side.
  39. _ = tenantId; _ = factoryId;
  40. var scope = await _scope.ResolveAsync();
  41. return Ok(await _exceptionSvc.GetFilterOptionsAsync(scope.TenantId, scope.FactoryId));
  42. }
  43. [HttpGet("{id:long}")]
  44. public async Task<IActionResult> GetDetailAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1)
  45. {
  46. // Compatibility-only. Security scope is resolved server-side.
  47. _ = tenantId; _ = factoryId;
  48. var scope = await _scope.ResolveAsync();
  49. var detail = await _exceptionSvc.GetDetailAsync(id, scope.TenantId, scope.FactoryId);
  50. return detail == null ? NotFound() : Ok(detail);
  51. }
  52. [HttpGet("{id:long}/timeline")]
  53. public async Task<IActionResult> GetTimelineAsync(long id)
  54. {
  55. if (!await IsInScopeAsync(id)) return NotFound();
  56. return Ok(await _decisionSvc.GetTimelineAsync(id));
  57. }
  58. [HttpGet("{id:long}/decisions")]
  59. public async Task<IActionResult> GetDecisionsAsync(long id)
  60. {
  61. if (!await IsInScopeAsync(id)) return NotFound();
  62. return Ok(await _decisionSvc.GetDecisionsAsync(id));
  63. }
  64. [HttpGet("{id:long}/evidences")]
  65. public async Task<IActionResult> GetEvidencesAsync(long id)
  66. {
  67. if (!await IsInScopeAsync(id)) return NotFound();
  68. return Ok(await _decisionSvc.GetEvidencesAsync(id));
  69. }
  70. /// <summary>子资源归属由父异常派生;不在可信作用域内一律按「不存在」处理,不泄露他租户资源是否存在。</summary>
  71. private async Task<bool> IsInScopeAsync(long exceptionId)
  72. {
  73. var scope = await _scope.ResolveAsync();
  74. return await _decisionSvc.IsExceptionInScopeAsync(exceptionId, scope.TenantId, scope.FactoryId);
  75. }
  76. [HttpPost("{id:long}/claim")]
  77. public async Task<IActionResult> ClaimAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  78. [FromBody] AdoS8ClaimBody? body = null)
  79. {
  80. _ = tenantId; _ = factoryId;
  81. try
  82. {
  83. var scope = await _scope.ResolveAsync();
  84. var e = await _taskFlowSvc.ClaimAsync(id, scope.TenantId, scope.FactoryId, body?.AssigneeId ?? 0, body?.Remark);
  85. return Ok(new { id = e.Id, status = e.Status });
  86. }
  87. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  88. }
  89. [HttpPost("{id:long}/transfer")]
  90. public async Task<IActionResult> TransferAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  91. [FromBody] AdoS8TransferDto? body = null)
  92. {
  93. _ = tenantId; _ = factoryId;
  94. try
  95. {
  96. var scope = await _scope.ResolveAsync();
  97. var e = await _taskFlowSvc.TransferAsync(id, scope.TenantId, scope.FactoryId, body?.AssigneeId ?? 0, body?.Remark);
  98. return Ok(new { id = e.Id, assigneeId = e.AssigneeId });
  99. }
  100. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  101. }
  102. [HttpPost("{id:long}/start-progress")]
  103. public async Task<IActionResult> StartProgressAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  104. [FromBody] AdoS8CommentDto? body = null)
  105. {
  106. _ = tenantId; _ = factoryId;
  107. try
  108. {
  109. var scope = await _scope.ResolveAsync();
  110. var e = await _taskFlowSvc.StartProgressAsync(id, scope.TenantId, scope.FactoryId, body?.Remark);
  111. return Ok(new { id = e.Id, status = e.Status });
  112. }
  113. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  114. }
  115. [HttpPost("{id:long}/upgrade")]
  116. public async Task<IActionResult> UpgradeAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  117. [FromBody] AdoS8CommentDto? body = null)
  118. {
  119. _ = tenantId; _ = factoryId;
  120. try
  121. {
  122. var scope = await _scope.ResolveAsync();
  123. var e = await _taskFlowSvc.UpgradeAsync(id, scope.TenantId, scope.FactoryId, body?.Remark);
  124. return Ok(new { id = e.Id, status = e.Status });
  125. }
  126. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  127. }
  128. [HttpPost("{id:long}/reject")]
  129. public async Task<IActionResult> RejectAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  130. [FromBody] AdoS8CommentDto? body = null)
  131. {
  132. _ = tenantId; _ = factoryId;
  133. try
  134. {
  135. var scope = await _scope.ResolveAsync();
  136. var e = await _taskFlowSvc.RejectAsync(id, scope.TenantId, scope.FactoryId, body?.Remark);
  137. return Ok(new { id = e.Id, status = e.Status });
  138. }
  139. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  140. }
  141. [HttpPost("{id:long}/submit-verification")]
  142. public async Task<IActionResult> SubmitVerificationAsync(long id,
  143. [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  144. [FromBody] AdoS8SubmitVerificationDto? body = null)
  145. {
  146. _ = tenantId; _ = factoryId;
  147. try
  148. {
  149. var scope = await _scope.ResolveAsync();
  150. var e = await _taskFlowSvc.SubmitVerificationAsync(
  151. id, scope.TenantId, scope.FactoryId, body?.VerifierId ?? 0, body?.Remark);
  152. return Ok(new { id = e.Id, status = e.Status, verifierId = e.VerifierId });
  153. }
  154. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  155. }
  156. [HttpPost("{id:long}/approve-verification")]
  157. public async Task<IActionResult> ApproveVerificationAsync(long id,
  158. [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  159. [FromBody] AdoS8ApproveVerificationDto? body = null)
  160. {
  161. _ = tenantId; _ = factoryId;
  162. try
  163. {
  164. var scope = await _scope.ResolveAsync();
  165. var e = await _taskFlowSvc.ApproveVerificationAsync(id, scope.TenantId, scope.FactoryId, body?.Remark);
  166. return Ok(new { id = e.Id, status = e.Status });
  167. }
  168. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  169. }
  170. [HttpPost("{id:long}/reject-verification")]
  171. public async Task<IActionResult> RejectVerificationAsync(long id,
  172. [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  173. [FromBody] AdoS8RejectVerificationDto? body = null)
  174. {
  175. _ = tenantId; _ = factoryId;
  176. try
  177. {
  178. var scope = await _scope.ResolveAsync();
  179. var e = await _taskFlowSvc.RejectVerificationAsync(id, scope.TenantId, scope.FactoryId, body?.Remark ?? string.Empty);
  180. return Ok(new { id = e.Id, status = e.Status });
  181. }
  182. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  183. }
  184. [HttpPost("{id:long}/comment")]
  185. public async Task<IActionResult> CommentAsync(long id, [FromBody] AdoS8CommentDto? body = null)
  186. {
  187. try
  188. {
  189. var scope = await _scope.ResolveAsync();
  190. await _taskFlowSvc.CommentAsync(id, scope.TenantId, scope.FactoryId, body?.Remark);
  191. return Ok(new { id });
  192. }
  193. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  194. }
  195. }
  196. public class AdoS8ClaimBody
  197. {
  198. public long AssigneeId { get; set; }
  199. public string? Remark { get; set; }
  200. }