Преглед изворни кода

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

xucaiqin пре 1 месец
родитељ
комит
2f82c2c793

+ 16 - 19
sckw-common/sckw-common-core/src/main/java/com/sckw/core/model/enums/CarWaybillV1Enum.java

@@ -69,41 +69,38 @@ public enum CarWaybillV1Enum {
      */
     WAIT_LOADING(18,  "已离场"),
 
-
     /**
-     * 已卸货
+     * 到达卸货点 (只有友盛在用)
      */
-    COMPLETION_LOADING(20,  "已卸货"),
+    UNLOADING_POINT(19, "到达卸货点"),
+
     /**
-     * 已完成
+     * 卸货待离场 (只有友盛在用)
      */
-    COMPLETED(25,  "已完成"),
+    UNLOADING_WAIT_LEAVE(20, "卸货待离场"),
+
     /**
-     * 审核驳回
+     * 卸货待放行 (只有友盛在用)
      */
-    REVIEW_REJECTION(30,  "审核驳回"),
-
+    UNLOADING_WAIT_RELEASE(21, "卸货待放行"),
 
     /**
-     * 到达卸货点
+     * 卸货已放行待离场 (只有友盛在用)  弃用
      */
-    UNLOADING_POINT(40, "到达卸货点"),
+    UNLOADING_RELEASED_WAIT_LEAVE(22, "卸货已放行待离场"),
 
     /**
-     * 卸货待离场
+     * 卸货
      */
-    UNLOADING_WAIT_LEAVE(45, "卸货待离场"),
-
+    COMPLETION_LOADING(23,  "已卸货"),
     /**
-     * 卸货待放行
+     * 已完成
      */
-    UNLOADING_WAIT_RELEASE(50, "卸货待放行"),
-
+    COMPLETED(25,  "已完成"),
     /**
-     * 卸货已放行待离场  弃用
+     * 审核驳回
      */
-    UNLOADING_RELEASED_WAIT_LEAVE(55, "卸货已放行待离场"),
-
+    REVIEW_REJECTION(30,  "审核驳回"),
 
     /**
      * 已作废

+ 1 - 1
sckw-common/sckw-common-core/src/main/java/com/sckw/core/model/enums/GatekeeperStatusEnum.java

@@ -48,7 +48,7 @@ public enum GatekeeperStatusEnum {
     /**
      * 取消
      */
-    CANCEL(99, "取消"),
+    CANCEL(99, "取消","取消"),
 
     ;
 

+ 13 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/dubbo/TransportServiceImpl.java

@@ -163,8 +163,20 @@ public class TransportServiceImpl implements TransportRemoteService {
             CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
             CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),
             CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
-            CarWaybillV1Enum.WEIGHT_TRAFFIC.getCode(),
+            CarWaybillV1Enum.EMPTY_WAIT_LEAVE.getCode(),
+            CarWaybillV1Enum.WAIT_LEAVE.getCode(),
+            CarWaybillV1Enum.UNLOADING.getCode(),
+            CarWaybillV1Enum.WAIT_RELEASE.getCode(),
+            CarWaybillV1Enum.REPLENISHING.getCode(),
+            CarWaybillV1Enum.REPLENISH_FINISH.getCode(),
+            CarWaybillV1Enum.RELEASED_NOT_EXITED.getCode(),
             CarWaybillV1Enum.WAIT_LOADING.getCode(),
+
+            CarWaybillV1Enum.UNLOADING_POINT.getCode(),
+            CarWaybillV1Enum.UNLOADING_WAIT_LEAVE.getCode(),
+            CarWaybillV1Enum.UNLOADING_WAIT_RELEASE.getCode(),
+            CarWaybillV1Enum.UNLOADING_RELEASED_WAIT_LEAVE.getCode(),
+
             CarWaybillV1Enum.REVIEW_REJECTION.getCode()
     );
 

+ 6 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/enuma/WaybillTimelinePhaseEnum.java

@@ -33,7 +33,12 @@ public enum WaybillTimelinePhaseEnum {
 
     DEPARTED(20, "已离场",
             EnumSet.of(
-                    CarWaybillV1Enum.WAIT_LOADING)),
+                    CarWaybillV1Enum.WAIT_LOADING,
+                    CarWaybillV1Enum.UNLOADING_POINT,
+                    CarWaybillV1Enum.UNLOADING_WAIT_LEAVE,
+                    CarWaybillV1Enum.UNLOADING_WAIT_RELEASE,
+                    CarWaybillV1Enum.UNLOADING_RELEASED_WAIT_LEAVE
+            )),
 
     UNLOADED(25, "已卸货",
             EnumSet.of(

+ 12 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/vo/WaybillOrderDetailResp.java

@@ -159,6 +159,18 @@ public class WaybillOrderDetailResp implements Serializable {
     @Schema(description = "毛重")
     private BigDecimal grossAmount;
 
+    /**
+     * 皮重
+     */
+    @Schema(description = "卸货皮重")
+    private BigDecimal unloadingTareAmount;
+
+    /**
+     * 毛重
+     */
+    @Schema(description = "卸货毛重")
+    private BigDecimal unloadingGrossAmount;
+
     /**
      * 状态
      */

+ 78 - 22
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtWaybillOrderV1Service.java

@@ -4603,6 +4603,18 @@ public class KwtWaybillOrderV1Service {
         resp.setLogisticOrderNo(logOrder.getLOrderNo());
         resp.setPriceType(String.valueOf(logOrder.getBillingMode()));
         resp.setPriceTypeDesc(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), logOrder.getBillingMode()));
+        // 票据信息
+        String shipmentTicketKey = subtask.getWOrderId() + "-" + AddressTypeEnum.SHIPMENT.getCode();
+        KwtWaybillOrderTicket tareAmountTicket = ticketMap.getOrDefault(shipmentTicketKey, new KwtWaybillOrderTicket());
+        resp.setTareAmount(tareAmountTicket.getTareAmount());
+        resp.setGrossAmount(tareAmountTicket.getGrossAmount());
+
+        // 卸货票据信息
+        String unloadShipmentTicketKey = subtask.getWOrderId() + "-" + AddressTypeEnum.TAKE.getCode();
+        KwtWaybillOrderTicket unloadTareAmountTicket = ticketMap.getOrDefault(unloadShipmentTicketKey, new KwtWaybillOrderTicket());
+        resp.setUnloadingTareAmount(unloadTareAmountTicket.getTareAmount());
+        resp.setUnloadingGrossAmount(unloadTareAmountTicket.getGrossAmount());
+
         if (org.apache.commons.lang3.StringUtils.equals(logOrder.getBillingMode(), DictEnum.CHARGING_TYPE_1.getValue())){
             BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(subtask.getLoadAmount()) ?
                     logOrder.getPrice().multiply(subtask.getLoadAmount()) : BigDecimal.ZERO;
@@ -4610,11 +4622,6 @@ public class KwtWaybillOrderV1Service {
                     contractGoodsDto.getPrice().multiply(subtask.getLoadAmount()) : BigDecimal.ZERO;
             resp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString() +"元");
             resp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString()+"元");
-            // 票据信息
-            String shipmentTicketKey = subtask.getWOrderId() + "-" + AddressTypeEnum.SHIPMENT.getCode();
-            KwtWaybillOrderTicket tareAmountTicket = ticketMap.getOrDefault(shipmentTicketKey, new KwtWaybillOrderTicket());
-            resp.setTareAmount(tareAmountTicket.getTareAmount());
-            resp.setGrossAmount(tareAmountTicket.getGrossAmount());
         }else if (org.apache.commons.lang3.StringUtils.equals(logOrder.getBillingMode(), DictEnum.CHARGING_TYPE_2.getValue())){
             BigDecimal actualPrice = Objects.nonNull(logOrder.getPrice()) && Objects.nonNull(subtask.getUnloadAmount()) ?
                     logOrder.getPrice().multiply(subtask.getUnloadAmount()) : BigDecimal.ZERO;
@@ -4623,11 +4630,6 @@ public class KwtWaybillOrderV1Service {
             resp.setActualPrice(actualPrice.setScale(2, RoundingMode.HALF_UP).toPlainString()+"元");
             resp.setActualGoodsPrice(actualGoodsPrice.setScale(2, RoundingMode.HALF_UP).toPlainString()+"元");
 
-            String takeTicketKey = subtask.getWOrderId() + "-" + AddressTypeEnum.TAKE.getCode();
-            KwtWaybillOrderTicket grossAmountTicket = ticketMap.getOrDefault(takeTicketKey, new KwtWaybillOrderTicket());
-            resp.setTareAmount(grossAmountTicket.getTareAmount());
-            resp.setGrossAmount(grossAmountTicket.getGrossAmount());
-
         }
         resp.setTruckNo(billOrder.getTruckNo());
         resp.setCarAxis(truck != null ? truck.getCarAxis() : "");
@@ -5511,9 +5513,7 @@ public class KwtWaybillOrderV1Service {
         // 获取时间节点,并按前端五步序号排序(映射写入 orderStatus / orderStatusName)
         List<WaybillOrderNodeVo.WaybillOrderNode> nodeList = getWaybillOrderNodes(voList);
         log.info("查询运单节点轨迹,时间节点:{}", JSON.toJSONString(nodeList));
-        // 将原始运单状态映射为前端五步时间轴阶段(1-5),并更新节点的状态码和名称
-        applyTimelinePhaseFromWaybillStatus(nodeList);
-        // 对映射后的节点列表按阶段去重,保留每个阶段最早的一条记录
+        // 按前端五步时间轴阶段去重,取满足状态中的最小原始状态对应时间
         nodeList = dedupeWaybillOrderNodesByStatus(nodeList);
         nodeList = nodeList.stream()
                 .sorted(Comparator.comparing(WaybillOrderNodeVo.WaybillOrderNode::getOrderStatus))
@@ -5605,20 +5605,76 @@ public class KwtWaybillOrderV1Service {
             return nodeList;
         }
         return nodeList.stream()
-                .filter(node -> node.getOrderStatus() != null)
-                .collect(Collectors.toMap(
-                        WaybillOrderNodeVo.WaybillOrderNode::getOrderStatus,
-                        Function.identity(),
-                        (a, b) -> {
-                            Date ta = parseWaybillNodeCreateTime(a.getCreateTime());
-                            Date tb = parseWaybillNodeCreateTime(b.getCreateTime());
-                            return !ta.after(tb) ? a : b;
-                        }))
+                .filter(node -> Objects.nonNull(node.getOrderStatus()))
+                .collect(Collectors.groupingBy(node -> WaybillTimelinePhaseEnum.resolve(node.getOrderStatus())
+                        .map(WaybillTimelinePhaseEnum::getPhaseOrder)
+                        .orElse(node.getOrderStatus())))
                 .values()
                 .stream()
+                .map(KwtWaybillOrderV1Service::selectMinStatusEarliestNode)
+                .filter(Objects::nonNull)
                 .collect(Collectors.toList());
     }
 
+    /**
+     * 从同一前端时间轴阶段的节点列表中,筛选出用于展示的单一节点。
+     * <p>
+     * 处理逻辑:
+     * 1. 找出列表中原始状态码(orderStatus)最小的节点集合(通常代表该阶段最早触发的业务状态)。
+     * 2. 在最小状态码的节点中,选取创建时间(createTime)最早的一个节点。
+     * 3. 将选中节点的 orderStatus 和 orderStatusName 映射为前端时间轴所需的阶段序号和阶段名称。
+     * </p>
+     *
+     * @param nodes 属于同一前端展示阶段的运单节点列表
+     * @return 筛选后的单个节点对象,若列表为空或无有效数据则返回 null
+     */
+    private static WaybillOrderNodeVo.WaybillOrderNode selectMinStatusEarliestNode(
+            List<WaybillOrderNodeVo.WaybillOrderNode> nodes) {
+        // 1. 空值校验
+        if (CollectionUtils.isEmpty(nodes)) {
+            log.debug("selectMinStatusEarliestNode: 节点列表为空,返回 null");
+            return null;
+        }
+        
+        // 2. 提取最小原始状态码
+        // 在同一阶段映射下,可能存在多个原始业务状态,取数值最小的作为基准(通常代表初始状态)
+        Integer minStatus = nodes.stream()
+                .map(WaybillOrderNodeVo.WaybillOrderNode::getOrderStatus)
+                .filter(Objects::nonNull)
+                .min(Integer::compareTo)
+                .orElse(null);
+                
+        if (Objects.isNull(minStatus)) {
+            log.warn("selectMinStatusEarliestNode: 无法从节点列表中提取有效的最小状态码,节点数量: {}", nodes.size());
+            return null;
+        }
+        log.debug("selectMinStatusEarliestNode: 提取到最小状态码: {}", minStatus);
+        
+        // 3. 筛选具有最小状态码且创建时间最早的节点
+        WaybillOrderNodeVo.WaybillOrderNode selected = nodes.stream()
+                .filter(node -> Objects.equals(node.getOrderStatus(), minStatus))
+                .min(Comparator.comparing(node -> parseWaybillNodeCreateTime(node.getCreateTime())))
+                .orElse(null);
+                
+        if (Objects.isNull(selected)) {
+            log.warn("selectMinStatusEarliestNode: 状态码为 {} 的节点中未找到有效创建时间的节点", minStatus);
+            return null;
+        }
+        log.debug("selectMinStatusEarliestNode: 选中节点 ID: {}, 状态: {}, 创建时间: {}", 
+                selected.getId(), selected.getOrderStatus(), selected.getCreateTime());
+        
+        // 4. 映射前端时间轴阶段信息
+        // 将原始业务状态转换为前端展示用的阶段序号(phaseOrder)和阶段名称(phaseLabel)
+        WaybillTimelinePhaseEnum.resolve(minStatus).ifPresent(phase -> {
+            log.debug("selectMinStatusEarliestNode: 映射前端阶段,原始状态: {} -> 阶段序号: {}, 阶段名称: {}", 
+                    minStatus, phase.getPhaseOrder(), phase.getPhaseLabel());
+            selected.setOrderStatus(phase.getPhaseOrder());
+            selected.setOrderStatusName(phase.getPhaseLabel());
+        });
+        
+        return selected;
+    }
+
     private static Date parseWaybillNodeCreateTime(String createTime) {
         if (org.apache.commons.lang3.StringUtils.isBlank(createTime)) {
             return new Date(0L);

+ 11 - 5
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/app/WaybillOrderService.java

@@ -17,6 +17,7 @@ import com.sckw.core.model.enums.LogisticsOrderV1Enum;
 import com.sckw.core.model.enums.UnitTypeEnum;
 import com.sckw.core.utils.CollectionUtils;
 import com.sckw.core.utils.DateUtils;
+import com.sckw.core.web.response.BaseResult;
 import com.sckw.core.web.response.result.PageDataResult;
 import com.sckw.fleet.api.RemoteFleetService;
 import com.sckw.fleet.api.model.vo.RTruckVo;
@@ -34,7 +35,9 @@ import com.sckw.transport.model.vo.OrderTotalTakeVo;
 import com.sckw.transport.model.vo.StatisticsWaybillResp;
 import com.sckw.transport.repository.*;
 import com.sckw.transport.service.KwtWaybillOrderV1Service;
+import io.swagger.v3.oas.annotations.Operation;
 import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -43,6 +46,8 @@ import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -1034,8 +1039,8 @@ public class WaybillOrderService {
     private static List<StatisticsWaybillResp.OrderBillStatusStatistics> calculateStatusStatistics(List<WaybillOrderStatusResp> waybillOrdertDatas) {
         // 定义状态码聚合规则
         Map<List<String>, String[]> aggregateRules = Map.of(
-                Arrays.asList("1", "5", "10", "11", "12", "13", "14", "15", "16", "17", "18"), new String[]{"1", "进行中"},
-                Arrays.asList("20", "30"), new String[]{"2", "单证审核"},
+                Arrays.asList("1", "5", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"), new String[]{"1", "进行中"},
+                Arrays.asList("23", "30"), new String[]{"2", "单证审核"},
                 Arrays.asList("25", "99"), new String[]{"3", "已完成"}
         );
 
@@ -1246,14 +1251,15 @@ public class WaybillOrderService {
     }
 
     /**
-     * 卸货离场
+     * 卸货过磅
      * @param param
      */
     @Transactional(rollbackFor = Exception.class)
     public void unloadingWeigh(WaybillOrderUnloadingWeighParam param) {
         unloadingWeighHandler.handler(param);
     }
-    
+
+
     /**
      * 卸货离场
      * @param param
@@ -1262,7 +1268,7 @@ public class WaybillOrderService {
     public void unloadingLeaved(WaybillOrderUnLoadingLeaveParam param) {
         unloadingLeavedHandler.handler(param);
     }
-
+    
     /**
      * 卸货
      * @param param

+ 13 - 12
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/dashboard/SubtaskCapacityAnalysisService.java

@@ -21,15 +21,7 @@ import org.springframework.stereotype.Service;
 
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -236,9 +228,18 @@ public class SubtaskCapacityAnalysisService {
         
         // 判断是否为“装卸作业中”
         // 包括:拒绝通行、出场完成、称重通行
-        if (ms == CarWaybillV1Enum.REFUSE_TRAFFIC.getCode()
-                || ms == CarWaybillV1Enum.EXIT_COMPLETED.getCode()
-                || ms == CarWaybillV1Enum.WEIGHT_TRAFFIC.getCode()) {
+        List<Integer> statusList = Arrays.asList(
+                CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),
+                CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
+                CarWaybillV1Enum.EMPTY_WAIT_LEAVE.getCode(),
+                CarWaybillV1Enum.WAIT_LEAVE.getCode(),
+                CarWaybillV1Enum.UNLOADING.getCode(),
+                CarWaybillV1Enum.WAIT_RELEASE.getCode(),
+                CarWaybillV1Enum.REPLENISHING.getCode(),
+                CarWaybillV1Enum.REPLENISH_FINISH.getCode(),
+                CarWaybillV1Enum.RELEASED_NOT_EXITED.getCode()
+        );
+        if (statusList.contains( ms)) {
             log.trace("运单ID: {} 分类为: 装卸作业中 (status={})", wid, ms);
             return CapacityCounts.loadingOne();
         }