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.XpSystemSettingClient;
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.XpSystemSetting;
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.enums.OrderStatusEnum;
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.service.impl.BootCommonService;
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;
@Resource
private XpSystemSettingClient xpSystemSettingClient;
@Resource
@Lazy
private BootCommonService bootCommonService;
/**
* 获取订单统计数据(内部接口)
*
* @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);
}
/**
* 通过订单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")
@AdminOperationLog(
businessType = AdminBusinessType.ORDER_MANAGEMENT,
operationType = AdminOperationType.DELETE,
contentExpression = "'删除订单,id=' + #p0",
appendRequestData = false
)
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")
@AdminOperationLog(
businessType = AdminBusinessType.ORDER_MANAGEMENT,
operationType = AdminOperationType.EXPORT,
content = "订单导出",
appendRequestData = true
)
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")
@AdminOperationLog(
businessType = AdminBusinessType.ORDER_MANAGEMENT,
operationType = AdminOperationType.EDIT,
content = "取消/关闭订单",
appendRequestData = true
)
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")
@AdminOperationLog(
businessType = AdminBusinessType.ORDER_MANAGEMENT,
operationType = AdminOperationType.EDIT,
content = "改派订单",
appendRequestData = true
)
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")
})
@AdminOperationLog(
businessType = AdminBusinessType.ORDER_MANAGEMENT,
operationType = AdminOperationType.EDIT,
contentExpression = "'订单改价,id=' + #p0 + ',amount=' + #p1",
appendRequestData = false
)
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");
NearestNextVo nearestNextVo = xpOrderService.quickCapsule(uid, startPointId);
return R.ok(nearestNextVo);
}
/**
* 获取订单详情
*/
@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);
//判断是否测试免费
XpSystemSetting xpSystemSetting = xpSystemSettingClient.getSystemSettingOne().getData();
if (xpSystemSetting != null && xpSystemSetting.getOperateFree() == 1) {
//将支付金额修改成0 并将状态修改成 订单状态9
XpOrder xpOrder1 = new XpOrder();
xpOrder1.setId(orderId);
xpOrder1.setIsFree(true);//豁免
xpOrder1.setPayMoney(BigDecimal.ZERO);
xpOrder1.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode());
xpOrder1.setUpdateTime(LocalDateTime.now());
xpOrderService.updateById(xpOrder1);
bootCommonService.setCache_orderStatus(xpOrder1.getId(), xpOrder1, null);
}
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) {
return xpOrderService.updateOrderStatus(orderId, status);
}
/**
* 行驶中车辆异常,订单状态修改- 修改状态=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);
}
}