package com.xiaopeng.order.controller; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.DesensitizedUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xiaopeng.api.dto.QueryOrderRouteDTO; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.order.GetOrderNumDto; import com.xiaopeng.api.dto.order.PopOrderDto; import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; import com.xiaopeng.api.feignClient.account.SysGroupMenuClient; import com.xiaopeng.api.feignClient.operation.XpWhiteListClient; import com.xiaopeng.api.feignClient.vehicleConvoy.VehicleMacClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.operation.XpOfficialPartner; import com.xiaopeng.api.model.operation.XpWhitelist; import com.xiaopeng.api.model.order.XpOrder; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.account.LoginUser; import com.xiaopeng.api.vo.operation.NavigationVo; import com.xiaopeng.api.vo.operation.NearestNextVo; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.api.vo.order.*; import com.xiaopeng.api.vo.vehicleConvoy.GetBleInfoVo; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.core.utils.WebUtils; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.common.log.annotation.AdminOperationLog; import com.xiaopeng.common.log.enums.AdminBusinessType; import com.xiaopeng.common.log.enums.AdminOperationType; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.common.security.service.TokenService; import com.xiaopeng.order.config.BluetoothDebugConfig; import com.xiaopeng.order.dto.OrderNavigationDto; import com.xiaopeng.api.model.order.OrderTrajectory; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderOperateDTO; import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.dto.XpOrderReassignDTO; import com.xiaopeng.order.model.exportExcel.XpOrderExportExcel; import com.xiaopeng.order.model.query.XpHistoryOrderListQuery; import com.xiaopeng.order.model.query.XpOrderExcelQuery; import com.xiaopeng.order.model.query.XpOrderPageQuery; import com.xiaopeng.order.model.vo.XpOrderDetailVO; import com.xiaopeng.order.model.vo.XpOrderHistoryVO; import com.xiaopeng.order.model.vo.XpOrderPageVO; import com.xiaopeng.order.service.IXpOrderService; import com.xiaopeng.order.vo.BluetoothTokenVo; import com.xiaopeng.order.vo.OrderDetailVo; import com.xiaopeng.order.vo.UpdateOrderStatusVo; import com.xiaopeng.order.vo.XpOrderInfoVo; import com.xiaopeng.unifiedverification.interceptor.XpClientCheck; import io.swagger.annotations.*; import lombok.RequiredArgsConstructor; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.util.CollectionUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.*; import java.util.stream.Collectors; /** *

* 订单 前端控制器 *

* * @author mitao * @since 2026-02-03 */ @RestController @Api(tags = "订单") @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpOrderController { private final IXpOrderService xpOrderService; private final RedisService redisService; @Autowired private MongoTemplate mongoTemplate; @Resource private XpVehicleClient xpVehicleClient; @Resource private VehicleMacClient vehicleMacClient; @Resource private SysGroupMenuClient groupMenuClient; @Resource private XpWhiteListClient xpWhiteListClient; @Resource private TokenService tokenService; @Autowired private BluetoothDebugConfig bluetoothDebugConfig; /** * 获取订单统计数据(内部接口) * * @param query 查询参数 * @return 订单统计数据 */ @ApiOperation(value = "获取订单统计数据", tags = {"内部接口"}) @PostMapping("/logan/inner/order/statistics") public R getOrderStatistics(@RequestBody StatisticsQueryDTO query) { return R.ok(xpOrderService.getOrderStatistics(query)); } /** * 查询是否有未支付订单 或 正在进行的订单 * 返回0 可以下单 1有进行中的订单 8有待支付的 */ @PostMapping("/logan/inner/order/has-unpaid-order") @ApiOperation(value = "查询是否有未支付订单 或 正在进行的订单", tags = {"内部接口"}) public R hasUnPaodOrder(String uid) { List list = xpOrderService.list(new LambdaQueryWrapper().eq(XpOrder::getAppUserId, Long.parseLong(uid)).in(XpOrder::getStatus, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8))); if (!list.isEmpty()) { return R.ok(list.get(0).getId()); } return R.ok(0L); } /** * 查询是否有未支付订单 * 返回0 可以下单,非0为未支付订单ID */ @PostMapping("/logan/inner/order/has-unpay-order") @ApiOperation(value = "查询是否有未支付订单", tags = {"内部接口"}) public R hasUnPayOrder(String uid) { XpOrder order = xpOrderService.getOne(new LambdaQueryWrapper() .eq(XpOrder::getAppUserId, Long.parseLong(uid)) .eq(XpOrder::getStatus, 8) .last("LIMIT 1")); if (order != null) { return R.ok(order.getId()); } return R.ok(0L); } /** * 通过订单id查询订单信息 * * @param orderId 订单id * @return 订单详情 */ @PostMapping("/logan/inner/order/queryOrderById") public R queryOrderById(@RequestParam Long orderId) { return R.ok(xpOrderService.getById(orderId)); } @PostMapping("/logan/inner/order/queryOrderByOrderNo") public R queryOrderByOrderNo(@RequestParam String orderNo) { return R.ok(xpOrderService.getOne(new LambdaQueryWrapper().eq(XpOrder::getOrderNumber, orderNo))); } /** * 获取订单数量 * * @return 订单数量 */ @PostMapping("/logan/inner/order/getOrderNum") public R getOrderNum(@RequestBody GetOrderNumDto dto) { return R.ok(xpOrderService.getOrderNum(dto)); } /** * 查询指定城市进行中的订单数量(status=1) * * @param cityId 开通城市ID * @return 进行中订单数量 */ @GetMapping("/logan/inner/order/countActiveOrders") public R countActiveOrdersByCityId(@RequestParam("cityId") Long cityId) { return R.ok(xpOrderService.countActiveOrdersByCityId(cityId)); } /** * 成功操作下发命令后调用 用于弹出redis队列的获取成功的数据 */ @PostMapping("/logan/inner/order/popOrder") public R popOrder(@RequestBody PopOrderDto dto) { xpOrderService.popOrder(dto); return R.ok(); } /** * 修改订单信息 * * @param xpOrder 订单信息 */ @PostMapping("/logan/inner/order/updateOrder") public R updateOrder(@RequestBody XpOrder xpOrder) { xpOrder.setAppUserId(null); return xpOrderService.updateById(xpOrder) ? R.ok() : R.fail(); } /** * 新增订单 * * @param xpOrder 订单信息 * @return 订单ID */ @PostMapping("/logan/inner/order/addOrder") public R addOrder(@RequestBody XpOrder xpOrder) { boolean save = xpOrderService.addOrder(xpOrder); if (!save) { return R.fail("新增失败"); } return R.ok(xpOrder.getId()); } /** * 取消订单 * * @param orderId 订单ID * @return 操作结果 */ @PostMapping("/logan/inner/order/cancelOrder") public R cancelOrder(@RequestParam("orderId") String orderId) { xpOrderService.cancelOrder(orderId); return R.ok(); } /** * 订单分页列表 * * @param query 分页查询参数 * @return 分页结果 */ @ApiOperation(value = "订单分页列表", tags = {"管理后台-交易管理-订单管理", "管理后台-活动管理"}) @PostMapping("/api/v1/order/pageList") public R> pageList( @RequestBody XpOrderPageQuery query) { LoginUser loginUser = tokenService.getLoginUser(); PageInfo pageInfo = xpOrderService.pageList(query); if(!loginUser.getPhoneDesensitizationExempt()){ pageInfo.getRecords().forEach(s->s.setPhoneNumber(DesensitizedUtil.mobilePhone(s.getPhoneNumber()))); } return R.ok(pageInfo); } /** * 订单详情 * * @param id 订单ID * @return 订单详情 */ @ApiOperation(value = "订单详情", tags = {"管理后台-交易管理-订单管理"}) @GetMapping("/api/v1/order/queryById") public R queryById(@ApiParam(value = "订单id", required = true) @RequestParam Long id) { LoginUser loginUser = tokenService.getLoginUser(); XpOrderDetailVO detail = xpOrderService.getOrderDetail(id); if(!loginUser.getPhoneDesensitizationExempt()){ detail.setPhoneNumber(DesensitizedUtil.mobilePhone(detail.getPhoneNumber())); } return R.ok(detail); } /** * 删除订单 * * @param id 订单ID * @return 操作结果 */ @ApiOperation(value = "删除订单", tags = {"管理后台-交易管理-订单管理"}) @DeleteMapping("/api/v1/order/deleteById") public R deleteById(@ApiParam(value = "订单id", required = true) @RequestParam Long id) { xpOrderService.deleteOrder(id); return R.ok(); } /** * 订单导出 * * @param query 查询参数 */ @ApiOperation(value = "订单导出", tags = {"管理后台-交易管理-订单管理"}) @PostMapping("/api/v1/order/exportExcel") public void exportExcel(@RequestBody XpOrderExcelQuery query) { // 1. 查询导出数据 List dataList = xpOrderService.exportList(query); // 2. 转换为导出对象 List exportList = BeanUtil.copyToList(dataList, XpOrderExportExcel.class); // 3. 生成 Excel Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), XpOrderExportExcel.class, exportList); // 4. 输出到响应流 HttpServletResponse response = WebUtils.response(); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); ServletOutputStream outputStream = null; try { String fileName = URLEncoder.encode("订单列表.xls", "utf-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName); outputStream = response.getOutputStream(); workbook.write(outputStream); } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * 取消/关闭订单 * * @param dto 操作请求参数 * @return 操作结果 */ @ApiOperation(value = "取消/关闭订单", tags = {"管理后台-交易管理-订单管理"}) @PostMapping("/api/v1/order/cancelAndCloseById") public R cancelAndCloseById(@Validated @RequestBody XpOrderOperateDTO dto) { xpOrderService.cancelOrCloseOrder(dto.getOrderId(), dto.getType(),dto.getIsFree()); return R.ok(); } /** * 改派订单 * * @param dto 改派请求参数 * @return 操作结果 */ @ApiOperation(value = "改派订单", tags = {"管理后台-交易管理-订单管理"}, notes = "车辆列表在 vehicleConvoy.availableList 服务") @PostMapping("/api/v1/order/reassignById") public R reassignById(@Validated @RequestBody XpOrderReassignDTO dto) { xpOrderService.reassignOrder( dto.getOrderId(), dto.getVehicleId(), dto.getReassignReason() ); return R.ok(); } @ApiOperation(value = "订单改价", tags = {"管理后台-交易管理-订单管理"}) @PostMapping("/api/v1/order/changeAmount") @ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "订单ID", required = true, dataType = "Long"), @ApiImplicitParam(name = "amount", value = "新的订单金额", required = true, dataType = "BigDecimal") }) public R changeAmount(@RequestParam("id") Long id, @RequestParam("amount") BigDecimal amount) { xpOrderService.changeAmount(id, amount); return R.ok(); } /** * 获取用户快捷胶囊 历史 时段 终点高点 */ @ApiOperation(value = "获取首页快捷胶囊推荐站点", notes = "根据当前起点和用户近30天有效订单,按场景优先推荐目的地;无匹配时返回空数据", tags = {"小程序-首页快捷胶囊"}, response = XpPointInfoVo.class) @ApiImplicitParams({ @ApiImplicitParam(name = "startPointId", value = "当前首页起点站点ID", required = true, dataType = "Long", paramType = "query") }) @GetMapping("/api/v1/mini-program/order/getUserQuickCapsule") @XpClientCheck(checkToken = false, checkOtpToken = true) public R getUserQuickCapsule(@RequestParam Long startPointId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getUserQuickCapsule(uid, startPointId)); } /** * 获取用户快捷胶囊 历史 时段 终点高点 */ @ApiOperation(value = "获取首页快捷胶囊推荐站点", notes = "根据当前起点和用户近30天有效订单,按场景优先推荐目的地;无匹配时返回空数据", tags = {"小程序-首页快捷胶囊"}, response = XpPointInfoVo.class) @ApiImplicitParams({ @ApiImplicitParam(name = "startPointId", value = "当前首页起点站点ID", required = true, dataType = "Long", paramType = "query") }) @GetMapping("/api/v1/mini-program/order/quick-capsule") @XpClientCheck(checkToken = false, checkOtpToken = true) public R quickCapsule(@RequestParam Long startPointId,HttpServletRequest request) { String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.quickCapsule(uid,startPointId)); } /** * 获取订单详情 */ @PutMapping("/api/v1/mini-program/order/orderDetail/{orderId}") @ApiOperation(value = "获取订单详情", tags = {"小程序-获取订单详情"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R orderDetail(@PathVariable("orderId") Long orderId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); OrderDetailVo orderDetailVo = xpOrderService.orderDetail(orderId, uid); BigDecimal orderMoney = orderDetailVo.getOrderMoney(); if (orderMoney == null) { orderDetailVo.setOrderMoneyStr("0.00"); } else { orderDetailVo.setOrderMoneyStr(orderMoney.setScale(2, RoundingMode.HALF_UP).toString()); } return R.ok(orderDetailVo); } /** * 获取历史下单成功起点10条数据列表 */ @ApiOperation(value = "获取历史下单成功起点10条数据列表", tags = {"小程序-获取历史下单成功起点10条数据列表"}) @GetMapping("/base/v1/mini-program/history/startPoints") @XpClientCheck(checkToken = false, checkOtpToken = true) public R> getHistoryStartPoints(double lon, double lat, Long electronicAreaId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getHistoryStartPoints(uid, lon, lat, electronicAreaId)); } /** * 获取历史下单成功终点点10条数据列表 */ @ApiOperation(value = "获取历史下单成功终点10条数据列表", tags = {"小程序-获取历史下单成功终点10条数据列表"}) @GetMapping("/base/v1/mini-program/history/endPoints") @XpClientCheck(checkToken = false, checkOtpToken = true) public R> getHistoryEndPoints(double lon, double lat, Long electronicAreaId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getHistoryEndPoints(uid, lon, lat, electronicAreaId)); } /** * 获取正在进行中的订单 */ @ApiOperation(value = "获取正在进行中的订单", tags = {"小程序-获取正在进行中的订单"}) @GetMapping("/api/v1/mini-program/order/active") @XpClientCheck(checkToken = false, checkOtpToken = true) public R getActiveOrder(HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getActiveOrder(uid)); } /** * 获取正在进行中的订单_行程管理 */ @ApiOperation(value = "获取正在进行中的订单_行程管理", tags = {"小程序-获取正在进行中的订单_行程管理"}) @GetMapping("/api/v1/mini-program/order/active_itineraryManage") @XpClientCheck(checkToken = false, checkOtpToken = true) public R getActiveOrder_itineraryManage(HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getActiveOrder_itineraryManage(uid)); } /** * 查询历史订单列表 */ @ApiOperation(value = "查询历史订单列表", tags = {"小程序-查询历史订单列表"}) @PostMapping("/api/v1/mini-program/order/history/list") @XpClientCheck(checkToken = false, checkOtpToken = true) public R getHistoryOrderList(@RequestBody XpHistoryOrderListQuery query, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getHistoryOrderList(query, uid)); } /** * 1.0 获取待支付订单数量 */ @ApiOperation(value = "1.0 获取待支付订单数量", tags = {"小程序-1.0 获取待支付订单数量"}) @GetMapping("/api/v1/mini-program/order/getWaitPayOrderNum") @XpClientCheck(checkToken = false, checkOtpToken = true) public R getWaitPayOrderNum(HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.getWaitPayOrderNum(uid)); } /** * + * 取消订单 */ @PutMapping("/api/v1/mini-program/order/cancel/{orderId}") @ApiOperation(value = "取消订单", tags = {"小程序-取消订单"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R cancelOrder(@PathVariable("orderId") Long orderId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); xpOrderService.cancelOrder(orderId, uid); return R.ok(); } /** * + * 手动结束订单 */ @PutMapping("/api/v1/mini-program/order/endTrip/{orderId}") @ApiOperation(value = "结束行程", tags = {"小程序-结束行程"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R endTrip(@PathVariable("orderId") Long orderId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); try { Boolean b = xpOrderService.endTrip(orderId, uid); return R.ok(b); } catch (Exception e) { return R.ok(); } } /** * + * 获取行程费用明细 */ @PostMapping("/api/v1/mini-program/order/fare-breakdown") @ApiOperation(value = "获取行程费用明细", tags = {"小程序-获取行程费用明细"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R fareBreakdown(@RequestBody com.xiaopeng.order.vo.FareBreakdownVo vo, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return xpOrderService.fareBreakdown(vo, uid); } /** * + * 获取行程费用明细 */ @PutMapping("/api/v1/mini-program/order/feeDescription/{orderId}") @ApiOperation(value = "获取费用说明", tags = {"小程序-获取费用说明"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R feeDescription(@PathVariable("orderId") Long orderId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return xpOrderService.feeDescription(orderId, uid); } /** * 订单评价 */ @PostMapping("/api/v1/mini-program/order/payment") @ApiOperation(value = "发起支付", tags = {"小程序-发起支付"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R payment(@Validated @RequestBody XpOrderPayDto dto, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return xpOrderService.payment(dto, uid); } /** * 订单评价 */ @PostMapping("/api/v1/mini-program/order/comment") @ApiOperation(value = "订单评价", tags = {"小程序-订单评价"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R comment(@Validated @RequestBody XpOrderCommentDto dto, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); xpOrderService.comment(dto, uid); return R.ok(); } /** * 订单状态修改-车控消息推送我方调用(内部接口) */ @ApiOperation(value = "订单状态推送修改") @PostMapping("/logan/inner/v1/order/updateOrderStatus") public R updateOrderStatus(@RequestParam Long orderId, @RequestParam Integer status, @RequestParam Boolean orderException) { return xpOrderService.updateOrderStatus(orderId, status, orderException); } /** * 行驶中车辆异常,订单状态修改- 修改状态=7 再修改 金额-再将状态修改成8 */ @ApiOperation(value = "行驶中车辆异常,订单状态修改- 修改状态=7 再修改 金额-再将状态修改成8") @PostMapping("/logan/inner/v1/order/carAbnormalUpdateOrderStatus") public R carAbnormalUpdateOrderStatus(@RequestParam Long orderId) { // Integer status = OrderStatusEnum.SEE_OFF_GUESTS.getCode(); return xpOrderService.carAbnormalUpdateOrderStatus(orderId); } /** * 业务流程-通过订单id查询车辆信息 */ @ApiOperation(value = "通过订单id查询车辆信息", tags = {"小程序-业务流程"}) @XpClientCheck(checkToken = false, checkOtpToken = true) @GetMapping("/api/v1/mini-program/order/queryVehicleByOrderId") public R queryVehicleByOrderId(@RequestParam Long orderId, HttpServletRequest request) { String uid = request.getHeader("XP-Uid"); return R.ok(xpOrderService.queryVehicleByOrderId(orderId, uid)); } /** * 订单车辆定位实时存储-订单车辆定位实时存储(内部接口) */ @ApiOperation(value = "订单车辆定位实时存储") @PostMapping("/logan/inner/v1/order/saveVehicleLocation") public R saveVehicleLocation(@RequestBody OrderTrajectoryVo vo) { OrderTrajectory orderTrajectory = new OrderTrajectory(); BeanUtils.copyProperties(vo, orderTrajectory); xpOrderService.saveVehicleLocation(orderTrajectory); return R.ok(); } /** * 订单查询实时轨迹路线 */ @ApiOperation(value = "订单查询实时轨迹路线") @PostMapping("/api/v1/mini-program/order/queryOrderRoute") @XpClientCheck(checkToken = false, checkOtpToken = true) public R queryOrderRoute(@Validated @RequestBody QueryOrderRouteDTO dto, HttpServletRequest request) { if (dto.getOrderId() == null) { return R.fail("参数不能为空"); } String uid = request.getHeader("XP-Uid"); // 查询订单信息 XpOrder xpOrder = xpOrderService.getById(dto.getOrderId()); // 获取路线规划 // RouteVo routeVo = redisService.getCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType()); String key = ""; //接驾情况,获取车辆位置到起点的导航 if (xpOrder.getStatus() < 5) { key = "ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId(); } //服务中,获取起点到终点的导航数据 if (xpOrder.getStatus() >= 5) { key = "ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId(); } Object cacheObject = redisService.getCacheObject(key); RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class); XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); // VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); // routeVo.setDirection(null != vehiclePosition ? vehiclePosition.getCourse() : 90); Long vehicleId = xpOrder.getVehicleId(); XpOrder one = xpOrderService.getOne(new QueryWrapper().eq("vehicle_id", vehicleId).in("status", Arrays.asList(6, 7)).eq("is_deleted", 0)); if(null != one){ routeVo.setEndLongitude(one.getEndLon()); routeVo.setEndLatitude(one.getEndLat()); } return R.ok(routeVo); } /** * 订单查询轨迹路线 */ @ApiOperation(value = "订单查询轨迹路线") @GetMapping("/api/v1/mini-program/order/queryOrderTrajectory") @XpClientCheck(checkToken = false, checkOtpToken = true) public R queryOrderTrajectory(@RequestParam String orderId, HttpServletRequest request) { if (orderId == null) { return R.fail("参数不能为空"); } List trajectories = mongoTemplate.find( new Query(Criteria.where("orderId").is(Long.valueOf(orderId))) .with(Sort.by(Sort.Direction.ASC, "locatetime")), OrderTrajectory.class ); // 封装信息 RouteVo routeVo = new RouteVo(); List polyline = new ArrayList<>(); if (!CollectionUtils.isEmpty(trajectories)) { for (OrderTrajectory trajectory : trajectories) { LonLatDto lonLatDto = new LonLatDto(); String[] split = trajectory.getLocation().split(","); lonLatDto.setLongitude(Double.valueOf(split[0])); lonLatDto.setLatitude(Double.valueOf(split[1])); polyline.add(lonLatDto); } } routeVo.setPolyline(polyline); return R.ok(routeVo); } /** * 当日取消订单次数 * * @param * @return 订单数量 */ @PostMapping("/inner/order/todayCancellationCount") public R todayCancellationCount(@RequestParam Long userId) { long count = xpOrderService.count(new QueryWrapper().eq("app_user_id", userId).eq("status", 0) .eq("is_deleted", 0).last(" and DATE_FORMAT(create_time, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d')")); return R.ok((int) count); } @ApiOperation(value = "通过订单id获取蓝牙开锁秘钥", tags = {"小程序-业务流程"}) @GetMapping("/api/v1/mini-program/bluetooth/getUnlocktToken/{orderId}") @XpClientCheck(checkToken = false, checkOtpToken = true) public R getBluetoothToken(@PathVariable("orderId") Long orderId, HttpServletRequest request) { // ========== 联调临时逻辑:通过 Nacos 配置返回固定蓝牙信息(bluetooth-debug.enabled=true 时生效) ========== if (bluetoothDebugConfig.isEnabled()) { BluetoothTokenVo vo = new BluetoothTokenVo(); vo.setToken(bluetoothDebugConfig.getToken()); vo.setMacAddress(bluetoothDebugConfig.getMacAddress()); vo.setSlaveMacList(bluetoothDebugConfig.getSlaveMacList()); return R.ok(vo); } // ========== 联调临时逻辑结束 ========== // 原逻辑 String uid = request.getHeader("XP-Uid"); XpOrder xpOrder = xpOrderService.getById(orderId); if (!Objects.equals(xpOrder.getAppUserId(), Long.valueOf(uid))) { return R.ok(); } if(!Arrays.asList(4, 5, 6, 7, 8).contains(xpOrder.getStatus())){ return R.ok(); } String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + orderId); if (StringUtils.isBlank(token)) { return R.ok(); } XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); GetBleInfoVo getBleInfoVo = new GetBleInfoVo(); getBleInfoVo.setVin(xpVehicle.getVehicleVin()); BaseVehicleUserDto baseVehicleUserDto = vehicleMacClient.getBleInfo(uid, getBleInfoVo); if(null == baseVehicleUserDto || 200 != baseVehicleUserDto.getCode()){ throw new ServiceException("获取蓝牙信息失败"); } JSONObject jsonObject = JSON.parseObject(baseVehicleUserDto.getData().toString()); BluetoothTokenVo vo = new BluetoothTokenVo(); vo.setToken(token); vo.setMacAddress(jsonObject.getString("macAddress")); vo.setSlaveMacList(jsonObject.getList("slaveMacList", String.class)); return R.ok(vo); } /** * 判断用户类型 * @param userId * @return 2=老用户,3=新用户,4=流失用户 */ @PostMapping("/logan/inner/order/determineUserType") public R determineUserType(@RequestParam Long userId){ //判断流失用户 XpOrder one = xpOrderService.getOne(new QueryWrapper().eq("app_user_id", userId).in("status", Arrays.asList(9, 10)).last(" order by create_time desc limit 1")); if(null != one){ long time = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - one.getCreateTime().toEpochSecond(ZoneOffset.of("+8")); if(time >= 60 * 60 * 24 * 5){ return R.ok(4); } return R.ok(2); }else{ return R.ok(3); } } /** * 判断用户类型 * @param userType * @return 2=老用户,3=新用户,4=流失用户 */ @PostMapping("/logan/inner/order/getUserTypeIdList") public R> getUserTypeIdList(@RequestParam Integer userType){ List data = xpWhiteListClient.getXpWhitelistByName("").getData(); //判断流失用户 if(4 == userType){ Set collect = data.stream().map(XpWhitelist::getAppUserId).collect(Collectors.toSet()); List one = xpOrderService.list(new QueryWrapper().in("app_user_id", collect).in("status", Arrays.asList(9, 10)).last(" order by create_time desc limit 1")); if(one.isEmpty()){ return R.ok(new ArrayList<>()); } List appUserIds = new ArrayList<>(); for (XpOrder order : one) { long time = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - order.getCreateTime().toEpochSecond(ZoneOffset.of("+8")); if(time >= 60 * 60 * 24 * 5){ appUserIds.add(order.getAppUserId()); } } return R.ok(appUserIds); } //新用户 if(3 == userType){ Set collect = data.stream().map(XpWhitelist::getAppUserId).collect(Collectors.toSet()); List one = xpOrderService.list(new QueryWrapper().in("app_user_id", collect).in("status", Arrays.asList(9, 10)).last(" order by create_time desc limit 1")); if(one.isEmpty()){ return R.ok(new ArrayList<>(collect)); } collect.removeAll(one.stream().map(XpOrder::getAppUserId).collect(Collectors.toList())); return R.ok(new ArrayList<>(collect)); } //老用户 if(2 == userType){ Set collect = data.stream().map(XpWhitelist::getAppUserId).collect(Collectors.toSet()); List one = xpOrderService.list(new QueryWrapper().in("app_user_id", collect).in("status", Arrays.asList(9, 10)).last(" order by create_time desc limit 1")); if(one.isEmpty()){ return R.ok(new ArrayList<>()); } List appUserIds = new ArrayList<>(); for (XpOrder order : one) { appUserIds.add(order.getAppUserId()); } return R.ok(appUserIds); } return R.ok(new ArrayList<>()); } /** * 获取用户订单数量 * @param userId * @return */ @PostMapping("/logan/inner/order/getUserOrderNum") public R getUserOrderNum(@RequestParam Long userId){ long count = xpOrderService.count(new QueryWrapper().eq("app_user_id", userId) .ne("status", 0).eq("is_deleted", 0)); return R.ok(count); } @PostMapping("/drainage/v1/order/updateOrderStatus") @ApiOperation(value = "更新订单状态", notes = "流量接入-订单信息") @ApiImplicitParams({ @ApiImplicitParam(value = "token", name = "token", required = true, paramType = "header") }) public R officialPartnerUpdateOrderStatus(@RequestBody UpdateOrderStatusVo vo, HttpServletRequest request){ XpOfficialPartner officialPartner = tokenService.getOfficialPartner(); return xpOrderService.officialPartnerUpdateOrderStatus(vo, officialPartner.getId()); } @PostMapping("/drainage/v1/order/getOrderNavigation") @ApiOperation(value = "获取订单导航数据", notes = "流量接入-订单信息") @ApiImplicitParams({ @ApiImplicitParam(value = "token", name = "token", required = true, paramType = "header") }) public R getOrderNavigation(@RequestBody OrderNavigationDto dto, HttpServletRequest request){ XpOfficialPartner officialPartner = tokenService.getOfficialPartner(); XpOrder xpOrder = xpOrderService.getById(dto.getOrderId()); if(!xpOrder.getOfficialPartnerId().equals(officialPartner.getId())){ return R.fail("无权限"); } NavigationVo navigationVo = null; if(1 == dto.getNavigationType()){ Object cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId()); if(null != cacheObject){ navigationVo = JSON.parseObject(cacheObject.toString(), NavigationVo.class); } } if(2 == dto.getNavigationType()){ Object cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId()); if(null != cacheObject){ navigationVo = JSON.parseObject(cacheObject.toString(), NavigationVo.class); } } return R.ok(navigationVo); } @PostMapping("/drainage/v1/order/getOrderInfo") @ApiOperation(value = "获取订单详情", notes = "流量接入-订单信息") @ApiImplicitParams({ @ApiImplicitParam(value = "token", name = "token", required = true, paramType = "header") }) public R getOfficialPartnerOrderInfo(@PathVariable Long orderId){ XpOfficialPartner officialPartner = tokenService.getOfficialPartner(); XpOrder xpOrder = xpOrderService.getById(orderId); if(!xpOrder.getOfficialPartnerId().equals(officialPartner.getId())){ return R.fail("无权限"); } XpOrderInfoVo xpOrderInfoVo = BeanUtil.copyProperties(xpOrder, XpOrderInfoVo.class); return R.ok(xpOrderInfoVo); } @ApiOperation(value = "获取订单支付状态", tags = {"小程序-业务流程"}) @GetMapping("/api/v1/mini-program/order/queryOrderStatusFromOrderId") @XpClientCheck(checkToken = false, checkOtpToken = true) public R queryOrderStatusFromOrderId(Long orderId) { XpOrder order = xpOrderService.getById(orderId); OrderStatusFromOrderIdVo orderStatusFromOrderIdVo = new OrderStatusFromOrderIdVo(); orderStatusFromOrderIdVo.setOrderId(order.getId()); orderStatusFromOrderIdVo.setStatus(order.getStatus()); return R.ok( xpOrderService.queryOrderStatusFromOrderId(orderId)); } }