AdoS8ExceptionsController.cs 9.6 KB

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