AdoS8ExceptionsController.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. var (total, list) = await _exceptionSvc.GetPagedAsync(q);
  35. return Ok(new { total, page = q.Page, pageSize = q.PageSize, list });
  36. }
  37. [HttpGet("filter-options")]
  38. [S8Permission(S8PermissionCatalog.ExceptionRead)]
  39. public async Task<IActionResult> GetFilterOptionsAsync([FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1)
  40. {
  41. // Compatibility-only. Security scope is resolved server-side.
  42. _ = tenantId; _ = factoryId;
  43. var scope = await _scope.ResolveAsync();
  44. return Ok(await _exceptionSvc.GetFilterOptionsAsync(scope.TenantId));
  45. }
  46. [HttpGet("{id:long}")]
  47. [S8Permission(S8PermissionCatalog.ExceptionRead)]
  48. public async Task<IActionResult> GetDetailAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1)
  49. {
  50. // Compatibility-only. Security scope is resolved server-side.
  51. _ = tenantId; _ = factoryId;
  52. var scope = await _scope.ResolveAsync();
  53. var detail = await _exceptionSvc.GetDetailAsync(id, scope.TenantId);
  54. return detail == null ? NotFound() : Ok(detail);
  55. }
  56. [HttpGet("{id:long}/timeline")]
  57. [S8Permission(S8PermissionCatalog.ExceptionRead)]
  58. public async Task<IActionResult> GetTimelineAsync(long id)
  59. {
  60. if (!await IsInScopeAsync(id)) return NotFound();
  61. return Ok(await _decisionSvc.GetTimelineAsync(id));
  62. }
  63. [HttpGet("{id:long}/decisions")]
  64. [S8Permission(S8PermissionCatalog.ExceptionRead)]
  65. public async Task<IActionResult> GetDecisionsAsync(long id)
  66. {
  67. if (!await IsInScopeAsync(id)) return NotFound();
  68. return Ok(await _decisionSvc.GetDecisionsAsync(id));
  69. }
  70. [HttpGet("{id:long}/evidences")]
  71. [S8Permission(S8PermissionCatalog.ExceptionRead)]
  72. public async Task<IActionResult> GetEvidencesAsync(long id)
  73. {
  74. if (!await IsInScopeAsync(id)) return NotFound();
  75. return Ok(await _decisionSvc.GetEvidencesAsync(id));
  76. }
  77. /// <summary>子资源归属由父异常派生;不在可信作用域内一律按「不存在」处理,不泄露他租户资源是否存在。</summary>
  78. private async Task<bool> IsInScopeAsync(long exceptionId)
  79. {
  80. var scope = await _scope.ResolveAsync();
  81. return await _decisionSvc.IsExceptionInScopeAsync(exceptionId, scope.TenantId);
  82. }
  83. [HttpPost("{id:long}/claim")]
  84. [S8Permission(S8PermissionCatalog.ExceptionClaim)]
  85. public async Task<IActionResult> ClaimAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  86. [FromBody] AdoS8ClaimBody? body = null)
  87. {
  88. _ = tenantId; _ = factoryId;
  89. try
  90. {
  91. var scope = await _scope.ResolveAsync();
  92. var e = await _taskFlowSvc.ClaimAsync(id, scope.TenantId, body?.AssigneeId ?? 0, body?.Remark);
  93. return Ok(new { id = e.Id, status = e.Status });
  94. }
  95. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  96. }
  97. [HttpPost("{id:long}/transfer")]
  98. [S8Permission(S8PermissionCatalog.ExceptionAssign)]
  99. public async Task<IActionResult> TransferAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  100. [FromBody] AdoS8TransferDto? body = null)
  101. {
  102. _ = tenantId; _ = factoryId;
  103. try
  104. {
  105. var scope = await _scope.ResolveAsync();
  106. var e = await _taskFlowSvc.TransferAsync(id, scope.TenantId, body?.AssigneeId ?? 0, body?.Remark);
  107. return Ok(new { id = e.Id, assigneeId = e.AssigneeId });
  108. }
  109. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  110. }
  111. [HttpPost("{id:long}/start-progress")]
  112. [S8Permission(S8PermissionCatalog.ExceptionStart)]
  113. public async Task<IActionResult> StartProgressAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  114. [FromBody] AdoS8CommentDto? body = null)
  115. {
  116. _ = tenantId; _ = factoryId;
  117. try
  118. {
  119. var scope = await _scope.ResolveAsync();
  120. var e = await _taskFlowSvc.StartProgressAsync(id, scope.TenantId, body?.Remark);
  121. return Ok(new { id = e.Id, status = e.Status });
  122. }
  123. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  124. }
  125. [HttpPost("{id:long}/upgrade")]
  126. [S8Permission(S8PermissionCatalog.ExceptionUpgrade)]
  127. public async Task<IActionResult> UpgradeAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  128. [FromBody] AdoS8CommentDto? body = null)
  129. {
  130. _ = tenantId; _ = factoryId;
  131. try
  132. {
  133. var scope = await _scope.ResolveAsync();
  134. var e = await _taskFlowSvc.UpgradeAsync(id, scope.TenantId, body?.Remark);
  135. return Ok(new { id = e.Id, status = e.Status });
  136. }
  137. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  138. }
  139. [HttpPost("{id:long}/reject")]
  140. [S8Permission(S8PermissionCatalog.ExceptionReject)]
  141. public async Task<IActionResult> RejectAsync(long id, [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  142. [FromBody] AdoS8CommentDto? body = null)
  143. {
  144. _ = tenantId; _ = factoryId;
  145. try
  146. {
  147. var scope = await _scope.ResolveAsync();
  148. var e = await _taskFlowSvc.RejectAsync(id, scope.TenantId, body?.Remark);
  149. return Ok(new { id = e.Id, status = e.Status });
  150. }
  151. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  152. }
  153. [HttpPost("{id:long}/submit-verification")]
  154. [S8Permission(S8PermissionCatalog.VerificationSubmit)]
  155. public async Task<IActionResult> SubmitVerificationAsync(long id,
  156. [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  157. [FromBody] AdoS8SubmitVerificationDto? body = null)
  158. {
  159. _ = tenantId; _ = factoryId;
  160. try
  161. {
  162. var scope = await _scope.ResolveAsync();
  163. var e = await _taskFlowSvc.SubmitVerificationAsync(
  164. id, scope.TenantId, body?.VerifierId ?? 0, body?.Remark);
  165. return Ok(new { id = e.Id, status = e.Status, verifierId = e.VerifierId });
  166. }
  167. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  168. }
  169. [HttpPost("{id:long}/approve-verification")]
  170. [S8Permission(S8PermissionCatalog.VerificationApprove)]
  171. public async Task<IActionResult> ApproveVerificationAsync(long id,
  172. [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  173. [FromBody] AdoS8ApproveVerificationDto? body = null)
  174. {
  175. _ = tenantId; _ = factoryId;
  176. try
  177. {
  178. var scope = await _scope.ResolveAsync();
  179. var e = await _taskFlowSvc.ApproveVerificationAsync(id, scope.TenantId, body?.Remark);
  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}/reject-verification")]
  185. [S8Permission(S8PermissionCatalog.VerificationReject)]
  186. public async Task<IActionResult> RejectVerificationAsync(long id,
  187. [FromQuery] long tenantId = 1, [FromQuery] long factoryId = 1,
  188. [FromBody] AdoS8RejectVerificationDto? body = null)
  189. {
  190. _ = tenantId; _ = factoryId;
  191. try
  192. {
  193. var scope = await _scope.ResolveAsync();
  194. var e = await _taskFlowSvc.RejectVerificationAsync(id, scope.TenantId, body?.Remark ?? string.Empty);
  195. return Ok(new { id = e.Id, status = e.Status });
  196. }
  197. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  198. }
  199. [HttpPost("{id:long}/comment")]
  200. [S8Permission(S8PermissionCatalog.ExceptionComment)]
  201. public async Task<IActionResult> CommentAsync(long id, [FromBody] AdoS8CommentDto? body = null)
  202. {
  203. try
  204. {
  205. var scope = await _scope.ResolveAsync();
  206. await _taskFlowSvc.CommentAsync(id, scope.TenantId, body?.Remark);
  207. return Ok(new { id });
  208. }
  209. catch (S8BizException ex) { return BadRequest(new { message = ex.Message }); }
  210. }
  211. }
  212. public class AdoS8ClaimBody
  213. {
  214. public long AssigneeId { get; set; }
  215. public string? Remark { get; set; }
  216. }