puzhibing
2026-03-07 2a889bf2b917b72fcc03104f5064cf305ce1612b
修改bug
26个文件已修改
798 ■■■■■ 已修改文件
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/SysUserController.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/SysGroupAddDTO.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsRoleMapper.xml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsUserMapper.xml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpPoint.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/PointListQuery.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/PointPageListListQuery.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/constant/I18nKeyConstant.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/exportExcel/XpPointExportExcel.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/resources/mapper/XpPointMapper.xml 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpAgreementController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/QuartzManager.java 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpSystemSettingServiceImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/task/BannerTaskUtil.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/resources/i18n/messages.properties 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/resources/i18n/messages_en_US.properties 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/resources/i18n/messages_zh_CN.properties 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpPointMapper.xml 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleAnnualRecordServiceImpl.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/SysUserController.java
@@ -32,6 +32,10 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.KeyPair;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -44,6 +48,9 @@
 */
@RestController
public class SysUserController extends BaseController {
    private static final DateTimeFormatter UNIQUE_NUMBER_DATE_FORMATTER = DateTimeFormatter.BASIC_ISO_DATE;
    private static final String UNIQUE_NUMBER_REDIS_KEY_PREFIX = "sys:user:unique-number:";
    @Resource
    private ISysUserService userService;
@@ -99,11 +106,7 @@
        if (StringUtils.isNotEmpty(user.getUserAccount()) && !userService.checkUserNameUnique(user)) {
            throw new ServiceException("登录账号重复", I18nKeyConstant.ACCOUNT_DUPLICATE);
        }
        //校验编号是否唯一
        Long count = userService.lambdaQuery().eq(SysUser::getUniqueNumber, user.getUniqueNumber()).count();
        if (count > 0) {
            throw new ServiceException("用户编号已存在", I18nKeyConstant.ACCOUNT_UNIQUE_NUMBER_DUPLICATE);
        }
        user.setUniqueNumber(generateUniqueNumber());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        //TODO 手机号脱敏存储
        userService.insertUser(user);
@@ -113,6 +116,36 @@
        sysUserRoleService.insertSysUserRole(sysUserRole);
        return AjaxResult.success();
    }
    private String generateUniqueNumber() {
        LocalDate today = LocalDate.now();
        String dateStr = UNIQUE_NUMBER_DATE_FORMATTER.format(today);
        String redisKey = UNIQUE_NUMBER_REDIS_KEY_PREFIX + dateStr;
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime tomorrowStart = today.plusDays(1).atStartOfDay();
        long expireSeconds = Duration.between(now, tomorrowStart).getSeconds() + 60;
        for (int i = 0; i < 10; i++) {
            Long seq = redisService.redisTemplate.opsForValue().increment(redisKey);
            if (seq == null) {
                throw new ServiceException("用户编号生成失败");
            }
            if (expireSeconds > 0) {
                redisService.expire(redisKey, expireSeconds, TimeUnit.SECONDS);
            }
            if (seq > 999999L) {
                throw new ServiceException("当天生成用户编号已达上限");
            }
            String uniqueNumber = dateStr + String.format("%06d", seq);
            Long count = userService.lambdaQuery().eq(SysUser::getUniqueNumber, uniqueNumber).count();
            if (count == null || count == 0L) {
                return uniqueNumber;
            }
        }
        throw new ServiceException("用户编号生成失败,请稍后重试");
    }
    
    
    @GetMapping("/verifyUserNameRepeat/{username}")
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/SysGroupAddDTO.java
@@ -23,7 +23,6 @@
    private String groupName;
    @ApiModelProperty(value = "备注", required = true)
    @NotBlank(message = "{validation.group.remarks.notBlank}")
    private String remarks;
    @ApiModelProperty(value = "分组类型 1=管理端 2=运维app")
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsRoleMapper.xml
@@ -31,16 +31,18 @@
        FROM xp_operations_user u
        LEFT JOIN xp_operations_role ur ON u.id = ur.operations_user_id
        LEFT JOIN sys_role r ON ur.role_id = r.id AND r.is_deleted = 0
        WHERE 1=1
        <if test="nickName != null and nickName != ''">
            AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
        </if>
        <if test="phoneNumber != null and phoneNumber != ''">
            AND u.phone_number LIKE CONCAT('%', #{phoneNumber}, '%')
        </if>
        <if test="roleId != null">
            AND r.id = #{roleId}
        </if>
        <where>
            u.is_deleted = 0
            <if test="nickName != null and nickName != ''">
                AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
            </if>
            <if test="phoneNumber != null and phoneNumber != ''">
                AND u.phone_number LIKE CONCAT('%', #{phoneNumber}, '%')
            </if>
            <if test="roleId != null">
                AND r.id = #{roleId}
            </if>
        </where>
    </select>
    <select id="selectSysUserRoleByOperationUserId"
            resultType="com.xiaopeng.api.model.account.XpOperationsRole">
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsUserMapper.xml
@@ -16,6 +16,7 @@
        LEFT JOIN xp_operations_role ur ON u.id = ur.operations_user_id
        LEFT JOIN sys_role r ON ur.role_id = r.id AND r.is_deleted = 0
     <where>
        u.is_deleted = 0
        <if test="query.nickName != null and query.nickName != ''">
            AND u.nick_name LIKE CONCAT('%', #{query.nickName}, '%')
        </if>
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpPoint.java
@@ -1,9 +1,6 @@
package com.xiaopeng.api.model.operation;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -37,7 +34,7 @@
    private Long id;
    @ApiModelProperty(value = "电子围栏区域id")
    @TableField("electronic_area_id")
    @TableField(value = "electronic_area_id", updateStrategy = FieldStrategy.NEVER)
    private Long electronicAreaId;
    @ApiModelProperty(value = "点位名称")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/PointListQuery.java
@@ -19,4 +19,7 @@
    @ApiModelProperty(value = "点位类型1运营点位 2测试点位")
    private Integer pointType;
    @ApiModelProperty(value = "点位状态(多选) 1待测试 2测试中 3测试不通过 4可运营 5待生效 6启用中 7已停用 8已失效")
    private List<Integer> operationStatusList;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/PointPageListListQuery.java
@@ -14,8 +14,8 @@
    private String pointNumber;
    @ApiModelProperty(value = "点位名称")
    private String pointName;
    @ApiModelProperty(value = "点位状态 1待测试 2测试中 3测试不通过 4可运营 5待生效 6启用中 7已停用 8失效")
    private Integer operationStatus;
    @ApiModelProperty(value = "点位状态(多选) 1待测试 2测试中 3测试不通过 4可运营 5待生效 6启用中 7已停用 8失效")
    private List<Integer> operationStatusList;
    @ApiModelProperty(value = "限停时长")
    private Integer parkingTimeLimit;
    @ApiModelProperty(value = "点位经纬度")
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -38,6 +38,7 @@
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
@@ -293,6 +294,7 @@
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000));
        Long finalOrderId = orderId;
        Long finalOrderId1 = orderId;
        threadPoolExecutor.execute(() -> {
            //等待10秒后开始执行车子位移
            try {
@@ -312,17 +314,29 @@
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
                if (null == vehiclePosition) {
                    vehiclePosition = new VehiclePosition();
                    vehiclePosition.setVin(vin);
                    vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude));
                    vehiclePosition.setCourse(60D);
                    vehiclePosition.setAlt(100F);
                    vehiclePosition.setSpeed(50F);
                    vehiclePosition.setCurrentElectricity(80);
                    vehiclePosition.setMileageRange(300f);
                    vehiclePosition.setHasOrder(0);
                    vehiclePosition.setOrderId(finalOrderId1);
                    mongoTemplate.save(vehiclePosition);
                }else{
                    vehiclePosition.setOrderId(finalOrderId1);
                    Update update = new Update()
                            .set("point", new GeoJsonPoint(longitude, latitude))
                            .set("course", 60D)
                            .set("alt", 100F)
                            .set("speed", 50F)
                            .set("currentElectricity", 80)
                            .set("mileageRange", 300f)
                            .set("hasOrder", 0)
                            .set("orderId", finalOrderId1);
                    mongoTemplate.updateFirst(new Query(Criteria.where("vin").is(vin)), update, VehiclePosition.class);
                }
                vehiclePosition.setVin(vin);
                vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude));
                vehiclePosition.setCourse(60D);
                vehiclePosition.setAlt(100F);
                //车辆动态信息
                vehiclePosition.setSpeed(50F);
                vehiclePosition.setCurrentElectricity(80);
                vehiclePosition.setMileageRange(300f);
                vehiclePosition.setOrderId(finalOrderId);
                mongoTemplate.save(vehiclePosition);
                //调用推送服务接口
                if (null != finalOrderId) {
                    PushOrderRouteDTO dto = new PushOrderRouteDTO();
@@ -459,6 +473,7 @@
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000));
        Long finalOrderId = orderId;
        Long finalOrderId1 = orderId;
        threadPoolExecutor.execute(() -> {
            //等待10秒后开始执行车子位移
            try {
@@ -479,17 +494,29 @@
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
                if (null == vehiclePosition) {
                    vehiclePosition = new VehiclePosition();
                    vehiclePosition.setVin(vin);
                    vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude));
                    vehiclePosition.setCourse(60D);
                    vehiclePosition.setAlt(100F);
                    vehiclePosition.setSpeed(50F);
                    vehiclePosition.setCurrentElectricity(80);
                    vehiclePosition.setMileageRange(300f);
                    vehiclePosition.setHasOrder(0);
                    vehiclePosition.setOrderId(finalOrderId1);
                    mongoTemplate.save(vehiclePosition);
                }else{
                    vehiclePosition.setOrderId(finalOrderId1);
                    Update update = new Update()
                            .set("point", new GeoJsonPoint(longitude, latitude))
                            .set("course", 60D)
                            .set("alt", 100F)
                            .set("speed", 50F)
                            .set("currentElectricity", 80)
                            .set("mileageRange", 300f)
                            .set("hasOrder", 0)
                            .set("orderId", finalOrderId1);
                    mongoTemplate.updateFirst(new Query(Criteria.where("vin").is(vin)), update, VehiclePosition.class);
                }
                vehiclePosition.setVin(vin);
                vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude));
                vehiclePosition.setCourse(60D);
                vehiclePosition.setAlt(100F);
                //车辆动态信息
                vehiclePosition.setSpeed(50F);
                vehiclePosition.setCurrentElectricity(80);
                vehiclePosition.setMileageRange(300f);
                vehiclePosition.setOrderId(finalOrderId);
                mongoTemplate.save(vehiclePosition);
                //调用推送服务接口
                if (null != finalOrderId) {
                    PushOrderRouteDTO dto = new PushOrderRouteDTO();
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/constant/I18nKeyConstant.java
@@ -12,6 +12,8 @@
    String NO_CURRENT_REGION = "no.current.region";
    String NO_CURRENT_POINT = "no.current.point";
    String SYSTEM_EXCEPTION = "system.exception";
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java
@@ -444,9 +444,9 @@
        XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(xpElectronicFenceArea.getElectronicId());
        String operationStrategy = xpElectronicFence.getOperationStrategy();
        Boolean inOperationTime = isInOperationTime(operationStrategy);
//        if (!inOperationTime) {
//            throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
//        }
        if (!inOperationTime && xpElectronicFence.getFailureType()!=1) {
            throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
        }
        Integer cancelCount = xpTradingStrategyMapper.selectOne(null).getCancleCount();
@@ -458,9 +458,15 @@
        // 获取起点经纬度
        XpPoint xpPoint = xpPointService.getById(dto.getStartPointId());
        if(xpPoint.getOperationStatus()!=2){
            throw new ServiceException("该站点已停止运营", I18nKeyConstant.NO_CURRENT_POINT);
        }
        // 终点
        XpPoint endXpPoint = xpPointService.getById(dto.getEndPointId());
        if(endXpPoint.getOperationStatus()!=2){
            throw new ServiceException("该站点已停止运营", I18nKeyConstant.NO_CURRENT_POINT);
        }
        // 判断点位是否在运营区域内
        boolean inTime = xpPointClient.nowInTimePoint(dto.getStartPointId()).getData();
@@ -556,7 +562,17 @@
        routeAndFareDto.setDestination(lonLatDto1);
        XpOpenCity xpOpenCity = xpOpenCityMapper.selectById(dto.getOpenCityId());
        Map<String, String> geocode = gdMapGeocodingUtil.geocode(xpPoint.getPointLon().toString(), xpPoint.getPointLat().toString());
        if(null == geocode){
            throw new ServiceException("获取城市信息失败", I18nKeyConstant.CITY_NOT_FOUND);
        }
        String cityCode = geocode.get("cityCode");
        List<XpOpenCity> openCities = xpOpenCityMapper.selectList(new LambdaQueryWrapper<XpOpenCity>().eq(XpOpenCity::getCityCode, cityCode));
        if (openCities == null || openCities.isEmpty()) {
            throw new ServiceException("获取城市信息失败", I18nKeyConstant.CITY_NOT_FOUND);
        }
        XpOpenCity xpOpenCity = openCities.get(0);
        dto.setOpenCityId(xpOpenCity.getId());
        XpRoutePlan xpRoutePlan = xpRoutePlanMapper.selectOne(new LambdaQueryWrapper<XpRoutePlan>().eq(XpRoutePlan::getAuditStatus, 2).eq(XpRoutePlan::getCityCode, xpOpenCity.getCityCode()));
        if (xpRoutePlan != null) {
            routeAndFareDto.setRoutePlanRule(xpRoutePlan.getRoutePlanRule());
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java
@@ -10,23 +10,40 @@
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.WebUtils;
import com.xiaopeng.common.core.web.controller.BaseController;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.api.dto.map.XpPointExportExcelQuery;
import com.xiaopeng.map.exportExcel.XpPointExportExcel;
import com.xiaopeng.map.service.XpElectronicFenceAreaService;
import com.xiaopeng.map.service.XpElectronicFenceService;
import com.xiaopeng.map.service.XpPointService;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -35,6 +52,8 @@
@RequestMapping("/api/v1/point")
@Api(tags = "点位管理")
public class XpPointManagementController extends BaseController {
    private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Resource
    private XpPointService xpPointService;
@@ -79,6 +98,49 @@
        List<XpPoint> list = xpPointService.lambdaQuery().in(XpPoint::getId, query.getPointIds()).list();
        return R.ok(list);
    }
    // "2029885249115987970" "2029883649798512642"
    @ApiOperation(value = "点位导出")
    @PostMapping("/exportExcel")
    public void exportExcel(@RequestBody XpPointExportExcelQuery query) {
        List<Long> pointIds = query == null ? Collections.emptyList() : query.getPointIds();
        List<Long> distinctIds = pointIds == null
                ? Collections.emptyList()
                : pointIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<XpPoint> points = distinctIds.isEmpty()
                ? Collections.emptyList()
                : xpPointService.lambdaQuery().in(XpPoint::getId, distinctIds).list();
        Map<Long, XpPoint> pointById = points.stream()
                .filter(p -> p.getId() != null)
                .collect(Collectors.toMap(XpPoint::getId, Function.identity(), (a, b) -> a));
        List<XpPointExportExcel> exportList = new ArrayList<>(points.size());
        for (Long id : distinctIds) {
            XpPoint xpPoint = pointById.get(id);
            if (xpPoint == null) {
                continue;
            }
            exportList.add(toExportRow(xpPoint));
        }
        HttpServletResponse response = WebUtils.response();
        if (response == null) {
            throw new ServiceException("导出失败:未获取到响应对象");
        }
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        try {
            String fileName = URLEncoder.encode("点位列表.xls", StandardCharsets.UTF_8.name());
            response.setHeader("Content-disposition", "attachment;filename=" + fileName);
            try (Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), XpPointExportExcel.class, exportList);
                 ServletOutputStream outputStream = response.getOutputStream()) {
                workbook.write(outputStream);
            }
        } catch (IOException e) {
            log.error("点位导出失败 pointIds={}", distinctIds, e);
            throw new ServiceException("点位导出失败");
        }
    }
    /**
     * 新增点位
@@ -114,11 +176,16 @@
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R edit(@Validated @RequestBody PointUpdateDto pointAddDto) {
        XpPoint xpPoint = xpPointService.getById(pointAddDto.getId());
        //先删除原有的数据,因为会存在点位的从属区域变化的情况,所以先删除原有的数据后添加新的数据重新分片到新的库中
        xpPointService.removeById(pointAddDto.getId());
        BeanUtils.copyProperties(pointAddDto, xpPoint);
        xpPoint.setId(null);
        xpPointService.save(xpPoint);
        if (!xpPoint.getElectronicAreaId().equals(pointAddDto.getElectronicAreaId())) {
            BeanUtils.copyProperties(pointAddDto, xpPoint);
            xpPointService.updateById(xpPoint);
        } else {
            //先删除原有的数据,因为会存在点位的从属区域变化的情况,所以先删除原有的数据后添加新的数据重新分片到新的库中
            BeanUtils.copyProperties(pointAddDto, xpPoint);
            xpPointService.removeById(pointAddDto.getId());
            xpPoint.setId(null);
            xpPointService.save(xpPoint);
        }
        return R.ok();
    }
@@ -147,5 +214,56 @@
        return R.ok();
    }
    private static XpPointExportExcel toExportRow(XpPoint xpPoint) {
        XpPointExportExcel exportExcel = new XpPointExportExcel();
        exportExcel.setPointNumber(xpPoint.getPointNumber());
        exportExcel.setPointName(xpPoint.getPointName());
        exportExcel.setStatus(calcExportStatus(xpPoint.getOperationStatus(), xpPoint.getVerificationStatus()));
        exportExcel.setParkingTimeLimit(xpPoint.getParkingTimeLimit() == null ? null : String.valueOf(xpPoint.getParkingTimeLimit()));
        exportExcel.setPointLon(xpPoint.getPointLon());
        exportExcel.setPointLat(xpPoint.getPointLat());
        exportExcel.setCreateBy(xpPoint.getCreateBy());
        exportExcel.setCreateTime(formatExportTime(xpPoint.getCreateTime()));
        return exportExcel;
    }
    private static String formatExportTime(LocalDateTime time) {
        return time == null ? null : EXPORT_TIME_FORMATTER.format(time);
    }
    private static Integer calcExportStatus(Integer operationStatus, Integer verificationStatus) {
        if (operationStatus == null) {
            return null;
        }
        if (verificationStatus == 1) {
            return 1;
        }
        if (verificationStatus == 2) {
            return 2;
        }
        if (verificationStatus == 4) {
            return 3;
        }
        if (verificationStatus == 3 && operationStatus == 1) {
            return 4;
        }
        if (verificationStatus == 5 && operationStatus == 1) {
            return 5;
        }
        if (operationStatus == 2) {
            return 6;
        }
        if (operationStatus == 3) {
            return 7;
        }
        if (operationStatus == 4) {
            return 8;
        }
        if (operationStatus != 1 || verificationStatus == null) {
            return null;
        }
        return null;
    }
}
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/exportExcel/XpPointExportExcel.java
@@ -22,7 +22,7 @@
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "点位名称",width = 20)
    private String pointName;
    @ApiModelProperty(value = "状态")
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "状态",width = 20,replace = {"待测试_1","测试中_2","测试不通过_3","可运营_4","待生效_5","启用中_6","已停用_7","失效_8",})
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "状态",width = 20,replace = {"待测试_1","测试中_2","测试不通过_3","可运营_4","待生效_5","启用中_6","已停用_7","已失效_8",})
    private Integer status;
    @ApiModelProperty(value = "限停时长")
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "限停时长",width = 20)
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
@@ -44,6 +44,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -391,6 +392,30 @@
            xpElectronicFence.setCityCode(dto.getCityCode());
            this.updateById(xpElectronicFence);
            // 禁行区(areaType=2)差异删除:对比原有禁行区与本次编辑入参禁行区(按id)
            List<XpElectronicFenceArea> existingProhibitedAreas = xpElectronicFenceAreaService.lambdaQuery()
                    .eq(XpElectronicFenceArea::getElectronicId, dto.getId())
                    .eq(XpElectronicFenceArea::getAreaType, 2)
                    .list();
            Set<Long> incomingProhibitedIds = updatedElectronicFenceAreas.stream()
                    .filter(a -> a != null && a.getAreaType() != null && a.getAreaType() == 2 && a.getId() != null)
                    .map(XpElectronicFenceArea::getId)
                    .collect(Collectors.toSet());
            List<Long> toDeleteProhibitedIds = existingProhibitedAreas.stream()
                    .map(XpElectronicFenceArea::getId)
                    .filter(id -> id != null && !incomingProhibitedIds.contains(id))
                    .collect(Collectors.toList());
            if (!toDeleteProhibitedIds.isEmpty()) {
                // 逻辑删除MySQL禁行区
                xpElectronicFenceAreaService.removeByIds(toDeleteProhibitedIds);
                // 同步删除Mongo禁行区多边形
                List<String> toDeleteAreaIdStrings = toDeleteProhibitedIds.stream().map(String::valueOf).collect(Collectors.toList());
                Query delMongoQuery = new Query();
                delMongoQuery.addCriteria(Criteria.where("fenceId").is(String.valueOf(dto.getId())));
                delMongoQuery.addCriteria(Criteria.where("areaId").in(toDeleteAreaIdStrings));
                mongoTemplate.remove(delMongoQuery, XpGeoFencingProhibitedPolygon.class);
            }
            // 删除旧的区域数据,然后保存新的区域数据
            mongoTemplate.remove(new Query(Criteria.where("fenceId").is(String.valueOf(dto.getId()))), XpGeoFencingPolygon.class);
            if (xpElectronicFence.getStatus() == 2) {
xp-robotaxi-map-boot/src/main/resources/mapper/XpPointMapper.xml
@@ -80,11 +80,22 @@
        <if test="query.pointType != null">
            and t1.point_type = #{query.pointType}
        </if>
        <if test="query.operationStatusIds != null and query.operationStatusIds.size()>0">
            AND t1.operation_status IN
            <foreach collection="query.operationStatusIds" separator="," item="id" open="(" close=")">
                #{id}
            </foreach>
        <if test="query.operationStatusList != null and query.operationStatusList.size() > 0">
            <trim prefix="and (" suffix=")" prefixOverrides="OR">
                <foreach collection="query.operationStatusList" item="st">
                    <choose>
                        <when test="st == 1">OR t1.verification_status = 1</when>
                        <when test="st == 2">OR t1.verification_status = 2</when>
                        <when test="st == 3">OR t1.verification_status = 4</when>
                        <when test="st == 4">OR (t1.verification_status = 3 and t1.operation_status = 1)</when>
                        <when test="st == 5">OR (t1.verification_status = 5 and t1.operation_status = 1)</when>
                        <when test="st == 6">OR t1.operation_status = 2</when>
                        <when test="st == 7">OR t1.operation_status = 3</when>
                        <when test="st == 8">OR t1.operation_status = 4</when>
                        <otherwise>OR 1 = 0</otherwise>
                    </choose>
                </foreach>
            </trim>
        </if>
        order by t1.create_time desc
    </select>
@@ -132,31 +143,22 @@
        <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
            and xp.create_time between #{query.startTime} and #{query.endTime}
        </if>
        <if test="query.operationStatus != null">
        <if test="query.operationStatus ==1">
            and xp.verification_status = 1
        </if>
          <if test="query.operationStatus ==2">
            and xp.verification_status = 2
        </if>
          <if test="query.operationStatus ==3">
            and xp.verification_status = 4
        </if>
          <if test="query.operationStatus ==4">
            and xp.verification_status = 3 and xp.operation_status =1
        </if>
            <if test="query.operationStatus ==5">
                and xp.verification_status = 3 and xp.operation_status =1
            </if>
            <if test="query.operationStatus ==6">
                and xp.operation_status =2
            </if>
          <if test="query.operationStatus ==7">
                and xp.operation_status =3
            </if>
          <if test="query.operationStatus ==8">
                and xp.operation_status =4
            </if>
        <if test="query.operationStatusList != null and query.operationStatusList.size() > 0">
            <trim prefix="and (" suffix=")" prefixOverrides="OR">
                <foreach collection="query.operationStatusList" item="st">
                    <choose>
                        <when test="st == 1">OR xp.verification_status = 1</when>
                        <when test="st == 2">OR xp.verification_status = 2</when>
                        <when test="st == 3">OR xp.verification_status = 4</when>
                        <when test="st == 4">OR (xp.verification_status = 3 and xp.operation_status = 1)</when>
                        <when test="st == 5">OR (xp.verification_status = 5 and xp.operation_status = 1)</when>
                        <when test="st == 6">OR xp.operation_status = 2</when>
                        <when test="st == 7">OR xp.operation_status = 3</when>
                        <when test="st == 8">OR xp.operation_status = 4</when>
                        <otherwise>OR 1 = 0</otherwise>
                    </choose>
                </foreach>
            </trim>
        </if>
        order by xp.create_time desc
    </select>
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpAgreementController.java
@@ -50,7 +50,7 @@
    @ApiOperation(value = "获取协议",tags = {"管理后台-内容中心"})
    @GetMapping("/api/v1/agreement/content/{type}")
    public R<XpAgreement> getAgreementContent(@ApiParam(name = "type", value = "类型 1=用户服务协议 2=平台隐私政策 3=敏感个人信息处理情况说明 4=向第三方提供个人信息情况的说明 5=乘车须知 6=计费规则说明 ") @PathVariable Integer type) {
    public R<XpAgreement> getAgreementContent(@ApiParam(name = "type", value = "类型 1=用户服务协议 2=平台隐私政策 3=敏感个人信息处理情况说明 4=向第三方提供个人信息情况的说明 5=乘车须知 6=计费规则说明 7= 法律法规") @PathVariable Integer type) {
        return R.ok(xpAgreementService.getAgreementContent(type));
    }
    @ApiOperation(value = "保存协议",tags = {"管理后台-内容中心"})
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/base/QuartzManager.java
@@ -7,122 +7,122 @@
import java.util.Map;
public class QuartzManager {
    private static SchedulerFactory factory = new StdSchedulerFactory();
    private static final String TRIGGER_NAME_PREFIX = "TRIGGER_PREFIX_";
    private static final String JOB_NAME_PREFIX = "JOB_PREFIX_";
    /**
     * 添加定时任务:具体某个时间点执行一次的任务,如:在某个2015-06-01 12:00发送一条消息
     *
     * @param jobName
     *            具体的任务名+ID标识唯一
     * @param jobType
     * @param date
     * @param jp
     */
    public synchronized static void addJob(Class<? extends Job> jobClass, String jobName, TimeJobType jobType, Date date,
                                           Map<String,  ? extends Object> jp) {
        //logger.debug("ADD JOB {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        try {
            Scheduler sched = factory.getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass).withIdentity(JOB_NAME_PREFIX + jobName, jobType.getType())
                    .setJobData(new JobDataMap(jp)).build();
    private static SchedulerFactory factory = new StdSchedulerFactory();
    private static final String TRIGGER_NAME_PREFIX = "TRIGGER_PREFIX_";
    private static final String JOB_NAME_PREFIX = "JOB_PREFIX_";
            SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                    .withIdentity(TRIGGER_NAME_PREFIX + jobName, jobType.getType()).startAt(date).build();
            removeJob(jobName, jobType);
            sched.scheduleJob(job, trigger);
    /**
     * 添加定时任务:具体某个时间点执行一次的任务,如:在某个2015-06-01 12:00发送一条消息
     *
     * @param jobName 具体的任务名+ID标识唯一
     * @param jobType
     * @param date
     * @param jp
     */
    public synchronized static void addJob(Class<? extends Job> jobClass, String jobName, TimeJobType jobType, Date date,
                                           Map<String, ? extends Object> jp) {
        //logger.debug("ADD JOB {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        try {
            Scheduler sched = factory.getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass).withIdentity(JOB_NAME_PREFIX + jobName, jobType.getType())
                    .setJobData(new JobDataMap(jp)).build();
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            //logger.error("ADD JOB exception {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        }
    }
       /**
        * 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
        * @param jobName
        * @param time
        */
        public synchronized static void modifyJobTime(String jobName,TimeJobType jobType, Date time) {
             //logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
            try {
                JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
                TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
                Scheduler sched = factory.getScheduler();
                SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(key);
                if(trigger == null) {
                    return;
                }
                Date oldTime = trigger.getStartTime();
                if (oldTime.getTime() != time.getTime()) {
                    JobDetail jobDetail = sched.getJobDetail(jobKey);
                    Class<? extends Job> objJobClass = jobDetail.getJobClass();
                    removeJob(jobName,jobType);
                    Map<String, Object> jp = jobDetail.getJobDataMap();
                    addJob(objJobClass, jobName, jobType, time, jp);
                }
            } catch (Exception e) {
               // logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
            }
        }
            SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                    .withIdentity(TRIGGER_NAME_PREFIX + jobName, jobType.getType()).startAt(date).build();
            removeJob(jobName, jobType);
    /**
     * 移除一个任务
     *
     * @param jobName
     */
    public synchronized static void removeJob(String jobName, TimeJobType jobType) {
        try {
            JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
            TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
            Scheduler sched = factory.getScheduler();
            sched.scheduleJob(job, trigger);
            JobDetail detail = sched.getJobDetail(jobKey);
            if (detail != null) {
                sched.pauseJob(jobKey);
                sched.pauseTrigger(key);// 停止触发器
                sched.unscheduleJob(key);// 移除触发器
                sched.deleteJob(jobKey);// 删除任务
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            //logger.error("ADD JOB exception {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        }
    }
    /**
     * 启动所有定时任务
     */
    public synchronized static void startJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            sched.start();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
     *
     * @param jobName
     * @param time
     */
    public synchronized static void modifyJobTime(String jobName, TimeJobType jobType, Date time) {
        //logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
        try {
            JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
            TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
    /**
     * 关闭所有定时任务
     */
    public synchronized static void shutdownJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            if (!sched.isShutdown()) {
                sched.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
            Scheduler sched = factory.getScheduler();
            SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(key);
            if (trigger == null) {
                return;
            }
            Date oldTime = trigger.getStartTime();
            if (oldTime.getTime() != time.getTime()) {
                JobDetail jobDetail = sched.getJobDetail(jobKey);
                Class<? extends Job> objJobClass = jobDetail.getJobClass();
                removeJob(jobName, jobType);
                Map<String, Object> jp = jobDetail.getJobDataMap();
                addJob(objJobClass, jobName, jobType, time, jp);
            }
        } catch (Exception e) {
            // logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
        }
    }
    /**
     * 移除一个任务
     *
     * @param jobName
     */
    public synchronized static void removeJob(String jobName, TimeJobType jobType) {
        try {
            JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
            TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
            Scheduler sched = factory.getScheduler();
            JobDetail detail = sched.getJobDetail(jobKey);
            if (detail != null) {
                sched.pauseJob(jobKey);
                sched.pauseTrigger(key);// 停止触发器
                sched.unscheduleJob(key);// 移除触发器
                sched.deleteJob(jobKey);// 删除任务
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 启动所有定时任务
     */
    public synchronized static void startJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            sched.start();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 关闭所有定时任务
     */
    public synchronized static void shutdownJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            if (!sched.isShutdown()) {
                sched.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpSystemSettingServiceImpl.java
@@ -1,12 +1,15 @@
package com.xiaopeng.operation.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.operation.mapper.XpSystemSettingMapper;
import com.xiaopeng.api.model.operation.XpSystemSetting;
import com.xiaopeng.operation.service.XpSystemSettingService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Objects;
/**
 * <p>
@@ -49,6 +52,10 @@
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSystemSetting(XpSystemSetting xpSystemSetting) {
        saveOrUpdate(xpSystemSetting);
        if (Objects.nonNull(xpSystemSetting.getId())) {
            update(xpSystemSetting, new LambdaQueryWrapper<XpSystemSetting>().eq(XpSystemSetting::getId, xpSystemSetting.getId()));
        } else {
            save(xpSystemSetting);
        }
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -6,10 +6,14 @@
import com.xiaopeng.api.dto.map.RouteAndFareDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto;
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpTradingStrategy;
@@ -19,6 +23,7 @@
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.operation.VehiclePositionVo;
import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.redis.service.RedisService;
@@ -31,6 +36,7 @@
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
@@ -77,6 +83,9 @@
    //
    @Resource
    private OrderMissionClient orderMissionClient;
    @Resource
    private XpPushMessageClient xpPushMessageClient;
    @Resource
    private XpElectronicFenceMapper xpElectronicFenceMapper;
@@ -177,9 +186,15 @@
        // 取消订单
        R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.valueOf(orderId));
        if (xpOrderR.getCode() == 200) {
            if (xpOrderR.getData().getStatus() == 1) {
            XpOrder xpOrder = xpOrderR.getData();
            if (xpOrder.getStatus() == 1) {
                log.info("五轮推单结束,无车辆接单,执行取消订单 {}", orderNo);
                xpOrderClient.cancelOrder(orderId);
                //推送订单状态给乘客
                SendMessageDTO dto = new SendMessageDTO();
                dto.setAppUserId(xpOrder.getAppUserId().toString());
                dto.setMessage("{\"type\":\"ORDER_STATUS\",\"content\":\"{\\\"orderId\\\":\\\"" + orderId + "\\\",\\\"status\\\":0}\",\"timestamp\":\"" + System.currentTimeMillis() + "\"}");
                xpPushMessageClient.sendStatus(dto);
                //将订单从队列中移除
                log.info("五轮推单结束,无车辆接单,执行队列移除订单 {}", orderNo);
                redisService.popFirstElement(quoteName);
@@ -200,7 +215,7 @@
     */
    @SneakyThrows
    private void processPushOrder(String quoteName, int count, int sleepTime, String uid, String[] split, String orderNo, XpTradingStrategy xpTradingStrategy, String distance, String duration, String planRule) {
        System.out.println("进入推单环节");
        log.info("进入推单环节 单号 {}", orderNo);
        if (count == 0) {
            count = 1;
        }
@@ -221,14 +236,14 @@
        for (int i = 0; i < count; i++) {
            //等到sleepTime秒钟
            Thread.sleep(sleepTime);
            System.out.println("进入找车环节");
            Thread.sleep(sleepTime * 1000);
            log.info("进入找车环节 单号 {}", orderNo);
            // 根据距离找车
            // 车多则根据配置找具体车数量 根据距离最近
            // 更改 暂不限制数量
            List<VehiclePosition> positionList = vehiclePositionService.findAvailableVehiclesNearby(Double.parseDouble(split[0]), Double.parseDouble(split[1]), xpTradingStrategy.getOnePushDistance(), xpTradingStrategy.getSimultaneouslyOrderCount());
            log.info("根据距离找车 距离 {}KM  经度 {} 维度 {} 查找结果 {}", xpTradingStrategy.getOnePushDistance(), split[0], split[1], positionList);
            log.info("根据距离找车 {} 距离 {}KM  经度 {} 维度 {} 查找结果 {} 单号 {}", orderNo, xpTradingStrategy.getOnePushDistance(), split[0], split[1], positionList, orderNo);
            // 获取车辆的区域信息
            if (positionList.isEmpty()) {
                continue;
@@ -237,7 +252,7 @@
            // 获取车辆的信息 筛选出可用车辆
            R<List<String>> vehiclePositionVos = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(xpElectronicFence.getId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount()));
            log.info("筛选可用车辆结果 {}", JSON.toJSONString(vehiclePositionVos));
            log.info("筛选可用车辆结果 {} 单号 {}", JSON.toJSONString(vehiclePositionVos), orderNo);
            if (vehiclePositionVos.getCode() != 200) {
                continue;
            }
@@ -251,7 +266,7 @@
            if (!availableVehiclesNearby.isEmpty()) {
                if (availableVehiclesNearby.size() > 1) {
                    log.info("附近有 {} 辆车,进入权重判断流程", availableVehiclesNearby.size());
                    log.info("附近有 {} 辆车,进入权重判断流程 单号 {}", availableVehiclesNearby.size(), orderNo);
                    // 走权重
                    // 订单价值
@@ -734,7 +749,7 @@
                    RLock lock = redissonClient.getLock("FIND_CAR_" + vehiclePositionVo.getVin());
                    lock.lock(10, TimeUnit.SECONDS);
                    System.err.println("队列:" + quoteName + "  车辆:" + vehiclePositionVo.getVin() + "订单" + orderNo);
                    log.info("队列 {} 车辆 {} 单号 {}", quoteName, vehiclePositionVo.getVin(), orderNo);
                    try {
//                        VehiclePosition vehiclePosition = vehiclePositionService.findByVehicleId(vehiclePositionVo.getVehicle_id());
                        R<XpVehicle> vehiclePositionR = xpVehicleClient.findByVehicleVin(vehiclePositionVo.getVin());
@@ -742,15 +757,15 @@
                            continue;
                        }
                        XpVehicle vehiclePosition = vehiclePositionR.getData();
                        log.info("符合条件的车辆 {} ,直接推单XPU", vehiclePosition.getPlateNumber());
                        log.info("当前车辆状态 {}", vehiclePosition.getStatus());
                        log.info("符合条件的车辆 {} ,直接推单XPU。单号 {}", vehiclePosition.getPlateNumber(), orderNo);
                        log.info("当前车辆状态 {} 单号 {}", vehiclePosition.getStatus(), orderNo);
                        if (vehiclePosition.getStatus() != 1 || vehiclePosition.getState() != 0 || vehiclePosition.getVehicleType()==1) {
                            continue;
                        }
                        //  关闭巡游单子
                        R<String> stringR = xpCruiseOrderClient.updateCruiseOrder(vehiclePosition.getVehicleVin());
                        if(stringR ==null || stringR.getData()==null){
                            log.info("关闭巡游单子失败");
                            log.info("关闭巡游单子失败 车牌号 {}", vehiclePosition.getPlateNumber());
                            continue;
                        }
@@ -766,10 +781,10 @@
                        pushOrderDto.setStage(1);
                        // 调用推送服务  orderId + carVin
//                        orderMissionClient.pushOrder(pushOrderDto);
                        log.info("开始推送 {} 订单到XPU", xpOrder.getOrderNumber());
                        log.info("开始推送 {} 订单到XPU。单号 {}", xpOrder.getOrderNumber(), orderNo);
                        redisService.popFirstElement(quoteName);
                        log.info("将订单 {} 从队列 {} 弹出去", xpOrder.getOrderNumber(), quoteName);
                        log.info("将订单 {} 从队列 {} 弹出去", orderNo, quoteName);
                        return;
                    } catch (Exception e) {
                        e.printStackTrace();
@@ -791,15 +806,15 @@
                            continue;
                        }
                        XpVehicle vehicleId1 = vehicleR.getData();
                        log.info("附近只有一个车辆 {} ,直接推单XPU", vehicleId1.getPlateNumber());
                        log.info("当前车辆状态 {} 运营状态 {}", vehicleId1.getOperatingStatus(), vehicleId1.getState());
                        log.info("附近只有一个车辆 {} ,直接推单XPU。单号 {}", vehicleId1.getPlateNumber(), orderNo);
                        log.info("当前车辆状态 {} 运营状态 {} 单号 {}", vehicleId1.getOperatingStatus(), vehicleId1.getState(), orderNo);
                        if (vehicleId1.getOperatingStatus() != 1 || vehicleId1.getState() != 0 || vehicleId1.getVehicleType()==1) {
                            continue;
                        }
                        //  关闭巡游单子
                        R<String> stringR = xpCruiseOrderClient.updateCruiseOrder(vehicleId1.getVehicleVin());
                        if(stringR ==null || stringR.getData()==null){
                            log.info("关闭巡游单子失败");
                            log.info("关闭巡游单子失败 车牌号 {}", vehicleId1.getPlateNumber());
                            continue;
                        }
@@ -814,9 +829,9 @@
                        pushOrderDto.setStage(1);
                        // 调用推送服务  orderId + carVin
//                        orderMissionClient.pushOrder(pushOrderDto);
                        log.info("开始推送 {} 订单到XPU", xpOrder.getOrderNumber());
                        log.info("开始推送 {} 订单到XPU。单号 {}", xpOrder.getOrderNumber(), orderNo);
                        redisService.popFirstElement(quoteName);
                        log.info("将订单 {} 从队列 {} 弹出去", xpOrder.getOrderNumber(), quoteName);
                        log.info("将订单 {} 从队列 {} 弹出去", orderNo, quoteName);
                        return;
                    } catch (Exception e) {
                        e.printStackTrace();
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/task/BannerTaskUtil.java
@@ -2,6 +2,7 @@
import com.xiaopeng.api.model.operation.XpBanner;
import com.xiaopeng.operation.service.XpBannerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -13,6 +14,7 @@
 * @author 无关风月
 * @date 2026/2/26 9:49
 */
@Slf4j
@Component
public class BannerTaskUtil {
@@ -26,6 +28,7 @@
    @Scheduled(fixedRate = 60000)
    public void taskMinute() {
        try {
            log.info("处理的banner状态定时任务开始执行,当前时间:{}", LocalDateTime.now());
            // 根据banner开始、结束时间修改banner状态
            List<XpBanner> banners = bannerService.list();
            for (XpBanner banner : banners) {
xp-robotaxi-operation-boot/src/main/resources/i18n/messages.properties
@@ -17,7 +17,7 @@
pricing.not.exist=定价不存在
pricing.json.invalid=价格配置JSON格式不正确
pricing.rule.empty=价格规则不能为空
no.current.point=?????????
no.current.point=该站点已停止运营
path.not.found=路径不存在
has.unpaid.order=有正在进行的订单
cruise.plan.name.empty=计划名称不能为空
xp-robotaxi-operation-boot/src/main/resources/i18n/messages_en_US.properties
@@ -17,7 +17,7 @@
pricing.not.exist=Pricing does not exist
pricing.json.invalid=Invalid JSON format for pricing configuration
pricing.rule.empty=Price rule cannot be empty
no.current.point=The current location is not open for service
no.current.point=This site has ceased operations
path.not.found=Path does not exist
has.unpaid.order=There are ongoing orders
cruise.plan.name.exists=The name of the plan already exists
xp-robotaxi-operation-boot/src/main/resources/i18n/messages_zh_CN.properties
@@ -17,7 +17,7 @@
pricing.not.exist=定价不存在
pricing.json.invalid=价格配置JSON格式不正确
pricing.rule.empty=价格规则不能为空
no.current.point=?????????
no.current.point=该站点已停止运营
path.not.found=路径不存在
has.unpaid.order=有正在进行的订单
cruise.plan.name.exists=计划名称已存在
xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpPointMapper.xml
@@ -132,31 +132,22 @@
        <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
            and xp.create_time between #{query.startTime} and #{query.endTime}
        </if>
        <if test="query.operationStatus != null">
        <if test="query.operationStatus ==1">
            and xp.verification_status = 1
        </if>
          <if test="query.operationStatus ==2">
            and xp.verification_status = 2
        </if>
          <if test="query.operationStatus ==3">
            and xp.verification_status = 4
        </if>
          <if test="query.operationStatus ==4">
            and xp.verification_status = 3 and xp.operation_status =1
        </if>
            <if test="query.operationStatus ==5">
                and xp.verification_status = 3 and xp.operation_status =1
            </if>
            <if test="query.operationStatus ==6">
                and xp.operation_status =2
            </if>
          <if test="query.operationStatus ==7">
                and xp.operation_status =3
            </if>
          <if test="query.operationStatus ==8">
                and xp.operation_status =4
            </if>
        <if test="query.operationStatusList != null and query.operationStatusList.size() > 0">
            <trim prefix="and (" suffix=")" prefixOverrides="OR">
                <foreach collection="query.operationStatusList" item="st">
                    <choose>
                        <when test="st == 1">OR xp.verification_status = 1</when>
                        <when test="st == 2">OR xp.verification_status = 2</when>
                        <when test="st == 3">OR xp.verification_status = 4</when>
                        <when test="st == 4">OR (xp.verification_status = 3 and xp.operation_status = 1)</when>
                        <when test="st == 5">OR (xp.verification_status = 5 and xp.operation_status = 1)</when>
                        <when test="st == 6">OR xp.operation_status = 2</when>
                        <when test="st == 7">OR xp.operation_status = 3</when>
                        <when test="st == 8">OR xp.operation_status = 4</when>
                        <otherwise>OR 1 = 0</otherwise>
                    </choose>
                </foreach>
            </trim>
        </if>
        order by xp.create_time desc
    </select>
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -9,7 +9,7 @@
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto;
import com.mongodb.client.MongoCollection;import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto;
import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.feignClient.maintenance.XpChargingRecordClient;
@@ -45,7 +45,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.bson.Document;import org.springframework.beans.BeanUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
@@ -745,4 +745,16 @@
        return R.ok();
    }
    /**
     * 删除mongodb中的文档
     * @param collectionName
     * @return
     */
    @PostMapping("/base/vi/removeMongodb")
    public R<?> removeMongodb(String collectionName){
        MongoCollection<Document> collection = mongoTemplate.getCollection(collectionName);
        collection.drop();
        return R.ok();
    }
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java
@@ -185,6 +185,7 @@
            if (excludeFleetId != null) {
                wrapper.ne(XpFleetOperations::getFleetId, excludeFleetId);
            }
            wrapper.last("limit 1");
            XpFleetOperations operations = xpFleetOperationsService.getOne(wrapper);
            if (operations != null) {
                // 查询人员姓名和车队名称
@@ -218,6 +219,7 @@
            if (excludeFleetId != null) {
                wrapper.ne(XpFleetVehicle::getFleetId, excludeFleetId);
            }
            wrapper.last("limit 1");
            XpFleetVehicle fleetVehicle = xpFleetVehicleService.getOne(wrapper);
            if (fleetVehicle != null) {
                // 车辆已绑定其他车队,自动解绑
@@ -238,15 +240,53 @@
        FleetDetailVO vo = new FleetDetailVO();
        BeanUtils.copyProperties(fleet, vo);
        // 3. 统计人员数量
        long userCount = xpFleetOperationsService.count(new LambdaQueryWrapper<XpFleetOperations>()
                .eq(XpFleetOperations::getFleetId, id));
        vo.setUserCount((int) userCount);
        // 3. 统计人员数量(过滤已删除人员)
        List<Long> bindUserIds = xpFleetOperationsService.lambdaQuery()
                .eq(XpFleetOperations::getFleetId, id)
                .list()
                .stream()
                .map(XpFleetOperations::getOperationsUserId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        int userCount = 0;
        if (!CollectionUtils.isEmpty(bindUserIds)) {
            try {
                R<List<XpOperationsUser>> usersResult = xpOperationUserClient.listByIds(bindUserIds);
                if (usersResult != null && usersResult.getData() != null) {
                    userCount = usersResult.getData().size();
                } else {
                    userCount = bindUserIds.size();
                }
            } catch (Exception e) {
                userCount = bindUserIds.size();
            }
        }
        vo.setUserCount(userCount);
        // 4. 统计车辆数量
        long vehicleCount = xpFleetVehicleService.count(new LambdaQueryWrapper<XpFleetVehicle>()
                .eq(XpFleetVehicle::getFleetId, id));
        vo.setVehicleCount((int) vehicleCount);
        // 4. 统计车辆数量(过滤已删除车辆)
        List<Long> bindVehicleIds = xpFleetVehicleService.lambdaQuery()
                .eq(XpFleetVehicle::getFleetId, id)
                .list()
                .stream()
                .map(XpFleetVehicle::getVehicleId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        int vehicleCount = 0;
        if (!CollectionUtils.isEmpty(bindVehicleIds)) {
            try {
                R<List<XpVehicle>> vehiclesResult = xpVehicleClient.listByIds(bindVehicleIds);
                if (vehiclesResult != null && vehiclesResult.getData() != null) {
                    vehicleCount = vehiclesResult.getData().size();
                } else {
                    vehicleCount = bindVehicleIds.size();
                }
            } catch (Exception e) {
                vehicleCount = bindVehicleIds.size();
            }
        }
        vo.setVehicleCount(vehicleCount);
        // 5. 查询负责人信息
        if (fleet.getOperationsUserId() != null) {
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleAnnualRecordServiceImpl.java
@@ -39,6 +39,7 @@
            wrapper.le(XpVehicleAnnualRecord::getCreateTime, LocalDateTime.of(query.getEndTime(), LocalTime.MAX));
        }
        wrapper.like(StringUtils.isNotBlank(query.getOperationsUserName()), XpVehicleAnnualRecord::getCreateBy, query.getOperationsUserName());
        wrapper.eq(XpVehicleAnnualRecord::getVehicleId, query.getVehicleId());
        wrapper.orderByDesc(XpVehicleAnnualRecord::getCreateTime);
        return this.page(page, wrapper);
    }