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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Timer; import java.util.TimerTask; public class WorkJPanelScan extends JPanel { public static final Logger log = LoggerFactory.getLogger(WorkJPanelScan.class); public String oprno = "OP055"; public String pos = "A"; public String lastSn = ""; // 最近的码 public String lineSn = "CZ060"; /** 兼容现场短码、旧码和 24 位 EVE 长码 */ public static final int SN_LEN_SHORT = 16; public static final int SN_LEN_LEGACY = 19; public static final int SN_LEN_EVE = 24; 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 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 = "DB35"; public Integer tjFeedingFlag = 0; // 上料状态标识 public Integer tjFlag = 0; // 1=可加工 2=设备运行中 3=加工结束 public Integer tjStatus = 0; // 提交标识 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 int transferSn = 0; public int transferFloor = 0; public CacheData cacheData = null; public String cacheName = ""; private Boolean lastScanRequest = null; private boolean scanCompletedForRequest = false; private String manualPendingSn = ""; public WorkJPanelScan(String position){ this.setLayout(null); this.setBackground(Color.WHITE); this.pos = position; if(position.equals("A")){ s7PLC = new S7PLC(EPlcType.S1500, plcIp1); }else{ s7PLC = new S7PLC(EPlcType.S1500, plcIp2); } cacheName = "cache_scan_"+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)); } JLabel oprnoLabel = new JLabel(oprno); oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER); oprnoLabel.setForeground(Color.BLACK); oprnoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20)); oprnoLabel.setBounds(0, 0, workWidth/5, 40); this.add(oprnoLabel); if(this.pos.equals("A")){ oprnoLabel.setText("西侧"); }else{ oprnoLabel.setText("东侧"); } 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(true); productSnFeeding.setToolTipText("可手动输入工件码后按回车确认"); productSnFeeding.setBounds(workWidth/5, 50, workWidth*3/5, 40); productSnFeeding.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { applyManualSn(); } } }); productSnFeeding.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() >= 2) { String sn = productSnFeeding.getText().trim(); if (!sn.isEmpty()) { MesClient.createQRCode(sn, oprno + pos); } } } }); this.add(productSnFeeding); 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) { resetScanA(); } } }); resetFeedingBtn.setFont(new Font("微软雅黑", Font.PLAIN, 22)); resetFeedingBtn.setBounds(workWidth*4/5 + 10, 50, workWidth/5 - 10, 40); this.add(resetFeedingBtn); 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 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 = readScanFinish(); int choice = JOptionPane.showConfirmDialog(null, "确定修改MES允许扫码结果为"+(ret?"false":"true")+"吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { writeScanFinish(!ret); } } }); this.add(feedingmeslabel); // transfertodevicelabel = new JLabel("中转车上料到设备"); // transfertodevicelabel.setHorizontalAlignment(SwingConstants.LEFT); // transfertodevicelabel.setIcon(imageGreen); // transfertodevicelabel.setForeground(Color.BLACK); // transfertodevicelabel.setBounds(workWidth*2/3, 150, workWidth/3, 30); // this.add(transfertodevicelabel); // // blankinglabel = new JLabel("中转车号"); // blankinglabel.setHorizontalAlignment(SwingConstants.LEFT); // blankinglabel.setIcon(imageGreen); // blankinglabel.setForeground(Color.BLACK); // blankinglabel.setBounds(0, 190, workWidth/3, 30); // this.add(blankinglabel); // // blankingmeslabel = new JLabel("放置层数"); // blankingmeslabel.setHorizontalAlignment(SwingConstants.LEFT); // blankingmeslabel.setIcon(imageGreen); // blankingmeslabel.setForeground(Color.BLACK); // blankingmeslabel.setBounds(workWidth/3, 190, workWidth/3, 30); // this.add(blankingmeslabel); startOprnoTimer(); 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); // 缓存的码只用于历史追踪,不能恢复为当前扫码结果,否则会被误认为本轮已完成 productSnFeeding.setText(""); 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(productSnFeeding.getText()); cacheData.setFeedingSn(productSnFeeding.getText()); JdbcUtils.setCache(cacheName, JSON.toJSONString(cacheData)); } // 定时任务 ----------------------------------------------------------------------------------------------------- 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 = readScanFeeding(); feedinglabel.setIcon(retFeeding?imageGreen:imageGray); Boolean retFeedingAllow = readScanFinish(); feedingmeslabel.setIcon(retFeedingAllow?imageGreen:imageGray); if(retFeeding){ if(!Boolean.TRUE.equals(lastScanRequest)){ startScanRequest(); } if(scanCompletedForRequest){ writeScanFinish(true); }else{ barCode2(); } }else{ scanCompletedForRequest = false; writeScanFinish(false); } lastScanRequest = retFeeding; } }catch (Exception e) { log.error(e.getMessage()); } } }, 100,1500); } private void startScanRequest(){ scanCompletedForRequest = false; productSnFeeding.setText(""); MesClient.clearScanCode(isScan); String pendingSn = manualPendingSn == null ? "" : manualPendingSn.trim(); manualPendingSn = ""; if(isValidSn(pendingSn)){ publishScanResult(pendingSn, "手动录入"); }else{ setMenuStatus("正在扫码", 0); } } public void barCode2(){ String sn = readQrcode(); if(sn == null){ sn = ""; } sn = sn.trim(); if(!isValidSn(sn)){ setMenuStatus("扫码结果为空或格式不符", -1); return; } publishScanResult(sn, "扫码"); } private void publishScanResult(String sn, String source){ MesClient.publishScanCode(isScan, sn); productSnFeeding.setText(sn); scanCompletedForRequest = true; setMenuStatus(source + "成功", 0); if(readScanFeeding()){ writeScanFinish(true); } } /** 手动输入工件码:回车确认,写入全局码并回写 PLC 扫码完成 */ public void applyManualSn(){ String sn = productSnFeeding.getText() == null ? "" : productSnFeeding.getText().trim(); if(sn.isEmpty()){ setMenuStatus("请输入工件码", -1); return; } if(!isValidSn(sn)){ setMenuStatus("工件码应为16、19或24位,当前" + sn.length() + "位", -1); return; } manualPendingSn = sn; productSnFeeding.setText(sn); if(Boolean.TRUE.equals(lastScanRequest)){ publishScanResult(sn, "手动录入"); manualPendingSn = ""; }else{ setMenuStatus("手动录入成功,等待请求扫码", 0); } log.info("[{}]手动录入工件码: {}", oprno + pos, sn); } public static boolean isValidSn(String sn){ if(sn == null){ return false; } int length = sn.trim().length(); return length == SN_LEN_SHORT || length == SN_LEN_LEGACY || length == SN_LEN_EVE; } public void resetFeeding() { productSnFeeding.setText(""); tjFeedingFlag = 0; manualPendingSn = ""; scanCompletedForRequest = false; MesClient.clearScanCode(isScan); setMenuStatus("等待请求扫码",0); resetFeedingBtn.setEnabled(true); // writeAllowFeeding(false); } public void resetScanA() { tjFeedingFlag = 0; tjFlag = 0; tjStatus = 0; // productSnFeeding.setText("5001040043561100050"); productSnFeeding.setText(""); manualPendingSn = ""; scanCompletedForRequest = false; MesClient.clearScanCode(isScan); // setMenuStatus("等待请求扫码",0); if(isLocal == 0){ writeScanFinish(false); } } // 与设备交互----------------------------------------------------------------------------------------- // 请求扫码 public boolean readScanFeeding(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".0.0"); //7002 扫码 } } // 扫码完成 public boolean readScanFinish(){ if(isLocal == 1){ return false; }else{ return readBoolean(plcDb+".0.1"); // MES允许扫码 } } // MES允许扫码 / 扫码完成反馈 public boolean writeScanFinish(boolean bt){ if(isLocal == 1){ return false; }else{ return writeBoolean(plcDb+".0.1",bt); } } // 读取中转车上料到设备 public boolean readFeedingTransferToDevice(){ if(isLocal == 1){ return true; }else{ return readBoolean(plcDb+".0.2"); } } // 读取中转车号 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(this.pos.equals("A")){ sn = MesClient.scanQrcode1(); }else{ sn = MesClient.scanQrcode2(); } }catch (Exception e) { e.printStackTrace(); } } return sn; } public boolean readBoolean(String db){ boolean permit; try { permit = s7PLC.readBoolean(db); // log.info("<"+this.oprno+this.pos+">读取"+db+"-->成功,结果:{}", permit ? "true" : "false"); } catch (Exception e) { log.error("<"+this.oprno+this.pos+">读取"+db+"-->失败", e); return false; } return permit; } public boolean writeBoolean(String db, boolean permit){ try { s7PLC.writeBoolean(db,permit); // log.info("<"+this.oprno+this.pos+">写入"+db+"-->成功,写入内容:{}", permit ? "true" : "false"); } catch (Exception e) { // log.error("<"+this.oprno+this.pos+">写入"+db+"-->失败,写入内容:{}", permit ? "true" : "false"); log.error(e.getMessage(), e); return false; } return true; } }