SnapshotApplicationBase.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. using Hotline.Orders;
  2. using Hotline.Share.Dtos;
  3. using Hotline.Share.Dtos.Article;
  4. using Hotline.Share.Dtos.Snapshot;
  5. using Hotline.Share.Tools;
  6. using Hotline.Snapshot;
  7. using Hotline.Users;
  8. using SqlSugar;
  9. using XF.Domain.Authentications;
  10. using XF.Domain.Dependency;
  11. using XF.Domain.Repository;
  12. using Hotline.Repository.SqlSugar.Extensions;
  13. using Hotline.Share.Enums;
  14. using Hotline.Share.Enums.Order;
  15. using Hotline.Share.Requests;
  16. using Hotline.Share.Enums.Snapshot;
  17. using Mapster;
  18. using Hotline.Caching.Interfaces;
  19. using NPOI.Util.ArrayExtensions;
  20. using XF.Domain.Exceptions;
  21. using Hotline.Settings;
  22. using Hotline.Share.Dtos.Settings;
  23. using Hotline.File;
  24. using Hotline.Share.Enums.Article;
  25. using Hotline.Tools;
  26. using Hotline.Snapshot.Interfaces;
  27. using DotNetCore.CAP;
  28. using Microsoft.AspNetCore.Http;
  29. using Hotline.Share.Dtos.FlowEngine;
  30. using Hotline.FlowEngine.Workflows;
  31. using Hotline.Share.Enums.FlowEngine;
  32. using Hotline.Share.Dtos.Order;
  33. using Hotline.Share.Mq;
  34. using Hotline.Snapshot.Notifications;
  35. using Hotline.EventBus;
  36. using Hotline.Quality.Notifications;
  37. using Hotline.Settings.SystemLogDomain;
  38. using XF.Utility.EnumExtensions;
  39. namespace Hotline.Application.Snapshot;
  40. /// <summary>
  41. /// 随手拍应用层
  42. /// </summary>
  43. public abstract class SnapshotApplicationBase
  44. {
  45. private readonly IThirdAccountRepository _thirdAccountRepository;
  46. private readonly IRepository<Order> _orderRepository;
  47. private readonly ISnapshotBulletinRepository _bulletinRepository;
  48. /// <summary>
  49. /// 行业
  50. /// </summary>
  51. private readonly IIndustryRepository _industryRepository;
  52. private readonly IThirdIdentiyService _thirdLoginService;
  53. private readonly ISessionContext _sessionContext;
  54. private readonly IRepository<RedPackRecord> _redPackRecordRepository;
  55. private readonly IOrderSnapshotRepository _orderSnapshotRepository;
  56. private readonly ISystemSettingCacheManager _sysSetting;
  57. private readonly ISystemAreaDomainService _systemAreaDomainService;
  58. private readonly IRepository<SystemArea> _systemAreaRepository;
  59. private readonly IFileRepository _fileRepository;
  60. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  61. private readonly ISnapshotOrderPublishRepository _snapshotOrderPublishRepository;
  62. private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
  63. private readonly IPractitionerRepository _practitionerRepository;
  64. private readonly IVolunteerRepository _volunteerRepository;
  65. private readonly IVolunteerReportRepository _volunteerReportRepository;
  66. private readonly ISystemLogRepository _systemLog;
  67. private readonly IGuiderSystemService _guiderSystemService;
  68. private readonly ICapPublisher _capPublisher;
  69. private readonly Publisher _publisher;
  70. private readonly IGuiderInfoRepository _guiderInfoRepository;
  71. private readonly IFileDomainService _fileDomainService;
  72. private readonly ICommunityInfoRepository _communityInfoRepository;
  73. private readonly IRedPackAuditRepository _redPackAuditRepository;
  74. private readonly IRedPackGuiderAuditRepository _redPackGuiderAuditRepository;
  75. private readonly IOrderVisitRepository _orderVisitRepository;
  76. private readonly IOrderVisitDetailRepository _orderVisitDetailRepository;
  77. public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IIndustryRepository industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository, IRedPackGuiderAuditRepository redPackGuiderAuditRepository)
  78. {
  79. _thirdLoginService = thirdLoginService;
  80. _industryRepository = industryRepository;
  81. _bulletinRepository = bulletinRepository;
  82. _sessionContext = sessionContext;
  83. _redPackRecordRepository = redPackRecordRepository;
  84. _orderRepository = orderRepository;
  85. _thirdAccountRepository = thirdAccountRepository;
  86. _orderSnapshotRepository = orderSnapshotRepository;
  87. _sysSetting = systemSettingCacheManager;
  88. _systemAreaDomainService = systemAreaDomainService;
  89. _fileRepository = fileRepository;
  90. _systemDicDataCacheManager = systemDicDataCacheManager;
  91. _snapshotOrderPublishRepository = snapshotOrderPublishRepository;
  92. _workflowTraceRepository = workflowTraceRepository;
  93. _practitionerRepository = practitionerRepository;
  94. _systemAreaRepository = systemAreaRepository;
  95. _volunteerRepository = volunteerRepository;
  96. _volunteerReportRepository = volunteerReportRepository;
  97. _systemLog = systemLog;
  98. _guiderSystemService = guiderSystemService;
  99. _capPublisher = capPublisher;
  100. _publisher = publisher;
  101. _guiderInfoRepository = guiderInfoRepository;
  102. _fileDomainService = fileDomainService;
  103. _communityInfoRepository = communityInfoRepository;
  104. _redPackAuditRepository = redPackAuditRepository;
  105. _orderVisitRepository = orderVisitRepository;
  106. _orderVisitDetailRepository = orderVisitDetailRepository;
  107. _redPackGuiderAuditRepository = redPackGuiderAuditRepository;
  108. }
  109. #region 小程序
  110. /// <summary>
  111. /// 获取随手拍小程序首页数据
  112. /// </summary>
  113. /// <returns></returns>
  114. public async Task<HomePageOutDto> GetHomePageAsync()
  115. {
  116. var fileServiceUrl = _sysSetting.FileServerUrl;
  117. var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
  118. var items = await _industryRepository.Queryable()
  119. .Where(m => m.IsEnable)
  120. .OrderBy(m => m.DisplayOrder)
  121. .ToListAsync(m => new HomeIndustryOutDto());
  122. items.ForEach(m =>
  123. {
  124. if (m.BackgroundImgUrl.NotNullOrEmpty())
  125. m.BackgroundImgUrl = fileDownloadApi + m.BackgroundImgUrl;
  126. if (m.BannerImgUrl.NotNullOrEmpty())
  127. m.BannerImgUrl = fileDownloadApi + m.BannerImgUrl;
  128. if (m.CareCellImgUrl.NotNullOrEmpty())
  129. m.CareCellImgUrl = fileDownloadApi + m.CareCellImgUrl;
  130. if (m.CellImgUrl.NotNullOrEmpty())
  131. m.CellImgUrl = fileDownloadApi + m.CellImgUrl;
  132. });
  133. return new HomePageOutDto
  134. {
  135. Banners = _sysSetting.AppBanner.Split('|').Select(m => fileDownloadApi + m).ToList(),
  136. Industrys = items
  137. };
  138. }
  139. /// <summary>
  140. /// 获取小程序首页弹窗
  141. /// </summary>
  142. public async Task<BulletinOutDto> GetBulletionPopupAsync(CancellationToken requestAborted)
  143. {
  144. var item = await _bulletinRepository.Queryable()
  145. .Where(m => m.BulletinState == EBulletinState.ReviewPass)
  146. .Where(m => m.BulletinTime >= DateTime.Now && m.IsPopup == true)
  147. .OrderByDescending(m => m.CreationTime)
  148. .Select<BulletinOutDto>()
  149. .FirstAsync(requestAborted);
  150. return item;
  151. }
  152. /// <summary>
  153. /// 获取行业集合
  154. /// </summary>
  155. /// <returns></returns>
  156. public async Task<IList<IndustryOutDto>> GetIndustresAsync()
  157. {
  158. var fileServiceUrl = _sysSetting.FileServerUrl;
  159. var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
  160. var items = await _industryRepository.Queryable()
  161. .Where(m => m.IsEnable)
  162. .OrderBy(m => m.DisplayOrder)
  163. .ToListAsync(m => new IndustryOutDto());
  164. return items;
  165. }
  166. /// <summary>
  167. /// 行业页面基础数据
  168. /// </summary>
  169. /// <param name="id"></param>
  170. /// <param name="requestAborted"></param>
  171. /// <returns></returns>
  172. public async Task<IndustryBaseOutDto> GetIndustryBaseAsync(string id, CancellationToken requestAborted)
  173. {
  174. var fileServiceUrl = _sysSetting.FileServerUrl;
  175. var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
  176. var indurstry = await _industryRepository.GetAsync(id, requestAborted)
  177. ?? throw UserFriendlyException.SameMessage("行业不存在:" + id);
  178. var bulletinId = await _bulletinRepository.Queryable()
  179. .Where(m => m.SnapshotBulletinTypeId == indurstry.BulletinTypeGuideId && m.BulletinState == EBulletinState.ReviewPass)
  180. .OrderByDescending(m => m.CreationTime)
  181. .Select(m => m.Id)
  182. .FirstAsync(requestAborted);
  183. var outDto = new IndustryBaseOutDto
  184. {
  185. Industry = indurstry.Adapt<IndustryOutDto>()
  186. };
  187. outDto.BulletinId = bulletinId;
  188. if (indurstry.IndustryType == EIndustryType.Declare)
  189. {
  190. outDto.AreaTree = (await _systemAreaDomainService.GetAreaTree(parentId: "510300")).Adapt<List<SystemAreaOutDto>>();
  191. outDto.Files = (await _fileRepository.GetByKeyAsync(indurstry.Id, requestAborted)).Adapt<List<IndustryFileDto>>();
  192. outDto.Files.ToList().ForEach(m => m.Url = fileDownloadApi + m.AdditionId);
  193. outDto.WorkplaceName = _systemDicDataCacheManager.WorkplaceName;
  194. outDto.Workplace = _systemDicDataCacheManager.Workplace;
  195. outDto.JobType = _systemDicDataCacheManager.JobType;
  196. outDto.BusinessUnitType = _systemDicDataCacheManager.BusinessUnitType;
  197. }
  198. return outDto;
  199. }
  200. /// <summary>
  201. /// 获取公开工单集合
  202. /// </summary>
  203. /// <param name="dto"></param>
  204. /// <param name="requestAborted"></param>
  205. /// <returns></returns>
  206. public async Task<IList<OrderPublishOutDto>> GetOrderPublishAsync(OrderPublishInDto dto, CancellationToken requestAborted)
  207. {
  208. dto.ValidateObject();
  209. var items = await _snapshotOrderPublishRepository.Queryable()
  210. .LeftJoin<Order>((s, o) => s.Id == o.Id)
  211. .Where((s, o) => s.IndustryId == dto.IndustryId && s.Status == EOrderSnapshotPublishStatus.Agree)
  212. .WhereIF(dto.Keyword.NotNullOrEmpty(), (s, o) => s.No.Contains(dto.Keyword) || s.ArrangeTitle.Contains(dto.Keyword))
  213. .Select<OrderPublishOutDto>((s, o) => new OrderPublishOutDto
  214. {
  215. Title = s.ArrangeTitle
  216. }, true)
  217. .ToFixedListAsync(dto, requestAborted);
  218. return items;
  219. }
  220. /// <summary>
  221. /// 获取公开的工单详情
  222. /// </summary>
  223. /// <param name="id"></param>
  224. /// <param name="requestAborted"></param>
  225. /// <returns></returns>
  226. public async Task<OrderPublishDetailOutDto> GetOrderPublishDetailAsync(string id, CancellationToken requestAborted)
  227. {
  228. var order = await _orderRepository.GetAsync(id) ??
  229. throw UserFriendlyException.SameMessage("工单不存在");
  230. var outDto = order.Adapt<OrderPublishDetailOutDto>();
  231. var fileServiceUrl = _sysSetting.FileServerUrl;
  232. if (outDto.FileJson != null)
  233. {
  234. foreach (var item in outDto.FileJson)
  235. {
  236. item.Path = fileServiceUrl + item.Path;
  237. }
  238. }
  239. var traces = await _workflowTraceRepository.Queryable()
  240. .Where(m => m.ExternalId == order.Id && m.Status == EWorkflowStepStatus.Handled)
  241. .OrderBy(m => m.AcceptTime)
  242. .ToListAsync(requestAborted);
  243. var centre = traces.Where(m => m.StepType == EStepType.End || m.StepType == EStepType.Start || m.BusinessType == EBusinessType.Send || m.BusinessType == EBusinessType.Seat || m.BusinessType == EBusinessType.File)
  244. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  245. .ToList();
  246. outDto.Workflow = traces.Where(m => !centre.Select(s => s.Id).ToList().Contains(m.Id))
  247. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  248. .ToList();
  249. outDto.Workflow.AddRange(centre);
  250. outDto.Workflow = outDto.Workflow.OrderBy(m => m.HandleTime).ToList();
  251. return outDto;
  252. }
  253. /// <summary>
  254. /// 获取随手拍小程序公告
  255. /// </summary>
  256. /// <returns></returns>
  257. public async Task<IReadOnlyList<BulletinOutDto>> GetBulletinsAsync(BulletinInDto dto, CancellationToken cancellationToken)
  258. {
  259. var items = await _bulletinRepository.Queryable()
  260. .Where(m => m.BulletinState == EBulletinState.ReviewPass)
  261. .LeftJoin<Industry>((bulletin, industry) => bulletin.SnapshotBulletinTypeId == industry.BulletinTypePublicityId)
  262. .Where((bulletin, industry) => industry.Id == dto.IndustryId)
  263. .ToFixedListAsync(dto, cancellationToken);
  264. return items.Adapt<IReadOnlyList<BulletinOutDto>>();
  265. }
  266. /// <summary>
  267. /// 获取个人中心数据
  268. /// </summary>
  269. /// <returns></returns>
  270. public async Task<SnapshotUserInfoOutDto> GetSnapshotUserInfoAsync()
  271. {
  272. var openId = _sessionContext.OpenId;
  273. var thirdAccount = await _thirdAccountRepository.GetByOpenIdAsync(openId);
  274. var dayTime = DateTime.Now;
  275. var readPack = await _redPackRecordRepository.Queryable()
  276. .Where(m => m.WXOpenId == openId && m.PickupStatus == ERedPackPickupStatus.Received)
  277. .Where(m => m.CreationTime.Date == dayTime.Date)
  278. .Select(m => SqlFunc.AggregateSum(m.Amount))
  279. .FirstAsync();
  280. var outDto = await _orderRepository.Queryable()
  281. .Where(m => m.Contact == thirdAccount.PhoneNumber)
  282. .Select(m => new SnapshotUserInfoOutDto
  283. {
  284. NoReplyCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status < EOrderStatus.Filed, 1, 0)),
  285. ReplyCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status >= EOrderStatus.Filed, 1, 0)),
  286. AppraiseCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status == EOrderStatus.Visited, 1, 0)),
  287. }).FirstAsync();
  288. outDto.DayAmount = readPack;
  289. outDto.TotalAmount = thirdAccount.TotalAmount;
  290. outDto.PhoneNumber = thirdAccount.PhoneNumber;
  291. return outDto;
  292. }
  293. /// <summary>
  294. /// 获取工单列表
  295. /// </summary>
  296. public async Task<IList<OrderOutDto>> GetSnapshotOrdersAsync(OrderInDto dto, CancellationToken cancellationToken)
  297. {
  298. var items = await _orderSnapshotRepository.Queryable()
  299. .LeftJoin<Order>((snapshot, order) => snapshot.Id == order.Id)
  300. .Where((snapshot, order) => order.Contact == _sessionContext.Phone)
  301. .WhereIF(dto.Status == EOrderQueryStatus.Appraise, (snapshot, order) => order.Status == EOrderStatus.Visited)
  302. .WhereIF(dto.Status == EOrderQueryStatus.NoReply, (snapshot, order) => order.Status < EOrderStatus.Filed)
  303. .WhereIF(dto.Status == EOrderQueryStatus.Reply, (snapshot, order) => order.Status >= EOrderStatus.Filed)
  304. .WhereIF(dto.KeyWords.NotNullOrEmpty(), (snapshot, order) => order.Title.Contains(dto.KeyWords) || order.No.Contains(dto.KeyWords))
  305. .Select((snapshot, order) => new OrderOutDto
  306. {
  307. Id = snapshot.Id,
  308. OrderNo = order.No,
  309. Title = order.Title,
  310. Status = order.Status,
  311. IndustryName = snapshot.IndustryName,
  312. CreationTime = order.CreationTime,
  313. Area = order.City
  314. })
  315. .ToFixedListAsync(dto, cancellationToken);
  316. return items;
  317. }
  318. /// <summary>
  319. /// 获取工单详情
  320. /// </summary>
  321. /// <param name="id"></param>
  322. /// <returns></returns>
  323. public async Task<OrderPublishDetailOutDto> GetSnapshotOrderDetailAsync(string id, CancellationToken cancellationToken)
  324. {
  325. var order = await _orderRepository.GetAsync(id) ??
  326. throw UserFriendlyException.SameMessage("工单不存在");
  327. var outDto = order.Adapt<OrderPublishDetailOutDto>();
  328. var fileServiceUrl = _sysSetting.FileServerUrl;
  329. if (outDto.FileJson != null)
  330. {
  331. foreach (var item in outDto.FileJson)
  332. {
  333. item.Path = fileServiceUrl + item.Path;
  334. }
  335. }
  336. await _orderVisitRepository.Queryable()
  337. .Where(m => m.OrderId == id).FirstAsync(cancellationToken)
  338. .Then(orderVisit =>
  339. {
  340. if (orderVisit.NowEvaluate != null)
  341. {
  342. outDto.IsVisit = true;
  343. }
  344. });
  345. await _redPackAuditRepository.Queryable()
  346. .Where(m => m.OrderId == id)
  347. .FirstAsync(cancellationToken)
  348. .Then(redPack =>
  349. {
  350. outDto.AuditRemark = redPack.AuditRemark;
  351. outDto.RedPackStatus = redPack.Status;
  352. });
  353. var traces = await _workflowTraceRepository.Queryable()
  354. .Where(m => m.ExternalId == order.Id && m.Status == EWorkflowStepStatus.Handled)
  355. .OrderBy(m => m.AcceptTime)
  356. .ToListAsync(cancellationToken);
  357. var centre = traces.Where(m => m.StepType == EStepType.End || m.StepType == EStepType.Start || m.BusinessType == EBusinessType.Send || m.BusinessType == EBusinessType.Seat || m.BusinessType == EBusinessType.File)
  358. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  359. .ToList();
  360. outDto.Workflow = traces.Where(m => !centre.Select(s => s.Id).ToList().Contains(m.Id))
  361. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  362. .ToList();
  363. outDto.Workflow.AddRange(centre);
  364. outDto.Workflow = outDto.Workflow.OrderBy(m => m.HandleTime).ToList();
  365. return outDto;
  366. }
  367. /// <summary>
  368. /// 获取回访详情
  369. /// </summary>
  370. /// <param name="id"></param>
  371. /// <returns></returns>
  372. public async Task<IList<OrderVisitItemsOutDto>> GetOrderVisitDetailAsync(string id)
  373. {
  374. var orderVisitId = await _orderVisitRepository.Queryable()
  375. .Where(m => m.OrderId == id)
  376. .Select(m => m.Id)
  377. .FirstAsync();
  378. if (orderVisitId.IsNullOrEmpty()) return [];
  379. var orderVisitDetail = await _orderVisitDetailRepository.Queryable()
  380. .Where(m => m.VisitId == orderVisitId)
  381. .ToListAsync();
  382. if (orderVisitDetail.IsNullOrEmpty()) return [];
  383. var seat = orderVisitDetail.Where(m => m.VisitTarget == EVisitTarget.Seat).First();
  384. var item = new OrderVisitItemsOutDto();
  385. if (seat != null && seat.SeatEvaluate.HasValue)
  386. {
  387. item.SeatEvaluate = seat.SeatEvaluate.Value.GetDescription();
  388. }
  389. var org = orderVisitDetail.Where(m => m.VisitTarget == EVisitTarget.Org).First();
  390. if (org != null)
  391. {
  392. if (org.OrgProcessingResults != null) item.OrgProcessingResults = org.OrgProcessingResults.Value;
  393. if (org.OrgHandledAttitude != null) item.OrgHandledAttitude = org.OrgHandledAttitude.Value;
  394. }
  395. return
  396. [
  397. item
  398. ];
  399. }
  400. /// <summary>
  401. /// 获取当月详细红包列表
  402. /// </summary>
  403. /// <param name="dto"></param>
  404. /// <returns></returns>
  405. public async Task<IList<RedPackOutDto>> GetRedPacksAsync(RedPacksInDto dto, CancellationToken cancellationToken)
  406. {
  407. var items = await _redPackRecordRepository.Queryable(includeDeleted: true)
  408. .Where(m => m.IsDeleted == false)
  409. .Where(m => m.WXOpenId == _sessionContext.OpenId || m.PhoneNumber == _sessionContext.Phone)
  410. .Where(m => m.PickupStatus == dto.Status)
  411. .Where(m => m.CreationTime.ToString("yyyy-MM") == dto.Time)
  412. .LeftJoin<Order>((red, order) => red.OrderId == order.Id)
  413. .Select((red, order) => new RedPackOutDto
  414. {
  415. OrderId = order.Id,
  416. Amount = red.Amount,
  417. Title = order.Title,
  418. CreationTime = red.CreationTime
  419. })
  420. .ToFixedListAsync(dto, cancellationToken);
  421. return items;
  422. }
  423. /// <summary>
  424. /// 获取用户领取过的红包总金额
  425. /// </summary>
  426. /// <returns></returns>
  427. public async Task<string> GetRedPackReceivedTotalAsync(CancellationToken cancellationToken)
  428. {
  429. var member = await _thirdAccountRepository.GetAsync(m => m.OpenId == _sessionContext.OpenId || m.PhoneNumber == _sessionContext.Phone, cancellationToken)
  430. ?? throw UserFriendlyException.SameMessage("用户不存在");
  431. return member.TotalAmount.ToYuanFinance();
  432. }
  433. /// <summary>
  434. /// 按月统计红包金额
  435. /// </summary>
  436. /// <param name="count"></param>
  437. /// <returns></returns>
  438. public async Task<IReadOnlyList<RedPackDateOutDto>> GetRedPackDateAsync(RedPackDateInDto dto, CancellationToken cancellationToken)
  439. {
  440. var openId = _sessionContext.OpenId;
  441. var item = await _redPackRecordRepository.Queryable()
  442. .Where(m => m.WXOpenId == openId || m.PhoneNumber == _sessionContext.Phone)
  443. .Where(m => m.PickupStatus == dto.Status)
  444. .GroupBy(m => m.CreationTime.ToString("yyyy-MM"))
  445. .OrderByDescending(m => m.CreationTime)
  446. .Select(m => new RedPackDateOutDto
  447. {
  448. CreationTime = SqlFunc.AggregateMax(m.CreationTime.Date),
  449. Amount = SqlFunc.AggregateSum(m.Amount)
  450. })
  451. .ToListAsync(cancellationToken);
  452. return item;
  453. }
  454. /// <summary>
  455. /// 获取随手拍公告详情
  456. /// </summary>
  457. /// <param name="id"></param>
  458. /// <returns></returns>
  459. public async Task<BulletinOutDto> GetBulletinsDetailAsync(string id)
  460. {
  461. var detail = await _bulletinRepository.Queryable()
  462. .Where(m => m.Id == id)
  463. .Where(m => m.BulletinState == Share.Enums.Article.EBulletinState.ReviewPass)
  464. .Select(m => new BulletinOutDto
  465. {
  466. Id = m.Id,
  467. Title = m.Title,
  468. Content = m.Content,
  469. CreationTime = m.CreationTime
  470. })
  471. .FirstAsync();
  472. return detail;
  473. }
  474. /// <summary>
  475. /// 保存用户自己的邀请码
  476. /// </summary>
  477. /// <param name="dto"></param>
  478. /// <returns></returns>
  479. public async Task SaveInvitationCodeAsync(SaveInvitationCodeInDto dto)
  480. {
  481. dto.ValidateObject();
  482. var third = await _thirdAccountRepository.GetByOpenIdAsync(_sessionContext.OpenId)
  483. ?? throw UserFriendlyException.SameMessage("用户不存在");
  484. third.InvitationCode = dto.InvitationCode;
  485. await _thirdAccountRepository.UpdateAsync(third);
  486. }
  487. #endregion
  488. #region 网格员
  489. /// <summary>
  490. /// 推送工单到网格员系统
  491. /// </summary>
  492. /// <param name="orderId"></param>
  493. /// <returns></returns>
  494. public async Task PostOrderGuiderSystemAsync(string orderId, CancellationToken cancellationToken)
  495. {
  496. string LogName = "推送网格员系统";
  497. var order = await _orderRepository.GetAsync(orderId, cancellationToken);
  498. var orderSnapshot = await _orderSnapshotRepository.GetAsync(orderId, cancellationToken);
  499. if (order is null || orderSnapshot is null)
  500. {
  501. var msg = order is null ? "order" : "orderSnapshot";
  502. _systemLog.Add(LogName, $"OrderId: {orderId}", $"根据Id查询{msg}为null");
  503. return;
  504. }
  505. orderSnapshot.DeadLine = DateTime.Now.AddHours(_sysSetting.OvertimeBack);
  506. var keySecret = _sysSetting.TianQueAppKeySecret.Split('|');
  507. var token = new ThirdTokenDto
  508. {
  509. AppId = keySecret[0],
  510. Secret = keySecret[1]
  511. };
  512. if (order.FileJson.NotNullOrEmpty())
  513. {
  514. var url = _sysSetting.FileServerUrl;
  515. order.FileJson.ForEach(m => { m.Path = url + m.Path; });
  516. }
  517. var result = await _guiderSystemService.PostOrder(order, orderSnapshot, token);
  518. orderSnapshot.GuiderAccLog = result.Result.ToJson();
  519. if (result.Code != 0)
  520. {
  521. _systemLog.Add(LogName, $"OrderNo: {order.No}", $"推送失败: {result.ToJson()}");
  522. orderSnapshot.GuiderAccLog = result.ToJson();
  523. }
  524. orderSnapshot.NetworkENumber = result.Result.GuiderSystemId;
  525. await _orderSnapshotRepository.UpdateAsync(orderSnapshot, cancellationToken);
  526. _systemLog.Add(LogName, $"OrderNo: {order.No}", status: 1);
  527. if (result.Code == 0)
  528. {
  529. double intervalTime = await _industryRepository.GetIntervalTimeAsync(orderSnapshot.IndustryId, _sysSetting.OvertimeBack, cancellationToken);
  530. _systemLog.Add(LogName, $"OrderNo: {order.No}", $"intervalTime: {intervalTime} overtimeBack: {_sysSetting.OvertimeBack}");
  531. await _capPublisher.PublishDelayAsync(TimeSpan.FromHours(intervalTime), EventNames.GuiderSystemReplyDelay, new PostGuiderSystemDelayed(order.Id), cancellationToken: cancellationToken);
  532. }
  533. }
  534. /// <summary>
  535. /// 延迟检查网格员是否回复工单
  536. /// </summary>
  537. /// <param name="orderId"></param>
  538. /// <param name="cancellationToken"></param>
  539. /// <returns></returns>
  540. public async Task GuiderSystemReplyDelayAsync(string orderId, CancellationToken cancellationToken)
  541. {
  542. var orderSnapshot = await _orderSnapshotRepository.GetAsync(orderId)
  543. ?? throw new UserFriendlyException($"orderId:{orderId} order_snapshot 不存在该数据");
  544. if (orderSnapshot.IsDeal != null && orderSnapshot.IsDeal == true)
  545. return;
  546. // 网格员未回复, 推送事件
  547. await _publisher.PublishAsync(new GuiderSystemTimeOutBackNotification(orderId), cancellationToken);
  548. }
  549. /// <summary>
  550. /// 网格员系统回复
  551. /// </summary>
  552. /// <param name="dto"></param>
  553. /// <returns></returns>
  554. [LogToData("ReplyCode")]
  555. public async Task SaveGuiderSystemReplyAsync(GuiderSystemInDto dto, CancellationToken token)
  556. {
  557. var orderSnapshot = await _orderSnapshotRepository.GetByNetworkENumberAsync(dto.AppealNumber)
  558. ?? throw UserFriendlyException.SameMessage("工单不存在");
  559. dto.Adapt(orderSnapshot);
  560. if (dto.ReplyFileList.NotNullOrEmpty())
  561. {
  562. foreach (var file in dto.ReplyFileList)
  563. {
  564. await _fileDomainService.GetNetworkFileAsync(file, orderSnapshot.Id, token);
  565. }
  566. }
  567. await _orderSnapshotRepository.UpdateAsync(orderSnapshot);
  568. // 网格员办结
  569. if (orderSnapshot.ReplyResultType == EGuiderSystemReplyType.Field)
  570. {
  571. await _publisher.PublishAsync(new GuiderSystemFieldNotification(orderSnapshot, dto.Adapt<CommunityInfo>()), token);
  572. }
  573. // 网格员超时未回复退回
  574. if (orderSnapshot.ReplyResultType == EGuiderSystemReplyType.Returned)
  575. {
  576. await _publisher.PublishAsync(new GuiderSystemTimeOutBackNotification(orderSnapshot.Id), token);
  577. }
  578. }
  579. /// <summary>
  580. /// 根据网格员系统回复的内容同步网格员信息
  581. /// </summary>
  582. /// <param name="orderId"></param>
  583. /// <param name="cancellationToken"></param>
  584. /// <returns></returns>
  585. public async Task SyncGuiderInfoAsync(string orderId, CancellationToken cancellationToken)
  586. {
  587. var guiderInfo = await _orderSnapshotRepository.Queryable()
  588. .Where(m => m.Id == orderId)
  589. .Select(m => new { m.MemberName, m.MemberMobile })
  590. .FirstAsync(cancellationToken);
  591. var guider = await _guiderInfoRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile);
  592. if (guider != null) return;
  593. var entity = new GuiderInfo
  594. {
  595. Name = guiderInfo.MemberName,
  596. PhoneNumber = guiderInfo.MemberMobile
  597. };
  598. entity.Id = await _guiderInfoRepository.AddAsync(entity, cancellationToken);
  599. var third = await _thirdAccountRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile);
  600. if (third == null) return;
  601. third.UserId = entity.Id;
  602. third.CitizenType = EReadPackUserType.Guider;
  603. await _thirdAccountRepository.UpdateAsync(third, cancellationToken);
  604. }
  605. /// <summary>
  606. /// 同步社区信息
  607. /// </summary>
  608. /// <param name="entity"></param>
  609. /// <param name="cancellationToken"></param>
  610. /// <returns></returns>
  611. public async Task SyncCommunityInfoAsync(CommunityInfo community, CancellationToken cancellationToken)
  612. {
  613. var entity = await _communityInfoRepository.GetAsync(community.Id, cancellationToken);
  614. if (entity == null)
  615. {
  616. community.UniqueKey = community.GetUniqueKey();
  617. await _communityInfoRepository.AddAsync(community);
  618. return;
  619. }
  620. if (entity.UniqueKey != community.GetUniqueKey())
  621. {
  622. await _communityInfoRepository.UpdateAsync(community, cancellationToken);
  623. }
  624. }
  625. #endregion
  626. #region 从业人员
  627. /// <summary>
  628. /// 添加从业人员
  629. /// </summary>
  630. /// <param name="dtos"></param>
  631. /// <returns></returns>
  632. public async Task AddPractitionerAsync(IList<AddBatchPractitionerInDto> dtos)
  633. {
  634. foreach (var item in dtos)
  635. {
  636. try
  637. {
  638. var entity = item.Adapt<Practitioner>();
  639. switch (item.Gender.Trim())
  640. {
  641. case "男":
  642. entity.Gender = EGender.Male;
  643. break;
  644. case "女":
  645. entity.Gender = EGender.Female;
  646. break;
  647. default:
  648. entity.Gender = EGender.Unknown;
  649. break;
  650. }
  651. var area = await _systemAreaRepository.Queryable()
  652. .Where(m => m.AreaName == item.AreaName)
  653. .FirstAsync();
  654. entity.SystemAreaId = area.Id;
  655. entity.SystemAreaName = area.AreaName;
  656. await _practitionerRepository.AddAsync(entity);
  657. }
  658. catch (Exception e)
  659. {
  660. var msg = e.Message;
  661. }
  662. }
  663. }
  664. /// <summary>
  665. /// 获取从业人员
  666. /// </summary>
  667. /// <param name="dto"></param>
  668. /// <param name="cancellationToken"></param>
  669. /// <returns></returns>
  670. public async Task<IList<PractitionerItemOutDto>> GetPractitionerItemsAsync(PractitionerItemInDto dto, CancellationToken cancellationToken)
  671. {
  672. var items = await _practitionerRepository.Queryable()
  673. .Where(m => m.SystemAreaId == dto.AreaId)
  674. .OrderBy("RANDOM()")
  675. .Select<PractitionerItemOutDto>()
  676. .Take(dto.Count)
  677. .ToListAsync(cancellationToken);
  678. return items;
  679. }
  680. /// <summary>
  681. /// 获取从业人员详情
  682. /// </summary>
  683. /// <param name="id"></param>
  684. /// <param name="cancellationToken"></param>
  685. /// <returns></returns>
  686. public async Task<PractitionerDetailOutDto> GetPractitionerDetailAsync(string id, CancellationToken cancellationToken)
  687. {
  688. var item = await _practitionerRepository.GetAsync(id, cancellationToken)
  689. ?? throw UserFriendlyException.SameMessage("从业人员不存在");
  690. return item.Adapt<PractitionerDetailOutDto>();
  691. }
  692. #endregion
  693. #region 志愿者
  694. /// <summary>
  695. /// 添加志愿者
  696. /// </summary>
  697. /// <param name="dto"></param>
  698. /// <param name="cancellationToken"></param>
  699. /// <returns></returns>
  700. public async Task<string> AddVolunteerAsync(AddVolunteerInDto dto, CancellationToken cancellationToken)
  701. {
  702. var entity = dto.Adapt<Volunteer>();
  703. entity.Id = await _volunteerRepository.AddAsync(entity);
  704. return entity.Id;
  705. }
  706. /// <summary>
  707. /// 志愿者上报
  708. /// </summary>
  709. /// <param name="dto"></param>
  710. /// <param name="requestAborted"></param>
  711. /// <returns></returns>
  712. public async Task<AddVolunteerReportOutDto> AddVolunteerReportAsync(AddVolunteerReportInDto dto, CancellationToken requestAborted)
  713. {
  714. var volunteer = await _volunteerRepository.GetByPhoneAsync(_sessionContext.Phone)
  715. ?? throw UserFriendlyException.SameMessage("提交失败!您不是志愿者.");
  716. var entity = dto.Adapt<VolunteerReport>();
  717. entity.Volunteer = volunteer.Name;
  718. entity.VolunteerPhone = volunteer.PhoneNumber;
  719. entity.Id = await _volunteerReportRepository.AddAsync(entity, requestAborted);
  720. await _fileRepository.AddFileAsync(dto.Files, entity.Id, requestAborted);
  721. if (entity.Name.NotNullOrEmpty())
  722. {
  723. await _thirdAccountRepository.Updateable()
  724. .SetColumns(m => m.UserName, entity.Name)
  725. .Where(m => m.Id == _sessionContext.UserId)
  726. .ExecuteCommandAsync(requestAborted);
  727. }
  728. return entity.Adapt<AddVolunteerReportOutDto>();
  729. }
  730. #endregion
  731. #region 红包
  732. /// <summary>
  733. /// 生成用户红包审核数据
  734. /// </summary>
  735. /// <param name="id"></param>
  736. /// <param name="cancellationToken"></param>
  737. /// <returns></returns>
  738. [LogToData]
  739. public async Task<string> AddRedPardAsync(string orderId, CancellationToken cancellationToken)
  740. {
  741. var order = await _orderRepository.Queryable()
  742. .Where(m => m.Id == orderId)
  743. .Select(m => new { m.Id, m.Status, m.No , m.FromPhone})
  744. .FirstAsync(cancellationToken) ?? throw new UserFriendlyException($"{orderId} 工单不存在");
  745. var snapshot = await _orderSnapshotRepository.GetAsync(orderId) ?? throw new UserFriendlyException("工单不存在");
  746. if (order.Status != EOrderStatus.Filed) return $"{order.No} 工单状态非 {EOrderStatus.Filed} 不处理;";
  747. var redPack = await _redPackAuditRepository.GetByOrderIdAsync(orderId, cancellationToken);
  748. if (redPack != null) return $"{order.No} 工单已存在红包信息,不处理;";
  749. var industry = await _industryRepository.Queryable()
  750. .Where(m => m.Id == snapshot.IndustryId)
  751. .FirstAsync(cancellationToken);
  752. var entity = new RedPackAudit
  753. {
  754. OrderId = order.Id,
  755. Status = ERedPackAuditStatus.Pending,
  756. ShouldAmount = industry.CitizenReadPackAmount,
  757. PhoneNumber = order.FromPhone,
  758. IsSend = false,
  759. };
  760. await _redPackAuditRepository.AddAsync(entity, cancellationToken);
  761. var guiderAudit = entity.Adapt<RedPackGuiderAudit>();
  762. guiderAudit.ShouldAmount = industry.GuiderReadPackAmount;
  763. guiderAudit.PhoneNumber = snapshot.MemberMobile;
  764. await _redPackGuiderAuditRepository.AddAsync(guiderAudit, cancellationToken);
  765. return "ok";
  766. }
  767. #endregion
  768. #region 随手拍公告
  769. /// <summary>
  770. /// 添加随手拍公告
  771. /// </summary>
  772. /// <returns></returns>
  773. public async Task<string> AddBulletinAsync(AddSnapshotBulletinInDto dto)
  774. {
  775. dto.ValidateObject();
  776. var entity = dto.Adapt<SnapshotBulletin>();
  777. entity.BulletinState = EBulletinState.InReview;
  778. entity.Id = await _bulletinRepository.AddAsync(entity);
  779. return entity.Id;
  780. }
  781. /// <summary>
  782. /// 审核公告
  783. /// </summary>
  784. /// <param name="examineBulletinDto"></param>
  785. /// <returns></returns>
  786. public async Task AuditBulletinAsync(ExamineBulletinDto dto)
  787. {
  788. var bulletin = await _bulletinRepository.GetAsync(dto.Id)
  789. ?? throw UserFriendlyException.SameMessage("无效数据");
  790. if (bulletin.BulletinState != EBulletinState.InReview)
  791. throw UserFriendlyException.SameMessage("当前状态不能审核");
  792. bulletin.ExaminOpinion = dto.Reason;
  793. bulletin.ExaminTime = DateTime.Now;
  794. bulletin.ExaminManId = _sessionContext.RequiredUserId;
  795. if (dto.IsPass)
  796. {
  797. bulletin.BulletinState = EBulletinState.ReviewPass;
  798. }
  799. else
  800. {
  801. bulletin.BulletinState = EBulletinState.ReviewNoPass;
  802. }
  803. await _bulletinRepository.UpdateAsync(bulletin);
  804. }
  805. #endregion
  806. }