SnapshotApplicationBase.cs 46 KB

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