package com.ruoyi.app.order; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ruoyi.app.order.dto.OrderPushBodyDto; import com.ruoyi.app.service.UserService; import com.ruoyi.app.utils.PayPush; import com.ruoyi.app.utils.event.PushEventService; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.system.domain.InfoUser; import com.ruoyi.system.domain.PosOrder; import com.ruoyi.system.domain.PosStore; import com.ruoyi.system.domain.UserBilling; import com.ruoyi.system.service.IInfoUserService; import com.ruoyi.system.service.IPosOrderService; import com.ruoyi.system.service.IPosStoreService; import com.ruoyi.system.service.IUserBillingService; import com.ruoyi.system.utils.Auth; import com.ruoyi.system.utils.JwtUtil; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.web.bind.annotation.*; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @RestController @RequestMapping("/system/orderQsOprate") public class PosOrderQsOprateController extends BaseController { @Autowired private IPosOrderService posOrderService; @Autowired private IInfoUserService infoUserService; @Autowired private PushEventService pushEventService; @Autowired private RedissonClient redissonClient; @Autowired private UserService userService; @Autowired private IUserBillingService userBillingService; @Autowired private IPosStoreService posStoreService; /** * 骑手接单:校验 type=0 且 afterSaleStatus=0,设置 deliveryStatus=1 */ @Anonymous @Auth @PostMapping("/acceptOrder") @Transactional(rollbackFor = Exception.class) public AjaxResult acceptOrder(@RequestHeader String token, @RequestParam Long id) { JwtUtil jwtUtil = new JwtUtil(); PayPush push = new PayPush(); String qsId = jwtUtil.getusid(token); PosOrder order = posOrderService.getOne(new LambdaQueryWrapper().eq(PosOrder::getId, id)); if (order == null) { throw new ServiceException(MessageUtils.message("no.order.not.found")); } if (order.getType() != null && order.getType() != 0L) { throw new ServiceException("仅外送订单支持骑手接单"); } if (order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0) { throw new ServiceException("订单存在售后申请,无法操作"); } PosOrder posOrder = new PosOrder(); posOrder.setId(order.getId()); posOrder.setDeliveryStatus(1L); posOrder.setQsId(Long.valueOf(qsId)); return setOrderQsState(posOrder, qsId, push); } /** * 骑手取餐:校验 type=0 且 afterSaleStatus=0,设置 deliveryStatus=2 */ @Anonymous @Auth @PostMapping("/pickupOrder") @Transactional(rollbackFor = Exception.class) public AjaxResult pickupOrder(@RequestHeader String token, @RequestParam Long id) { JwtUtil jwtUtil = new JwtUtil(); PayPush push = new PayPush(); String qsId = jwtUtil.getusid(token); PosOrder order = posOrderService.getOne(new LambdaQueryWrapper().eq(PosOrder::getId, id)); if (order == null) { throw new ServiceException(MessageUtils.message("no.order.not.found")); } if (order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0) { throw new ServiceException("订单存在售后申请,无法操作"); } PosOrder posOrder = new PosOrder(); posOrder.setId(order.getId()); posOrder.setDeliveryStatus(2L); return setOrderQsState(posOrder, qsId, push); } /** * 骑手送达:设置 deliveryStatus=3,同时设置 state=3 */ @Anonymous @Auth @PostMapping("/deliverOrder") @Transactional(rollbackFor = Exception.class) public AjaxResult deliverOrder(@RequestHeader String token, @RequestParam Long id) { JwtUtil jwtUtil = new JwtUtil(); PayPush push = new PayPush(); String qsId = jwtUtil.getusid(token); PosOrder order = posOrderService.getOne(new LambdaQueryWrapper().eq(PosOrder::getId, id)); if (order == null) { throw new ServiceException(MessageUtils.message("no.order.not.found")); } PosOrder posOrder = new PosOrder(); posOrder.setId(order.getId()); posOrder.setDeliveryStatus(3L); posOrder.setState(3L); posOrder.setSdTime(new Date()); return setOrderQsState(posOrder, qsId, push); } //骑手接单、取餐、送达 private AjaxResult setOrderQsState(PosOrder posOrder, String qsId, PayPush push) { String lockKey = "order:qs:lock:" + posOrder.getId(); RLock lock = redissonClient.getLock(lockKey); try { var local = LocaleContextHolder.getLocale(); logger.info("骑手接单local信息:" + local.getLanguage()); logger.info(JSON.toJSONString(local)); // 尝试获取锁 if (lock.tryLock(20L, 10L, TimeUnit.SECONDS)) { boolean releaseInfinally = true; try { userService.checkUserStatus(Long.valueOf(qsId)); PosOrder orst = posOrderService.getById(posOrder.getId()); if (orst.getDeliveryStatus() != null && orst.getDeliveryStatus() == 1L && posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) { throw new ServiceException(MessageUtils.message("no.order.snatched")); } if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("qs_id", qsId); wrapper.in("delivery_status", 1, 2); List orsts = posOrderService.list(wrapper); if (orsts.size() > 0) { throw new ServiceException(MessageUtils.message("no.exist.undelivered.order")); } } String userMessage = MessageUtils.message("no.message.push.delivery.personnel.receiving.order"); if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 2L) { userMessage = MessageUtils.message("no.message.push.delivery.personnel.qspsz.order"); } else if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L) { userMessage = MessageUtils.message("no.message.push.delivery.personnel.qsysd.order"); } boolean org = posOrderService.saveOrUpdate(posOrder); if (org) { //到付订单,骑手送达时设置用户账单为完成 if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L && "1".equals(orst.getCollectPayment())) { updateUserBill(orst.getDdId(), orst.getUserId(), orst.getQsId()); } InfoUser user = infoUserService.getById(orst.getUserId()); InfoUser shu = infoUserService.getById(orst.getShId()); String finalUserMessage = userMessage; releaseInfinally = false; TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { if (lock.isHeldByCurrentThread()) { lock.unlock(); } // 给用户推送(骑手已接单/配送中/已送达) if (!StringUtils.isEmpty(user.getCid())) { String userTitle = "no.message.push.message"; String userContent = "no.message.push.delivery.personnel.receiving.order"; if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 2L) { userContent = "no.message.push.delivery.personnel.qspsz.order"; } else if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L) { userContent = "no.message.push.delivery.personnel.qsysd.order"; } final String finalUserContent = userContent; String userBody = OrderPushBodyDto.getJson(String.valueOf(orst.getDdId()), String.valueOf(posOrder.getState())); Long userUserId = user.getUserId(); String userCid = user.getCid(); String userCidType = ""; String userDdId = String.valueOf(orst.getDdId()); AsyncManager.me().execute(new TimerTask() { @Override public void run() { PayPush.userPushHandleLocal(push, pushEventService, userUserId, userCid, userTitle, finalUserContent, userBody, userCidType, userDdId); } }); } // 给商家推送(骑手已接单时) if (!StringUtils.isEmpty(shu.getCid()) && posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) { String shTitle = "no.message.push.message"; String shContent = "no.message.push.delivery.personnel.receiving.order"; String shBody = OrderPushBodyDto.getJson(String.valueOf(orst.getDdId()), String.valueOf(posOrder.getState())); Long shUserId = shu.getUserId(); String shCid = shu.getCid(); String shCidType = ""; String shDdId = String.valueOf(orst.getDdId()); AsyncManager.me().execute(new TimerTask() { @Override public void run() { PayPush.shPushHandleLocal(push, pushEventService, shUserId, shCid, shTitle, shContent, shBody, shCidType, shDdId); } }); } } }); return success(MessageUtils.message("no.modify.success"), posOrder.getId()); } else { return error(); } } finally { if (releaseInfinally && lock.isHeldByCurrentThread()) { lock.unlock(); } } } else { throw new ServiceException(MessageUtils.message("no.system.busy.try.again")); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again")); } } /** * 更新用户用户账单 * * @param ddId * @param userId * @param qsId */ private void updateUserBill(String ddId, Long userId, Long qsId) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("dd_id", ddId); queryWrapper.eq("user_id", userId); queryWrapper.eq("type", "3"); UserBilling userBill = userBillingService.getOne(queryWrapper); if (userBill != null) { userBill.setState("0"); userBill.setIllustrate("Rider Payment Order"); userBill.setBalancePay("1"); userBill.setPaymentId(String.valueOf(qsId)); userBillingService.saveOrUpdate(userBill); } } /** * 骑手端订单列表(Tab分页) */ @Anonymous @Auth @GetMapping("/orderList") public AjaxResult orderList(@RequestHeader String token, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) String tab, @RequestParam(required = false) java.math.BigDecimal longitude, @RequestParam(required = false) java.math.BigDecimal latitude) { JwtUtil jwtUtil = new JwtUtil(); String qsId = jwtUtil.getusid(token); Long riderId = Long.valueOf(qsId); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(PosOrder::getIsDisplay,true); switch (tab) { case "newTask": wrapper.eq(PosOrder::getType, 0L).eq(PosOrder::getDeliveryStatus, 0L).eq(PosOrder::getState, 2L).eq(PosOrder::getAfterSaleStatus, 0L); if (longitude != null && latitude != null) { wrapper.last("ORDER BY ST_Distance_Sphere(point(longitude, latitude), point(" + longitude + ", " + latitude + ")) ASC"); } else { wrapper.orderByDesc(PosOrder::getCretim); } break; case "toPickup": wrapper.eq(PosOrder::getDeliveryStatus, 1L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByAsc(PosOrder::getCretim); break; case "delivering": wrapper.eq(PosOrder::getDeliveryStatus, 2L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByAsc(PosOrder::getCretim); break; case "completed": wrapper.eq(PosOrder::getState, 3L).eq(PosOrder::getAfterSaleStatus, 0L).eq(PosOrder::getQsId, riderId).orderByDesc(PosOrder::getCretim); break; case "cancelled": wrapper.eq(PosOrder::getState, 4L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByDesc(PosOrder::getCretim); break; case "refund": wrapper.gt(PosOrder::getAfterSaleStatus, 0L).eq(PosOrder::getQsId, riderId).orderByDesc(PosOrder::getCretim); break; default: break; } com.baomidou.mybatisplus.extension.plugins.pagination.Page pageParam = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page, size); com.baomidou.mybatisplus.extension.plugins.pagination.Page result = posOrderService.page(pageParam, wrapper); Set mdIds = result.getRecords().stream().map(PosOrder::getMdId).filter(Objects::nonNull).collect(Collectors.toSet()); Map storeMap = mdIds.isEmpty() ? Collections.emptyMap() : posStoreService.listByIds(mdIds).stream().collect(Collectors.toMap(PosStore::getId, s -> s)); JSONArray arr=new JSONArray(); for (PosOrder order : result.getRecords()) { // 自动序列化所有PosOrder字段,新增字段无需手动添加 JSONObject org = JSON.parseObject( JSON.toJSONStringWithDateFormat(order, "yyyy-MM-dd HH:mm:ss") ); // 以下为非PosOrder字段或需要特殊处理的字段 org.put("store", storeMap.get(order.getMdId().intValue())); arr.add(org); } JSONObject org=new JSONObject(); org.put("records",arr); org.put("total",result.getTotal()); org.put("current",result.getCurrent()); return success(org); } }