|
@@ -3,7 +3,6 @@ package com.mes.component;
|
|
|
import com.mes.ui.DataUtil;
|
|
import com.mes.ui.DataUtil;
|
|
|
import com.mes.ui.MesClient;
|
|
import com.mes.ui.MesClient;
|
|
|
import com.mes.ui.Oprno;
|
|
import com.mes.ui.Oprno;
|
|
|
-import com.mes.util.S7PLCUtils;
|
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
@@ -11,43 +10,58 @@ import javax.swing.*;
|
|
|
import java.awt.*;
|
|
import java.awt.*;
|
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionEvent;
|
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.ActionListener;
|
|
|
-import java.awt.event.FocusAdapter;
|
|
|
|
|
-import java.awt.event.FocusEvent;
|
|
|
|
|
|
|
+import java.awt.event.MouseAdapter;
|
|
|
|
|
+import java.awt.event.MouseEvent;
|
|
|
import java.util.Timer;
|
|
import java.util.Timer;
|
|
|
import java.util.TimerTask;
|
|
import java.util.TimerTask;
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * OP120 单台 CNC 面板:独立轮询、独立工件数据。
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 状态:0 等待上料 → 1 质量检查 → 2 加工中等下料 → 3 已下料等 OK/NG → 4 已交结果并写下料反馈
|
|
|
|
|
+ */
|
|
|
public class MesClientComponent extends JPanel {
|
|
public class MesClientComponent extends JPanel {
|
|
|
|
|
|
|
|
public static final Logger log = LoggerFactory.getLogger(MesClientComponent.class);
|
|
public static final Logger log = LoggerFactory.getLogger(MesClientComponent.class);
|
|
|
- // 工位类
|
|
|
|
|
|
|
+
|
|
|
public Oprno oprnoClass = new Oprno();
|
|
public Oprno oprnoClass = new Oprno();
|
|
|
- // 工位号
|
|
|
|
|
- // 线体
|
|
|
|
|
- public static String lineSn = "XT";
|
|
|
|
|
- // 输入框
|
|
|
|
|
public JTextField productSn;
|
|
public JTextField productSn;
|
|
|
- // 状态栏
|
|
|
|
|
public JButton status_menu;
|
|
public JButton status_menu;
|
|
|
- // 宽度
|
|
|
|
|
- public static Integer workWidth = 350;
|
|
|
|
|
- // 高度
|
|
|
|
|
- public static Integer workHeight = 400;
|
|
|
|
|
- // 扫码按钮
|
|
|
|
|
|
|
+ public static Integer workWidth = 255;
|
|
|
|
|
+ public static Integer workHeight = 320;
|
|
|
|
|
+
|
|
|
public JButton scanBtn;
|
|
public JButton scanBtn;
|
|
|
- // 刷新按钮
|
|
|
|
|
public JButton resetBtn;
|
|
public JButton resetBtn;
|
|
|
- // 工作状态
|
|
|
|
|
- // 0:未扫码,等待允许扫码信号 1:扫码成功,质量检查 2:质量合格,开始做件 3:加工完成,提交结果
|
|
|
|
|
- public Integer work_status = 0;
|
|
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 0:等待上料完成
|
|
|
|
|
+ * 1:已读码,质量检查中
|
|
|
|
|
+ * 2:上料完成反馈已写,加工中,等待下料完成
|
|
|
|
|
+ * 3:已见下料,等待 OK/NG 并提交 MES
|
|
|
|
|
+ * 4:结果已提交且下料反馈已写,等待信号复位
|
|
|
|
|
+ */
|
|
|
|
|
+ public Integer work_status = 0;
|
|
|
|
|
|
|
|
|
|
+ /** 上料完成反馈(可手动点击翻转) */
|
|
|
public JLabel sllabel1;
|
|
public JLabel sllabel1;
|
|
|
-
|
|
|
|
|
|
|
+ /** 下料完成反馈(可手动点击翻转) */
|
|
|
public JLabel sllabel2;
|
|
public JLabel sllabel2;
|
|
|
|
|
+ /** 工位状态:正常/故障 */
|
|
|
|
|
+ public JLabel stationStatusLabel;
|
|
|
|
|
+ /** 加工结果展示 */
|
|
|
|
|
+ public JLabel resultLabel;
|
|
|
|
|
|
|
|
|
|
+ private boolean loadEdgeHandled = false;
|
|
|
|
|
+ private boolean resultHandled = false;
|
|
|
|
|
+ private boolean unloadEdgeHandled = false;
|
|
|
|
|
+ private boolean lastLoadComplete = false;
|
|
|
|
|
+ private boolean lastUnloadComplete = false;
|
|
|
|
|
+ /** 本轮是否已发送过 AQDW,避免每秒重复发 */
|
|
|
|
|
+ private boolean aqdwSent = false;
|
|
|
|
|
+ /** 上一次工位状态(用于故障恢复后还原状态栏) */
|
|
|
|
|
+ private Boolean lastStationOk = null;
|
|
|
|
|
|
|
|
- // UI(布局随 workWidth、workHeight 缩放,避免写死 350×400 下的像素坐标)
|
|
|
|
|
- public MesClientComponent(Oprno opno){
|
|
|
|
|
|
|
+ public MesClientComponent(Oprno opno) {
|
|
|
oprnoClass = opno;
|
|
oprnoClass = opno;
|
|
|
int w = workWidth;
|
|
int w = workWidth;
|
|
|
int h = workHeight;
|
|
int h = workHeight;
|
|
@@ -56,15 +70,16 @@ public class MesClientComponent extends JPanel {
|
|
|
this.setBorder(BorderFactory.createLineBorder(Color.GRAY));
|
|
this.setBorder(BorderFactory.createLineBorder(Color.GRAY));
|
|
|
|
|
|
|
|
int margin = Math.max(8, w / 40);
|
|
int margin = Math.max(8, w / 40);
|
|
|
- int hTitle = Math.max(36, (int) Math.round(h * 0.15));
|
|
|
|
|
- int hStatus = Math.max(32, (int) Math.round(h * 0.15));
|
|
|
|
|
- int hSn = Math.max(32, (int) Math.round(h * 0.15));
|
|
|
|
|
- int hBtn = Math.max(40, (int) Math.round(h * 0.15));
|
|
|
|
|
- int hLab = Math.max(28, (int) Math.round(h * 0.125));
|
|
|
|
|
|
|
+ int hTitle = Math.max(36, (int) Math.round(h * 0.12));
|
|
|
|
|
+ int hStatus = Math.max(32, (int) Math.round(h * 0.12));
|
|
|
|
|
+ int hSn = Math.max(32, (int) Math.round(h * 0.12));
|
|
|
|
|
+ int hBtn = Math.max(40, (int) Math.round(h * 0.12));
|
|
|
|
|
+ int hLab = Math.max(28, (int) Math.round(h * 0.1));
|
|
|
|
|
+ int hFeedback = Math.max(44, (int) Math.round(h * 0.14)); // 反馈行加高,保证圆点完整显示
|
|
|
int gap = Math.max(4, margin / 2);
|
|
int gap = Math.max(4, margin / 2);
|
|
|
|
|
|
|
|
int y = 0;
|
|
int y = 0;
|
|
|
- JLabel oprnoLabel = new JLabel(oprnoClass.getOprno());
|
|
|
|
|
|
|
+ JLabel oprnoLabel = new JLabel(displayOprno(oprnoClass.getOprno()));
|
|
|
oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
oprnoLabel.setForeground(Color.BLACK);
|
|
oprnoLabel.setForeground(Color.BLACK);
|
|
|
int titleFont = Math.max(16, Math.min(36, w / 11));
|
|
int titleFont = Math.max(16, Math.min(36, w / 11));
|
|
@@ -73,7 +88,7 @@ public class MesClientComponent extends JPanel {
|
|
|
this.add(oprnoLabel);
|
|
this.add(oprnoLabel);
|
|
|
y += hTitle;
|
|
y += hTitle;
|
|
|
|
|
|
|
|
- status_menu = new JButton("等待上料信号");
|
|
|
|
|
|
|
+ status_menu = new JButton("等待上料完成");
|
|
|
status_menu.setBounds(margin, y, w - 2 * margin, hStatus);
|
|
status_menu.setBounds(margin, y, w - 2 * margin, hStatus);
|
|
|
status_menu.setForeground(Color.GREEN);
|
|
status_menu.setForeground(Color.GREEN);
|
|
|
status_menu.addActionListener(new ActionListener() {
|
|
status_menu.addActionListener(new ActionListener() {
|
|
@@ -93,28 +108,49 @@ public class MesClientComponent extends JPanel {
|
|
|
productSn.setFont(new Font("微软雅黑", Font.PLAIN, snFont));
|
|
productSn.setFont(new Font("微软雅黑", Font.PLAIN, snFont));
|
|
|
productSn.setEditable(false);
|
|
productSn.setEditable(false);
|
|
|
productSn.setBounds(margin, y, w - 2 * margin, hSn);
|
|
productSn.setBounds(margin, y, w - 2 * margin, hSn);
|
|
|
- productSn.addFocusListener(new FocusAdapter() {
|
|
|
|
|
|
|
+ productSn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
|
|
|
+ productSn.setToolTipText("点击显示二维码");
|
|
|
|
|
+ productSn.setFocusable(false);
|
|
|
|
|
+ productSn.addMouseListener(new MouseAdapter() {
|
|
|
@Override
|
|
@Override
|
|
|
- public void focusGained(FocusEvent e) {
|
|
|
|
|
-
|
|
|
|
|
|
|
+ public void mousePressed(MouseEvent e) {
|
|
|
|
|
+ MesClient.createQRCode(productSn.getText(), oprnoClass.getOprno());
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
this.add(productSn);
|
|
this.add(productSn);
|
|
|
y += hSn + gap;
|
|
y += hSn + gap;
|
|
|
|
|
|
|
|
- scanBtn = new JButton("扫码");
|
|
|
|
|
|
|
+ stationStatusLabel = new JLabel("工位状态: --");
|
|
|
|
|
+ stationStatusLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
|
|
+ stationStatusLabel.setFont(new Font("微软雅黑", Font.PLAIN, Math.max(12, w / 18)));
|
|
|
|
|
+ stationStatusLabel.setBounds(0, y, w / 2, hLab);
|
|
|
|
|
+ this.add(stationStatusLabel);
|
|
|
|
|
+
|
|
|
|
|
+ resultLabel = new JLabel("结果: --");
|
|
|
|
|
+ resultLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
|
|
+ resultLabel.setFont(new Font("微软雅黑", Font.PLAIN, Math.max(12, w / 18)));
|
|
|
|
|
+ resultLabel.setBounds(w / 2, y, w - w / 2, hLab);
|
|
|
|
|
+ this.add(resultLabel);
|
|
|
|
|
+ y += hLab + gap;
|
|
|
|
|
+
|
|
|
|
|
+ scanBtn = new JButton("读码");
|
|
|
final MesClientComponent thisComponent = this;
|
|
final MesClientComponent thisComponent = this;
|
|
|
scanBtn.addActionListener(new ActionListener() {
|
|
scanBtn.addActionListener(new ActionListener() {
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
public void actionPerformed(ActionEvent e) {
|
|
|
- System.out.println("扫码");
|
|
|
|
|
thisComponent.scanBtnClick();
|
|
thisComponent.scanBtnClick();
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
- scanBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
|
|
|
|
|
- int btnFont = Math.max(16, Math.min(32, w / 10));
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ ImageIcon raw = new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png"));
|
|
|
|
|
+ Image scaled = raw.getImage().getScaledInstance(18, 18, Image.SCALE_SMOOTH);
|
|
|
|
|
+ scanBtn.setIcon(new ImageIcon(scaled));
|
|
|
|
|
+ } catch (Exception ignored) {
|
|
|
|
|
+ }
|
|
|
|
|
+ int btnFont = Math.max(14, Math.min(18, w / 14));
|
|
|
scanBtn.setFont(new Font("微软雅黑", Font.PLAIN, btnFont));
|
|
scanBtn.setFont(new Font("微软雅黑", Font.PLAIN, btnFont));
|
|
|
- int btnGap = gap;
|
|
|
|
|
- int btnW = (w - 2 * margin - btnGap) / 2;
|
|
|
|
|
|
|
+ scanBtn.setMargin(new Insets(2, 4, 2, 4));
|
|
|
|
|
+ scanBtn.setIconTextGap(4);
|
|
|
|
|
+ int btnW = (w - 2 * margin - gap) / 2;
|
|
|
scanBtn.setBounds(margin, y, btnW, hBtn);
|
|
scanBtn.setBounds(margin, y, btnW, hBtn);
|
|
|
this.add(scanBtn);
|
|
this.add(scanBtn);
|
|
|
|
|
|
|
@@ -124,55 +160,133 @@ public class MesClientComponent extends JPanel {
|
|
|
resetBtnClick();
|
|
resetBtnClick();
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
- resetBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ ImageIcon raw = new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png"));
|
|
|
|
|
+ Image scaled = raw.getImage().getScaledInstance(18, 18, Image.SCALE_SMOOTH);
|
|
|
|
|
+ resetBtn.setIcon(new ImageIcon(scaled));
|
|
|
|
|
+ } catch (Exception ignored) {
|
|
|
|
|
+ }
|
|
|
resetBtn.setFont(new Font("微软雅黑", Font.PLAIN, btnFont));
|
|
resetBtn.setFont(new Font("微软雅黑", Font.PLAIN, btnFont));
|
|
|
- resetBtn.setBounds(margin + btnW + btnGap, y, btnW, hBtn);
|
|
|
|
|
|
|
+ resetBtn.setMargin(new Insets(2, 4, 2, 4));
|
|
|
|
|
+ resetBtn.setIconTextGap(4);
|
|
|
|
|
+ resetBtn.setBounds(margin + btnW + gap, y, btnW, hBtn);
|
|
|
this.add(resetBtn);
|
|
this.add(resetBtn);
|
|
|
y += hBtn + gap;
|
|
y += hBtn + gap;
|
|
|
|
|
|
|
|
- sllabel1 = new JLabel("上料允许");
|
|
|
|
|
|
|
+ sllabel1 = new JLabel("上料完成反馈");
|
|
|
sllabel1.setHorizontalAlignment(SwingConstants.CENTER);
|
|
sllabel1.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
- sllabel1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
|
|
|
|
|
|
|
+ sllabel1.setVerticalAlignment(SwingConstants.CENTER);
|
|
|
|
|
+ sllabel1.setIcon(dot(false));
|
|
|
sllabel1.setForeground(Color.BLACK);
|
|
sllabel1.setForeground(Color.BLACK);
|
|
|
- sllabel1.setBounds(0, y, w / 2, hLab);
|
|
|
|
|
|
|
+ sllabel1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
|
|
|
+ sllabel1.setToolTipText("点击手动翻转上料完成反馈信号");
|
|
|
|
|
+ sllabel1.setBounds(0, y, w / 2, hFeedback);
|
|
|
|
|
+ sllabel1.addMouseListener(new MouseAdapter() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void mouseClicked(MouseEvent e) {
|
|
|
|
|
+ toggleFeedback(true);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
this.add(sllabel1);
|
|
this.add(sllabel1);
|
|
|
- sllabel2 = new JLabel("下料允许");
|
|
|
|
|
|
|
+
|
|
|
|
|
+ sllabel2 = new JLabel("下料完成反馈");
|
|
|
sllabel2.setHorizontalAlignment(SwingConstants.CENTER);
|
|
sllabel2.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
- sllabel2.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
|
|
|
|
|
|
|
+ sllabel2.setVerticalAlignment(SwingConstants.CENTER);
|
|
|
|
|
+ sllabel2.setIcon(dot(false));
|
|
|
sllabel2.setForeground(Color.BLACK);
|
|
sllabel2.setForeground(Color.BLACK);
|
|
|
- sllabel2.setBounds(w / 2, y, w - w / 2, hLab);
|
|
|
|
|
|
|
+ sllabel2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
|
|
|
+ sllabel2.setToolTipText("点击手动翻转下料完成反馈信号");
|
|
|
|
|
+ sllabel2.setBounds(w / 2, y, w - w / 2, hFeedback);
|
|
|
|
|
+ sllabel2.addMouseListener(new MouseAdapter() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void mouseClicked(MouseEvent e) {
|
|
|
|
|
+ toggleFeedback(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
this.add(sllabel2);
|
|
this.add(sllabel2);
|
|
|
|
|
|
|
|
this.startOprnoTimer();
|
|
this.startOprnoTimer();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 扫码按钮
|
|
|
|
|
- public void scanBtnClick() {
|
|
|
|
|
- if (work_status != 0) {
|
|
|
|
|
- status_menu.setText("工件加工中,请勿重复扫码");
|
|
|
|
|
|
|
+ /** 面板标题:MES工位号 + CNC序号 */
|
|
|
|
|
+ private static String displayOprno(String oprno) {
|
|
|
|
|
+ if ("OP120A".equals(oprno)) {
|
|
|
|
|
+ return "OP120A / CNC1";
|
|
|
|
|
+ }
|
|
|
|
|
+ if ("OP120B".equals(oprno)) {
|
|
|
|
|
+ return "OP120B / CNC2";
|
|
|
|
|
+ }
|
|
|
|
|
+ if ("OP120C".equals(oprno)) {
|
|
|
|
|
+ return "OP120C / CNC3";
|
|
|
|
|
+ }
|
|
|
|
|
+ if ("OP120D".equals(oprno)) {
|
|
|
|
|
+ return "OP120D / CNC4";
|
|
|
|
|
+ }
|
|
|
|
|
+ return oprno;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private ImageIcon dot(boolean on) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String path = on ? "/bg/green_dot.png" : "/bg/grey_dot.png";
|
|
|
|
|
+ return new ImageIcon(MesClient.class.getResource(path));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 手动翻转上料/下料完成反馈(需输入操作密码) */
|
|
|
|
|
+ private void toggleFeedback(boolean load) {
|
|
|
|
|
+ if (!MesClient.verifyManualPlcPassword(this)) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
- String sn = "";
|
|
|
|
|
- boolean hgA = MesClient.s7PLC.readBoolean(oprnoClass.getHgA_out());
|
|
|
|
|
- boolean hgB = MesClient.s7PLC.readBoolean(oprnoClass.getHgB_out());
|
|
|
|
|
- if (!hgA && !hgB) {
|
|
|
|
|
- sn = "";
|
|
|
|
|
- }
|
|
|
|
|
- if (hgA) {
|
|
|
|
|
- sn = MesClient.s7PLC.readString(oprnoClass.getHgA_sn());
|
|
|
|
|
- }else if (hgB) {
|
|
|
|
|
- sn = MesClient.s7PLC.readString(oprnoClass.getHgB_sn());
|
|
|
|
|
- }else {
|
|
|
|
|
- sn = MesClient.s7PLC.readString(oprnoClass.getProduct_sn());
|
|
|
|
|
|
|
+ String addr = load ? oprnoClass.getLoad_feedback() : oprnoClass.getUnload_feedback();
|
|
|
|
|
+ boolean cur = MesClient.s7PLC.readBoolean(addr);
|
|
|
|
|
+ boolean next = !cur;
|
|
|
|
|
+ MesClient.s7PLC.writeBoolean(addr, next);
|
|
|
|
|
+ if (load) {
|
|
|
|
|
+ sllabel1.setIcon(dot(next));
|
|
|
|
|
+ setMenuStatus("手动设置上料完成反馈=" + next, 0);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ sllabel2.setIcon(dot(next));
|
|
|
|
|
+ setMenuStatus("手动设置下料完成反馈=" + next, 0);
|
|
|
}
|
|
}
|
|
|
- if (sn == null || sn.trim().isEmpty() || "".equals(sn)) {
|
|
|
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
|
+ log.error("手动翻转反馈失败", ex);
|
|
|
|
|
+ setMenuStatus("手动写 PLC 失败", -1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void refreshFeedbackIcons() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ boolean lf = MesClient.s7PLC.readBoolean(oprnoClass.getLoad_feedback());
|
|
|
|
|
+ boolean uf = MesClient.s7PLC.readBoolean(oprnoClass.getUnload_feedback());
|
|
|
|
|
+ sllabel1.setIcon(dot(lf));
|
|
|
|
|
+ sllabel2.setIcon(dot(uf));
|
|
|
|
|
+ } catch (Exception ignored) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 手动读本机二维码并进入质量检查(需输入操作密码) */
|
|
|
|
|
+ public void scanBtnClick() {
|
|
|
|
|
+ if (!MesClient.verifyManualPlcPassword(this)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (work_status != 0 && work_status != 1) {
|
|
|
|
|
+ status_menu.setText("工件加工中,请勿重复读码");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ String sn = MesClient.s7PLC.readString(oprnoClass.getProduct_sn());
|
|
|
|
|
+ if (sn == null || sn.trim().isEmpty()) {
|
|
|
setMenuStatus("扫码结果为空", -1);
|
|
setMenuStatus("扫码结果为空", -1);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
sn = sn.trim();
|
|
sn = sn.trim();
|
|
|
productSn.setText(sn);
|
|
productSn.setText(sn);
|
|
|
work_status = 1;
|
|
work_status = 1;
|
|
|
|
|
+ loadEdgeHandled = true;
|
|
|
|
|
+ aqdwSent = false;
|
|
|
setMenuStatus("已读取工件码,等待校验", 0);
|
|
setMenuStatus("已读取工件码,等待校验", 0);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("读取 PLC 工件码失败", e);
|
|
log.error("读取 PLC 工件码失败", e);
|
|
@@ -180,94 +294,246 @@ public class MesClientComponent extends JPanel {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public Timer oprnoTimer;
|
|
|
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // 定时任务
|
|
|
|
|
- public Timer oprnoTimer;
|
|
|
|
|
public void startOprnoTimer() {
|
|
public void startOprnoTimer() {
|
|
|
- if(oprnoTimer!=null) {
|
|
|
|
|
|
|
+ if (oprnoTimer != null) {
|
|
|
oprnoTimer.cancel();
|
|
oprnoTimer.cancel();
|
|
|
}
|
|
}
|
|
|
oprnoTimer = new Timer();
|
|
oprnoTimer = new Timer();
|
|
|
oprnoTimer.schedule(new TimerTask() {
|
|
oprnoTimer.schedule(new TimerTask() {
|
|
|
public void run() {
|
|
public void run() {
|
|
|
- if (work_status == 0){
|
|
|
|
|
- // 未扫码,等待允许扫码信号
|
|
|
|
|
- // 当遍历出有上料点位为true的工位时
|
|
|
|
|
- if (MesClient.s7PLC.readBoolean(oprnoClass.getHgA_out()) || MesClient.s7PLC.readBoolean(oprnoClass.getHgB_out())) {
|
|
|
|
|
- MesClient.s7PLC.writeBoolean(oprnoClass.getMes_out(),false);
|
|
|
|
|
- String sn = "";
|
|
|
|
|
- boolean hgA = MesClient.s7PLC.readBoolean(oprnoClass.getHgA_out());
|
|
|
|
|
- boolean hgB = MesClient.s7PLC.readBoolean(oprnoClass.getHgB_out());
|
|
|
|
|
- if (hgA) {
|
|
|
|
|
- // 获取A号料
|
|
|
|
|
- sn = MesClient.s7PLC.readString(oprnoClass.getHgA_sn());
|
|
|
|
|
- }
|
|
|
|
|
- if (hgB) {
|
|
|
|
|
- sn = MesClient.s7PLC.readString(oprnoClass.getHgB_sn());
|
|
|
|
|
- }
|
|
|
|
|
- if (sn == null || sn.trim().isEmpty() || "".equals(sn)){
|
|
|
|
|
- setMenuStatus("扫码结果为空", -1);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- productSn.setText(sn);
|
|
|
|
|
- work_status = 1;
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ pollOnce();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error(oprnoClass.getOprno() + " 轮询异常", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 100, 1000);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void pollOnce() {
|
|
|
|
|
+ // 工位状态显示(故障时同步到上方状态栏)
|
|
|
|
|
+ try {
|
|
|
|
|
+ boolean stationOk = MesClient.s7PLC.readBoolean(oprnoClass.getStation_status());
|
|
|
|
|
+ final boolean ok = stationOk;
|
|
|
|
|
+ SwingUtilities.invokeLater(() -> {
|
|
|
|
|
+ if (ok) {
|
|
|
|
|
+ stationStatusLabel.setText("工位状态: 正常");
|
|
|
|
|
+ stationStatusLabel.setForeground(new Color(0, 128, 0));
|
|
|
|
|
+ if (lastStationOk != null && !lastStationOk) {
|
|
|
|
|
+ restoreStatusAfterFault();
|
|
|
}
|
|
}
|
|
|
- }else if (work_status == 1){
|
|
|
|
|
- // 已扫码,等待允许加工信号
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ stationStatusLabel.setText("工位状态: 故障");
|
|
|
|
|
+ stationStatusLabel.setForeground(Color.RED);
|
|
|
|
|
+ setMenuStatus("工位故障", -1);
|
|
|
|
|
+ }
|
|
|
|
|
+ lastStationOk = ok;
|
|
|
|
|
+ });
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ // PLC 未就绪时忽略
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ refreshFeedbackIcons();
|
|
|
|
|
+
|
|
|
|
|
+ boolean loadComplete = false;
|
|
|
|
|
+ boolean unloadComplete = false;
|
|
|
|
|
+ try {
|
|
|
|
|
+ loadComplete = MesClient.s7PLC.readBoolean(oprnoClass.getLoad_complete());
|
|
|
|
|
+ unloadComplete = MesClient.s7PLC.readBoolean(oprnoClass.getUnload_complete());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 上料完成下降沿:仅复位本轮软件标记(不清 PLC 反馈,由 PLC 自行复位)
|
|
|
|
|
+ if (lastLoadComplete && !loadComplete) {
|
|
|
|
|
+ loadEdgeHandled = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ lastLoadComplete = loadComplete;
|
|
|
|
|
+
|
|
|
|
|
+ // 下料完成下降沿:仅复位软件状态;已完成的一轮清码回到 0(不清 PLC 反馈)
|
|
|
|
|
+ if (lastUnloadComplete && !unloadComplete) {
|
|
|
|
|
+ unloadEdgeHandled = false;
|
|
|
|
|
+ if (work_status == 4) {
|
|
|
|
|
+ resetCycleSoft();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ lastUnloadComplete = unloadComplete;
|
|
|
|
|
+
|
|
|
|
|
+ if (work_status == 0) {
|
|
|
|
|
+ if (loadComplete && !loadEdgeHandled) {
|
|
|
|
|
+ String sn = "";
|
|
|
|
|
+ try {
|
|
|
|
|
+ sn = MesClient.s7PLC.readString(oprnoClass.getProduct_sn());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ setMenuStatus("读二维码失败", -1);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (sn == null || sn.trim().isEmpty()) {
|
|
|
|
|
+ setMenuStatus("二维码为空", -1);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ sn = sn.trim();
|
|
|
|
|
+ productSn.setText(sn);
|
|
|
|
|
+ resultLabel.setText("结果: --");
|
|
|
|
|
+ resultLabel.setForeground(Color.BLACK);
|
|
|
|
|
+ loadEdgeHandled = true;
|
|
|
|
|
+ resultHandled = false;
|
|
|
|
|
+ unloadEdgeHandled = false;
|
|
|
|
|
+ aqdwSent = false;
|
|
|
|
|
+ work_status = 1;
|
|
|
|
|
+ setMenuStatus("已读码,质量检查中", 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (work_status == 1) {
|
|
|
|
|
+ String sn = productSn.getText();
|
|
|
|
|
+ if (sn == null || sn.trim().isEmpty()) {
|
|
|
|
|
+ setMenuStatus("读码结果为空", -1);
|
|
|
|
|
+ productSn.setText("");
|
|
|
|
|
+ work_status = 0;
|
|
|
|
|
+ loadEdgeHandled = false;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!aqdwSent) {
|
|
|
|
|
+ Boolean ok = DataUtil.checkQualityByGw(MesClient.nettyClient, sn, MesClient.user20, oprnoClass.getOprno());
|
|
|
|
|
+ if (ok) {
|
|
|
|
|
+ aqdwSent = true;
|
|
|
|
|
+ setMenuStatus("质量检查已发送,等待回复", 0);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setMenuStatus("质量检查消息发送失败", -1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 等 MesRevice 回包后切到 status=2
|
|
|
|
|
+ } else if (work_status == 2) {
|
|
|
|
|
+ // 加工中:先等下料完成,再进结果提交(不下料反馈)
|
|
|
|
|
+ if (unloadComplete) {
|
|
|
|
|
+ work_status = 3;
|
|
|
|
|
+ setMenuStatus("已下料,等待工位 OK/NG", 0);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setMenuStatus("加工中,等待下料", 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (work_status == 3) {
|
|
|
|
|
+ // 已见下料:等 OK/NG → 提交 MES → 再写下料反馈
|
|
|
|
|
+ try {
|
|
|
|
|
+ boolean okBit = MesClient.s7PLC.readBoolean(oprnoClass.getProcess_result_ok());
|
|
|
|
|
+ boolean ngBit = MesClient.s7PLC.readBoolean(oprnoClass.getProcess_result_ng());
|
|
|
|
|
+ if (!resultHandled && (okBit || ngBit)) {
|
|
|
|
|
+ String ret = ngBit ? "NG" : "OK";
|
|
|
String sn = productSn.getText();
|
|
String sn = productSn.getText();
|
|
|
- if (sn == null || sn.trim().isEmpty() || "".equals(sn)) {
|
|
|
|
|
- setMenuStatus("读码结果为空", -1);
|
|
|
|
|
- productSn.setText("");
|
|
|
|
|
- work_status = 0;
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- Boolean checkQualityResult = DataUtil.checkQualityByGw(MesClient.nettyClient, sn,MesClient.user20,oprnoClass.getOprno());
|
|
|
|
|
- if (!checkQualityResult){
|
|
|
|
|
- setMenuStatus("消息发送失败,请重试",-1);
|
|
|
|
|
- }
|
|
|
|
|
- }else if (work_status == 2){
|
|
|
|
|
- if (MesClient.s7PLC.readBoolean(oprnoClass.getOut_ok())){
|
|
|
|
|
- MesClient.s7PLC.writeBoolean(oprnoClass.getMes_in(),false);
|
|
|
|
|
- }
|
|
|
|
|
- if (MesClient.s7PLC.readBoolean(oprnoClass.getProcess_ok())){
|
|
|
|
|
- MesClient.s7PLC.writeBoolean(oprnoClass.getMes_out(),true);
|
|
|
|
|
- String sn = productSn.getText();
|
|
|
|
|
- String ret = "OK";
|
|
|
|
|
- if (MesClient.s7PLC.readBoolean(oprnoClass.getProcess_result_ng())){
|
|
|
|
|
- ret = "NG";
|
|
|
|
|
- }
|
|
|
|
|
- Boolean result = DataUtil.sendQualityByGW(MesClient.nettyClient, sn, ret, MesClient.user20, oprnoClass.getOprno());
|
|
|
|
|
- if (!result){
|
|
|
|
|
- setMenuStatus("消息发送失败,请重试",-1);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Boolean sent = DataUtil.sendQualityByGW(MesClient.nettyClient, sn, ret, MesClient.user20, oprnoClass.getOprno());
|
|
|
|
|
+ if (sent) {
|
|
|
|
|
+ resultHandled = true;
|
|
|
|
|
+ final String show = ret;
|
|
|
|
|
+ SwingUtilities.invokeLater(() -> {
|
|
|
|
|
+ resultLabel.setText("结果: " + show);
|
|
|
|
|
+ resultLabel.setForeground("NG".equals(show) ? Color.RED : new Color(0, 128, 0));
|
|
|
|
|
+ });
|
|
|
|
|
+ setMenuStatus("结果已提交(" + ret + "),写下料反馈", 0);
|
|
|
|
|
+ writeUnloadFeedback();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setMenuStatus("结果提交失败,请重试", -1);
|
|
|
}
|
|
}
|
|
|
- }else if (work_status == 3){
|
|
|
|
|
- productSn.setText("");
|
|
|
|
|
- work_status = 0;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("读取工位结果失败", e);
|
|
|
}
|
|
}
|
|
|
- },100,1000);
|
|
|
|
|
|
|
+ } else if (work_status == 4) {
|
|
|
|
|
+ setMenuStatus("下料完成反馈已写,等待复位", 0);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 刷新
|
|
|
|
|
- public void resetBtnClick() {
|
|
|
|
|
- productSn.setText("");
|
|
|
|
|
- work_status = 0;
|
|
|
|
|
- setMenuStatus("请扫码",0);
|
|
|
|
|
|
|
+ /** 结果已交 MES 后再写下料完成反馈 */
|
|
|
|
|
+ private void writeUnloadFeedback() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ MesClient.s7PLC.writeBoolean(oprnoClass.getUnload_feedback(), true);
|
|
|
|
|
+ unloadEdgeHandled = true;
|
|
|
|
|
+ work_status = 4;
|
|
|
|
|
+ setMenuStatus("结果已提交,下料反馈已写", 0);
|
|
|
|
|
+ refreshFeedbackIcons();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("写下料完成反馈失败", e);
|
|
|
|
|
+ setMenuStatus("写下料完成反馈失败", -1);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** 质量检查通过后由 MesRevice 调用:写上料完成反馈 + MKSW 记开始时间 */
|
|
|
|
|
+ public void onQualityPass(String sn) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ MesClient.s7PLC.writeBoolean(oprnoClass.getLoad_feedback(), true);
|
|
|
|
|
+ DataUtil.startWorkByGw(MesClient.nettyClient, sn, MesClient.user20, oprnoClass.getOprno());
|
|
|
|
|
+ work_status = 2;
|
|
|
|
|
+ setMenuStatus("上料完成反馈已写,加工中", 0);
|
|
|
|
|
+ refreshFeedbackIcons();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("写上料完成反馈失败", e);
|
|
|
|
|
+ setMenuStatus("写上料完成反馈失败", -1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ public void onQualityFail(String msg) {
|
|
|
|
|
+ aqdwSent = false;
|
|
|
|
|
+ setMenuStatus(msg + ",自动重试中…", -1);
|
|
|
|
|
+ // 不写上料反馈;aqdwSent 已清,下一轮轮询会再次发质量检查
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- public void setMenuStatus(String msg,int error){
|
|
|
|
|
- if(error == 0){
|
|
|
|
|
- this.status_menu.setForeground(Color.GREEN);
|
|
|
|
|
- }else{
|
|
|
|
|
- this.status_menu.setForeground(Color.RED);
|
|
|
|
|
|
|
+ /** 工位从故障恢复后,按当前流程阶段还原状态栏文案 */
|
|
|
|
|
+ private void restoreStatusAfterFault() {
|
|
|
|
|
+ switch (work_status) {
|
|
|
|
|
+ case 0:
|
|
|
|
|
+ setMenuStatus("等待上料完成", 0);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ setMenuStatus(aqdwSent ? "质量检查已发送,等待回复" : "已读码,质量检查中", 0);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ setMenuStatus("加工中,等待下料", 0);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ setMenuStatus("已下料,等待工位 OK/NG", 0);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 4:
|
|
|
|
|
+ setMenuStatus("结果已提交,下料反馈已写", 0);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- this.status_menu.setText(msg);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void resetCycleSoft() {
|
|
|
|
|
+ productSn.setText("");
|
|
|
|
|
+ resultLabel.setText("结果: --");
|
|
|
|
|
+ resultLabel.setForeground(Color.BLACK);
|
|
|
|
|
+ work_status = 0;
|
|
|
|
|
+ resultHandled = false;
|
|
|
|
|
+ aqdwSent = false;
|
|
|
|
|
+ setMenuStatus("等待上料完成", 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 刷新复位本机面板状态(需输入操作密码):清空 SN/结果,状态回到等待上料,允许重新跑一轮 */
|
|
|
|
|
+ public void resetBtnClick() {
|
|
|
|
|
+ if (!MesClient.verifyManualPlcPassword(this)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ productSn.setText("");
|
|
|
|
|
+ resultLabel.setText("结果: --");
|
|
|
|
|
+ resultLabel.setForeground(Color.BLACK);
|
|
|
|
|
+ work_status = 0;
|
|
|
|
|
+ loadEdgeHandled = false;
|
|
|
|
|
+ resultHandled = false;
|
|
|
|
|
+ unloadEdgeHandled = false;
|
|
|
|
|
+ aqdwSent = false;
|
|
|
|
|
+ lastStationOk = null;
|
|
|
|
|
+ setMenuStatus("等待上料完成", 0);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ public void setMenuStatus(String msg, int error) {
|
|
|
|
|
+ SwingUtilities.invokeLater(() -> {
|
|
|
|
|
+ if (error == 0) {
|
|
|
|
|
+ this.status_menu.setForeground(Color.GREEN);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.status_menu.setForeground(Color.RED);
|
|
|
|
|
+ }
|
|
|
|
|
+ this.status_menu.setText(msg);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|