package com.mes.component; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType; import com.github.xingshuangs.iot.protocol.s7.service.S7PLC; import com.mes.ui.CacheData; import com.mes.ui.DataUtil; import com.mes.ui.MesClient; import com.mes.util.JdbcUtils; import com.mes.util.TCPClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class WorkJPanelOP40 extends JPanel { public static final Logger log = LoggerFactory.getLogger(WorkJPanelOP40.class); public String oprno = "OP055"; public String pos = "A"; public String lastSn = ""; // 最近的码 public String lineSn = "CZ060"; public JLabel feedinglabel; public JLabel feedingmeslabel; public JLabel runlabel; //运行反馈, public JLabel blankinglabel; // 下料反馈 public JLabel blankingmeslabel; // 下料MES反馈 public JLabel feedingtodevicelabel; // 上料到设备 public JLabel feedingtotransferlabel; // 上料到中转车 public JLabel transfertodevicelabel; // 上料到中转车 public JButton scanBtn; public JTextField productSn; public JTextField productSnFeeding; public JButton status_menu; public JButton resetBtn; public JButton resetFeedingBtn; public JButton submitBtn; // 手动提交按钮 public JButton signalBtn; // 信号监控按钮 public PlcSignalMonitor signalMonitor; // 信号监控组件 public ImageIcon imageGreen; public ImageIcon imageGray; public String plcIp1 = "192.168.90.83"; // plc3 public String plcIp2 = "192.168.90.84"; // plc4 public S7PLC s7PLC = null; public Integer workWidth = 470; public Integer workHeight = 300; public String plcDb = ""; public Integer tjFeedingFlag = 0; // 上料状态标识 public Integer tjFlag = 0; // 1=可加工 2=设备运行中 3=加工结束 public Integer tjTransferStatus = 0; // 中转台提交标识 public Integer tjQualityStatus = 0; // 质量上传标识 // 扫码重试机制 private int scanRetryCount = 0; private static final int MAX_SCAN_RETRY = 2; // 最大重试2次 // 用于检测状态变化的上一次值 private Boolean lastRetBlanking = null; private Boolean lastRetFeeding = null; private Boolean lastRetRunning = null; private Boolean lastTransferToDevice = null; private Boolean lastToDevice = null; private Boolean lastToTransfer = null; private Integer lastTjFlag = null; private Integer lastTjFeedingFlag = null; private Integer lastTjTransferStatus = null; private Integer lastTjQualityStatus = null; private String lastProductSn = null; private String lastProductSnFeeding = null; public Boolean toDevice = false; public Boolean toTransfer = false; public Boolean transferToDevice = false; public Boolean plcHeart = false; public Integer isLocal = 0; // 0=正式 1=本地 public Integer isScan = 1; // 1=西侧 2=东测 public CacheData cacheData = null; public String cacheName = ""; public WorkJPanelOP40(String position){ this.setLayout(null); this.setBackground(Color.WHITE); this.pos = position; cacheName = "cache_"+oprno+pos; cacheData = JdbcUtils.getCache(cacheName); if(cacheData == null){ cacheData = new CacheData(); cacheData.setLastSn(""); cacheData.setSn(""); cacheData.setFeedingSn(""); cacheData.setTjStatus(0); cacheData.setTjFlag(0); cacheData.setError(-1); cacheData.setMsg(""); JdbcUtils.setCache(cacheName, JSON.toJSONString(cacheData)); } // A/B/C 由 mes.side 切换东西侧;D-F 西 / G-L 东 逻辑保留 if(position.equals("A") || position.equals("B") || position.equals("C")){ if(MesClient.isEastSide()){ s7PLC = new S7PLC(EPlcType.S1500, plcIp2); isScan = 2; }else{ s7PLC = new S7PLC(EPlcType.S1500, plcIp1); isScan = 1; } }else if(position.equals("D") || position.equals("E") || position.equals("F")){ s7PLC = new S7PLC(EPlcType.S1500, plcIp1); isScan = 1; }else{ s7PLC = new S7PLC(EPlcType.S1500, plcIp2); isScan = 2; } switch (position){ case "A": plcDb = "DB7000"; break; case "B": plcDb = "DB7001"; break; case "C": plcDb = "DB7002"; break; case "D": plcDb = "DB7003"; break; case "E": plcDb = "DB7004"; break; case "F": plcDb = "DB7005"; break; case "G": plcDb = "DB7000"; break; case "H": plcDb = "DB7001"; break; case "I": plcDb = "DB7002"; break; case "J": plcDb = "DB7003"; break; case "K": plcDb = "DB7004"; break; case "L": plcDb = "DB7005"; break; } JLabel oprnoLabel = new JLabel(oprno+pos); oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER); oprnoLabel.setForeground(Color.BLACK); oprnoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20)); oprnoLabel.setBounds(0, 0, workWidth/5, 25); this.add(oprnoLabel); // 工位标注(东1站-东6站,西1站-西6站) String stationLabel = getStationLabel(position); JLabel stationNameLabel = new JLabel(stationLabel); stationNameLabel.setHorizontalAlignment(SwingConstants.CENTER); stationNameLabel.setForeground(Color.BLACK); stationNameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12)); stationNameLabel.setBounds(0, 25, workWidth/5, 15); this.add(stationNameLabel); status_menu = new JButton("等待请求扫码"); status_menu.setBounds(workWidth/5, 0, workWidth*4/5, 40); status_menu.setForeground(Color.GREEN); status_menu.setForeground(Color.GREEN); status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 16)); status_menu.setBackground(Color.BLACK); this.add(status_menu); JLabel oprnoLabelFeeding = new JLabel("上料"); oprnoLabelFeeding.setHorizontalAlignment(SwingConstants.CENTER); oprnoLabelFeeding.setForeground(Color.BLACK); oprnoLabelFeeding.setFont(new Font("微软雅黑", Font.PLAIN, 20)); oprnoLabelFeeding.setBounds(0, 50, workWidth/5, 40); this.add(oprnoLabelFeeding); productSnFeeding = new JTextField(""); productSnFeeding.setHorizontalAlignment(SwingConstants.CENTER); productSnFeeding.setForeground(Color.BLACK); productSnFeeding.setFont(new Font("微软雅黑", Font.PLAIN, 16)); productSnFeeding.setEditable(false); productSnFeeding.setBounds(workWidth/5, 50, workWidth*3/5, 40); productSnFeeding.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { String sn = productSnFeeding.getText().trim(); if(!sn.isEmpty()){ MesClient.createQRCode(productSnFeeding.getText(),oprno+pos); } } }); this.add(productSnFeeding); JLabel oprnoLabelWork = new JLabel("加工"); oprnoLabelWork.setHorizontalAlignment(SwingConstants.CENTER); oprnoLabelWork.setForeground(Color.BLACK); oprnoLabelWork.setFont(new Font("微软雅黑", Font.PLAIN, 20)); oprnoLabelWork.setBounds(0, 100, workWidth/5, 40); this.add(oprnoLabelWork); productSn = new JTextField(""); productSn.setHorizontalAlignment(SwingConstants.CENTER); productSn.setForeground(Color.BLACK); productSn.setFont(new Font("微软雅黑", Font.PLAIN, 16)); productSn.setEditable(false); productSn.setBounds(workWidth/5, 100, workWidth*3/5, 40); productSn.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { String sn = productSn.getText().trim(); if(!sn.isEmpty()){ MesClient.createQRCode(productSn.getText(),oprno+pos); } } }); this.add(productSn); // scanBtn = new JButton("扫码"); // scanBtn.addActionListener(new ActionListener() { // public void actionPerformed(ActionEvent e) { // log.info("test2:"+productSn.getText()); // barCode(); // } // }); // scanBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png"))); // scanBtn.setFont(new Font("微软雅黑", Font.PLAIN, 32)); // scanBtn.setBounds(0, 160, workWidth/2 - 5, 50); // this.add(scanBtn); resetFeedingBtn = new JButton("刷新"); resetFeedingBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int choice = JOptionPane.showConfirmDialog(null, "确定刷新上料工件吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { resetFeeding(); } } }); // resetFeedingBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png"))); resetFeedingBtn.setFont(new Font("微软雅黑", Font.PLAIN, 22)); resetFeedingBtn.setBounds(workWidth*4/5 + 10, 50, workWidth/5 - 10, 40); this.add(resetFeedingBtn); resetBtn = new JButton("刷新"); resetBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int choice = JOptionPane.showConfirmDialog(null, "确定刷新加工工件吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { resetBlanking(); } } }); // resetBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png"))); resetBtn.setFont(new Font("微软雅黑", Font.PLAIN, 22)); resetBtn.setBounds(workWidth*4/5 + 10, 100, workWidth/5 - 10, 40); this.add(resetBtn); imageGreen = new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")); imageGreen.setImage(imageGreen.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH)); imageGray = new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")); imageGray.setImage(imageGray.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH)); feedinglabel = new JLabel("请求上料"); feedinglabel.setHorizontalAlignment(SwingConstants.LEFT); feedinglabel.setIcon(imageGray); // 默认 0,等 PLC 轮询后再亮 feedinglabel.setForeground(Color.BLACK); feedinglabel.setBounds(0, 150, workWidth/3, 30); this.add(feedinglabel); feedingmeslabel = new JLabel("MES允许上料"); feedingmeslabel.setHorizontalAlignment(SwingConstants.LEFT); feedingmeslabel.setIcon(imageGray); feedingmeslabel.setForeground(Color.BLACK); feedingmeslabel.setBounds(workWidth/3, 150, workWidth/3, 30); feedingmeslabel.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { boolean ret = readAllowFeeding(); int choice = JOptionPane.showConfirmDialog(null, "确定修改MES允许上料结果为"+(ret?"false":"true")+"吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { writeAllowFeeding(!ret); } } }); this.add(feedingmeslabel); runlabel = new JLabel("设备运行中"); runlabel.setHorizontalAlignment(SwingConstants.LEFT); runlabel.setIcon(imageGray); runlabel.setForeground(Color.BLACK); runlabel.setBounds(workWidth*2/3, 150, workWidth/3, 30); this.add(runlabel); blankinglabel = new JLabel("下料请求"); blankinglabel.setHorizontalAlignment(SwingConstants.LEFT); blankinglabel.setIcon(imageGray); blankinglabel.setForeground(Color.BLACK); blankinglabel.setBounds(0, 190, workWidth/3, 30); this.add(blankinglabel); blankingmeslabel = new JLabel("MES允许下料"); blankingmeslabel.setHorizontalAlignment(SwingConstants.LEFT); blankingmeslabel.setIcon(imageGray); blankingmeslabel.setForeground(Color.BLACK); blankingmeslabel.setBounds(workWidth/3, 190, workWidth/3, 30); this.add(blankingmeslabel); blankingmeslabel.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { boolean ret = readAllowBlanking(); int choice = JOptionPane.showConfirmDialog(null, "确定修改MES允许下料结果为"+(ret?"false":"true")+"吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { writeAllowBlanking(!ret); } } }); feedingtodevicelabel = new JLabel("上料到设备"); feedingtodevicelabel.setHorizontalAlignment(SwingConstants.LEFT); feedingtodevicelabel.setIcon(imageGray); feedingtodevicelabel.setForeground(Color.BLACK); feedingtodevicelabel.setBounds(workWidth*2/3, 190, workWidth/3, 30); this.add(feedingtodevicelabel); feedingtotransferlabel = new JLabel("上料到中转车"); feedingtotransferlabel.setHorizontalAlignment(SwingConstants.LEFT); feedingtotransferlabel.setIcon(imageGray); feedingtotransferlabel.setForeground(Color.BLACK); feedingtotransferlabel.setBounds(0, 230, workWidth/3, 30); this.add(feedingtotransferlabel); feedingtotransferlabel.setVisible(MesClient.transferEnabled); transfertodevicelabel = new JLabel("中转车上料到设备"); transfertodevicelabel.setHorizontalAlignment(SwingConstants.LEFT); transfertodevicelabel.setIcon(imageGray); transfertodevicelabel.setForeground(Color.BLACK); transfertodevicelabel.setBounds(workWidth/3, 230, workWidth/3, 30); this.add(transfertodevicelabel); transfertodevicelabel.setVisible(MesClient.transferEnabled); // 手动提交按钮 submitBtn = new JButton("提交"); submitBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12)); submitBtn.setBounds(workWidth*2/3 + 10, 230, 60, 26); submitBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String sn = productSn.getText().trim(); String msg; if(sn.isEmpty() || sn.equals("空结果")){ msg = "确定重置当前工位状态吗?"; }else{ msg = "确定手动提交工件 " + sn + " 并重置状态吗?"; } int choice = JOptionPane.showConfirmDialog(null, msg, "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { manualSubmit(); } } }); this.add(submitBtn); // 信号监控按钮 signalMonitor = new PlcSignalMonitor(s7PLC, plcDb, oprno + pos, MesClient.mesClientFrame); signalBtn = signalMonitor.createSignalButton(); signalBtn.setBounds(workWidth*2/3 + 64, 230, 90, 26); this.add(signalBtn); this.startOprnoTimer(); heartData(); resetScanA(); formatElementUI(); } public void formatElementUI(){ cacheData = JdbcUtils.getCache(cacheName); if(cacheData == null){ return; } String msg = cacheData.getMsg(); int error = cacheData.getError(); String sn = cacheData.getSn(); productSn.setText(sn); String feedingSn = cacheData.getFeedingSn(); productSnFeeding.setText(feedingSn); tjFlag = cacheData.getTjFlag(); lastSn = cacheData.getLastSn(); setMenuStatus(msg,error); this.repaint(); } public void setMenuStatus(String msg,int error){ if(error == 0){ this.status_menu.setForeground(Color.GREEN); }else{ this.status_menu.setForeground(Color.RED); } this.status_menu.setText(msg); cacheData.setMsg(msg); cacheData.setError(error); cacheData.setTjFlag(tjFlag); // cacheData.setTjStatus(tjStatus); cacheData.setLastSn(lastSn); cacheData.setSn(productSn.getText()); cacheData.setFeedingSn(productSnFeeding.getText()); JdbcUtils.setCache(cacheName, JSON.toJSONString(cacheData)); } // 定时任务 ----------------------------------------------------------------------------------------------------- public Timer cjTimerText2; public void heartData() { if(cjTimerText2!=null) { cjTimerText2.cancel(); } cjTimerText2 = new Timer(); cjTimerText2.schedule(new TimerTask() { public void run() { if(MesClient.isLogin == 1 && isLocal == 0){ plcHeart = !plcHeart; writeBoolean(plcDb+".0.6",plcHeart); } } }, 1000,1000); } public Timer oprnoTimer; public void startOprnoTimer() { //心跳显示图标 if(oprnoTimer!=null) { oprnoTimer.cancel(); } oprnoTimer = new Timer(); oprnoTimer.schedule(new TimerTask() { public void run() { try{ if(MesClient.isLogin == 1){ Boolean retFeeding = readFeeding(); feedinglabel.setIcon(retFeeding?imageGreen:imageGray); Boolean retFeedingAllow = readAllowFeeding(); feedingmeslabel.setIcon(retFeedingAllow?imageGreen:imageGray); // 与 auto3 一致:PLC 不再请求上料时,清掉 MES 允许上料,避免信号粘滞 if(!retFeeding && retFeedingAllow){ writeAllowFeeding(false); } Boolean retBlanking = readBlanking(); blankinglabel.setIcon(retBlanking?imageGreen:imageGray); Boolean retAllowBlanking = readAllowBlanking(); blankingmeslabel.setIcon(retAllowBlanking?imageGreen:imageGray); toDevice = readFeedingToDevice(); feedingtodevicelabel.setIcon(toDevice?imageGreen:imageGray); toTransfer = MesClient.transferEnabled && readFeedingToTransfer(); if (MesClient.transferEnabled) { feedingtotransferlabel.setIcon(toTransfer?imageGreen:imageGray); } transferToDevice = MesClient.transferEnabled && readFeedingTransferToDevice(); if (MesClient.transferEnabled) { transfertodevicelabel.setIcon(transferToDevice?imageGreen:imageGray); } Boolean retRunning = readRunning(); runlabel.setIcon(retRunning?imageGreen:imageGray); // 无加工码却请求下料:允许下料并复位,防止死锁(对齐 auto3) if(retBlanking && productSn.getText().isEmpty()){ writeAllowBlanking(true); resetBlanking(); } // 只在状态变化时打印日志,减少日志量 String currentProductSn = productSn.getText(); String currentProductSnFeeding = productSnFeeding.getText(); boolean stateChanged = !java.util.Objects.equals(lastRetBlanking, retBlanking) || !java.util.Objects.equals(lastRetFeeding, retFeeding) || !java.util.Objects.equals(lastRetRunning, retRunning) || !java.util.Objects.equals(lastTjFlag, tjFlag) || !java.util.Objects.equals(lastTjFeedingFlag, tjFeedingFlag) || !java.util.Objects.equals(lastTjTransferStatus, tjTransferStatus) || !java.util.Objects.equals(lastTjQualityStatus, tjQualityStatus) || !java.util.Objects.equals(lastTransferToDevice, transferToDevice) || !java.util.Objects.equals(lastToDevice, toDevice) || !java.util.Objects.equals(lastToTransfer, toTransfer) || !java.util.Objects.equals(lastProductSn, currentProductSn) || !java.util.Objects.equals(lastProductSnFeeding, currentProductSnFeeding); if(stateChanged){ log.info("[{}]状态变化: tjFeedingFlag={}, tjFlag={}, tjTransferStatus={}, tjQualityStatus={}, retFeeding={}, retBlanking={}, retRunning={}, toDevice={}, toTransfer={}, transferToDevice={}, productSnFeeding={}, productSn={}", oprno+pos, tjFeedingFlag, tjFlag, tjTransferStatus, tjQualityStatus, retFeeding, retBlanking, retRunning, toDevice, toTransfer, transferToDevice, currentProductSnFeeding, currentProductSn); lastRetBlanking = retBlanking; lastRetFeeding = retFeeding; lastRetRunning = retRunning; lastTjFlag = tjFlag; lastTjFeedingFlag = tjFeedingFlag; lastTjTransferStatus = tjTransferStatus; lastTjQualityStatus = tjQualityStatus; lastTransferToDevice = transferToDevice; lastToDevice = toDevice; lastToTransfer = toTransfer; lastProductSn = currentProductSn; lastProductSnFeeding = currentProductSnFeeding; } if(tjFeedingFlag == 0){ if(retFeeding){ if(MesClient.transferEnabled && plcDb.equals("DB7005") && toTransfer){ log.info("[{}]tjFeedingFlag=0且retFeeding=true且toTransfer=true,触发中转车扫码", oprno+pos); barCodeForTransfer(); } else { log.info("[{}]tjFeedingFlag=0且retFeeding=true,触发工位取码", oprno+pos); barCode(); } } }else if(tjFeedingFlag == 1){ if(tjFlag == 0 && retRunning){ log.info("[{}]tjFeedingFlag=1, tjFlag=0, retRunning=true -> 设置tjFlag=1,工件进入加工位", oprno+pos); tjFlag = 1; productSn.setText(productSnFeeding.getText()); // resetBtn.setEnabled(false); resetFeeding(); } if(MesClient.transferEnabled && toTransfer){ // 去中转台 int transferSn = readTransferNo(); int transferFloor = readTransferFloor(); log.info("[{}]去中转台: transferSn={}, transferFloor={}, tjTransferStatus={}", oprno+pos, transferSn, transferFloor, tjTransferStatus); if(transferSn > 0 && transferFloor > 0){ if(tjTransferStatus == 0) { tjTransferStatus = 1; log.info("[{}]提交中转台数据...", oprno+pos); JSONObject retObj = DataUtil.saveSn(oprno+pos,productSnFeeding.getText().trim(),transferSn,transferFloor,MesClient.user_menu.getText()); log.info("[{}]中转台提交结果: {}", oprno+pos, retObj); if(retObj != null && retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) { tjTransferStatus = 0; resetFeeding(); }else{ tjTransferStatus = 0; if(retObj == null || retObj.get("result")==null){ setMenuStatus("请求失败,请重试",-1); }else if(retObj.get("result").toString().equalsIgnoreCase("false")){ setMenuStatus(retObj.getString("message"),-1); } } } } } } if(tjFlag == 0 && !retBlanking){ writeAllowBlanking(false); } if(tjFlag == 1){ // 只在状态变化时打印,避免日志过多 // log.info("[{}]tjFlag=1, 等待设备运行, toDevice={}, retRunning={}", oprno+pos, toDevice, retRunning); // 当tjFlag=1时,工件已在设备上(无论是直接上料还是中转车上料),只要设备运行中就认为在加工 if(retRunning){ log.info("[{}]tjFlag 1->2,工件加工中", oprno+pos); tjFlag = 2; setMenuStatus("工件加工中", 0); // 运行中清除下料反馈 writeAllowBlanking(false); }else{ } }else if(tjFlag == 2){ // 与 auto3 一致:只认 PLC 请求下料,不停机即报工 if(retBlanking){ upResult(); } }else if(tjFlag == 3){ // 只在状态变化时打印,避免日志过多 // log.info("[{}]tjFlag=3, 等待上传完成重置, tjQualityStatus={}", oprno+pos, tjQualityStatus); } } }catch (Exception e) { log.error(e.getMessage()); } } }, 100,1500); } public void upResult(){ if(tjQualityStatus == 1){ log.info("[{}]tjQualityStatus=1,跳过上传(已在上传中)", oprno+pos); return; } String sn = productSn.getText() == null ? "" : productSn.getText().trim(); if(sn.isEmpty() || sn.equals("空结果")){ log.warn("[{}]下料时加工码为空,允许下料并复位", oprno+pos); writeAllowBlanking(true); resetBlanking(); return; } log.info("[{}]tjFlag 2->3,收到下料信号,准备上传结果, sn={}", oprno+pos, sn); tjFlag = 3; tjQualityStatus = 1; setMenuStatus("工件加工结束,结果上传中", 0); try { JSONObject retObj = DataUtil.sendQuality(sn, oprno+pos, "OK", MesClient.user_menu.getText()); log.info("[{}]质量上传返回结果: {}", oprno+pos, retObj); if(retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) { log.info("[{}]质量上传成功,执行resetBlanking", oprno+pos); resetBlanking(); }else{ tjQualityStatus = 0; tjFlag = 2; if(retObj == null || retObj.get("result") == null){ log.error("[{}]质量上传失败,result为null", oprno+pos); setMenuStatus("请求失败,请重试", -1); }else{ log.error("[{}]质量上传失败: {}", oprno+pos, retObj.getString("message")); setMenuStatus(retObj.getString("message"), -1); } } } catch (Exception e) { tjQualityStatus = 0; tjFlag = 2; log.error("[{}]质量上传异常: {}", oprno+pos, e.getMessage(), e); setMenuStatus("请求失败,请重试", -1); } } public void barCode(){ if(!productSnFeeding.getText().isEmpty()){ return; } String sn = readQrcode(); if(sn == null){ sn = ""; } sn = sn.trim(); if(sn.isEmpty()){ // 对齐 auto3:码未就绪不写死「空结果」,下个轮询继续取 setMenuStatus("等待扫码站扫码", 0); return; } productSnFeeding.setText(sn); lastSn = sn; consumeScanSn(sn); JSONObject retObj = DataUtil.checkQuality(sn, oprno+pos, MesClient.user_menu.getText()); if(retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) { tjFeedingFlag = 1; scanRetryCount = 0; setMenuStatus("工件可以加工", 0); writeAllowFeeding(true); }else{ writeAllowFeeding(false); resetFeedingBtn.setEnabled(true); if(retObj == null || retObj.get("result") == null){ setMenuStatus("请求失败,请重试", -1); }else{ setMenuStatus(retObj.getString("message"), -1); } } } private void consumeScanSn(String sn){ if(sn == null || sn.isEmpty()){ return; } if(isScan == 1 && sn.equals(MesClient.scanSnA)){ MesClient.scanSnA = ""; }else if(isScan == 2 && sn.equals(MesClient.scanSnB)){ MesClient.scanSnB = ""; } } /** * 专门给中转车扫码的方法(仅工位F/L使用) * 触发摄像头扫码,但码赋值给中转车的productSnFeeding,不影响工位6的状态 */ public void barCodeForTransfer(){ // 获取对应的中转车面板 WorkJPanelOP40Transfer transferPanel = null; if(pos.equals("F")){ transferPanel = MesClient.workJPanelOP40Transfer1; } else if(pos.equals("L")){ transferPanel = MesClient.workJPanelOP40Transfer2; } if(transferPanel == null){ log.error("[{}]barCodeForTransfer: 找不到对应的中转车面板", oprno+pos); return; } // 判断是否为有效工件码(排除"空结果"等无效值) String currentSn = transferPanel.productSnFeeding.getText().trim(); boolean isValidSn = !currentSn.isEmpty() && !currentSn.equals("空结果"); // 如果中转车已有有效码,跳过扫码 if(isValidSn){ log.info("[{}]barCodeForTransfer: 中转车已有有效码({}),跳过扫码", oprno+pos, currentSn); return; } // 如果是无效码(如"空结果"),检查重试次数 if(!currentSn.isEmpty() && !isValidSn){ if(transferPanel.scanRetryCount > WorkJPanelOP40Transfer.MAX_SCAN_RETRY){ log.info("[{}]barCodeForTransfer: 已达最大重试次数({}),等待人工处理", oprno+pos, transferPanel.scanRetryCount); return; } // 清空无效码,准备重试 log.info("[{}]barCodeForTransfer: 检测到无效码({}),准备重试(第{}次)", oprno+pos, currentSn, transferPanel.scanRetryCount + 1); transferPanel.productSnFeeding.setText(""); } // 触发摄像头扫码 String sn = ""; if(isScan == 1){ log.info("[{}]触发西侧摄像头扫码(给中转车)", oprno+pos); // sn = MesClient.scanQrcode1(); sn = MesClient.scanSnA; }else{ log.info("[{}]触发东侧摄像头扫码(给中转车)", oprno+pos); // sn = MesClient.scanQrcode2(); sn = MesClient.scanSnB; } log.info("[{}]中转车扫码完成,结果: {}", oprno+pos, sn); // // 如果中转车已有有效码,跳过扫码 // if(isValidSn){ // if(sn.equals(currentSn)){ // log.info("[{}]barCodeForTransfer: 中转车已有有效码({}),跳过扫码", oprno+pos, currentSn); // return; // } // } if(sn.equals("")){ transferPanel.scanRetryCount++; // 扫码失败,增加重试计数 transferPanel.productSnFeeding.setText("空结果"); if(transferPanel.scanRetryCount > WorkJPanelOP40Transfer.MAX_SCAN_RETRY){ transferPanel.setMenuStatus("扫码失败(已重试" + transferPanel.scanRetryCount + "次),请人工处理", -1); log.warn("[{}]中转车扫码失败,已达最大重试次数,等待人工处理", oprno+pos); }else{ transferPanel.setMenuStatus("扫码结果为空,准备重试", -1); log.info("[{}]中转车扫码失败,将在3秒后重试(第{}次)", oprno+pos, transferPanel.scanRetryCount); } }else{ // 码赋值给中转车的productSnFeeding transferPanel.productSnFeeding.setText(sn); transferPanel.lastSn = sn; // 校验工件质量 JSONObject retObj = DataUtil.checkQuality(sn, oprno+pos, MesClient.user_menu.getText()); if(retObj.get("result")!=null && retObj.get("result").toString().equalsIgnoreCase("true")) { transferPanel.tjFeedingFlag = 1; transferPanel.setMenuStatus("工件校验通过,准备保存", 0); // 调用saveSn保存到数据库 int transferSn = readTransferNo(); int transferFloor = readTransferFloor(); log.info("[{}]中转车扫码成功,准备saveSn: sn={}, transferSn={}, transferFloor={}", oprno+pos, sn, transferSn, transferFloor); if(transferSn > 0 && transferFloor > 0){ JSONObject saveRet = DataUtil.saveSn(oprno+pos, sn, transferSn, transferFloor, MesClient.user_menu.getText()); log.info("[{}]saveSn结果: {}", oprno+pos, saveRet); if(saveRet.get("result")!=null && saveRet.get("result").toString().equalsIgnoreCase("true")) { writeAllowFeeding(true); transferPanel.setMenuStatus("工件已保存到中转车", 0); }else{ writeAllowFeeding(false); if(saveRet.get("result")==null){ transferPanel.setMenuStatus("保存失败,请重试", -1); }else{ transferPanel.setMenuStatus(saveRet.getString("message"), -1); } } }else{ log.error("[{}]中转车号或层数无效: transferSn={}, transferFloor={}", oprno+pos, transferSn, transferFloor); transferPanel.setMenuStatus("中转车号或层数无效", -1); writeAllowFeeding(false); } }else{ writeAllowFeeding(false); transferPanel.resetFeedingBtn.setEnabled(true); if(retObj.get("result")==null){ transferPanel.setMenuStatus("请求失败,请重试", -1); }else{ if(retObj.get("result").toString().equalsIgnoreCase("false")){ transferPanel.setMenuStatus(retObj.getString("message"), -1); } } } } } public void resetBlanking() { log.info("[{}]resetBlanking执行: tjFlag {} -> 0, tjQualityStatus {} -> 0", oprno+pos, tjFlag, tjQualityStatus); tjFlag = 0; tjQualityStatus = 0; productSn.setText(""); setMenuStatus("工件结果已提交,等待下一件",0); resetBtn.setEnabled(true); // writeAllowFeeding(false); // writeAllowBlanking(false); } public void resetFeeding() { log.info("[{}]resetFeeding执行: tjFeedingFlag {} -> 0", oprno+pos, tjFeedingFlag); productSnFeeding.setText(""); tjFeedingFlag = 0; tjTransferStatus = 0; // 重置中转台状态 scanRetryCount = 0; // 重置扫码重试计数 setMenuStatus("等待物料扫码",0); resetFeedingBtn.setEnabled(true); writeAllowFeeding(false); } public void resetScanA() { tjFeedingFlag = 0; tjFlag = 0; tjTransferStatus = 0; tjQualityStatus = 0; scanRetryCount = 0; productSn.setText(""); productSnFeeding.setText(""); // setMenuStatus("等待请求扫码",0); resetBtn.setEnabled(true); resetFeedingBtn.setEnabled(true); // 延迟写入PLC,避免初始化时连接超时 if(MesClient.isLogin == 1) { writeAllowFeeding(false); writeAllowBlanking(false); } } // 手动提交方法 public void manualSubmit() { String sn = productSn.getText().trim(); if(sn.isEmpty() || sn.equals("空结果")){ // 无码:直接重置状态,不提交 log.info("[{}]手动重置(无码)", oprno+pos); resetScanA(); setMenuStatus("已重置,等待下一件", 0); }else{ // 有码:先提交再重置 log.info("[{}]手动提交: sn={}", oprno+pos, sn); JSONObject retObj = DataUtil.sendQuality(sn, oprno+pos, "OK", MesClient.user_menu.getText()); log.info("[{}]手动提交结果: {}", oprno+pos, retObj); if(retObj.get("result")!=null && retObj.get("result").toString().equalsIgnoreCase("true")) { resetScanA(); setMenuStatus("提交成功,等待下一件", 0); }else{ if(retObj.get("result")==null){ setMenuStatus("提交失败,请重试", -1); }else{ setMenuStatus(retObj.getString("message"), -1); } } } } // 与设备交互----------------------------------------------------------------------------------------- // 请求扫码 public boolean readFeeding(){ if(isLocal == 1){ return false; }else{ return readBoolean(plcDb+".0.0"); } } // 读取上料到设备 public boolean readFeedingToDevice(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".0.7"); } } // 读取上料到中转车 public boolean readFeedingToTransfer(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".1.0"); } } // 读取中转车上料到设备 public boolean readFeedingTransferToDevice(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".1.1"); } } // 读取下料信号 public boolean readBlanking(){ if(isLocal == 1){ return false; }else{ return readBoolean(plcDb+".0.1"); } } // 读取设备运行信号 public boolean readRunning(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".0.2"); } } // 读取设备通讯状态 public boolean readDeviceStatus(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".0.3"); } } // 读取MES允许上料信号 public boolean readAllowFeeding(){ if(isLocal == 1){ return false; }else{ return readBoolean(plcDb+".0.4"); } } // 写入MES允许上料信号 public boolean writeAllowFeeding(Boolean b){ if(isLocal == 1){ return true; } // 判断MES是否屏蔽 if(isScan == 1 && !MesClient.mesEnabledWest){ log.info("[{}]西侧MES已屏蔽,跳过writeAllowFeeding({})", oprno+pos, b); return true; } if(isScan == 2 && !MesClient.mesEnabledEast){ log.info("[{}]东侧MES已屏蔽,跳过writeAllowFeeding({})", oprno+pos, b); return true; } return writeBoolean(plcDb+".0.4",b); } // 读取MES允许下料信号 public boolean readAllowBlanking(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".0.5"); } } // 写入MES允许下料信号 public boolean writeAllowBlanking(Boolean b){ if(isLocal == 1){ return true; } // 判断MES是否屏蔽 if(isScan == 1 && !MesClient.mesEnabledWest){ log.info("[{}]西侧MES已屏蔽,跳过writeAllowBlanking({})", oprno+pos, b); return true; } if(isScan == 2 && !MesClient.mesEnabledEast){ log.info("[{}]东侧MES已屏蔽,跳过writeAllowBlanking({})", oprno+pos, b); return true; } return writeBoolean(plcDb+".0.5",b); } // 读取中转车号 public int readTransferNo(){ if(isLocal == 1){ return 1; }else{ return s7PLC.readInt16(plcDb+".2.0"); } } // 读取中转车层数 public int readTransferFloor(){ if(isLocal == 1){ return 1; }else{ return s7PLC.readInt16(plcDb+".4.0"); } } // 控制扫码枪读取二维码 public String readQrcode(){ // String sn = "5001040043561010006"; String sn = ""; if(isLocal == 1){ return ""; }else{ try{ if(MesClient.transferEnabled && transferToDevice){ // 中转车上料到设备 int transferSn = readTransferNo(); int transferFloor = readTransferFloor(); log.info("[{}]中转车上料到设备: transferSn={}, transferFloor={}", oprno+pos, transferSn, transferFloor); JSONObject retObj = DataUtil.getSn(oprno+pos,transferSn,transferFloor,MesClient.user_menu.getText()); log.info("[{}]getSn返回结果: {}", oprno+pos, retObj); if(retObj != null && retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) { sn = retObj.getString("data"); log.info("[{}]中转车获取到工件码: {}", oprno+pos, sn); this.setMenuStatus("允许工件加工",0); }else{ if(retObj == null || retObj.get("result")==null){ log.error("[{}]getSn失败: result为null", oprno+pos); this.setMenuStatus("请求失败,请重试",-1); }else if(retObj.get("result").toString().equalsIgnoreCase("false")){ log.error("[{}]getSn失败: {}", oprno+pos, retObj.getString("message")); this.setMenuStatus(retObj.getString("message"),-1); } } }else{ if(isScan == 1){ sn = MesClient.scanSnA == null ? "" : MesClient.scanSnA; }else{ sn = MesClient.scanSnB == null ? "" : MesClient.scanSnB; } } log.info("[{}]扫码完成,结果: {}", oprno+pos, sn); }catch (Exception e) { e.printStackTrace(); } } return sn; } public boolean readBoolean(String db){ boolean permit; try { // 检查PLC连接是否可用 if(s7PLC == null) { return false; } permit = s7PLC.readBoolean(db); // log.info("<"+this.oprno+this.pos+">读取"+db+"-->成功,结果:{}", permit ? "true" : "false"); } catch (Exception e) { // 连接超时时不打印完整堆栈,只记录简要信息 if(e.getMessage() != null && e.getMessage().contains("connect timed out")) { // 连接超时是常见情况,降低日志级别 // log.debug("<"+this.oprno+this.pos+">读取"+db+"-->连接超时"); } else { log.error("<"+this.oprno+this.pos+">读取"+db+"-->失败: {}", e.getMessage()); } return false; } return permit; } public boolean writeBoolean(String db, boolean permit){ try { // 检查PLC连接是否可用 if(s7PLC == null) { log.warn("<"+this.oprno+this.pos+">PLC未初始化,跳过写入"+db); return false; } s7PLC.writeBoolean(db,permit); // log.info("<"+this.oprno+this.pos+">写入"+db+"-->成功,写入内容:{}", permit ? "true" : "false"); } catch (Exception e) { // 连接超时时不打印完整堆栈,只记录简要信息 if(e.getMessage() != null && e.getMessage().contains("connect timed out")) { log.warn("<"+this.oprno+this.pos+">写入"+db+"-->连接超时(PLC未连接)"); } else { log.error("<"+this.oprno+this.pos+">写入"+db+"-->失败,写入内容:{}", permit ? "true" : "false"); log.error(e.getMessage()); } return false; } return true; } // 获取工位站点标注 private String getStationLabel(String position) { String side = MesClient.isEastSide() ? "东侧" : "西侧"; switch (position) { case "A": return side + "1号机"; case "B": return side + "2号机"; case "C": return side + "3号机"; case "D": return "西侧4号机"; case "E": return "西侧5号机"; case "F": return "西侧6号机"; case "G": return "东侧1号机"; case "H": return "东侧2号机"; case "I": return "东侧3号机"; case "J": return "东侧4号机"; case "K": return "东侧5号机"; case "L": return "东侧6号机"; default: return ""; } } }