package com.xiaopeng.operation.controller;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaopeng.api.dto.operation.CruisePointDto;
import com.xiaopeng.api.dto.operation.NewCruiseOrderDto;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.operation.XpCruisePlan;
import com.xiaopeng.api.model.operation.XpCruisePlanPoint;
import com.xiaopeng.api.model.operation.XpCruisePlanVehicle;
import com.xiaopeng.api.model.operation.XpPoint;
import com.xiaopeng.api.model.order.XpCruiseOrder;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.operation.dto.XpCruisePlanAddDTO;
import com.xiaopeng.operation.dto.XpCruisePlanEditDTO;
import com.xiaopeng.operation.query.CruisePlanQuery;
import com.xiaopeng.operation.service.IXpCruisePlanPointService;
import com.xiaopeng.operation.service.IXpCruisePlanService;
import com.xiaopeng.operation.service.IXpCruisePlanVehicleService;
import com.xiaopeng.operation.service.XpPointService;
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.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.stream.Collectors;
/**
*
* 巡游计划 前端控制器
*
*
* @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;
@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"})
public R> add(@Valid @RequestBody XpCruisePlanAddDTO dto) {
xpCruisePlanService.add(dto);
return R.ok();
}
@ApiOperation(value = "编辑巡游计划", tags = {"管理后台-巡游计划"})
@PostMapping(value = {"/api/v1/xp-cruise-plan/edit"})
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}"})
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()));
if (plan == null) {
return R.fail("没有找到对应的计划");
}
// 找对应的多个点位
List planPointList = xpCruisePlanPointService.list(new LambdaQueryWrapper().eq(XpCruisePlanPoint::getCruisePlanId, plan.getCruisePlanId()).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());
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));
// 找对应的多个点位
List planPointList = xpCruisePlanPointService.list(new LambdaQueryWrapper().eq(XpCruisePlanPoint::getCruisePlanId, plan.getCruisePlanId()).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()));
// 找对应的多个点位
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);
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());
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){
return R.fail("没有巡游计划,执行收车失败");
}
// 找对应的多个点位
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());
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);
}
}