OrderTerminateController.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. using Hotline.Orders;
  2. using Hotline.Permissions;
  3. using Hotline.Quality;
  4. using Hotline.Share.Dtos.Quality;
  5. using Hotline.Share.Dtos;
  6. using Microsoft.AspNetCore.Mvc;
  7. using XF.Domain.Authentications;
  8. using XF.Domain.Exceptions;
  9. using XF.Domain.Repository;
  10. using Hotline.Api.Filter;
  11. using Hotline.Caching.Services;
  12. using Hotline.FlowEngine.WorkflowModules;
  13. using Hotline.Repository.SqlSugar.Orders;
  14. using Hotline.Settings;
  15. using Hotline.Share.Dtos.FlowEngine;
  16. using Hotline.Share.Dtos.Order;
  17. using Hotline.Share.Enums.FlowEngine;
  18. using Hotline.Share.Enums.Order;
  19. using Hotline.Share.Enums.Settings;
  20. using SqlSugar;
  21. using XF.Utility.EnumExtensions;
  22. using MapsterMapper;
  23. using Hotline.File;
  24. using Hotline.Application.FlowEngine;
  25. using Hotline.Application.OrderApp;
  26. using Hotline.FlowEngine.Workflows;
  27. using Hotline.Repository.SqlSugar.Extensions;
  28. using Hotline.Share.Dtos.FlowEngine.Workflow;
  29. using Hotline.Share.Requests;
  30. using Hotline.Tools;
  31. using Hotline.Configurations;
  32. using Microsoft.Extensions.Options;
  33. namespace Hotline.Api.Controllers
  34. {
  35. /// <summary>
  36. /// 终止管理
  37. /// </summary>
  38. public class OrderTerminateController : BaseController
  39. {
  40. private readonly ISessionContext _sessionContext;
  41. private readonly IMapper _mapper;
  42. private readonly IFileRepository _fileRepository;
  43. private readonly IWorkflowApplication _workflowApplication;
  44. private readonly IRepository<Workflow> _workflowRepository;
  45. private readonly IWorkflowDomainService _workflowDomainService;
  46. private readonly IOrderRepository _orderRepository;
  47. private readonly IOrderDomainService _orderDomainService;
  48. private readonly IOrderTerminateRepository _orderTerminateRepository;
  49. private readonly IOrderApplication _orderApplication;
  50. private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
  51. public OrderTerminateController(
  52. ISessionContext sessionContext,
  53. IMapper mapper,
  54. IFileRepository fileRepository,
  55. IWorkflowApplication workflowApplication,
  56. IRepository<Workflow> workflowRepository,
  57. IWorkflowDomainService workflowDomainService,
  58. IOrderRepository orderRepository,
  59. IOrderDomainService orderDomainService,
  60. IOrderTerminateRepository orderTerminateRepository,
  61. IOrderApplication orderApplication,
  62. IOptionsSnapshot<AppConfiguration> appOptions
  63. )
  64. {
  65. _sessionContext = sessionContext;
  66. _mapper = mapper;
  67. _fileRepository = fileRepository;
  68. _workflowApplication = workflowApplication;
  69. _workflowRepository = workflowRepository;
  70. _workflowDomainService = workflowDomainService;
  71. _orderRepository = orderRepository;
  72. _orderDomainService = orderDomainService;
  73. _orderTerminateRepository = orderTerminateRepository;
  74. _orderApplication = orderApplication;
  75. _appOptions = appOptions;
  76. }
  77. /// <summary>
  78. /// 工单终止待申请列表
  79. /// </summary>
  80. /// <param name="dto"></param>
  81. /// <returns></returns>
  82. [HttpGet("may-terminate")]
  83. public async Task<PagedDto<OrderDto>> MayOrderTerminateList([FromQuery] OrderTerminateListDto dto)
  84. {
  85. var isAdmin = _orderDomainService.IsCheckAdmin();
  86. var (total, items) = await _orderRepository.Queryable(isAdmin: isAdmin)
  87. .Includes(d => d.OrderTerminates)
  88. .WhereIF(_appOptions.Value.IsZiGong, d => d.Source != ESource.ProvinceStraight)//自贡任务 495 终止申请页面只显示市工单
  89. .Where(d => SqlFunc.Subqueryable<OrderTerminate>().Where(t => t.OrderId == d.Id && t.Status != ETerminateStatus.SendBackStart).NotAny())
  90. .Where(d => d.Status >= EOrderStatus.Filed && d.ActualHandleOrgCode.StartsWith(_sessionContext.OrgId))
  91. .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No!.Contains(dto.No!))
  92. .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
  93. .WhereIF(dto.ApplyStartTime.HasValue && dto.ApplyEndTime.HasValue,
  94. d => d.OrderTerminates.Any(t => t.CreationTime >= dto.ApplyStartTime && t.CreationTime <= dto.ApplyEndTime))
  95. .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.StartTime >= dto.StartTime && d.StartTime <= dto.EndTime)
  96. .OrderByDescending(d => d.StartTime)
  97. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  98. return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
  99. }
  100. /// <summary>
  101. /// 工单终止列表
  102. /// </summary>
  103. /// <param name="dto"></param>
  104. /// <returns></returns>
  105. [HttpGet]
  106. public async Task<PagedDto<OrderTerminateEntityDto>> OrderTerminateList([FromQuery] OrderTerminateListDto dto)
  107. {
  108. var (total, items) = await _orderApplication.OrderTerminateList(dto)
  109. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  110. return new PagedDto<OrderTerminateEntityDto>(total, _mapper.Map<IReadOnlyList<OrderTerminateEntityDto>>(items));
  111. }
  112. /// <summary>
  113. /// 工单终止列表导出
  114. /// </summary>
  115. /// <param name="dto"></param>
  116. /// <returns></returns>
  117. [HttpPost("export")]
  118. public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<OrderTerminateListDto> dto)
  119. {
  120. var query = _orderApplication.OrderTerminateList(dto.QueryDto);
  121. List<OrderTerminate> data;
  122. if (dto.IsExportAll)
  123. {
  124. data = await query.ToListAsync(HttpContext.RequestAborted);
  125. }
  126. else
  127. {
  128. var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
  129. data = items;
  130. }
  131. var dataDtos = _mapper.Map<ICollection<OrderTerminateEntityDto>>(data);
  132. dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderTerminateEntityDto>(dto.ColumnInfos);
  133. var dtos = dataDtos
  134. .Select(stu => _mapper.Map(stu, typeof(OrderTerminateEntityDto), dynamicClass))
  135. .Cast<object>()
  136. .ToList();
  137. var stream = ExcelHelper.CreateStream(dtos);
  138. return ExcelStreamResult(stream, "工单终止列表");
  139. }
  140. /// <summary>
  141. /// 开始工单终止流程
  142. /// </summary>
  143. [HttpPost("startflow")]
  144. [LogFilter("开始工单终止流程")]
  145. public async Task StartFlow([FromBody] StartWorkflowDto<OrderTerminateDto> dto)
  146. {
  147. var screenAny = await _orderTerminateRepository.AnyAsync(x =>
  148. x.OrderId == dto.Data.OrderId && x.Status == ETerminateStatus.Approval);
  149. if (screenAny)
  150. throw UserFriendlyException.SameMessage("该工单已提起终止申请,正在审批过程中,不能申请");
  151. var isNoPass = await _orderTerminateRepository.AnyAsync(x => x.Status == ETerminateStatus.Refuse && x.OrderId == dto.Data.OrderId);
  152. if (isNoPass)
  153. throw UserFriendlyException.SameMessage("该工单已被拒绝过终止申请,不能再次申请");
  154. var model = _mapper.Map<OrderTerminate>(dto.Data);
  155. model.Status = ETerminateStatus.Approval;
  156. model.InitId();
  157. if (dto.Data.Files.Any())
  158. model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
  159. else
  160. model.FileJson = new List<Share.Dtos.File.FileJson>();
  161. await _orderTerminateRepository.AddAsync(model, HttpContext.RequestAborted);
  162. try
  163. {
  164. var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
  165. startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderTerminate;
  166. startDto.Opinion = dto.Data.Content;
  167. startDto.Title = "申请终止流程";
  168. // await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
  169. // await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
  170. await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
  171. }
  172. catch (Exception e)
  173. {
  174. await _orderTerminateRepository.RemoveAsync(model.Id);
  175. model.Id = string.Empty;
  176. throw new UserFriendlyException($"工单开启终止流程失败!, {e.Message}", "工单开启终止流程失败");
  177. }
  178. }
  179. /// <summary>
  180. /// 工单终止修改后下一步流程
  181. /// </summary>
  182. [HttpPost("initial_nextFlow")]
  183. [LogFilter("办理工单终止流程")]
  184. public async Task InitialNextFlow([FromBody] TerminateNextFlowDto dto)
  185. {
  186. var model = await _orderTerminateRepository.GetAsync(dto.Data.Id);
  187. if (dto.Data.Files.Any())
  188. model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
  189. else
  190. model.FileJson = new List<Share.Dtos.File.FileJson>();
  191. model.Status = ETerminateStatus.Approval;
  192. model.Content = dto.Data.Content;
  193. model.IsRecommit = true;
  194. await _orderTerminateRepository.UpdateAsync(model, HttpContext.RequestAborted);
  195. try
  196. {
  197. dto.NextWorkflow.WorkflowId = model.WorkflowId;
  198. await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
  199. }
  200. catch (Exception e)
  201. {
  202. throw new UserFriendlyException($"工单终止下一步流程失败!, {e.Message}", "工单终止下一步流程失败");
  203. }
  204. }
  205. /// <summary>
  206. /// 查询工单终止流程开启参数
  207. /// </summary>
  208. /// <returns></returns>
  209. [HttpGet("screen/startflow")]
  210. public async Task<NextStepsDto> GetTerminateFlowStartOptionsAsync()
  211. {
  212. return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderTerminate,
  213. HttpContext.RequestAborted);
  214. }
  215. /// <summary>
  216. /// 查询工单终止流程参数
  217. /// </summary>
  218. /// <returns></returns>
  219. [HttpGet("workflow/{id}")]
  220. public async Task<string> GetTerminateWorkFlowAsync(string id)
  221. {
  222. var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
  223. return workflow.Id;
  224. }
  225. /// <summary>
  226. /// 甄别查询流程办理下一步可选节点
  227. /// </summary>
  228. /// <param name="workflowId"></param>
  229. /// <returns></returns>
  230. [HttpGet("{workflowId}/nextsteps")]
  231. public async Task<NextStepsDto> OrderTerminateNextsteps(string workflowId)
  232. {
  233. return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
  234. }
  235. /// <summary>
  236. /// 终止详情
  237. /// </summary>
  238. /// <param name="id"></param>
  239. /// <returns></returns>
  240. [HttpGet("{id}")]
  241. public async Task<OrderTerminateEntityDto> Entity(string id)
  242. {
  243. var model = await _orderTerminateRepository.Queryable()
  244. .Includes(x => x.Order)
  245. .Includes(x => x.Workflow, d => d.Steps)
  246. .FirstAsync(x => x.Id == id);
  247. var rspModel = _mapper.Map<OrderTerminateEntityDto>(model);
  248. rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
  249. _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
  250. if (model.Status == ETerminateStatus.SendBackStart)
  251. rspModel.IsCanHandle = false;
  252. rspModel.Handle = false;
  253. if (!string.IsNullOrEmpty(rspModel.WorkflowId))
  254. {
  255. rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
  256. _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
  257. }
  258. if (rspModel.FileJson != null && rspModel.FileJson.Any())
  259. {
  260. var ids = rspModel.FileJson.Select(x => x.Id).ToList();
  261. rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
  262. }
  263. return rspModel;
  264. }
  265. /// <summary>
  266. /// 列表页面基础数据
  267. /// </summary>
  268. /// <returns></returns>
  269. [HttpGet("base")]
  270. public async Task<object> BaseData()
  271. {
  272. var rsp = new
  273. {
  274. Status = EnumExts.GetDescriptions<ETerminateStatus>(),
  275. };
  276. return rsp;
  277. }
  278. /// <summary>
  279. /// 终止修改理由
  280. /// </summary>
  281. /// <param name="dto"></param>
  282. /// <returns></returns>
  283. [HttpPut("update_content")]
  284. [LogFilter("终止修改理由")]
  285. public async Task Update([FromBody] OrderTerminateContentDto dto)
  286. {
  287. await _orderTerminateRepository.Updateable().SetColumns(x => new OrderTerminate { Content = dto.Content }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
  288. }
  289. }
  290. }