OrderApplication.cs 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. using DotNetCore.CAP;
  2. using Hotline.Application.Quality;
  3. using Hotline.Caching.Interfaces;
  4. using Hotline.File;
  5. using Hotline.FlowEngine.Workflows;
  6. using Hotline.Orders;
  7. using Hotline.Repository.SqlSugar.Extensions;
  8. using Hotline.Repository.SqlSugar.Ts;
  9. using Hotline.Settings.TimeLimits;
  10. using Hotline.Share.Dtos;
  11. using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
  12. using Hotline.Share.Dtos.File;
  13. using Hotline.Share.Dtos.FlowEngine;
  14. using Hotline.Share.Dtos.FlowEngine.Workflow;
  15. using Hotline.Share.Dtos.Order;
  16. using Hotline.Share.Dtos.Settings;
  17. using Hotline.Share.Enums.Order;
  18. using Hotline.Share.Enums.Quality;
  19. using Hotline.Share.Enums.Settings;
  20. using Hotline.Share.Requests;
  21. using Hotline.Tools;
  22. using MapsterMapper;
  23. using Microsoft.AspNetCore.Mvc.Formatters;
  24. using Microsoft.EntityFrameworkCore.Metadata.Internal;
  25. using Novacode;
  26. using SqlSugar;
  27. using System.Data;
  28. using System.Dynamic;
  29. using Hotline.Settings;
  30. using XF.Domain.Authentications;
  31. using XF.Domain.Constants;
  32. using XF.Domain.Dependency;
  33. using XF.Domain.Exceptions;
  34. using XF.Domain.Repository;
  35. using Hotline.Repository.SqlSugar.System;
  36. using Microsoft.AspNetCore.Mvc;
  37. using Hotline.Share.Dtos.Bi;
  38. using System.Net;
  39. using PanGu;
  40. using Hotline.Users;
  41. using PanGu.Match;
  42. namespace Hotline.Application.Orders;
  43. public class OrderApplication : IOrderApplication, IScopeDependency
  44. {
  45. private readonly IOrderDomainService _orderDomainService;
  46. private readonly IWorkflowDomainService _workflowDomainService;
  47. private readonly IOrderRepository _orderRepository;
  48. private readonly ITimeLimitDomainService _timeLimitDomainService;
  49. private readonly IMapper _mapper;
  50. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  51. private readonly IRepository<OrderWord> _orderWrodRepository;
  52. private readonly IRepositoryTextSearch<OrderTs> _repositoryts;
  53. private readonly IFileRepository _fileRepository;
  54. private readonly ISessionContext _sessionContext;
  55. private readonly IRepository<OrderVisit> _orderVisitRepository;
  56. private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
  57. private readonly IQualityApplication _qualityApplication;
  58. private readonly ICapPublisher _capPublisher;
  59. private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
  60. private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
  61. private readonly IRepository<OrderSpecialDetail> _orderSpecialDetailRepository;
  62. public OrderApplication(
  63. IOrderDomainService orderDomainService,
  64. IOrderRepository orderRepository,
  65. IWorkflowDomainService workflowDomainService,
  66. ITimeLimitDomainService timeLimitDomainService,
  67. ISystemSettingCacheManager systemSettingCacheManager,
  68. IMapper mapper,
  69. IRepository<OrderWord> orderWrodRepository,
  70. IRepositoryTextSearch<OrderTs> repositoryts,
  71. IFileRepository fileRepository,
  72. ISessionContext sessionContext,
  73. IRepository<OrderVisit> orderVisitRepository,
  74. IRepository<OrderVisitDetail> orderVisitDetailRepository,
  75. IQualityApplication qualityApplication,
  76. ICapPublisher capPublisher,
  77. IRepository<SystemOrganize> systemOrganizeRepository,
  78. IRepository<WorkflowCountersign> workflowCountersignRepository,
  79. IRepository<OrderSpecialDetail> orderSpecialDetailRepository
  80. )
  81. {
  82. _orderDomainService = orderDomainService;
  83. _workflowDomainService = workflowDomainService;
  84. _orderRepository = orderRepository;
  85. _timeLimitDomainService = timeLimitDomainService;
  86. _mapper = mapper;
  87. _systemSettingCacheManager = systemSettingCacheManager;
  88. _orderWrodRepository = orderWrodRepository;
  89. _repositoryts = repositoryts;
  90. _fileRepository = fileRepository;
  91. _sessionContext = sessionContext;
  92. _orderVisitRepository = orderVisitRepository;
  93. _orderVisitDetailRepository = orderVisitDetailRepository;
  94. _qualityApplication = qualityApplication;
  95. _capPublisher = capPublisher;
  96. _systemOrganizeRepository = systemOrganizeRepository;
  97. _workflowCountersignRepository = workflowCountersignRepository;
  98. _orderSpecialDetailRepository = orderSpecialDetailRepository;
  99. }
  100. /// <summary>
  101. /// 更新工单办理期满时间(延期调用,其他不调用)
  102. /// 1.更新工单 2.更新流程 3.推送省平台
  103. /// </summary>
  104. /// <returns></returns>
  105. public async Task DelayOrderExpiredTimeAsync(string orderId, int timeCount, ETimeType timeType, CancellationToken cancellationToken)
  106. {
  107. var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: cancellationToken);
  108. var expiredTimeConfig =
  109. _timeLimitDomainService.CalcEndTime(DateTime.Now, new TimeConfig(timeCount, timeType), order.AcceptTypeCode);
  110. order.TimeLimit = expiredTimeConfig.TimeText;
  111. order.TimeLimitCount = expiredTimeConfig.Count;
  112. order.TimeLimitUnit = expiredTimeConfig.TimeType;
  113. order.ExpiredTime = expiredTimeConfig.ExpiredTime;
  114. order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
  115. //if (string.IsNullOrEmpty(order.WorkflowId))
  116. // throw new UserFriendlyException("该工单流程id异常");
  117. //var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, cancellationToken: cancellationToken);
  118. //await _workflowDomainService.UpdateExpiredTimeAsync(workflow, expiredTimeConfig.ExpiredTime,
  119. // expiredTimeConfig.TimeText, expiredTimeConfig.Count, expiredTimeConfig.TimeType, expiredTimeConfig.NearlyExpiredTime, cancellationToken);
  120. if (string.IsNullOrEmpty(order.WorkflowId))
  121. throw new UserFriendlyException("该工单流程id异常");
  122. await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, expiredTimeConfig.ExpiredTime, cancellationToken);
  123. await _orderRepository.UpdateAsync(order, cancellationToken);
  124. }
  125. /// <summary>
  126. /// 新增工单办理流程记录
  127. /// </summary>
  128. public async Task AddOrderTracesAsync(string orderId, ICollection<WorkflowTraceDto> traces, CancellationToken cancellationToken)
  129. {
  130. var order = await _orderRepository.GetAsync(orderId, cancellationToken);
  131. if (order is null)
  132. throw new UserFriendlyException("工单不存在");
  133. if (string.IsNullOrEmpty(order.WorkflowId))
  134. throw new UserFriendlyException("工单未开启流程");
  135. await _workflowDomainService.AddTracesAsync(order.WorkflowId, _mapper.Map<List<WorkflowTrace>>(traces),
  136. cancellationToken);
  137. }
  138. /// <summary>
  139. /// 撤销工单
  140. /// </summary>
  141. public async Task CancelOrderAsync(string orderId, string opinion, CancellationToken cancellationToken)
  142. {
  143. var order = await _orderRepository.GetAsync(orderId, cancellationToken);
  144. if (order is null)
  145. throw new UserFriendlyException("工单不存在");
  146. if (!string.IsNullOrEmpty(order.WorkflowId))
  147. {
  148. //结束流程
  149. await _workflowDomainService.TerminateAsync(new TerminateDto
  150. {
  151. WorkflowId = order.WorkflowId,
  152. Opinion = opinion
  153. }, cancellationToken);
  154. }
  155. //归档工单
  156. var now = DateTime.Now;
  157. var handleDuration = order.StartTime.HasValue
  158. ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value,
  159. now, order.ProcessType is EProcessType.Zhiban)
  160. : 0;
  161. var fileDuration = order.CenterToOrgTime.HasValue
  162. ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value,
  163. now, order.ProcessType is EProcessType.Zhiban)
  164. : 0;
  165. var allDuration = order.StartTime.HasValue
  166. ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value, now,
  167. order.ProcessType is EProcessType.Zhiban)
  168. : 0;
  169. var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
  170. ? _timeLimitDomainService.CalcWorkTime(order.CreationTime, order.ActualHandleTime.Value,
  171. order.ProcessType is EProcessType.Zhiban)
  172. : 0;
  173. var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
  174. ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value, order.ActualHandleTime.Value,
  175. order.ProcessType is EProcessType.Zhiban)
  176. : 0;
  177. order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
  178. await _orderRepository.UpdateAsync(order, cancellationToken);
  179. }
  180. /// <summary>
  181. /// 即将超期列表
  182. /// </summary>
  183. /// <param name="dto"></param>
  184. /// <param name="cancellationToken"></param>
  185. /// <returns></returns>
  186. public ISugarQueryable<Order> GetAboutToExpireAsync(AboutToExpireListDto dto)
  187. {
  188. //var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
  189. //var value = setting?.SettingValue[0];
  190. //value = string.IsNullOrEmpty(value) ? "0" : value;
  191. //DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
  192. //stTime = _timeLimitDomainService.WorkDay(stTime);
  193. //DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
  194. DateTime? dateTime = DateTime.Now;
  195. return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
  196. .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
  197. .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
  198. .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
  199. .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
  200. .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
  201. //&& stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value
  202. //.Where(d => d.ExpiredTime != null &&
  203. // d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
  204. .Where(d=>d.Status < EOrderStatus.Filed && dateTime > d.NearlyExpiredTime && dateTime < d.ExpiredTime)
  205. .OrderByDescending(d => d.CreationTime);
  206. }
  207. // /// <summary>
  208. // /// 即将超期节点列表
  209. // /// </summary>
  210. // /// <param name="dto"></param>
  211. // /// <param name="cancellationToken"></param>
  212. // /// <returns></returns>
  213. //public async Task<PagedDto<WorkflowOrderDto>> GetAboutToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
  214. //{
  215. // var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
  216. // var value = setting?.SettingValue[0];
  217. // value = string.IsNullOrEmpty(value) ? "0" : value;
  218. // DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
  219. // stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
  220. // DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
  221. // RefAsync<int> total = 0;
  222. // var items = await Db.Queryable<Workflow>()
  223. // .LeftJoin<Order>((x, o) => x.ExternalId == o.Id)
  224. // .Where(x => x.ModuleCode == "OrderHandle")
  225. // .WhereIF(dto.IsProvince.HasValue, (x, o) => o.IsProvince == dto.IsProvince)
  226. // .WhereIF(!string.IsNullOrEmpty(dto.Keyword), (x, o) => o.Title.Contains(dto.Keyword!) || o.No.Contains(dto.Keyword!))
  227. // .Where((x, o) => (int)x.Status < 20 && stTime >= x.ExpiredTime && stTime2 <= x.ExpiredTime)
  228. // .Select((x, o) => new WorkflowOrder { Order = o }, true)
  229. // .OrderByDescending(x => x.CreationTime)
  230. // .ToPageListAsync(dto.PageIndex, dto.PageSize, total, cancellationToken);
  231. // return new PagedDto<WorkflowOrderDto>(total, _mapper.Map<IReadOnlyList<WorkflowOrderDto>>(items));
  232. //}
  233. /// <summary>
  234. /// 已超期列表
  235. /// </summary>
  236. /// <param name="dto"></param>
  237. /// <param name="cancellationToken"></param>
  238. /// <returns></returns>
  239. public ISugarQueryable<Order> GetToExpireAsync(AboutToExpireListDto dto)
  240. {
  241. DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
  242. return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
  243. .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
  244. //.WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
  245. .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No))
  246. .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!))
  247. .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
  248. .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
  249. .Where(d => d.ExpiredTime != null &&
  250. (((d.Status == EOrderStatus.Filed || d.Status == EOrderStatus.Published || d.Status == EOrderStatus.Visited) && d.FiledTime >= d.ExpiredTime) ||
  251. ((d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited) && stTime >= d.ExpiredTime.Value)))
  252. .OrderByDescending(x => x.CreationTime);
  253. }
  254. // /// <summary>
  255. // /// 已超期节点列表
  256. // /// </summary>
  257. // /// <param name="dto"></param>
  258. // /// <param name="cancellationToken"></param>
  259. // /// <returns></returns>
  260. // public async Task<PagedDto<WorkflowOrderDto>> GetToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
  261. // {
  262. // DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
  263. //RefAsync<int> total = 0;
  264. //var items= await Db.Queryable<Workflow>()
  265. // .LeftJoin<Order>((x,o)=>x.ExternalId == o.Id)
  266. // .Where(x => x.ModuleCode == "OrderHandle")
  267. // .WhereIF(dto.IsProvince.HasValue, (x, o) => o.IsProvince == dto.IsProvince)
  268. // .WhereIF(!string.IsNullOrEmpty(dto.Keyword), (x, o) => o.Title.Contains(dto.Keyword!) || o.No.Contains(dto.Keyword!))
  269. // .Where((x,o) => (((int)x.Status >= 20 && x.EndTime >= x.ExpiredTime) || ((int)x.Status < 20 && stTime >= x.ExpiredTime)))
  270. // .Select((x, o) => new WorkflowOrder { Order = o }, true)
  271. // .OrderByDescending(x => x.CreationTime)
  272. // .ToPageListAsync(dto.PageIndex, dto.PageSize, total, cancellationToken);
  273. // return new PagedDto<WorkflowOrderDto>(total, _mapper.Map<IReadOnlyList<WorkflowOrderDto>>(items));
  274. // }
  275. /// <summary>
  276. /// 工单关键字分词
  277. /// </summary>
  278. /// <param name="inputStr"></param>
  279. /// <returns></returns>
  280. public async Task OrderParticiple(string inputStr, string orderId,DateTime time, CancellationToken cancellationToken)
  281. {
  282. var seg = new Segment();
  283. ICollection<WordInfo> splitWords = seg.DoSegment(inputStr);
  284. var words = new List<string>();
  285. for (int i = 0; i < splitWords.Count; i++)
  286. {
  287. var word = splitWords.ElementAt(i);
  288. if (word is { WordType: WordType.SimplifiedChinese, Word.Length: > 1 } )
  289. words.Add(splitWords.ElementAt(i).Word);
  290. }
  291. var vector = await _repositoryts.SearchAsync(orderId, cancellationToken);
  292. if (vector != null && vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, words, cancellationToken);
  293. else await _repositoryts.AddVectorAsync(orderId, time, words, cancellationToken);
  294. //var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("普通标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
  295. //var res = new List<string>();
  296. //if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
  297. //var participles = await _orderWrodRepository.Queryable().In(x => x.Tag, res).ToListAsync(cancellationToken);
  298. //if (participles.Any())
  299. //{
  300. // //关键词
  301. // var tags = participles.Select(x => x.Tag).ToList();
  302. // var tagsStr = string.Join(",", tags);
  303. // await _orderRepository.Updateable().SetColumns(x => x.TagNames == tagsStr).Where(x => x.Id == orderId).ExecuteCommandAsync(cancellationToken);
  304. // List<string> synonyms = participles.Select(x => x.Synonym).ToList();
  305. // if (synonyms.Any())
  306. // {
  307. // var synonymsStr = string.Join(",", synonyms);
  308. // synonyms = synonymsStr.Split(",").Distinct().ToList();
  309. // tags.AddRange(synonyms);
  310. // }
  311. // var vector = await _orderRepository.Queryable().Where(x => x.Id == orderId).ToListAsync(cancellationToken);
  312. // if (vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, tags, cancellationToken);
  313. // else await _repositoryts.AddVectorAsync(orderId, DateTime.Now, tags, cancellationToken);
  314. //}
  315. }
  316. public async Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken)
  317. {
  318. var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("敏感标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
  319. var res = new List<string>();
  320. if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
  321. if (res.Any())
  322. {
  323. var intersect = words.Intersect(res).ToList();
  324. await _orderRepository.Updateable().SetColumns(o => new Order() { Sensitive = intersect }).Where(o => o.Id == orderId).ExecuteCommandAsync(cancellationToken);
  325. }
  326. }
  327. /// <summary>
  328. /// 接收外部平台工单
  329. /// </summary>
  330. public Task<AddOrderResponse> ReceiveOrderFromExternalAsync(AddOrderDto dto, ISessionContext current, CancellationToken cancellationToken)
  331. {
  332. switch (dto.Source)
  333. {
  334. case ESource.ProvinceStraight:
  335. return ReceiveOrderFromProvinceAsync(dto, dto.Files, current, cancellationToken);
  336. case ESource.Police110:
  337. case ESource.CityDataExchangeLz:
  338. case ESource.CityDataExchangeYB:
  339. case ESource.CityDataExchangeZG:
  340. case ESource.CityDataExchangeNJ:
  341. case ESource.WebPortal:
  342. case ESource.ConvergenceMedia:
  343. case ESource.IYIBIN:
  344. case ESource.ZHYB:
  345. case ESource.ZZPT:
  346. case ESource.WLLZ:
  347. return ReceiveOrderFromOtherPlatformAsync(dto, dto.Files, current, cancellationToken);
  348. case ESource.Hotline:
  349. case ESource.HotlineImport:
  350. default:
  351. throw new ArgumentOutOfRangeException();
  352. }
  353. }
  354. /// <summary>
  355. /// 接收外部平台修改工单附件
  356. /// </summary>
  357. public async Task UpdateOrderFilesAnonymousAsync(UpdateOrderFilesDto dto, CancellationToken cancellationToken)
  358. {
  359. if (string.IsNullOrEmpty(dto.Id) && string.IsNullOrEmpty(dto.OrderNo))
  360. throw new UserFriendlyException("工单外部编号不能为空");
  361. var order = await _orderRepository.Queryable()
  362. .FirstAsync(d => d.Id == dto.Id || d.No == dto.OrderNo, cancellationToken);
  363. if (order != null && dto.Files != null && dto.Files.Any())
  364. {
  365. order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", cancellationToken);
  366. await _orderRepository.UpdateAsync(order, cancellationToken);
  367. }
  368. }
  369. /// <summary>
  370. /// 工单回访
  371. /// </summary>
  372. /// <param name="dto"></param>
  373. /// <param name="cancellationToken"></param>
  374. /// <returns></returns>
  375. public async Task OrderVisitWeb(OrderVisitWebDto dto, CancellationToken cancellationToken)
  376. {
  377. var visit = await _orderVisitRepository.Queryable()
  378. .Includes(x => x.Order)
  379. .Includes(x => x.OrderVisitDetails)
  380. .FirstAsync(x => x.Id == dto.Id);
  381. if (visit != null)
  382. {
  383. var first = dto.OrderVisitDetailDto.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);
  384. if (first != null)
  385. {
  386. visit.NowEvaluate = first.OrgProcessingResults;
  387. visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
  388. }
  389. visit.VisitState = EVisitState.Visited;
  390. visit.VisitTime = dto.VisitTime;
  391. visit.VisitType = dto.VisitType;
  392. for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
  393. {
  394. var detail = visit.OrderVisitDetails[i];
  395. var detaildto = dto.OrderVisitDetailDto.FirstOrDefault(x => x.Id == detail.Id);
  396. if (detaildto != null)
  397. {
  398. _mapper.Map(detaildto, visit.OrderVisitDetails[i]);
  399. }
  400. }
  401. await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
  402. await _orderVisitDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, cancellationToken);
  403. await _orderRepository.UpdateAsync(visit.Order, cancellationToken);
  404. var orderDto = _mapper.Map<OrderDto>(visit.Order);
  405. if (first != null)
  406. {
  407. //推省上
  408. await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
  409. new PublishVisitDto()
  410. {
  411. Order = orderDto,
  412. No = visit.No,
  413. VisitType = visit.VisitType,
  414. VisitName = visit.CreatorName,
  415. VisitTime = visit.VisitTime,
  416. VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
  417. AreaCode = visit.Order.AreaCode!,
  418. SubjectResultSatifyCode = first.OrgProcessingResults.Key,
  419. FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
  420. ClientGuid = ""
  421. }, cancellationToken: cancellationToken);
  422. }
  423. //写入质检
  424. await _qualityApplication.AddQualityAsync(EQualitySource.Visit, orderDto.Id, visit.Id,
  425. cancellationToken);
  426. }
  427. }
  428. public ISugarQueryable<Order> QueryOrders(QueryOrderDto dto)
  429. {
  430. var isCenter = _sessionContext.OrgIsCenter;
  431. return _orderRepository.Queryable(canView: !isCenter)
  432. .Includes(x => x.OrderScreens)
  433. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!)) //标题
  434. .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo == dto.ProvinceNo) //省本地编号
  435. .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) //工单编码
  436. //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
  437. .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
  438. .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
  439. .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
  440. .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone == dto.TransferPhone!) //转接号码
  441. //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
  442. .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
  443. .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
  444. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
  445. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
  446. .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel)) //紧急程度
  447. .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
  448. .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo!) //联系电话
  449. .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
  450. .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
  451. .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
  452. .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status)) //工单状态
  453. .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
  454. .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName == dto.ActualHandlerName) //接办人
  455. .WhereIF(dto.IsScreen == true, d => d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //有甄别
  456. .WhereIF(dto.IsScreen == false, d => !d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //无甄别
  457. .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.ActualHandleStepCode == dto.CurrentStepCode) //当前办理节点
  458. .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
  459. .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
  460. .WhereIF(dto.IsOverTime == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
  461. .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
  462. .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
  463. .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
  464. .WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
  465. .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.IsProvince == true)
  466. .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.IsProvince == false)
  467. .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), d => SqlFunc.JsonArrayAny(d.Sensitive, dto.SensitiveWord))
  468. .WhereIF(dto.IsSensitiveWord.HasValue && dto.IsSensitiveWord == true, d => d.Sensitive != null && SqlFunc.JsonArrayLength(d.Sensitive) > 0)
  469. .WhereIF(dto.IsUrgent.HasValue , d=>d.IsUrgent == dto.IsUrgent.Value)
  470. .OrderByDescending(d => d.CreationTime);
  471. }
  472. /// <summary>
  473. /// 未签收统计
  474. /// </summary>
  475. /// <param name="dto"></param>
  476. /// <returns></returns>
  477. public ISugarQueryable<Order, WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto)
  478. {
  479. if (dto.EndTime.HasValue)
  480. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  481. var IsCenter = _sessionContext.OrgIsCenter;
  482. return _orderRepository.Queryable()
  483. .LeftJoin<WorkflowStep>((x, ws) => x.Id == ws.ExternalId)
  484. .WhereIF(dto.StartTime.HasValue, (x, ws) => ws.CreationTime >= dto.StartTime)
  485. .WhereIF(dto.EndTime.HasValue, (x, ws) => ws.CreationTime <= dto.EndTime)
  486. .WhereIF(dto.Level == 0 && IsCenter == false, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
  487. .WhereIF(dto.Level == 1, (x, ws) => ws.AcceptorOrgId == _sessionContext.OrgId)
  488. .WhereIF(dto.Level == 2, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
  489. .WhereIF(dto.Signed == 0, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
  490. .WhereIF(dto.Signed == 1, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForHandle)
  491. .Where((x, ws) => ws.CountersignPosition == Share.Enums.FlowEngine.ECountersignPosition.None && x.Status > EOrderStatus.WaitForAccept)
  492. .OrderByDescending((x, ws) => ws.CreationTime);
  493. }
  494. /// <summary>
  495. /// 信件来源统计
  496. /// </summary>
  497. /// <param name="dto"></param>
  498. /// <returns></returns>
  499. public ISugarQueryable<Order> QueryOrderSource(QueryOrderSourceRequest dto)
  500. {
  501. if (dto.EndTime.HasValue)
  502. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  503. return _orderRepository.Queryable()
  504. .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
  505. .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
  506. .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
  507. .Where(d => d.SourceChannel != null && d.SourceChannel != "");
  508. }
  509. /// <summary>
  510. /// 信件来源统计明细
  511. /// </summary>
  512. /// <param name="dto"></param>
  513. /// <returns></returns>
  514. public ISugarQueryable<Order> QueryOrderSourceDetail(QueryOrderSourceDetailRequest dto)
  515. {
  516. return _orderRepository.Queryable()
  517. .WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), d => d.SourceChannel == dto.SourceChannel)
  518. .WhereIF(dto.Time.HasValue, d => d.CreationTime.ToString("yyyy-MM-dd") == dto.Time.Value.ToString("yyyy-MM-dd"))
  519. .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
  520. .Where(d => d.SourceChannel != null && d.SourceChannel != "");
  521. }
  522. /// <summary>
  523. /// 部门超期统计
  524. /// </summary>
  525. /// <param name="dto"></param>
  526. /// <returns></returns>
  527. public ISugarQueryable<OrderBiOrgDataListVo> QueryOrgDataList(ReportPagedRequest dto)
  528. {
  529. if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
  530. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  531. var IsCenter = _sessionContext.OrgIsCenter;
  532. var queryOrder = _systemOrganizeRepository.Queryable()
  533. .LeftJoin<Order>((x, o) => x.Id == o.ActualHandleOrgCode)
  534. .WhereIF(dto.StartTime.HasValue, (x, o) => o.CreationTime >= dto.StartTime)
  535. .WhereIF(dto.EndTime.HasValue, (x, o) => o.CreationTime <= dto.EndTime)
  536. .WhereIF(IsCenter == false, (x, o) => o.ActualHandleOrgCode == _sessionContext.RequiredOrgId)
  537. .GroupBy((x, o) => new { x.Id, x.Name })
  538. .Select((x, o) => new OrderBiOrgDataListVo
  539. {
  540. OrgName = x.Name,
  541. OrgId = x.Id,
  542. HandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.Status >= EOrderStatus.Filed && o.ExpiredTime < o.FiledTime, 1, 0)),
  543. NoHandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.Status < EOrderStatus.Filed && o.ExpiredTime < SqlFunc.GetDate(), 1, 0)),
  544. }).MergeTable();
  545. var queryCountersign = _workflowCountersignRepository.Queryable()
  546. .LeftJoin<WorkflowCountersignMember>((x, o) => x.Id == o.WorkflowCountersignId)
  547. .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
  548. .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
  549. .GroupBy((x, o) => o.Key)
  550. .Select((x, o) => new OrderBiOrgDataListVo
  551. {
  552. OrgId = o.Key,
  553. CounterHandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsHandled && x.IsExpired.HasValue && x.IsExpired.Value == true, 1, 0)),
  554. CounterNoHandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsHandled == false && x.IsExpired.HasValue && x.IsExpired.Value == true, 1, 0)),
  555. }).MergeTable();
  556. var query = queryOrder.LeftJoin(queryCountersign, (or, co) => or.OrgId == co.OrgId)
  557. .LeftJoin<SystemOrganize>((or, co, so) => or.OrgId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == so.Id)
  558. .GroupBy((or, co, so) => new { so.Id, so.Name })
  559. .Select((or, co, so) => new OrderBiOrgDataListVo
  560. {
  561. OrgName = so.Name,
  562. OrgId = so.Id,
  563. HandlerExtendedNum = SqlFunc.AggregateSum(or.HandlerExtendedNum),
  564. NoHandlerExtendedNum = SqlFunc.AggregateSum(or.NoHandlerExtendedNum),
  565. CounterHandlerExtendedNum = SqlFunc.AggregateSum(co.CounterHandlerExtendedNum),
  566. CounterNoHandlerExtendedNum = SqlFunc.AggregateSum(co.CounterNoHandlerExtendedNum)
  567. }).MergeTable();
  568. query = query.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrgName.Contains(dto.Keyword!)).Where(x => x.HandlerExtendedNum > 0 || x.NoHandlerExtendedNum > 0 || x.CounterHandlerExtendedNum > 0 || x.CounterNoHandlerExtendedNum > 0);
  569. switch (dto.SortField)
  570. {
  571. case "handlerExtendedNum":
  572. query = dto.SortRule is 0 ? query.OrderBy(x => x.HandlerExtendedNum) : query.OrderByDescending(x => x.HandlerExtendedNum);
  573. break;
  574. case "counterHandlerExtendedNum":
  575. query = dto.SortRule is 0 ? query.OrderBy(x => x.CounterHandlerExtendedNum) : query.OrderByDescending(x => x.CounterHandlerExtendedNum);
  576. break;
  577. case "noHandlerExtendedNum":
  578. query = dto.SortRule is 0 ? query.OrderBy(x => x.NoHandlerExtendedNum) : query.OrderByDescending(x => x.NoHandlerExtendedNum);
  579. break;
  580. case "counterNoHandlerExtendedNum":
  581. query = dto.SortRule is 0 ? query.OrderBy(x => x.CounterNoHandlerExtendedNum) : query.OrderByDescending(x => x.CounterNoHandlerExtendedNum);
  582. break;
  583. }
  584. return query;
  585. }
  586. /// <summary>
  587. /// 部门超期统计明细
  588. /// </summary>
  589. /// <param name="dto"></param>
  590. /// <returns></returns>
  591. public ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListDetailRequest dto)
  592. {
  593. dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
  594. var quer = _orderRepository.Queryable()
  595. .InnerJoin<SystemOrganize>((x, so) => x.ActualHandleOrgCode == so.Id)
  596. .Where(x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
  597. //.WhereIF(dto.Statuses.Any(), x => dto.Statuses.Contains(x.Status)) //工单状态
  598. .WhereIF(dto.QueryType == 1, x => x.Status >= EOrderStatus.Filed && x.ExpiredTime < x.FiledTime) //业务已办超期
  599. .WhereIF(dto.QueryType == 3, x => x.Status < EOrderStatus.Filed && x.ExpiredTime < SqlFunc.GetDate()) //业务待办超期
  600. .WhereIF(dto.QueryType == 5, x =>
  601. (x.Status >= EOrderStatus.Filed && x.ExpiredTime < x.FiledTime) || (x.Status < EOrderStatus.Filed && x.ExpiredTime < SqlFunc.GetDate()))
  602. .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.QueryType is 1 or 3 && dto.OrgCode == "001", x => x.ActualHandleOrgCode == dto.OrgCode)
  603. .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.QueryType is 1 or 3 && dto.OrgCode != "001", x => x.ActualHandleOrgCode.StartsWith(dto.OrgCode))
  604. .MergeTable();
  605. if (dto.QueryType is 2 or 4 or 5)
  606. {
  607. var queryCountersign = _workflowCountersignRepository.Queryable()
  608. .LeftJoin<WorkflowCountersignMember>((x, o) => x.Id == o.WorkflowCountersignId)
  609. .Where((x, o) => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime && x.IsExpired.HasValue && x.IsExpired.Value == true)
  610. .WhereIF(dto.QueryType == 2, (x, o) => o.IsHandled == true) //会签已办超期
  611. .WhereIF(dto.QueryType == 4, (x, o) => o.IsHandled == false) //会签待办超期
  612. .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.QueryType is 2 or 4 or 5, (x, o) => o.Key.StartsWith(dto.OrgCode))
  613. //.GroupBy((x,o)=>x.WorkflowId)
  614. .Select((x, o) => new { Id = x.WorkflowId })
  615. .MergeTable();
  616. quer = quer.InnerJoin(queryCountersign, (x, c) => x.WorkflowId == c.Id);
  617. }
  618. return quer;
  619. }
  620. /// <summary>
  621. /// 部门超期统计明细
  622. /// </summary>
  623. /// <param name="dto"></param>
  624. /// <returns></returns>
  625. public ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListAllDetailRequest dto)
  626. {
  627. dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
  628. bool IsCenter = _sessionContext.OrgIsCenter;
  629. var quer = _orderRepository.Queryable()
  630. .InnerJoin<SystemOrganize>((x, so) => x.ActualHandleOrgCode == so.Id)
  631. .Where(x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
  632. .WhereIF(dto.Statuses.Any(), x => dto.Statuses.Contains(x.Status)) //工单状态
  633. .WhereIF( dto.ExpiredType is 2, x=>x.OrderDelays.Any(x=> x.DelayState == EDelayState.Pass))
  634. .Where(x =>
  635. (x.Status >= EOrderStatus.Filed && x.ExpiredTime < x.FiledTime) || (x.Status < EOrderStatus.Filed && x.ExpiredTime < SqlFunc.GetDate()))
  636. .WhereIF(IsCenter == false, x => x.ActualHandleOrgCode.StartsWith(_sessionContext.RequiredOrgId))
  637. .WhereIF(!string.IsNullOrEmpty(dto.OrgName) , x => x.AcceptorOrgName == dto.OrgName)
  638. .MergeTable();
  639. var queryCountersign = _workflowCountersignRepository.Queryable()
  640. .LeftJoin<WorkflowCountersignMember>((x, o) => x.Id == o.WorkflowCountersignId)
  641. .Where((x, o) => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime && x.IsExpired.HasValue && x.IsExpired.Value == true)
  642. .WhereIF(IsCenter == false, (x, o) => o.Key.StartsWith(_sessionContext.RequiredOrgId))
  643. .WhereIF(!string.IsNullOrEmpty(dto.OrgName) && IsCenter == false, (x, o) => o.Value == dto.OrgName)
  644. .Select((x, o) => new { Id = x.WorkflowId, ActualHandleOrgCode = o.Key, ActualHandleOrgName = o.Value })
  645. .MergeTable();
  646. quer = quer.LeftJoin(queryCountersign, (x, c) => x.WorkflowId == c.Id).Select((x, c) => new Order
  647. {
  648. DaysOverdueOrgName = SqlFunc.IIF(!string.IsNullOrEmpty(c.Id), c.ActualHandleOrgName, x.ActualHandleOrgName),
  649. Id = x.Id.SelectAll()
  650. }) ;
  651. return quer;
  652. }
  653. /// <summary>
  654. /// 回退错件统计
  655. /// </summary>
  656. /// <param name="dto"></param>
  657. /// <returns></returns>
  658. public ISugarQueryable<OrderReTransactVo> OrderReTransact(QueryOrderReTransactRequest dto)
  659. {
  660. return _orderSpecialDetailRepository.Queryable()
  661. .Includes(x => x.OrderSpecial)
  662. .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName!))
  663. .Where(x => x.OrderSpecial.ESpecialType == ESpecialType.ReTransact)
  664. .Where(x => x.OrderSpecial.CreationTime >= dto.StartTime)
  665. .Where(x => x.OrderSpecial.CreationTime <= dto.EndTime)
  666. .GroupBy(x => new { Time = x.OrderSpecial.CreationTime.ToString("yyyy-MM-dd"), x.OrgId, x.OrgName })
  667. .Select(x => new OrderReTransactVo
  668. {
  669. Time = x.OrderSpecial.CreationTime.ToString("yyyy-MM-dd"),
  670. OrgId = x.OrgId,
  671. OrgName = x.OrgName,
  672. Num = SqlFunc.AggregateCount(1)
  673. }).MergeTable()
  674. .OrderByIF(dto.SortRule is 0, x => x.Num, OrderByType.Asc)
  675. .OrderByIF(dto.SortRule is 1, x => x.Num, OrderByType.Desc); ;
  676. }
  677. /// <summary>
  678. /// 回退错件明细统计
  679. /// </summary>
  680. /// <param name="dto"></param>
  681. /// <returns></returns>
  682. public ISugarQueryable<OrderSpecialDetail> QueryOrderSourceDetail(QueryOrderReTransactDetailRequest dto)
  683. {
  684. return _orderSpecialDetailRepository.Queryable()
  685. .Includes(x => x.OrderSpecial, s => s.Order)
  686. .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName!))
  687. .WhereIF(!string.IsNullOrEmpty(dto.ErrorName), x => x.ErrorName.Contains(dto.ErrorName!))
  688. .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderSpecial!.Order!.No!.Contains(dto.No!))
  689. .Where(x => x.OrderSpecial.ESpecialType == ESpecialType.ReTransact)
  690. .Where(x => x.OrderSpecial.CreationTime >= dto.StartTime)
  691. .Where(x => x.OrderSpecial.CreationTime <= dto.EndTime);
  692. }
  693. /// <summary>
  694. /// 部门满意度统计
  695. /// </summary>
  696. /// <returns></returns>
  697. public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgSatisfactionStatistics(PagedKeywordSonRequest dto) {
  698. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  699. bool IsCenter = _sessionContext.OrgIsCenter;
  700. var list = _orderVisitDetailRepository.Queryable()
  701. .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value && x.OrderVisit.VisitTime <= dto.EndTime.Value && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
  702. .WhereIF(string.IsNullOrEmpty(dto.OrgName) == false, x => x.VisitOrgName.Contains(dto.OrgName))
  703. .WhereIF(string.IsNullOrEmpty(dto.LineNum) == false, x => x.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
  704. .WhereIF(IsCenter == false, x => x.VisitOrgCode.StartsWith(_sessionContext.OrgId));
  705. var data = new List<VisitAndOrgSatisfactionStatisticsDto>();
  706. if (IsCenter && list != null)
  707. {
  708. data = await list.GroupBy(x => new
  709. {
  710. VisitOrgCode = x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))
  711. })
  712. .Select(x => new VisitAndOrgSatisfactionStatisticsDto()
  713. {
  714. OrgCode = x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
  715. TotalSumCount = SqlFunc.AggregateCount(x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
  716. VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
  717. SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
  718. RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
  719. DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
  720. NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
  721. NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
  722. NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
  723. })
  724. .MergeTable()
  725. .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
  726. .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
  727. {
  728. OrgName = o.Name,
  729. OrgCode = it.OrgCode,
  730. OrgType = o.OrgType,
  731. TotalSumCount = it.TotalSumCount,
  732. VerySatisfiedCount = it.VerySatisfiedCount,//非常满意数
  733. SatisfiedCount = it.SatisfiedCount, //满意数
  734. RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount,//视为满意
  735. DefaultSatisfiedCount = it.DefaultSatisfiedCount,//默认满意
  736. NoSatisfiedCount = it.NoSatisfiedCount,//不满意
  737. NoEvaluateCount = it.NoEvaluateCount,//未做评价
  738. NoPutThroughCount = it.NoPutThroughCount,//未接通
  739. })
  740. .ToListAsync();
  741. }
  742. else
  743. {
  744. data = await list.GroupBy(x => new
  745. {
  746. x.VisitOrgCode
  747. })
  748. .Select(x => new VisitAndOrgSatisfactionStatisticsDto()
  749. {
  750. OrgCode = x.VisitOrgCode,
  751. TotalSumCount = SqlFunc.AggregateCount(x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
  752. VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
  753. SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
  754. RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
  755. DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
  756. NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
  757. NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
  758. NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
  759. })
  760. .MergeTable()
  761. .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
  762. .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
  763. {
  764. OrgName = o.Name,
  765. OrgCode = it.OrgCode,
  766. OrgType = o.OrgType,
  767. TotalSumCount = it.TotalSumCount,
  768. VerySatisfiedCount = it.VerySatisfiedCount,//非常满意数
  769. SatisfiedCount = it.SatisfiedCount, //满意数
  770. RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount,//视为满意
  771. DefaultSatisfiedCount = it.DefaultSatisfiedCount,//默认满意
  772. NoSatisfiedCount = it.NoSatisfiedCount,//不满意
  773. NoEvaluateCount = it.NoEvaluateCount,//未做评价
  774. NoPutThroughCount = it.NoPutThroughCount,//未接通
  775. })
  776. .ToListAsync();
  777. }
  778. return data;
  779. }
  780. /// <summary>
  781. /// 子部门满意度
  782. /// </summary>
  783. /// <returns></returns>
  784. public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgStatisfactionOrgDetail(PagedKeywordSonRequest dto)
  785. {
  786. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  787. bool IsCenter = _sessionContext.OrgIsCenter;
  788. var list = await _systemOrganizeRepository.Queryable().Where(x => x.Id.StartsWith(dto.OrgCode))
  789. .LeftJoin<OrderVisitDetail>((x, it) => x.Id == it.VisitOrgCode)
  790. .Where((x, it) => it.OrderVisit.VisitTime >= dto.StartTime.Value && it.OrderVisit.VisitTime <= dto.EndTime.Value && it.VisitTarget == EVisitTarget.Org && it.OrderVisit.VisitState == EVisitState.Visited)
  791. .WhereIF(dto.OrgCode == "001", (x, it) => it.VisitOrgCode == dto.OrgCode)
  792. .WhereIF(dto.OrgCode != "001", (x, it) => it.VisitOrgCode.StartsWith(dto.OrgCode))
  793. .WhereIF(!string.IsNullOrEmpty(dto.LineNum), (x, it) => it.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
  794. .WhereIF(IsCenter == false, (x, it) => it.VisitOrgCode.StartsWith(_sessionContext.OrgId))
  795. .GroupBy((x, it) => new
  796. {
  797. VisitOrgCode = it.VisitOrgCode
  798. })
  799. .Select((x, it) => new VisitAndOrgSatisfactionStatisticsDto()
  800. {
  801. OrgCode = it.VisitOrgCode,
  802. TotalSumCount = SqlFunc.AggregateCount(it.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("9"))),
  803. VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
  804. SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
  805. RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
  806. DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
  807. NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
  808. NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
  809. NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "6", 1, 0)))//未接通
  810. })
  811. .MergeTable()
  812. .LeftJoin<SystemOrganize>((x, it) => x.OrgCode == it.Id)
  813. .Select((x, it) => new VisitAndOrgSatisfactionStatisticsDto()
  814. {
  815. OrgName = it.Name,
  816. OrgCode = x.OrgCode,
  817. OrgType = it.OrgType,
  818. TotalSumCount = x.TotalSumCount,
  819. VerySatisfiedCount = x.VerySatisfiedCount,//非常满意数
  820. SatisfiedCount = x.SatisfiedCount, //满意数
  821. RegardedAsSatisfiedCount = x.RegardedAsSatisfiedCount,//视为满意
  822. DefaultSatisfiedCount = x.DefaultSatisfiedCount,//默认满意
  823. NoSatisfiedCount = x.NoSatisfiedCount,//不满意
  824. NoEvaluateCount = x.NoEvaluateCount,//未做评价
  825. NoPutThroughCount = x.NoPutThroughCount,//未接通
  826. })
  827. .ToListAsync();
  828. return list;
  829. }
  830. /// <summary>
  831. /// 部门满意度明细统计
  832. /// </summary>
  833. /// <param name="dto"></param>
  834. /// <returns></returns>
  835. public ISugarQueryable<OrderVisitDetail> VisitAndOrgSatisfactionDetail(VisitAndOrgSatisfactionDetailDto dto)
  836. {
  837. dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
  838. bool IsCenter = _sessionContext.OrgIsCenter;
  839. return _orderVisitDetailRepository.Queryable()
  840. .Includes(x => x.OrderVisit, o => o.Order, d => d.CallRecord)
  841. .Where(x => x.OrderVisit.VisitTime >= dto.StartTime && x.OrderVisit.VisitTime <= dto.EndTime && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited)
  842. .WhereIF(dto.OrgCode == "001", x => x.VisitOrgCode == dto.OrgCode)
  843. //.WhereIF(dto.OrgCode != "001", x => x.VisitOrgCode == dto.OrgCode).
  844. .WhereIF(dto.IsOnlyMy == true, x => x.VisitOrgCode == dto.OrgCode)
  845. .WhereIF(IsCenter == true && dto.IsOnlyMy == true, x => x.VisitOrgCode == dto.OrgCode)
  846. .WhereIF(IsCenter == true && dto.IsOnlyMy == null, x => x.VisitOrgCode.StartsWith(dto.OrgCode))
  847. .WhereIF(IsCenter == false, x => x.VisitOrgCode == dto.OrgCode)
  848. .WhereIF(dto.TypeId is 1, x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == dto.DateValue)
  849. .WhereIF(dto.TypeId is 2, x => SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == dto.DateValue)
  850. .WhereIF(!string.IsNullOrEmpty(dto.LineNum), x => x.OrderVisit.Order.CallRecord.Gateway == dto.LineNum);
  851. }
  852. #region private
  853. /// <summary>
  854. /// 接受外部工单(除省平台)
  855. /// </summary>
  856. /// <param name="dto"></param>
  857. /// <param name="cancellationToken"></param>
  858. /// <returns></returns>
  859. private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
  860. ISessionContext current, CancellationToken cancellationToken)
  861. {
  862. if (string.IsNullOrEmpty(dto.ExternalId))
  863. throw new UserFriendlyException("工单外部编号不能为空");
  864. var order = await _orderRepository.Queryable()
  865. .FirstAsync(d => d.ExternalId == dto.ExternalId, cancellationToken);
  866. if (order == null)
  867. {
  868. order = _mapper.Map<Order>(dto);
  869. order.InitId();
  870. if (files != null && files.Any())
  871. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  872. await _orderDomainService.AddAsync(order, cancellationToken: cancellationToken);
  873. }
  874. else
  875. {
  876. _mapper.Map(dto, order);
  877. if (files != null && files.Any())
  878. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  879. await _orderRepository.UpdateAsync(order, cancellationToken);
  880. }
  881. return _mapper.Map<AddOrderResponse>(order);
  882. }
  883. /// <summary>
  884. /// 接受省平台工单
  885. /// </summary>
  886. private async Task<AddOrderResponse> ReceiveOrderFromProvinceAsync(AddOrderDto dto, List<FileDto> files,
  887. ISessionContext current, CancellationToken cancellationToken)
  888. {
  889. if (string.IsNullOrEmpty(dto.ProvinceNo))
  890. throw new UserFriendlyException("无效省工单编号");
  891. var orderExtension = await _orderDomainService.GetOrderExtensionsAsync(dto.ProvinceNo, cancellationToken);
  892. var order = await _orderRepository.GetAsync(d => d.ProvinceNo == dto.ProvinceNo, cancellationToken);
  893. if (order is null)
  894. {
  895. order = _mapper.Map<Order>(dto);
  896. order.InitId();
  897. if (files != null && files.Any())
  898. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  899. await _orderDomainService.AddAsync(order, cancellationToken: cancellationToken);
  900. if (orderExtension is not null)
  901. {
  902. orderExtension.Id = order.Id;
  903. if (dto.OrderExtension != null)
  904. _mapper.Map(dto.OrderExtension, orderExtension);
  905. await _orderDomainService.UpdateExtensionAsync(orderExtension, cancellationToken);
  906. }
  907. }
  908. else
  909. {
  910. _mapper.Map(dto, order);
  911. if (files != null && files.Any())
  912. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  913. await _orderRepository.UpdateAsync(order, cancellationToken);
  914. if (orderExtension is not null)
  915. {
  916. orderExtension.Id = order.Id;
  917. if (dto.OrderExtension != null)
  918. _mapper.Map(dto.OrderExtension, orderExtension);
  919. await _orderDomainService.UpdateExtensionAsync(orderExtension, cancellationToken);
  920. }
  921. //特提(撤回至发起)
  922. if (!string.IsNullOrEmpty(order.WorkflowId))
  923. await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, "省工单重派", current, cancellationToken);
  924. }
  925. return _mapper.Map<AddOrderResponse>(order);
  926. }
  927. #endregion
  928. }