puzhibing
2026-04-03 666f1353ed6850623af09d955982f6bc5c9cf65c
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -5,45 +5,54 @@
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
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;
import com.xiaopeng.api.feignClient.maintenance.XpTaskClient;
import com.xiaopeng.api.feignClient.maintenance.XpTaskRuleClient;
import com.xiaopeng.api.feignClient.maintenance.XpVehiclePreparationClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.maintenance.*;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.maintenance.XpTask;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.model.maintenance.XpVehicleRepair;
import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo;
import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandCallbackVo;
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.page.PageInfo;
import com.xiaopeng.common.security.service.TokenService;
import com.xiaopeng.evi.oss.service.AliOssService;
import com.xiaopeng.vehicleConvoy.constant.I18nKeyConstant;
import com.xiaopeng.vehicleConvoy.model.dto.*;
import com.xiaopeng.vehicleConvoy.model.exportExcel.XpVehicleExportExcel;
import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel;
import com.xiaopeng.vehicleConvoy.model.query.*;
import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO;
import com.xiaopeng.vehicleConvoy.service.IXpFleetService;
import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService;
import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService;
import com.xiaopeng.vehicleConvoy.service.IXpVehicleService;
import com.xiaopeng.vehicleConvoy.util.AliOssDownloadUtil;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
@@ -51,19 +60,21 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
/**
 * <p>
@@ -79,14 +90,23 @@
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class XpVehicleController {
    private static final Pattern VEHICLE_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9_]{1,5}$");
    private static final Pattern VEHICLE_VIN_PATTERN = Pattern.compile("^[A-Z0-9]{17}$");
    private final IXpVehicleService xpVehicleService;
    private final IXpFleetVehicleService vehicleService;
    private final IXpFleetService xpFleetService;
    private final IXpVehicleAnnualRecordService xpVehicleAnnualRecordService;
    private final XpVehiclePreparationClient xpVehiclePreparationClient;
    private final XpChargingRecordClient xpChargingRecordClient;
    private final XpTaskClient xpTaskClient;
    private final XpTaskRuleClient xpTaskRuleClient;
    private final MongoTemplate mongoTemplate;
    private final MessageSource messageSource;
    private final TokenService tokenService;
    private final XpVehicleRepairClient xpVehicleRepairClient;
    private final AliOssService aliOssService;
    private final AliOssDownloadUtil aliOssDownloadUtil;
    /**
     * 根据ID列表批量查询车辆信息(内部接口)
     *
@@ -118,12 +138,24 @@
     * @return 车辆列表
     */
    @GetMapping("/inner/vehicle/queryById")
    public R<XpVehicle> queryById(@RequestParam Long id) {
    public R<XpVehicle> queryById(@RequestParam Long id) throws UnsupportedEncodingException {
        XpVehicle xpVehicle = xpVehicleService.getById(id);
        // 获取车队
        XpFleetVehicle xpFleetVehicle = vehicleService.getOne(new LambdaQueryWrapper<XpFleetVehicle>().eq(XpFleetVehicle::getVehicleId, xpVehicle.getId()));
        if (Objects.nonNull(xpFleetVehicle)) {
            xpVehicle.setFleetId(xpFleetVehicle.getFleetId());
        if (Objects.nonNull(xpVehicle)) {
            String vehiclePictures = xpVehicle.getVehiclePictures();
            if(vehiclePictures!=null){
                JSONObject jsonObject = JSON.parseObject(vehiclePictures);
                // 1
                String downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                jsonObject.put("url", downloadUrl);
                xpVehicle.setVehiclePictures(jsonObject.toJSONString());
            }
            // 获取车队
            XpFleetVehicle xpFleetVehicle = vehicleService.getOne(new LambdaQueryWrapper<XpFleetVehicle>().eq(XpFleetVehicle::getVehicleId, xpVehicle.getId()));
            if (Objects.nonNull(xpFleetVehicle)) {
                xpVehicle.setFleetId(xpFleetVehicle.getFleetId());
            }
        }
        return R.ok(xpVehicle);
    }
@@ -224,7 +256,7 @@
    @PostMapping("/api/v1/vehicle/importTemplate")
    public void importTemplate() {
        // 1. 查询导出数据
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), XpVehicleExportExcel.class, new ArrayList<>());
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), XpVehicleImportExcel.class, new ArrayList<>());
        // 4. 输出到响应流
        HttpServletResponse response = WebUtils.response();
@@ -232,7 +264,7 @@
        response.setCharacterEncoding("utf-8");
        ServletOutputStream outputStream = null;
        try {
            String fileName = URLEncoder.encode("在库车辆导入模板.xls", "utf-8");
            String fileName = URLEncoder.encode("在库车辆导入模板.xlsx", "utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName);
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
@@ -256,7 +288,7 @@
     */
    @ApiOperation(value = "导入", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/importExcel")
    public R<?> importExcel(@RequestPart("file") MultipartFile file) {
    public R<?> importExcel(@RequestParam("file") MultipartFile file) {
        ImportParams params = new ImportParams();
        params.setHeadRows(1);
        InputStream inputStream = null;
@@ -266,6 +298,9 @@
            importList = ExcelImportUtil.importExcel(inputStream, XpVehicleImportExcel.class, params);
        } catch (Exception e) {
            log.error("车辆导入失败:{}", e.getMessage(), e);
            if (e instanceof NotOfficeXmlFileException || e.getCause() instanceof NotOfficeXmlFileException) {
                throw new ServiceException("上传文件不是有效的Excel(.xlsx)文件!", I18nKeyConstant.VEHICLE_IMPORT_FAILED);
            }
            throw new ServiceException("车辆导入失败!", I18nKeyConstant.VEHICLE_IMPORT_FAILED);
        } finally {
            if (inputStream != null) {
@@ -279,10 +314,244 @@
        if (CollectionUtils.isEmpty(importList)) {
            throw new ServiceException("导入数据为空!", I18nKeyConstant.VEHICLE_IMPORT_DATA_EMPTY);
        }
        validateImportRequiredFields(importList, params.getHeadRows());
        validateImportBusinessFields(importList, params.getHeadRows());
        uploadVehiclePicture(importList);
        xpVehicleService.importVehicles(importList);
        return R.ok();
    }
    private void validateImportRequiredFields(List<XpVehicleImportExcel> importList, int headRows) {
        for (int index = 0; index < importList.size(); index++) {
            XpVehicleImportExcel row = importList.get(index);
            List<String> missingFields = new ArrayList<>();
            addIfBlank(missingFields, row.getVehicleCode(), "vehicle.import.field.vehicleCode");
            addIfBlank(missingFields, row.getVehicleVin(), "vehicle.import.field.vehicleVin");
            addIfBlank(missingFields, row.getPlateNumber(), "vehicle.import.field.plateNumber");
            addIfBlank(missingFields, row.getVehicleModel(), "vehicle.import.field.vehicleModel");
            addIfBlank(missingFields, row.getVehicleColor(), "vehicle.import.field.vehicleColor");
            addIfBlank(missingFields, row.getVehiclePictures(), "vehicle.import.field.vehiclePictures.tip");
            addIfBlank(missingFields, row.getProcurementSource(), "vehicle.import.field.procurementSource");
            if (!missingFields.isEmpty()) {
                int excelRowNumber = index + headRows + 1;
                String missing = String.join(", ", missingFields);
                throw new ServiceException("导入数据必填字段为空!", I18nKeyConstant.VEHICLE_IMPORT_FIELDS_REQUIRED,
                        new Object[]{excelRowNumber, missing});
            }
        }
    }
    private void addIfBlank(List<String> missingFields, String value, String fieldNameKey) {
        if (StringUtils.isBlank(value)) {
            String fieldName = messageSource.getMessage(fieldNameKey, null, fieldNameKey, LocaleContextHolder.getLocale());
            missingFields.add(fieldName);
        }
    }
    private void validateImportBusinessFields(List<XpVehicleImportExcel> importList, int headRows) {
        List<String> errors = new ArrayList<>();
        Locale locale = LocaleContextHolder.getLocale();
        for (int index = 0; index < importList.size(); index++) {
            XpVehicleImportExcel row = importList.get(index);
            int excelRowNumber = index + headRows + 1;
            String vehicleCode = trimToNull(row.getVehicleCode());
            String vehicleVin = normalizeVin(row.getVehicleVin());
            String plateNumber = trimToNull(row.getPlateNumber());
            String vehicleColor = trimToNull(row.getVehicleColor());
            row.setVehicleCode(vehicleCode);
            row.setVehicleVin(vehicleVin);
            row.setPlateNumber(plateNumber);
            row.setVehicleColor(vehicleColor);
            if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleCode) && !VEHICLE_CODE_PATTERN.matcher(vehicleCode).matches()) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_INVALID,
                        new Object[]{excelRowNumber, vehicleCode},
                        I18nKeyConstant.VEHICLE_IMPORT_CODE_INVALID,
                        locale));
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleVin) && !VEHICLE_VIN_PATTERN.matcher(vehicleVin).matches()) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_INVALID,
                        new Object[]{excelRowNumber, vehicleVin},
                        I18nKeyConstant.VEHICLE_IMPORT_VIN_INVALID,
                        locale));
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(plateNumber) && !Validator.isPlateNumber(plateNumber)) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_INVALID,
                        new Object[]{excelRowNumber, plateNumber},
                        I18nKeyConstant.VEHICLE_IMPORT_PLATE_INVALID,
                        locale));
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleColor) && vehicleColor.length() > 2) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_COLOR_INVALID,
                        new Object[]{excelRowNumber, vehicleColor},
                        I18nKeyConstant.VEHICLE_IMPORT_COLOR_INVALID,
                        locale));
            }
        }
        Set<String> duplicatedCodes = findDuplicated(importList.stream()
                .map(XpVehicleImportExcel::getVehicleCode)
                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                .collect(java.util.stream.Collectors.toList()));
        Set<String> duplicatedVins = findDuplicated(importList.stream()
                .map(XpVehicleImportExcel::getVehicleVin)
                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                .collect(java.util.stream.Collectors.toList()));
        Set<String> duplicatedPlates = findDuplicated(importList.stream()
                .map(XpVehicleImportExcel::getPlateNumber)
                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                .collect(java.util.stream.Collectors.toList()));
        for (int index = 0; index < importList.size(); index++) {
            XpVehicleImportExcel row = importList.get(index);
            int excelRowNumber = index + headRows + 1;
            if (duplicatedCodes.contains(row.getVehicleCode())) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_DUPLICATE,
                        new Object[]{excelRowNumber, row.getVehicleCode()},
                        I18nKeyConstant.VEHICLE_IMPORT_CODE_DUPLICATE,
                        locale));
            }
            if (duplicatedVins.contains(row.getVehicleVin())) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_DUPLICATE,
                        new Object[]{excelRowNumber, row.getVehicleVin()},
                        I18nKeyConstant.VEHICLE_IMPORT_VIN_DUPLICATE,
                        locale));
            }
            if (duplicatedPlates.contains(row.getPlateNumber())) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_DUPLICATE,
                        new Object[]{excelRowNumber, row.getPlateNumber()},
                        I18nKeyConstant.VEHICLE_IMPORT_PLATE_DUPLICATE,
                        locale));
            }
        }
        Set<String> codeSet = importList.stream()
                .map(XpVehicleImportExcel::getVehicleCode)
                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                .collect(java.util.stream.Collectors.toSet());
        Set<String> vinSet = importList.stream()
                .map(XpVehicleImportExcel::getVehicleVin)
                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                .collect(java.util.stream.Collectors.toSet());
        Set<String> plateSet = importList.stream()
                .map(XpVehicleImportExcel::getPlateNumber)
                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                .collect(java.util.stream.Collectors.toSet());
        Set<String> existsCodes = Collections.emptySet();
        if (!codeSet.isEmpty()) {
            existsCodes = xpVehicleService.lambdaQuery()
                    .select(XpVehicle::getVehicleCode)
                    .in(XpVehicle::getVehicleCode, codeSet)
                    .list()
                    .stream()
                    .map(XpVehicle::getVehicleCode)
                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                    .collect(java.util.stream.Collectors.toSet());
        }
        Set<String> existsVins = Collections.emptySet();
        if (!vinSet.isEmpty()) {
            existsVins = xpVehicleService.lambdaQuery()
                    .select(XpVehicle::getVehicleVin)
                    .in(XpVehicle::getVehicleVin, vinSet)
                    .list()
                    .stream()
                    .map(XpVehicle::getVehicleVin)
                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                    .collect(java.util.stream.Collectors.toSet());
        }
        Set<String> existsPlates = Collections.emptySet();
        if (!plateSet.isEmpty()) {
            existsPlates = xpVehicleService.lambdaQuery()
                    .select(XpVehicle::getPlateNumber)
                    .in(XpVehicle::getPlateNumber, plateSet)
                    .list()
                    .stream()
                    .map(XpVehicle::getPlateNumber)
                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                    .collect(java.util.stream.Collectors.toSet());
        }
        for (int index = 0; index < importList.size(); index++) {
            XpVehicleImportExcel row = importList.get(index);
            int excelRowNumber = index + headRows + 1;
            if (existsCodes.contains(row.getVehicleCode())) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_EXISTS,
                        new Object[]{excelRowNumber, row.getVehicleCode()},
                        I18nKeyConstant.VEHICLE_IMPORT_CODE_EXISTS,
                        locale));
            }
            if (existsVins.contains(row.getVehicleVin())) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_EXISTS,
                        new Object[]{excelRowNumber, row.getVehicleVin()},
                        I18nKeyConstant.VEHICLE_IMPORT_VIN_EXISTS,
                        locale));
            }
            if (existsPlates.contains(row.getPlateNumber())) {
                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_EXISTS,
                        new Object[]{excelRowNumber, row.getPlateNumber()},
                        I18nKeyConstant.VEHICLE_IMPORT_PLATE_EXISTS,
                        locale));
            }
        }
        if (!errors.isEmpty()) {
            throw new ServiceException("导入校验失败!", I18nKeyConstant.VEHICLE_IMPORT_VALIDATE_FAIL,
                    new Object[]{String.join("\n", errors)});
        }
    }
    private static String normalizeVin(String vin) {
        String trimmed = trimToNull(vin);
        return trimmed == null ? null : trimmed.toUpperCase(Locale.ROOT);
    }
    private static String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }
    private static Set<String> findDuplicated(List<String> values) {
        if (values == null || values.isEmpty()) {
            return Collections.emptySet();
        }
        Set<String> seen = new HashSet<>();
        Set<String> duplicated = new HashSet<>();
        for (String value : values) {
            if (!seen.add(value)) {
                duplicated.add(value);
            }
        }
        return duplicated;
    }
    private void uploadVehiclePicture(List<XpVehicleImportExcel> importList) {
        for (XpVehicleImportExcel xpVehicleImportExcel : importList) {
            xpVehicleImportExcel.setVehiclePictures(getOssUrl(xpVehicleImportExcel.getVehiclePictures()));
        }
    }
    private String getOssUrl(String filePath) {
        try {
            // 获取到暂存的文件
            File tmpFile = new File(filePath);
            FileInputStream fileInputStream = new FileInputStream(tmpFile);
            // TODO 上传oss
            JSONObject res = new JSONObject();
            res.put("url", "https://we-park-life.oss-cn-beijing.aliyuncs.com/img/K4vqtLmVc6.png");
            res.put("id", "1");
            res.put("name", "测试.png");
            return res.toJSONString();
        } catch (Exception e) {
            log.error("在库车辆导入图片上传oss异常", e);
        }
        return null;
    }
    /**
     * 导出在库车辆列表
     *
@@ -350,8 +619,16 @@
     */
    @ApiOperation(value = "车辆详情", tags = {"管理后台-车辆管理-在库车辆管理"})
    @GetMapping("/api/v1/vehicle/queryById")
    public R<XpVehicle> getVehicleDetail(@ApiParam(value = "车辆id", required = true) @RequestParam Long id) {
        return R.ok(xpVehicleService.getVehicleDetail(id));
    public R<XpVehicle> getVehicleDetail(@ApiParam(value = "车辆id", required = true) @RequestParam Long id) throws UnsupportedEncodingException {
        XpVehicle vehicleDetail = xpVehicleService.getVehicleDetail(id);
        if(vehicleDetail.getVehiclePictures()!=null){
            JSONObject jsonObject = JSONObject.parseObject(vehicleDetail.getVehiclePictures());
            String downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
            jsonObject.put("url",downloadUrl);
            String jsonString = jsonObject.toJSONString();
            vehicleDetail.setVehiclePictures(jsonString);
        }
        return R.ok(vehicleDetail);
    }
    /**
@@ -362,6 +639,23 @@
    @ApiOperation(value = "删除在库车辆",tags = {"管理后台-车辆管理-在库车辆管理"})
    @DeleteMapping("/api/v1/vehicle/delete/{id}")
    public R<?> delete(@ApiParam(name = "id", value = "车辆ID") @PathVariable Long id) {
        XpFleetVehicle binding = vehicleService.lambdaQuery()
                .eq(XpFleetVehicle::getVehicleId, id)
                .last("limit 1")
                .one();
        if (binding != null && binding.getFleetId() != null) {
            String fleetName = String.valueOf(binding.getFleetId());
            try {
                XpFleet fleet = xpFleetService.getById(binding.getFleetId());
                if (fleet != null && StringUtils.isNotBlank(fleet.getFleetName())) {
                    fleetName = fleet.getFleetName();
                }
            } catch (Exception e) {
                // ignore, fallback to fleetId
            }
            throw new ServiceException("当前车辆已关联车队:" + fleetName, I18nKeyConstant.VEHICLE_DELETE_HAS_BOUND_FLEET,
                    new Object[]{fleetName});
        }
        xpVehicleService.removeById(id);
        return R.ok();
    }
@@ -393,9 +687,15 @@
        List<XpVehicleExportExcel> exportList = BeanUtil.copyToList(dataList, XpVehicleExportExcel.class);
        for (XpVehicleExportExcel xpVehicleExportExcel : exportList) {
            if (StringUtils.isNotBlank(xpVehicleExportExcel.getVehiclePictures())) {
                JSONObject jsonObject = JSONObject.parseObject(xpVehicleExportExcel.getVehiclePictures());
                // xpVehicleExportExcel.setVehiclePictures(jsonObject.getString("url"));
                xpVehicleExportExcel.setVehiclePictures(null);
                String pictureJSONObject = aliOssDownloadUtil.getPictureJSONObject(xpVehicleExportExcel.getVehiclePictures());
                if (StringUtils.isNotBlank(pictureJSONObject)) {
                    JSONObject jsonObject = JSONObject.parseObject(pictureJSONObject);
                    xpVehicleExportExcel.setVehiclePictures(jsonObject.containsKey("url") ? jsonObject.getString("url") : "");
                }
            }
            if (Integer.valueOf(2).equals(xpVehicleExportExcel.getStatus()) && Integer.valueOf(1).equals(xpVehicleExportExcel.getOperatingStatus())) {
                xpVehicleExportExcel.setStatus(4);
            }
        }
        // 3. 生成Excel
@@ -427,8 +727,30 @@
    @ApiOperation(value = "通过车辆id查询年检分页列表", tags = {"管理后台-车辆管理-运营车辆管理"})
    @PostMapping("/api/v1/vehicle/queryTaskRoutineByVehicleId")
    public R<PageInfo<XpVehicleAnnualRecord>> queryTaskRoutineByVehicleId(
            @Valid @RequestBody XpVehicleAnnualRecordPageQuery query){
            @Valid @RequestBody XpVehicleAnnualRecordPageQuery query) throws UnsupportedEncodingException {
        return R.ok(xpVehicleAnnualRecordService.queryTaskRoutineByVehicleId(query));
    }
    public static void main(String[] args) {
        String inspectionAttachments = "[{\"id\": \"d57c4ac4-acb0-451b-8e94-70f226331e0c\", \"url\": \"https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/552a3a31-e4dd-4a28-8748-fd8b87dd3055.png\", \"name\": \"测试.jpg\"}]";
        if (StringUtils.isNotBlank(inspectionAttachments)) {
            JSONArray jsonArray = JSONArray.parseArray(inspectionAttachments);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                if (Objects.isNull(jsonObject)) {
                    continue;
                }
                jsonObject.put("url", "downloadUrl");
            }
            String jsonString = JSONArray.toJSONString(jsonArray);
            System.out.println(jsonString);
        }
    }
    /**
@@ -447,7 +769,8 @@
     */
    @PostMapping("/inner/vehicle/queryVehiclePositionByVin")
    public R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto){
        List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0).eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin,
        List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0)
                .eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin,
                dto.getVinList()));
        if(list.isEmpty()){
            return R.ok(new ArrayList<>());
@@ -519,9 +842,12 @@
     */
    @ApiOperation(value = "查询可改派的车辆列表", tags = {"管理后台-订单管理"})
    @GetMapping("/api/v1/vehicle/availableList")
    @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataTypeClass = Long.class)
    public R<List<XpVehicle>> listAvailableVehicles(@RequestParam Long orderId) {
        List<XpVehicle> list = xpVehicleService.listAvailableVehicles(orderId);
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataTypeClass = Long.class),
            @ApiImplicitParam(name = "orderType", value = "订单类型(1=用户单,2=测试单)", required = true, dataTypeClass = Integer.class)
    })
    public R<List<XpVehicle>> listAvailableVehicles(@RequestParam Long orderId, Integer orderType) {
        List<XpVehicle> list = xpVehicleService.listAvailableVehicles(orderId, orderType);
        return R.ok(list);
    }
@@ -597,6 +923,22 @@
            xpVehicleVO.setMileageRange(0F);
            xpVehicleVO.setCurrentElectricity(0);
        }
        if (StringUtils.isNotBlank(xpVehicleVO.getVehiclePictures())) {
            JSONObject jsonObject = JSONObject.parseObject(xpVehicleVO.getVehiclePictures());
            if(jsonObject!=null){
                String downloadUrl = null;
                try {
                    downloadUrl= aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                jsonObject.put("url", downloadUrl);
                xpVehicleVO.setVehiclePictures(jsonObject.toJSONString());
            }
        }
        // 判断车辆维修状态
        Integer maintenanceStatus = xpVehicleRepairClient.getMaintenanceStatus(xpVehicleVO.getId()).getData();
        xpVehicleVO.setMaintenanceStatus(maintenanceStatus);
        return R.ok(xpVehicleVO);
    }
@@ -607,6 +949,8 @@
    @ApiOperation(value = "车辆管理-地图", tags = {"运维APP-车辆管理"})
    @PostMapping("/api/v1/vehicle/vehicleMap")
    public R<PageInfo<XpVehicleVO>> vehicleMap(@RequestBody VehicleMapQuery query) {
        Long operationsUserId = tokenService.getLoginOperationUser().getId();
        query.setOperationsUserId(operationsUserId);
        return R.ok(xpVehicleService.pageList(query));
    }
    /**
@@ -634,7 +978,7 @@
    /**
     * 业务流程-车门解锁/后备箱解锁
     */
    @ApiOperation(value = "打开车门操作", tags = {"小程序-业务流程"})
    @ApiOperation(value = "打开车门解锁/后备箱开关车门", tags = {"小程序-业务流程"})
    @PostMapping("/api/v1/mini-program/order/vehicle/unlock")
    public R<Integer> unlock(@RequestBody UnlockAppletDTO dto) {
        return R.ok(xpVehicleService.unlock(dto));
@@ -654,11 +998,23 @@
     */
    @ApiOperation(value = "通过订单id查询当前车辆温度", tags = {"小程序-业务流程"})
    @GetMapping("/api/v1/mini-program/order/queryTemperatureByOrderId")
    public R<VehicleTemperatureDto> queryTemperatureByOrderId(@RequestParam Long orderId, HttpServletRequest request) {
    public R<String> queryTemperatureByOrderId(@RequestParam Long orderId, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        VehicleTemperatureDto vehicleTemperatureDto = xpVehicleService.queryTemperatureByOrderId(orderId,uid);
        VehicleStateVo hvacInnerTemp = vehicleTemperatureDto.getStateMap().get("hvacInnerTemp");
        return R.ok(hvacInnerTemp.getValue());
    }
    @ApiOperation(value = "通过订单id查询当前车辆车门状态", tags = {"小程序-业务流程"})
    @GetMapping("/api/v1/mini-program/order/queryVehicleTrunkOpenStatus")
    public R<VehicleTemperatureDto> queryVehicleTrunkOpenStatus(@RequestParam Long orderId, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        VehicleTemperatureDto vehicleTemperatureDto = xpVehicleService.queryTemperatureByOrderId(orderId,uid);
        return R.ok(vehicleTemperatureDto);
    }
    /**
     * 获取车辆不分页列表
@@ -671,4 +1027,42 @@
    public R<PageInfo<XpVehicleVO>> getVehiclePageList(@RequestBody VehicleSelectPageQuery query) {
        return R.ok(xpVehicleService.getVehiclePageList(query));
    }
    /**
     * 临时用于修改车辆接单状态
     * @param updateVehicleStateDto
     * @return
     */
    @PostMapping("/base/vi/vehicle/updateVehicleStatus")
    public R<?> testUpdateVehicleStatus(@RequestBody UpdateVehicleStateDto updateVehicleStateDto){
        xpVehicleService.update(new LambdaUpdateWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, updateVehicleStateDto.getVin()).set(XpVehicle::getState, updateVehicleStateDto.getState()));
        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();
    }
    /**
     * 获取车辆后备箱开关状态
     * @param uid
     * @param id
     * @return
     */
    @PostMapping("/inner/vi/vehicle/getVehicleTrunkOpenStatus")
    public R<Boolean> getVehicleTrunkOpenStatus(@RequestParam("uid") Long uid, @RequestParam("id") Long id){
        Boolean vehicleTrunkOpenStatus = xpVehicleService.getVehicleTrunkOpenStatus(uid, id);
        return R.ok(vehicleTrunkOpenStatus);
    }
}