OrderApplication.cs 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  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. return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
  195. .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
  196. .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
  197. .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
  198. .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
  199. .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
  200. .Where(d => d.ExpiredTime != null &&
  201. d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
  202. .OrderByDescending(d => d.CreationTime);
  203. }
  204. // /// <summary>
  205. // /// 即将超期节点列表
  206. // /// </summary>
  207. // /// <param name="dto"></param>
  208. // /// <param name="cancellationToken"></param>
  209. // /// <returns></returns>
  210. //public async Task<PagedDto<WorkflowOrderDto>> GetAboutToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
  211. //{
  212. // var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
  213. // var value = setting?.SettingValue[0];
  214. // value = string.IsNullOrEmpty(value) ? "0" : value;
  215. // DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
  216. // stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
  217. // DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
  218. // RefAsync<int> total = 0;
  219. // var items = await Db.Queryable<Workflow>()
  220. // .LeftJoin<Order>((x, o) => x.ExternalId == o.Id)
  221. // .Where(x => x.ModuleCode == "OrderHandle")
  222. // .WhereIF(dto.IsProvince.HasValue, (x, o) => o.IsProvince == dto.IsProvince)
  223. // .WhereIF(!string.IsNullOrEmpty(dto.Keyword), (x, o) => o.Title.Contains(dto.Keyword!) || o.No.Contains(dto.Keyword!))
  224. // .Where((x, o) => (int)x.Status < 20 && stTime >= x.ExpiredTime && stTime2 <= x.ExpiredTime)
  225. // .Select((x, o) => new WorkflowOrder { Order = o }, true)
  226. // .OrderByDescending(x => x.CreationTime)
  227. // .ToPageListAsync(dto.PageIndex, dto.PageSize, total, cancellationToken);
  228. // return new PagedDto<WorkflowOrderDto>(total, _mapper.Map<IReadOnlyList<WorkflowOrderDto>>(items));
  229. //}
  230. /// <summary>
  231. /// 已超期列表
  232. /// </summary>
  233. /// <param name="dto"></param>
  234. /// <param name="cancellationToken"></param>
  235. /// <returns></returns>
  236. public ISugarQueryable<Order> GetToExpireAsync(AboutToExpireListDto dto)
  237. {
  238. DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
  239. return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
  240. .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
  241. //.WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
  242. .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No))
  243. .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!))
  244. .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
  245. .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
  246. .Where(d => d.ExpiredTime != null &&
  247. (((d.Status == EOrderStatus.Filed || d.Status == EOrderStatus.Published || d.Status == EOrderStatus.Visited) && d.FiledTime >= d.ExpiredTime) ||
  248. ((d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited) && stTime >= d.ExpiredTime.Value)))
  249. .OrderByDescending(x => x.CreationTime);
  250. }
  251. // /// <summary>
  252. // /// 已超期节点列表
  253. // /// </summary>
  254. // /// <param name="dto"></param>
  255. // /// <param name="cancellationToken"></param>
  256. // /// <returns></returns>
  257. // public async Task<PagedDto<WorkflowOrderDto>> GetToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
  258. // {
  259. // DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
  260. //RefAsync<int> total = 0;
  261. //var items= await Db.Queryable<Workflow>()
  262. // .LeftJoin<Order>((x,o)=>x.ExternalId == o.Id)
  263. // .Where(x => x.ModuleCode == "OrderHandle")
  264. // .WhereIF(dto.IsProvince.HasValue, (x, o) => o.IsProvince == dto.IsProvince)
  265. // .WhereIF(!string.IsNullOrEmpty(dto.Keyword), (x, o) => o.Title.Contains(dto.Keyword!) || o.No.Contains(dto.Keyword!))
  266. // .Where((x,o) => (((int)x.Status >= 20 && x.EndTime >= x.ExpiredTime) || ((int)x.Status < 20 && stTime >= x.ExpiredTime)))
  267. // .Select((x, o) => new WorkflowOrder { Order = o }, true)
  268. // .OrderByDescending(x => x.CreationTime)
  269. // .ToPageListAsync(dto.PageIndex, dto.PageSize, total, cancellationToken);
  270. // return new PagedDto<WorkflowOrderDto>(total, _mapper.Map<IReadOnlyList<WorkflowOrderDto>>(items));
  271. // }
  272. /// <summary>
  273. /// 工单关键字分词
  274. /// </summary>
  275. /// <param name="inputStr"></param>
  276. /// <returns></returns>
  277. public async Task OrderParticiple(string inputStr, string orderId,DateTime time, CancellationToken cancellationToken)
  278. {
  279. var seg = new Segment();
  280. ICollection<WordInfo> splitWords = seg.DoSegment(inputStr);
  281. var words = new List<string>();
  282. for (int i = 0; i < splitWords.Count; i++)
  283. {
  284. var word = splitWords.ElementAt(i);
  285. if (word is { WordType: WordType.SimplifiedChinese, Word.Length: > 1 } )
  286. words.Add(splitWords.ElementAt(i).Word);
  287. }
  288. var vector = await _repositoryts.SearchAsync(orderId, cancellationToken);
  289. if (vector != null && vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, words, cancellationToken);
  290. else await _repositoryts.AddVectorAsync(orderId, time, words, cancellationToken);
  291. //var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("普通标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
  292. //var res = new List<string>();
  293. //if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
  294. //var participles = await _orderWrodRepository.Queryable().In(x => x.Tag, res).ToListAsync(cancellationToken);
  295. //if (participles.Any())
  296. //{
  297. // //关键词
  298. // var tags = participles.Select(x => x.Tag).ToList();
  299. // var tagsStr = string.Join(",", tags);
  300. // await _orderRepository.Updateable().SetColumns(x => x.TagNames == tagsStr).Where(x => x.Id == orderId).ExecuteCommandAsync(cancellationToken);
  301. // List<string> synonyms = participles.Select(x => x.Synonym).ToList();
  302. // if (synonyms.Any())
  303. // {
  304. // var synonymsStr = string.Join(",", synonyms);
  305. // synonyms = synonymsStr.Split(",").Distinct().ToList();
  306. // tags.AddRange(synonyms);
  307. // }
  308. // var vector = await _orderRepository.Queryable().Where(x => x.Id == orderId).ToListAsync(cancellationToken);
  309. // if (vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, tags, cancellationToken);
  310. // else await _repositoryts.AddVectorAsync(orderId, DateTime.Now, tags, cancellationToken);
  311. //}
  312. }
  313. public async Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken)
  314. {
  315. var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("敏感标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
  316. var res = new List<string>();
  317. if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
  318. if (res.Any())
  319. {
  320. var intersect = words.Intersect(res).ToList();
  321. await _orderRepository.Updateable().SetColumns(o => new Order() { Sensitive = intersect }).Where(o => o.Id == orderId).ExecuteCommandAsync(cancellationToken);
  322. }
  323. }
  324. /// <summary>
  325. /// 接收外部平台工单
  326. /// </summary>
  327. public Task<AddOrderResponse> ReceiveOrderFromExternalAsync(AddOrderDto dto, ISessionContext current, CancellationToken cancellationToken)
  328. {
  329. switch (dto.Source)
  330. {
  331. case ESource.ProvinceStraight:
  332. return ReceiveOrderFromProvinceAsync(dto, dto.Files, current, cancellationToken);
  333. case ESource.Police110:
  334. case ESource.CityDataExchangeLz:
  335. case ESource.CityDataExchangeYB:
  336. case ESource.CityDataExchangeZG:
  337. case ESource.CityDataExchangeNJ:
  338. case ESource.WebPortal:
  339. case ESource.ConvergenceMedia:
  340. case ESource.IYIBIN:
  341. case ESource.ZHYB:
  342. case ESource.ZZPT:
  343. case ESource.WLLZ:
  344. return ReceiveOrderFromOtherPlatformAsync(dto, dto.Files, current, cancellationToken);
  345. case ESource.Hotline:
  346. case ESource.HotlineImport:
  347. default:
  348. throw new ArgumentOutOfRangeException();
  349. }
  350. }
  351. /// <summary>
  352. /// 接收外部平台修改工单附件
  353. /// </summary>
  354. public async Task UpdateOrderFilesAnonymousAsync(UpdateOrderFilesDto dto, CancellationToken cancellationToken)
  355. {
  356. if (string.IsNullOrEmpty(dto.Id) && string.IsNullOrEmpty(dto.OrderNo))
  357. throw new UserFriendlyException("工单外部编号不能为空");
  358. var order = await _orderRepository.Queryable()
  359. .FirstAsync(d => d.Id == dto.Id || d.No == dto.OrderNo, cancellationToken);
  360. if (order != null && dto.Files != null && dto.Files.Any())
  361. {
  362. order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", cancellationToken);
  363. await _orderRepository.UpdateAsync(order, cancellationToken);
  364. }
  365. }
  366. /// <summary>
  367. /// 工单回访
  368. /// </summary>
  369. /// <param name="dto"></param>
  370. /// <param name="cancellationToken"></param>
  371. /// <returns></returns>
  372. public async Task OrderVisitWeb(OrderVisitWebDto dto, CancellationToken cancellationToken)
  373. {
  374. var visit = await _orderVisitRepository.Queryable()
  375. .Includes(x => x.Order)
  376. .Includes(x => x.OrderVisitDetails)
  377. .FirstAsync(x => x.Id == dto.Id);
  378. if (visit != null)
  379. {
  380. var first = dto.OrderVisitDetailDto.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);
  381. if (first != null)
  382. {
  383. visit.NowEvaluate = first.OrgProcessingResults;
  384. visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
  385. }
  386. visit.VisitState = EVisitState.Visited;
  387. visit.VisitTime = dto.VisitTime;
  388. visit.VisitType = dto.VisitType;
  389. for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
  390. {
  391. var detail = visit.OrderVisitDetails[i];
  392. var detaildto = dto.OrderVisitDetailDto.FirstOrDefault(x => x.Id == detail.Id);
  393. if (detaildto != null)
  394. {
  395. _mapper.Map(detaildto, visit.OrderVisitDetails[i]);
  396. }
  397. }
  398. await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
  399. await _orderVisitDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, cancellationToken);
  400. await _orderRepository.UpdateAsync(visit.Order, cancellationToken);
  401. var orderDto = _mapper.Map<OrderDto>(visit.Order);
  402. if (first != null)
  403. {
  404. //推省上
  405. await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
  406. new PublishVisitDto()
  407. {
  408. Order = orderDto,
  409. No = visit.No,
  410. VisitType = visit.VisitType,
  411. VisitName = visit.CreatorName,
  412. VisitTime = visit.VisitTime,
  413. VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
  414. AreaCode = visit.Order.AreaCode!,
  415. SubjectResultSatifyCode = first.OrgProcessingResults.Key,
  416. FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
  417. ClientGuid = ""
  418. }, cancellationToken: cancellationToken);
  419. }
  420. //写入质检
  421. await _qualityApplication.AddQualityAsync(EQualitySource.Visit, orderDto.Id, visit.Id,
  422. cancellationToken);
  423. }
  424. }
  425. public ISugarQueryable<Order> QueryOrders(QueryOrderDto dto)
  426. {
  427. var isCenter = _sessionContext.OrgIsCenter;
  428. return _orderRepository.Queryable(canView: !isCenter)
  429. .Includes(x => x.OrderScreens)
  430. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!)) //标题
  431. .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo == dto.ProvinceNo) //省本地编号
  432. .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) //工单编码
  433. //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
  434. .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
  435. .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
  436. .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
  437. .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone == dto.TransferPhone!) //转接号码
  438. //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
  439. .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
  440. .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
  441. .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
  442. .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
  443. .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel)) //紧急程度
  444. .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
  445. .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo!) //联系电话
  446. .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
  447. .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
  448. .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
  449. .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status)) //工单状态
  450. .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
  451. .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName == dto.ActualHandlerName) //接办人
  452. .WhereIF(dto.IsScreen == true, d => d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //有甄别
  453. .WhereIF(dto.IsScreen == false, d => !d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //无甄别
  454. .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.ActualHandleStepCode == dto.CurrentStepCode) //当前办理节点
  455. .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
  456. .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
  457. .WhereIF(dto.IsOverTime == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
  458. .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
  459. .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
  460. .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
  461. .WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
  462. .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.IsProvince == true)
  463. .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.IsProvince == false)
  464. .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), d => SqlFunc.JsonArrayAny(d.Sensitive, dto.SensitiveWord))
  465. .WhereIF(dto.IsSensitiveWord.HasValue && dto.IsSensitiveWord == true, d => d.Sensitive != null && SqlFunc.JsonArrayLength(d.Sensitive) > 0)
  466. .WhereIF(dto.IsUrgent.HasValue , d=>d.IsUrgent == dto.IsUrgent.Value)
  467. .OrderByDescending(d => d.CreationTime);
  468. }
  469. /// <summary>
  470. /// 未签收统计
  471. /// </summary>
  472. /// <param name="dto"></param>
  473. /// <returns></returns>
  474. public ISugarQueryable<Order, WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto)
  475. {
  476. if (dto.EndTime.HasValue)
  477. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  478. var IsCenter = _sessionContext.OrgIsCenter;
  479. return _orderRepository.Queryable()
  480. .LeftJoin<WorkflowStep>((x, ws) => x.Id == ws.ExternalId)
  481. .WhereIF(dto.StartTime.HasValue, (x, ws) => ws.CreationTime >= dto.StartTime)
  482. .WhereIF(dto.EndTime.HasValue, (x, ws) => ws.CreationTime <= dto.EndTime)
  483. .WhereIF(dto.Level == 0 && IsCenter == false, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
  484. .WhereIF(dto.Level == 1, (x, ws) => ws.AcceptorOrgId == _sessionContext.OrgId)
  485. .WhereIF(dto.Level == 2, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
  486. .WhereIF(dto.Signed == 0, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
  487. .WhereIF(dto.Signed == 1, (x, ws) => ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForHandle)
  488. .Where((x, ws) => ws.CountersignPosition == Share.Enums.FlowEngine.ECountersignPosition.None && x.Status > EOrderStatus.WaitForAccept)
  489. .OrderByDescending((x, ws) => ws.CreationTime);
  490. }
  491. /// <summary>
  492. /// 信件来源统计
  493. /// </summary>
  494. /// <param name="dto"></param>
  495. /// <returns></returns>
  496. public ISugarQueryable<Order> QueryOrderSource(QueryOrderSourceRequest dto)
  497. {
  498. if (dto.EndTime.HasValue)
  499. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  500. return _orderRepository.Queryable()
  501. .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
  502. .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
  503. .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
  504. .Where(d => d.SourceChannel != null && d.SourceChannel != "");
  505. }
  506. /// <summary>
  507. /// 信件来源统计明细
  508. /// </summary>
  509. /// <param name="dto"></param>
  510. /// <returns></returns>
  511. public ISugarQueryable<Order> QueryOrderSourceDetail(QueryOrderSourceDetailRequest dto)
  512. {
  513. return _orderRepository.Queryable()
  514. .WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), d => d.SourceChannel == dto.SourceChannel)
  515. .WhereIF(dto.Time.HasValue, d => d.CreationTime.ToString("yyyy-MM-dd") == dto.Time.Value.ToString("yyyy-MM-dd"))
  516. .WhereIF(dto.IdentityType.HasValue, d => d.IdentityType == dto.IdentityType)
  517. .Where(d => d.SourceChannel != null && d.SourceChannel != "");
  518. }
  519. /// <summary>
  520. /// 部门超期统计
  521. /// </summary>
  522. /// <param name="dto"></param>
  523. /// <returns></returns>
  524. public ISugarQueryable<OrderBiOrgDataListVo> QueryOrgDataList(ReportPagedRequest dto)
  525. {
  526. if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
  527. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  528. var IsCenter = _sessionContext.OrgIsCenter;
  529. var queryOrder = _systemOrganizeRepository.Queryable()
  530. .LeftJoin<Order>((x, o) => x.Id == o.ActualHandleOrgCode)
  531. .WhereIF(dto.StartTime.HasValue, (x, o) => o.CreationTime >= dto.StartTime)
  532. .WhereIF(dto.EndTime.HasValue, (x, o) => o.CreationTime <= dto.EndTime)
  533. .WhereIF(IsCenter == false, (x, o) => o.ActualHandleOrgCode == _sessionContext.RequiredOrgId)
  534. .GroupBy((x, o) => new { x.Id, x.Name })
  535. .Select((x, o) => new OrderBiOrgDataListVo
  536. {
  537. OrgName = x.Name,
  538. OrgId = x.Id,
  539. HandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.Status >= EOrderStatus.Filed && o.ExpiredTime < o.FiledTime, 1, 0)),
  540. NoHandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.Status < EOrderStatus.Filed && o.ExpiredTime < SqlFunc.GetDate(), 1, 0)),
  541. }).MergeTable();
  542. var queryCountersign = _workflowCountersignRepository.Queryable()
  543. .LeftJoin<WorkflowCountersignMember>((x, o) => x.Id == o.WorkflowCountersignId)
  544. .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
  545. .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
  546. .GroupBy((x, o) => o.Key)
  547. .Select((x, o) => new OrderBiOrgDataListVo
  548. {
  549. OrgId = o.Key,
  550. CounterHandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsHandled && x.IsExpired.HasValue && x.IsExpired.Value == true, 1, 0)),
  551. CounterNoHandlerExtendedNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.IsHandled == false && x.IsExpired.HasValue && x.IsExpired.Value == true, 1, 0)),
  552. }).MergeTable();
  553. var query = queryOrder.LeftJoin(queryCountersign, (or, co) => or.OrgId == co.OrgId)
  554. .LeftJoin<SystemOrganize>((or, co, so) => or.OrgId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == so.Id)
  555. .GroupBy((or, co, so) => new { so.Id, so.Name })
  556. .Select((or, co, so) => new OrderBiOrgDataListVo
  557. {
  558. OrgName = so.Name,
  559. OrgId = so.Id,
  560. HandlerExtendedNum = SqlFunc.AggregateSum(or.HandlerExtendedNum),
  561. NoHandlerExtendedNum = SqlFunc.AggregateSum(or.NoHandlerExtendedNum),
  562. CounterHandlerExtendedNum = SqlFunc.AggregateSum(co.CounterHandlerExtendedNum),
  563. CounterNoHandlerExtendedNum = SqlFunc.AggregateSum(co.CounterNoHandlerExtendedNum)
  564. }).MergeTable();
  565. 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);
  566. switch (dto.SortField)
  567. {
  568. case "handlerExtendedNum":
  569. query = dto.SortRule is 0 ? query.OrderBy(x => x.HandlerExtendedNum) : query.OrderByDescending(x => x.HandlerExtendedNum);
  570. break;
  571. case "counterHandlerExtendedNum":
  572. query = dto.SortRule is 0 ? query.OrderBy(x => x.CounterHandlerExtendedNum) : query.OrderByDescending(x => x.CounterHandlerExtendedNum);
  573. break;
  574. case "noHandlerExtendedNum":
  575. query = dto.SortRule is 0 ? query.OrderBy(x => x.NoHandlerExtendedNum) : query.OrderByDescending(x => x.NoHandlerExtendedNum);
  576. break;
  577. case "counterNoHandlerExtendedNum":
  578. query = dto.SortRule is 0 ? query.OrderBy(x => x.CounterNoHandlerExtendedNum) : query.OrderByDescending(x => x.CounterNoHandlerExtendedNum);
  579. break;
  580. }
  581. return query;
  582. }
  583. /// <summary>
  584. /// 部门超期统计明细
  585. /// </summary>
  586. /// <param name="dto"></param>
  587. /// <returns></returns>
  588. public ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListDetailRequest dto)
  589. {
  590. dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
  591. var quer = _orderRepository.Queryable()
  592. .InnerJoin<SystemOrganize>((x, so) => x.ActualHandleOrgCode == so.Id)
  593. .Where(x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
  594. .WhereIF(dto.QueryType == 1, x => x.Status >= EOrderStatus.Filed && x.ExpiredTime < x.FiledTime) //业务已办超期
  595. .WhereIF(dto.QueryType == 3, x => x.Status < EOrderStatus.Filed && x.ExpiredTime < SqlFunc.GetDate()) //业务待办超期
  596. .WhereIF(dto.QueryType == 5, x =>
  597. (x.Status >= EOrderStatus.Filed && x.ExpiredTime < x.FiledTime) || (x.Status < EOrderStatus.Filed && x.ExpiredTime < SqlFunc.GetDate()))
  598. .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.QueryType is 1 or 3 && dto.OrgCode == "001", x => x.ActualHandleOrgCode == dto.OrgCode)
  599. .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.QueryType is 1 or 3 && dto.OrgCode != "001", x => x.ActualHandleOrgCode.StartsWith(dto.OrgCode))
  600. .MergeTable();
  601. if (dto.QueryType is 2 or 4 or 5)
  602. {
  603. var queryCountersign = _workflowCountersignRepository.Queryable()
  604. .LeftJoin<WorkflowCountersignMember>((x, o) => x.Id == o.WorkflowCountersignId)
  605. .Where((x, o) => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime && x.IsExpired.HasValue && x.IsExpired.Value == true)
  606. .WhereIF(dto.QueryType == 2, (x, o) => o.IsHandled == true) //会签已办超期
  607. .WhereIF(dto.QueryType == 4, (x, o) => o.IsHandled == false) //会签待办超期
  608. .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.QueryType is 2 or 4 or 5, (x, o) => o.Key.StartsWith(dto.OrgCode))
  609. //.GroupBy((x,o)=>x.WorkflowId)
  610. .Select((x, o) => new { Id = x.WorkflowId })
  611. .MergeTable();
  612. quer = quer.InnerJoin(queryCountersign, (x, c) => x.WorkflowId == c.Id);
  613. }
  614. return quer;
  615. }
  616. /// <summary>
  617. /// 回退错件统计
  618. /// </summary>
  619. /// <param name="dto"></param>
  620. /// <returns></returns>
  621. public ISugarQueryable<OrderReTransactVo> OrderReTransact(QueryOrderReTransactRequest dto)
  622. {
  623. return _orderSpecialDetailRepository.Queryable()
  624. .Includes(x => x.OrderSpecial)
  625. .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName!))
  626. .Where(x => x.OrderSpecial.ESpecialType == ESpecialType.ReTransact)
  627. .Where(x => x.OrderSpecial.CreationTime >= dto.StartTime)
  628. .Where(x => x.OrderSpecial.CreationTime <= dto.EndTime)
  629. .GroupBy(x => new { Time = x.OrderSpecial.CreationTime.ToString("yyyy-MM-dd"), x.OrgId, x.OrgName })
  630. .Select(x => new OrderReTransactVo
  631. {
  632. Time = x.OrderSpecial.CreationTime.ToString("yyyy-MM-dd"),
  633. OrgId = x.OrgId,
  634. OrgName = x.OrgName,
  635. Num = SqlFunc.AggregateCount(1)
  636. }).MergeTable()
  637. .OrderByIF(dto.SortRule is 0, x => x.Num, OrderByType.Asc)
  638. .OrderByIF(dto.SortRule is 1, x => x.Num, OrderByType.Desc); ;
  639. }
  640. /// <summary>
  641. /// 回退错件明细统计
  642. /// </summary>
  643. /// <param name="dto"></param>
  644. /// <returns></returns>
  645. public ISugarQueryable<OrderSpecialDetail> QueryOrderSourceDetail(QueryOrderReTransactDetailRequest dto)
  646. {
  647. return _orderSpecialDetailRepository.Queryable()
  648. .Includes(x => x.OrderSpecial, s => s.Order)
  649. .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName!))
  650. .WhereIF(!string.IsNullOrEmpty(dto.ErrorName), x => x.ErrorName.Contains(dto.ErrorName!))
  651. .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderSpecial!.Order!.No!.Contains(dto.No!))
  652. .Where(x => x.OrderSpecial.ESpecialType == ESpecialType.ReTransact)
  653. .Where(x => x.OrderSpecial.CreationTime >= dto.StartTime)
  654. .Where(x => x.OrderSpecial.CreationTime <= dto.EndTime);
  655. }
  656. /// <summary>
  657. /// 部门满意度统计
  658. /// </summary>
  659. /// <returns></returns>
  660. public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgSatisfactionStatistics(PagedKeywordSonRequest dto) {
  661. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  662. bool IsCenter = _sessionContext.OrgIsCenter;
  663. var list = _orderVisitDetailRepository.Queryable()
  664. .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))
  665. .WhereIF(string.IsNullOrEmpty(dto.OrgName) == false, x => x.VisitOrgName.Contains(dto.OrgName))
  666. .WhereIF(string.IsNullOrEmpty(dto.LineNum) == false, x => x.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
  667. .WhereIF(IsCenter == false, x => x.VisitOrgCode.StartsWith(_sessionContext.OrgId));
  668. var data = new List<VisitAndOrgSatisfactionStatisticsDto>();
  669. if (IsCenter && list != null)
  670. {
  671. data = await list.GroupBy(x => new
  672. {
  673. VisitOrgCode = x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))
  674. })
  675. .Select(x => new VisitAndOrgSatisfactionStatisticsDto()
  676. {
  677. OrgCode = x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
  678. TotalSumCount = SqlFunc.AggregateCount(x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
  679. 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))),//非常满意数
  680. 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))), //满意数
  681. 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))),//视为满意
  682. 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))),//默认满意
  683. 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))),//不满意
  684. 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))),//未做评价
  685. 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))),//未接通
  686. })
  687. .MergeTable()
  688. .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
  689. .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
  690. {
  691. OrgName = o.Name,
  692. OrgCode = it.OrgCode,
  693. OrgType = o.OrgType,
  694. TotalSumCount = it.TotalSumCount,
  695. VerySatisfiedCount = it.VerySatisfiedCount,//非常满意数
  696. SatisfiedCount = it.SatisfiedCount, //满意数
  697. RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount,//视为满意
  698. DefaultSatisfiedCount = it.DefaultSatisfiedCount,//默认满意
  699. NoSatisfiedCount = it.NoSatisfiedCount,//不满意
  700. NoEvaluateCount = it.NoEvaluateCount,//未做评价
  701. NoPutThroughCount = it.NoPutThroughCount,//未接通
  702. })
  703. .ToListAsync();
  704. }
  705. else
  706. {
  707. data = await list.GroupBy(x => new
  708. {
  709. x.VisitOrgCode
  710. })
  711. .Select(x => new VisitAndOrgSatisfactionStatisticsDto()
  712. {
  713. OrgCode = x.VisitOrgCode,
  714. TotalSumCount = SqlFunc.AggregateCount(x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))),
  715. 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))),//非常满意数
  716. 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))), //满意数
  717. 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))),//视为满意
  718. 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))),//默认满意
  719. 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))),//不满意
  720. 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))),//未做评价
  721. 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))),//未接通
  722. })
  723. .MergeTable()
  724. .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
  725. .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
  726. {
  727. OrgName = o.Name,
  728. OrgCode = it.OrgCode,
  729. OrgType = o.OrgType,
  730. TotalSumCount = it.TotalSumCount,
  731. VerySatisfiedCount = it.VerySatisfiedCount,//非常满意数
  732. SatisfiedCount = it.SatisfiedCount, //满意数
  733. RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount,//视为满意
  734. DefaultSatisfiedCount = it.DefaultSatisfiedCount,//默认满意
  735. NoSatisfiedCount = it.NoSatisfiedCount,//不满意
  736. NoEvaluateCount = it.NoEvaluateCount,//未做评价
  737. NoPutThroughCount = it.NoPutThroughCount,//未接通
  738. })
  739. .ToListAsync();
  740. }
  741. return data;
  742. }
  743. /// <summary>
  744. /// 子部门满意度
  745. /// </summary>
  746. /// <returns></returns>
  747. public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgStatisfactionOrgDetail(PagedKeywordSonRequest dto)
  748. {
  749. dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
  750. bool IsCenter = _sessionContext.OrgIsCenter;
  751. var list = await _systemOrganizeRepository.Queryable().Where(x => x.Id.StartsWith(dto.OrgCode))
  752. .LeftJoin<OrderVisitDetail>((x, it) => x.Id == it.VisitOrgCode)
  753. .Where((x, it) => it.OrderVisit.VisitTime >= dto.StartTime.Value && it.OrderVisit.VisitTime <= dto.EndTime.Value && it.VisitTarget == EVisitTarget.Org && it.OrderVisit.VisitState == EVisitState.Visited)
  754. .WhereIF(dto.OrgCode == "001", (x, it) => it.VisitOrgCode == dto.OrgCode)
  755. .WhereIF(dto.OrgCode != "001", (x, it) => it.VisitOrgCode.StartsWith(dto.OrgCode))
  756. .WhereIF(!string.IsNullOrEmpty(dto.LineNum), (x, it) => it.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
  757. .WhereIF(IsCenter == false, (x, it) => it.VisitOrgCode.StartsWith(_sessionContext.OrgId))
  758. .GroupBy((x, it) => new
  759. {
  760. VisitOrgCode = it.VisitOrgCode
  761. })
  762. .Select((x, it) => new VisitAndOrgSatisfactionStatisticsDto()
  763. {
  764. OrgCode = it.VisitOrgCode,
  765. TotalSumCount = SqlFunc.AggregateCount(it.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("9"))),
  766. 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))),//非常满意数
  767. 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))), //满意数
  768. 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))),//视为满意
  769. 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))),//默认满意
  770. 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))),//不满意
  771. 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))),//未做评价
  772. 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)))//未接通
  773. })
  774. .MergeTable()
  775. .LeftJoin<SystemOrganize>((x, it) => x.OrgCode == it.Id)
  776. .Select((x, it) => new VisitAndOrgSatisfactionStatisticsDto()
  777. {
  778. OrgName = it.Name,
  779. OrgCode = x.OrgCode,
  780. OrgType = it.OrgType,
  781. TotalSumCount = x.TotalSumCount,
  782. VerySatisfiedCount = x.VerySatisfiedCount,//非常满意数
  783. SatisfiedCount = x.SatisfiedCount, //满意数
  784. RegardedAsSatisfiedCount = x.RegardedAsSatisfiedCount,//视为满意
  785. DefaultSatisfiedCount = x.DefaultSatisfiedCount,//默认满意
  786. NoSatisfiedCount = x.NoSatisfiedCount,//不满意
  787. NoEvaluateCount = x.NoEvaluateCount,//未做评价
  788. NoPutThroughCount = x.NoPutThroughCount,//未接通
  789. })
  790. .ToListAsync();
  791. return list;
  792. }
  793. /// <summary>
  794. /// 部门满意度明细统计
  795. /// </summary>
  796. /// <param name="dto"></param>
  797. /// <returns></returns>
  798. public ISugarQueryable<OrderVisitDetail> VisitAndOrgSatisfactionDetail(VisitAndOrgSatisfactionDetailDto dto)
  799. {
  800. dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
  801. bool IsCenter = _sessionContext.OrgIsCenter;
  802. return _orderVisitDetailRepository.Queryable()
  803. .Includes(x => x.OrderVisit, o => o.Order, d => d.CallRecord)
  804. .Where(x => x.OrderVisit.VisitTime >= dto.StartTime && x.OrderVisit.VisitTime <= dto.EndTime && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited)
  805. .WhereIF(dto.OrgCode == "001", x => x.VisitOrgCode == dto.OrgCode)
  806. //.WhereIF(dto.OrgCode != "001", x => x.VisitOrgCode == dto.OrgCode).
  807. .WhereIF(dto.IsOnlyMy == true, x => x.VisitOrgCode == dto.OrgCode)
  808. .WhereIF(IsCenter == true && dto.IsOnlyMy == true, x => x.VisitOrgCode == dto.OrgCode)
  809. .WhereIF(IsCenter == true && dto.IsOnlyMy == null, x => x.VisitOrgCode.StartsWith(dto.OrgCode))
  810. .WhereIF(IsCenter == false, x => x.VisitOrgCode == dto.OrgCode)
  811. .WhereIF(dto.TypeId is 1, x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == dto.DateValue)
  812. .WhereIF(dto.TypeId is 2, x => SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == dto.DateValue)
  813. .WhereIF(!string.IsNullOrEmpty(dto.LineNum), x => x.OrderVisit.Order.CallRecord.Gateway == dto.LineNum);
  814. }
  815. #region private
  816. /// <summary>
  817. /// 接受外部工单(除省平台)
  818. /// </summary>
  819. /// <param name="dto"></param>
  820. /// <param name="cancellationToken"></param>
  821. /// <returns></returns>
  822. private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
  823. ISessionContext current, CancellationToken cancellationToken)
  824. {
  825. if (string.IsNullOrEmpty(dto.ExternalId))
  826. throw new UserFriendlyException("工单外部编号不能为空");
  827. var order = await _orderRepository.Queryable()
  828. .FirstAsync(d => d.ExternalId == dto.ExternalId, cancellationToken);
  829. if (order == null)
  830. {
  831. order = _mapper.Map<Order>(dto);
  832. order.InitId();
  833. if (files != null && files.Any())
  834. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  835. await _orderDomainService.AddAsync(order, cancellationToken: cancellationToken);
  836. }
  837. else
  838. {
  839. _mapper.Map(dto, order);
  840. if (files != null && files.Any())
  841. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  842. await _orderRepository.UpdateAsync(order, cancellationToken);
  843. }
  844. return _mapper.Map<AddOrderResponse>(order);
  845. }
  846. /// <summary>
  847. /// 接受省平台工单
  848. /// </summary>
  849. private async Task<AddOrderResponse> ReceiveOrderFromProvinceAsync(AddOrderDto dto, List<FileDto> files,
  850. ISessionContext current, CancellationToken cancellationToken)
  851. {
  852. if (string.IsNullOrEmpty(dto.ProvinceNo))
  853. throw new UserFriendlyException("无效省工单编号");
  854. var orderExtension = await _orderDomainService.GetOrderExtensionsAsync(dto.ProvinceNo, cancellationToken);
  855. var order = await _orderRepository.GetAsync(d => d.ProvinceNo == dto.ProvinceNo, cancellationToken);
  856. if (order is null)
  857. {
  858. order = _mapper.Map<Order>(dto);
  859. order.InitId();
  860. if (files != null && files.Any())
  861. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  862. await _orderDomainService.AddAsync(order, cancellationToken: cancellationToken);
  863. if (orderExtension is not null)
  864. {
  865. orderExtension.Id = order.Id;
  866. if (dto.OrderExtension != null)
  867. _mapper.Map(dto.OrderExtension, orderExtension);
  868. await _orderDomainService.UpdateExtensionAsync(orderExtension, cancellationToken);
  869. }
  870. }
  871. else
  872. {
  873. _mapper.Map(dto, order);
  874. if (files != null && files.Any())
  875. order.FileJson = await _fileRepository.AddFileAsync(files, order.Id, "", cancellationToken);
  876. await _orderRepository.UpdateAsync(order, cancellationToken);
  877. if (orderExtension is not null)
  878. {
  879. orderExtension.Id = order.Id;
  880. if (dto.OrderExtension != null)
  881. _mapper.Map(dto.OrderExtension, orderExtension);
  882. await _orderDomainService.UpdateExtensionAsync(orderExtension, cancellationToken);
  883. }
  884. //特提(撤回至发起)
  885. if (!string.IsNullOrEmpty(order.WorkflowId))
  886. await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, "省工单重派", current, cancellationToken);
  887. }
  888. return _mapper.Map<AddOrderResponse>(order);
  889. }
  890. #endregion
  891. }