package com.xiaopeng.order.service.impl;
|
|
import cn.hutool.core.bean.BeanUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.google.common.collect.ImmutableMap;
|
import com.xiaopeng.api.dto.account.GetUserCouponDto;
|
import com.xiaopeng.api.dto.operation.LonLatDto;
|
import com.xiaopeng.api.dto.order.HistoryEndPointsDto;
|
import com.xiaopeng.api.dto.order.HistoryStartPointsDto;
|
import com.xiaopeng.api.dto.statistics.DailyCountDTO;
|
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.XpAppUserClient;
|
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
|
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
|
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
|
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient;
|
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
|
import com.xiaopeng.api.feignClient.operation.XpPointClient;
|
import com.xiaopeng.api.feignClient.operation.XpPricingClient;
|
import com.xiaopeng.api.model.account.XpAppUser;
|
import com.xiaopeng.api.model.operation.XpPricing;
|
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
|
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
|
import com.xiaopeng.api.model.order.XpOrder;
|
import com.xiaopeng.api.model.order.XpOrderCancel;
|
import com.xiaopeng.api.model.order.XpOrderEvaluate;
|
import com.xiaopeng.api.model.order.XpOrderReassign;
|
import com.xiaopeng.api.vo.account.UserCouponVo;
|
import com.xiaopeng.api.vo.order.FareBreakdownVo;
|
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
|
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
|
import com.xiaopeng.api.vo.order.XpPointInfoVo;
|
import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo;
|
import com.xiaopeng.common.core.domain.R;
|
import com.xiaopeng.common.core.exception.ServiceException;
|
import com.xiaopeng.common.core.utils.DateUtils;
|
import com.xiaopeng.common.core.utils.StringUtils;
|
import com.xiaopeng.common.core.web.domain.BaseModel;
|
import com.xiaopeng.common.core.web.page.PageInfo;
|
import com.xiaopeng.common.redis.service.RedisService;
|
import com.xiaopeng.common.security.utils.SecurityUtils;
|
import com.xiaopeng.order.constant.I18nKeyConstant;
|
import com.xiaopeng.order.mapper.XpOrderMapper;
|
import com.xiaopeng.order.model.dto.XpOrderCommentDto;
|
import com.xiaopeng.order.model.dto.XpOrderPayDto;
|
import com.xiaopeng.order.model.query.XpHistoryOrderListQuery;
|
import com.xiaopeng.order.model.query.XpOrderPageQuery;
|
import com.xiaopeng.order.model.vo.*;
|
import com.xiaopeng.order.service.IXpOrderCancelService;
|
import com.xiaopeng.order.service.IXpOrderEvaluateService;
|
import com.xiaopeng.order.service.IXpOrderReassignService;
|
import com.xiaopeng.order.service.IXpOrderService;
|
import com.xiaopeng.order.job.base.QuartzManager;
|
import com.xiaopeng.order.job.base.TimeJobType;
|
import com.xiaopeng.order.job.jobs.OrderCancelJob;
|
import io.swagger.annotations.ApiModelProperty;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.BeanUtils;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.CollectionUtils;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.time.Duration;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.LocalTime;
|
import java.util.*;
|
import java.util.function.Function;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 订单 服务实现类
|
* </p>
|
*
|
* @author mitao
|
* @since 2026-02-03
|
*/
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor(onConstructor_ = @Lazy)
|
public class XpOrderServiceImpl extends ServiceImpl<XpOrderMapper, XpOrder> implements IXpOrderService {
|
|
private final XpAppUserClient xpAppUserClient;
|
private final XpPointClient xpPointClient;
|
private final XpVehicleClient xpVehicleClient;
|
private final XpAppUserCouponClient xpAppUserCouponClient;
|
private final XpFleetClient xpFleetClient;
|
private final XpFleetVehicleClient xpFleetVehicleClient;
|
private final UserVehicleClient userVehicleClient;
|
private final IXpOrderEvaluateService xpOrderEvaluateService;
|
private final IXpOrderCancelService xpOrderCancelService;
|
private final IXpOrderReassignService xpOrderReassignService;
|
private final RedisService redisService;
|
private final XpPricingClient xpPricingClient;
|
|
|
@Override
|
public OrderStatisticsDTO getOrderStatistics(StatisticsQueryDTO query) {
|
OrderStatisticsDTO dto = new OrderStatisticsDTO();
|
|
// 1. 查询订单总数(状态为9=待评价或10=已完成)
|
dto.setTotalCount(baseMapper.countCompletedOrders());
|
|
// 2. 查询时间范围内新增订单数
|
if (Objects.nonNull(query.getStartDate()) && Objects.nonNull(query.getEndDate())) {
|
dto.setNewCount(baseMapper.countNewOrders(query.getStartDate(), query.getEndDate()));
|
} else {
|
dto.setNewCount(0L);
|
}
|
|
// 3. 查询总交易金额和总收入(pay_money累加)
|
BigDecimal totalMoney = baseMapper.sumTotalMoney();
|
dto.setTotalMoney(Objects.nonNull(totalMoney) ? totalMoney : BigDecimal.ZERO);
|
dto.setTotalIncome(Objects.nonNull(totalMoney) ? totalMoney : BigDecimal.ZERO);
|
|
// 4. 查询近N天每日新增订单数(默认30天)
|
Integer trendDays = Objects.nonNull(query.getTrendDays()) ? query.getTrendDays() : 30;
|
LocalDate endDate = LocalDate.now();
|
LocalDate startDate = endDate.minusDays(trendDays - 1);
|
List<DailyCountDTO> dailyCountList = baseMapper.getDailyOrderCount(startDate, endDate);
|
dto.setDailyCountList(Objects.nonNull(dailyCountList) ? dailyCountList : new ArrayList<>());
|
|
return dto;
|
}
|
|
@Override
|
public PageInfo<XpOrderPageVO> pageList(XpOrderPageQuery query) {
|
// 1. 构建查询条件
|
LambdaQueryWrapper<XpOrder> wrapper = buildQueryWrapper(query);
|
wrapper.orderByDesc(XpOrder::getCreateTime);
|
|
// 2. 分页查询
|
PageInfo<XpOrder> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
|
PageInfo<XpOrder> orderPage = this.page(pageInfo, wrapper);
|
|
if (CollectionUtils.isEmpty(orderPage.getRecords())) {
|
PageInfo<XpOrderPageVO> resultPage = new PageInfo<>(query.getPageNum(), query.getPageSize());
|
resultPage.setTotal(0L);
|
resultPage.setRecords(new ArrayList<>());
|
return resultPage;
|
}
|
|
// 3. 收集关联ID
|
Set<Long> userIds = new HashSet<>();
|
Set<Long> vehicleIds = new HashSet<>();
|
Set<Long> fleetIds = new HashSet<>();
|
for (XpOrder order : orderPage.getRecords()) {
|
if (Objects.nonNull(order.getAppUserId())) {
|
userIds.add(order.getAppUserId());
|
}
|
if (Objects.nonNull(order.getVehicleId())) {
|
vehicleIds.add(order.getVehicleId());
|
}
|
if (Objects.nonNull(order.getFleetId())) {
|
fleetIds.add(order.getFleetId());
|
}
|
}
|
|
// 4. 批量查询关联数据
|
Map<Long, XpAppUser> userMap = batchGetUsers(userIds);
|
Map<Long, XpVehicle> vehicleMap = batchGetVehicles(vehicleIds);
|
Map<Long, XpFleet> fleetMap = batchGetFleets(fleetIds);
|
|
// 5. 组装 VO
|
List<XpOrderPageVO> voList = orderPage.getRecords().stream()
|
.map(order -> convertToPageVO(order, userMap, vehicleMap, fleetMap))
|
.collect(Collectors.toList());
|
|
// 6. 返回分页结果
|
PageInfo<XpOrderPageVO> resultPage = new PageInfo<>(query.getPageNum(), query.getPageSize());
|
resultPage.setTotal(orderPage.getTotal());
|
resultPage.setRecords(voList);
|
return resultPage;
|
}
|
|
@Override
|
public XpOrderDetailVO getOrderDetail(Long id) {
|
// 1. 查询订单基础信息
|
XpOrder order = this.getById(id);
|
if (order == null) {
|
throw new ServiceException("订单不存在");
|
}
|
|
// 2. 转换为详情 VO
|
XpOrderDetailVO vo = BeanUtil.toBean(order, XpOrderDetailVO.class);
|
|
// 3. 获取用户信息
|
if (Objects.nonNull(order.getAppUserId())) {
|
Map<Long, XpAppUser> userMap = batchGetUsers(Collections.singleton(order.getAppUserId()));
|
XpAppUser user = userMap.get(order.getAppUserId());
|
if (Objects.nonNull(user)) {
|
vo.setNickName(user.getNickName());
|
vo.setPhoneNumber(user.getPhoneNumber());
|
}
|
}
|
|
// 4. 获取车辆信息
|
if (Objects.nonNull(order.getVehicleId())) {
|
Map<Long, XpVehicle> vehicleMap = batchGetVehicles(Collections.singleton(order.getVehicleId()));
|
XpVehicle vehicle = vehicleMap.get(order.getVehicleId());
|
if (Objects.nonNull(vehicle)) {
|
vo.setPlateNumber(vehicle.getPlateNumber());
|
vo.setVehicleModel(vehicle.getVehicleModel());
|
}
|
}
|
|
// 5. 获取车队信息
|
if (Objects.nonNull(order.getFleetId())) {
|
Map<Long, XpFleet> fleetMap = batchGetFleets(Collections.singleton(order.getFleetId()));
|
XpFleet fleet = fleetMap.get(order.getFleetId());
|
if (Objects.nonNull(fleet)) {
|
vo.setFleetName(fleet.getFleetName());
|
}
|
}
|
|
// 6. 获取评价信息
|
LambdaQueryWrapper<XpOrderEvaluate> evaluateWrapper = new LambdaQueryWrapper<>();
|
evaluateWrapper.eq(XpOrderEvaluate::getOrderId, id);
|
XpOrderEvaluate evaluate = xpOrderEvaluateService.getOne(evaluateWrapper);
|
if (Objects.nonNull(evaluate)) {
|
vo.setOrderRating(evaluate.getOrderRating());
|
}
|
//TODO 7.查询mongodb 该订单上传的经纬度轨迹信息
|
vo.setOrderPositionList(new ArrayList<>());
|
return vo;
|
}
|
|
@Override
|
public void deleteOrder(Long id) {
|
// 1. 校验订单是否存在
|
XpOrder order = this.getById(id);
|
if (Objects.isNull(order)) {
|
throw new ServiceException("订单不存在", I18nKeyConstant.ORDER_NOT_EXISTS);
|
}
|
|
this.removeById(id);
|
}
|
|
@Override
|
public List<XpOrderPageVO> exportList(XpOrderPageQuery query) {
|
// 1. 构建查询条件
|
LambdaQueryWrapper<XpOrder> wrapper = buildQueryWrapper(query);
|
|
// 2. 查询订单列表
|
List<XpOrder> orderList = this.list(wrapper);
|
|
if (CollectionUtils.isEmpty(orderList)) {
|
return new ArrayList<>();
|
}
|
|
// 3. 收集关联ID
|
Set<Long> userIds = new HashSet<>();
|
Set<Long> vehicleIds = new HashSet<>();
|
Set<Long> fleetIds = new HashSet<>();
|
for (XpOrder order : orderList) {
|
if (Objects.nonNull(order.getAppUserId())) {
|
userIds.add(order.getAppUserId());
|
}
|
if (Objects.nonNull(order.getVehicleId())) {
|
vehicleIds.add(order.getVehicleId());
|
}
|
if (Objects.nonNull(order.getFleetId())) {
|
fleetIds.add(order.getFleetId());
|
}
|
}
|
|
// 4. 批量查询关联数据
|
Map<Long, XpAppUser> userMap = batchGetUsers(userIds);
|
Map<Long, XpVehicle> vehicleMap = batchGetVehicles(vehicleIds);
|
Map<Long, XpFleet> fleetMap = batchGetFleets(fleetIds);
|
|
// 5. 组装 VO
|
return orderList.stream()
|
.map(order -> convertToPageVO(order, userMap, vehicleMap, fleetMap))
|
.collect(Collectors.toList());
|
}
|
|
/**
|
* 构建查询条件
|
*/
|
private LambdaQueryWrapper<XpOrder> buildQueryWrapper(XpOrderPageQuery query) {
|
LambdaQueryWrapper<XpOrder> wrapper = new LambdaQueryWrapper<>();
|
|
wrapper.like(StringUtils.isNotBlank(query.getOrderNumber()), XpOrder::getOrderNumber, query.getOrderNumber())
|
.eq(Objects.nonNull(query.getFleetId()), XpOrder::getFleetId, query.getFleetId())
|
.eq(Objects.nonNull(query.getOrderSource()), XpOrder::getOrderSource, query.getOrderSource())
|
.like(StringUtils.isNotBlank(query.getCityCode()), XpOrder::getCityCode, query.getCityCode())
|
.eq(Objects.nonNull(query.getStatus()), XpOrder::getStatus, query.getStatus());
|
|
if (Objects.nonNull(query.getStartTime())) {
|
wrapper.ge(XpOrder::getCreateTime, LocalDateTime.of(query.getStartTime(), LocalTime.MIN));
|
}
|
if (Objects.nonNull(query.getEndTime())) {
|
wrapper.ge(XpOrder::getCreateTime, LocalDateTime.of(query.getEndTime(), LocalTime.MAX));
|
}
|
wrapper.orderByDesc(XpOrder::getCreateTime);
|
return wrapper;
|
}
|
|
/**
|
* 批量获取用户信息
|
*/
|
private Map<Long, XpAppUser> batchGetUsers(Set<Long> userIds) {
|
if (CollectionUtils.isEmpty(userIds)) {
|
return new HashMap<>();
|
}
|
try {
|
R<List<XpAppUser>> result = xpAppUserClient.listByIds(new ArrayList<>(userIds));
|
if (Objects.nonNull(result) && Objects.nonNull(result.getData())) {
|
return result.getData().stream()
|
.collect(Collectors.toMap(XpAppUser::getId, Function.identity(), (a, b) -> a));
|
}
|
} catch (Exception e) {
|
log.error("批量获取用户信息失败: {}", e.getMessage());
|
}
|
return new HashMap<>();
|
}
|
|
/**
|
* 批量获取车辆信息
|
*/
|
private Map<Long, XpVehicle> batchGetVehicles(Set<Long> vehicleIds) {
|
if (CollectionUtils.isEmpty(vehicleIds)) {
|
return new HashMap<>();
|
}
|
try {
|
R<List<XpVehicle>> result = xpVehicleClient.listByIds(new ArrayList<>(vehicleIds));
|
if (Objects.nonNull(result) && Objects.nonNull(result.getData())) {
|
return result.getData().stream()
|
.collect(Collectors.toMap(XpVehicle::getId, Function.identity(), (a, b) -> a));
|
}
|
} catch (Exception e) {
|
log.error("批量获取车辆信息失败: {}", e.getMessage());
|
}
|
return new HashMap<>();
|
}
|
|
/**
|
* 批量获取车队信息
|
*/
|
private Map<Long, XpFleet> batchGetFleets(Set<Long> fleetIds) {
|
if (CollectionUtils.isEmpty(fleetIds)) {
|
return new HashMap<>();
|
}
|
try {
|
R<List<XpFleet>> result = xpFleetClient.listByIds(new ArrayList<>(fleetIds));
|
if (Objects.nonNull(result) && Objects.nonNull(result.getData())) {
|
return result.getData().stream()
|
.collect(Collectors.toMap(XpFleet::getId, Function.identity(), (a, b) -> a));
|
}
|
} catch (Exception e) {
|
log.error("批量获取车队信息失败: {}", e.getMessage());
|
}
|
return new HashMap<>();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void cancelOrCloseOrder(Long orderId, Integer type) {
|
// 1. 校验订单是否存在
|
XpOrder order = this.getById(orderId);
|
if (Objects.isNull(order)) {
|
throw new ServiceException("订单不存在");
|
}
|
|
// 2. 校验操作类型
|
if (type != 1 && type != 2) {
|
throw new ServiceException("操作类型错误,type只能为1或2");
|
}
|
|
// 3. 校验订单状态是否允许操作
|
Integer currentStatus = order.getStatus();
|
//取消订单:在未接到乘客前都可以,关闭订单,在送达目的地可以操作关闭
|
if (type == 1) {
|
// 取消订单:只有待接单(1)、待出发(2)、接驾中(3)状态可以取消
|
if (currentStatus != 1 && currentStatus != 2 && currentStatus != 3) {
|
throw new ServiceException("当前订单状态不允许取消,只有待接单、待出发、接驾中状态的订单可以取消", I18nKeyConstant.ORDER_CANCEL_FAILED);
|
}
|
} else {
|
// 关闭订单:只有待付款(8)、待评价(9)状态可以关闭
|
if (currentStatus != 7 && currentStatus != 8 && currentStatus != 9) {
|
throw new ServiceException("当前订单状态不允许关闭,只有待付款、待评价状态的订单可以关闭", I18nKeyConstant.ORDER_CLOSE_FAILED);
|
}
|
}
|
|
// 4. 执行操作
|
if (type == 1) {
|
// 取消订单
|
cancelOrder(order);
|
} else {
|
// 关闭订单
|
closeOrder(order);
|
}
|
}
|
|
/**
|
* 转换为分页列表 VO
|
*/
|
private XpOrderPageVO convertToPageVO(XpOrder order,
|
Map<Long, XpAppUser> userMap,
|
Map<Long, XpVehicle> vehicleMap,
|
Map<Long, XpFleet> fleetMap) {
|
XpOrderPageVO vo = new XpOrderPageVO();
|
vo.setId(order.getId());
|
vo.setOrderNumber(order.getOrderNumber());
|
vo.setCreateTime(order.getCreateTime());
|
vo.setOrderSource(order.getOrderSource());
|
vo.setRideTime(order.getRideTime());
|
vo.setStartAddress(order.getStartAddress());
|
vo.setEndAddress(order.getEndAddress());
|
vo.setOrderMoney(order.getOrderMoney());
|
vo.setStatus(order.getStatus());
|
|
// 用户信息
|
if (Objects.nonNull(order.getAppUserId()) && userMap.containsKey(order.getAppUserId())) {
|
XpAppUser user = userMap.get(order.getAppUserId());
|
vo.setNickName(user.getNickName());
|
vo.setPhoneNumber(user.getPhoneNumber());
|
}
|
|
// 车辆信息
|
if (Objects.nonNull(order.getVehicleId()) && vehicleMap.containsKey(order.getVehicleId())) {
|
XpVehicle vehicle = vehicleMap.get(order.getVehicleId());
|
vo.setPlateNumber(vehicle.getPlateNumber());
|
vo.setVehicleModel(vehicle.getVehicleModel());
|
}
|
|
// 车队信息
|
if (Objects.nonNull(order.getFleetId()) && fleetMap.containsKey(order.getFleetId())) {
|
XpFleet fleet = fleetMap.get(order.getFleetId());
|
vo.setFleetName(fleet.getFleetName());
|
}
|
|
return vo;
|
}
|
|
/**
|
* 取消订单
|
*/
|
private void cancelOrder(XpOrder order) {
|
// 1. 更新订单状态为已取消(0)
|
order.setStatus(0);
|
this.updateById(order);
|
|
// 2. 保存取消记录
|
XpOrderCancel orderCancel = new XpOrderCancel();
|
orderCancel.setOrderId(order.getId());
|
orderCancel.setCancelSource(3); // 3=运营人员(后台管理接口固定为运营人员)
|
orderCancel.setUserId(SecurityUtils.getUserId()); // 当前登录用户ID
|
orderCancel.setCancelReason("运营人员取消订单");
|
orderCancel.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
|
xpOrderCancelService.save(orderCancel);
|
|
log.info("订单取消成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername());
|
}
|
|
/**
|
* 关闭订单
|
*/
|
private void closeOrder(XpOrder order) {
|
// 更新订单状态为已完成(10)
|
order.setStatus(10);
|
this.updateById(order);
|
|
log.info("订单关闭成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername());
|
}
|
|
/**
|
* 改派订单
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void reassignOrder(Long orderId, Long newVehicleId, String reassignReason) {
|
// 1. 校验订单是否存在
|
XpOrder order = this.getById(orderId);
|
if (Objects.isNull(order)) {
|
throw new ServiceException("订单不存在");
|
}
|
|
// 2. 校验订单状态(只有待接单、待出发、接驾中状态可以改派)
|
Integer currentStatus = order.getStatus();
|
if (currentStatus != 1 && currentStatus != 2 && currentStatus != 3) {
|
throw new ServiceException("当前订单状态不允许改派,只有待接单、待出发、接驾中状态的订单可以改派", I18nKeyConstant.ORDER_REASSIGN_FAILED);
|
}
|
|
// 3. 校验新旧车辆是否相同
|
if (Objects.equals(order.getVehicleId(), newVehicleId)) {
|
throw new ServiceException("新车辆与原车辆相同,无需改派", I18nKeyConstant.ORDER_REASSIGN_VEHICLE_FAILED);
|
}
|
|
// 4. 查询新车辆信息并校验
|
R<List<XpVehicle>> vehicleResult = xpVehicleClient.listByIds(Collections.singletonList(newVehicleId));
|
if (Objects.isNull(vehicleResult) || Objects.isNull(vehicleResult.getData()) || vehicleResult.getData().isEmpty()) {
|
throw new ServiceException("新车辆不存在", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_EXISTS);
|
}
|
XpVehicle newVehicle = vehicleResult.getData().get(0);
|
|
// 5. 校验新车辆的运营状态
|
// 车辆状态:1=待完善 2=待运营 3=保险/年检过期
|
// 运营状态:1=运营中 2=维修中 3=已收车 4=车辆异常
|
// 当前模式:1=接单 2=测试
|
// 模式状态:1=开始接单/开始测试 2=停止接单/停止测试
|
if (Objects.isNull(newVehicle.getStatus()) || newVehicle.getStatus() == 3) {
|
throw new ServiceException("新车辆保险或年检已过期,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_STATUS_INVALID);
|
}
|
if (Objects.isNull(newVehicle.getOperatingStatus()) || newVehicle.getOperatingStatus() != 1) {
|
throw new ServiceException("新车辆运营状态异常,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_OPERATING_STATUS_INVALID);
|
}
|
if (Objects.isNull(newVehicle.getAcceptOrTest()) || newVehicle.getAcceptOrTest() != 1) {
|
throw new ServiceException("新车辆当前不在接单模式", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_IN_ACCEPT_MODE);
|
}
|
if (Objects.isNull(newVehicle.getAcceptOrTestStatus()) || newVehicle.getAcceptOrTestStatus() != 1) {
|
throw new ServiceException("新车辆未开始接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_START_ACCEPT);
|
}
|
|
// 6. 保存原车辆和车队信息
|
Long oldVehicleId = order.getVehicleId();
|
Long oldFleetId = order.getFleetId();
|
|
// 7. 查询新车辆关联的车队ID
|
Long newFleetId = null;
|
try {
|
R<Long> fleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(newVehicleId);
|
if (Objects.nonNull(fleetIdResult) && Objects.nonNull(fleetIdResult.getData())) {
|
newFleetId = fleetIdResult.getData();
|
log.info("查询到新车辆ID: {} 关联的车队ID: {}", newVehicleId, newFleetId);
|
} else {
|
log.warn("新车辆ID: {} 未关联任何车队,将使用原车队ID: {}", newVehicleId, oldFleetId);
|
newFleetId = oldFleetId;
|
}
|
} catch (Exception e) {
|
log.error("查询新车辆关联的车队ID失败,车辆ID: {},错误: {}", newVehicleId, e.getMessage());
|
newFleetId = oldFleetId;
|
}
|
|
// 8. 如果旧订单的车队ID为空,尝试查询旧车辆的车队ID
|
if (Objects.isNull(oldFleetId) && Objects.nonNull(oldVehicleId)) {
|
try {
|
R<Long> oldFleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(oldVehicleId);
|
if (Objects.nonNull(oldFleetIdResult) && Objects.nonNull(oldFleetIdResult.getData())) {
|
oldFleetId = oldFleetIdResult.getData();
|
log.info("补充查询到旧车辆ID: {} 关联的车队ID: {}", oldVehicleId, oldFleetId);
|
}
|
} catch (Exception e) {
|
log.warn("查询旧车辆关联的车队ID失败,车辆ID: {},错误: {}", oldVehicleId, e.getMessage());
|
}
|
}
|
|
// 9. 更新订单的车辆和车队信息
|
order.setVehicleId(newVehicleId);
|
if (Objects.nonNull(newFleetId)) {
|
order.setFleetId(newFleetId);
|
}
|
this.updateById(order);
|
|
// 10. 保存改派记录
|
XpOrderReassign orderReassign = new XpOrderReassign();
|
orderReassign.setOrderId(orderId);
|
orderReassign.setUserId(SecurityUtils.getUserId());
|
orderReassign.setOperationTime(LocalDateTime.now());
|
orderReassign.setOldVehicleId(oldVehicleId);
|
orderReassign.setNewVehicleId(newVehicleId);
|
orderReassign.setOldFleetId(oldFleetId);
|
orderReassign.setNewFleetId(newFleetId);
|
orderReassign.setReassignReason(
|
StringUtils.isNotBlank(reassignReason) ? reassignReason : "运营人员改派订单"
|
);
|
orderReassign.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
|
xpOrderReassignService.save(orderReassign);
|
|
log.info("订单改派成功,订单ID: {}, 原车辆ID: {}, 新车辆ID: {}, 原车队ID: {}, 新车队ID: {}, 操作人: {}",
|
orderId, oldVehicleId, newVehicleId, oldFleetId, newFleetId, SecurityUtils.getUsername());
|
}
|
|
@Override
|
public XpPointInfoVo getUserQuickCapsule(String uid) {
|
try {
|
// 使用Redis的sorted set(排行榜)获取第一个元素
|
// 获取分数最高的元素(默认按分数从高到低排序)
|
Set<Object> result = redisService.redisTemplate.opsForZSet().reverseRange("history_order_" + uid, 0, 0);
|
if (result != null && !result.isEmpty()) {
|
// 排行榜中存储的是JSON字符串
|
String jsonString = result.iterator().next().toString();
|
// 使用Hutool的JSON工具解析为XpPointInfoVo对象
|
return cn.hutool.json.JSONUtil.toBean(jsonString, XpPointInfoVo.class);
|
}
|
} catch (Exception e) {
|
log.error("获取用户快捷胶囊失败: {}", e.getMessage(), e);
|
}
|
return null;
|
}
|
|
@Override
|
public List<XpHistoryStartPointsVo> getHistoryStartPoints(String uid, double lon, double lat) {
|
//
|
List<XpOrder> xpOrders = this.baseMapper.selectList(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, uid).orderByDesc(BaseModel::getCreateTime).last("LIMIT 10"));
|
if (xpOrders.isEmpty()) {
|
return Collections.emptyList();
|
}
|
// 获取点位信息
|
List<Long> startPointsIds = xpOrders.stream().map(XpOrder::getStartPointId).collect(Collectors.toList());
|
|
R<List<XpHistoryStartPointsVo>> r = xpPointClient.getHistoryStartPoints(new HistoryStartPointsDto(startPointsIds, lon, lat));
|
return r.getData();
|
|
}
|
|
@Override
|
public List<XpHistoryEndPointsVo> getHistoryEndPoints(String uid, double lon, double lat) {
|
//
|
List<XpOrder> xpOrders = this.baseMapper.selectList(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, uid).orderByDesc(BaseModel::getCreateTime).last("LIMIT 10"));
|
if (xpOrders.isEmpty()) {
|
return Collections.emptyList();
|
}
|
// 获取点位信息
|
List<Long> endPointsIds = xpOrders.stream().map(XpOrder::getEndPointId).collect(Collectors.toList());
|
|
R<List<XpHistoryEndPointsVo>> r = xpPointClient.getHistoryEndPoints(new HistoryEndPointsDto(endPointsIds, lon, lat));
|
return r.getData();
|
|
}
|
|
/**
|
* 获取历史订单列表
|
*
|
* @param query
|
* @param uid
|
* @return
|
*/
|
@Override
|
public XpOrderHistoryVO getHistoryOrderList(XpHistoryOrderListQuery query, String uid) {
|
Page<XpOrderHistoryListVO> page = new Page<>(query.getPageNum(), query.getPageSize());
|
List<XpOrderHistoryListVO> list = this.baseMapper.getHistoryOrderList(page, query, uid);
|
|
|
XpOrderHistoryVO xpOrderHistoryVO = new XpOrderHistoryVO();
|
xpOrderHistoryVO.setTotal((int) page.getTotal());
|
|
// 根据time分组
|
Map<LocalDateTime, List<XpOrderHistoryListVO>> map = list.stream().collect(Collectors.groupingBy(XpOrderHistoryListVO::getTime));
|
List<XpOrderHistoryDateVO> dateVOS = map.entrySet().stream().map(entry -> {
|
XpOrderHistoryDateVO xpOrderHistoryDateVO = new XpOrderHistoryDateVO();
|
xpOrderHistoryDateVO.setDateLabel(entry.getKey().toString());
|
xpOrderHistoryDateVO.setOrders(entry.getValue());
|
return xpOrderHistoryDateVO;
|
}).collect(Collectors.toList());
|
xpOrderHistoryVO.setList(dateVOS);
|
|
return xpOrderHistoryVO;
|
}
|
|
|
/**
|
* 取消订单
|
*
|
* @param orderId
|
* @param uid
|
*/
|
@Override
|
@Transactional
|
public void cancelOrder(Long orderId, String uid) {
|
XpOrder order = this.getById(orderId);
|
if (order == null) {
|
throw new RuntimeException("订单不存在");
|
}
|
if (!order.getAppUserId().toString().equals(uid)) {
|
throw new RuntimeException("无权限取消该订单");
|
}
|
if (order.getStatus() > 5 || order.getStatus() < 1) {
|
throw new RuntimeException("订单状态错误");
|
}
|
order.setStatus(0);
|
|
// 组装调用车机参数
|
CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
|
Long vehicleId = order.getVehicleId();
|
R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(vehicleId);
|
XpVehicle xpVehicle = xpVehicleR.getData();
|
if (xpVehicle == null) {
|
throw new RuntimeException("车辆不存在");
|
}
|
cancelTaxiPassengerVo.setVin(xpVehicle.getVehicleVin());
|
cancelTaxiPassengerVo.setUid(order.getAppUserId().toString());
|
cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber());
|
// TODO 加配置文件取
|
cancelTaxiPassengerVo.setAppId("");
|
|
|
BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
|
if (baseVehicleUserDto.getCode() != 200) {
|
throw new RuntimeException("取消订单失败");
|
}
|
|
baseMapper.updateById(order);
|
XpOrderCancel xpOrderCancel = new XpOrderCancel();
|
xpOrderCancel.setOrderId(orderId);
|
xpOrderCancel.setUserId(Long.valueOf(uid));
|
xpOrderCancel.setCancelSource(1);
|
xpOrderCancel.setCancelReason("用户取消订单");
|
xpOrderCancelService.save(xpOrderCancel);
|
|
|
// 设置当天的取消次数缓存
|
Object cacheObject = redisService.getCacheObject("CANCEL_ORDER_" + uid);
|
if (cacheObject == null) {
|
redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, 1);
|
} else {
|
Integer i = Integer.valueOf(cacheObject.toString());
|
redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, i + 1);
|
}
|
}
|
|
@Override
|
@Transactional
|
public void cancelOrder(String orderId) {
|
XpOrder order = this.getById(orderId);
|
if (order == null) {
|
throw new RuntimeException("订单不存在");
|
}
|
order.setStatus(0);
|
baseMapper.updateById(order);
|
XpOrderCancel xpOrderCancel = new XpOrderCancel();
|
xpOrderCancel.setOrderId(Long.valueOf(orderId));
|
xpOrderCancel.setUserId(1l);
|
xpOrderCancel.setCancelSource(4);
|
xpOrderCancel.setCancelReason("系统取消订单");
|
xpOrderCancelService.save(xpOrderCancel);
|
}
|
|
/**
|
* 评价订单
|
*
|
* @param dto
|
* @param uid
|
*/
|
@Override
|
@Transactional
|
public void comment(XpOrderCommentDto dto, String uid) {
|
XpOrder xpOrder = this.getById(dto.getOrderId());
|
if (xpOrder == null) {
|
throw new RuntimeException("订单不存在");
|
}
|
if (!xpOrder.getAppUserId().toString().equals(uid)) {
|
throw new RuntimeException("无权限评价该订单");
|
}
|
if (xpOrder.getStatus() != 9) {
|
throw new RuntimeException("订单状态错误");
|
}
|
xpOrder.setStatus(10);
|
baseMapper.updateById(xpOrder);
|
|
XpOrderEvaluate evaluate = new XpOrderEvaluate();
|
evaluate.setOrderId(xpOrder.getId());
|
evaluate.setVehicleId(xpOrder.getVehicleId());
|
evaluate.setAppUserId(Long.valueOf(uid));
|
evaluate.setOrderRating(dto.getOrderRating());
|
evaluate.setEvaluateTime(LocalDateTime.now());
|
evaluate.setFeedbackContent(dto.getFeedbackContent());
|
evaluate.setFeedbackPictures(dto.getFeedbackPictures());
|
evaluate.setFeedbackTypeId(dto.getFeedbackTypeId());
|
xpOrderEvaluateService.save(evaluate);
|
|
}
|
|
@Override
|
public R<String> updateOrderStatus(Long orderId, Integer status) {
|
XpOrder xpOrder = this.getById(orderId);
|
if (Objects.isNull(xpOrder)) {
|
return R.fail("订单不存在");
|
}
|
if (xpOrder.getStatus() == 0) {
|
return R.fail("订单已取消");
|
}
|
xpOrder.setStatus(status);
|
switch (status) {
|
case 4:
|
// 添加定时任务job
|
Map<String, ? extends Object> maps =
|
new ImmutableMap.Builder<String, Long>().
|
put("id", xpOrder.getId())
|
.build();
|
QuartzManager.addJob(
|
OrderCancelJob.class,
|
(OrderCancelJob.name + xpOrder.getId()).toUpperCase(),
|
TimeJobType.ORDER_CANCEL,
|
DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(5)),
|
maps
|
);
|
break;
|
case 5:
|
// 删除定时任务job
|
QuartzManager.removeJob((OrderCancelJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.ORDER_CANCEL);
|
break;
|
}
|
baseMapper.updateById(xpOrder);
|
return R.ok();
|
}
|
|
@Override
|
public void endTrip(Long orderId, String uid) {
|
XpOrder order = this.getById(orderId);
|
if (order == null) {
|
throw new RuntimeException("订单不存在");
|
}
|
|
if (order.getStatus() != 7) {
|
throw new RuntimeException("订单状态错误");
|
}
|
order.setStatus(8);
|
// 计算实际价格
|
// 根据订单所属开通城市id 查询定价
|
R<XpPricing> pricingByCityId = xpPricingClient.getPricingByCityId(order.getCityId());
|
XpPricing pricing = pricingByCityId.getData();
|
if (pricing == null) {
|
throw new ServiceException("当前城市未配置定价规则", I18nKeyConstant.ORDER_PRICING_NOT_EXISTS);
|
}
|
// Long id = pricing.getId();
|
// Integer pricingType = pricing.getPricingType();
|
// String basicPricingJson = pricing.getBasicPricingJson();
|
// String startingFareJson = pricing.getStartingFareJson();
|
// String dynamicPricingJson = pricing.getDynamicPricingJson();
|
// String priceRule = pricing.getPriceRule();
|
// // 根据计价规则计算费用
|
// BigDecimal startMoney = BigDecimal.ZERO;// 起步价
|
// BigDecimal mileageMoney = BigDecimal.ZERO;// 里程费
|
// BigDecimal durationMoney = BigDecimal.ZERO;// 时长费
|
// BigDecimal waitMoney = BigDecimal.ZERO;// 等待费
|
// BigDecimal longDistancemoney = BigDecimal.ZERO;// 远途费
|
// BigDecimal redPacketMoney = BigDecimal.ZERO;// 红包抵扣金额
|
// BigDecimal couponMoney = BigDecimal.ZERO;// 优惠券抵扣金额
|
// if (pricingType == 1) {
|
//
|
// } else {
|
//
|
// }
|
// if (org.springframework.util.StringUtils.hasLength(basicPricingJson)) {
|
//
|
// }
|
// if (org.springframework.util.StringUtils.hasLength(startingFareJson)) {
|
//
|
// }
|
// if (org.springframework.util.StringUtils.hasLength(dynamicPricingJson)) {
|
//
|
// }
|
// if (org.springframework.util.StringUtils.hasLength(priceRule)) {
|
//
|
// }
|
|
// 计算完价格后 挑选优惠券
|
GetUserCouponDto getUserCouponDto = new GetUserCouponDto();
|
getUserCouponDto.setUserId(Long.valueOf(uid));
|
getUserCouponDto.setTotalAmount(order.getOrderMoney().doubleValue());
|
R<UserCouponVo> userCouponVoR = xpAppUserCouponClient.getUserCoupon(getUserCouponDto);
|
UserCouponVo userCouponVo = userCouponVoR.getData();
|
if (userCouponVo != null) {
|
order.setCouponId(userCouponVo.getId());
|
order.setCouponMoney(BigDecimal.valueOf(userCouponVo.getMoney()));
|
}
|
order.setTripEnd(LocalDateTime.now());
|
baseMapper.updateById(order);
|
// 解绑用户与车辆关系
|
CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
|
XpVehicle vehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
|
if (vehicle != null) {
|
cancelTaxiPassengerVo.setVin(vehicle.getVehicleVin());
|
cancelTaxiPassengerVo.setUid(uid);
|
cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber());
|
// cancelTaxiPassengerVo.setAppId();
|
|
userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
|
}
|
|
}
|
|
@Override
|
public R<FareBreakdownVo> fareBreakdown(Long orderId, String uid) {
|
XpOrder order = this.getById(orderId);
|
FareBreakdownVo fareBreakdownVo = new FareBreakdownVo();
|
BeanUtils.copyProperties(order, fareBreakdownVo);
|
fareBreakdownVo.setTotalKilometers(
|
BigDecimal.valueOf(order.getStartMileage() + order.getMileageKilometers() + order.getLongDistance())
|
);
|
LocalDateTime createTime = order.getCreateTime();
|
LocalDateTime tripEnd = order.getTripEnd();
|
// 计算行程时间 单位分钟
|
|
// 计算时间差
|
Duration duration = Duration.between(createTime, tripEnd);
|
|
// 转换为分钟并保留一位小数
|
BigDecimal minutes = BigDecimal.valueOf(duration.getSeconds())
|
.divide(BigDecimal.valueOf(60), 1, RoundingMode.HALF_UP);
|
|
fareBreakdownVo.setTotalTime(minutes);
|
return R.ok(fareBreakdownVo);
|
}
|
|
@Override
|
public R payment(XpOrderPayDto dto, String uid) {
|
// mvp版本不做支付 使用优惠券抵扣为0元订单处理 处理订单状态即可
|
XpOrder order = this.getById(dto.getOrderId());
|
order.setStatus(9);
|
baseMapper.updateById(order);
|
return R.ok();
|
}
|
|
@Override
|
public boolean addOrder(XpOrder xpOrder) {
|
int insert = this.baseMapper.insert(xpOrder);
|
return true;
|
}
|
|
|
/**
|
* 获取当前用户正在执行的订单
|
*
|
* @param uid
|
* @return
|
*/
|
@Override
|
public XpOrderDetailVO getActiveOrder(String uid) {
|
XpOrderDetailVO xpOrderDetailVO = new XpOrderDetailVO();
|
XpOrder xpOrder = this.baseMapper.selectOne(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, uid).in(XpOrder::getStatus, Arrays.asList(3, 4, 5, 6, 7, 8)).orderByDesc(BaseModel::getCreateTime).last("LIMIT 1"));
|
if (xpOrder == null) {
|
return xpOrderDetailVO;
|
}
|
BeanUtils.copyProperties(xpOrder, xpOrderDetailVO);
|
// 算时间
|
if (xpOrder.getStatus() == 1) {
|
R<Integer> r = xpPricingClient.getWaitTime(new LonLatDto(xpOrder.getStartLon(), xpOrder.getStartLat()));
|
if (r.getCode() == R.SUCCESS) {
|
xpOrderDetailVO.setEstimatedTime(r.getData());
|
} else {
|
throw new RuntimeException(r.getMsg());
|
}
|
|
}
|
|
return xpOrderDetailVO;
|
}
|
}
|