OrderController.cs 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  1. using DotNetCore.CAP;
  2. using Hotline.Application.FlowEngine;
  3. using Hotline.Application.TimeLimits;
  4. using Hotline.Caching.Interfaces;
  5. using Hotline.File;
  6. using Hotline.FlowEngine.Definitions;
  7. using Hotline.FlowEngine.WfModules;
  8. using Hotline.FlowEngine.Workflows;
  9. using Hotline.Orders;
  10. using Hotline.Orders.Notifications;
  11. using Hotline.Permissions;
  12. using Hotline.Repository.SqlSugar.Extensions;
  13. using Hotline.Repository.SqlSugar.Ts;
  14. using Hotline.Settings;
  15. using Hotline.Settings.Hotspots;
  16. using Hotline.Settings.TimeLimits;
  17. using Hotline.Share.Dtos;
  18. using Hotline.Share.Dtos.FlowEngine;
  19. using Hotline.Share.Dtos.Order;
  20. using Hotline.Share.Enums.Order;
  21. using Hotline.Share.Enums.Settings;
  22. using Hotline.Share.Mq;
  23. using Hotline.Share.Requests;
  24. using MapsterMapper;
  25. using MediatR;
  26. using Microsoft.AspNetCore.Mvc;
  27. using Microsoft.IdentityModel.Tokens;
  28. using MongoDB.Driver;
  29. using SqlSugar;
  30. using System.Threading;
  31. using XF.Domain.Authentications;
  32. using XF.Domain.Constants;
  33. using XF.Domain.Exceptions;
  34. using XF.Domain.Repository;
  35. using XF.Utility.EnumExtensions;
  36. namespace Hotline.Api.Controllers;
  37. /// <summary>
  38. /// 工单
  39. /// </summary>
  40. public class OrderController : BaseController
  41. {
  42. private readonly IOrderDomainService _orderDomainService;
  43. private readonly IOrderRepository _orderRepository;
  44. private readonly IWorkflowApplication _workflowApplication;
  45. private readonly IWorkflowDomainService _workflowDomainService;
  46. private readonly IRepository<Hotspot> _hotspotTypeRepository;
  47. private readonly ISystemDomainService _systemDomainService;
  48. private readonly ISystemOrganizeRepository _organizeRepository;
  49. private readonly IDefinitionDomainService _definitionDomainService;
  50. private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
  51. private readonly ISessionContext _sessionContext;
  52. private readonly IMapper _mapper;
  53. private readonly IMediator _mediator;
  54. private readonly IRepository<OrderPublish> _orderPublishRepository;
  55. private readonly IRepository<OrderVisit> _orderVisitRepository;
  56. private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
  57. private readonly ICapPublisher _capPublisher;
  58. private readonly IRepository<OrderDelay> _orderDelayRepository;
  59. private readonly ITimeLimitApplication _timeLimitApplication;
  60. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  61. private readonly IRepository<OrderRedo> _orderRedoRepository;
  62. private readonly IRepository<OrderSupervise> _orderSuperviseRepository;
  63. private readonly IRepository<OrderUrge> _orderUrgeRepository;
  64. private readonly IFileRepository _fileRepository;
  65. private readonly IRepository<OrderScreen> _orderScreenRepository;
  66. private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
  67. private readonly IRepositoryTextSearch<OrderTs> _repositoryts;
  68. private readonly ITimeLimitDomainService _timeLimitDomainService;
  69. public OrderController(
  70. IOrderDomainService orderDomainService,
  71. IOrderRepository orderRepository,
  72. IWorkflowApplication workflowApplication,
  73. IWorkflowDomainService workflowDomainService,
  74. IRepository<Hotspot> hotspotTypeRepository,
  75. ISystemDomainService systemDomainService,
  76. ISystemOrganizeRepository organizeRepository,
  77. IDefinitionDomainService definitionDomainService,
  78. ISystemDicDataCacheManager sysDicDataCacheManager,
  79. ISessionContext sessionContext,
  80. IMapper mapper,
  81. IMediator mediator,
  82. IRepository<OrderPublish> orderPublishRepository,
  83. IRepository<OrderVisit> orderVisitRepository,
  84. IRepository<OrderVisitDetail> orderVisitedDetailRepository,
  85. ICapPublisher capPublisher,
  86. IRepository<OrderDelay> orderDelayRepository,
  87. ITimeLimitApplication timeLimitApplication,
  88. ISystemSettingCacheManager systemSettingCacheManager,
  89. IRepository<OrderRedo> orderRedoRepository,
  90. IRepository<OrderSupervise> orderSuperviseRepository,
  91. IRepository<OrderUrge> orderUrgeRepository,
  92. IFileRepository fileRepository,
  93. IRepository<OrderScreen> orderScreenRepository,
  94. IRepository<OrderPublishHistory> orderPublishHistoryRepository,
  95. IRepositoryTextSearch<OrderTs> repositoryts,
  96. ITimeLimitDomainService timeLimitDomainService
  97. )
  98. {
  99. _orderDomainService = orderDomainService;
  100. _orderRepository = orderRepository;
  101. _workflowApplication = workflowApplication;
  102. _workflowDomainService = workflowDomainService;
  103. _hotspotTypeRepository = hotspotTypeRepository;
  104. _systemDomainService = systemDomainService;
  105. _organizeRepository = organizeRepository;
  106. _definitionDomainService = definitionDomainService;
  107. _sysDicDataCacheManager = sysDicDataCacheManager;
  108. _sessionContext = sessionContext;
  109. _mapper = mapper;
  110. _mediator = mediator;
  111. _orderPublishRepository = orderPublishRepository;
  112. _orderVisitRepository = orderVisitRepository;
  113. _orderVisitedDetailRepository = orderVisitedDetailRepository;
  114. _capPublisher = capPublisher;
  115. _orderDelayRepository = orderDelayRepository;
  116. _timeLimitApplication = timeLimitApplication;
  117. _systemSettingCacheManager = systemSettingCacheManager;
  118. _orderRedoRepository = orderRedoRepository;
  119. _orderSuperviseRepository = orderSuperviseRepository;
  120. _orderUrgeRepository = orderUrgeRepository;
  121. _fileRepository = fileRepository;
  122. _orderScreenRepository = orderScreenRepository;
  123. _orderPublishHistoryRepository = orderPublishHistoryRepository;
  124. _repositoryts = repositoryts;
  125. _timeLimitDomainService = timeLimitDomainService;
  126. }
  127. #region 工单发布
  128. /// <summary>
  129. /// 查询(工单发布)
  130. /// </summary>
  131. /// <param name="dto"></param>
  132. /// <returns></returns>
  133. [Permission(EPermission.PublishOrderList)]
  134. [HttpGet("publish")]
  135. public async Task<PagedDto<PublishDto>> PublishOrderList([FromQuery] QueryOrderPublishDto dto)
  136. {
  137. var (total, items) = await _orderRepository.Queryable()
  138. .Includes(d => d.OrderPublish)
  139. .Where(x => x.Status == EOrderStatus.Filed)
  140. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
  141. .WhereIF(dto.PubState == EPubState.Pub, d => d.Status >= EOrderStatus.Published)
  142. .WhereIF(dto.PubState == EPubState.NoPub, d => d.Status < EOrderStatus.Published)
  143. .WhereIF(!string.IsNullOrEmpty(dto.PubMan), d => d.Acceptor.Name.Contains(dto.PubMan!) || d.Acceptor.StaffNo.Contains(dto.PubMan!))
  144. .WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublish.PublishState)
  145. .WhereIF(dto.PubRange == EPublicState.NoPub, d => !d.OrderPublish.PublishState)
  146. .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
  147. .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId))
  148. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
  149. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
  150. .WhereIF(dto.FiledTimeStart.HasValue, d => d.OrderPublish.CreationTime >= dto.CreationTimeStart)
  151. .WhereIF(dto.FiledTimeEnd.HasValue, d => d.OrderPublish.CreationTime <= dto.CreationTimeEnd)
  152. .OrderBy(d => d.CreationTime)
  153. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  154. return new PagedDto<PublishDto>(total, _mapper.Map<IReadOnlyList<PublishDto>>(items));
  155. }
  156. /// <summary>
  157. /// 发布工单
  158. /// </summary>
  159. /// <returns></returns>
  160. [Permission(EPermission.PublishOrder)]
  161. [HttpPost("publish")]
  162. public async Task PublishOrder([FromBody] PublishOrderDto dto)
  163. {
  164. //验证订单
  165. var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  166. if (order is null)
  167. throw UserFriendlyException.SameMessage("未找到工单,无法发布");
  168. //新增发布工单
  169. OrderPublish orderPublish = new OrderPublish();
  170. orderPublish.OrderId = order.Id;
  171. orderPublish.No = order.No;
  172. orderPublish.PublishState = dto.PublishState;
  173. orderPublish.ArrangeTitle = dto.ArrangeTitle;
  174. orderPublish.ArrangeContent = dto.ArrangeContent;
  175. orderPublish.ArrangeOpinion = dto.ArrangeOpinion;
  176. orderPublish.ProPublishState = dto.ProPublishState;
  177. orderPublish.FeedBackPhone = dto.FeedBackPhone;
  178. orderPublish.NoPubReason = dto.NoPubReason;
  179. orderPublish.CreatorName = _sessionContext.UserName;
  180. string id = await _orderPublishRepository.AddAsync(orderPublish);
  181. order.Publish(orderPublish.PublishState);
  182. await _orderRepository.UpdateAsync(order);
  183. var orderVisit = new OrderVisit();
  184. orderVisit.No = order.No;
  185. orderVisit.OrderId = order.Id;
  186. orderVisit.VisitState = EVisitState.WaitForVisit;
  187. orderVisit.PublishTime = DateTime.Now;
  188. string visitId = await _orderVisitRepository.AddAsync(orderVisit);
  189. //新增回访信息
  190. var visitedDetail = new List<OrderVisitDetail>();
  191. var seatDetail = new OrderVisitDetail();
  192. seatDetail.VisitId = visitId;
  193. seatDetail.VisitTarget = EVisitTarget.Seat;
  194. visitedDetail.Add(seatDetail);
  195. foreach (var item in dto.IdNames)
  196. {
  197. var orgDetail = new OrderVisitDetail();
  198. orgDetail.VisitId = visitId;
  199. orgDetail.VisitOrgCode = item.Id;
  200. orgDetail.VisitOrgName = item.Name;
  201. orgDetail.VisitTarget = EVisitTarget.Org;
  202. visitedDetail.Add(orgDetail);
  203. }
  204. await _mediator.Publish(new AddVisitNotify(visitedDetail), HttpContext.RequestAborted);
  205. //TODO 中国政府网
  206. if (order.SourceChannel == "ZGZFW")
  207. {
  208. }
  209. //TODO 省政民互动
  210. if (order.SourceChannel == "ZMHD")
  211. {
  212. }
  213. }
  214. /// <summary>
  215. /// 发布页面基础信息
  216. /// </summary>
  217. /// <returns></returns>
  218. [Permission(EPermission.PublishOrderPageBase)]
  219. [HttpGet("publish-order-pagebase/{id}")]
  220. public async Task<PublishOrderPageBaseDto> PublishOrderPageBase(string id)
  221. {
  222. var order = await _orderRepository.Queryable()
  223. .Includes(d => d.Acceptor)
  224. .Includes(d => d.OrderComplain)
  225. .FirstAsync(d => d.Id == id);
  226. if (order is null)
  227. throw UserFriendlyException.SameMessage("未知工单,无法发布");
  228. var res = new PublishOrderPageBaseDto() { SourceChannel = order.SourceChannel, OrderTitle = order.Title, Content = order.Content, ActualOpinion = order.ActualOpinion };
  229. var (idName, idNames) = await _workflowDomainService.GetUnvisitOrgsAsync(order.WorkflowId, HttpContext.RequestAborted);
  230. res.ActualHandleOrgName = idName;
  231. res.idNames = idNames.ToList();
  232. return res;
  233. }
  234. /// <summary>
  235. /// 已发布列表
  236. /// </summary>
  237. /// <param name="dto"></param>
  238. /// <returns></returns>
  239. [Permission(EPermission.PublishedOrderList)]
  240. [HttpGet("published")]
  241. public async Task<PagedDto<PublishedDto>> PublishedOrderList([FromQuery] PagedKeywordRequest dto)
  242. {
  243. var (total,items) = await _orderPublishRepository.Queryable()
  244. .Includes(x=>x.Order)
  245. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
  246. .OrderBy(d => d.CreationTime)
  247. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  248. return new PagedDto<PublishedDto>(total, _mapper.Map<IReadOnlyList<PublishedDto>>(items));
  249. }
  250. /// <summary>
  251. /// 发布详情
  252. /// </summary>
  253. /// <param name="id"></param>
  254. /// <returns></returns>
  255. [Permission(EPermission.PublishedOrder)]
  256. [HttpGet("published-order/{id}")]
  257. public async Task<PublishedEntityDto> PublishedOrder(string id)
  258. {
  259. var publishedOrder = await _orderPublishRepository.GetAsync(id, HttpContext.RequestAborted);
  260. if (publishedOrder is null)
  261. {
  262. throw UserFriendlyException.SameMessage("未知数据!");
  263. }
  264. var pubentity = _mapper.Map<PublishedEntityDto>(publishedOrder);
  265. var visit = await _orderVisitRepository.Queryable().Includes(x => x.OrderVisitDetails).OrderByDescending(x=>x.CreationTime).FirstAsync(x => x.OrderId == publishedOrder.OrderId, HttpContext.RequestAborted);
  266. if (visit!=null)
  267. {
  268. var details = visit.OrderVisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList();
  269. if (details!=null && details.Count>0)
  270. {
  271. pubentity.IdNames = new List<IdName>();
  272. details.ForEach(f => pubentity.IdNames.Add(new IdName() { Id = f.VisitOrgCode, Name = f.VisitOrgName }));
  273. }
  274. }
  275. return pubentity;
  276. }
  277. /// <summary>
  278. /// 修改发布内容
  279. /// </summary>
  280. /// <param name="dto"></param>
  281. /// <returns></returns>
  282. [Permission(EPermission.PublishedModify)]
  283. [HttpPost("published-order-modify")]
  284. public async Task PublishedModify([FromBody]PublishOrderModifyDto dto)
  285. {
  286. var publishOrder = await _orderPublishRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  287. if(publishOrder is null)
  288. {
  289. throw UserFriendlyException.SameMessage("无效数据");
  290. }
  291. var history = new OrderPublishHistory();
  292. history.ArrangeTitleBefor = publishOrder.ArrangeTitle;
  293. history.ArrangeTitleAfter = dto.ArrangeTitle;
  294. history.ArrangeContentBefor = publishOrder.ArrangeContent;
  295. history.ArrangeContentAfter = dto.ArrangeContent;
  296. history.ArrangeOpinionBefor = publishOrder.ArrangeOpinion;
  297. history.ArrangeOpinionAfter = dto.ArrangeOpinion;
  298. history.No = publishOrder.No;
  299. history.OrderId = publishOrder.OrderId;
  300. history.OrderPublishId = publishOrder.Id;
  301. publishOrder.ArrangeTitle = dto.ArrangeTitle;
  302. publishOrder.ArrangeContent = dto.ArrangeContent;
  303. publishOrder.ArrangeOpinion = dto.ArrangeOpinion;
  304. await _orderPublishRepository.UpdateAsync(publishOrder, HttpContext.RequestAborted);
  305. await _orderPublishHistoryRepository.AddAsync(history, HttpContext.RequestAborted);
  306. }
  307. /// <summary>
  308. /// 发布修改记录
  309. /// </summary>
  310. /// <param name="id"></param>
  311. /// <returns></returns>
  312. [Permission(EPermission.QueryPublishedHistory)]
  313. [HttpGet("published-history-list/{id}")]
  314. public async Task<List<OrderPublishHistory>> QueryPublishedHistory(string id)
  315. {
  316. return await _orderPublishHistoryRepository.Queryable().Where(x => x.OrderPublishId == id).OrderByDescending(x=>x.CreationTime).ToListAsync(HttpContext.RequestAborted);
  317. }
  318. #endregion
  319. #region 工单回访
  320. /// <summary>
  321. /// 回访列表
  322. /// </summary>
  323. /// <param name="dto"></param>
  324. /// <returns></returns>
  325. [Permission(EPermission.QueryOrderVisitList)]
  326. [HttpGet("visit")]
  327. public async Task<PagedDto<OrderVisitDto>> QueryOrderVisitList([FromQuery] QueryOrderVisitDto dto)
  328. {
  329. var (total, items) = await _orderVisitRepository.Queryable()
  330. .Includes(x => x.Order)
  331. .Includes(x => x.Employee)
  332. .Includes(x => x.OrderVisitDetails)
  333. .WhereIF(dto.VisitState == EVisitStateQuery.NoVisit, x => x.VisitState == Share.Enums.Order.EVisitState.WaitForVisit || x.VisitState == Share.Enums.Order.EVisitState.NoSatisfiedWaitForVisit)
  334. .WhereIF(dto.VisitState == EVisitStateQuery.Visited, x => x.VisitState == Share.Enums.Order.EVisitState.Visited)
  335. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
  336. .OrderBy(x => x.CreationTime)
  337. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  338. return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
  339. }
  340. /// <summary>
  341. /// 回访详情
  342. /// </summary>
  343. /// <returns></returns>
  344. [Permission(EPermission.VisitInfo)]
  345. [HttpGet("visit/{id}")]
  346. public async Task<object> VisitInfo(string id)
  347. {
  348. var orderVisit = await _orderVisitRepository.Queryable()
  349. .Includes(x => x.Order)
  350. .Includes(x => x.Employee)
  351. .Includes(x=>x.OrderVisitDetails)
  352. .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
  353. if (orderVisit is null)
  354. {
  355. throw UserFriendlyException.SameMessage("未知工单回访");
  356. }
  357. int visitCount = await _orderVisitRepository.CountAsync(x => x.OrderId == orderVisit.OrderId && x.VisitState == Share.Enums.Order.EVisitState.Visited, HttpContext.RequestAborted);
  358. int againCount = await _orderVisitRepository.CountAsync(x => x.OrderId == orderVisit.OrderId && x.AgainState == EAgainState.DoAgain, HttpContext.RequestAborted);
  359. var voiceEvaluate = EnumExts.GetDescriptions<EVoiceEvaluate>();
  360. var seatEvaluate = EnumExts.GetDescriptions<ESeatEvaluate>();
  361. var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction);
  362. var dissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason);
  363. var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner);
  364. return new { OrderVisitModel = orderVisit, VisitCount = visitCount, AgainCount = againCount, VisitSatisfaction = visitSatisfaction, DissatisfiedReason = dissatisfiedReason, VisitManner = visitManner,ViceEvaluate= voiceEvaluate, SeatEvaluate = seatEvaluate };
  365. }
  366. /// <summary>
  367. /// 回访明细
  368. /// </summary>
  369. /// <returns></returns>
  370. [Permission(EPermission.VisitDetailList)]
  371. [HttpGet("visit/detail")]
  372. public async Task<PagedDto<OrderVisitDetailDto>> VisitDetailList([FromQuery] VisitDetailListDto dto)
  373. {
  374. var (total, items) = await _orderVisitedDetailRepository.Queryable()
  375. .Includes(x => x.OrderVisit,s=>s.Order)
  376. .WhereIF(dto.VisitState == EVisitStateQuery.NoVisit, x => x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.WaitForVisit || x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.NoSatisfiedWaitForVisit)
  377. .WhereIF(dto.VisitState == EVisitStateQuery.Visited, x => x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.Visited)
  378. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.OrderVisit.Order.Title.Contains(dto.Keyword!) || d.OrderVisit.Order.No.Contains(dto.Keyword!))
  379. .OrderByDescending(x => x.CreationTime)
  380. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  381. return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
  382. }
  383. /// <summary>
  384. /// 回访保存
  385. /// </summary>
  386. /// <returns></returns>
  387. [Permission(EPermission.Visit)]
  388. [HttpPost("visit")]
  389. public async Task Visit([FromBody] VisitDto dto)
  390. {
  391. //var visit = await _orderVisitRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  392. var visit = await _orderVisitRepository.Queryable()
  393. .Includes(d => d.Order)
  394. .Includes(d => d.OrderVisitDetails)
  395. .FirstAsync(d => d.Id == dto.Id, HttpContext.RequestAborted);
  396. if (visit is null)
  397. throw UserFriendlyException.SameMessage("未知回访信息");
  398. if (visit.VisitState == EVisitState.Visited)
  399. throw UserFriendlyException.SameMessage("已回访,不能重复回访");
  400. var first = dto.VisitDetails.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);
  401. //更新主表
  402. if (dto.IsPutThrough)
  403. {
  404. visit.VisitState = Share.Enums.Order.EVisitState.Visited;
  405. visit.VisitTime = DateTime.Now;
  406. visit.VisitType = EVisitType.ArtificialVisit;
  407. }
  408. visit.IsPutThrough = dto.IsPutThrough;
  409. visit.AgainState = dto.IsAgain ? EAgainState.NeedAgain : EAgainState.NoAgain;
  410. visit.EmployeeId = _sessionContext.UserId;
  411. if (first!=null)
  412. {
  413. visit.NowEvaluate = first.OrgProcessingResults;
  414. }
  415. //await _orderVisitRepository.UpdateAsync(visit,HttpContext.RequestAborted);
  416. //update order
  417. if (dto.IsPutThrough)
  418. {
  419. if (first!=null)
  420. {
  421. visit.Order.Visited(first.OrgProcessingResults.Id, first.OrgProcessingResults.Name);
  422. }
  423. //_mapper.Map(dto.VisitDetails,visit.OrderVisitDetails);
  424. for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
  425. {
  426. var detail = visit.OrderVisitDetails[i];
  427. var detaildto = dto.VisitDetails.FirstOrDefault(x => x.Id == detail.Id);
  428. if (detaildto!=null)
  429. {
  430. _mapper.Map(detaildto, visit.OrderVisitDetails[i]);
  431. }
  432. }
  433. await _orderVisitRepository.UpdateAsync(visit,HttpContext.RequestAborted);
  434. await _orderVisitedDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, HttpContext.RequestAborted);
  435. await _orderRepository.UpdateAsync(visit.Order, HttpContext.RequestAborted);
  436. var orderDto = _mapper.Map<OrderDto>(visit.Order);
  437. if (first!=null)
  438. {
  439. //推省上
  440. _capPublisher.Publish(EventNames.HotlineOrderVisited, new PublishVisitDto() { Order = orderDto, No = visit.No, VisitType = visit.VisitType, VisitName = visit.CreatorName, VisitTime = visit.VisitTime, VisitRemark = first.VisitContent, AreaCode = visit.Order.AreaCode!, SubjectResultSatifyCode = first.OrgProcessingResults.Id, FirstSatisfactionCode = visit.Order.FirstVisitResultCode!, ClientGuid = "" });
  441. }
  442. }
  443. }
  444. #endregion
  445. #region 工单重办
  446. /// <summary>
  447. /// 重办查询
  448. /// </summary>
  449. /// <param name="dto"></param>
  450. /// <returns></returns>
  451. [Permission(EPermission.QueryOrderRedoRecord)]
  452. [HttpGet("redo")]
  453. public async Task<PagedDto<OrderRedo>> QueryOrderRedo([FromQuery] QueryOrderRedoRecordDto dto)
  454. {
  455. var (total, items) = await _orderRedoRepository.Queryable()
  456. .Includes(x => x.Order)
  457. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
  458. .OrderByDescending(x => x.CreationTime)
  459. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  460. return new PagedDto<OrderRedo>(total, items);
  461. }
  462. /// <summary>
  463. /// 重办详情
  464. /// </summary>
  465. /// <param name="id"></param>
  466. /// <returns></returns>
  467. [Permission(EPermission.OrderRedoRecord)]
  468. [HttpGet("redo/{id}")]
  469. public async Task<OrderRedo> GetOrderRedo(string id)
  470. {
  471. return await _orderRedoRepository.Queryable()
  472. .Includes(x => x.Order)
  473. .FirstAsync(x => x.Id == id);
  474. }
  475. /// <summary>
  476. /// 发起重办
  477. /// </summary>
  478. [HttpPost("redo")]
  479. public async Task<string> AddRedo([FromBody] OrderRedoStartFlowDto dto)
  480. {
  481. var redo = _mapper.Map<OrderRedo>(dto.Data);
  482. redo.CreatorName = _sessionContext.UserName ?? string.Empty;
  483. redo.CreatorOrgName = _sessionContext.OrgName ?? string.Empty;
  484. redo.TimeLimitCount = dto.Workflow.Extension.TimeLimitCount;
  485. redo.TimeLimitUnit = dto.Workflow.Extension.TimeLimitUnit;
  486. //todo
  487. var handler = dto.Workflow.NextHandlers.First();
  488. redo.RedoOrgCode = handler.Id;
  489. redo.RedoOrgCode = handler.Name;
  490. var id = await _orderRedoRepository.AddAsync(redo, HttpContext.RequestAborted);
  491. try
  492. {
  493. var order = await _orderRepository.GetAsync(dto.Data.OrderId, HttpContext.RequestAborted);
  494. if (order == null)
  495. throw UserFriendlyException.SameMessage("无效工单编号");
  496. if (string.IsNullOrEmpty(order.WorkflowId))
  497. throw UserFriendlyException.SameMessage("无效工单流程编号");
  498. var redoFlowDto = _mapper.Map<RecallDto>(dto.Workflow);
  499. redoFlowDto.WorkflowId = order.WorkflowId;
  500. await _workflowApplication.RedoAsync(redoFlowDto, HttpContext.RequestAborted);
  501. return id;
  502. }
  503. catch (Exception e)
  504. {
  505. await _orderRedoRepository.RemoveAsync(id, cancellationToken: HttpContext.RequestAborted);
  506. throw new UserFriendlyException($"发起重办失败,{e.Message}");
  507. }
  508. }
  509. /// <summary>
  510. /// 重办基础数据
  511. /// </summary>
  512. /// <returns></returns>
  513. [HttpGet("base-data-redo")]
  514. public async Task<dynamic> BaseDataRedo()
  515. {
  516. var rsp = new
  517. {
  518. OrderRedoReasonOptions = EnumExts.GetDescriptions<EOrderRedoReason>(),
  519. };
  520. return rsp;
  521. }
  522. #endregion
  523. #region 工单延期
  524. /// <summary>
  525. /// 可申请延期工单
  526. /// </summary>
  527. /// <param name="dto"></param>
  528. /// <returns></returns>
  529. [Permission(EPermission.CanDelayOrderList)]
  530. [HttpGet("candelay")]
  531. public async Task<PagedDto<OrderDto>> CanDelayOrderList([FromQuery] CanDelayOrderListDto dto)
  532. {
  533. var (total, items) = await _orderRepository.Queryable()
  534. .Includes(d => d.Acceptor)
  535. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
  536. .Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.Filed &&
  537. SqlFunc.Subqueryable<OrderDelay>().Where(s => s.OrderId == d.Id && s.DelayState == EDelayState.Examining).NotAny())
  538. .OrderByDescending(d => d.CreationTime)
  539. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  540. return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
  541. }
  542. /// <summary>
  543. /// 申请延期
  544. /// </summary>
  545. /// <param name="dto"></param>
  546. /// <returns></returns>
  547. [Permission(EPermission.ApplyDelay)]
  548. [HttpPost("delay")]
  549. public async Task ApplyDelay([FromBody] ApplyDelayDto dto)
  550. {
  551. //验证工单是否可以申请
  552. var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
  553. if (order is null)
  554. throw UserFriendlyException.SameMessage("无效工单");
  555. //验证工单是否在办理中
  556. if (order.Status == EOrderStatus.WaitForAccept || order.Status == EOrderStatus.Filed)
  557. throw UserFriendlyException.SameMessage("当前工单状态不能申请延期");
  558. bool IsHas = await _orderDelayRepository.AnyAsync(x => x.OrderId == dto.OrderId && x.DelayState == EDelayState.Examining, HttpContext.RequestAborted);
  559. if (IsHas)
  560. throw UserFriendlyException.SameMessage("该存在延期申请正在审核");
  561. //验证延期次数
  562. var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
  563. int count = await _orderDelayRepository.CountAsync(x => x.OrderId == dto.OrderId);
  564. if (count > int.Parse(setting?.SettingValue[0]))
  565. throw UserFriendlyException.SameMessage("延期申请已超过系统预定设置,不能申请");
  566. var model = _mapper.Map<OrderDelay>(dto);
  567. model.EmployeeId = _sessionContext.UserId;
  568. model.ApplyOrgName = _sessionContext.OrgName;
  569. model.ApplyOrgCode = _sessionContext.OrgId;
  570. model.BeforeDelay = order.ExpiredTime;
  571. model.DelayState = EDelayState.Examining;
  572. if (model.BeforeDelay != null)
  573. {
  574. model.AfterDelay = _timeLimitApplication.CalcEndTime(model.BeforeDelay.Value, dto.DelayUnit, dto.DelayNum)?.EndTime;
  575. }
  576. model.ApplyDelayTime = DateTime.Now;
  577. model.No = order.No;
  578. await _orderDelayRepository.AddAsync(model, HttpContext.RequestAborted);
  579. }
  580. /// <summary>
  581. /// 延期列表
  582. /// </summary>
  583. /// <returns></returns>
  584. [Permission(EPermission.DelayList)]
  585. [HttpGet("delay")]
  586. public async Task<PagedDto<OrderDelay>> DelayList([FromQuery] DelayListDto dto)
  587. {
  588. var (total, items) = await _orderDelayRepository.Queryable()
  589. .Includes(x => x.Order)
  590. .Includes(x => x.Employee)
  591. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
  592. .WhereIF(dto.IsApply, x => x.DelayState != EDelayState.Examining)
  593. .WhereIF(!dto.IsApply, x => x.DelayState == EDelayState.Examining)
  594. .OrderByDescending(x => x.CreationTime)
  595. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  596. return new PagedDto<OrderDelay>(total, _mapper.Map<IReadOnlyList<OrderDelay>>(items));
  597. }
  598. /// <summary>
  599. /// 延期详情
  600. /// </summary>
  601. /// <param name="id"></param>
  602. /// <returns></returns>
  603. [Permission(EPermission.DelayEntity)]
  604. [HttpGet("delay/{id}")]
  605. public async Task<OrderDelay> DelayEntity(string id)
  606. {
  607. return await _orderDelayRepository.Queryable()
  608. .Includes(x => x.Order)
  609. .Includes(x => x.Employee)
  610. .FirstAsync(x => x.Id == id);
  611. }
  612. #endregion
  613. #region 工单甄别
  614. /// <summary>
  615. /// 工单甄别列表
  616. /// </summary>
  617. /// <param name="dto"></param>
  618. /// <returns></returns>
  619. [Permission(EPermission.OrderScreenList)]
  620. [HttpGet("screen")]
  621. public async Task<PagedDto<OrderScreen>> ScreenList([FromQuery] ScreenListDto dto)
  622. {
  623. var (total, items) = await _orderScreenRepository.Queryable()
  624. .Includes(x => x.Visit, d => d.Order)
  625. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Visit.Order.Title.Contains(dto.Keyword!) || d.Visit.Order.No.Contains(dto.Keyword!))
  626. .WhereIF(dto.Status == EScreenStatus.Apply || dto.Status == EScreenStatus.Approval || dto.Status == EScreenStatus.End, x => x.Status == dto.Status)
  627. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
  628. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
  629. .OrderByDescending(x => x.CreationTime)
  630. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  631. return new PagedDto<OrderScreen>(total, items);
  632. }
  633. /// <summary>
  634. /// 开始工单甄别流程
  635. /// </summary>
  636. [Permission(EPermission.ApplyScreen)]
  637. [HttpPost("screen/startflow")]
  638. public async Task StartFlow([FromBody] ScreenStartFlowDto dto)
  639. {
  640. var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyNum);
  641. int count = await _orderScreenRepository.CountAsync(x => x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse);
  642. if (count > int.Parse(setting?.SettingValue[0]))
  643. throw UserFriendlyException.SameMessage("甄别申请已超过系统预定设置,不能申请");
  644. var visit = await _orderVisitRepository.GetAsync(dto.Data.VisitId, HttpContext.RequestAborted);
  645. setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyEndTime);
  646. var endTime = _timeLimitDomainService.CalcEndTime(visit.VisitTime.Value,ETimeType.WorkDay,int.Parse(setting?.SettingValue[0]), false).EndTime.Value;
  647. if (DateTime.Now > endTime)
  648. throw UserFriendlyException.SameMessage("甄别申请时限已超过系统预定设置,不能申请");
  649. var model = _mapper.Map<OrderScreen>(dto.Data);
  650. model.Status = EScreenStatus.Apply;
  651. model.ApplyEndTime = endTime;
  652. var id = await _orderScreenRepository.AddAsync(model, HttpContext.RequestAborted);
  653. if (dto.Data.Files.Any()) await _fileRepository.AddFileAsync(dto.Data.Files, id, HttpContext.RequestAborted);
  654. try
  655. {
  656. var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
  657. startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
  658. startDto.Title = dto.Data.Content;
  659. await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
  660. }
  661. catch (Exception e)
  662. {
  663. await _orderScreenRepository.RemoveAsync(id);
  664. throw new UserFriendlyException($"工单开启甄别流程失败!, {e.Message}", "工单开启甄别流程失败");
  665. }
  666. }
  667. /// <summary>
  668. /// 查询工单甄别流程开启参数
  669. /// </summary>
  670. /// <returns></returns>
  671. [HttpGet("screen/startflow")]
  672. public async Task<DefinedStepDto> GetScreenFlowStartOptionsAsync()
  673. {
  674. return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.OrderScreen, HttpContext.RequestAborted);
  675. }
  676. /// <summary>
  677. /// 列表页面基础数据
  678. /// </summary>
  679. /// <returns></returns>
  680. [HttpGet("screen/base")]
  681. public async Task<object> ScreenBaseData()
  682. {
  683. var rsp = new
  684. {
  685. ScreenStatus = EnumExts.GetDescriptions<EScreenStatus>(),
  686. ScreenType = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.ScreenType),
  687. };
  688. return rsp;
  689. }
  690. /// <summary>
  691. /// 甄别详情
  692. /// </summary>
  693. /// <param name="id"></param>
  694. /// <returns></returns>
  695. [Permission(EPermission.ScreenEntity)]
  696. [HttpGet("screen/{id}")]
  697. public async Task<OrderScreen> ScreenEntity(string id)
  698. {
  699. return await _orderScreenRepository.Queryable()
  700. .Includes(x => x.Visit, d => d.Order)
  701. .FirstAsync(x => x.Id == id);
  702. }
  703. #endregion
  704. #region 工单督办
  705. /// <summary>
  706. /// 工单督办列表
  707. /// </summary>
  708. /// <param name="dto"></param>
  709. /// <returns></returns>
  710. [Permission(EPermission.SuperviseOrderList)]
  711. [HttpGet("supervise")]
  712. public async Task<PagedDto<SuperviseOrderDto>> SuperviseList([FromQuery] SuperviseListDto dto)
  713. {
  714. var (total, items) = await _orderSuperviseRepository.Queryable()
  715. .Includes(x => x.Order)
  716. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
  717. .WhereIF(dto.SuperviseState > -1, x => x.State == dto.SuperviseState)
  718. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
  719. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
  720. .OrderByDescending(x => x.CreationTime)
  721. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  722. return new PagedDto<SuperviseOrderDto>(total, _mapper.Map<IReadOnlyList<SuperviseOrderDto>>(items));
  723. }
  724. /// <summary>
  725. /// 申请督办
  726. /// </summary>
  727. /// <param name="dto"></param>
  728. /// <returns></returns>
  729. [Permission(EPermission.ApplySupervise)]
  730. [HttpPost("supervise/apply")]
  731. public async Task<string> ApplySupervise([FromBody] ApplyOrderSuperviseDto dto)
  732. {
  733. //验证工单是否可以申请
  734. var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
  735. if (order is null)
  736. throw UserFriendlyException.SameMessage("无效工单");
  737. var model = _mapper.Map<OrderSupervise>(dto);
  738. model.CreatorOrgName = _sessionContext.OrgName;
  739. model.CrUser = _sessionContext.UserName;
  740. model.State = 0;
  741. var id = await _orderSuperviseRepository.AddAsync(model, HttpContext.RequestAborted);
  742. if (dto.Files.Any()) await _fileRepository.AddFileAsync(dto.Files, id, HttpContext.RequestAborted);
  743. if (dto.AcceptSms)
  744. {
  745. //TODO 发送短信
  746. }
  747. return id;
  748. }
  749. /// <summary>
  750. /// 回复督办
  751. /// </summary>
  752. /// <param name="dto"></param>
  753. /// <returns></returns>
  754. [Permission(EPermission.ReplySupervise)]
  755. [HttpPost("supervise/reply")]
  756. public async Task ReplySupervise([FromBody] ReplyOrderSuperviseDto dto)
  757. {
  758. //验证是否存在督办
  759. var supervise = await _orderSuperviseRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  760. if (supervise is null)
  761. throw UserFriendlyException.SameMessage("无效督办");
  762. if (supervise.State > 0)
  763. throw UserFriendlyException.SameMessage("督办已回复,请勿重复回复");
  764. _mapper.Map(dto, supervise);
  765. supervise.ReplyId = _sessionContext.UserId;
  766. supervise.ReUser = _sessionContext.UserName;
  767. supervise.ReplyTime = DateTime.Now;
  768. supervise.State = 1;
  769. if (dto.Files.Any()) await _fileRepository.AddFileAsync(dto.Files, supervise.Id, HttpContext.RequestAborted);
  770. await _orderSuperviseRepository.UpdateAsync(supervise, HttpContext.RequestAborted);
  771. }
  772. /// <summary>
  773. /// 签收督办
  774. /// </summary>
  775. /// <param name="dto"></param>
  776. /// <returns></returns>
  777. [Permission(EPermission.SignSupervise)]
  778. [HttpPost("supervise/sign")]
  779. public async Task SignSupervise([FromBody] SignOrderSuperviseDto dto)
  780. {
  781. //验证是否存在督办
  782. var supervise = await _orderSuperviseRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  783. if (supervise is null)
  784. throw UserFriendlyException.SameMessage("无效督办");
  785. supervise.SignTime = DateTime.Now;
  786. supervise.SignUser = _sessionContext.UserName;
  787. await _orderSuperviseRepository.UpdateAsync(supervise, HttpContext.RequestAborted);
  788. }
  789. /// <summary>
  790. /// 督办详情
  791. /// </summary>
  792. /// <param name="id"></param>
  793. /// <returns></returns>
  794. [Permission(EPermission.SuperviseEntity)]
  795. [HttpGet("supervise/{id}")]
  796. public async Task<OrderSupervise> SuperviseEntity(string id)
  797. {
  798. return await _orderSuperviseRepository.Queryable()
  799. .Includes(x => x.Order)
  800. .FirstAsync(x => x.Id == id);
  801. }
  802. #endregion
  803. #region 工单催办
  804. /// <summary>
  805. /// 工单催办列表
  806. /// </summary>
  807. /// <param name="dto"></param>
  808. /// <returns></returns>
  809. [Permission(EPermission.UrgeOrderList)]
  810. [HttpGet("urge")]
  811. public async Task<PagedDto<UrgeOrderDto>> UrgeList([FromQuery] UrgeListDto dto)
  812. {
  813. var (total, items) = await _orderUrgeRepository.Queryable()
  814. .Includes(x => x.Order)
  815. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
  816. .WhereIF(dto.SuperviseState > -1, x => x.State == dto.SuperviseState)
  817. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
  818. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
  819. .OrderByDescending(x => x.CreationTime)
  820. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  821. return new PagedDto<UrgeOrderDto>(total, _mapper.Map<IReadOnlyList<UrgeOrderDto>>(items));
  822. }
  823. /// <summary>
  824. /// 申请催办
  825. /// </summary>
  826. /// <param name="dto"></param>
  827. /// <returns></returns>
  828. [Permission(EPermission.ApplyUrge)]
  829. [HttpPost("urge/apply")]
  830. public async Task<string> ApplyUrge([FromBody] ApplyOrderUrgeDto dto)
  831. {
  832. //验证工单是否可以申请
  833. var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted);
  834. if (order is null)
  835. throw UserFriendlyException.SameMessage("无效工单");
  836. var model = _mapper.Map<OrderUrge>(dto);
  837. model.CreatorOrgName = _sessionContext.OrgName;
  838. model.CrUser = _sessionContext.UserName;
  839. model.State = 0;
  840. var id = await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted);
  841. if (dto.Files.Any()) await _fileRepository.AddFileAsync(dto.Files, id, HttpContext.RequestAborted);
  842. if (dto.AcceptSms)
  843. {
  844. //TODO 发送短信
  845. }
  846. return id;
  847. }
  848. /// <summary>
  849. /// 回复催办
  850. /// </summary>
  851. /// <param name="dto"></param>
  852. /// <returns></returns>
  853. [Permission(EPermission.ReplyUrge)]
  854. [HttpPost("urge/reply")]
  855. public async Task ReplyUrge([FromBody] ReplyOrderUrgeDto dto)
  856. {
  857. //验证是否存在催办
  858. var urge = await _orderUrgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  859. if (urge is null)
  860. throw UserFriendlyException.SameMessage("无效催办");
  861. if (urge.State > 0)
  862. throw UserFriendlyException.SameMessage("督办已回复,请勿重复回复");
  863. _mapper.Map(dto, urge);
  864. urge.ReplyId = _sessionContext.UserId;
  865. urge.ReUser = _sessionContext.UserName;
  866. urge.ReplyContent = dto.ReplyContent;
  867. urge.ReplyTime = DateTime.Now;
  868. urge.State = 1;
  869. if (dto.Files.Any()) await _fileRepository.AddFileAsync(dto.Files, urge.Id, HttpContext.RequestAborted);
  870. await _orderUrgeRepository.UpdateAsync(urge, HttpContext.RequestAborted);
  871. }
  872. /// <summary>
  873. /// 签收催办
  874. /// </summary>
  875. /// <param name="dto"></param>
  876. /// <returns></returns>
  877. [Permission(EPermission.SignUrge)]
  878. [HttpPost("urge/sign")]
  879. public async Task SignUrge([FromBody] SignOrderUrgeDto dto)
  880. {
  881. //验证是否存在催办
  882. var urge = await _orderUrgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
  883. if (urge is null)
  884. throw UserFriendlyException.SameMessage("无效催办");
  885. urge.SignUser = _sessionContext.UserName;
  886. urge.SignTime = DateTime.Now;
  887. await _orderUrgeRepository.UpdateAsync(urge, HttpContext.RequestAborted);
  888. }
  889. /// <summary>
  890. /// 催办详情
  891. /// </summary>
  892. /// <param name="id"></param>
  893. /// <returns></returns>
  894. [Permission(EPermission.UrgeEntity)]
  895. [HttpGet("urge/{id}")]
  896. public async Task<OrderUrge> UrgeEntity(string id)
  897. {
  898. return await _orderUrgeRepository.Queryable()
  899. .Includes(x => x.Order)
  900. .FirstAsync(x => x.Id == id);
  901. }
  902. #endregion
  903. #region 工单办理
  904. /// <summary>
  905. /// 工单列表
  906. /// </summary>
  907. /// <param name="dto"></param>
  908. /// <returns></returns>
  909. [Permission(EPermission.OrderQuery)]
  910. [HttpGet]
  911. public async Task<PagedDto<OrderDto>> Query([FromQuery] QueryOrderDto dto)
  912. {
  913. var (total, items) = await _orderRepository.Queryable()
  914. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
  915. .WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
  916. .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
  917. .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannel))
  918. .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId))
  919. .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!))
  920. //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
  921. .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.Workflow.ActualHandleOrgCode))
  922. .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!))
  923. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
  924. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
  925. .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))
  926. .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.FromPhone.Contains(dto.PhoneNo!) || d.Contact.Contains(dto.PhoneNo!))
  927. .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode)
  928. .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart)
  929. .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd)
  930. .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))
  931. .OrderByDescending(d => d.CreationTime)
  932. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  933. return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
  934. }
  935. /// <summary>
  936. /// 历史工单
  937. /// </summary>
  938. /// <param name="dto"></param>
  939. /// <returns></returns>
  940. [Permission(EPermission.OrderHistory)]
  941. [HttpGet("history")]
  942. public async Task<PagedDto<OrderDto>> Query([FromQuery] QueryOrderHistoryDto dto)
  943. {
  944. var (total, items) = await _orderRepository.Queryable()
  945. .Where(d => d.FromPhone == dto.PhoneNo)
  946. .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId)
  947. .OrderByDescending(d => d.CreationTime)
  948. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  949. return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
  950. }
  951. /// <summary>
  952. /// 查询重复工单
  953. /// </summary>
  954. [HttpGet("duplicate")]
  955. public async Task<PagedDto<OrderDto>> Query([FromQuery] QueryOrderDuplicateDto dto)
  956. {
  957. if (!dto.OrderIds.Any())
  958. return new PagedDto<OrderDto>(0, new List<OrderDto>());
  959. var (total, items) = await _orderRepository.Queryable()
  960. .Where(d => dto.OrderIds.Contains(d.Id))
  961. .OrderByDescending(d => d.CreationTime)
  962. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  963. return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
  964. }
  965. /// <summary>
  966. /// 查询工单详情
  967. /// </summary>
  968. /// <param name="id"></param>
  969. /// <returns></returns>
  970. [Permission(EPermission.GetOrder)]
  971. [HttpGet("{id}")]
  972. public async Task<OrderDto> Get(string id)
  973. {
  974. var order = await _orderRepository.Queryable()
  975. .Includes(d => d.Acceptor)
  976. .Includes(d => d.OrderComplain)
  977. .Includes(d => d.OrderReport)
  978. .FirstAsync(d => d.Id == id);
  979. if (order == null)
  980. return new();
  981. var canHandle = false;
  982. if (!string.IsNullOrEmpty(order?.WorkflowId))
  983. {
  984. var (workflow, handlePermission) = await _workflowDomainService.GetWorkflowHandlePermissionAsync(
  985. order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
  986. withSteps: true, withSupplements: true, withAssigns: true,
  987. cancellationToken: HttpContext.RequestAborted);
  988. order.Workflow = workflow;
  989. canHandle = handlePermission;
  990. await _mediator.Publish(new GetOrderDetailNotify(order.Workflow, _sessionContext.RequiredUserId,
  991. _sessionContext.UserName, _sessionContext.RequiredOrgId, _sessionContext.OrgName));
  992. }
  993. var dto = _mapper.Map<OrderDto>(order!);
  994. if (order?.Workflow != null)
  995. dto.Workflow.CanHandle = canHandle;
  996. return dto;
  997. }
  998. /// <summary>
  999. /// 新增工单
  1000. /// </summary>
  1001. /// <param name="dto"></param>
  1002. /// <returns></returns>
  1003. [Permission(EPermission.OrderAdd)]
  1004. [HttpPost]
  1005. public async Task<string> Add([FromBody] AddOrderDto dto)
  1006. {
  1007. var order = _mapper.Map<Order>(dto);
  1008. var orderId = await _orderDomainService.AddAsync(order, HttpContext.RequestAborted);
  1009. if (dto.Tags.Any()) await _repositoryts.AddVectorAsync(orderId, DateTime.Now, dto.Tags, HttpContext.RequestAborted);
  1010. if (dto.Files.Any()) await _fileRepository.AddFileAsync(dto.Files, orderId, HttpContext.RequestAborted);
  1011. return orderId;
  1012. }
  1013. /// <summary>
  1014. /// 删除工单
  1015. /// </summary>
  1016. /// <param name="id"></param>
  1017. /// <returns></returns>
  1018. [Permission(EPermission.OrderRemove)]
  1019. [HttpDelete("{id}")]
  1020. public async Task Remove(string id)
  1021. {
  1022. var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
  1023. if (order == null) return;
  1024. if (order.Status != EOrderStatus.WaitForAccept)
  1025. throw UserFriendlyException.SameMessage("非草稿工单不可删除");
  1026. await _orderRepository.RemoveAsync(order);
  1027. }
  1028. /// <summary>
  1029. /// 更新工单信息
  1030. /// </summary>
  1031. /// <param name="dto"></param>
  1032. /// <returns></returns>
  1033. [Permission(EPermission.OrderUpdate)]
  1034. [HttpPut]
  1035. public async Task Update([FromBody] UpdateOrderDto dto)
  1036. {
  1037. var order = await _orderRepository.Queryable()
  1038. .Includes(d => d.OrderComplain)
  1039. .Includes(d => d.OrderReport)
  1040. .FirstAsync(d => d.Id == dto.Id);
  1041. if (order == null)
  1042. throw UserFriendlyException.SameMessage("无效工单编号");
  1043. if (order.Status != EOrderStatus.WaitForAccept || !string.IsNullOrEmpty(order.WorkflowId))
  1044. throw UserFriendlyException.SameMessage("工单已发起流程");
  1045. if (order?.OrderComplain is not null)
  1046. await _orderRepository.RemoveOrderComplainAsync(order.OrderComplain, HttpContext.RequestAborted);
  1047. if (order?.OrderReport is not null)
  1048. await _orderRepository.RemoveOrderReportAsync(order.OrderReport, HttpContext.RequestAborted);
  1049. if (dto.Tags.Any()) await _repositoryts.UpdateVectorAsync(dto.Id, dto.Tags, HttpContext.RequestAborted);
  1050. _mapper.Map(dto, order);
  1051. await _orderRepository.UpdateOrderNavAsync(order, HttpContext.RequestAborted);
  1052. }
  1053. /// <summary>
  1054. /// 开始流程
  1055. /// </summary>
  1056. /// <param name="id">工单id</param>
  1057. /// <param name="dto">流程开启参数</param>
  1058. /// <returns></returns>
  1059. [HttpPost("{id}/startflow")]
  1060. [Obsolete]
  1061. public async Task StartFlow(string id, [FromBody] StartWorkflowDto dto)
  1062. {
  1063. var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
  1064. if (order == null)
  1065. throw UserFriendlyException.SameMessage("无效工单编号");
  1066. if (order.Status != EOrderStatus.WaitForAccept || !string.IsNullOrEmpty(order.WorkflowId))
  1067. throw UserFriendlyException.SameMessage("工单已发起流程");
  1068. dto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
  1069. dto.Title = order.Title;
  1070. order.StartManageFlow();
  1071. await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
  1072. await _workflowApplication.StartWorkflowAsync(dto, order.Id, HttpContext.RequestAborted);
  1073. }
  1074. /// <summary>
  1075. /// 开始工单办理流程
  1076. /// </summary>
  1077. [HttpPost("startflow")]
  1078. public async Task StartFlow([FromBody] OrderStartFlowDto dto)
  1079. {
  1080. var id = dto.Data.Id;
  1081. if (string.IsNullOrEmpty(dto.Data.Id))
  1082. {
  1083. id = await Add(_mapper.Map<AddOrderDto>(dto.Data));
  1084. }
  1085. else
  1086. {
  1087. await Update(dto.Data);
  1088. }
  1089. try
  1090. {
  1091. var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
  1092. startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
  1093. startDto.Title = dto.Data.Title;
  1094. await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
  1095. }
  1096. catch (Exception e)
  1097. {
  1098. await Remove(id);
  1099. throw new UserFriendlyException($"工单开启流程失败!, {e.Message}", "工单开启流程失败");
  1100. }
  1101. }
  1102. /// <summary>
  1103. /// 查询工单办理流程开启参数
  1104. /// </summary>
  1105. /// <returns></returns>
  1106. [HttpGet("startflow")]
  1107. public async Task<DefinedStepDto> GetFlowStartOptionsAsync()
  1108. {
  1109. return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted);
  1110. }
  1111. /// <summary>
  1112. /// 列表页面基础数据
  1113. /// </summary>
  1114. /// <returns></returns>
  1115. [HttpGet("base-data")]
  1116. public async Task<object> BaseData()
  1117. {
  1118. var rsp = new
  1119. {
  1120. AcceptTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.AcceptType),//EnumExts.GetDescriptions<EAcceptType>(),
  1121. ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
  1122. OrgsOptions = await _organizeRepository.GetOrgJson(),
  1123. EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
  1124. PushTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.PushType),
  1125. OrderStatusOptions = EnumExts.GetDescriptions<EOrderStatus>(),
  1126. };
  1127. return rsp;
  1128. }
  1129. /// <summary>
  1130. /// 新增页面基础数据
  1131. /// </summary>
  1132. /// <returns></returns>
  1133. [HttpGet("base-data-add")]
  1134. public async Task<object> BaseDataAdd()
  1135. {
  1136. var rsp = new
  1137. {
  1138. ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
  1139. AcceptTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.AcceptType),
  1140. EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
  1141. PushTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.PushType),
  1142. GenderOptions = EnumExts.GetDescriptions<EGender>(),
  1143. IdentityTypeOptions = EnumExts.GetDescriptions<EIdentityType>(),
  1144. LicenceTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.LicenceType),
  1145. AgeRangeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.AgeRange),
  1146. OrderTypeOptions = EnumExts.GetDescriptions<EOrderType>(),
  1147. };
  1148. return rsp;
  1149. }
  1150. /// <summary>
  1151. /// 扩展信息新增页面基础数据
  1152. /// </summary>
  1153. /// <returns></returns>
  1154. [HttpGet("base-data-ext")]
  1155. public async Task<object> BaseDataExtension()
  1156. {
  1157. var rsp = new
  1158. {
  1159. LicenceTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.LicenceType),
  1160. IdentityTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.ProviderIdentityType),
  1161. IdentityOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.Identity),
  1162. NationalityOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.Nationality),
  1163. NationOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.Nation),
  1164. MarketTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.MarketType),
  1165. IndustryClassifyOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.IndustryClassify),
  1166. BrandOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.Brand),
  1167. ObjectClassifyOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.ObjectClassify),
  1168. ComplainClassifyOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.ComplainClassify),
  1169. ReportClassifyOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.ReportClassify),
  1170. SalesModeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.SalesMode),
  1171. ECommercePlatformOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.ECommercePlatform),
  1172. PatentTypeOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.PatentType),
  1173. AffairTargetOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.AffairTarget),
  1174. ComplainTypeOptions = EnumExts.GetDescriptions<EComplainType>().Select(d => new IdName(d.Key.ToString(), d.Value)),
  1175. SalesChannelOptions = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.SalesChannel),
  1176. };
  1177. return rsp;
  1178. }
  1179. #endregion
  1180. #region 工单待办
  1181. /// <summary>
  1182. /// 查询待办工单
  1183. /// </summary>
  1184. /// <param name="dto"></param>
  1185. /// <returns></returns>
  1186. [HttpGet("waited")]
  1187. public async Task<PagedDto<OrderWaitedDto>> QueryWaited([FromQuery] PagedRequest dto)
  1188. {
  1189. if (dto.PageSize > 100)
  1190. dto.PageSize = 100;
  1191. var (total, items) = await _orderRepository.Queryable()
  1192. .OrderBy(d => d.ExpiredTime)
  1193. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  1194. var dtos = _mapper.Map<IReadOnlyList<OrderWaitedDto>>(items);
  1195. //calc expired description
  1196. var now = DateTime.Now;
  1197. foreach (var waitedDto in dtos)
  1198. {
  1199. var ts = waitedDto.ExpiredTime - now;
  1200. if (ts.Value.TotalDays <= 0)
  1201. {
  1202. //已超期
  1203. waitedDto.ExpiredDescription = $"已超期{Math.Abs(ts.Value.TotalDays):F1}天";
  1204. }
  1205. else
  1206. {
  1207. //未超期
  1208. waitedDto.ExpiredDescription = $"{ts.Value.TotalDays:F1}天后超期";
  1209. }
  1210. }
  1211. return new PagedDto<OrderWaitedDto>(total, dtos);
  1212. }
  1213. #endregion
  1214. }