Forráskód Böngészése

Merge remote-tracking branch 'origin/dev_20251130' into dev_20251130

xucaiqin 1 hónapja
szülő
commit
56dc2e4cc3

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

@@ -74,7 +74,7 @@ public class KwfTruckTraceController {
      */
     @PostMapping("/replay")
     @Operation(summary = "轨迹回放")
-    public BaseResult<PageDataResult<KwfTruckTraceReplayVo>> findPage(@RequestBody KwfTruckTraceReplayReq req )  {
+    public BaseResult<PageDataResult<KwfTruckTraceReplayVo>> findPage(@RequestBody @Valid KwfTruckTraceReplayReq req )  {
 
         return BaseResult.success( kwfTruckTraceService.findPage(req));
     }

+ 18 - 4
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/KwfTruckTraceReplayReq.java

@@ -2,6 +2,8 @@ package com.sckw.transport.model.param;
 
 import com.sckw.core.web.request.PageReq;
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
@@ -18,17 +20,29 @@ public class KwfTruckTraceReplayReq extends PageReq implements Serializable {
     @Serial
     private static final long serialVersionUID = -34385531213284288L;
     /**
-     * 任务创建时间下限
+     * 任务创建开始时间 yyyy-MM-dd
      */
-    @Schema(description = "任务创建时间下限")
+    @Schema(description = "任务创建开始时间 yyyy-MM-dd")
+    @NotBlank(message = "任务创建开始时间不能为空")
     private String startTime;
     /**
-     * 任务开始时间上限
+     * 任务创建结束时间 yyyy-MM-dd
      */
-    @Schema(description = "任务创建时间上限")
+    @Schema(description = "任务创建结束时间 yyyy-MM-dd")
+    @NotBlank(message = "任务创建结束时间不能为空")
     private String endTime;
     /**
      * 车牌号
      */
+    @Schema(description = "车牌号")
     private String truckNo;
+
+    @Schema(description = "承运单位ID")
+    private Long carrierEntId;
+    @Schema(description = "物流订单号")
+    private String logisticOrderNo;
+
+
+    @Schema(description = "排序类型(1-按时间排序,2-耗时排序,3-异常排序)", example = "1")
+    private Integer sortType = 1;
 }

+ 25 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/vo/KwfTruckTraceReplayVo.java

@@ -20,6 +20,11 @@ public class KwfTruckTraceReplayVo implements Serializable {
      */
     @Schema(description = "运单id")
     private Long orderId;
+    /**
+     * 物流订单号
+     */
+    @Schema(description = "物流订单号")
+    private String logOrderNo;
     /**
      * 运单编号
      */
@@ -35,6 +40,11 @@ public class KwfTruckTraceReplayVo implements Serializable {
      */
     @Schema(description = "司机手机号")
     private String phone;
+    /**
+     * 车牌号
+     */
+    @Schema(description = "车牌号")
+    private String truckNo;
     /**
      * 承运单位
      */
@@ -43,7 +53,7 @@ public class KwfTruckTraceReplayVo implements Serializable {
     /**
      * 状态
      */
-    @Schema(description = "状态")
+    @Schema(description = "状态 0-任务中 1-已结束")
     private String status;
 
     /**
@@ -82,4 +92,18 @@ public class KwfTruckTraceReplayVo implements Serializable {
      */
     @Schema(description = "告警记录数")
     private String warningCount;
+
+    @Schema(description = "异常数量")
+    private Integer exceptionCount;
+
+    @Schema(description = "任务耗时(分钟)")
+    private Long taskDuration;
+
+    @Schema(description = "任务进行中的实时经度")
+    private String longitude;
+    /**
+     * 任务进行中的实时纬度
+     */
+    @Schema(description = "任务进行中的实时纬度")
+    private String latitude;
 }

+ 2 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderRepository.java

@@ -53,12 +53,13 @@ public class KwtWaybillOrderRepository extends ServiceImpl<KwtWaybillOrderMapper
 
     }
 
-    public Page<KwtWaybillOrder> findPage(String truckNo,int pageNum, int pageSize, Date beforeDate, Date date) {
+    public Page<KwtWaybillOrder> findPage(Set<Long> wayOrderIds,String truckNo,int pageNum, int pageSize, Date beforeDate, Date date) {
         Page<KwtWaybillOrder> page = new Page<>(pageNum, pageSize);
         LambdaQueryWrapper<KwtWaybillOrder> wrapper = Wrappers.<KwtWaybillOrder>lambdaQuery()
                 .ge(KwtWaybillOrder::getCreateTime, beforeDate)
                 .le(KwtWaybillOrder::getCreateTime, date)
                 .eq(KwtWaybillOrder::getDelFlag, 0)
+                .in(CollectionUtils.isNotEmpty(wayOrderIds),KwtWaybillOrder::getLOrderId, wayOrderIds)
                 .eq(StringUtils.isNotBlank(truckNo),KwtWaybillOrder::getTruckNo, truckNo)
                 .orderByDesc(KwtWaybillOrder::getCreateTime);
         return page(page,wrapper);

+ 142 - 21
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/kwfTruckTraceService.java

@@ -122,18 +122,18 @@ public class kwfTruckTraceService {
 
     public PageDataResult<KwfTruckTraceReplayVo> findPage(KwfTruckTraceReplayReq req) {
         log.info("查询历轨迹回放参数:{}", req);
-        if (StringUtils.isBlank(req.getTruckNo())){
+
+        Date startDate = getStartDate(req.getStartTime());
+        Date endDate = getEndDate(req.getEndTime());
+        // 前置条件:根据承运单位和托运单位筛选出符合条件的运单ID
+        MapVehicleQueryReq queryReq = new MapVehicleQueryReq();
+        queryReq.setCarrierEntId(req.getCarrierEntId());
+        queryReq.setLogisticOrderNo(req.getLogisticOrderNo());
+        Set<Long> wayOrderIds = getWayOrderIds(queryReq);
+        if (CollectionUtils.isEmpty(wayOrderIds) && (StringUtils.isNotBlank(req.getLogisticOrderNo()) || Objects.nonNull(req.getCarrierEntId()))) {
             return PageDataResult.empty(req.getPageNum(), req.getPageSize());
         }
-        Date date = new Date();
-        if (StringUtils.isNotBlank(req.getStartTime())){
-            date = DateUtils.formatDate(req.getStartTime());
-        }
-        Date beforeDate = DateUtils.addDateDays(date, -30);
-        if (StringUtils.isNotBlank(req.getEndTime())){
-            beforeDate = DateUtils.formatDate(req.getEndTime());
-        }
-        Page<KwtWaybillOrder> page = kwtWaybillOrderRepository.findPage(req.getTruckNo(),req.getPageNum(), req.getPageSize(), beforeDate, date);
+        Page<KwtWaybillOrder> page = kwtWaybillOrderRepository.findPage(wayOrderIds,req.getTruckNo(),req.getPageNum(), req.getPageSize(), startDate, endDate);
         List<KwtWaybillOrder> records = page.getRecords();
         if(CollectionUtils.isEmpty(page.getRecords())) {
             return PageDataResult.success(req.getPageNum(), req.getPageSize(),0L, null);
@@ -154,8 +154,19 @@ public class kwfTruckTraceService {
             worderNoAndWorderMap = waybillOrderSubtasks.stream()
                     .collect(Collectors.toMap(KwtWaybillOrderSubtask::getWOrderNo, Function.identity(), (k1, k2) -> k1));
         }
+        List<KwtLogisticsOrderUnit> logisticsOrderUnits = Lists.newArrayList();
+        Map<Long, KwtLogisticsOrder> logisticsOrderMap = Maps.newHashMap();
+        if (CollectionUtils.isNotEmpty(lOrderIds)){
+            //查询物流订单
+            List<KwtLogisticsOrder> logisticsOrders = kwtLogisticsOrderRepository.queryByLogisticsOrderIds(new ArrayList<>(lOrderIds));
+            logisticsOrderMap = Optional.ofNullable(logisticsOrders)
+                    .orElse(List.of())
+                    .stream()
+                    .collect(Collectors.toMap(KwtLogisticsOrder::getId, Function.identity(), (k1, k2) -> k1));
+            logisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByLOrderIdsAndUnitType(lOrderIds,2);
+        }
+
 
-        List<KwtLogisticsOrderUnit> logisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByLOrderIdsAndUnitType(lOrderIds,2);
         //物流订单id映射企业
         Map<Long, KwtLogisticsOrderUnit> lOrderIdAndLogisticsOrderUnitMap = logisticsOrderUnits.stream()
                 .collect(Collectors.toMap(KwtLogisticsOrderUnit::getLOrderId, Function.identity(), (k1, k2) -> k1));
@@ -169,13 +180,84 @@ public class kwfTruckTraceService {
         Map<Long, List<KwtWaybillOrderAddress>> wOrderIdAndAddressMap = orderAddresses.stream()
                 .collect(Collectors.groupingBy(KwtWaybillOrderAddress::getWOrderId));
 
+        // 批量查询运单轨迹数据,统计异常数量(通过alarmCode判断)
+        List<String> wOrderNos = records.stream()
+                .map(KwtWaybillOrder::getWOrderNo)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        // 批量查询每个运单的轨迹数据
+        Map<String, Integer> exceptionCountMap = Maps.newHashMap();
+        Map<String,List<VehicleReturnData>> traceMap = Maps.newHashMap();
+        getTraceInfoList(wOrderNos, traceMap, exceptionCountMap);
+
+        // Map<String, Integer> exceptionCountMap = countExceptionsByTraceData(wOrderNos);
         Map<String, KwtWaybillOrderSubtask> finalWorderNoAndWorderMap = worderNoAndWorderMap;
+        Map<Long, KwtLogisticsOrder> finalLogisticsOrderMap = logisticsOrderMap;
         List<KwfTruckTraceReplayVo> kwfTruckTraceReplayVoList = records.stream()
-                .map(r -> getKwfTruckTraceReplayVo(r, idAndKwsEnterpriseMap, wOrderIdAndAddressMap, lOrderIdAndLogisticsOrderUnitMap, finalWorderNoAndWorderMap))
+                .map(r -> getKwfTruckTraceReplayVo(r, idAndKwsEnterpriseMap, wOrderIdAndAddressMap,
+                        lOrderIdAndLogisticsOrderUnitMap, finalWorderNoAndWorderMap,
+                        exceptionCountMap, finalLogisticsOrderMap,traceMap))
                 .collect(Collectors.toList());
+        // 根据排序类型进行排序
+        MapVehicleSortTypeEnum sortType = MapVehicleSortTypeEnum.getByCode(req.getSortType());
+        kwfTruckTraceReplayVoList = switch (sortType) {
+            case TIME_DESC ->
+                // 按任务开始时间倒序
+                    kwfTruckTraceReplayVoList.stream()
+                            .sorted(Comparator.comparing(KwfTruckTraceReplayVo::getTaskStartTime,
+                                    Comparator.nullsLast(Comparator.reverseOrder())))
+                            .collect(Collectors.toList());
+            case DURATION_DESC ->
+                // 按任务耗时倒序
+                    kwfTruckTraceReplayVoList.stream()
+                            .sorted(Comparator.comparing(KwfTruckTraceReplayVo::getTaskDuration,
+                                    Comparator.nullsLast(Comparator.reverseOrder())))
+                            .collect(Collectors.toList());
+            case EXCEPTION_COUNT_DESC ->
+                // 按异常数量倒序
+                    kwfTruckTraceReplayVoList.stream()
+                            .sorted(Comparator.comparing(KwfTruckTraceReplayVo::getExceptionCount,
+                                    Comparator.nullsLast(Comparator.reverseOrder())))
+                            .collect(Collectors.toList());
+        };
        return PageDataResult.of(page,kwfTruckTraceReplayVoList);
     }
 
+    private void getTraceInfoList(List<String> wOrderNos, Map<String,List<VehicleReturnData>> traceMap, Map<String, Integer> exceptionCountMap) {
+        if (CollectionUtils.isNotEmpty(wOrderNos)) {
+            for (String wOrderNo : wOrderNos) {
+                try {
+                    VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
+                    vehicleDataDTO.setWOrderNo(wOrderNo);
+
+                    // 调用Feign接口查询轨迹列表
+                    log.info("查询车辆数据中台请求轨迹数据:{}", JSON.toJSONString( vehicleDataDTO));
+                    BaseIotResult<List<VehicleReturnData>> result =
+                            vehicleTraceClient.queryVehicleDataList(vehicleDataDTO);
+                    log.info("查询车辆数据中台响应轨迹数据:{}", JSON.toJSONString( result));
+                    if (result != null && StringUtils.equals(result.getCode(), "0") && result.getData() != null) {
+                        List<VehicleReturnData> traceDataList = result.getData();
+                        traceMap.put(wOrderNo, traceDataList);
+                        // 统计alarmCode不为null且不为0的记录数量(表示有异常报警)
+                        int exceptionCount = (int) traceDataList.stream()
+                                .filter(data -> StringUtils.equals(data.getStatus(),"0"))
+                                .count();
+
+                        exceptionCountMap.put(wOrderNo, exceptionCount);
+                        log.debug("运单号: {}, 异常数量: {}", wOrderNo, exceptionCount);
+                    } else {
+                        log.warn("查询运单轨迹数据失败或返回空数据, 运单号: {}", wOrderNo);
+                        exceptionCountMap.put(wOrderNo, 0);
+                    }
+                } catch (Exception e) {
+                    log.error("查询运单轨迹数据异常, 运单号: {}", wOrderNo, e);
+                    exceptionCountMap.put(wOrderNo, 0);
+                }
+            }
+        }
+    }
+
     /**
      * 组织轨迹回访返回数据
      * @param waybillOrder 运单信息
@@ -186,17 +268,43 @@ public class kwfTruckTraceService {
     private static KwfTruckTraceReplayVo getKwfTruckTraceReplayVo(KwtWaybillOrder waybillOrder, Map<Long, KwsEnterpriseResDto> idAndKwsEnterpriseMap,
                                                                   Map<Long, List<KwtWaybillOrderAddress>> wOrderIdAndAddressMap
                                                                 ,Map<Long, KwtLogisticsOrderUnit> lOrderIdAndLogisticsOrderUnitMap
-                                                                ,Map<String, KwtWaybillOrderSubtask> worderNoAndWorderMap) {
+                                                                ,Map<String, KwtWaybillOrderSubtask> worderNoAndWorderMap,
+                                                                  Map<String, Integer> exceptionCountMap,
+                                                                  Map<Long, KwtLogisticsOrder> logisticsOrderMap,
+                                                                  Map<String,List<VehicleReturnData>> traceMap) {
 
         KwfTruckTraceReplayVo kwfTruckTraceReplay = new KwfTruckTraceReplayVo();
         kwfTruckTraceReplay.setOrderId(waybillOrder.getId());
         kwfTruckTraceReplay.setOrderNo(waybillOrder.getWOrderNo());
         kwfTruckTraceReplay.setDriverName(waybillOrder.getDriverName());
         kwfTruckTraceReplay.setPhone(waybillOrder.getDriverPhone());
+        kwfTruckTraceReplay.setTruckNo(waybillOrder.getTruckNo());
+        //已完成的状态
+        List<Integer> complatedStatusList = Arrays.asList(CarWaybillV1Enum.WAIT_UNLOADING.getCode(), CarWaybillV1Enum.APPROVAL_TREAT.getCode());
+        if (complatedStatusList.contains(waybillOrder.getStatus())){
+            kwfTruckTraceReplay.setStatus("1");
+            kwfTruckTraceReplay.setStatusDesc("已结束");
+            String endStartEndTime = DateUtils.format(waybillOrder.getUpdateTime(), DateUtils.DATE_TIME_PATTERN);
+            kwfTruckTraceReplay.setTaskEndTime(StringUtils.equals(endStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: endStartEndTime);
+        }else {
+            kwfTruckTraceReplay.setStatus("0");
+            kwfTruckTraceReplay.setStatusDesc("任务中");
+            List<VehicleReturnData> data = traceMap.getOrDefault(waybillOrder.getWOrderNo(), new ArrayList<>());
+            if (CollectionUtils.isNotEmpty(data)){
+                VehicleReturnData vehicleReturnData = data.get(0);
+                kwfTruckTraceReplay.setLatitude(vehicleReturnData.getLatitude());
+                kwfTruckTraceReplay.setLongitude(vehicleReturnData.getLongitude());
+                String endStartEndTime = DateUtils.format(vehicleReturnData.getTs(), DateUtils.DATE_TIME_PATTERN);
+                kwfTruckTraceReplay.setTaskEndTime(StringUtils.equals(endStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: endStartEndTime);
+            }
+
+        }
         kwfTruckTraceReplay.setStatus(String.valueOf(waybillOrder.getStatus()));
         kwfTruckTraceReplay.setStatusDesc(CarWaybillEnum.getName(waybillOrder.getStatus()));
         KwtWaybillOrderSubtask subtask = worderNoAndWorderMap.getOrDefault(waybillOrder.getWOrderNo(), new KwtWaybillOrderSubtask());
         kwfTruckTraceReplay.setRelationTaskNo(String.valueOf(subtask.getLOrderId()));
+        KwtLogisticsOrder logisticsOrder = logisticsOrderMap.getOrDefault(subtask.getLOrderId(), new KwtLogisticsOrder());
+        kwfTruckTraceReplay.setLogOrderNo(logisticsOrder.getLOrderNo());
         KwtLogisticsOrderUnit kwtLogisticsOrderUnit = lOrderIdAndLogisticsOrderUnitMap.getOrDefault(subtask.getLOrderId(), new KwtLogisticsOrderUnit());
         KwsEnterpriseResDto orDefault = idAndKwsEnterpriseMap.getOrDefault(kwtLogisticsOrderUnit.getEntId(), new KwsEnterpriseResDto());
         kwfTruckTraceReplay.setCarrier(orDefault.getFirmName());
@@ -210,13 +318,21 @@ public class kwfTruckTraceService {
             }
         });
 
-
-        String taskStartEndTime = DateUtils.format(waybillOrder.getTaskStartTime(), DateUtils.DATE_TIME_PATTERN);
+        Date startTime =  waybillOrder.getCreateTime();
+        String taskStartEndTime = DateUtils.format(startTime, DateUtils.DATE_TIME_PATTERN);
         kwfTruckTraceReplay.setTaskStartTime(StringUtils.equals(taskStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: taskStartEndTime);
 
-        String endStartEndTime = DateUtils.format(waybillOrder.getTaskEndTime(), DateUtils.DATE_TIME_PATTERN);
-        kwfTruckTraceReplay.setTaskEndTime(StringUtils.equals(endStartEndTime, CommonConstants.DATE_TIME) ? StringUtils.EMPTY: endStartEndTime);
         kwfTruckTraceReplay.setWarningCount("");
+        // 从异常表查询该运单的异常数量
+        Integer exceptionCount = exceptionCountMap.getOrDefault(waybillOrder.getWOrderNo(), 0);
+        kwfTruckTraceReplay.setExceptionCount(exceptionCount);
+        // 计算任务耗时(分钟)
+        Date endTime = new Date();
+        if (Objects.equals(waybillOrder.getStatus(), CarWaybillV1Enum.WAIT_UNLOADING.getCode())){
+            endTime = waybillOrder.getUpdateTime() != null ? waybillOrder.getUpdateTime() : new Date();
+        }
+        long duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
+        kwfTruckTraceReplay.setTaskDuration(duration);
         return kwfTruckTraceReplay;
     }
 
@@ -918,7 +1034,7 @@ public class kwfTruckTraceService {
         
         // 批量查询定位状态和位置信息
         Map<String, VehicleLocationInfo> locationInfoMap = queryVehicleLocationBatch(truckNos);
-        
+
         // 批量查询运单轨迹数据,统计异常数量(通过alarmCode判断)
         List<String> wOrderNos = waybillOrders.stream()
                 .map(KwtWaybillOrder::getWOrderNo)
@@ -987,11 +1103,16 @@ public class kwfTruckTraceService {
     @NotNull
     private Set<Long> getWayOrderIds(MapVehicleQueryReq req) {
         Set<Long> wayOrderIds = Sets.newHashSet();
-        if (req.getConsignEntId() != null || req.getCarrierEntId() != null) {
+        List<Long> entIds = new ArrayList<>();
+        if (req.getConsignEntId() != null){
+            entIds.add(req.getConsignEntId());
+        }
+        if (req.getCarrierEntId() != null){
+            entIds.add(req.getCarrierEntId());
+        }
+        if (CollectionUtils.isNotEmpty(entIds)) {
             // 第一步:从物流订单单位表查询符合条件的物流订单ID
             // 同时有托运和承运单位条件,将企业ID和类型组合后批量查询
-            List<Long> entIds = Arrays.asList(req.getConsignEntId(), req.getCarrierEntId());
-
             List<KwtLogisticsOrderUnit> allUnits = kwtLogisticsOrderUnitRepository.list(
                     Wrappers.<KwtLogisticsOrderUnit>lambdaQuery()
                             .eq(KwtLogisticsOrderUnit::getDelFlag, 0)