huang
2025-10-20 23f026fbfd81066b1f2e9662bbeff31965dda4d6
hangzhoumesParent/moduleService/GlassStorageModule/src/main/java/com/mes/job/RawGlassTask.java
@@ -3,15 +3,22 @@
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.kangaroohy.milo.model.ReadWriteEntity;
import com.kangaroohy.milo.service.MiloService;
import com.mes.common.config.Const;
import com.mes.engineering.entity.Engineering;
import com.mes.engineering.mapper.EngineeringMapper;
import com.mes.opctask.entity.LoadGlassDeviceTask;
import com.mes.opctask.service.LoadGlassDeviceTaskService;
import com.mes.rawglassdetails.entity.RawGlassStorageDetails;
import com.mes.rawglassdetails.service.RawGlassStorageDetailsService;
import com.mes.rawglassstation.entity.RawGlassStorageStation;
import com.mes.rawglassstation.service.RawGlassStorageStationService;
import com.mes.rawglasstask.entity.RawGlassStorageTask;
import com.mes.rawglasstask.service.RawGlassStorageTaskService;
import com.mes.s7.entity.S7Data;
import com.mes.uppattenusage.entity.UpPattenUsage;
import com.mes.uppattenusage.entity.vo.UpPattenUsageVO;
import com.mes.uppattenusage.mapper.UpPattenUsageMapper;
import lombok.extern.slf4j.Slf4j;
@@ -38,46 +45,81 @@
    @Autowired
    private RawGlassStorageTaskService rawGlassStorageTaskService;
    @Autowired
    private RawGlassStorageStationService rawGlassStorageStationService;
    @Resource
    private EngineeringMapper engineeringMapper;
    @Resource
    private UpPattenUsageMapper upPattenUsageMapper;
    @Resource
    private LoadGlassDeviceTaskService loadGlassDeviceTaskService;
    @Autowired(required = false)
    private MiloService miloService;
    private static final List<Integer> LIFTING_STATION = Arrays.asList(4);
    private static final List<String> LOAD_STATION_01 = Arrays.asList("101", "102");
    private static final List<String> LOAD_STATION_02 = Arrays.asList("103", "104");
    private static final List<Integer> LOAD_STATION_MAX = Arrays.asList(102, 104);
    private static final Integer LEFTING_01 = 98;
    private static final Integer LEFTING_02 = 99;
    private static final Integer LOAD_GLASS_01_01 = 101;
    private static final Integer LOAD_GLASS_01_02 = 102;
    private static final Integer LOAD_GLASS_02_01 = 103;
    private static final Integer LOAD_GLASS_02_02 = 104;
    @Autowired(required = false)
    S7Serializer s7Serializer;
    private static final String LOAD_GLASS_DEVICE_ONE_TASK = "load_glass_device_one_task";
    private static final String LOAD_GLASS_DEVICE_TWO_TASK = "load_glass_device_two_task";
    private static final List<Integer> LOAD_STATION_01 = Collections.singletonList(101);
//    private static final List<Integer> LOAD_STATION_02 = Arrays.asList(103, 104);
//    private static final List<Integer> LOAD_STATION_ALL = Arrays.asList(101, 102, 103, 104);
    private static final Integer LEFTING_01 = 99;
//    private static final Integer LEFTING_02 = 99;
    private static final Integer LOAD_GLASS_ONE_DEVICE = 5;
    private static final Integer LOAD_GLASS_TWO_DEVICE = 6;
    @Scheduled(fixedDelay = 1000)
    public void rawStorageTask() throws Exception {
        ReadWriteEntity requestWord = miloService.readFromOpcUa("A01-CC.dev.request");
        ReadWriteEntity confireWord = miloService.readFromOpcUa("A01-CC.dev.confirmationWord");
        ReadWriteEntity reportWord = miloService.readFromOpcUa("A01-CC.dev.reportWord");
        ReadWriteEntity taskWord = miloService.readFromOpcUa("A01-CC.dev.taskWord");
        String requestValue = requestWord.getValue() + "";
        S7Data S7DataWL1 = s7Serializer.read(S7Data.class);
//        S7Data S7DataWL1 = new S7Data();
//        S7DataWL1.setRequest((short) 1);
//        S7DataWL1.setConfirmation((short) 0);
//        S7DataWL1.setReportWord((short) 0);
//        S7DataWL1.setTaskWord((short) 0);
//        String requestWord = S7DataWL1.getRequest().toString();
//        String confireWord = S7DataWL1.getConfirmation().toString();
//        String reportWord = S7DataWL1.getReportWord().toString();
//        String taskWord = S7DataWL1.getTaskWord().toString();
        String requestWord = S7DataWL1.getRequest().toString();
        String confireWord = S7DataWL1.getConfirmation().toString();
        String reportWord = S7DataWL1.getReportWord().toString();
        String taskWord = S7DataWL1.getTaskWord().toString();
        String requestValue = requestWord;
//        ReadWriteEntity requestWord = miloService.readFromOpcUa("CC.CC.request");
//        ReadWriteEntity confireWord = miloService.readFromOpcUa("CC.CC.confirmation");
//        ReadWriteEntity reportWord = miloService.readFromOpcUa("CC.CC.reportWord");
//        ReadWriteEntity taskWord = miloService.readFromOpcUa("CC.CC.taskWord");
//        String requestValue = requestWord.getValue() + "";
        if ("0".equals(requestValue)) {
            if ("1".equals(confireWord.getValue() + "") && "0".equals(reportWord.getValue() + "")) {
                List<ReadWriteEntity> list = new ArrayList<>();
                list.add(generateReadWriteEntity("A01-CC.dev.confirmationWord", 0));
                miloService.writeToOpcWord(list);
            if ("1".equals(confireWord) && "0".equals(reportWord)) {
//            if ("1".equals(confireWord.getValue() + "") && "0".equals(reportWord.getValue() + "")) {
                S7Data s7Data = new S7Data();
                s7Data.setConfirmation((short) 0);
                s7Serializer.write(s7Data);
//                List<ReadWriteEntity> list = new ArrayList<>();
//                list.add(generateReadWriteEntity("CC.CC.confirmation", 0));
//                miloService.writeToOpcWord(list);
            }
            if ("1".equals(taskWord.getValue() + "")) {
                List<ReadWriteEntity> list = new ArrayList<>();
                list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 0));
//                list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 0));
                list.add(generateReadWriteEntity("A01-CC.dev.startSlot", 0));
                list.add(generateReadWriteEntity("A01-CC.dev.endSlot", 0));
                miloService.writeToOpcWord(list);
            if ("1".equals(taskWord)) {
//          if ("1".equals(taskWord.getValue() + "")) {
                S7Data s7Data = new S7Data();
                s7Data.setTaskWord((short) 0);
                s7Data.setStartSlot((short) 0);
                s7Data.setEndSlot((short) 0);
                s7Serializer.write(s7Data);
//                List<ReadWriteEntity> list = new ArrayList<>();
//                list.add(generateReadWriteEntity("CC.CC.taskWord", 0));
//                list.add(generateReadWriteEntity("CC.CC.startSlot", 0));
//                list.add(generateReadWriteEntity("CC.CC.endSlot", 0));
//                miloService.writeToOpcWord(list);
            }
            return;
        }
@@ -97,14 +139,19 @@
            log.info("执行调度任务,结束");
            return;
        }
        flag = outboundTask();
        flag = inboundRequestTask();
        if (flag) {
            log.info("执行出库任务,结束");
            log.info("执行吊装位请求任务");
            return;
        }
        flag = warehouseTask();
        if (flag) {
            log.info("执行入库任务");
            log.info("执行回库任务");
            return;
        }
        flag = outboundTask();
        if (flag) {
            log.info("执行出库任务,结束");
            return;
        }
        log.info("无任务执行,结束");
@@ -112,8 +159,12 @@
    @Scheduled(fixedDelay = 1000)
    public void rawStorageInCar() throws Exception {
        ReadWriteEntity entity = miloService.readFromOpcUa("A01-CC.dev.inCar");
        String value = entity.getValue() + "";
        S7Data S7DataWL1 = s7Serializer.read(S7Data.class);
//        S7Data S7DataWL1 = new S7Data();
//        S7DataWL1.setInCar((short) 1);
        String value = S7DataWL1.getInCar().toString();
//        ReadWriteEntity entity = miloService.readFromOpcUa("CC.CC.inCar");
//        String value = entity.getValue() + "";
        if (!"1".equals(value)) {
            log.info("大车上没有架子");
            return;
@@ -127,13 +178,16 @@
        }
        rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>().eq(RawGlassStorageDetails::getId, one.getId())
                .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_CAR));
    }
    @Scheduled(fixedDelay = 1000)
    public void rawStorageFinish() throws Exception {
        ReadWriteEntity entity = miloService.readFromOpcUa("A01-CC.dev.reportWord");
        String value = entity.getValue() + "";
        S7Data S7DataWL1 = s7Serializer.read(S7Data.class);
//        S7Data S7DataWL1 = new S7Data();
//        S7DataWL1.setReportWord((short) 1);
        String value = S7DataWL1.getReportWord().toString();
//        ReadWriteEntity entity = miloService.readFromOpcUa("CC.CC.reportWord");
//        String value = entity.getValue() + "";
        if ("0".equals(value)) {
            log.info("当前任务未汇报,结束本次任务");
            return;
@@ -145,8 +199,9 @@
            return;
        }
        RawGlassStorageTask task = rawGlassStorageTaskService.getOne(new LambdaQueryWrapper<RawGlassStorageTask>()
                .in(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW));
        RawGlassStorageDetails targetDetails = generateDetails(details, task.getEndSlot());
                .in(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING, Const.RAW_GLASS_TASK_NEW));
        RawGlassStorageDetails targetDetails = rawGlassStorageDetailsService.generateDetails(details, task.getEndSlot());
        int deviceId = details.getDeviceId();
        Integer taskType = task.getTaskType();
        if ("1".equals(value)) {
            log.info("将详情表的状态改为已出库");
@@ -155,10 +210,11 @@
                    .eq(RawGlassStorageDetails::getSlot, task.getStartSlot()).eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_CAR));
            log.info("任务状态已更改为:已完成");
            rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                    .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                    .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING)
                    .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_SUCCESS));
            switch (taskType) {
                case 1:
                case 3:
                    log.info("1、入库,3、调度任务。{}", taskType);
                    if (targetDetails.getRemainQuantity() > 0) {
                        rawGlassStorageDetailsService.save(targetDetails);
@@ -166,9 +222,10 @@
                    break;
                case 2:
                case 4:
                    log.info("2、出片,4、入库请求。{}", taskType);
                    log.info("2、出片,4、吊装位请求。{}", taskType);
                    targetDetails = new RawGlassStorageDetails();
                    targetDetails.setSlot(task.getEndSlot());
                    targetDetails.setDeviceId(deviceId);
                    targetDetails.setShelf(task.getStartSlot());
                    targetDetails.setState(Const.RAW_GLASS_STATE_IN);
                    rawGlassStorageDetailsService.save(targetDetails);
@@ -189,18 +246,18 @@
                        .in(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING, Const.RAW_GLASS_STATE_CAR));
            }
            rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                    .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                    .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING)
                    .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_FAILURE));
        }
        List<ReadWriteEntity> list = new ArrayList<>();
        list.add(generateReadWriteEntity("A01-CC.dev.confirmationWord", 1));
        miloService.writeToOpcWord(list);
        S7Data s7Data = new S7Data();
        s7Data.setConfirmation((short) 1);
        s7Serializer.write(s7Data);
    }
    private boolean isHasRunningTask() {
        RawGlassStorageTask task = rawGlassStorageTaskService.getOne(new LambdaQueryWrapper<RawGlassStorageTask>()
                .in(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW));
                .in(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING));
        return task == null ? Boolean.FALSE : Boolean.TRUE;
    }
@@ -223,47 +280,163 @@
        }
        return Boolean.FALSE;
    }
    /**
     * 处理空架子吊装位请求任务:将仓库的空架子送到吊装位99,等待入库
     *
     * @return
     */
    public boolean inboundRequestTask() throws Exception {
        // 步骤1:查询“未执行的空架子到吊装位请求任务”(类型IN_REQUEST,状态NEW)
        RawGlassStorageTask inRequestTask = rawGlassStorageTaskService.getOne(new LambdaQueryWrapper<RawGlassStorageTask>()
                .eq(RawGlassStorageTask::getTaskType, Const.RAW_GLASS_TASK_TYPE_IN_REQUEST) // 空架子入库请求类型
                .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                .last("limit 1")); // 每次处理一个任务,避免冲突
        if (inRequestTask == null) {
            log.info("无待执行的空架子吊装位请求任务");
            return Boolean.FALSE;
        }
        // 步骤2:检查任务关联的空架子状态(需为“待入库”,且确实是空架子)
        RawGlassStorageDetails emptyShelf = rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, inRequestTask.getStartSlot()) // 起始位:仓库空架子位
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING)); // 待入库状态);
        if (emptyShelf == null) {
            log.info("空架子到吊装位请求任务关联的架子异常(非空架子或状态错误),跳过执行");
            return Boolean.FALSE;
        }
        // 步骤3:检查目标吊装位99是否空闲
        List<RawGlassStorageDetails> liftingShelfList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, inRequestTask.getEndSlot()) // 目标位:吊装位99
                .in(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN_ALL));
        if (CollectionUtil.isNotEmpty(liftingShelfList)) {
            log.info("吊装位{}已有关联架子,无法执行空架子到吊装位请求", inRequestTask.getEndSlot());
            return Boolean.FALSE;
        }
        // 步骤4:更新空架子状态为“执行中”
        rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, emptyShelf.getSlot())
                .eq(RawGlassStorageDetails::getState, Const.GLASS_STATE_IN)
                .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
        // 步骤5:更新任务状态为“执行中”,避免重复执行
        rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                .eq(RawGlassStorageTask::getId, inRequestTask.getId())
                .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING));
        // 步骤6:发送PLC指令,驱动空架子从仓库→吊装位
        S7Data s7Data = new S7Data();
        s7Data.setTaskWord((short) 1); // 任务触发信号
        s7Data.setStartSlot((short) inRequestTask.getStartSlot().intValue()); // 起始位:仓库空架子位
        s7Data.setEndSlot((short) inRequestTask.getEndSlot().intValue());     // 目标位:吊装位99
        s7Serializer.write(s7Data);
        log.info("执行空架子到吊装位请求任务:从仓库{}到吊装位{}", inRequestTask.getStartSlot(), inRequestTask.getEndSlot());
        return Boolean.TRUE;
    }
    /**
     * 出库任务:1、点出库,立马生成出片任务 2、点出库修改工位详情内的状态为待出库,定时任务扫描生成出库任务
     */
    public boolean outboundTask() throws Exception {
        List<RawGlassStorageDetails> rawGlassList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_WAIT_OUT)
                .inSql(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1"));
        if (CollectionUtil.isEmpty(rawGlassList)) {
            log.info("系统没有需要出库的原片信息");
        // 步骤1:查询已生成的“未执行出库任务”(状态为NEW,类型为OUT)
        RawGlassStorageTask outboundTask = rawGlassStorageTaskService.getOne(new LambdaQueryWrapper<RawGlassStorageTask>()
                .eq(RawGlassStorageTask::getTaskType, Const.RAW_GLASS_TASK_TYPE_OUT)
                .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                .last("limit 1")); // 每次处理一个任务
        if (outboundTask == null) {
            log.info("无待执行的出库任务");
            return Boolean.FALSE;
        }
        //获取工位上是否有架子,
        // 步骤2:获取任务关联的架子详情,检查状态是否合法(待出库)
        RawGlassStorageDetails details = rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, outboundTask.getStartSlot()) // 任务起始位(仓库位)
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_WAIT_OUT)); // 待出库状态
        if (details == null) {
            log.info("出库任务关联的架子状态异常,跳过执行");
            return Boolean.FALSE;
        }
        // 步骤3:检查吊装位99是否空闲(无架子)
        List<RawGlassStorageDetails> emptyLeftingList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .in(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN_ALL)
                .in(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1 and device_id = 4"));
        if (CollectionUtil.isNotEmpty(emptyLeftingList) && emptyLeftingList.size() > 1) {
            log.info("吊装位当前都有架子,结束出片任务");
        if (CollectionUtil.isNotEmpty(emptyLeftingList)) {
            log.info("吊装位99当前有架子,无法执行出库任务");
            return Boolean.FALSE;
        }
        //获取需要落架的
        List<Integer> leftingList = emptyLeftingList.stream().map(RawGlassStorageDetails::getSlot).collect(Collectors.toList());
        int lefting = CollectionUtil.isEmpty(leftingList) ? LEFTING_01 : leftingList.get(0).equals(LEFTING_01) ? LEFTING_02 : LEFTING_01;
        Integer startSlot = rawGlassList.get(0).getSlot();
        //生成出库任务
        rawGlassStorageDetailsService.generateTask(startSlot, lefting, startSlot, rawGlassList.get(0).getRemainQuantity(), Const.RAW_GLASS_TASK_TYPE_OUT);
//        List<ReadWriteEntity> list = new ArrayList<>();
//        list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 1));
//        list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 1));
//        list.add(generateReadWriteEntity("A01-CC.dev.startSlot", startSlot));
//        list.add(generateReadWriteEntity("A01-CC.dev.endSlot", lefting));
//        miloService.writeToOpcWord(list);
        //修改出片任务状态
        // 步骤4:更新架子状态为“执行中”
        rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, rawGlassList.get(0).getSlot())
                .eq(RawGlassStorageDetails::getSlot, details.getSlot())
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_WAIT_OUT)
                .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
        // 步骤5:更新任务状态为“执行中”(避免重复执行)
        rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                .eq(RawGlassStorageTask::getId, outboundTask.getId())
                .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING));
        S7Data s7Data = new S7Data();
        s7Data.setTaskWord((short) 1);
        s7Data.setStartSlot((short) outboundTask.getStartSlot().intValue()); // 仓库存储位(起始位)
        s7Data.setEndSlot((short) outboundTask.getEndSlot().intValue());     // 吊装位99(目标位)
        s7Serializer.write(s7Data);
        return Boolean.TRUE;
    }
    /**
     * 复位任务:1、点复位,立马生成复位任务 2、点出库修改工位详情内的状态为架子复位,定时任务扫描生成复位任务
     */
    public boolean shelfResetTask() throws Exception {
        // 1. 查询“待复位”的架子(状态为RESET,且工位启用)
        List<RawGlassStorageDetails> rawGlassList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RESET)
                .inSql(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1"));
        if (CollectionUtil.isEmpty(rawGlassList)) {
            log.info("系统没有需要复位的原片信息");
            return Boolean.FALSE;
        }
        // 2. 取第一条待复位的架子(每次处理一个)
        RawGlassStorageDetails details = rawGlassList.get(0);
        Integer startSlot = details.getSlot();       // 复位起始位(当前架子所在位)
        Integer targetSlot = details.getShelf();     // 复位目标位(初始仓库存储位)
        // 3. 生成复位任务(类型建议单独定义:如Const.RAW_GLASS_TASK_TYPE_RESET,避免与调度任务混淆)
        rawGlassStorageDetailsService.generateTask(
                startSlot,
                targetSlot,
                targetSlot,
                details.getRemainQuantity(),
                Const.RAW_GLASS_TASK_TYPE_DISPATCH
        );
        // 4. 更新架子状态为“执行中”
        rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, startSlot)
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RESET)
                .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
        // 5. 补充PLC交互:发送复位指令
        S7Data s7Data = new S7Data();
        s7Data.setTaskWord((short) 1); // 任务触发信号
        s7Data.setStartSlot((short) startSlot.intValue()); // 起始位:当前架子位
        s7Data.setEndSlot((short) targetSlot.intValue());   // 目标位:初始仓库位
        s7Serializer.write(s7Data);
        log.info("执行架子复位任务:从{}到{}", startSlot, targetSlot);
        return Boolean.TRUE;
    }
@@ -273,32 +446,49 @@
     * @throws Exception
     */
    public boolean warehouseTask() throws Exception {
        List<RawGlassStorageDetails> rawGlassList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getState, Const.GLASS_STATE_IN)
                .gt(RawGlassStorageDetails::getRemainQuantity, 0)
                .inSql(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1 and device_id = 4")
                .inSql(RawGlassStorageDetails::getShelf, "select slot from raw_glass_storage_station where enable_state = 1 "));
        if (CollectionUtil.isEmpty(rawGlassList)) {
            log.info("吊装位被禁用/架子所在工位被禁用/无原片信息");
            return Boolean.FALSE;
//        List<RawGlassStorageDetails> rawGlassList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
//                .eq(RawGlassStorageDetails::getState, Const.GLASS_STATE_IN)
//                .gt(RawGlassStorageDetails::getRemainQuantity, 0)
//                .inSql(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1 and device_id = 4")
//                .inSql(RawGlassStorageDetails::getShelf, "select slot from raw_glass_storage_station where enable_state = 1 "));
//        if (CollectionUtil.isEmpty(rawGlassList)) {
//            log.info("吊装位被禁用/架子所在工位被禁用/无原片信息");
//            return Boolean.FALSE;
//        }
        // 查询回库任务
        RawGlassStorageTask task = rawGlassStorageTaskService.getOne(new LambdaQueryWrapper<RawGlassStorageTask>()
                .in(RawGlassStorageTask::getTaskType,  Const.RAW_GLASS_TASK_TYPE_IN)
                .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                .last("limit 1"));
        if (task == null) {
            log.info("无待执行的回库任务");
            return false;
        }
        //生成进笼任务
        RawGlassStorageDetails details = rawGlassList.get(0);
        rawGlassStorageDetailsService.generateTask(details.getSlot(), details.getShelf(), details.getShelf(),
                details.getRemainQuantity(), Const.RAW_GLASS_TASK_TYPE_IN);
        RawGlassStorageDetails details = rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, task.getStartSlot()) // 任务起始位(吊装位)
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING)); // 已标记为执行中
        if (details == null) {
            log.info("任务关联的架子状态异常,跳过执行");
            return false;
        }
        rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                .eq(RawGlassStorageTask::getId, task.getId())
                .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING));
        log.info("执行回库任务:从{}到{}", task.getStartSlot(), task.getEndSlot());
//        List<ReadWriteEntity> list = new ArrayList<>();
//        list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 1));
//        list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 1));
//        list.add(generateReadWriteEntity("A01-CC.dev.startSlot", details.getSlot()));
//        list.add(generateReadWriteEntity("A01-CC.dev.endSlot", details.getShelf()));
//        list.add(generateReadWriteEntity("CC.CC.taskWord", 1));
//        list.add(generateReadWriteEntity("CC.CC.taskSending", 1));
//        list.add(generateReadWriteEntity("CC.CC.startSlot", details.getSlot()));
//        list.add(generateReadWriteEntity("CC.CC.endSlot", details.getShelf()));
//        miloService.writeToOpcWord(list);
        //生成工位任务,将吊装位的玻璃状态改位进笼中
        //修改吊装位的原片状态为103 出片中
        //修改出片任务状态
        rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getSlot, rawGlassList.get(0).getSlot())
                .eq(RawGlassStorageDetails::getState, Const.GLASS_STATE_IN)
                .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
        S7Data s7Data = new S7Data();
        s7Data.setTaskWord((short) 1);
        s7Data.setStartSlot((short) details.getSlot().intValue());
        s7Data.setEndSlot((short) details.getShelf().intValue());
        s7Serializer.write(s7Data);
        return Boolean.TRUE;
    }
@@ -315,161 +505,97 @@
            log.info("正在执行的工程原片无可上片的原片信息");
            return Boolean.FALSE;
        }
        //获取当前上片位1号架子信息
        int endSlot = stationCell == LOAD_GLASS_01_01 ? LOAD_GLASS_01_01 : LOAD_GLASS_02_01;
        int endSlot02 = stationCell == LOAD_GLASS_01_02 ? LOAD_GLASS_01_01 : LOAD_GLASS_02_02;
        //获取当前需要上片的原片数据
        Map<String, List<UpPattenUsageVO>> upListMap = pattenUsageList.stream()
                .collect(Collectors.groupingBy(UpPattenUsageVO::getGroupNumber));
        //1、查询2个上片的原片详情
        List<RawGlassStorageDetails> rawGlassDetailsList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getState, Const.GLASS_STATE_IN).in(RawGlassStorageDetails::getDeviceId, stationCell)
                .orderByAsc(RawGlassStorageDetails::getSlot));
        List<UpPattenUsageVO> upPattenUsage01VOS = upListMap.get("1");
        UpPattenUsageVO usageVO = upPattenUsage01VOS.get(0);
        if (CollectionUtils.isEmpty(rawGlassDetailsList)) {
            //表示1上片位没有架子,直接找原片放入对应路线的1号上片位
            RawGlassStorageDetails details = rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                            .eq(RawGlassStorageDetails::getFilmsId, usageVO.getFilmsId())
                            .eq(RawGlassStorageDetails::getPatternWidth, usageVO.getWidth())
                            .eq(RawGlassStorageDetails::getPatternHeight, usageVO.getHeight())
                            .eq(RawGlassStorageDetails::getPatternThickness, usageVO.getThickness())
                            .inSql(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1")
                            .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
//                    .gt(RawGlassStorageDetails::getRemainQuantity, upPattenUsage01VOS.size())
                            .orderByAsc(RawGlassStorageDetails::getRemainQuantity)
                            .last("limit 1")
            );
            rawGlassStorageDetailsService.generateTask(details.getSlot(), endSlot, details.getSlot(), details.getRemainQuantity(), Const.RAW_GLASS_TASK_TYPE_DISPATCH);
        List<UpPattenUsageVO> usageVOS = upListMap.get("1");
        //获取当前上片位1号架子信息
        List<Integer> loadStation = LOAD_STATION_01;
        List<RawGlassStorageStation> stations = rawGlassStorageStationService.list(new LambdaQueryWrapper<RawGlassStorageStation>()
                .in(RawGlassStorageStation::getSlot, loadStation)
                .eq(RawGlassStorageStation::getEnableState, Const.SLOT_ON)
                .orderByAsc(RawGlassStorageStation::getSlot));
        if (CollectionUtils.isEmpty(stations)) {
            log.info("101的上片位不可用");
            return Boolean.FALSE;
        }
            //结束调度任务 修改工位状态(起始位)状态为103 RAW_GLASS_STATE_RUNNING 任务完成后将状态改为101  目标位新增一条数据,架子号为(起始位)
        List<RawGlassStorageDetails> loadStationList = rawGlassStorageDetailsService.list(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .inSql(RawGlassStorageDetails::getSlot, "select slot from raw_glass_storage_station where enable_state = 1")
                .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                .eq(RawGlassStorageDetails::getDeviceId, stationCell));
        if (CollectionUtils.isEmpty(loadStationList)) {
            RawGlassStorageDetails rawDetails = getRawGlassStorageDetailsBySize(usageVOS.get(0), usageVOS.size());
            if (rawDetails == null) {
                log.info("仓库无匹配规格的原片,无法调度到101工位");
                return Boolean.FALSE;
            }
            // 生成调度任务:仓库原片位 → 101上片位
            rawGlassStorageDetailsService.generateTask(
                    rawDetails.getSlot(),
                    stations.get(0).getSlot(),
                    rawDetails.getShelf(),
                    rawDetails.getRemainQuantity(),
                    Const.RAW_GLASS_TASK_TYPE_DISPATCH);
            rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                    .eq(RawGlassStorageTask::getTaskType, Const.RAW_GLASS_TASK_TYPE_DISPATCH)
                    .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                    .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING));
            rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                    .eq(RawGlassStorageDetails::getSlot, details.getSlot()).eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                    .set(RawGlassStorageDetails::getDeviceId, Const.RAW_GLASS_STATE_RUNNING));
                    .eq(RawGlassStorageDetails::getSlot, rawDetails.getSlot())
                    .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                    .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
            S7Data s7Data = new S7Data();
            s7Data.setTaskWord((short) 1);
            s7Data.setStartSlot((short) rawDetails.getSlot().intValue()); // 起始位:仓库
            s7Data.setEndSlot((short) LOAD_STATION_01.get(0).intValue()); // 目标位:上片位101
            s7Serializer.write(s7Data); // 发送到PLC
            log.info("调度任务已发送PLC:从仓库{}到上片位{}", rawDetails.getSlot(), LOAD_STATION_01);
            return Boolean.TRUE;
        }
        RawGlassStorageDetails glassStorageDetails = rawGlassDetailsList.get(0);
        if (rawGlassDetailsList.size() == 2) {
            if (!((usageVO.getWidth() == glassStorageDetails.getPatternWidth() && usageVO.getHeight() == glassStorageDetails.getPatternHeight() &&
                    usageVO.getThickness() == glassStorageDetails.getPatternThickness() && usageVO.getFilmsId().equals(glassStorageDetails.getFilmsId())))
                    || ((usageVO.getWidth() == glassStorageDetails.getPatternWidth() && usageVO.getHeight() == glassStorageDetails.getPatternHeight() &&
                    usageVO.getThickness() == glassStorageDetails.getPatternThickness() && usageVO.getFilmsId().equals(glassStorageDetails.getFilmsId()))
                    && glassStorageDetails.getRemainQuantity() == 0)) {
                //将架子放回原工位上
                rawGlassStorageDetailsService.generateTask(endSlot, glassStorageDetails.getShelf(), glassStorageDetails.getShelf(), 0, Const.RAW_GLASS_TASK_TYPE_DISPATCH);
//                List<ReadWriteEntity> list = new ArrayList<>();
//                list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.startSlot", endSlot));
//                list.add(generateReadWriteEntity("A01-CC.dev.endSlot", glassStorageDetails.getShelf()));
//                miloService.writeToOpcWord(list);
                rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                        .eq(RawGlassStorageDetails::getSlot, glassStorageDetails.getSlot()).eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                        .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
                return Boolean.TRUE;
        // 上片位101有玻璃 → 判断尺寸是否匹配
        RawGlassStorageDetails oneLoadStation = loadStationList.get(0);
        if (oneLoadStation.getRemainQuantity() <= 0 || !compareRawSize(usageVOS.get(0), oneLoadStation)) {
            // 检查上片机是否正在工作,若正在工作则不生成退回任务
            if (pattenUsageList.stream().allMatch(vo -> vo.getState() == 101)) {
                log.warn("上片机{}正在工作,无法执行退回任务", stationCell);
                return Boolean.FALSE;
            }
            // 生成退回任务:101上片位 → 原仓库存储位
            rawGlassStorageDetailsService.generateTask(
                    stations.get(0).getSlot(),
                    oneLoadStation.getShelf(),
                    oneLoadStation.getShelf(),
                    oneLoadStation.getRemainQuantity(),
                    Const.RAW_GLASS_TASK_TYPE_DISPATCH);
            rawGlassStorageTaskService.update(new LambdaUpdateWrapper<RawGlassStorageTask>()
                    .eq(RawGlassStorageTask::getTaskType, Const.RAW_GLASS_TASK_TYPE_DISPATCH)
                    .eq(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_NEW)
                    .set(RawGlassStorageTask::getTaskState, Const.RAW_GLASS_TASK_RUNNING));
            rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                    .eq(RawGlassStorageDetails::getSlot, oneLoadStation.getSlot())
                    .eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                    .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
            S7Data s7Data = new S7Data();
            s7Data.setTaskWord((short) 1); // 任务触发信号
            s7Data.setStartSlot((short) LOAD_STATION_01.get(0).intValue()); // 起始位:上片位101
            s7Data.setEndSlot((short) oneLoadStation.getShelf().intValue()); // 目标位:仓库
            s7Serializer.write(s7Data); // 发送到PLC
            log.info("退回任务已发送PLC:从上片位{}到仓库{}", LOAD_STATION_01, oneLoadStation.getShelf());
            return Boolean.FALSE;
        }
        //todo:1条线且当条线为2号上片为
        if (LOAD_STATION_MAX.contains(glassStorageDetails.getSlot())) {
            log.info("上片位2号有架子,结束本条线{}的调度任务", stationCell);
            if (!((usageVO.getWidth() == glassStorageDetails.getPatternWidth() && usageVO.getHeight() == glassStorageDetails.getPatternHeight() &&
                    usageVO.getThickness() == glassStorageDetails.getPatternThickness() && usageVO.getFilmsId().equals(glassStorageDetails.getFilmsId())))
                    || ((usageVO.getWidth() == glassStorageDetails.getPatternWidth() && usageVO.getHeight() == glassStorageDetails.getPatternHeight() &&
                    usageVO.getThickness() == glassStorageDetails.getPatternThickness() && usageVO.getFilmsId().equals(glassStorageDetails.getFilmsId()))
                    && glassStorageDetails.getRemainQuantity() == 0)) {
                //将架子放回原工位上
                rawGlassStorageDetailsService.generateTask(endSlot02, glassStorageDetails.getShelf(), glassStorageDetails.getShelf(), 0, Const.RAW_GLASS_TASK_TYPE_DISPATCH);
//                List<ReadWriteEntity> list = new ArrayList<>();
//                list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.startSlot", endSlot02));
//                list.add(generateReadWriteEntity("A01-CC.dev.endSlot", glassStorageDetails.getShelf()));
//                miloService.writeToOpcWord(list);
                rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                        .eq(RawGlassStorageDetails::getSlot, glassStorageDetails.getSlot()).eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                        .set(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_RUNNING));
                return Boolean.TRUE;
            }
            return Boolean.FALSE;
        } else {
            //比较当前1号架子上的玻璃剩余数量是否为0或者已用完
            if (usageVO.getWidth() == glassStorageDetails.getPatternWidth() && usageVO.getHeight() == glassStorageDetails.getPatternHeight() &&
                    usageVO.getThickness() == glassStorageDetails.getPatternThickness() && usageVO.getFilmsId().equals(glassStorageDetails.getFilmsId())) {
                RawGlassStorageDetails details = null;
                if (upPattenUsage01VOS.size() > glassStorageDetails.getRemainQuantity()) {
                    //2号位上片:继续当前尺寸的原片
                    details = rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                            .eq(RawGlassStorageDetails::getFilmsId, usageVO.getFilmsId())
                            .eq(RawGlassStorageDetails::getPatternWidth, usageVO.getWidth())
                            .eq(RawGlassStorageDetails::getPatternHeight, usageVO.getHeight())
                            .eq(RawGlassStorageDetails::getPatternThickness, usageVO.getThickness())
                            .gt(RawGlassStorageDetails::getRemainQuantity, upPattenUsage01VOS.size())
                            .orderByAsc(RawGlassStorageDetails::getRemainQuantity)
                            .last("limit 1"));
                } else {
                    //2号位上片:获取第二种尺寸的原片
                    List<UpPattenUsageVO> upPattenUsage02VOS = upListMap.get("2");
                    if (CollectionUtils.isEmpty(upPattenUsage01VOS)) {
                        return Boolean.FALSE;
                    }
                    usageVO = upPattenUsage02VOS.get(0);
                    details = rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                            .eq(RawGlassStorageDetails::getFilmsId, usageVO.getFilmsId())
                            .eq(RawGlassStorageDetails::getPatternWidth, usageVO.getWidth())
                            .eq(RawGlassStorageDetails::getPatternHeight, usageVO.getHeight())
                            .eq(RawGlassStorageDetails::getPatternThickness, usageVO.getThickness())
                            .gt(RawGlassStorageDetails::getRemainQuantity, upPattenUsage01VOS.size())
                            .orderByAsc(RawGlassStorageDetails::getRemainQuantity)
                            .last("limit 1"));
                }
                //将工位的架子传送到上片位
                rawGlassStorageDetailsService.generateTask(details.getSlot(), endSlot02, details.getShelf(), details.getRemainQuantity(), Const.RAW_GLASS_TASK_TYPE_DISPATCH);
                rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                        .eq(RawGlassStorageDetails::getSlot, details.getSlot()).eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                        .set(RawGlassStorageDetails::getDeviceId, Const.RAW_GLASS_STATE_RUNNING));
//                List<ReadWriteEntity> list = new ArrayList<>();
//                list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.startSlot", glassStorageDetails.getShelf()));
//                list.add(generateReadWriteEntity("A01-CC.dev.endSlot", endSlot02));
//                miloService.writeToOpcWord(list);
                return Boolean.TRUE;
            } else {
                //将架子放回原工位上
                rawGlassStorageDetailsService.generateTask(endSlot, glassStorageDetails.getShelf(), glassStorageDetails.getShelf(), glassStorageDetails.getRemainQuantity(), Const.RAW_GLASS_TASK_TYPE_DISPATCH);
                rawGlassStorageDetailsService.update(new LambdaUpdateWrapper<RawGlassStorageDetails>()
                        .eq(RawGlassStorageDetails::getSlot, endSlot).eq(RawGlassStorageDetails::getState, Const.RAW_GLASS_STATE_IN)
                        .set(RawGlassStorageDetails::getDeviceId, Const.RAW_GLASS_STATE_RUNNING));
//                List<ReadWriteEntity> list = new ArrayList<>();
//                list.add(generateReadWriteEntity("A01-CC.dev.taskWord", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.taskSending", 1));
//                list.add(generateReadWriteEntity("A01-CC.dev.startSlot", endSlot));
//                list.add(generateReadWriteEntity("A01-CC.dev.endSlot", glassStorageDetails.getShelf()));
//                miloService.writeToOpcWord(list);
                return Boolean.TRUE;
            }
        }
        // 上片位101玻璃尺寸匹配且数量充足 → 无需调度
        log.info("101工位玻璃尺寸匹配且数量充足,无需调度");
        return Boolean.FALSE;
    }
    private RawGlassStorageDetails generateDetails(RawGlassStorageDetails details, Integer targetSlot) {
        RawGlassStorageDetails targetDetails = new RawGlassStorageDetails();
//        details.setDeviceId();
        targetDetails.setSlot(targetSlot);
        targetDetails.setShelf(details.getShelf());
        targetDetails.setPatternWidth(details.getPatternWidth());
        targetDetails.setPatternHeight(details.getPatternHeight());
        targetDetails.setPatternThickness(details.getPatternThickness());
        targetDetails.setFilmsId(details.getFilmsId());
        targetDetails.setRemainQuantity(details.getRemainQuantity());
        targetDetails.setCreateTime(new Date());
        targetDetails.setState(Const.RAW_GLASS_STATE_IN);
        return targetDetails;
    }
    private ReadWriteEntity generateReadWriteEntity(String identifier, int value) {
        ReadWriteEntity readWriteEntity = new ReadWriteEntity();
@@ -478,5 +604,31 @@
        return readWriteEntity;
    }
    private RawGlassStorageDetails getRawGlassStorageDetailsBySize(UpPattenUsageVO usageVO, int remainQuantity) {
        return rawGlassStorageDetailsService.getOne(new LambdaQueryWrapper<RawGlassStorageDetails>()
                .eq(RawGlassStorageDetails::getFilmsId, usageVO.getFilmsId())
                .eq(RawGlassStorageDetails::getPatternWidth, usageVO.getWidth())
                .eq(RawGlassStorageDetails::getPatternHeight, usageVO.getHeight())
                .eq(RawGlassStorageDetails::getPatternThickness, usageVO.getThickness())
                .notIn(RawGlassStorageDetails::getSlot, LOAD_STATION_01)
                .eq(RawGlassStorageDetails::getState, Const.GLASS_STATE_IN)
                .orderByAsc(RawGlassStorageDetails::getRemainQuantity)
                .last("order by abs(t.remain_quantity - " + remainQuantity + ")  asc")
                .last("limit 1"));
    }
    /**
     * 尺寸一样并且原片数量大于0
     *
     * @param upPattenUsage
     * @param details
     * @return
     */
    private boolean compareRawSize(UpPattenUsage upPattenUsage, RawGlassStorageDetails details) {
        boolean flag = upPattenUsage.getWidth() == details.getPatternWidth() && upPattenUsage.getHeight() == details.getPatternHeight() &&
                upPattenUsage.getThickness() == details.getPatternThickness() && upPattenUsage.getFilmsId().equals(details.getFilmsId());
        return flag;
    }
}