Browse Source

提交全图监控

chenxiaofei 1 month ago
parent
commit
b7b3e5158d

+ 10 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/controller/KwfTruckTraceController.java

@@ -14,6 +14,7 @@ import com.sckw.transport.model.dto.MapVehicleQueryReq;
 import com.sckw.transport.model.vo.MapVehicleVo;
 import com.sckw.transport.model.dto.VehicleExceptionQueryReq;
 import com.sckw.transport.model.vo.VehicleExceptionVo;
+import com.sckw.transport.model.dto.GenerateTraceReq;
 import com.sckw.transport.service.kwfTruckTraceService;
 import com.sckw.transport.service.VehicleExceptionService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -105,6 +106,14 @@ public class KwfTruckTraceController {
         return BaseResult.success(vehicleExceptionService.queryExceptionList(req));
     }
 
-
+    /**
+     * 生成车辆轨迹
+     */
+    @PostMapping("/generateTrace")
+    @Operation(summary = "生成车辆轨迹", description = "根据日期、运单号、车牌号、当前位置生成车辆轨迹数据")
+    public BaseResult<Void> generateTrace(@Valid @RequestBody GenerateTraceReq req) {
+        kwfTruckTraceService.generateTrace(req);
+        return BaseResult.success();
+    }
 
 }

+ 26 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/controller/KwtWaybillOrderController.java

@@ -717,5 +717,31 @@ public class KwtWaybillOrderController {
          transportService.addLogisticOrder(req);
     }
 
+    /**
+     * 根据运单号模糊查询运单ID和运单号列表
+     *
+     * @param req 查询请求参数
+     * @return 运单列表
+     * @author system
+     * @date 2025-12-01
+     */
+    @PostMapping("/queryWaybillOrderList")
+    @Operation(summary = "根据运单号模糊查询运单ID和运单号列表")
+    public BaseResult<List<WaybillOrderSimpleVo>> queryWaybillOrderList(@RequestBody WaybillOrderQueryByNoReq req) {
+        return BaseResult.success(waybillOrderV1Service.queryWaybillOrderListByWOrderNo(req.getWOrderNo()));
+    }
+
+    /**
+     * 查询运单车辆ID和车牌号列表
+     *
+     * @return 车辆列表
+     * @author system
+     * @date 2025-12-02
+     */
+    @GetMapping("/queryTruckList")
+    @Operation(summary = "查询运单车辆ID和车牌号列表")
+    public BaseResult<List<WaybillOrderTruckVo>> queryTruckList() {
+        return BaseResult.success(waybillOrderV1Service.queryTruckList());
+    }
 
 }

+ 1 - 24
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/KwtVehicleException.java

@@ -86,30 +86,7 @@ public class KwtVehicleException implements Serializable {
      */
     @TableField("exception_time")
     private Date exceptionTime;
-    
-    /**
-     * 任务开始时间
-     */
-    @TableField("task_start_time")
-    private Date taskStartTime;
-    
-    /**
-     * 任务结束时间
-     */
-    @TableField("task_end_time")
-    private Date taskEndTime;
-    
-    /**
-     * 任务耗时(分钟)
-     */
-    @TableField("task_duration")
-    private Integer taskDuration;
-    
-    /**
-     * 异常数量
-     */
-    @TableField("exception_count")
-    private Integer exceptionCount;
+
     
     /**
      * 经度

+ 40 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/dto/GenerateTraceReq.java

@@ -0,0 +1,40 @@
+package com.sckw.transport.model.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author system
+ * @desc 生成轨迹请求
+ * @date 2025-12-02
+ */
+@Data
+@Schema(description = "生成轨迹请求")
+public class GenerateTraceReq implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "日期(格式:yyyy-MM-dd)", example = "2025-11-18", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "日期不能为空")
+    private String date;
+
+    @Schema(description = "运单号", example = "T88565469682136456969", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "运单号不能为空")
+    private String wOrderNo;
+
+    @Schema(description = "车牌号", example = "川A888528", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "车牌号不能为空")
+    private String truckNo;
+
+    @Schema(description = "当前位置(经纬度,格式:经度,纬度)", example = "104.065735,30.659462", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "当前位置不能为空")
+    private String currentLocation;
+
+    @Schema(description = "异常类型(1-车辆偏航,2-急刹车,3-超速,4-异常停车)")
+    private Integer exceptionType;
+}

+ 23 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/dto/WaybillOrderQueryByNoReq.java

@@ -0,0 +1,23 @@
+package com.sckw.transport.model.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author system
+ * @desc 根据运单号查询运单请求参数
+ * @date 2025-12-01
+ */
+@Data
+@Schema(description = "根据运单号查询运单请求参数")
+public class WaybillOrderQueryByNoReq implements Serializable {
+    
+    @Serial
+    private static final long serialVersionUID = 1L;
+    
+    @Schema(description = "运单号(支持模糊查询)", example = "YD202512")
+    private String wOrderNo;
+}

+ 1 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/VehiclesTrajectoryReq.java

@@ -15,7 +15,7 @@ import java.util.Date;
 @Data
 @Valid
 public class VehiclesTrajectoryReq {
-    //private String ts;
+    private String ts;
     /**
      * 手机号
      */

+ 26 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/vo/WaybillOrderSimpleVo.java

@@ -0,0 +1,26 @@
+package com.sckw.transport.model.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author system
+ * @desc 运单简单信息VO(用于下拉选择)
+ * @date 2025-12-01
+ */
+@Data
+@Schema(description = "运单简单信息VO")
+public class WaybillOrderSimpleVo implements Serializable {
+    
+    @Serial
+    private static final long serialVersionUID = 1L;
+    
+    @Schema(description = "运单ID")
+    private Long id;
+    
+    @Schema(description = "运单号")
+    private String wOrderNo;
+}

+ 23 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/vo/WaybillOrderTruckVo.java

@@ -0,0 +1,23 @@
+package com.sckw.transport.model.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 运单车辆信息VO
+ * @author system
+ */
+@Data
+@Schema(description = "运单车辆信息")
+public class WaybillOrderTruckVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "车辆ID")
+    private Long truckId;
+
+    @Schema(description = "车牌号")
+    private String truckNo;
+}

+ 35 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderRepository.java

@@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckw.core.model.enums.CarWaybillEnum;
 import com.sckw.transport.dao.KwtWaybillOrderMapper;
 import com.sckw.transport.model.KwtWaybillOrder;
+import jakarta.validation.constraints.NotBlank;
 import org.springframework.stereotype.Repository;
 
 import java.time.LocalDateTime;
@@ -236,4 +237,38 @@ public class KwtWaybillOrderRepository extends ServiceImpl<KwtWaybillOrderMapper
                         .le(Objects.nonNull(endDate), KwtWaybillOrder::getCreateTime, endDate)
                         .orderByDesc(KwtWaybillOrder::getUpdateTime));
     }
+    
+    /**
+     * 根据运单号模糊查询运单ID和运单号列表
+     * @param wOrderNo 运单号关键字(模糊匹配)
+     * @return 运单列表(最多返回50条)
+     */
+    public List<KwtWaybillOrder> queryWaybillOrderListByWOrderNo(String wOrderNo) {
+        return list(Wrappers.<KwtWaybillOrder>lambdaQuery()
+                .select(KwtWaybillOrder::getId, KwtWaybillOrder::getWOrderNo)
+                .eq(KwtWaybillOrder::getDelFlag, 0)
+                .like(StringUtils.isNotBlank(wOrderNo), KwtWaybillOrder::getWOrderNo, wOrderNo)
+                .orderByDesc(KwtWaybillOrder::getCreateTime)
+                .last("LIMIT 50"));
+    }
+
+    /**
+     * 查询运单车辆ID和车牌号列表(去重)
+     * @return 车辆列表(按车牌号分组去重)
+     */
+    public List<KwtWaybillOrder> queryTruckList(Long entId ) {
+        return list(Wrappers.<KwtWaybillOrder>lambdaQuery()
+                .select(KwtWaybillOrder::getTruckId, KwtWaybillOrder::getTruckNo)
+                .eq(KwtWaybillOrder::getDelFlag, 0)
+                .eq(KwtWaybillOrder::getEntId, entId)
+                .orderByDesc(KwtWaybillOrder::getTruckId));
+    }
+
+    public KwtWaybillOrder queryByWayOrderNo(String wOrderNo) {
+        return getOne(
+                Wrappers.<KwtWaybillOrder>lambdaQuery()
+                        .eq(KwtWaybillOrder::getWOrderNo, wOrderNo)
+                        .eq(KwtWaybillOrder::getDelFlag, 0)
+                        .last("limit 1"));
+    }
 }

+ 94 - 4
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtWaybillOrderV1Service.java

@@ -3,6 +3,8 @@ package com.sckw.transport.service;
 import cn.hutool.core.bean.BeanUtil;
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -3021,6 +3023,9 @@ public class KwtWaybillOrderV1Service {
 
         // 查询运单相关的装卸货时间信息
         Map<String, KwtWaybillOrderTicket> subBillIdAddressIdKeyAndOrderTrackMap = getStringKwtWaybillOrderTrackMap(addressIds);
+        
+        // 查询运单节点数据,获取离场时间
+        Map<Long, KwtWaybillOrderNode> wOrderIdAndOffsiteNodeMap = getOffsiteNodeMap(wayBillOrderIds);
 
         //更具物流订单查询商品
         List<KwtLogisticsOrderGoods> logisticsOrderGoods =
@@ -3065,7 +3070,7 @@ public class KwtWaybillOrderV1Service {
                 .map(record -> getWaybillOrderResp(record, waybillOrderIdAndBillOrderMap,
                         logOrderIdUnitTypeKeyAndUnitMap, finalLogOrderIdAndGoodsIdMap,
                         kwpGoodsMap, finalSubOrderIdAddressTypeKeyAndAddressMap, subBillIdAddressIdKeyAndOrderTrackMap,
-                        finalLogIdAndOrderMap, finalDictValueAndDictResDtoMap))
+                        finalLogIdAndOrderMap, finalDictValueAndDictResDtoMap, wOrderIdAndOffsiteNodeMap))
                 .collect(Collectors.toList());
 
         return PageDataResult.of(page,resps);
@@ -3134,6 +3139,41 @@ public class KwtWaybillOrderV1Service {
         }
         return subBillIdAddressIdKeyAndOrderTrackMap;
     }
+    
+    /**
+     * 批量查询运单的离场节点
+     * @param wOrderIds 运单ID集合
+     * @return 运单ID对应的离场节点Map
+     */
+    @NotNull
+    private Map<Long, KwtWaybillOrderNode> getOffsiteNodeMap(Set<Long> wOrderIds) {
+        Map<Long, KwtWaybillOrderNode> offsiteNodeMap = Maps.newHashMap();
+        
+        if (CollectionUtils.isEmpty(wOrderIds)) {
+            return offsiteNodeMap;
+        }
+        
+        // 查询所有运单的节点数据,过滤出状态为“已离场”的节点
+        List<KwtWaybillOrderNode> nodes = kwtWaybillOrderNodeRepository.list(
+                Wrappers.<KwtWaybillOrderNode>lambdaQuery()
+                        .in(KwtWaybillOrderNode::getWOrderId, wOrderIds)
+                        .eq(KwtWaybillOrderNode::getOrderStatus, CarWaybillV1Enum.WAIT_LOADING.getCode())
+                        .orderByAsc(KwtWaybillOrderNode::getCreateTime)
+        );
+        
+        if (CollectionUtils.isNotEmpty(nodes)) {
+            // 每个运单只取最后一条离场记录
+            offsiteNodeMap = nodes.stream()
+                    .collect(Collectors.toMap(
+                            KwtWaybillOrderNode::getWOrderId,
+                            Function.identity(),
+                            (existing, replacement) -> 
+                                    existing.getCreateTime().before(replacement.getCreateTime()) ? existing : replacement
+                    ));
+        }
+        
+        return offsiteNodeMap;
+    }
 
     @NotNull
     private Set<Long> getLogOrderIds(WaybillOrderReq req) {
@@ -3238,7 +3278,8 @@ public class KwtWaybillOrderV1Service {
                                                         Map<String, KwtWaybillOrderAddress> finalSubOrderIdAddressTypeKeyAndAddressMap,
                                                         Map<String, KwtWaybillOrderTicket> finalSubBillIdAddressIdKeyAndOrderTrackMap,
                                                         Map<Long, KwtLogisticsOrder> finalLogIdAndOrderMap,
-                                                        Map<String, SysDictResDto> dictValueAndDictResDtoMap) {
+                                                        Map<String, SysDictResDto> dictValueAndDictResDtoMap,
+                                                        Map<Long, KwtWaybillOrderNode> wOrderIdAndOffsiteNodeMap) {
         WaybillOrderResp waybillOrderResp = new WaybillOrderResp();
         KwtWaybillOrder billOrder = finalWaybillOrderIdAndBillOrderMap.getOrDefault(record.getWOrderId(),
                 new KwtWaybillOrder());
@@ -3291,8 +3332,13 @@ public class KwtWaybillOrderV1Service {
                 finalSubBillIdAddressIdKeyAndOrderTrackMap.getOrDefault(record.getId() + "-" + loadingAdd.getId(),
                         new KwtWaybillOrderTicket());
         waybillOrderResp.setLoadingTime(DateUtils.format(loadTrack.getOperateTime(),DateUtils.DATE_TIME_PATTERN));
-        //todo  cxf
-        waybillOrderResp.setOffsiteTime(DateUtils.format(unloadTrack.getOperateTime(),DateUtils.DATE_TIME_PATTERN));
+        
+        // 从节点表中获取离场时间
+        KwtWaybillOrderNode offsiteNode = wOrderIdAndOffsiteNodeMap.get(record.getWOrderId());
+        if (offsiteNode != null) {
+            waybillOrderResp.setOffsiteTime(DateUtils.format(offsiteNode.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
+        }
+        
         waybillOrderResp.setUnloadingTime(DateUtils.format(unloadTrack.getOperateTime(),DateUtils.DATE_TIME_PATTERN));
         if (Objects.equals(record.getStatus(), CarWaybillV1Enum.WAIT_UNLOADING.getCode())){
             waybillOrderResp.setCompleteTime(DateUtils.format(record.getUpdateTime(),DateUtils.DATE_TIME_PATTERN));
@@ -3934,4 +3980,48 @@ public class KwtWaybillOrderV1Service {
         // 暂时返回经纬度格式
         return String.format("经度:%s, 纬度:%s", lng, lat);
     }
+    
+    /**
+     * 根据运单号模糊查询运单ID和运单号列表
+     *
+     * @param wOrderNo 运单号关键字(模糊匹配)
+     * @return 运单列表
+     */
+    public List<WaybillOrderSimpleVo> queryWaybillOrderListByWOrderNo(String wOrderNo) {
+        // 查询运单数据
+        List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryWaybillOrderListByWOrderNo(wOrderNo);
+        
+        // 转换为VO
+        return waybillOrders.stream()
+                .map(order -> {
+                    WaybillOrderSimpleVo vo = new WaybillOrderSimpleVo();
+                    vo.setId(order.getId());
+                    vo.setWOrderNo(order.getWOrderNo());
+                    return vo;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 查询运单车辆ID和车牌号列表(去重)
+     *
+     * @return 车辆列表
+     */
+    public List<WaybillOrderTruckVo> queryTruckList() {
+        Long entId = LoginUserHolder.getEntId();
+        // 查询运单车辆数据
+        List<KwtWaybillOrder> waybillOrders = kwtWaybillOrderRepository.queryTruckList(entId);
+        if (org.apache.commons.collections4.CollectionUtils.isEmpty(waybillOrders)){
+            return List.of();
+        }
+        // 转换为VO
+        return waybillOrders.stream()
+                .map(order -> {
+                    WaybillOrderTruckVo vo = new WaybillOrderTruckVo();
+                    vo.setTruckId(order.getTruckId());
+                    vo.setTruckNo(order.getTruckNo());
+                    return vo;
+                })
+                .collect(Collectors.toList());
+    }
 }

+ 3 - 3
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/VehicleExceptionService.java

@@ -68,7 +68,7 @@ public class VehicleExceptionService {
         // 转换为VO
         final Map<String, Integer> finalLocationStatusMap = truckLocationStatusMap;
         List<VehicleExceptionVo> voList = records.stream()
-                .map(image -> buildVehicleExceptionImageVo(image, finalLocationStatusMap))
+                .map(image -> buildVehicleExceptionVo(image, finalLocationStatusMap))
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
         
@@ -89,8 +89,8 @@ public class VehicleExceptionService {
      * @param locationStatusMap    定位状态Map
      * @return VO对象
      */
-    private VehicleExceptionVo buildVehicleExceptionImageVo(KwtVehicleException image,
-                                                            Map<String, Integer> locationStatusMap) {
+    private VehicleExceptionVo buildVehicleExceptionVo(KwtVehicleException image,
+                                                       Map<String, Integer> locationStatusMap) {
         VehicleExceptionVo vo = new VehicleExceptionVo();
         
         vo.setId(image.getId());

+ 120 - 11
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/kwfTruckTraceService.java

@@ -24,6 +24,7 @@ import com.sckw.core.web.response.BaseResult;
 import com.sckw.fleet.api.RemoteFleetService;
 import com.sckw.fleet.api.model.vo.RDriverVo;
 import com.sckw.fleet.api.model.vo.RFleetDriverVo;
+import com.sckw.fleet.api.model.vo.RFleetVo;
 import com.sckw.fleet.api.model.vo.RTruckVo;
 import com.sckw.manage.api.RemoteManageService;
 import com.sckw.order.api.dubbo.RemoteTradeOrderAmountService;
@@ -41,6 +42,7 @@ import com.sckw.transport.api.feign.VehicleTraceClient;
 import com.sckw.transport.api.model.dto.VehicleDataDTO;
 import com.sckw.transport.api.model.dto.VehicleReturnData;
 import com.sckw.transport.model.param.*;
+import com.sckw.transport.model.dto.GenerateTraceReq;
 import com.sckw.transport.model.vo.CurrentTaskTraceReqVo;
 import com.sckw.transport.model.vo.KwfTruckTraceReplayVo;
 import com.sckw.transport.model.vo.TruckInfoVo;
@@ -89,6 +91,7 @@ public class kwfTruckTraceService {
     private final VehicleTraceClient vehicleTraceClient;
     private final KwtLogisticsOrderGoodsRepository kwtLogisticsOrderGoodsRepository;
     private final KwtLogisticsOrderRepository kwtLogisticsOrderRepository;
+    private final KwtVehicleExceptionRepository kwtVehicleExceptionRepository;
     @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
     RemoteSystemService remoteSystemService;
 
@@ -1158,20 +1161,16 @@ public class kwfTruckTraceService {
         }
         
         // 任务开始时间
-        if (order.getTaskStartTime() != null) {
-            vo.setTaskStartTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(order.getTaskStartTime()));
-        } else if (order.getCreateTime() != null) {
-            // 如果没有任务开始时间,使用创建时间
-            vo.setTaskStartTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(order.getCreateTime()));
-        }
+        vo.setTaskStartTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(order.getCreateTime()));
         
         // 计算任务耗时(分钟)
-        Date startTime = order.getTaskStartTime() != null ? order.getTaskStartTime() : order.getCreateTime();
-        if (startTime != null) {
-            Date endTime = order.getTaskEndTime() != null ? order.getTaskEndTime() : new Date();
-            long duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
-            vo.setTaskDuration(duration);
+        Date startTime =  order.getCreateTime();
+        Date endTime = new Date();
+        if (Objects.equals(order.getStatus(), CarWaybillV1Enum.WAIT_UNLOADING.getCode())){
+            endTime = order.getUpdateTime() != null ? order.getUpdateTime() : new Date();
         }
+        long duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
+        vo.setTaskDuration(duration);
         
         // 从异常表查询该运单的异常数量
         Integer exceptionCount = exceptionCountMap.getOrDefault(order.getWOrderNo(), 0);
@@ -1210,4 +1209,114 @@ public class kwfTruckTraceService {
         }
         return allEnt;
     }
+
+    /**
+     * 生成车辆轨迹数据
+     * @param req 生成轨迹请求
+     */
+    public void generateTrace(GenerateTraceReq req) {
+        log.info("生成车辆轨迹参数:{}", JSON.toJSONString(req));
+        
+        // 校验当前位置格式
+        String[] location = req.getCurrentLocation().split(",");
+        if (location.length != 2) {
+            throw new BusinessException("当前位置格式错误,应为:经度,纬度");
+        }
+        
+        String longitude = location[0];
+        String latitude = location[1];
+
+        KwtWaybillOrder order = kwtWaybillOrderRepository.queryByWayOrderNo(req.getWOrderNo());
+        if (Objects.isNull(order)){
+            throw new BusinessException("运单不存在");
+        }
+        //查询子运单
+        KwtWaybillOrder subOrders = kwtWaybillOrderRepository.queryByBillOrderId(order.getLOrderId());
+        if (Objects.isNull(subOrders)){
+            throw new BusinessException("子运单不存在");
+        }
+        // 通过车牌id查询车队
+        RFleetVo fleetByTruckId = fleetService.findFleetByTruckId(order.getTruckId(), order.getEntId());
+        //查询物流订单号
+        KwtLogisticsOrder logisticsOrder = kwtLogisticsOrderRepository.queryByLogisticsOrderId(subOrders.getLOrderId());
+
+        // 构造轨迹数据
+        VehiclesTrajectoryReq vehiclesTrajectoryReq = getVehiclesTrajectoryReq(req, order, longitude, latitude, logisticsOrder, fleetByTruckId);
+
+        try {
+            // 调用数据中台保存轨迹数据
+            BaseResult<Void> result = vehicleTraceClient.saveVehicleData(vehiclesTrajectoryReq);
+            if (result.getCode() != HttpStatus.SUCCESS_CODE) {
+                log.error("保存车辆轨迹数据失败:{}", result.getMessage());
+                throw new BusinessException("生成轨迹失败:" + result.getMessage());
+            }
+            
+            // 如果有异常类型,同时保存到本地车辆异常表
+            saveException(req, order, longitude, latitude);
+
+            log.info("生成车辆轨迹成功,运单号:{},车牌号:{}", req.getWOrderNo(), req.getTruckNo());
+        } catch (Exception e) {
+            log.error("生成车辆轨迹异常:", e);
+            throw new BusinessException("生成轨迹失败:" + e.getMessage());
+        }
+
+
+    }
+
+    private void saveException(GenerateTraceReq req, KwtWaybillOrder order, String longitude, String latitude) {
+        if (Objects.nonNull(req.getExceptionType())) {
+            // 保存到车辆异常表
+            KwtVehicleException vehicleException = new KwtVehicleException();
+            vehicleException.setEntId(order.getEntId());
+            vehicleException.setTruckId(order.getTruckId());
+            vehicleException.setTruckNo(req.getTruckNo());
+            vehicleException.setWOrderNo(req.getWOrderNo());
+            vehicleException.setDriverId(order.getDriverId());
+            vehicleException.setDriverName(order.getDriverName());
+            vehicleException.setDriverPhone(order.getDriverPhone());
+            vehicleException.setExceptionType(req.getExceptionType());
+            vehicleException.setLongitude(longitude);
+            vehicleException.setLatitude(latitude);
+            vehicleException.setExceptionTime(new Date());
+            vehicleException.setCreateBy(LoginUserHolder.getUserId());
+            vehicleException.setCreateTime(new Date());
+            vehicleException.setUpdateBy(LoginUserHolder.getUserId());
+            vehicleException.setUpdateTime(new Date());
+            vehicleException.setDelFlag(0);
+
+            // 保存异常信息
+            kwtVehicleExceptionRepository.save(vehicleException);
+        }
+    }
+
+    @NotNull
+    private static VehiclesTrajectoryReq getVehiclesTrajectoryReq(GenerateTraceReq req, KwtWaybillOrder order, String longitude, String latitude, KwtLogisticsOrder logisticsOrder, RFleetVo fleetByTruckId) {
+        VehiclesTrajectoryReq vehiclesTrajectoryReq = new VehiclesTrajectoryReq();
+        vehiclesTrajectoryReq.setTs(req.getDate() + " " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
+        vehiclesTrajectoryReq.setMobile(order.getDriverPhone());
+        vehiclesTrajectoryReq.setTruckNo(req.getTruckNo());
+        vehiclesTrajectoryReq.setLongitude(longitude);
+        vehiclesTrajectoryReq.setLatitude(latitude);
+        vehiclesTrajectoryReq.setSpeed(60.0f);
+        vehiclesTrajectoryReq.setGpsStatus("60");
+        vehiclesTrajectoryReq.setDirection(30.0f);
+        vehiclesTrajectoryReq.setFuelLevel(20.0f);
+        vehiclesTrajectoryReq.setMileage("60");
+        vehiclesTrajectoryReq.setEngineTemp(40.0f);
+        vehiclesTrajectoryReq.setBatteryVoltage(30.0f);
+        vehiclesTrajectoryReq.setStatus("0");
+        if (req.getExceptionType() != null){
+            vehiclesTrajectoryReq.setStatus(String.valueOf(req.getExceptionType()));
+        }
+        vehiclesTrajectoryReq.setWOrderNo(req.getWOrderNo());
+        vehiclesTrajectoryReq.setLOrderNo(Optional.ofNullable(logisticsOrder).map(KwtLogisticsOrder::getLOrderNo).orElse( ""));
+        VehiclesTrajectoryReq.VehicleDataVO vehicleDataVO = new VehiclesTrajectoryReq.VehicleDataVO();
+        vehicleDataVO.setCarNo(req.getTruckNo());
+        if (fleetByTruckId != null){
+            vehicleDataVO.setFleetId(fleetByTruckId.getId().toString());
+            vehicleDataVO.setFleetName(fleetByTruckId.getName());
+        }
+        vehiclesTrajectoryReq.setVehicleDataVO(vehicleDataVO);
+        return vehiclesTrajectoryReq;
+    }
 }

+ 1 - 7
sql/2025/12/01/2025_12_01_vehicle_exception.sql

@@ -11,10 +11,6 @@ CREATE TABLE IF NOT EXISTS `kwt_vehicle_exception` (
   `exception_type` int(2) DEFAULT '0' COMMENT '异常类型(1-车辆偏航,2-急刹车,3-超速,4-异常停车)',
   `image_url` varchar(500) DEFAULT '' COMMENT '图片URL',
   `exception_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '异常时间',
-  `task_start_time` datetime DEFAULT NULL COMMENT '任务开始时间',
-  `task_end_time` datetime DEFAULT NULL COMMENT '任务结束时间',
-  `task_duration` int(10) DEFAULT '0' COMMENT '任务耗时(分钟)',
-  `exception_count` int(10) DEFAULT '0' COMMENT '异常数量',
   `longitude` varchar(50) DEFAULT '' COMMENT '经度',
   `latitude` varchar(50) DEFAULT '' COMMENT '纬度',
   `location` varchar(200) DEFAULT '' COMMENT '位置描述',
@@ -29,7 +25,5 @@ CREATE TABLE IF NOT EXISTS `kwt_vehicle_exception` (
   KEY `idx_truck_no` (`truck_no`),
   KEY `idx_w_order_no` (`w_order_no`),
   KEY `idx_exception_type` (`exception_type`),
-  KEY `idx_exception_time` (`exception_time`),
-  KEY `idx_task_duration` (`task_duration`),
-  KEY `idx_exception_count` (`exception_count`)
+  KEY `idx_exception_time` (`exception_time`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆异常表';