FlashDeliveryNotificationService.java 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package com.ruoyi.app.flashdelivery.service;
  2. import com.ruoyi.app.order.dto.OrderPushBodyDto;
  3. import com.ruoyi.app.utils.PayPush;
  4. import com.ruoyi.app.utils.event.PushEventService;
  5. import com.ruoyi.common.core.domain.entity.SysDictData;
  6. import com.ruoyi.common.utils.DictUtils;
  7. import com.ruoyi.framework.manager.AsyncManager;
  8. import com.ruoyi.system.domain.InfoUser;
  9. import com.ruoyi.system.domain.RiderPosition;
  10. import com.ruoyi.system.domain.flash.FlashDeliveryOrder;
  11. import com.ruoyi.system.mapper.InfoUserMapper;
  12. import com.ruoyi.system.mapper.RiderPositionMapper;
  13. import org.slf4j.Logger;
  14. import org.slf4j.LoggerFactory;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.stereotype.Service;
  17. import org.springframework.transaction.support.TransactionSynchronization;
  18. import org.springframework.transaction.support.TransactionSynchronizationManager;
  19. import java.util.List;
  20. import java.util.TimerTask;
  21. import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.ACCEPTED;
  22. import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.CANCELLED;
  23. import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.DELIVERED;
  24. import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.PICKED_UP;
  25. import static com.ruoyi.system.domain.flash.FlashDeliveryStatus.WAITING_ACCEPTANCE;
  26. /**
  27. * 闪送订单消息推送:可抢新单推符合条件的骑手,履约事件推寄件用户,取消事件推接单骑手。
  28. * 推送统一在事务提交后异步执行,失败仅记日志,不影响订单状态流转本身。
  29. */
  30. @Service
  31. public class FlashDeliveryNotificationService {
  32. private static final Logger log = LoggerFactory.getLogger(FlashDeliveryNotificationService.class);
  33. private static final String TITLE_KEY = "no.message.push.message";
  34. private static final String CONTENT_ACCEPTED = "no.message.push.delivery.personnel.receiving.order";
  35. private static final String CONTENT_PICKED_UP = "no.message.push.delivery.personnel.qspsz.order";
  36. private static final String CONTENT_DELIVERED = "no.message.push.delivery.personnel.qsysd.order";
  37. private static final String CONTENT_CANCELLED = "no.message.push.order.cancelled";
  38. private static final String CONTENT_AVAILABLE = "no.message.push.new.flash.order";
  39. private static final int RIDER_NOTIFICATION_LIMIT = 20;
  40. /** 推送 payload 的业务类型:1=外卖、2=充值,3=闪送。 */
  41. private static final int PUSH_TYPE_FLASH = 3;
  42. /** -1 表示非语音提醒;0 表示骑手新单提醒。 */
  43. private static final int PUSH_PAYLOAD_TYPE_NONE = -1;
  44. private final InfoUserMapper userMapper;
  45. private final PushEventService pushEventService;
  46. private final RiderPositionMapper riderPositionMapper;
  47. public FlashDeliveryNotificationService(InfoUserMapper userMapper, PushEventService pushEventService) {
  48. this(userMapper, pushEventService, null);
  49. }
  50. @Autowired
  51. public FlashDeliveryNotificationService(InfoUserMapper userMapper, PushEventService pushEventService,
  52. RiderPositionMapper riderPositionMapper) {
  53. this.userMapper = userMapper;
  54. this.pushEventService = pushEventService;
  55. this.riderPositionMapper = riderPositionMapper;
  56. }
  57. /** 按订单取寄件用户;订单或用户缺失时静默跳过。 */
  58. InfoUser senderOf(FlashDeliveryOrder order) {
  59. if (order == null || order.getUserId() == null) return null;
  60. return userMapper.selectById(order.getUserId());
  61. }
  62. /** 按订单取接单骑手;未接单(riderId 为空)或骑手缺失时静默跳过。 */
  63. InfoUser riderOf(FlashDeliveryOrder order) {
  64. if (order == null || order.getRiderId() == null) return null;
  65. return userMapper.selectById(order.getRiderId());
  66. }
  67. /** 向寄件用户推送指定状态文案;消息入库由通道内 PublisherEvent 完成,cid 为空时仅入库。 */
  68. void sendToUser(InfoUser recipient, FlashDeliveryOrder order, String status, String contentKey) {
  69. if (recipient == null || recipient.getUserId() == null) return;
  70. String orderNo = order.getOrderNo();
  71. String body = OrderPushBodyDto.getJson(orderNo, status, PUSH_PAYLOAD_TYPE_NONE, PUSH_TYPE_FLASH);
  72. AsyncManager.me().execute(new TimerTask() {
  73. @Override
  74. public void run() {
  75. try {
  76. PayPush.userPushHandleLocal(new PayPush(), pushEventService, recipient.getUserId(),
  77. recipient.getCid(), TITLE_KEY, contentKey, body, "", orderNo);
  78. } catch (Exception e) {
  79. log.error("闪送用户推送失败,userId:{}, orderNo:{}", recipient.getUserId(), orderNo, e);
  80. }
  81. }
  82. });
  83. }
  84. /** 向接单骑手推送指定状态文案;与用户端一致,失败仅记日志。 */
  85. void sendToRider(InfoUser recipient, FlashDeliveryOrder order, String status, String contentKey) {
  86. sendToRider(recipient, order, status, contentKey, PUSH_PAYLOAD_TYPE_NONE);
  87. }
  88. private void sendToRider(InfoUser recipient, FlashDeliveryOrder order, String status,
  89. String contentKey, int payloadType) {
  90. if (recipient == null || recipient.getUserId() == null) return;
  91. String orderNo = order.getOrderNo();
  92. String body = OrderPushBodyDto.getJson(orderNo, status, payloadType, PUSH_TYPE_FLASH);
  93. AsyncManager.me().execute(new TimerTask() {
  94. @Override
  95. public void run() {
  96. try {
  97. PayPush.qsPushHandleLocal(new PayPush(), pushEventService, recipient.getUserId(),
  98. recipient.getCid(), TITLE_KEY, contentKey, body, "", orderNo);
  99. } catch (Exception e) {
  100. log.error("闪送骑手推送失败,riderId:{}, orderNo:{}", recipient.getUserId(), orderNo, e);
  101. }
  102. }
  103. });
  104. }
  105. /** 向一名可接单骑手发送闪送新单提醒;type=0 保留骑手端新单语音语义。 */
  106. void sendAvailableOrderToRider(RiderPosition rider, FlashDeliveryOrder order) {
  107. if (rider == null || rider.getRiderId() == null) return;
  108. InfoUser recipient = new InfoUser();
  109. recipient.setUserId(rider.getRiderId());
  110. recipient.setCid(rider.getCid());
  111. sendToRider(recipient, order, WAITING_ACCEPTANCE, CONTENT_AVAILABLE, 0);
  112. }
  113. /** 订单已向骑手开放后,通知附近最多 20 名符合闪送接单条件的骑手。 */
  114. public void notifyAvailable(FlashDeliveryOrder order) {
  115. if (order == null || riderPositionMapper == null || !WAITING_ACCEPTANCE.equals(order.getStatus())
  116. || !Boolean.TRUE.equals(order.getIsDisplay()) || order.getRiderId() != null
  117. || order.getPickupLongitude() == null || order.getPickupLatitude() == null) {
  118. return;
  119. }
  120. runAfterCommit(() -> {
  121. int vehicleType = Integer.valueOf(2).equals(order.getVehicleType()) ? 2 : 1;
  122. List<RiderPosition> riders = riderPositionMapper.getFlashRiderNotificationList(
  123. order.getPickupLongitude(), order.getPickupLatitude(), vehicleType,
  124. order.getDeliveryType(), newTaskDistanceLimit(), RIDER_NOTIFICATION_LIMIT);
  125. if (riders != null) {
  126. riders.forEach(rider -> sendAvailableOrderToRider(rider, order));
  127. }
  128. });
  129. }
  130. /** 骑手抢单成功后通知寄件用户;未解析到寄件用户时跳过。 */
  131. public void notifyAccepted(FlashDeliveryOrder order) {
  132. runAfterCommit(() -> {
  133. InfoUser sender = senderOf(order);
  134. if (sender != null) sendToUser(sender, order, ACCEPTED, CONTENT_ACCEPTED);
  135. });
  136. }
  137. /** 骑手取件成功后通知寄件用户;未解析到寄件用户时跳过。 */
  138. public void notifyPickedUp(FlashDeliveryOrder order) {
  139. runAfterCommit(() -> {
  140. InfoUser sender = senderOf(order);
  141. if (sender != null) sendToUser(sender, order, PICKED_UP, CONTENT_PICKED_UP);
  142. });
  143. }
  144. /** 骑手送达后通知寄件用户;未解析到寄件用户时跳过。 */
  145. public void notifyDelivered(FlashDeliveryOrder order) {
  146. runAfterCommit(() -> {
  147. InfoUser sender = senderOf(order);
  148. if (sender != null) sendToUser(sender, order, DELIVERED, CONTENT_DELIVERED);
  149. });
  150. }
  151. /** 订单取消后通知接单骑手;未接单(无骑手归属)或骑手缺失时跳过,寄件用户不推。 */
  152. public void notifyCancelled(FlashDeliveryOrder order) {
  153. runAfterCommit(() -> {
  154. InfoUser rider = riderOf(order);
  155. if (rider != null) sendToRider(rider, order, CANCELLED, CONTENT_CANCELLED);
  156. });
  157. }
  158. /** 仅事务提交后执行推送准备;无事务同步时(单测)直接执行。 */
  159. static void runAfterCommit(Runnable action) {
  160. if (!TransactionSynchronizationManager.isSynchronizationActive()) {
  161. action.run();
  162. return;
  163. }
  164. TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  165. @Override
  166. public void afterCommit() {
  167. action.run();
  168. }
  169. });
  170. }
  171. private Integer newTaskDistanceLimit() {
  172. try {
  173. List<SysDictData> values = DictUtils.getDictCache("sys_qs_newtask_distance");
  174. if (values != null && !values.isEmpty()) {
  175. int limit = Integer.parseInt(values.get(0).getDictValue());
  176. return limit > 0 ? limit : null;
  177. }
  178. } catch (Exception ignored) {
  179. // 与骑手新任务列表保持一致:缺失或非法配置时不限制距离。
  180. }
  181. return null;
  182. }
  183. }