package com.xiaopeng.operation.controller; import cn.hutool.core.lang.Snowflake; import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; import com.xiaopeng.api.dto.operation.CruisePointDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.operation.NewCruiseOrderDto; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.operation.*; import com.xiaopeng.api.model.order.XpCruiseOrder; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.common.core.domain.R; 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.operation.dto.XpCruisePlanAddDTO; import com.xiaopeng.operation.dto.XpCruisePlanEditDTO; import com.xiaopeng.operation.query.CruisePlanQuery; import com.xiaopeng.operation.service.*; import com.xiaopeng.operation.vo.XpCruisePlanDetailVO; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Lazy; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import io.swagger.annotations.ApiParam; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import com.xiaopeng.common.log.annotation.AdminOperationLog; import com.xiaopeng.common.log.enums.AdminBusinessType; import com.xiaopeng.common.log.enums.AdminOperationType; /** *

* 巡游计划 前端控制器 *

* * @author mitao * @since 2026-02-26 */ @Validated @RestController @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpCruisePlanController { private final IXpCruisePlanService xpCruisePlanService; private final IXpCruisePlanVehicleService xpCruisePlanVehicleService; private final IXpCruisePlanPointService xpCruisePlanPointService; private final XpPointService pointService; private final XpVehicleClient xpVehicleClient; @Resource private XpTargetedServiceVehicleService xpTargetedServiceVehicleService; @Resource private XpTargetedServiceService xpTargetedServiceService; @Resource private XpMapClient xpMapClient; @Resource private RedisService redisService; @Resource(name = "hutoolSnowflake") private Snowflake snowflake; @ApiOperation(value = "获取巡游计划分页列表", tags = {"管理后台-巡游计划"}) @PostMapping(value = {"/api/v1/xp-cruise-plan/pageList"}) public R> getPageList(@RequestBody CruisePlanQuery query) { return R.ok(xpCruisePlanService.getPageList(query)); } @ApiOperation(value = "新增巡游计划", tags = {"管理后台-巡游计划"}) @PostMapping(value = {"/api/v1/xp-cruise-plan/add"}) @AdminOperationLog( businessType = AdminBusinessType.CRUISE_PLAN, operationType = AdminOperationType.ADD, content = "新增巡游计划", appendRequestData = true ) public R add(@Valid @RequestBody XpCruisePlanAddDTO dto) { xpCruisePlanService.add(dto); return R.ok(); } @ApiOperation(value = "编辑巡游计划", tags = {"管理后台-巡游计划"}) @PostMapping(value = {"/api/v1/xp-cruise-plan/edit"}) @AdminOperationLog( businessType = AdminBusinessType.CRUISE_PLAN, operationType = AdminOperationType.EDIT, content = "编辑巡游计划", appendRequestData = true ) public R edit(@Valid @RequestBody XpCruisePlanEditDTO dto) { xpCruisePlanService.edit(dto); return R.ok(); } @ApiOperation(value = "删除巡游计划", tags = {"管理后台-巡游计划"}) @DeleteMapping(value = {"/api/v1/xp-cruise-plan/deleteById/{id}"}) @AdminOperationLog( businessType = AdminBusinessType.CRUISE_PLAN, operationType = AdminOperationType.DELETE, contentExpression = "'删除巡游计划,id=' + #p0", appendRequestData = false ) public R deleteById(@ApiParam(name = "id", value = "巡游计划ID") @PathVariable Long id) { xpCruisePlanService.deleteById(id); return R.ok(); } @ApiOperation(value = "巡游计划详情", tags = {"管理后台-巡游计划"}) @GetMapping(value = {"/api/v1/xp-cruise-plan/detail"}) public R detail(@ApiParam(name = "id", value = "巡游计划ID") @RequestParam Long id) { return R.ok(xpCruisePlanService.detail(id)); } /** * 获取车辆下个点位 * @return */ @PostMapping("/logan/inner/cruise/getCruisePoint") public R getCruisePoint(@RequestBody CruisePointDto dto) { // 先找计划 XpCruisePlanVehicle plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper().eq(XpCruisePlanVehicle::getVehicleId, dto.getVehicleId())); Long cruisePlanId = null; if (plan == null) { //没有巡游计划,判断是否在定向服务里面 List targetedServices = xpTargetedServiceService.list(new QueryWrapper().eq("status", 1)); if(targetedServices.isEmpty()){ return R.fail("没有巡游计划"); } List collect1 = targetedServices.stream().map(XpTargetedService::getId).collect(Collectors.toList()); List list = xpTargetedServiceVehicleService.list(new QueryWrapper().in("targeted_service_id", collect1) .eq("vehicle_id", dto.getVehicleId())); if(list.isEmpty()){ return R.fail("没有巡游计划"); } cruisePlanId = list.get(0).getCruisePlanId(); }else{ cruisePlanId = plan.getCruisePlanId(); } // 找对应的多个点位 List planPointList = xpCruisePlanPointService.list(new LambdaQueryWrapper().eq(XpCruisePlanPoint::getCruisePlanId, cruisePlanId).orderByAsc(XpCruisePlanPoint::getSortOrder)); // 找到现在这个点位 // 根据dto的pointId 是第几个 int index = 0; for (int i = 0; i < planPointList.size(); i++) { if (planPointList.get(i).getPointId().equals(dto.getPointId())) { index = i; break; } } XpCruiseOrder newXpCruiseOrder = dto.getNewXpCruiseOrder(); XpCruisePlanPoint xpCruisePlanPoint = null; // 判断是否是最后一个 是则往前一个 否找下一个 if (index == planPointList.size() - 1) { // 最后一个 找上一个 xpCruisePlanPoint = planPointList.get(index - 1); newXpCruiseOrder.setOrderReverse(2); } else if (index == 0) { // 第一个 找下一个 xpCruisePlanPoint = planPointList.get(index + 1); newXpCruiseOrder.setOrderReverse(1); } else { // 中间点位 if (dto.getOrderReverse() == 1) { // 正向 找下一个 xpCruisePlanPoint = planPointList.get(index + 1); newXpCruiseOrder.setOrderReverse(1); } else { // 反向找上一个 xpCruisePlanPoint = planPointList.get(index - 1); newXpCruiseOrder.setOrderReverse(2); } } Long pointId = xpCruisePlanPoint.getPointId(); XpPoint point = pointService.getById(pointId); newXpCruiseOrder.setEndPointId(pointId); newXpCruiseOrder.setEndPointName(point.getPointName()); newXpCruiseOrder.setEndLon(point.getPointLon()); newXpCruiseOrder.setEndLat(point.getPointLat()); newXpCruiseOrder.setMissionId(xpCruisePlanPoint.getCruisePlanId()); //获取巡游导航数据,如果无法获取到有效的导航,则继续用下一个点位作为终点 LonLatDto destination = new LonLatDto(); LonLatDto origin = new LonLatDto(); boolean ROUTE_FLAG = false; boolean start = false; if(newXpCruiseOrder.getOrderReverse() == 1){ for (XpCruisePlanPoint xpCruisePlanPoint1 : planPointList) { if (start || xpCruisePlanPoint1.getPointId().equals(newXpCruiseOrder.getEndPointId())) { start = true; origin.setLongitude(newXpCruiseOrder.getStartLon()); origin.setLatitude(newXpCruiseOrder.getStartLat()); XpPoint xpPoint1 = pointService.getById(xpCruisePlanPoint1.getPointId()); destination.setLongitude(xpPoint1.getPointLon()); destination.setLatitude(xpPoint1.getPointLat()); OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto(); dto1.setOrigin(origin); dto1.setDestination(destination); dto1.setRouteType(3); R routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1); if (200 != routeVoR.getCode()) { continue; } RouteVo routeVo = routeVoR.getData(); redisService.setCacheObject("CRUISE_ROUTE:" + newXpCruiseOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS); ROUTE_FLAG = true; break; } } }else{ for (int i = planPointList.size() - 1; i >= 0; i--) { XpCruisePlanPoint xpCruisePlanPoint1 = planPointList.get(i); if(start || xpCruisePlanPoint1.getPointId().equals(newXpCruiseOrder.getEndPointId())){ start = true; origin.setLongitude(newXpCruiseOrder.getStartLon()); origin.setLatitude(newXpCruiseOrder.getStartLat()); XpPoint xpPoint1 = pointService.getById(xpCruisePlanPoint1.getPointId()); destination.setLongitude(xpPoint1.getPointLon()); destination.setLatitude(xpPoint1.getPointLat()); OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto(); dto1.setOrigin(origin); dto1.setDestination(destination); dto1.setRouteType(3); R routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1); if (200 != routeVoR.getCode()) { continue; } RouteVo routeVo = routeVoR.getData(); redisService.setCacheObject("CRUISE_ROUTE:" + newXpCruiseOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS); ROUTE_FLAG = true; break; } } } if(!ROUTE_FLAG){ return R.fail("巡游计划获取导航信息失败"); } return R.ok(newXpCruiseOrder); } /** * 获取巡游计划 * @param vehicleId * @return */ @PostMapping("/logan/inner/cruise/getCruisePlan") public R getCruisePlan(@RequestParam Long vehicleId) { XpCruisePlanVehicle plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper().eq(XpCruisePlanVehicle::getVehicleId, vehicleId)); return R.ok(plan); } /** * 获取巡游计划点位列表 * @param vehicleId * @return */ @PostMapping("/logan/inner/cruise/getCruisePlanPointList") public R> getCruisePlanPointList(@RequestParam Long vehicleId) { // 先找计划 XpCruisePlanVehicle plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper().eq(XpCruisePlanVehicle::getVehicleId, vehicleId)); Long cruisePlanId = null; if(null == plan){ //没有巡游计划,判断是否在定向服务里面 List targetedServices = xpTargetedServiceService.list(new QueryWrapper().eq("status", 1)); if(targetedServices.isEmpty()){ return R.fail("没有巡游计划,执行收车失败"); } List collect1 = targetedServices.stream().map(XpTargetedService::getId).collect(Collectors.toList()); List list = xpTargetedServiceVehicleService.list(new QueryWrapper().in("targeted_service_id", collect1) .eq("vehicle_id", vehicleId)); if(list.isEmpty()){ return R.fail("没有巡游计划,执行收车失败"); } cruisePlanId = list.get(0).getCruisePlanId(); }else{ cruisePlanId = plan.getCruisePlanId(); } // 找对应的多个点位 List planPointList = xpCruisePlanPointService.list(new LambdaQueryWrapper() .eq(XpCruisePlanPoint::getCruisePlanId, cruisePlanId).orderByAsc(XpCruisePlanPoint::getSortOrder)); return R.ok(planPointList); } /** * 获取巡游订单数据 * @return */ @PostMapping("/logan/inner/cruise/getNewCruiseOrder") public R getNewCruiseOrder(@RequestBody NewCruiseOrderDto dto) { // 先找计划 XpCruisePlanVehicle plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper().eq(XpCruisePlanVehicle::getVehicleId, dto.getVehicleId())); if(null == plan){ //没有巡游计划,判断是否在定向服务里面 List targetedServices = xpTargetedServiceService.list(new QueryWrapper().eq("status", 1)); if(targetedServices.isEmpty()){ return R.ok(null); } List collect1 = targetedServices.stream().map(XpTargetedService::getId).collect(Collectors.toList()); List list = xpTargetedServiceVehicleService.list(new QueryWrapper().in("targeted_service_id", collect1) .eq("vehicle_id", dto.getVehicleId())); if(list.isEmpty()){ return R.ok(null); } plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper() .eq(XpCruisePlanVehicle::getCruisePlanId, list.get(0).getCruisePlanId()).eq(XpCruisePlanVehicle::getVehicleId, dto.getVehicleId())); } // 找对应的多个点位 List planPointList = xpCruisePlanPointService.list(new LambdaQueryWrapper().eq(XpCruisePlanPoint::getCruisePlanId, plan.getCruisePlanId()).orderByAsc(XpCruisePlanPoint::getSortOrder)); XpCruiseOrder newXpCruiseOrder = new XpCruiseOrder(); newXpCruiseOrder.setFleetId(dto.getFleetId()); newXpCruiseOrder.setVehicleId(dto.getVehicleId()); newXpCruiseOrder.setVehicleVin(dto.getVehicleVin()); newXpCruiseOrder.setOrderType(1); newXpCruiseOrder.setMissionId(plan.getCruisePlanId()); newXpCruiseOrder.setStatus(1); newXpCruiseOrder.setOrderReverse(1); newXpCruiseOrder.setXpuTaskId(snowflake.nextId() + ""); GeoJsonPoint point = dto.getPoint(); // 起点 newXpCruiseOrder.setStartLon(point.getX()); newXpCruiseOrder.setStartLat(point.getY()); // 终点 XpCruisePlanPoint endCruisePlanPoint = planPointList.get(0); Long endPointId = endCruisePlanPoint.getPointId(); XpPoint endPoint = pointService.getById(endPointId); newXpCruiseOrder.setEndPointId(endPointId); newXpCruiseOrder.setEndPointName(endPoint.getPointName()); newXpCruiseOrder.setEndLon(endPoint.getPointLon()); newXpCruiseOrder.setEndLat(endPoint.getPointLat()); //获取巡游导航数据,如果无法获取到有效的导航,则继续用下一个点位作为终点 LonLatDto destination = new LonLatDto(); LonLatDto origin = new LonLatDto(); boolean ROUTE_FLAG = false; boolean start = false; if(newXpCruiseOrder.getOrderReverse() == 1){ for (XpCruisePlanPoint xpCruisePlanPoint1 : planPointList) { if (start || xpCruisePlanPoint1.getPointId().equals(newXpCruiseOrder.getEndPointId())) { start = true; origin.setLongitude(newXpCruiseOrder.getStartLon()); origin.setLatitude(newXpCruiseOrder.getStartLat()); XpPoint xpPoint1 = pointService.getById(xpCruisePlanPoint1.getPointId()); destination.setLongitude(xpPoint1.getPointLon()); destination.setLatitude(xpPoint1.getPointLat()); OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto(); dto1.setOrigin(origin); dto1.setDestination(destination); dto1.setRouteType(3); R routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1); if (200 != routeVoR.getCode()) { continue; } RouteVo routeVo = routeVoR.getData(); redisService.setCacheObject("CRUISE_ROUTE:" + newXpCruiseOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS); ROUTE_FLAG = true; break; } } }else{ for (int i = planPointList.size() - 1; i >= 0; i--) { XpCruisePlanPoint xpCruisePlanPoint1 = planPointList.get(i); if(start || xpCruisePlanPoint1.getPointId().equals(newXpCruiseOrder.getEndPointId())){ start = true; origin.setLongitude(newXpCruiseOrder.getStartLon()); origin.setLatitude(newXpCruiseOrder.getStartLat()); XpPoint xpPoint1 = pointService.getById(xpCruisePlanPoint1.getPointId()); destination.setLongitude(xpPoint1.getPointLon()); destination.setLatitude(xpPoint1.getPointLat()); OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto(); dto1.setOrigin(origin); dto1.setDestination(destination); dto1.setRouteType(3); R routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1); if (200 != routeVoR.getCode()) { continue; } RouteVo routeVo = routeVoR.getData(); redisService.setCacheObject("CRUISE_ROUTE:" + newXpCruiseOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS); ROUTE_FLAG = true; break; } } } if(!ROUTE_FLAG){ return R.fail("巡游计划获取导航信息失败"); } return R.ok(newXpCruiseOrder); } /** * 获取车辆返回点位 * @param xpCruiseOrder * @return */ @PostMapping("/logan/inner/cruise/findReturnCruisePoint") public R findReturnCruisePoint(@RequestBody XpCruiseOrder xpCruiseOrder) { // 先找计划 XpCruisePlanVehicle plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper().eq(XpCruisePlanVehicle::getVehicleId, xpCruiseOrder.getVehicleId())); if(null == plan){ //没有巡游计划,判断是否在定向服务里面 List targetedServices = xpTargetedServiceService.list(new QueryWrapper().eq("status", 1)); if(targetedServices.isEmpty()){ return R.fail("没有巡游计划,执行收车失败"); } List collect1 = targetedServices.stream().map(XpTargetedService::getId).collect(Collectors.toList()); List list = xpTargetedServiceVehicleService.list(new QueryWrapper().in("targeted_service_id", collect1) .eq("vehicle_id", xpCruiseOrder.getVehicleId())); if(list.isEmpty()){ return R.fail("没有巡游计划,执行收车失败"); } plan = xpCruisePlanVehicleService.getOne(new LambdaQueryWrapper() .eq(XpCruisePlanVehicle::getCruisePlanId, list.get(0).getCruisePlanId()).eq(XpCruisePlanVehicle::getVehicleId, xpCruiseOrder.getVehicleId())); } // 找对应的多个点位 List planPointList = xpCruisePlanPointService.list(new LambdaQueryWrapper().eq(XpCruisePlanPoint::getCruisePlanId, plan.getCruisePlanId()).orderByAsc(XpCruisePlanPoint::getSortOrder)); XpPoint xpPoint = pointService.list(new LambdaQueryWrapper().eq(XpPoint::getParkingPoint, 1).in(XpPoint::getId, planPointList.stream().map(XpCruisePlanPoint::getPointId).collect(Collectors.toList()))).get(0); xpCruiseOrder.setEndPointId(xpPoint.getId()); xpCruiseOrder.setEndPointName(xpPoint.getPointName()); xpCruiseOrder.setEndLon(xpPoint.getPointLon()); xpCruiseOrder.setEndLat(xpPoint.getPointLat()); xpCruiseOrder.setMissionId(plan.getCruisePlanId()); //获取巡游导航数据,如果无法获取到有效的导航,则继续用下一个点位作为终点 LonLatDto destination = new LonLatDto(); LonLatDto origin = new LonLatDto(); boolean ROUTE_FLAG = false; boolean start = false; if(xpCruiseOrder.getOrderReverse() == 1){ for (XpCruisePlanPoint xpCruisePlanPoint1 : planPointList) { if (start || xpCruisePlanPoint1.getPointId().equals(xpCruiseOrder.getEndPointId())) { start = true; origin.setLongitude(xpCruiseOrder.getStartLon()); origin.setLatitude(xpCruiseOrder.getStartLat()); XpPoint xpPoint1 = pointService.getById(xpCruisePlanPoint1.getPointId()); destination.setLongitude(xpPoint1.getPointLon()); destination.setLatitude(xpPoint1.getPointLat()); OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto(); dto1.setOrigin(origin); dto1.setDestination(destination); dto1.setRouteType(3); R routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1); if (200 != routeVoR.getCode()) { continue; } RouteVo routeVo = routeVoR.getData(); redisService.setCacheObject("CRUISE_ROUTE:" + xpCruiseOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS); ROUTE_FLAG = true; break; } } }else{ for (int i = planPointList.size() - 1; i >= 0; i--) { XpCruisePlanPoint xpCruisePlanPoint1 = planPointList.get(i); if(start || xpCruisePlanPoint1.getPointId().equals(xpCruiseOrder.getEndPointId())){ start = true; origin.setLongitude(xpCruiseOrder.getStartLon()); origin.setLatitude(xpCruiseOrder.getStartLat()); XpPoint xpPoint1 = pointService.getById(xpCruisePlanPoint1.getPointId()); destination.setLongitude(xpPoint1.getPointLon()); destination.setLatitude(xpPoint1.getPointLat()); OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto(); dto1.setOrigin(origin); dto1.setDestination(destination); dto1.setRouteType(3); R routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1); if (200 != routeVoR.getCode()) { continue; } RouteVo routeVo = routeVoR.getData(); redisService.setCacheObject("CRUISE_ROUTE:" + xpCruiseOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS); ROUTE_FLAG = true; break; } } } if(!ROUTE_FLAG){ return R.fail("巡游计划获取导航信息失败"); } return R.ok(xpCruiseOrder); } /** * 判断点位ID列表是否存在关联的巡游计划点位(内部接口) */ @PostMapping("/logan/inner/cruise/existsCruisePlanPointByPointIds") public R existsCruisePlanPointByPointIds(@RequestBody List pointIds) { List distinctPointIds = pointIds == null ? java.util.Collections.emptyList() : pointIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); if (distinctPointIds.isEmpty()) { return R.ok(Boolean.FALSE); } XpCruisePlanPoint exists = xpCruisePlanPointService.getOne( new LambdaQueryWrapper() .in(XpCruisePlanPoint::getPointId, distinctPointIds) .last("limit 1") ); return R.ok(exists != null); } }