“mitao”
2026-03-06 ddcce4e9bc4f1a71284008135f0065349c3b960a
bugfix
17个文件已修改
410 ■■■■■ 已修改文件
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-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/service/impl/XpSystemSettingServiceImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/task/BannerTaskUtil.java 3 ●●●●● 补丁 | 查看 | 原始文档 | 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/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-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/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/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/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/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);
    }