|  |  |  | 
|---|
|  |  |  | import com.alibaba.fastjson.JSON; | 
|---|
|  |  |  | import com.alibaba.fastjson.JSONObject; | 
|---|
|  |  |  | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 
|---|
|  |  |  | import com.zy.acs.framework.common.Cools; | 
|---|
|  |  |  | import com.zy.acs.framework.common.SnowflakeIdWorker; | 
|---|
|  |  |  | import com.zy.acs.framework.exception.CoolException; | 
|---|
|  |  |  | import com.zy.acs.common.domain.AgvAction; | 
|---|
|  |  |  | import com.zy.acs.common.domain.AgvActionItem; | 
|---|
|  |  |  | import com.zy.acs.common.domain.AgvProtocol; | 
|---|
|  |  |  | 
|---|
|  |  |  | import com.zy.acs.common.domain.protocol.AGV_70_UP; | 
|---|
|  |  |  | import com.zy.acs.common.domain.protocol.IMessageBody; | 
|---|
|  |  |  | import com.zy.acs.common.domain.protocol.action.*; | 
|---|
|  |  |  | import com.zy.acs.common.enums.*; | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvBackpackType; | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvCompleteType; | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvDirectionType; | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvSpeedType; | 
|---|
|  |  |  | import com.zy.acs.common.utils.GsonUtils; | 
|---|
|  |  |  | import com.zy.acs.common.utils.Utils; | 
|---|
|  |  |  | import com.zy.acs.framework.common.Cools; | 
|---|
|  |  |  | import com.zy.acs.framework.common.SnowflakeIdWorker; | 
|---|
|  |  |  | import com.zy.acs.framework.exception.CoolException; | 
|---|
|  |  |  | import com.zy.acs.manager.common.domain.TaskDto; | 
|---|
|  |  |  | import com.zy.acs.manager.common.domain.param.HandlerPublishParam; | 
|---|
|  |  |  | import com.zy.acs.manager.common.exception.BusinessException; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.AgvBackpackDto; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.Lane; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.TaskPosDto; | 
|---|
|  |  |  | import com.zy.acs.manager.core.service.astart.MapDataDispatcher; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam; | 
|---|
|  |  |  | 
|---|
|  |  |  | import lombok.extern.slf4j.Slf4j; | 
|---|
|  |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
|---|
|  |  |  | import org.springframework.stereotype.Component; | 
|---|
|  |  |  | import org.springframework.transaction.annotation.Propagation; | 
|---|
|  |  |  | import org.springframework.transaction.annotation.Transactional; | 
|---|
|  |  |  | import org.springframework.transaction.interceptor.TransactionAspectSupport; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.util.*; | 
|---|
|  |  |  | import java.util.concurrent.TimeUnit; | 
|---|
|  |  |  | import java.util.concurrent.locks.ReentrantLock; | 
|---|
|  |  |  | import java.util.stream.Collectors; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | 
|---|
|  |  |  | @Slf4j | 
|---|
|  |  |  | @Component("mainService") | 
|---|
|  |  |  | public class MainService { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final int LOCK_TIMEOUT = 5; | 
|---|
|  |  |  | private final ReentrantLock lock = new ReentrantLock(Boolean.TRUE); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private BusService busService; | 
|---|
|  |  |  | 
|---|
|  |  |  | private ConfigService configService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private ValidService validService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private AllocateService allocateService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private CodeService codeService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private AgvModelService agvModelService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private MissionAssignService missionAssignService; | 
|---|
|  |  |  | private LaneService laneService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @SuppressWarnings("all") | 
|---|
|  |  |  | @Transactional | 
|---|
|  |  |  | 
|---|
|  |  |  | taskDtoList.sort((o1, o2) -> o2.getPriority() - o1.getPriority()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 校验 | 
|---|
|  |  |  | List<Task> taskList = validService.validBusDto(taskDtoList); | 
|---|
|  |  |  | List<Task> taskList = validService.validTaskDtoList(taskDtoList); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 保存总线 | 
|---|
|  |  |  | Date now = new Date(); | 
|---|
|  |  |  | 
|---|
|  |  |  | * 任务分配给车辆 ( 车辆此时是空闲且静止的 ) | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Transactional | 
|---|
|  |  |  | public synchronized void infuseAgvForTask(Bus bus) { | 
|---|
|  |  |  | public synchronized void allocateTask(Bus bus) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | Date now = new Date(); | 
|---|
|  |  |  | List<Task> taskList = taskService.list(new LambdaQueryWrapper<Task>() | 
|---|
|  |  |  | 
|---|
|  |  |  | bus.setBusSts(BusStsType.PROGRESS.val()); | 
|---|
|  |  |  | bus.setUpdateTime(now); | 
|---|
|  |  |  | if (!busService.updateById(bus)) { | 
|---|
|  |  |  | log.error("Bus [{}] 更新失败 !!!", bus.getUuid()); | 
|---|
|  |  |  | log.error("Bus [{}] failed to Update !!!", bus.getUuid()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | List<Long> taskIds = taskList.stream().map(Task::getId).distinct().collect(Collectors.toList()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Map<String, List<Long>> taskAllot = new HashMap<>(); | 
|---|
|  |  |  | List<Long> taskIds = taskList.stream().map(Task::getId).distinct().collect(Collectors.toList()); | 
|---|
|  |  |  | for (Task task : taskList) { | 
|---|
|  |  |  | Agv agv = missionAssignService.execute(task, taskAllot, taskIds); | 
|---|
|  |  |  | Agv agv = allocateService.execute(task); | 
|---|
|  |  |  | if (null == agv) { | 
|---|
|  |  |  | log.warn("{}任务异常,无法检索空闲Agv...", task.getSeqNum()); | 
|---|
|  |  |  | //                    log.warn("Task[{}] has an issue, because it failed to checkout agv which is idle...", task.getSeqNum()); | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | task.setAgvId(agv.getId()); | 
|---|
|  |  |  | task.setTaskSts(TaskStsType.WAITING.val()); | 
|---|
|  |  |  | task.setIoTime(now); | 
|---|
|  |  |  | task.setUpdateTime(now); | 
|---|
|  |  |  | if (!taskService.updateById(task)) { | 
|---|
|  |  |  | throw new BusinessException(task.getSeqNum() + "任务更新失败"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (taskAllot.containsKey(agv.getUuid())) { | 
|---|
|  |  |  | taskAllot.get(agv.getUuid()).add(task.getId()); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | taskAllot.put(agv.getUuid(), Utils.singletonList(task.getId())); | 
|---|
|  |  |  | throw new BusinessException("seqNum: " + task.getSeqNum() + " failed to update"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //            bus.setUpdateTime(now); | 
|---|
|  |  |  | //            if (!busService.updateById(bus)) { | 
|---|
|  |  |  | //                throw new BusinessException(bus.getSeqNum() + "总线更新失败"); | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("mainService.infuseAgvForTask", e); | 
|---|
|  |  |  | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 解析取放货集合任务,进行最优的排列组合顺序 ( 车辆此时是空闲且静止的 ) | 
|---|
|  |  |  | * todo: {@link com.zy.acs.manager.core.HandlerController#controlAgv(String, HandlerPublishParam)} | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Transactional | 
|---|
|  |  |  | public synchronized void mergeMajorTask(Long agvId, List<Task> taskList) { | 
|---|
|  |  |  | if (Cools.isEmpty(taskList)) { return; } | 
|---|
|  |  |  | boolean lockAcquired = false; | 
|---|
|  |  |  | @Transactional(propagation = Propagation.REQUIRES_NEW) | 
|---|
|  |  |  | public void buildMajorTask(Long agvId, List<Task> taskList) { | 
|---|
|  |  |  | if (Cools.isEmpty(agvId, taskList)) { return; } | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (!(lockAcquired = this.lock.tryLock(LOCK_TIMEOUT, TimeUnit.SECONDS))) { | 
|---|
|  |  |  | throw new CoolException("generate [task] action fail, cause can not acquire lock ..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | Date now = new Date(); | 
|---|
|  |  |  | final String sameGroupXy = configService.getVal( "sameGroupXy", String.class); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // valid ----------------------------------------------- | 
|---|
|  |  |  | Agv agv = agvService.getById(agvId); | 
|---|
|  |  |  | if (!agvService.judgeEnable(agv.getId(), agvDetail -> agvDetail.getVol() > agv.getChargeLine())) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]当前不可用..."); | 
|---|
|  |  |  | if (!agvService.judgeEnable(agv.getId(), true)) { | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | //                throw new CoolException("AGV[" + agv.getUuid() + "]当前不可用..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!Cools.isEmpty(taskService.selectInSts(agvId, TaskStsType.ASSIGN, TaskStsType.PROGRESS))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]分配任务失败,已存在执行任务..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | AgvDetail agvDetail = agvDetailService.selectByAgvId(agvId); | 
|---|
|  |  |  | assert agvDetail != null; | 
|---|
|  |  |  | if (agvDetail.getPos() == 0) { | 
|---|
|  |  |  | if (!agvDetail.getAgvStatus().equals(AgvStatusType.CHARGE)) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]当前不在定位..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString())) | 
|---|
|  |  |  | || !Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "] failed to assign,because already has the segment in running..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // execute ---------------------------------------------------- | 
|---|
|  |  |  | Date now = new Date(); | 
|---|
|  |  |  | // sort and sub | 
|---|
|  |  |  | taskList.sort(new Comparator<Task>() { | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public int compare(Task o1, Task o2) { | 
|---|
|  |  |  | return 0; | 
|---|
|  |  |  | return o2.getPriority() - o1.getPriority(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | Integer backpack = agvService.getBackpack(agv); | 
|---|
|  |  |  | 
|---|
|  |  |  | taskList = taskList.subList(0, backpack); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | AgvDetail agvDetail = agvDetailService.selectByAgvId(agvId); | 
|---|
|  |  |  | List<AgvBackpackDto> backpackDtoList = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * single agvId | 
|---|
|  |  |  | * 同巷道归类 | 
|---|
|  |  |  | * same lane for every single agvId | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: y + TaskPosDto.PosType.ORI_LOC / ORI_STA / DEST_LOC / DEST_STA | 
|---|
|  |  |  | * key: y(val) + TaskPosDto.PosType.ORI_LOC / ORI_STA / DEST_LOC / DEST_STA | 
|---|
|  |  |  | * val: new TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType) | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | Map<String, List<TaskPosDto>> groups = new HashMap<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<AgvBackpackDto> backpackDtoList = new ArrayList<>(); | 
|---|
|  |  |  | final String sameGroupXy = configService.getVal( "sameGroupXy", String.class); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int backpackLev = 0; | 
|---|
|  |  |  | for (Task task : taskList) { | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | *  List<TaskPosDto>: task list on the same channel | 
|---|
|  |  |  | * 1.Map<String, List<TaskPosDto>> groups | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 1000 + ORIGIN | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 3000 + ORIGIN | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 2000 + ORIGIN | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 1000 + DESTINATION | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 2000 + DESTINATION | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * ...... | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * 2.ArrayList<List<TaskPosDto>> list | 
|---|
|  |  |  | * [ | 
|---|
|  |  |  | *  [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...], | 
|---|
|  |  |  | *  [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...], | 
|---|
|  |  |  | *  [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...], | 
|---|
|  |  |  | *  ...... | 
|---|
|  |  |  | * ] | 
|---|
|  |  |  | */ | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 对所有巷道进行有序排序,先是针对List为一个单位,对他们进行FirstWeight排序,相当于表1的key的数值进行有序排序 | 
|---|
|  |  |  | *  List<TaskPosDto>: task list on the same lane | 
|---|
|  |  |  | *  ArrayList<List<TaskPosDto>>: all the task list by one agv | 
|---|
|  |  |  | * | 
|---|
|  |  |  | *  tip: ORI 和 DEST 永远不会存在同一个 List | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | ArrayList<List<TaskPosDto>> list = new ArrayList<>(groups.values()); | 
|---|
|  |  |  | list.sort((o1, o2) -> { | 
|---|
|  |  |  | 
|---|
|  |  |  | double o2CompVal = (o2.get(0).getFirstWeight(sameGroupXy) * 100) + o2.get(0).getPosType().compOffset; | 
|---|
|  |  |  | return (int) (o1CompVal - o2CompVal); | 
|---|
|  |  |  | }); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 针对Dto,按照SecondWeight进行排序 | 
|---|
|  |  |  | for (List<TaskPosDto> taskPosDtoList : list) { | 
|---|
|  |  |  | taskPosDtoList.sort((o1, o2) -> (int) (o1.getSecondWeight(sameGroupXy) * 100 - o2.getSecondWeight(sameGroupXy) * 100)); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // re-order by agv current position | 
|---|
|  |  |  | Code currCode = codeService.getById(agvDetail.getRecentCode()); | 
|---|
|  |  |  | Double[] currPosition = new Double[] {currCode.getX(), currCode.getY()}; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<List<TaskPosDto>> pickGroups = new ArrayList<>(); | 
|---|
|  |  |  | List<List<TaskPosDto>> dropGroups = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (List<TaskPosDto> group : list) { | 
|---|
|  |  |  | // Assume 一个任务组中所有TaskPosDto的PosType.brief相同 | 
|---|
|  |  |  | TaskPosDto.PosType posType = group.get(0).getPosType(); | 
|---|
|  |  |  | if (posType == TaskPosDto.PosType.ORI_LOC || posType == TaskPosDto.PosType.ORI_STA) { | 
|---|
|  |  |  | pickGroups.add(group); | 
|---|
|  |  |  | } else if (posType == TaskPosDto.PosType.DEST_LOC || posType == TaskPosDto.PosType.DEST_STA) { | 
|---|
|  |  |  | dropGroups.add(group); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | // import tip: the list must only contain ORIGIN and DESTINATION | 
|---|
|  |  |  | log.error("the list must only contain ORIGIN and DESTINATION"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | currPosition = allocateService.pac(currPosition, pickGroups); | 
|---|
|  |  |  | currPosition = allocateService.pac(currPosition, dropGroups); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<List<TaskPosDto>> reorderedList = new ArrayList<>(); | 
|---|
|  |  |  | reorderedList.addAll(pickGroups); | 
|---|
|  |  |  | reorderedList.addAll(dropGroups); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | list.clear(); | 
|---|
|  |  |  | list.addAll(reorderedList); | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // generate travel | 
|---|
|  |  |  | Travel travel = new Travel(); | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | log.error("mainService.mergeMajorTask[task]", e); | 
|---|
|  |  |  | log.error("mainService.buildMajorTask[task]", e); | 
|---|
|  |  |  | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); | 
|---|
|  |  |  | } finally { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (lockAcquired) { | 
|---|
|  |  |  | this.lock.unlock(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 充电 回待机位任务 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Transactional | 
|---|
|  |  |  | public synchronized boolean buildMinorTask(Agv agv, AgvDetail agvDetail, TaskTypeType taskType, String destination) { | 
|---|
|  |  |  | @Transactional(propagation = Propagation.REQUIRES_NEW) // although there is a Transactional here that the lock is isolated, but we can't join the caller's Transactional | 
|---|
|  |  |  | public boolean buildMinorTask(Agv agv, TaskTypeType taskType, String destination, Jam jam) { | 
|---|
|  |  |  | if (Cools.isEmpty(agv, taskType)) { return false; } | 
|---|
|  |  |  | boolean lockAcquired = false; | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (!(lockAcquired = this.lock.tryLock(LOCK_TIMEOUT, TimeUnit.SECONDS))) { | 
|---|
|  |  |  | throw new CoolException("generate [task] action fail, cause can not acquire lock ..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (null == agvDetail) { | 
|---|
|  |  |  | agvDetail = agvDetailService.selectByAgvId(agv.getId()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId()); | 
|---|
|  |  |  | if (!agvService.judgeEnable(agv.getId())) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(taskService.selectInSts(agv.getId(), TaskStsType.ASSIGN, TaskStsType.PROGRESS))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "] failed to assign,because already has the task in running..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString())) | 
|---|
|  |  |  | || !Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "] failed to assign,because already has the segment in running..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Date now = new Date(); | 
|---|
|  |  |  | 
|---|
|  |  |  | switch (taskType) { | 
|---|
|  |  |  | case TO_CHARGE: | 
|---|
|  |  |  | case TO_STANDBY: | 
|---|
|  |  |  | List<FuncSta> funcStaList = funcStaService.list(new LambdaQueryWrapper<FuncSta>() | 
|---|
|  |  |  | .eq(FuncSta::getType, FuncStaType.query(taskType).toString()) | 
|---|
|  |  |  | .eq(FuncSta::getAgvId, agv.getId()) | 
|---|
|  |  |  | .eq(FuncSta::getState, FuncStaStateType.IDLE.toString()) | 
|---|
|  |  |  | .eq(FuncSta::getStatus, StatusType.ENABLE.val) | 
|---|
|  |  |  | ); | 
|---|
|  |  |  | if (!Cools.isEmpty(funcStaList)) { | 
|---|
|  |  |  | FuncSta funcSta = funcStaList.get(0); | 
|---|
|  |  |  | List<FuncSta> idleFunStaList = funcStaService.findInIdleStatus(FuncStaType.query(taskType), agv.getId()); | 
|---|
|  |  |  | if (!Cools.isEmpty(idleFunStaList)) { | 
|---|
|  |  |  | FuncSta funcSta = funcStaService.checkoutClosestFunSta(agvDetail.getRecentCode(), idleFunStaList); | 
|---|
|  |  |  | endCode = codeService.getById(funcSta.getCode()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (null == endCode) { | 
|---|
|  |  |  | log.warn("AGV[{}] failed to search destination,there hadn't any idle funSta,TaskTypeType:{}", agv.getUuid(), taskType.toString()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | break; | 
|---|
|  |  |  | case MOVE: | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (null == endCode) { | 
|---|
|  |  |  | log.error("{}号车辆建立功能任务失败,无法检索到目标定位,TaskTypeType:{}", agv.getUuid(), taskType.toString()); | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!allocateService.validCapacityOfLane(agv, endCode)) { | 
|---|
|  |  |  | throw new BusinessException("the lane with code:" + endCode.getData() + " is full of AGV[" + agv.getUuid() + "]!!!"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Task task = new Task(); | 
|---|
|  |  |  | 
|---|
|  |  |  | task.setSeqNum(Utils.generateSeqNum(Cools.isEmpty(lastTasks)?null:lastTasks.get(0).getSeqNum())); | 
|---|
|  |  |  | task.setOriCode(agvDetail.getCode()); | 
|---|
|  |  |  | task.setDestCode(endCode.getId()); | 
|---|
|  |  |  | // lane | 
|---|
|  |  |  | Lane destLane = laneService.search(endCode.getData()); | 
|---|
|  |  |  | if (null != destLane) { | 
|---|
|  |  |  | task.setDestLaneHash(destLane.getHashCode()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | task.setPriority(taskType.equals(TaskTypeType.TO_CHARGE)?2:1); | 
|---|
|  |  |  | task.setTaskSts(TaskStsType.ASSIGN.val()); | 
|---|
|  |  |  | task.setTaskType(taskType.val()); | 
|---|
|  |  |  | task.setIoTime(now); | 
|---|
|  |  |  | task.setStartTime(now); | 
|---|
|  |  |  | if (!taskService.save(task)) { | 
|---|
|  |  |  | throw new BusinessException(task.getSeqNum() + "任务保存失败"); | 
|---|
|  |  |  | throw new BusinessException(task.getSeqNum() + " failed to save"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // generate travel | 
|---|
|  |  |  | 
|---|
|  |  |  | travel.setTravelId(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); | 
|---|
|  |  |  | travel.setAgvId(agv.getId()); | 
|---|
|  |  |  | //            travel.setTaskContent(JSON.toJSONString(list)); | 
|---|
|  |  |  | travel.setTaskIds(JSON.toJSONString(Collections.singletonList(task.getId()))); | 
|---|
|  |  |  | travel.setTaskIds(GsonUtils.toJson(Utils.singletonList(task.getId()))); | 
|---|
|  |  |  | travel.setState(TravelStateType.RUNNING.toString()); | 
|---|
|  |  |  | if (!travelService.save(travel)) { | 
|---|
|  |  |  | throw new BusinessException("任务组保存失败"); | 
|---|
|  |  |  | throw new BusinessException("travel failed to save"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // generate segment | 
|---|
|  |  |  | 
|---|
|  |  |  | next.setState(SegmentStateType.WAITING.toString()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!segmentService.save(next)) { | 
|---|
|  |  |  | throw new BusinessException("任务组保存失败"); | 
|---|
|  |  |  | throw new BusinessException("segment failed to save"); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | if (null != jam && i == 0) { | 
|---|
|  |  |  | jam.setAvoSeg(next.getId()); | 
|---|
|  |  |  | jam.setAvoCode(endCode.getId()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | destFuncSta.setState(FuncStaStateType.OCCUPIED.toString()); | 
|---|
|  |  |  | destFuncSta.setUpdateTime(now); | 
|---|
|  |  |  | if (!funcStaService.updateById(destFuncSta)) { | 
|---|
|  |  |  | log.error("FuncSta [{}] 更新状态失败 !!!", destFuncSta.getName()); | 
|---|
|  |  |  | log.error("FuncSta [{}] failed to update !!!", destFuncSta.getName()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | break; | 
|---|
|  |  |  | case MOVE: | 
|---|
|  |  |  | 
|---|
|  |  |  | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } finally { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (lockAcquired) { | 
|---|
|  |  |  | this.lock.unlock(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | AgvDetail agvDetail = agvDetailService.selectByAgvId(agvId); | 
|---|
|  |  |  | assert agvDetail != null; | 
|---|
|  |  |  | if (agvDetail.getPos() == 0) { | 
|---|
|  |  |  | if (!agvDetail.getAgvStatus().equals(AgvStatusType.CHARGE)) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]当前不在定位..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<Action> actionList = new ArrayList<>(); | 
|---|
|  |  |  | // start node | 
|---|
|  |  |  | Code lastCode = codeService.getById(agvDetail.getRecentCode()); | 
|---|
|  |  |  | Double lastDirection = agvDetail.getAgvAngle(); | 
|---|
|  |  |  | if (!lastCode.getData().equals(pathList.get(0))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]定位偏移..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Double lastDirection = agvDetail.getAgvAngle(); | 
|---|
|  |  |  | boolean first = true; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (Segment segment : segmentList) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 分段所属的Task | 
|---|
|  |  |  | 
|---|
|  |  |  | break; | 
|---|
|  |  |  | case TO_CHARGE: | 
|---|
|  |  |  | // 检验方向 | 
|---|
|  |  |  | FuncSta chargeFuncSta = funcStaService.query(agvId, lastCode.getId(), FuncStaType.CHARGE.toString()); | 
|---|
|  |  |  | FuncSta chargeFuncSta = funcStaService.query(lastCode.getId(), FuncStaType.CHARGE.toString()); | 
|---|
|  |  |  | Double chargeDirection = Double.parseDouble(chargeFuncSta.getAngle()); | 
|---|
|  |  |  | if (!lastDirection.equals(chargeDirection)) { | 
|---|
|  |  |  | actionList.add(new Action( | 
|---|
|  |  |  | 
|---|
|  |  |  | for (Action action : actionList) { | 
|---|
|  |  |  | action.setActionSts(ActionStsType.ISSUED.val()); | 
|---|
|  |  |  | action.setStartTime(now); | 
|---|
|  |  |  | action.setIoTime(now); | 
|---|
|  |  |  | action.setUpdateTime(now); | 
|---|
|  |  |  | if (!actionService.updateById(action)) { | 
|---|
|  |  |  | throw new BusinessException(action.getPriority() + " - " + action.getName() + "动作更新失败"); | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // segment call back | 
|---|
|  |  |  | trafficService.callback(segmentList); | 
|---|
|  |  |  | segmentService.processNext(segmentList); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | log.info("Agv [{}] {}作业完毕 ==========>> ", protocol.getAgvNo(), serialNo); | 
|---|
|  |  |  |  | 
|---|