严智鑫
2024-07-25 88883cf4ccdb4dfe6ed62952271c498c0a4d8704
hangzhoumesParent/moduleService/CacheGlassModule/src/main/java/com/mes/job/CacheGlassTask.java
@@ -2,10 +2,17 @@
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.query.MPJQueryWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mes.common.S7object;
import com.mes.common.config.Const;
import com.mes.device.PlcParameterObject;
import com.mes.edgglasstask.entity.EdgGlassTaskInfo;
import com.mes.edgglasstask.service.EdgGlassTaskInfoService;
import com.mes.edgstoragecage.entity.EdgStorageCage;
import com.mes.edgstoragecage.entity.EdgStorageCageDetails;
import com.mes.edgstoragecage.service.EdgStorageCageDetailsService;
@@ -14,15 +21,19 @@
import com.mes.glassinfo.service.GlassInfoService;
import com.mes.taskcache.entity.TaskCache;
import com.mes.taskcache.service.TaskCacheService;
import com.mes.tools.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * @Author : zhoush
@@ -42,21 +53,49 @@
    @Autowired
    EdgStorageCageDetailsService edgStorageCageDetailsService;
    @Autowired
    EdgGlassTaskInfoService edgGlassTaskInfoService;
    @Autowired
    WebSocketServer webServerService;
    @Value("${mes.threshold}")
    private int threshold;
    @Value("${mes.ratio}")
    private int ratio;
    @Value("${mes.sequence.order}")
    private boolean sequenceOrder;
    @Value("${mes.max.firstLength}")
    private String firstLength;
    @Value("${mes.max.secondLength}")
    private String secondLength;
    @Value("${mes.min.firstLength}")
    private String minFirstLength;
    @Value("${mes.min.secondLength}")
    private String minSecondLength;
    @Scheduled(fixedDelay = 1000)
    public void plcHomeEdgTask() {
        Date startDate = new Date();
        log.info("本次任务开始执行时间:{}", startDate);
        PlcParameterObject plcParameterObject = S7object.getinstance().PlcMesObject;
        String taskRequestTypeValue = plcParameterObject.getPlcParameter("A06_request_word").getValue();
        String glassIdeValue = plcParameterObject.getPlcParameter("A05_scanning_ID").getValue();
        String confirmationWrodValue = plcParameterObject.getPlcParameter("MES_confirmation_word").getValue();
//        1为A09空闲,2为A10空闲,3为A09A10都空闲,0为A09A10都有玻璃
        String outGlassstate = plcParameterObject.getPlcParameter("A09_glass_status").getValue();
        //A08  A09表示线路相同  可做等价  无数据转int异常
        String out08Glassstate = plcParameterObject.getPlcParameter("A08_glass_status").getValue();
        String out10Glassstate = plcParameterObject.getPlcParameter("A10_glass_status").getValue();
        String confirmationWrodAddress = plcParameterObject.getPlcParameter("MES_confirmation_word").getAddress();
        String currentSlot = plcParameterObject.getPlcParameter("Current_slot").getValue();
        log.info("1、获取到的请求字为:{},获取到的扫描ID为:{},获取到的确认字为:{},获取到的出片状态为:{},当前格子号为:{}",
                taskRequestTypeValue, glassIdeValue, confirmationWrodValue, outGlassstate, currentSlot);
        log.info("1、获取到的请求字为:{},获取到的扫描ID为:{},获取到的确认字为:{},获取到的出片状态分别为:A09:{}、A10:{},当前格子号为:{}",
                taskRequestTypeValue, glassIdeValue, confirmationWrodValue, out08Glassstate, out10Glassstate, currentSlot);
        if ("0".equals(taskRequestTypeValue)) {
            if ("0".equals(confirmationWrodValue)) {
@@ -64,120 +103,600 @@
                return;
            }
            log.info("2、获取到的请求字为0,将确认字改为0");
            S7object.getinstance().plccontrol.WriteWord(confirmationWrodAddress, (short) 0);
            S7object.getinstance().plccontrol.writeWord(confirmationWrodAddress, 0);
            return;
        }
        if (!"0".equals(confirmationWrodValue)) {
            log.info("2、获取到的请求字不为0,将确认字改为0");
            S7object.getinstance().plccontrol.WriteWord(confirmationWrodAddress, (short) 0);
            log.info("2、获取到的请求字不为0,将确认字不为0,直接结束");
            return;
        }
        if ("1".equals(taskRequestTypeValue)) {
            log.info("3、进片请求,且确认字为0,执行进片任务");
            log.info("2、进片请求,且确认字为0,执行进片任务");
            inTo(glassIdeValue, confirmationWrodAddress, currentSlot);
        } else if ("2".equals(taskRequestTypeValue)) {
            //09空闲 :1      10空闲 :2        都空闲:3    其他0
            log.info("3、出片请求,且确认字为0,执行进片任务");
            outTo(Integer.parseInt(outGlassstate), confirmationWrodAddress, currentSlot);
            log.info("2、出片请求,且确认字为0,执行进片任务");
            outTo(Integer.parseInt(out08Glassstate),
                    Integer.parseInt(out10Glassstate), confirmationWrodAddress, "", 0);
        } else if ("3".equals(taskRequestTypeValue)) {
            log.info("3、进片和出片都空闲,执行出片任务");
            if ("0".equals(outGlassstate)) {
            log.info("2、进片和出片都空闲,执行出片任务");
            //加笼子里面是否有玻璃,有先出,无玻璃先进
            boolean outFlase = outTo(Integer.parseInt(out08Glassstate),
                    Integer.parseInt(out10Glassstate), confirmationWrodAddress, glassIdeValue, Integer.parseInt(currentSlot));
            log.info("出片任务是否完成:{},失败且玻璃id:{}不为空则执行进片任务", outFlase, glassIdeValue);
            if (!outFlase && StringUtils.isNotBlank(glassIdeValue)) {
                inTo(glassIdeValue, confirmationWrodAddress, currentSlot);
            } else {
                outTo(Integer.parseInt(outGlassstate), confirmationWrodAddress, currentSlot);
            }
        }
        Date endDate = new Date();
        log.info("本次任务结束时间:{},共耗时:{}ms", endDate, endDate.getTime() - startDate.getTime());
    }
    /**
     * 进片任务
     *
     * @param glassId
     * @param confirmationWrodAddress
     * @param currentSlot
     */
    private void inTo(String glassId, String confirmationWrodAddress, String currentSlot) {
    public void inTo(String glassId, String confirmationWrodAddress, String currentSlot) {
        log.info("1、按照玻璃id:{}获取玻璃小片信息,当前格子为:{}", glassId, currentSlot);
        GlassInfo glassInfo = glassInfoService.getOne(new LambdaQueryWrapper<GlassInfo>().eq(GlassInfo::getGlassId, glassId));
        if (glassInfo == null) {
            log.info("2、此玻璃编号不存在");
            return;
        }
        log.info("2、获取到的玻璃信息为{}", glassInfo);
        //添加进片任务  查找空格
        EdgStorageCage nearestEmpty = edgStorageCageService.selectNearestEmpty(Integer.parseInt(currentSlot));
        Assert.isTrue(nearestEmpty == null, "格子已满");
        log.info("3、查询卧式理片笼里面的空格:{}", nearestEmpty);
        EdgStorageCage nearestEmpty = edgStorageCageService.selectNearestEmpty(Integer.parseInt(currentSlot), Boolean.FALSE);
        Assert.isTrue(null != nearestEmpty, "格子已满");
        log.info("2、查询卧式理片笼里面的空格:{}", nearestEmpty);
        log.info("4、将玻璃信息插入卧式理片笼,当前玻璃信息:{}", glassInfo);
        //查询玻璃并进行交换
        GlassInfo glassInfo = queryAndChangeGlass(glassId);
        log.info("3、将玻璃信息插入卧式理片笼,当前玻璃信息:{}", glassInfo);
        EdgStorageCageDetails details = new EdgStorageCageDetails();
        BeanUtils.copyProperties(glassInfo, details);
        details.setState(Const.GLASS_STATE_IN);
        details.setSlot(nearestEmpty.getSlot());
        details.setDeviceId(nearestEmpty.getDeviceId());
        edgStorageCageDetailsService.save(details);
        log.info("5、玻璃信息已存入理片笼详情表,玻璃信息为{}", details);
        log.info("4、玻璃信息已存入理片笼详情表,玻璃信息为{}", details);
        //添加进片任务
        TaskCache taskCache = new TaskCache();
        taskCache.setGlassId(glassId);
        taskCache.setTaskStatus(0);
        taskCache.setStartCell(0);
        taskCache.setEndCell(nearestEmpty.getSlot());
        taskCache.setTaskType(1);
        taskCache.setCreateTime(new Date());
        taskCacheService.insertTaskCache(taskCache);
        log.info("6、生成进片任务信息存入任务表{}", taskCache);
        boolean taskCache = saveTaskCache(details.getGlassId(), 0, nearestEmpty.getSlot(), Const.GLASS_CACHE_TYPE_IN);
        log.info("5、生成进片任务信息存入任务表是否完成:{}", taskCache);
        S7object.getinstance().plccontrol.WriteWord(confirmationWrodAddress, (short) 1);
        log.info("7、发送确认字完成");
        S7object.getinstance().plccontrol.writeWord(confirmationWrodAddress, 1);
        log.info("6、发送确认字完成");
    }
    /**
     * 查询玻璃并进行交换
     *
     * @param glassId
     * @return
     */
    public GlassInfo queryAndChangeGlass(String glassId) {
        GlassInfo glassInfo = glassInfoService.getOne(new LambdaQueryWrapper<GlassInfo>().eq(GlassInfo::getGlassId, glassId));
//                .inSql(GlassInfo::getEngineerId, "select engineer_id from engineering where state = 1"));
        Assert.isFalse(null == glassInfo, "玻璃信息不存在");
        //按照玻璃尺寸
        LambdaQueryWrapper<GlassInfo> queryWrapper = new LambdaQueryWrapper<GlassInfo>()
                .eq(GlassInfo::getWidth, glassInfo.getWidth())
                .eq(GlassInfo::getHeight, glassInfo.getHeight())
                .eq(GlassInfo::getThickness, glassInfo.getThickness())
                .eq(GlassInfo::getFilmsid, glassInfo.getFilmsid())
                .eq(GlassInfo::getTotalLayer, glassInfo.getTotalLayer())
                .eq(GlassInfo::getLayer, glassInfo.getLayer())
                .eq(GlassInfo::getEngineerId, glassInfo.getEngineerId())
                .notInSql(GlassInfo::getGlassId, "select distinct glass_id from edg_storage_cage_details " +
                        "where engineer_id = '" + glassInfo.getEngineerId() + "' and width = " + glassInfo.getWidth() + " and height = " + glassInfo.getHeight())
                .orderByAsc(GlassInfo::getTemperingLayoutId)
                .orderBy(Boolean.TRUE, sequenceOrder, GlassInfo::getTemperingFeedSequence)
                .last("Limit 1");
        GlassInfo swapGlassInfo = glassInfoService.getOne(queryWrapper);
        if (swapGlassInfo != null && !glassInfo.getGlassId().equals(swapGlassInfo.getGlassId())) {
            String swapGlassId = swapGlassInfo.getGlassId();
            log.info("将玻璃{}和玻璃{},信息互换,进玻璃 {}", glassInfo, swapGlassInfo, swapGlassInfo);
            swapGlassInfo.setGlassId(glassId);
            glassInfo.setGlassId(swapGlassId);
            glassInfoService.updateById(swapGlassInfo);
            glassInfoService.updateById(glassInfo);
            return swapGlassInfo;
        }
        return glassInfo;
    }
    /**
     * 出片任务
     * @param line
     *
     * @param out08Glassstate
     * @param out10Glassstate
     * @param confirmationWrodAddress
     * @param glassId
     * @param currentSlot
     */
    private void outTo(int line, String confirmationWrodAddress, String currentSlot) {
        Assert.isTrue(line != 0, "A09、A10都有玻璃,无法出片");
        log.info("1、出片任务出【{}】号线,备注(09空闲:1;10空闲:2;都空闲:3)", line);
    public boolean outTo(int out08Glassstate, int out10Glassstate, String confirmationWrodAddress, String glassId, int currentSlot) {
        //逻辑步骤:
//        0、A09、A10是否空闲,是否可以执行出片任务
//        1、获取钢化版图是否超过阈值
//        1.1、超过阈值:获取当前最小版图需要出片的玻璃信息
//        1.1.1、获取两条线最后一次出片的任务信息
//        1.1.2、按照出片信息去详情表查询格子在笼子里面剩余相同尺寸的玻璃数据
//        1.1.3、判断哪条线玻璃数量在理片笼内的数据最少,决定最小版图走该条线(问题:如果这条线非空闲,直接结束)
//        1.2、未超过阈值:
//        1.2.1、获取程序那条线空闲
//        1.2.2、获取该条线最后一次出片的任务信息
//        1.2.3、按照出片信息去详情表查询格子在笼子里面剩余相同尺寸的玻璃数据且以版图id、版序升序排序  取第一块玻璃出片
//        2、如果没有历史出片任务
//        2.1、出当前版图id最小版序最小的玻璃(问题:两条线都没有历史任务,出片时两条线的玻璃尺寸相同,是否找尺寸不同的)
        if ((out08Glassstate == 2 && out10Glassstate == 2) || (out08Glassstate == 0 && out10Glassstate == 0)) {
            log.info("A09、A10为{},{}非自动状态,无法出片");
            return Boolean.FALSE;
        }
        log.info("0、出片任务出的状态:A09:【{}】;A10:【{}】)", out08Glassstate, out10Glassstate);
        //定义出片玻璃信息
        int endcell = 0;
        List<TaskCache> oldTaskCacheList;
        if (line == 2) {
            endcell = Const.A10_OUT_TARGET_POSITION;
            oldTaskCacheList = taskCacheService.selectLastOutCacheInfos(Const.A10_OUT_TARGET_POSITION);
        EdgStorageCageDetails glassInfo = null;
        boolean flag = queryMaxMinDiff(threshold);
        log.info("1、获取钢化版图是否超过阈值:{}", flag);
        if (flag) {
            //获取当前最小版图需要出片的玻璃信息
            glassInfo = queryMinGlass(0.0, 0.0, glassId);
            log.info("1.1、超过阈值:获取当前最小版图需要出片的玻璃信息:{}", glassInfo);
            if (glassInfo == null) {
                log.info("笼子内和待进片没有玻璃");
                return Boolean.FALSE;
            }
            EdgStorageCageDetails a09EdgGlass = queryGlassByTaskCache(Const.A09_OUT_TARGET_POSITION, Const.GLASS_CACHE_TYPE_OUT_ALL);
            EdgStorageCageDetails a10EdgGlass = queryGlassByTaskCache(Const.A10_OUT_TARGET_POSITION, Const.GLASS_CACHE_TYPE_OUT_ALL);
            endcell = queryLineByGlassInfo(a09EdgGlass, a10EdgGlass, glassInfo, out08Glassstate, out10Glassstate);
        } else {
            endcell = Const.A09_OUT_TARGET_POSITION;
            oldTaskCacheList = taskCacheService.selectLastOutCacheInfos(Const.A09_OUT_TARGET_POSITION);
        }
        log.info("2、判断出片线路{},获取最后该条线已出片的任务信息{}(备注:0待执行,1已执行).都空闲优先出A09线", endcell, oldTaskCacheList);
            //按照状态判断两条线走那条线
            endcell = computerLineByState(out08Glassstate, out10Glassstate);
        String glassId = "";
        if (CollectionUtil.isNotEmpty(oldTaskCacheList)) {
            glassId = oldTaskCacheList.get(0).getGlassId();
            if (out08Glassstate == 1 && out10Glassstate == 1) {
                EdgStorageCageDetails a09EdgGlass = queryGlassByTaskCache(Const.A09_OUT_TARGET_POSITION, Const.GLASS_CACHE_TYPE_OUT_ALL);
                EdgStorageCageDetails a10EdgGlass = queryGlassByTaskCache(Const.A10_OUT_TARGET_POSITION, Const.GLASS_CACHE_TYPE_OUT_ALL);
                if (a09EdgGlass == null && a10EdgGlass == null) {
                    MPJQueryWrapper<EdgStorageCageDetails> wrapper = new MPJQueryWrapper<>();
                    wrapper.select("count(t.glass_id), t.width, t.height")
                            .eq("t.state", Const.GLASS_STATE_IN)
                            .inSql("t.slot", "select slot from edg_storage_cage where enable_state = " + Const.SLOT_ON)
                            .groupBy("t.width, t.height");
                    if (endcell == Const.A10_OUT_TARGET_POSITION) {
                        wrapper.innerJoin("(select glass_id, case when height <= width then width else height end as first_length, " +
                                "case when width < height then width else height end as second_length from edg_storage_cage_details) t1 " +
                                "on t.glass_id = t1.glass_id and (t1.first_length <=" + firstLength + " and t1.second_length<=" + secondLength + ") ");
                    } else {
                        wrapper.innerJoin("(select glass_id, case when height <= width then width else height end as first_length, " +
                                "case when width < height then width else height end as second_length from edg_storage_cage_details) t1 " +
                                "on t.glass_id = t1.glass_id and (t1.first_length >=" + minFirstLength + " and t1.second_length>=" + minSecondLength + ") ");
                    }
                    wrapper.last("order by count(t.glass_id) desc  limit 2");
                    List<EdgStorageCageDetails> list = edgStorageCageDetailsService.list(wrapper);
                    if (CollectionUtil.isEmpty(list)) {
                        MPJQueryWrapper<GlassInfo> queryWrapper = new MPJQueryWrapper<GlassInfo>()
                                .selectAll(GlassInfo.class).eq("t.glass_id", glassId);
//                                .inSql("t.engineer_id", "select engineer_id from engineering where state = 1");
                        if (endcell == Const.A10_OUT_TARGET_POSITION) {
                            wrapper.innerJoin("(select glass_id, case when height <= width then width else height end as first_length, " +
                                    "case when width < height then width else height end as second_length from edg_storage_cage_details) t1 " +
                                    "on t.glass_id = t1.glass_id and (t1.first_length <=" + firstLength + " and t1.second_length<=" + secondLength + ") ");
                        } else {
                            wrapper.innerJoin("(select glass_id, case when height <= width then width else height end as first_length, " +
                                    "case when width < height then width else height end as second_length from edg_storage_cage_details) t1 " +
                                    "on t.glass_id = t1.glass_id and (t1.first_length >=" + minFirstLength + " and t1.second_length>=" + minSecondLength + ") ");
                        }
                        GlassInfo one = glassInfoService.getOne(queryWrapper);
                        if (one != null) {
                            EdgStorageCageDetails resultDetails = new EdgStorageCageDetails();
                            BeanUtils.copyProperties(one, resultDetails);
                            glassInfo = resultDetails;
                        } else {
                            log.info("获取笼内玻璃和带进片玻璃为空或者不符合磨边尺寸");
                        }
                    } else {
                        glassInfo = queryMinGlass(list.get(0).getWidth(), list.get(0).getHeight(), glassId);
                    }
                } else if (a09EdgGlass != null && a10EdgGlass != null) {
                    List<EdgStorageCageDetails> a09Count = queryGlassByTaskLine(Const.A09_OUT_TARGET_POSITION);
                    List<EdgStorageCageDetails> a10Count = queryGlassByTaskLine(Const.A10_OUT_TARGET_POSITION);
                    endcell = a09Count.size() > a10Count.size() ? Const.A09_OUT_TARGET_POSITION : Const.A10_OUT_TARGET_POSITION;
                    glassInfo = a09Count.size() > a10Count.size() ? queryMinGlass(a09EdgGlass.getWidth(), a09EdgGlass.getHeight(), glassId)
                            : queryMinGlass(a10EdgGlass.getWidth(), a10EdgGlass.getHeight(), glassId);
                } else {
                    //按照历史任务获取需要执行的路线,如果该条线笼内无玻璃 走其他逻辑
                    endcell = a09EdgGlass == null ? Const.A09_OUT_TARGET_POSITION : Const.A10_OUT_TARGET_POSITION;
                    List<EdgStorageCageDetails> details = queryGlassByTaskLine(endcell);
                    if (CollectionUtil.isEmpty(details)) {
                        int othercell = endcell == Const.A10_OUT_TARGET_POSITION ? Const.A09_OUT_TARGET_POSITION : Const.A10_OUT_TARGET_POSITION;
                        glassInfo = queryChangeGlassInfo(othercell, glassId);
                    } else {
                        glassInfo = a09EdgGlass != null ? queryMinGlass(a09EdgGlass.getWidth(), a09EdgGlass.getHeight(), glassId)
                                : queryMinGlass(a10EdgGlass.getWidth(), a10EdgGlass.getHeight(), glassId);
                    }
                }
            } else {
                List<EdgStorageCageDetails> edgStorageCageDetails = queryGlassByTaskLine(endcell);
                if (CollectionUtil.isNotEmpty(edgStorageCageDetails)) {
                    glassInfo = edgStorageCageDetails.get(0);
                } else {
                    //获取笼内所有玻璃信息,包括待进片的
                    List<EdgStorageCageDetails> glassList = queryEdgAllGlass(glassId);
                    if (CollectionUtil.isEmpty(glassList)) {
                        log.info("笼内和待进片都没有玻璃");
                        return Boolean.FALSE;
                    }
                    if (glassList.size() == 1 && glassId.equals(glassList.get(0).getGlassId())) {
                        glassInfo = glassList.get(0);
                    } else {
                        int othercell = endcell == Const.A10_OUT_TARGET_POSITION ? Const.A09_OUT_TARGET_POSITION : Const.A10_OUT_TARGET_POSITION;
                        glassInfo = queryChangeGlassInfo(othercell, glassId);
                    }
                }
            }
        }
        EdgStorageCageDetails glassInfo = edgStorageCageDetailsService.selectOutGlass(glassId, threshold);
        log.info("3、按照历史已出玻璃id{}和阈值{},拿出理片笼内的出片信息{}", glassId, threshold, glassInfo);
        return saveOutGlassMessage(glassInfo, endcell, confirmationWrodAddress, glassId, currentSlot);
    }
    /**
     * 获取笼子内所有玻璃信息,包括待进片的
     *
     * @param glassId
     */
    private List<EdgStorageCageDetails> queryEdgAllGlass(String glassId) {
        List<EdgStorageCageDetails> glassList = new ArrayList<>();
        //获取待进片玻璃
        //todo: 获取正在执行的工程信息
        if (StringUtils.isNotBlank(glassId)) {
            GlassInfo one = glassInfoService.getOne(new LambdaQueryWrapper<GlassInfo>()
                    .eq(GlassInfo::getGlassId, glassId));
//                    .inSql(GlassInfo::getEngineerId, "select engineer_id from engineering where state = 1"));
            EdgStorageCageDetails resultDetails = new EdgStorageCageDetails();
            BeanUtils.copyProperties(one, resultDetails);
            glassList.add(resultDetails);
        }
        //获取笼内玻璃
        List<EdgStorageCageDetails> details = edgStorageCageDetailsService.selectJoinList(EdgStorageCageDetails.class, new MPJLambdaWrapper<EdgStorageCageDetails>().selectAll(EdgStorageCageDetails.class)
                .leftJoin(EdgStorageCage.class, on -> on.eq(EdgStorageCage::getSlot, EdgStorageCageDetails::getSlot).eq(EdgStorageCageDetails::getState, Const.GLASS_STATE_IN))
                .eq(EdgStorageCage::getEnableState, Const.SLOT_ON));
        glassList.addAll(details);
        return glassList;
    }
    /**
     * 获取详情表内最大最小版图id的差值,判断是否出最小版图玻璃
     *
     * @return
     */
    public boolean queryMaxMinDiff(int threshold) {
        //获取笼子内最大版图id和最小版图id插值,判断是否大于阈值,大于阈值直接出最小版图玻璃
        QueryWrapper<EdgStorageCageDetails> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("max(tempering_layout_id)-min(tempering_layout_id) as diff")
                .eq("state", Const.GLASS_STATE_IN)
                .inSql("slot", "select slot from edg_storage_cage where enable_state = " + Const.SLOT_ON);
        List<Object> list = edgStorageCageDetailsService.listObjs(queryWrapper);
        //获取笼内玻璃版图差值是否大于阈值
        if (CollectionUtil.isNotEmpty(list)) {
            Long diff = (Long) list.get(0);
            return diff > threshold;
        } else {
            return Boolean.FALSE;
        }
    }
    /**
     * 获取当前最小版图需要出片的玻璃信息
     *
     * @param width
     * @param height
     */
    private EdgStorageCageDetails queryMinGlass(double width, double height, String glassId) {
        //获取表内版图id最小的玻璃信息
        EdgStorageCageDetails glassDetails = edgStorageCageDetailsService.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>()
                .eq(EdgStorageCageDetails::getState, 100)
                .eq(width != 0, EdgStorageCageDetails::getWidth, width)
                .eq(height != 0, EdgStorageCageDetails::getHeight, height)
                .inSql(EdgStorageCageDetails::getSlot, "select slot from edg_storage_cage where enable_state = " + Const.SLOT_ON)
                .orderByAsc(EdgStorageCageDetails::getTemperingLayoutId)
                .orderBy(Boolean.TRUE, sequenceOrder, EdgStorageCageDetails::getTemperingFeedSequence)
                .last("limit 1"));
        if (StringUtils.isBlank(glassId)) {
            return glassDetails;
        }
        GlassInfo one = glassInfoService.getOne(new LambdaQueryWrapper<GlassInfo>()
                        .eq(GlassInfo::getGlassId, glassId)
//                .inSql(GlassInfo::getEngineerId, "select engineer_id from engineering where state = 1")
        );
        EdgStorageCageDetails resultDetails = new EdgStorageCageDetails();
        BeanUtils.copyProperties(one, resultDetails);
        if (null == glassDetails) {
            return resultDetails;
        }
        return resultDetails.getTemperingLayoutId() <= glassDetails.getTemperingLayoutId() && resultDetails.getTemperingFeedSequence() > glassDetails.getTemperingFeedSequence() ?
                resultDetails : glassDetails;
    }
    /**
     * 获取任务表中指定线路笼子内还剩余的玻璃信息
     */
    private List<EdgStorageCageDetails> queryGlassByTaskLine(int line) {
        //获取任务表中最后一次出片的玻璃id
        TaskCache taskCache = taskCacheService.queryGlassByTaskCache(line, Const.GLASS_CACHE_TYPE_OUT_ALL);
        if (null == taskCache) {
            log.info("没有找到{}线任务信息", line);
            return new ArrayList<>();
        }
        MPJQueryWrapper<EdgStorageCageDetails> mpjLambdaWrapper = new MPJQueryWrapper<>();
        mpjLambdaWrapper.select("t1.*")
                .innerJoin("edg_storage_cage_details t1 on t.width = t1.width and t.height = t1.height")
                .eq("t.glass_id", taskCache.getGlassId())
                .ne("t1.glass_id", taskCache.getGlassId())
                .eq("t1.state", Const.GLASS_STATE_IN)
                .inSql("t1.slot", "select slot from edg_storage_cage where enable_state = " + Const.SLOT_ON)
                .orderByAsc("t1.tempering_layout_id")
                .orderBy(Boolean.TRUE, sequenceOrder, "t1.tempering_feed_sequence");
        List<EdgStorageCageDetails> details = edgStorageCageDetailsService.selectJoinList(EdgStorageCageDetails.class, mpjLambdaWrapper);
        if (CollectionUtil.isEmpty(details)) {
            return new ArrayList<>();
        }
        return details;
    }
    /**
     * 按照任务类型、线号获取任务信息
     *
     * @param line
     * @param taskTypes
     * @return
     */
    private EdgStorageCageDetails queryGlassByTaskCache(int line, List<Integer> taskTypes) {
        TaskCache taskCache = taskCacheService.queryGlassByTaskCache(line, taskTypes);
        if (null == taskCache) {
            log.info("没有找到{}线任务信息", line);
            return null;
        }
        return edgStorageCageDetailsService.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>().eq(EdgStorageCageDetails::getGlassId, taskCache.getGlassId())
                .inSql(EdgStorageCageDetails::getSlot, "select slot from edg_storage_cage where enable_state = " + Const.SLOT_ON)
                .last(" limit 1 "));
    }
    /**
     * 按照任务玻璃信息和待出片玻璃信息获取出片路径
     *
     * @param a08EdgStorageCageDetails 09号线出片玻璃信息
     * @param a10EdgStorageCageDetails 10号线出片玻璃信息
     * @param glassInfo                带出片玻璃信息
     * @param out08Glassstate          09号线空闲状态
     * @param out10Glassstate          10号线空闲状态
     * @return
     */
    private Integer queryLineByGlassInfo(EdgStorageCageDetails a08EdgStorageCageDetails, EdgStorageCageDetails a10EdgStorageCageDetails,
                                         EdgStorageCageDetails glassInfo, int out08Glassstate, int out10Glassstate) {
        //存在出片任务 07为空
        if (out08Glassstate == 1 && out10Glassstate == 1) {
            boolean b08 = a08EdgStorageCageDetails != null && a08EdgStorageCageDetails.getHeight() == glassInfo.getHeight()
                    && a08EdgStorageCageDetails.getWidth() == glassInfo.getWidth();
            boolean b10 = a10EdgStorageCageDetails != null && a10EdgStorageCageDetails.getHeight() == glassInfo.getHeight()
                    && a10EdgStorageCageDetails.getWidth() == glassInfo.getWidth();
            if (b08) {
                return Const.A09_OUT_TARGET_POSITION;
            }
            if (b10) {
                return Const.A10_OUT_TARGET_POSITION;
            }
        }
        return computerLineByState(out08Glassstate, out10Glassstate);
    }
    /**
     * 按照尺寸出玻璃
     *
     * @param endcell endcell = out08Glassstate == 1 ? Const.A09_OUT_TARGET_POSITION : Const.A10_OUT_TARGET_POSITION;
     * @param glassId
     * @return
     */
    public EdgStorageCageDetails queryChangeGlassInfo(int endcell, String glassId) {
        //获取笼子内数量前二的玻璃数量
        MPJQueryWrapper<EdgStorageCageDetails> wrapper = new MPJQueryWrapper<>();
        wrapper.select("count(t.glass_id) as count, t.width, t.height")
                .eq("t.state", Const.GLASS_STATE_IN)
                .inSql("t.slot", "select slot from edg_storage_cage where enable_state = " + Const.SLOT_ON)
                .groupBy("t.width, t.height");
        if (endcell == Const.A10_OUT_TARGET_POSITION) {
            wrapper.innerJoin("(select glass_id, case when height <= width then width else height end as first_length, " +
                    "case when width < height then width else height end as second_length from edg_storage_cage_details) t1 " +
                    "on t.glass_id = t1.glass_id and (t1.first_length <=" + firstLength + " and t1.second_length<=" + secondLength + ") ");
        } else {
            wrapper.innerJoin("(select glass_id, case when height <= width then width else height end as first_length, " +
                    "case when width < height then width else height end as second_length from edg_storage_cage_details) t1 " +
                    "on t.glass_id = t1.glass_id and (t1.first_length >=" + minFirstLength + " and t1.second_length>=" + minSecondLength + ") ");
        }
        wrapper.last("order by count(t.glass_id) desc  limit 2");
        List<EdgStorageCageDetails> list = edgStorageCageDetailsService.list(wrapper);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        log.info("获取笼子内数量前二的玻璃数量:{}", list);
        //获取宽高拍第一的玻璃信息
        EdgStorageCageDetails firstSize = list.get(0);
        Integer firstCount = firstSize.getCount();
        double firstWidth = firstSize.getWidth();
        double firstHeight = firstSize.getHeight();
        if (list.size() == 1) {
            return queryMinGlass(firstWidth, firstHeight, glassId);
        }
        //获取宽高拍第二的玻璃信息
        EdgStorageCageDetails secondSize = list.get(1);
        Integer secondCount = secondSize.getCount();
        double secondWidth = secondSize.getWidth();
        double secondHeight = secondSize.getHeight();
        //获取数量前2的玻璃数量比例
        Integer mix = firstCount / secondCount;
        log.info("获取玻璃数量前2的玻璃占比为:{}", mix);
        if (mix >= 2) {
            log.info("获取玻璃数量前2的玻璃占比为{},大于2,直接出玻璃数据的最多的,宽:{},高:{}", mix, firstWidth, firstHeight);
            return queryMinGlass(firstWidth, firstHeight, glassId);
        } else {
            log.info("获取玻璃数量前2的玻璃占比为{},小于2", mix);
            //获取任务表中最后一次出片的玻璃id
            TaskCache taskCache = taskCacheService.queryGlassByTaskCache(endcell, Const.GLASS_CACHE_TYPE_OUT_ALL);
            log.info("获取任务表中{}线最后一次出片的玻璃任务信息:{}", endcell, taskCache);
            if (null == taskCache) {
                log.info("{}线没有出片任务信息,直接出片", endcell);
                return queryMinGlass(firstSize.getWidth(), firstSize.getHeight(), glassId);
            }
            EdgStorageCageDetails outGlassInfo = edgStorageCageDetailsService.getOne(new LambdaQueryWrapper<EdgStorageCageDetails>()
                    .eq(EdgStorageCageDetails::getGlassId, taskCache.getGlassId()));
            log.info("{}线有出片任务信息,任务信息为{},玻璃信息为{}", endcell, taskCache, outGlassInfo);
            if (outGlassInfo.getWidth() == firstWidth && outGlassInfo.getHeight() == firstHeight) {
                log.info("数量最多的宽{}高{}和{}线任务的宽{}高{}相同,出数量排第二的玻璃,宽{}高{}",
                        firstWidth, firstHeight, endcell, outGlassInfo.getWidth(), outGlassInfo.getHeight(), secondWidth, secondHeight);
                return queryMinGlass(secondWidth, secondHeight, glassId);
            } else {
                log.info("数量第二多的宽{}高{}和{}线任务的宽{}高{}相同,出数量排第二的玻璃,宽{}高{}",
                        secondWidth, secondHeight, endcell, outGlassInfo.getWidth(), outGlassInfo.getHeight(), firstWidth, firstHeight);
                return queryMinGlass(firstWidth, firstHeight, glassId);
            }
        }
    }
    /**
     * 保存出片任务相关信息
     *
     * @param glassInfo
     * @param endcell
     * @param confirmationWrodAddress
     * @param glassId
     * @return
     */
    private boolean saveOutGlassMessage(EdgStorageCageDetails glassInfo, int endcell, String confirmationWrodAddress, String glassId, Integer currentSlot) {
        if (glassInfo != null) {
            log.info("4、添加出片任务,玻璃id:{},任务类型:{},起始位置:{},结束位置:{}", glassInfo.getGlassId(),
                    2, glassInfo.getSlot(), endcell);
            TaskCache taskCache = new TaskCache();
            taskCache.setGlassId(glassInfo.getGlassId());
            taskCache.setTaskStatus(0);
            taskCache.setStartCell(glassInfo.getSlot());
            taskCache.setEndCell(endcell);
            taskCache.setTaskType(2);
            taskCache.setCreateTime(new Date());
            taskCacheService.insertTaskCache(taskCache);
            S7object.getinstance().plccontrol.WriteWord(confirmationWrodAddress, (short) 1);
            if (glassInfo.getGlassId().equals(glassId)) {
                log.info("5、直通任务,将玻璃信息插入卧式理片笼,当前玻璃信息:{}", glassInfo);
                EdgStorageCageDetails details = new EdgStorageCageDetails();
                BeanUtils.copyProperties(glassInfo, details);
                EdgStorageCage nearestEmpty = edgStorageCageService.selectNearestEmpty(currentSlot, Boolean.TRUE);
                Assert.isTrue(null != nearestEmpty, "格子已满,无法执行直通任务");
                log.info("3、查询卧式理片笼里面的空格:{}", nearestEmpty);
                details.setSlot(nearestEmpty.getSlot());
                details.setState(Const.GLASS_STATE_OUT);
                edgStorageCageDetailsService.save(details);
                boolean taskCacheStatus = saveTaskCache(glassInfo.getGlassId(), nearestEmpty.getSlot(), endcell, Const.GLASS_CACHE_TYPE_THROUGH);
                log.info("6、添加出片任务是否完成:{}", taskCacheStatus);
            } else {
                log.info("5、非直通任务,将玻璃信息插入卧式理片笼,当前玻璃信息:{}", glassInfo);
                LambdaUpdateWrapper<EdgStorageCageDetails> wrapper = new LambdaUpdateWrapper<>();
                wrapper.eq(EdgStorageCageDetails::getGlassId, glassInfo.getGlassId()).set(EdgStorageCageDetails::getState, Const.GLASS_STATE_OUT);
                edgStorageCageDetailsService.update(wrapper);
                log.info("5、更新出片玻璃的状态为{}", Const.GLASS_STATE_OUT);
                boolean taskCacheStatus = saveTaskCache(glassInfo.getGlassId(), glassInfo.getSlot(), endcell, Const.GLASS_CACHE_TYPE_OUT);
                log.info("6、添加出片任务是否完成:{}", taskCacheStatus);
            }
            boolean glassSizeStatus = saveGlassSize(glassInfo, endcell);
            log.info("7、添加出片玻璃尺寸信息到磨边前玻璃表是否完成:{}", glassSizeStatus);
            S7object.getinstance().plccontrol.writeWord(confirmationWrodAddress, 1);
            log.info("8、发送确认字已完成");
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }
    /**
     * 添加理片笼任务
     *
     * @param glassId
     * @param startcell
     * @param endcell
     * @param taskType
     * @return
     */
    private boolean saveTaskCache(String glassId, int startcell, int endcell, int taskType) {
        TaskCache taskCache = new TaskCache();
        taskCache.setGlassId(glassId);
        taskCache.setTaskStatus(0);
        taskCache.setStartCell(startcell);
        taskCache.setEndCell(endcell);
        taskCache.setTaskType(taskType);
        taskCache.setCreateTime(new Date());
        return taskCacheService.save(taskCache);
    }
    /**
     * 添加理片笼任务
     *
     * @param glassInfo
     * @param endcell
     * @return
     */
    private boolean saveGlassSize(EdgStorageCageDetails glassInfo, int endcell) {
        EdgGlassTaskInfo edgGlassTaskInfo = new EdgGlassTaskInfo();
        BeanUtils.copyProperties(glassInfo, edgGlassTaskInfo);
        edgGlassTaskInfo.setHeight((int) (glassInfo.getHeight() * ratio));
        edgGlassTaskInfo.setWidth((int) (glassInfo.getWidth() * ratio));
        edgGlassTaskInfo.setThickness((int) (glassInfo.getThickness() * ratio));
        edgGlassTaskInfo.setStatus(Const.EDG_GLASS_BEFORE);
        edgGlassTaskInfo.setLine(endcell);
        edgGlassTaskInfo.setTime(new Date());
        return edgGlassTaskInfoService.save(edgGlassTaskInfo);
    }
    /**
     * 计算出片线路
     * 已排除都为2  都为0 的情况
     *
     * @param out08Glassstate
     * @param out10Glassstate
     * @return
     */
    private int computerLineByState(int out08Glassstate, int out10Glassstate) {
        if (out08Glassstate == 0) {
            if (out10Glassstate == 2) {
                return Const.A09_OUT_TARGET_POSITION;
            } else {
                return Const.A10_OUT_TARGET_POSITION;
            }
        } else if (out08Glassstate == 1) {
            return Const.A09_OUT_TARGET_POSITION;
        } else {
            return Const.A10_OUT_TARGET_POSITION;
        }
    }
    @Scheduled(fixedDelay = 1000)
    public void CacheGlassTasks() {
        JSONObject jsonObject = new JSONObject();
        //识别摆片
        List<Map<String, Object>> currentCutTerritorys = edgStorageCageDetailsService.selectCutTerritory();
        jsonObject.append("currentCutTerritory", currentCutTerritorys);
        //磨边信息
        List<Map<String, Object>> EdgTasks1 = taskCacheService.selectEdgInfo("2001");
        List<Map<String, Object>> EdgTasks2 = taskCacheService.selectEdgInfo("2002");
        jsonObject.append("EdgTasks1", EdgTasks1);
        jsonObject.append("EdgTasks2", EdgTasks2);
        //卧室缓存笼内信息
        List<Map<String, Object>> EdgStorageCageinfos = edgStorageCageService.selectEdgStorageCages();
        jsonObject.append("EdgStorageCageinfos", EdgStorageCageinfos);
        ArrayList<WebSocketServer> sendwServer = WebSocketServer.sessionMap.get("cacheGlass");
        if (sendwServer != null) {
            for (WebSocketServer webserver : sendwServer) {
                if (webserver != null) {
                    webserver.sendMessage(jsonObject.toString());
                    List<String> messages = webserver.getMessages();
                    if (!messages.isEmpty()) {
                        // // 将最后一个消息转换为整数类型的列表
                        webserver.clearMessages();
                    }
                } else {
                    log.info("Home is closed");
                }
            }
        }
    }