package com.zy.acs.manager.core.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.acs.common.hk.state.HkState; import com.zy.acs.common.hk.state.HkStateActionState; import com.zy.acs.common.hk.state.HkStateBatteryState; import com.zy.acs.common.hk.action.type.HkActionType; import com.zy.acs.common.hk.state.type.HkActionStatusType; import com.zy.acs.common.utils.RedisSupport; import com.zy.acs.framework.common.Cools; import com.zy.acs.manager.core.domain.TaskPosDto; import com.zy.acs.manager.manager.entity.Action; import com.zy.acs.manager.manager.entity.Segment; import com.zy.acs.manager.manager.enums.ActionStsType; import com.zy.acs.manager.manager.enums.SegmentStateType; import com.zy.acs.manager.manager.service.ActionService; import com.zy.acs.manager.manager.service.SegmentService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; /** * 海康 VDA state 闭环处理。 * 仅复用现有结算逻辑,不改原有完成订阅逻辑。 */ @Slf4j @Service public class HkOrderStateClosureService { private static final String HK_ORDER_COMPLETE_FLAG = "HK_AGV_ORDER_COMPLETE"; private static final int COMPLETE_MARK_EXPIRE_SECONDS = 7 * 24 * 60 * 60; private final RedisSupport redis = RedisSupport.defaultRedisSupport; @Autowired private ActionService actionService; @Autowired private SegmentService segmentService; @Autowired private MainService mainService; @Transactional public void process(HkState state) { if (state == null || Cools.isEmpty(state.getOrderId())) { return; } syncFinishedActions(state); List segmentList = segmentService.list(new LambdaQueryWrapper() .eq(Segment::getGroupId, state.getOrderId()) .orderByAsc(Segment::getSerial)); if (!isOrderCompleted(state, segmentList)) { return; } settleCompletedOrder(state, segmentList); } private void syncFinishedActions(HkState state) { if (Cools.isEmpty(state.getActionStates())) { return; } Date now = new Date(); String orderId = state.getOrderId(); for (HkStateActionState actionState : state.getActionStates()) { if (actionState == null || actionState.getActionStatus() != HkActionStatusType.FINISHED) { continue; } Long actionId = parseActionId(actionState.getActionId()); if (actionId == null) { continue; } Action action = actionService.getOne(new LambdaQueryWrapper() .eq(Action::getId, actionId) .eq(Action::getGroupId, orderId) .eq(Action::getActionSts, ActionStsType.ISSUED.val()) .last("limit 1")); if (action == null) { continue; } action.setActionSts(ActionStsType.FINISH.val()); action.setEndTime(now); action.setUpdateTime(now); if (!actionService.updateById(action)) { log.error("hk state close action failed, orderId={}, actionId={}", orderId, actionId); } else { log.info("hk state close action success, orderId={}, actionId={}, hkActionId={}", orderId, actionId, actionState.getActionId()); } } } private boolean isOrderCompleted(HkState state, List segmentList) { if (isChargeOrder(segmentList) && isChargeTaskCompleted(state)) { return true; } if (!Cools.isEmpty(state.getNodeStates()) || !Cools.isEmpty(state.getEdgeStates())) { return false; } if (Cools.isEmpty(state.getActionStates())) { return true; } for (HkStateActionState actionState : state.getActionStates()) { if (actionState == null) { continue; } HkActionStatusType status = actionState.getActionStatus(); if (status == null || status == HkActionStatusType.WAITING || status == HkActionStatusType.INITIALIZING || status == HkActionStatusType.RUNNING || status == HkActionStatusType.PAUSED || status == HkActionStatusType.FAILED) { return false; } } return true; } private void settleCompletedOrder(HkState state, List segmentList) { String orderId = state.getOrderId(); String completeKey = buildCompleteKey(state); if (redis.getObject(HK_ORDER_COMPLETE_FLAG, completeKey) != null) { return; } if (Cools.isEmpty(segmentList)) { log.warn("hk state order completed but no segment found, agvNo={}, orderId={}, orderUpdateId={}", state.getSerialNumber(), orderId, state.getOrderUpdateId()); return; } if (!hasReachedOrderTail(state, segmentList)) { // return; } boolean needSettle = segmentList.stream() .anyMatch(segment -> !SegmentStateType.FINISH.toString().equals(segment.getState())); if (!needSettle) { redis.setObject(HK_ORDER_COMPLETE_FLAG, completeKey, Boolean.TRUE, COMPLETE_MARK_EXPIRE_SECONDS); return; } mainService.settleSegmentList(segmentList, orderId); redis.setObject(HK_ORDER_COMPLETE_FLAG, completeKey, Boolean.TRUE, COMPLETE_MARK_EXPIRE_SECONDS); log.info("hk state settle completed order, agvNo={}, orderId={}, orderUpdateId={}", state.getSerialNumber(), orderId, state.getOrderUpdateId()); } private String buildCompleteKey(HkState state) { return state.getSerialNumber() + "_" + state.getOrderId() + "_" + (state.getOrderUpdateId() == null ? "null" : state.getOrderUpdateId()); } private boolean hasReachedOrderTail(HkState state, List segmentList) { Long lastNodeSequenceId = state.getLastNodeSequenceId(); if (lastNodeSequenceId == null) { return false; } long expectedLastNodeSequenceId = segmentList.size() * 2L; return lastNodeSequenceId >= expectedLastNodeSequenceId; } private boolean isChargeOrder(List segmentList) { if (Cools.isEmpty(segmentList)) { return false; } return segmentList.stream() .map(Segment::getPosType) .map(TaskPosDto::queryPosType) .anyMatch(TaskPosDto.PosType.TO_CHARGE::equals); } private boolean isChargeTaskCompleted(HkState state) { HkStateBatteryState batteryState = state.getBatteryState(); if (batteryState != null && Boolean.TRUE.equals(batteryState.getCharging())) { return true; } if (Cools.isEmpty(state.getActionStates())) { return false; } for (HkStateActionState actionState : state.getActionStates()) { if (actionState == null || Cools.isEmpty(actionState.getActionType())) { continue; } if (!HkActionType.START_CHARGING.getCode().equalsIgnoreCase(actionState.getActionType())) { continue; } if (actionState.getActionStatus() == HkActionStatusType.FINISHED) { return true; } } return false; } private Long parseActionId(String hkActionId) { if (Cools.isEmpty(hkActionId) || hkActionId.length() < 2) { return null; } if (hkActionId.charAt(0) != 'A' && hkActionId.charAt(0) != 'a') { return null; } try { return Long.parseLong(hkActionId.substring(1)); } catch (NumberFormatException e) { log.warn("parse hk action id failed, hkActionId={}", hkActionId); return null; } } }