SnapshotApplicationBase.cs 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  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 SqlSugar;
  8. using XF.Domain.Authentications;
  9. using XF.Domain.Dependency;
  10. using XF.Domain.Repository;
  11. using Hotline.Repository.SqlSugar.Extensions;
  12. using Hotline.Share.Enums;
  13. using Hotline.Share.Enums.Order;
  14. using Hotline.Share.Requests;
  15. using Hotline.Share.Enums.Snapshot;
  16. using Mapster;
  17. using Hotline.Caching.Interfaces;
  18. using NPOI.Util.ArrayExtensions;
  19. using XF.Domain.Exceptions;
  20. using Hotline.Settings;
  21. using Hotline.Share.Dtos.Settings;
  22. using Hotline.File;
  23. using Hotline.Share.Enums.Article;
  24. using Hotline.Tools;
  25. using DotNetCore.CAP;
  26. using Microsoft.AspNetCore.Http;
  27. using Hotline.Share.Dtos.FlowEngine;
  28. using Hotline.FlowEngine.Workflows;
  29. using Hotline.Share.Enums.FlowEngine;
  30. using Hotline.Share.Dtos.Order;
  31. using Hotline.Share.Mq;
  32. using Hotline.Snapshot.Notifications;
  33. using Hotline.EventBus;
  34. using Hotline.Quality.Notifications;
  35. using XF.Utility.EnumExtensions;
  36. using Hotline.ThirdAccountDomainServices.Interfaces;
  37. using Hotline.Snapshot.IRepository;
  38. using Hotline.Share.Enums.CallCenter;
  39. using Hotline.Repository.SqlSugar.Snapshot;
  40. using Hotline.Settings.Hotspots;
  41. using Microsoft.Extensions.Options;
  42. using XF.Utility.MQ;
  43. using System.Threading;
  44. using BulletinOutDto = Hotline.Share.Dtos.Article.BulletinOutDto;
  45. using NPOI.SS.Formula.Functions;
  46. namespace Hotline.Application.Snapshot;
  47. /// <summary>
  48. /// 随手拍应用层
  49. /// </summary>
  50. public abstract class SnapshotApplicationBase
  51. {
  52. private readonly IThirdAccountRepository _thirdAccountRepository;
  53. private readonly IRepository<Order> _orderRepository;
  54. private readonly ISnapshotBulletinRepository _bulletinRepository;
  55. /// <summary>
  56. /// 行业
  57. /// </summary>
  58. private readonly IIndustryRepository _industryRepository;
  59. private readonly IThirdIdentiyService _thirdLoginService;
  60. private readonly ISessionContext _sessionContext;
  61. private readonly IRedPackRecordRepository _redPackRecordRepository;
  62. private readonly IOrderSnapshotRepository _orderSnapshotRepository;
  63. private readonly ISystemSettingCacheManager _sysSetting;
  64. private readonly ISystemAreaDomainService _systemAreaDomainService;
  65. private readonly IRepository<SystemArea> _systemAreaRepository;
  66. private readonly IFileRepository _fileRepository;
  67. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  68. private readonly ISnapshotOrderPublishRepository _snapshotOrderPublishRepository;
  69. private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
  70. private readonly IPractitionerRepository _practitionerRepository;
  71. private readonly IVolunteerRepository _volunteerRepository;
  72. private readonly IVolunteerReportRepository _volunteerReportRepository;
  73. private readonly ISystemLogRepository _systemLog;
  74. private readonly IGuiderSystemService _guiderSystemService;
  75. private readonly ICapPublisher _capPublisher;
  76. private readonly Publisher _publisher;
  77. private readonly IFileDomainService _fileDomainService;
  78. private readonly ICommunityInfoRepository _communityInfoRepository;
  79. private readonly IRedPackAuditRepository _redPackAuditRepository;
  80. private readonly IRedPackGuiderAuditRepository _redPackGuiderAuditRepository;
  81. private readonly IOrderVisitRepository _orderVisitRepository;
  82. private readonly IOrderVisitDetailRepository _orderVisitDetailRepository;
  83. private readonly IInviteCodeRecordRepository _inviteCodeRecordRepository;
  84. private readonly IInviteCodeRepository _inviteCodeRepository;
  85. private readonly ICitizenRepository _citizenRepository;
  86. private readonly ISnapshotPointsRecordRepository _pointsRecordRepository;
  87. private readonly IOptionsSnapshot<MqConfiguration> _mqConfiguration;
  88. private readonly INotificationReceiverRepository _notificationReceiverRepository;
  89. public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IIndustryRepository industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRedPackRecordRepository 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, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IInviteCodeRecordRepository inviteCodeRecordRepository, IInviteCodeRepository inviteCodeRepository, ICitizenRepository citizenRepository, ISnapshotPointsRecordRepository snapshotPointsRecordRepository, IOptionsSnapshot<MqConfiguration> mqConfiguration, INotificationReceiverRepository notificationReceiverRepository)
  90. {
  91. _thirdLoginService = thirdLoginService;
  92. _industryRepository = industryRepository;
  93. _bulletinRepository = bulletinRepository;
  94. _sessionContext = sessionContext;
  95. _redPackRecordRepository = redPackRecordRepository;
  96. _orderRepository = orderRepository;
  97. _thirdAccountRepository = thirdAccountRepository;
  98. _orderSnapshotRepository = orderSnapshotRepository;
  99. _sysSetting = systemSettingCacheManager;
  100. _systemAreaDomainService = systemAreaDomainService;
  101. _fileRepository = fileRepository;
  102. _systemDicDataCacheManager = systemDicDataCacheManager;
  103. _snapshotOrderPublishRepository = snapshotOrderPublishRepository;
  104. _workflowTraceRepository = workflowTraceRepository;
  105. _practitionerRepository = practitionerRepository;
  106. _systemAreaRepository = systemAreaRepository;
  107. _volunteerRepository = volunteerRepository;
  108. _volunteerReportRepository = volunteerReportRepository;
  109. _systemLog = systemLog;
  110. _guiderSystemService = guiderSystemService;
  111. _capPublisher = capPublisher;
  112. _publisher = publisher;
  113. _fileDomainService = fileDomainService;
  114. _communityInfoRepository = communityInfoRepository;
  115. _redPackAuditRepository = redPackAuditRepository;
  116. _orderVisitRepository = orderVisitRepository;
  117. _orderVisitDetailRepository = orderVisitDetailRepository;
  118. _redPackGuiderAuditRepository = redPackGuiderAuditRepository;
  119. _inviteCodeRecordRepository = inviteCodeRecordRepository;
  120. _inviteCodeRepository = inviteCodeRepository;
  121. _citizenRepository = citizenRepository;
  122. _pointsRecordRepository = snapshotPointsRecordRepository;
  123. _mqConfiguration = mqConfiguration;
  124. _notificationReceiverRepository = notificationReceiverRepository;
  125. }
  126. #region 小程序
  127. /// <summary>
  128. /// 获取随手拍小程序首页数据
  129. /// </summary>
  130. /// <returns></returns>
  131. public async Task<HomePageOutDto> GetHomePageAsync()
  132. {
  133. var fileServiceUrl = _sysSetting.FileServerUrl;
  134. var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
  135. var items = await _industryRepository.Queryable()
  136. .Where(m => m.IsEnable)
  137. .OrderBy(m => m.DisplayOrder)
  138. .ToListAsync(m => new HomeIndustryOutDto());
  139. items.ForEach(m =>
  140. {
  141. if (m.BackgroundImgUrl.NotNullOrEmpty())
  142. m.BackgroundImgUrl = fileServiceUrl + m.BackgroundImgUrl;
  143. if (m.BannerImgUrl.NotNullOrEmpty())
  144. m.BannerImgUrl = fileServiceUrl + m.BannerImgUrl;
  145. if (m.CareCellImgUrl.NotNullOrEmpty())
  146. m.CareCellImgUrl = fileServiceUrl + m.CareCellImgUrl;
  147. if (m.CellImgUrl.NotNullOrEmpty())
  148. m.CellImgUrl = fileServiceUrl + m.CellImgUrl;
  149. });
  150. var banners = (await _bulletinRepository.Queryable()
  151. .Where(m => m.SnapshotBulletinTypeId == "SSPBanner" && m.BulletinState == EBulletinState.ReviewPass && m.IsArrive == true)
  152. .Select(m => m.Content).ToListAsync()).Select(m => m.GetHtmlImgSrc()).ToList();
  153. return new HomePageOutDto
  154. {
  155. Banners = banners,
  156. Industrys = items
  157. };
  158. }
  159. /// <summary>
  160. /// 获取小程序首页弹窗
  161. /// </summary>
  162. public async Task<BulletinOutDto> GetBulletionPopupAsync(CancellationToken requestAborted)
  163. {
  164. var item = await _bulletinRepository.Queryable()
  165. .Where(m => m.BulletinState == EBulletinState.ReviewPass)
  166. .Where(m => m.BulletinTime >= DateTime.Now && m.IsPopup == true)
  167. .OrderByDescending(m => m.CreationTime)
  168. .Select<BulletinOutDto>()
  169. .FirstAsync(requestAborted);
  170. return item;
  171. }
  172. /// <summary>
  173. /// 获取行业集合
  174. /// </summary>
  175. /// <returns></returns>
  176. public async Task<IList<IndustryOutDto>> GetIndustresAsync()
  177. {
  178. var fileServiceUrl = _sysSetting.FileServerUrl;
  179. var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
  180. var items = await _industryRepository.Queryable()
  181. .Where(m => m.IsEnable)
  182. .OrderBy(m => m.DisplayOrder)
  183. .ToListAsync(m => new IndustryOutDto());
  184. return items;
  185. }
  186. /// <summary>
  187. /// 行业页面基础数据
  188. /// </summary>
  189. /// <param name="id"></param>
  190. /// <param name="requestAborted"></param>
  191. /// <returns></returns>
  192. public async Task<IndustryBaseOutDto> GetIndustryBaseAsync(string id, CancellationToken requestAborted)
  193. {
  194. var fileServiceUrl = _sysSetting.FileServerUrl;
  195. var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
  196. var indurstry = await _industryRepository.GetAsync(id, requestAborted)
  197. ?? throw UserFriendlyException.SameMessage("行业不存在:" + id);
  198. var bulletinId = await _bulletinRepository.Queryable()
  199. .Where(m => m.SnapshotBulletinTypeId == indurstry.BulletinTypeGuideId && m.BulletinState == EBulletinState.ReviewPass)
  200. .OrderByDescending(m => m.CreationTime)
  201. .Select(m => m.Id)
  202. .FirstAsync(requestAborted);
  203. var outDto = new IndustryBaseOutDto
  204. {
  205. Industry = indurstry.Adapt<IndustryOutDto>()
  206. };
  207. outDto.BulletinId = bulletinId;
  208. if (indurstry.IndustryType == EIndustryType.Declare)
  209. {
  210. outDto.AreaTree = (await _systemAreaDomainService.GetAreaTree(parentId: "510300")).Adapt<List<SystemAreaOutDto>>();
  211. outDto.AreaTree.ToList().ForEach(m =>
  212. {
  213. if (m.Children.IsNullOrEmpty())
  214. m.Children = new List<SystemAreaOutDto>() { new SystemAreaOutDto { Id = "0", AreaName = "无" } };
  215. });
  216. outDto.Files = (await _fileRepository.GetByKeyAsync(indurstry.Id, requestAborted)).Adapt<List<IndustryFileDto>>();
  217. outDto.Files.ToList().ForEach(m => m.Url = fileDownloadApi + m.AdditionId);
  218. outDto.WorkplaceName = _systemDicDataCacheManager.WorkplaceName;
  219. outDto.Workplace = _systemDicDataCacheManager.Workplace;
  220. outDto.JobType = _systemDicDataCacheManager.JobType;
  221. outDto.BusinessUnitType = _systemDicDataCacheManager.BusinessUnitType;
  222. }
  223. return outDto;
  224. }
  225. /// <summary>
  226. /// 获取公开工单集合
  227. /// </summary>
  228. /// <param name="dto"></param>
  229. /// <param name="requestAborted"></param>
  230. /// <returns></returns>
  231. public async Task<IList<OrderPublishOutDto>> GetOrderPublishAsync(OrderPublishInDto dto, CancellationToken requestAborted)
  232. {
  233. dto.ValidateObject();
  234. var items = await _snapshotOrderPublishRepository.Queryable()
  235. .LeftJoin<Order>((s, o) => s.Id == o.Id)
  236. .Where((s, o) => s.IndustryId == dto.IndustryId && s.Status == EOrderSnapshotPublishStatus.Agree)
  237. .WhereIF(dto.Keyword.NotNullOrEmpty(), (s, o) => s.No.Contains(dto.Keyword) || s.ArrangeTitle.Contains(dto.Keyword))
  238. .Select<OrderPublishOutDto>((s, o) => new OrderPublishOutDto
  239. {
  240. Title = s.ArrangeTitle
  241. }, true)
  242. .ToFixedListAsync(dto, requestAborted);
  243. return items;
  244. }
  245. /// <summary>
  246. /// 获取公开的工单详情
  247. /// </summary>
  248. /// <param name="id"></param>
  249. /// <param name="requestAborted"></param>
  250. /// <returns></returns>
  251. public async Task<OrderPublishDetailOutDto> GetOrderPublishDetailAsync(string id, CancellationToken requestAborted)
  252. {
  253. var order = await _orderRepository.GetAsync(id) ??
  254. throw UserFriendlyException.SameMessage("工单不存在");
  255. var outDto = order.Adapt<OrderPublishDetailOutDto>();
  256. var fileServiceUrl = _sysSetting.FileServerUrl;
  257. if (outDto.FileJson != null)
  258. {
  259. foreach (var item in outDto.FileJson)
  260. {
  261. item.Path = fileServiceUrl + item.Path;
  262. }
  263. }
  264. var traces = await _workflowTraceRepository.Queryable()
  265. .Where(m => m.ExternalId == order.Id && m.Status == EWorkflowStepStatus.Handled)
  266. .OrderBy(m => m.AcceptTime)
  267. .ToListAsync(requestAborted);
  268. 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)
  269. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  270. .ToList();
  271. outDto.Workflow = traces.Where(m => !centre.Select(s => s.Id).ToList().Contains(m.Id))
  272. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  273. .ToList();
  274. outDto.Workflow.AddRange(centre);
  275. outDto.Workflow = outDto.Workflow.OrderBy(m => m.HandleTime).ToList();
  276. return outDto;
  277. }
  278. /// <summary>
  279. /// 获取随手拍小程序公告
  280. /// </summary>
  281. /// <returns></returns>
  282. public async Task<IReadOnlyList<BulletinListOutDto>> GetBulletinsAsync(BulletinInDto dto, CancellationToken cancellationToken)
  283. {
  284. var items = await _bulletinRepository.Queryable()
  285. .Where(m => m.BulletinState == EBulletinState.ReviewPass && m.IsArrive == true)
  286. .LeftJoin<Industry>((bulletin, industry) => bulletin.SnapshotBulletinTypeId == industry.BulletinTypePublicityId)
  287. .Where((bulletin, industry) => industry.Id == dto.IndustryId)
  288. .ToFixedListAsync(dto, cancellationToken);
  289. return items.Adapt<IReadOnlyList<BulletinListOutDto>>();
  290. }
  291. /// <summary>
  292. /// 获取个人中心数据
  293. /// </summary>
  294. /// <returns></returns>
  295. public async Task<SnapshotUserInfoOutDto> GetSnapshotUserInfoAsync(CancellationToken token)
  296. {
  297. var userInfo = await _citizenRepository.GetAsync(_sessionContext.UserId);
  298. var dayTime = DateTime.Now;
  299. var query = _redPackRecordRepository.Queryable()
  300. .Where(m => m.WXOpenId == _sessionContext.OpenId && m.PickupStatus == ERedPackPickupStatus.Received)
  301. .Where(m => m.CreationTime.Date == dayTime.Date)
  302. .Select(m => SqlFunc.AggregateSum(m.Amount));
  303. #if DEBUG
  304. var sql = query.ToSqlString();
  305. #endif
  306. var redPack = await query.FirstAsync(token);
  307. var outDto = await _orderRepository.Queryable()
  308. .Where(m => m.Contact == userInfo.PhoneNumber && m.CreatorId == _sessionContext.UserId)
  309. .Select(m => new SnapshotUserInfoOutDto
  310. {
  311. NoReplyCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status < EOrderStatus.Filed, 1, 0)),
  312. ReplyCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status >= EOrderStatus.Filed, 1, 0)),
  313. AppraiseCount = SqlFunc.AggregateSum(SqlFunc.IIF(m.Status == EOrderStatus.Visited, 1, 0)),
  314. }).FirstAsync(token);
  315. outDto.DayAmount = redPack;
  316. outDto.TotalAmount = await _redPackRecordRepository.GetReceivedTotalAmountAsync(_sessionContext.OpenId, token);
  317. outDto.PhoneNumber = userInfo.PhoneNumber;
  318. return outDto;
  319. }
  320. /// <summary>
  321. /// 获取工单列表
  322. /// </summary>
  323. public async Task<IList<OrderOutDto>> GetSnapshotOrdersAsync(OrderInDto dto, CancellationToken cancellationToken)
  324. {
  325. var items = await _orderSnapshotRepository.Queryable()
  326. .LeftJoin<Order>((snapshot, order) => snapshot.Id == order.Id)
  327. .Where((snapshot, order) => order.Contact == _sessionContext.Phone)
  328. .WhereIF(dto.Status == EOrderQueryStatus.Appraise, (snapshot, order) => order.Status == EOrderStatus.Visited)
  329. .WhereIF(dto.Status == EOrderQueryStatus.NoReply, (snapshot, order) => order.Status < EOrderStatus.Filed)
  330. .WhereIF(dto.Status == EOrderQueryStatus.Reply, (snapshot, order) => order.Status >= EOrderStatus.Filed)
  331. .WhereIF(dto.KeyWords.NotNullOrEmpty(), (snapshot, order) => order.Title.Contains(dto.KeyWords) || order.No.Contains(dto.KeyWords))
  332. .OrderByDescending((snapshot, order) => snapshot.CreationTime)
  333. .Select((snapshot, order) => new OrderOutDto
  334. {
  335. Id = snapshot.Id,
  336. OrderNo = order.No,
  337. Title = order.Title,
  338. Status = order.Status,
  339. IndustryName = snapshot.IndustryName,
  340. CreationTime = order.CreationTime,
  341. Area = order.City
  342. })
  343. .ToFixedListAsync(dto, cancellationToken);
  344. return items;
  345. }
  346. /// <summary>
  347. /// 积分详情集合
  348. /// </summary>
  349. /// <param name="dto"></param>
  350. /// <returns></returns>
  351. public async Task<IList<PointItemsOutDto>> GetPointItemsAsync(PointItemsInDto dto, CancellationToken token)
  352. {
  353. var items = await _pointsRecordRepository.Queryable()
  354. .Where(m => m.UserId == _sessionContext.UserId && dto.Direction == m.Direction)
  355. .Select(m => new PointItemsOutDto(), true)
  356. .OrderByDescending(m => m.CreationTime)
  357. .ToFixedListAsync(dto, token);
  358. return items;
  359. }
  360. /// <summary>
  361. /// 积分总计
  362. /// </summary>
  363. /// <param name="dto"></param>
  364. /// <param name="requestAborted"></param>
  365. /// <returns></returns>
  366. public async Task<int> GetPointsTotalAsync(PointItemsInDto dto, CancellationToken token)
  367. {
  368. return await _pointsRecordRepository.Queryable()
  369. .Where(m => m.UserId == _sessionContext.UserId && dto.Direction == m.Direction)
  370. .SumAsync(m => m.Points);
  371. }
  372. public async Task<IList<GetNotifyOutDto>> GetNotificationAsync(GetNotifyInDto dto, CancellationToken requestAborted)
  373. {
  374. var items = await _notificationReceiverRepository.Queryable()
  375. .LeftJoin<Notification>((m , notify) => m.NotificationId == notify.Id)
  376. .Where((m, notify) => m.ReceiverId == _sessionContext.UserId && dto.NotifyType == notify.NotifyType)
  377. .Select((m, notify) => new GetNotifyOutDto
  378. {
  379. NotificationId = m.NotificationId,
  380. Title = notify.Title ,
  381. CreationTime = m.CreationTime
  382. }, true)
  383. .ToFixedListAsync(dto, requestAborted);
  384. return items;
  385. }
  386. /// <summary>
  387. /// 获取工单详情
  388. /// </summary>
  389. /// <param name="id"></param>
  390. /// <returns></returns>
  391. public async Task<OrderPublishDetailOutDto> GetSnapshotOrderDetailAsync(string id, CancellationToken cancellationToken)
  392. {
  393. var order = await _orderRepository.GetAsync(id) ??
  394. throw UserFriendlyException.SameMessage("工单不存在");
  395. var outDto = order.Adapt<OrderPublishDetailOutDto>();
  396. var fileServiceUrl = _sysSetting.FileServerUrl;
  397. if (outDto.FileJson != null)
  398. {
  399. foreach (var item in outDto.FileJson)
  400. {
  401. item.Path = fileServiceUrl + item.Path;
  402. }
  403. }
  404. await _orderVisitRepository.Queryable()
  405. .Where(m => m.OrderId == id).FirstAsync(cancellationToken)
  406. .Then(orderVisit =>
  407. {
  408. if (orderVisit.NowEvaluate != null)
  409. {
  410. outDto.IsVisit = true;
  411. }
  412. });
  413. await _redPackAuditRepository.Queryable()
  414. .Where(m => m.OrderId == id)
  415. .FirstAsync(cancellationToken)
  416. .Then(redPack =>
  417. {
  418. outDto.AuditRemark = redPack.AuditRemark;
  419. outDto.RedPackStatus = redPack.Status;
  420. });
  421. var traces = await _workflowTraceRepository.Queryable()
  422. .Where(m => m.ExternalId == order.Id && m.Status == EWorkflowStepStatus.Handled)
  423. .OrderBy(m => m.AcceptTime)
  424. .ToListAsync(cancellationToken);
  425. 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)
  426. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  427. .ToList();
  428. outDto.Workflow = traces.Where(m => !centre.Select(s => s.Id).ToList().Contains(m.Id))
  429. .Select(m => new SnapshotWorkflow(m.Id, m.Name, m.HandleTime.Value))
  430. .ToList();
  431. outDto.Workflow.AddRange(centre);
  432. outDto.Workflow = outDto.Workflow.OrderBy(m => m.HandleTime).ToList();
  433. return outDto;
  434. }
  435. /// <summary>
  436. /// 获取回访详情
  437. /// </summary>
  438. /// <param name="id"></param>
  439. /// <returns></returns>
  440. public async Task<IList<OrderVisitItemsOutDto>> GetOrderVisitDetailAsync(string id)
  441. {
  442. var orderVisitId = await _orderVisitRepository.Queryable()
  443. .Where(m => m.OrderId == id)
  444. .Select(m => m.Id)
  445. .FirstAsync();
  446. if (orderVisitId.IsNullOrEmpty()) return [];
  447. var orderVisitDetail = await _orderVisitDetailRepository.Queryable()
  448. .Where(m => m.VisitId == orderVisitId)
  449. .ToListAsync();
  450. if (orderVisitDetail.IsNullOrEmpty()) return [];
  451. var seat = orderVisitDetail.Where(m => m.VisitTarget == EVisitTarget.Seat).First();
  452. var item = new OrderVisitItemsOutDto();
  453. if (seat != null && seat.SeatEvaluate.HasValue)
  454. {
  455. item.SeatEvaluate = seat.SeatEvaluate.Value.GetDescription();
  456. }
  457. var org = orderVisitDetail.Where(m => m.VisitTarget == EVisitTarget.Org).First();
  458. if (org != null)
  459. {
  460. if (org.OrgProcessingResults != null) item.OrgProcessingResults = org.OrgProcessingResults.Value;
  461. if (org.OrgHandledAttitude != null) item.OrgHandledAttitude = org.OrgHandledAttitude.Value;
  462. }
  463. return
  464. [
  465. item
  466. ];
  467. }
  468. /// <summary>
  469. /// 获取当月详细红包列表
  470. /// </summary>
  471. /// <param name="dto"></param>
  472. /// <returns></returns>
  473. public async Task<IList<RedPackOutDto>> GetRedPacksAsync(RedPacksInDto dto, CancellationToken cancellationToken)
  474. {
  475. var items = await _redPackRecordRepository.Queryable(includeDeleted: true)
  476. .LeftJoin<Order>((m, order) => m.OrderId == order.Id)
  477. .Where(m => m.IsDeleted == false)
  478. .Where(m => m.WXOpenId == _sessionContext.OpenId)
  479. .WhereIF(dto.Status == ERedPackPickupStatus.Unreceived, (m, order) => m.PickupStatus == dto.Status && (order.HotspotId == null || order.HotspotId.StartsWith("18") == false))
  480. .WhereIF(dto.Status != ERedPackPickupStatus.Unreceived, (m, order) => m.PickupStatus == dto.Status)
  481. .Where(m => m.CreationTime.ToString("yyyy-MM") == dto.Time)
  482. .Select((m, order) => new RedPackOutDto
  483. {
  484. OrderId = order.Id,
  485. Amount = m.Amount,
  486. Title = order.Title,
  487. CreationTime = m.CreationTime,
  488. RedPackAuditId = m.RedPackAuditId
  489. })
  490. .ToFixedListAsync(dto, cancellationToken);
  491. return items;
  492. }
  493. /// <summary>
  494. /// 获取用户领取过的红包总金额
  495. /// </summary>
  496. /// <returns></returns>
  497. public async Task<string> GetRedPackReceivedTotalAsync(CancellationToken cancellationToken)
  498. {
  499. return (await _redPackRecordRepository.GetReceivedTotalAmountAsync(_sessionContext.OpenId, cancellationToken)).ToYuanFinance();
  500. }
  501. /// <summary>
  502. /// 按月统计红包金额
  503. /// </summary>
  504. /// <param name="count"></param>
  505. /// <returns></returns>
  506. public async Task<IReadOnlyList<RedPackDateOutDto>> GetRedPackDateAsync(RedPackDateInDto dto, CancellationToken cancellationToken)
  507. {
  508. var openId = _sessionContext.OpenId;
  509. var item = await _redPackRecordRepository.Queryable()
  510. .Where(m => m.WXOpenId == openId || m.PhoneNumber == _sessionContext.Phone)
  511. .Where(m => m.PickupStatus == dto.Status)
  512. .GroupBy(m => m.CreationTime.ToString("yyyy-MM"))
  513. .OrderByDescending(m => m.CreationTime)
  514. .Select(m => new RedPackDateOutDto
  515. {
  516. CreationTime = SqlFunc.AggregateMax(m.CreationTime.Date),
  517. Amount = SqlFunc.AggregateSum(m.Amount)
  518. })
  519. .ToListAsync(cancellationToken);
  520. return item;
  521. }
  522. /// <summary>
  523. /// 获取随手拍公告详情
  524. /// </summary>
  525. /// <param name="id"></param>
  526. /// <returns></returns>
  527. public async Task<BulletinOutDto> GetBulletinsDetailAsync(string id)
  528. {
  529. var detail = await _bulletinRepository.Queryable()
  530. .Where(m => m.Id == id)
  531. .Where(m => m.BulletinState == Share.Enums.Article.EBulletinState.ReviewPass)
  532. .Select(m => new BulletinOutDto
  533. {
  534. Id = m.Id,
  535. Title = m.Title,
  536. Content = m.Content,
  537. CreationTime = m.CreationTime
  538. })
  539. .FirstAsync();
  540. return detail;
  541. }
  542. /// <summary>
  543. /// 保存用户自己的邀请码
  544. /// </summary>
  545. /// <param name="dto"></param>
  546. /// <returns></returns>
  547. public async Task SaveInvitationCodeAsync(SaveInvitationCodeInDto dto)
  548. {
  549. dto.ValidateObject();
  550. if (int.TryParse(dto.InvitationCode, out var invitationCode) == false)
  551. {
  552. throw new UserFriendlyException(200, "邀请码格式错误");
  553. }
  554. var userInfo = await _citizenRepository.GetAsync(_sessionContext.UserId)
  555. ?? throw UserFriendlyException.SameMessage("用户不存在");
  556. if (userInfo.InvitationCode.NotNullOrEmpty())
  557. {
  558. throw new UserFriendlyException(200, "邀请码已存在");
  559. }
  560. if (_inviteCodeRecordRepository.Queryable().Where(m => m.InviteCode == dto.InvitationCode).Any())
  561. {
  562. throw new UserFriendlyException(200, "邀请码已经被使用");
  563. }
  564. userInfo.InvitationCode = dto.InvitationCode;
  565. var invite = await _inviteCodeRepository.Queryable()
  566. .Where(m => invitationCode >= m.BeginCode && invitationCode <= m.EndCode)
  567. .FirstAsync() ?? throw new UserFriendlyException(200, "邀请码无效");
  568. var entity = new InviteCodeRecord
  569. {
  570. OrgId = invite.Id,
  571. OrgName = invite.OrgName,
  572. InviteCode = dto.InvitationCode,
  573. WXOpenId = _sessionContext.OpenId,
  574. PhoneNumber = userInfo.PhoneNumber,
  575. Name = userInfo.Name,
  576. };
  577. await _citizenRepository.UpdateAsync(userInfo);
  578. await _inviteCodeRecordRepository.AddAsync(entity);
  579. }
  580. #endregion
  581. #region 网格员
  582. /// <summary>
  583. /// 推送工单到网格员系统
  584. /// </summary>
  585. /// <param name="orderId"></param>
  586. /// <returns></returns>
  587. public async Task PostOrderGuiderSystemAsync(string orderId, CancellationToken cancellationToken)
  588. {
  589. string LogName = "推送网格员系统";
  590. var order = await _orderRepository.GetAsync(orderId, cancellationToken);
  591. var orderSnapshot = await _orderSnapshotRepository.GetAsync(orderId, cancellationToken);
  592. if (order is null || orderSnapshot is null)
  593. {
  594. var msg = order is null ? "order" : "orderSnapshot";
  595. _systemLog.Add(LogName, $"OrderId: {orderId}", $"根据Id查询{msg}为null");
  596. return;
  597. }
  598. orderSnapshot.DeadLine = DateTime.Now.AddHours(_sysSetting.OvertimeBack);
  599. orderSnapshot.SendGuidSystemTime = DateTime.Now;
  600. var keySecret = _sysSetting.TianQueAppKeySecret.Split('|');
  601. var token = new ThirdTokenDto
  602. {
  603. AppId = keySecret[0],
  604. Secret = keySecret[1]
  605. };
  606. if (order.FileJson.NotNullOrEmpty())
  607. {
  608. var url = _sysSetting.FileServerUrl;
  609. order.FileJson.ForEach(m => { m.Path = url + m.Path; });
  610. }
  611. var result = await _guiderSystemService.PostOrder(order, orderSnapshot, token);
  612. orderSnapshot.GuiderAccLog = result.Result.ToJson();
  613. if (result.Code != 0)
  614. {
  615. _systemLog.Add(LogName, $"OrderNo: {order.No}", $"推送失败: {result.ToJson()}");
  616. orderSnapshot.GuiderAccLog = result.ToJson();
  617. }
  618. orderSnapshot.NetworkENumber = result.Result.GuiderSystemId;
  619. await _orderSnapshotRepository.UpdateAsync(orderSnapshot, cancellationToken);
  620. _systemLog.Add(LogName, $"OrderNo: {order.No}", status: 1);
  621. if (result.Code == 0)
  622. {
  623. double intervalTime = await _industryRepository.GetIntervalTimeAsync(orderSnapshot.IndustryId, _sysSetting.OvertimeBack, cancellationToken);
  624. _systemLog.Add(LogName, $"OrderNo: {order.No}", $"intervalTime: {intervalTime} overtimeBack: {_sysSetting.OvertimeBack}");
  625. await _capPublisher.PublishDelayAsync(TimeSpan.FromHours(intervalTime), EventNames.GuiderSystemReplyDelay, new PostGuiderSystemDelayed(order.Id), cancellationToken: cancellationToken);
  626. }
  627. }
  628. /// <summary>
  629. /// 延迟检查网格员是否回复工单
  630. /// </summary>
  631. /// <param name="orderId"></param>
  632. /// <param name="cancellationToken"></param>
  633. /// <returns></returns>
  634. public async Task GuiderSystemReplyDelayAsync(string orderId, CancellationToken cancellationToken)
  635. {
  636. var orderSnapshot = await _orderSnapshotRepository.GetAsync(orderId)
  637. ?? throw new UserFriendlyException($"orderId:{orderId} order_snapshot {_mqConfiguration?.Value?.RabbitMq?.VirtualHost} 不存在该数据");
  638. if (orderSnapshot.IsDeal != null && orderSnapshot.IsDeal == true)
  639. return;
  640. // 网格员未回复, 推送事件
  641. await _publisher.PublishAsync(new GuiderSystemTimeOutBackNotification(orderId), cancellationToken);
  642. }
  643. /// <summary>
  644. /// 网格员系统回复
  645. /// </summary>
  646. /// <param name="dto"></param>
  647. /// <returns></returns>
  648. public async Task SaveGuiderSystemReplyAsync(GuiderSystemInDto dto, CancellationToken token)
  649. {
  650. var orderSnapshot = await _orderSnapshotRepository.GetByNetworkENumberAsync(dto.AppealNumber)
  651. ?? throw UserFriendlyException.SameMessage("工单不存在");
  652. dto.Adapt(orderSnapshot);
  653. if (dto.ReplyFileList.NotNullOrEmpty())
  654. {
  655. foreach (var file in dto.ReplyFileList)
  656. {
  657. await _fileDomainService.GetNetworkFileAsync(file, orderSnapshot.Id, token);
  658. }
  659. }
  660. orderSnapshot.IsGuidSystemCallBack = true;
  661. orderSnapshot.GuidSystemCallBackTime = DateTime.Now;
  662. await _orderSnapshotRepository.UpdateAsync(orderSnapshot);
  663. // 网格员办结
  664. if (orderSnapshot.ReplyResultType == EGuiderSystemReplyType.Field)
  665. {
  666. await _publisher.PublishAsync(new GuiderSystemFieldNotification(orderSnapshot, dto.Adapt<CommunityInfo>()), token);
  667. }
  668. // 网格员超时未回复退回
  669. if (orderSnapshot.ReplyResultType == EGuiderSystemReplyType.Returned)
  670. {
  671. await _publisher.PublishAsync(new GuiderSystemTimeOutBackNotification(orderSnapshot.Id), token);
  672. }
  673. }
  674. /// <summary>
  675. /// 根据网格员系统回复的内容同步网格员信息
  676. /// </summary>
  677. /// <param name="orderId"></param>
  678. /// <param name="cancellationToken"></param>
  679. /// <returns></returns>
  680. public async Task SyncGuiderInfoAsync(string orderId, CancellationToken cancellationToken)
  681. {
  682. var guiderInfo = await _orderSnapshotRepository.Queryable()
  683. .Where(m => m.Id == orderId)
  684. .Select(m => new { m.MemberName, m.MemberMobile })
  685. .FirstAsync(cancellationToken);
  686. var guider = await _citizenRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile);
  687. if (guider != null) return;
  688. var entity = new Citizen
  689. {
  690. Name = guiderInfo.MemberName,
  691. PhoneNumber = guiderInfo.MemberMobile,
  692. CitizenType = EReadPackUserType.Guider
  693. };
  694. entity.Id = await _citizenRepository.AddAsync(entity, cancellationToken);
  695. var third = (await _thirdAccountRepository.GetByPhoneNumberAsync(guiderInfo.MemberMobile, cancellationToken))
  696. .Where(m => m.ExternalId == null)
  697. .ToList();
  698. third.ForEach(m => m.ExternalId = entity.Id);
  699. await _thirdAccountRepository.UpdateRangeAsync(third);
  700. }
  701. /// <summary>
  702. /// 同步社区信息
  703. /// </summary>
  704. /// <param name="entity"></param>
  705. /// <param name="cancellationToken"></param>
  706. /// <returns></returns>
  707. public async Task SyncCommunityInfoAsync(CommunityInfo community, CancellationToken cancellationToken)
  708. {
  709. var entity = await _communityInfoRepository.GetAsync(community.Id, cancellationToken);
  710. if (entity == null)
  711. {
  712. community.UniqueKey = community.GetUniqueKey();
  713. await _communityInfoRepository.AddAsync(community);
  714. return;
  715. }
  716. if (entity.UniqueKey != community.GetUniqueKey())
  717. {
  718. await _communityInfoRepository.UpdateAsync(community, cancellationToken);
  719. }
  720. }
  721. #endregion
  722. #region 从业人员
  723. /// <summary>
  724. /// 添加从业人员
  725. /// </summary>
  726. /// <param name="dtos"></param>
  727. /// <returns></returns>
  728. public async Task AddPractitionerAsync(IList<AddBatchPractitionerInDto> dtos)
  729. {
  730. foreach (var item in dtos)
  731. {
  732. try
  733. {
  734. var entity = item.Adapt<Practitioner>();
  735. switch (item.Gender.Trim())
  736. {
  737. case "男":
  738. entity.Gender = EGender.Male;
  739. break;
  740. case "女":
  741. entity.Gender = EGender.Female;
  742. break;
  743. default:
  744. entity.Gender = EGender.Unknown;
  745. break;
  746. }
  747. var area = await _systemAreaRepository.Queryable()
  748. .Where(m => m.AreaName == item.AreaName)
  749. .FirstAsync();
  750. entity.SystemAreaId = area.Id;
  751. entity.SystemAreaName = area.AreaName;
  752. await _practitionerRepository.AddAsync(entity);
  753. }
  754. catch (Exception e)
  755. {
  756. var msg = e.Message;
  757. }
  758. }
  759. }
  760. /// <summary>
  761. /// 获取从业人员
  762. /// </summary>
  763. /// <param name="dto"></param>
  764. /// <param name="cancellationToken"></param>
  765. /// <returns></returns>
  766. public async Task<IList<PractitionerItemOutDto>> GetPractitionerItemsAsync(PractitionerItemInDto dto, CancellationToken cancellationToken)
  767. {
  768. var items = await _practitionerRepository.Queryable()
  769. .Where(m => m.SystemAreaId == dto.AreaId)
  770. .OrderBy("RANDOM()")
  771. .Select<PractitionerItemOutDto>()
  772. .Take(dto.Count)
  773. .ToListAsync(cancellationToken);
  774. return items;
  775. }
  776. /// <summary>
  777. /// 获取从业人员详情
  778. /// </summary>
  779. /// <param name="id"></param>
  780. /// <param name="cancellationToken"></param>
  781. /// <returns></returns>
  782. public async Task<PractitionerDetailOutDto> GetPractitionerDetailAsync(string id, CancellationToken cancellationToken)
  783. {
  784. var item = await _practitionerRepository.GetAsync(id, cancellationToken)
  785. ?? throw UserFriendlyException.SameMessage("从业人员不存在");
  786. return item.Adapt<PractitionerDetailOutDto>();
  787. }
  788. #endregion
  789. #region 志愿者
  790. /// <summary>
  791. /// 添加志愿者
  792. /// </summary>
  793. /// <param name="dto"></param>
  794. /// <param name="cancellationToken"></param>
  795. /// <returns></returns>
  796. public async Task<string> AddVolunteerAsync(AddVolunteerInDto dto, CancellationToken cancellationToken)
  797. {
  798. var entity = dto.Adapt<Volunteer>();
  799. entity.Id = await _volunteerRepository.AddAsync(entity);
  800. return entity.Id;
  801. }
  802. /// <summary>
  803. /// 志愿者上报
  804. /// </summary>
  805. /// <param name="dto"></param>
  806. /// <param name="requestAborted"></param>
  807. /// <returns></returns>
  808. public async Task<AddVolunteerReportOutDto> AddVolunteerReportAsync(AddVolunteerReportInDto dto, CancellationToken requestAborted)
  809. {
  810. var volunteer = await _volunteerRepository.GetByPhoneAsync(_sessionContext.Phone)
  811. ?? throw UserFriendlyException.SameMessage("提交失败!您不是志愿者.");
  812. var entity = dto.Adapt<VolunteerReport>();
  813. entity.Volunteer = volunteer.Name;
  814. entity.VolunteerPhone = volunteer.PhoneNumber;
  815. entity.Id = await _volunteerReportRepository.AddAsync(entity, requestAborted);
  816. await _fileRepository.AddFileAsync(dto.Files, entity.Id, requestAborted);
  817. if (entity.Name.NotNullOrEmpty())
  818. {
  819. await _thirdAccountRepository.Updateable()
  820. .SetColumns(m => m.UserName, entity.Name)
  821. .Where(m => m.Id == _sessionContext.UserId)
  822. .ExecuteCommandAsync(requestAborted);
  823. }
  824. return entity.Adapt<AddVolunteerReportOutDto>();
  825. }
  826. #endregion
  827. #region 红包
  828. /// <summary>
  829. /// 生成用户红包审核数据
  830. /// </summary>
  831. /// <param name="orderId">工单Id</param>
  832. /// <param name="cancellationToken"></param>
  833. /// <returns></returns>
  834. public async Task<string> AddRedPardAsync(string orderId, CancellationToken cancellationToken)
  835. {
  836. var order = await _orderRepository.Queryable()
  837. .Where(m => m.Id == orderId)
  838. .Select(m => new { m.Id, m.Status, m.No, m.FromPhone })
  839. .FirstAsync(cancellationToken) ?? throw new UserFriendlyException($"{orderId} 工单不存在");
  840. var snapshot = await _orderSnapshotRepository.GetAsync(orderId) ?? throw new UserFriendlyException("工单不存在");
  841. if (order.Status != EOrderStatus.Filed) return $"{order.No} 工单状态非 {EOrderStatus.Filed} 不处理;";
  842. var redPack = await _redPackAuditRepository.GetByOrderIdAsync(orderId, cancellationToken);
  843. if (redPack != null) return $"{order.No} 工单已存在红包信息,不处理;";
  844. var industry = await _industryRepository.Queryable()
  845. .Where(m => m.Id == snapshot.IndustryId)
  846. .FirstAsync(cancellationToken);
  847. var entity = new RedPackAudit
  848. {
  849. OrderId = order.Id,
  850. Status = ERedPackAuditStatus.Pending,
  851. ShouldAmount = industry.CitizenReadPackAmount,
  852. PhoneNumber = order.FromPhone,
  853. IsSend = false,
  854. };
  855. await _redPackAuditRepository.AddAsync(entity, cancellationToken);
  856. var guiderAudit = entity.Adapt<RedPackGuiderAudit>();
  857. guiderAudit.ShouldAmount = industry.GuiderReadPackAmount;
  858. guiderAudit.PhoneNumber = snapshot.MemberMobile;
  859. guiderAudit.LevelTwoStatus = ERedPackAuditStatus.Pending;
  860. guiderAudit.ApprovedAmount = industry.GuiderReadPackAmount;
  861. await _redPackGuiderAuditRepository.AddAsync(guiderAudit, cancellationToken);
  862. return "ok";
  863. }
  864. #endregion
  865. #region 随手拍公告
  866. /// <summary>
  867. /// 添加随手拍公告
  868. /// </summary>
  869. /// <returns></returns>
  870. public async Task<string> AddBulletinAsync(AddSnapshotBulletinInDto dto)
  871. {
  872. dto.ValidateObject();
  873. var entity = dto.Adapt<SnapshotBulletin>();
  874. entity.BulletinState = EBulletinState.InReview;
  875. entity.Id = await _bulletinRepository.AddAsync(entity);
  876. return entity.Id;
  877. }
  878. /// <summary>
  879. /// 审核公告
  880. /// </summary>
  881. /// <param name="examineBulletinDto"></param>
  882. /// <returns></returns>
  883. public async Task AuditBulletinAsync(ExamineBulletinDto dto)
  884. {
  885. var bulletin = await _bulletinRepository.GetAsync(dto.Id)
  886. ?? throw UserFriendlyException.SameMessage("无效数据");
  887. if (bulletin.BulletinState != EBulletinState.InReview)
  888. throw UserFriendlyException.SameMessage("当前状态不能审核");
  889. bulletin.ExaminOpinion = dto.Reason;
  890. bulletin.ExaminTime = DateTime.Now;
  891. bulletin.ExaminManId = _sessionContext.RequiredUserId;
  892. if (dto.IsPass)
  893. {
  894. bulletin.BulletinState = EBulletinState.ReviewPass;
  895. }
  896. else
  897. {
  898. bulletin.BulletinState = EBulletinState.ReviewNoPass;
  899. }
  900. await _bulletinRepository.UpdateAsync(bulletin);
  901. }
  902. #endregion
  903. #region 积分
  904. public async Task<PointsRankOutDto> GetPointsRankAsync()
  905. {
  906. var outDto = new PointsRankOutDto();
  907. var record = await _pointsRecordRepository.Queryable()
  908. .Where(m => m.UserId == _sessionContext.UserId)
  909. .Select(m => new
  910. {
  911. Total = SqlFunc.AggregateSum(m.Points),
  912. Out = SqlFunc.AggregateSum(SqlFunc.IIF(m.Direction == EPointsDirection.Out, m.Points, 0))
  913. }).FirstAsync();
  914. outDto.ValidPoints = record.Total - record.Out;
  915. var startTime = new DateTime(DateTime.Now.Year, 1, 1, 0, 0, 0);
  916. var endTime = new DateTime(DateTime.Now.Year, 12, 31, 23, 59, 59);
  917. var query = _pointsRecordRepository.Queryable()
  918. .LeftJoin<Citizen>((points, citizen) => points.UserId == citizen.Id)
  919. .Where((points, citizen) => points.CreationTime >= startTime && points.CreationTime <= endTime)
  920. .GroupBy((points, citizen) => new { citizen.Id, points.UserId, citizen.IsSecurityMax, citizen.Name, citizen.PhoneNumber })
  921. .Select((points, citizen) => new PointsRankUserDto
  922. {
  923. IsSecurityMax = citizen.IsSecurityMax ?? false,
  924. Rank = SqlFunc.MappingColumn<int>($@" DENSE_RANK() OVER (ORDER BY SUM(CASE WHEN ""points"".""Direction"" = 0 THEN ""points"".""Points"" ELSE 0 END) DESC)"),
  925. Points = SqlFunc.AggregateSum(points.Points),
  926. UserName = citizen.Name!,
  927. PhoneNumber = citizen.PhoneNumber,
  928. CitizenId = citizen.Id,
  929. }).MergeTable()
  930. .Take(11);
  931. #if DEBUG
  932. var sql = query.ToSqlString();
  933. #endif
  934. var item = await query.ToListAsync();
  935. item.ForEach(m =>
  936. {
  937. if (m.IsSecurityMax)
  938. m.HeadUrl = _systemDicDataCacheManager.HeaderImages("aqws");
  939. else
  940. m.HeadUrl = _systemDicDataCacheManager.HeaderImages("default");
  941. });
  942. if (item.Any(m => m.CitizenId == _sessionContext.UserId) == false)
  943. {
  944. var my = (await _pointsRecordRepository.Queryable()
  945. .LeftJoin<Citizen>((points, citizen) => points.UserId == citizen.Id)
  946. .Where((points, citizen) => points.CreationTime >= startTime && points.CreationTime <= endTime)
  947. .GroupBy((points, citizen) => new { citizen.Id, points.UserId, citizen.IsSecurityMax, citizen.Name, citizen.PhoneNumber })
  948. .Select((points, citizen) => new PointsRankUserDto
  949. {
  950. IsSecurityMax = citizen.IsSecurityMax ?? false,
  951. Rank = SqlFunc.MappingColumn<int>($@" DENSE_RANK() OVER (ORDER BY SUM(CASE WHEN ""points"".""Direction"" = 0 THEN ""points"".""Points"" ELSE 0 END) DESC)"),
  952. Points = SqlFunc.AggregateSum(points.Points),
  953. UserName = citizen.Name!,
  954. PhoneNumber = citizen.PhoneNumber,
  955. CitizenId = citizen.Id,
  956. }).MergeTable()
  957. .ToListAsync()).FirstOrDefault(m => m.CitizenId == _sessionContext.UserId);
  958. if (my != null)
  959. {
  960. item.Insert(0, new PointsRankUserDto
  961. {
  962. UserName = my.UserName,
  963. CitizenId = my.CitizenId,
  964. PhoneNumber = my.PhoneNumber,
  965. Rank = my.Rank,
  966. Points = my.Points,
  967. HeadUrl = _systemDicDataCacheManager.HeaderImages("default"),
  968. IsSecurityMax = false
  969. });
  970. }
  971. else
  972. {
  973. var citizen = await _citizenRepository.GetAsync(_sessionContext.UserId);
  974. var count = await _citizenRepository.CountAsync(m => m.Name != "");
  975. if (citizen != null)
  976. {
  977. item.Insert(0, new PointsRankUserDto
  978. {
  979. UserName = citizen.Name,
  980. CitizenId = citizen.Id,
  981. PhoneNumber = citizen.PhoneNumber,
  982. Rank = count,
  983. Points = 0,
  984. HeadUrl = _systemDicDataCacheManager.HeaderImages("default"),
  985. IsSecurityMax = false
  986. });
  987. }
  988. }
  989. }
  990. else
  991. {
  992. var my = item.First(m => m.CitizenId == _sessionContext.UserId);
  993. item.Remove(my);
  994. item.Insert(0, my);
  995. }
  996. outDto.Ranks = item;
  997. outDto.VideoBulletin = await _notificationReceiverRepository.Queryable()
  998. .LeftJoin<Notification>((receiver, notify) => notify.Id == receiver.NotificationId)
  999. .LeftJoin<SnapshotBulletin>((receiver, notify, bulletin) => bulletin.Id == notify.ExternalId)
  1000. .Where((receiver, notify) => receiver.ReceiverId == _sessionContext.UserId)
  1001. .GroupBy((receiver, notify, bulletin) => new
  1002. {
  1003. notify.Title,
  1004. notify.ExternalId,
  1005. bulletin.SnapshotBulletinTypeName,
  1006. bulletin.VideoCoverImgUrl,
  1007. notify.CreationTime
  1008. })
  1009. .OrderByDescending((receiver, notify) => notify.CreationTime)
  1010. .Select((receiver, notify, bulletin) => new VideoBulletinOutDto
  1011. {
  1012. Title = notify.Title,
  1013. BulletinId = notify.ExternalId,
  1014. UnReadCount = SqlFunc.AggregateSum(SqlFunc.IIF( receiver.IsRead == false, 1, 0)),
  1015. SnapshotBulletinTypeName = bulletin.SnapshotBulletinTypeName,
  1016. VideoCoverImgUrl = bulletin.VideoCoverImgUrl,
  1017. }).FirstAsync();
  1018. outDto.Bulletins = new PointsBulletinOutDto
  1019. {
  1020. Items = await _notificationReceiverRepository.Queryable()
  1021. .LeftJoin<Notification>((receiver, notify) => notify.Id == receiver.NotificationId)
  1022. .Select((receiver, notify) => new PointsBulletinItemsOutDto
  1023. {
  1024. BulletinId = notify.ExternalId,
  1025. Title = notify.Title,
  1026. }, true)
  1027. .Take(2)
  1028. .ToListAsync(),
  1029. UnReadCount = await _notificationReceiverRepository.Queryable()
  1030. .Where(m => m.IsRead == false && m.ReceiverId == _sessionContext.UserId)
  1031. .CountAsync()
  1032. };
  1033. return outDto;
  1034. }
  1035. #endregion
  1036. }