张田野 1 неделя назад
Родитель
Сommit
3f95f7daef

+ 13 - 9
.classpath

@@ -1,24 +1,28 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
 		<attributes>
 			<attribute name="module" value="true"/>
 		</attributes>
 	</classpathentry>
-    <classpathentry kind="src" path="image"/>
+	<classpathentry kind="src" path="image"/>
 	<classpathentry excluding="resources/" kind="src" path="src"/>
 	<classpathentry kind="src" path="src/resources"/>
 	<classpathentry kind="output" path="bin"/>
-	<classpathentry kind="lib" path="lib/s7connector-2.1.jar"/>
-	<classpathentry kind="lib" path="lib/slf4j-api-2.0.6.jar"/>
-	<classpathentry kind="lib" path="lib/okhttp-4.10.0.jar"/>
-	<classpathentry kind="lib" path="lib/kotlin-stdlib-1.8.10.jar"/>
-	<classpathentry kind="lib" path="lib/okio-jvm-3.3.0.jar"/>
+	<classpathentry kind="lib" path="lib/commons-codec-1.15.jar"/>
+	<classpathentry kind="lib" path="lib/fastjson2-2.0.16.jar"/>
 	<classpathentry kind="lib" path="lib/gson-2.10.jar"/>
+	<classpathentry kind="lib" path="lib/iot-communication-1.4.4.jar"/>
 	<classpathentry kind="lib" path="lib/jfreechart-1.5.4.jar"/>
+	<classpathentry kind="lib" path="lib/jSerialComm-2.6.2.jar"/>
 	<classpathentry kind="lib" path="lib/jshortcut-0.4-oberzalek.jar"/>
+	<classpathentry kind="lib" path="lib/kotlin-stdlib-1.8.10.jar"/>
+	<classpathentry kind="lib" path="lib/logback-classic-1.2.13.jar"/>
+	<classpathentry kind="lib" path="lib/logback-core-1.2.13.jar"/>
 	<classpathentry kind="lib" path="lib/netty-all-4.1.48.Final.jar"/>
+	<classpathentry kind="lib" path="lib/okhttp-4.10.0.jar"/>
+	<classpathentry kind="lib" path="lib/okio-jvm-3.3.0.jar"/>
+	<classpathentry kind="lib" path="lib/s7connector-2.1.jar"/>
+	<classpathentry kind="lib" path="lib/slf4j-api-1.7.36.jar"/>
 	<classpathentry kind="lib" path="lib/sqlite-jdbc-3.36.0.3.jar"/>
-	<classpathentry kind="lib" path="lib/commons-codec-1.15.jar"/>
-	<classpathentry kind="lib" path="lib/fastjson2-2.0.16.jar"/>
 </classpath>

BIN
lib/core-3.5.1.jar


BIN
lib/javase-3.5.1.jar


+ 393 - 130
src/com/mes/component/MesClientComponent.java

@@ -3,7 +3,6 @@ package com.mes.component;
 import com.mes.ui.DataUtil;
 import com.mes.ui.MesClient;
 import com.mes.ui.Oprno;
-import com.mes.util.S7PLCUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -11,43 +10,58 @@ import javax.swing.*;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 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.TimerTask;
 
+/**
+ * OP170 单台 CNC 面板:独立轮询、独立工件数据。
+ * <p>
+ * 状态:0 等待上料 → 1 质量检查 → 2 加工中等下料 → 3 已下料等 OK/NG → 4 已交结果并写下料反馈
+ */
 public class MesClientComponent extends JPanel {
 
     public static final Logger log = LoggerFactory.getLogger(MesClientComponent.class);
-    // 工位类
+
     public Oprno oprnoClass = new Oprno();
-    // 工位号
-    // 线体
-    public static String lineSn = "XT";
-    // 输入框
     public JTextField productSn;
-    // 状态栏
     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 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 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;
         int w = workWidth;
         int h = workHeight;
@@ -56,15 +70,16 @@ public class MesClientComponent extends JPanel {
         this.setBorder(BorderFactory.createLineBorder(Color.GRAY));
 
         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 y = 0;
-        JLabel oprnoLabel = new JLabel(oprnoClass.getOprno());
+        JLabel oprnoLabel = new JLabel(displayOprno(oprnoClass.getOprno()));
         oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER);
         oprnoLabel.setForeground(Color.BLACK);
         int titleFont = Math.max(16, Math.min(36, w / 11));
@@ -73,7 +88,7 @@ public class MesClientComponent extends JPanel {
         this.add(oprnoLabel);
         y += hTitle;
 
-        status_menu = new JButton("等待上料信号");
+        status_menu = new JButton("等待上料完成");
         status_menu.setBounds(margin, y, w - 2 * margin, hStatus);
         status_menu.setForeground(Color.GREEN);
         status_menu.addActionListener(new ActionListener() {
@@ -93,28 +108,49 @@ public class MesClientComponent extends JPanel {
         productSn.setFont(new Font("微软雅黑", Font.PLAIN, snFont));
         productSn.setEditable(false);
         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
-            public void focusGained(FocusEvent e) {
-
+            public void mousePressed(MouseEvent e) {
+                MesClient.createQRCode(productSn.getText(), oprnoClass.getOprno());
             }
         });
         this.add(productSn);
         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;
         scanBtn.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
-                System.out.println("扫码");
                 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));
-        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);
         this.add(scanBtn);
 
@@ -124,55 +160,130 @@ public class MesClientComponent extends JPanel {
                 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.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);
         y += hBtn + gap;
 
-        sllabel1 = new JLabel("上料允许");
+        sllabel1 = new JLabel("上料完成反馈");
         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.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);
-        sllabel2 = new JLabel("下料允许");
+
+        sllabel2 = new JLabel("下料完成反馈");
         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.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.startOprnoTimer();
     }
 
-    // 扫码按钮
-    public void scanBtnClick() {
-        if (work_status != 0) {
-            status_menu.setText("工件加工中,请勿重复扫码");
+    /** 面板标题:MES工位号 + CNC序号 */
+    private static String displayOprno(String oprno) {
+        if ("OP170A".equals(oprno)) {
+            return "OP170A / CNC1";
+        }
+        if ("OP170B".equals(oprno)) {
+            return "OP170B / CNC2";
+        }
+        if ("OP170C".equals(oprno)) {
+            return "OP170C / CNC3";
+        }
+        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;
         }
         try {
-            String sn = "";
-            boolean hgA = MesClient.s7PLC.readBoolean(oprnoClass.getHgA_out());
-            boolean hgB = MesClient.s7PLC.readBoolean(oprnoClass.getHgB_out());
-            if (!hgA && !hgB) {
-                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 (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());
-            }
-            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);
                 return;
             }
             sn = sn.trim();
             productSn.setText(sn);
             work_status = 1;
+            loadEdgeHandled = true;
+            aqdwSent = false;
             setMenuStatus("已读取工件码,等待校验", 0);
         } catch (Exception e) {
             log.error("读取 PLC 工件码失败", e);
@@ -180,94 +291,246 @@ public class MesClientComponent extends JPanel {
         }
     }
 
+    public Timer oprnoTimer;
 
-
-
-    // 定时任务
-    public  Timer oprnoTimer;
     public void startOprnoTimer() {
-        if(oprnoTimer!=null) {
+        if (oprnoTimer != null) {
             oprnoTimer.cancel();
         }
         oprnoTimer = new Timer();
         oprnoTimer.schedule(new TimerTask() {
             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();
-                    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);
+        });
+    }
 }

+ 1 - 1
src/com/mes/ui/DataUtil.java

@@ -331,7 +331,7 @@ public class DataUtil {
             pro.load(br);
             String start = "aaaabbbbbABW";
             String gy = "GY" + rightPad(craft, 6);
-            gw = "GW" + gw;
+            gw = "GW" + rightPad(gw, 6);
             String reslx = "LX" + rightPad(lx, 2);
             String id = pro.getProperty("mes.line_sn") + rightPad(sn, 36);
             String rs = "RS"+ rightPad(result, 2);

+ 2 - 5
src/com/mes/ui/LoginFarme.java

@@ -183,11 +183,8 @@ public class LoginFarme extends JFrame {
                     MesClient.welcomeWin.setVisible(false);
                     MesClient.mesClientFrame.setVisible(true);
 
-                    if(MesClient.jfxPanel == null){
-                        String url = "http://"+ MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/work?oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn;
-                        MesClient.jfxPanel = new MesWebView(url);
-                        MesClient.jfxPanel.setSize(990, 550);
-                        MesClient.indexPanelB.add(MesClient.jfxPanel);
+                    if(!MesClient.workRecordInited){
+                        MesClient.initWorkRecordTabs();
                     }
 
                     if(MesClient.jfxPanel2 == null){

+ 137 - 29
src/com/mes/ui/MesClient.java

@@ -3,6 +3,10 @@ package com.mes.ui;
 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.google.zxing.BarcodeFormat;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
 import com.mes.component.MesClientComponent;
 import com.mes.component.MesRadio;
 import com.mes.component.MesWebView;
@@ -22,6 +26,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
 import java.io.*;
 import java.lang.reflect.Field;
 import java.nio.channels.FileChannel;
@@ -94,6 +99,9 @@ public class MesClient extends JFrame {
     public static MesWebView jfxPanel = null;
     public static JPanel indexPanelC;
     public static MesWebView jfxPanel2 = null;
+    /** 工作记录机台分标签(点哪个加载哪个) */
+    public static JTabbedPane workRecordTabs = null;
+    public static boolean workRecordInited = false;
     public static MesRadio mesRadioHj;
 
     public static JTable table;
@@ -117,8 +125,37 @@ public class MesClient extends JFrame {
     //点检字段
     public static Boolean check_info = false;
 
-    public static S7PLC s7PLC = new S7PLC(EPlcType.S1200,"10.88.10.80");
+    public static S7PLC s7PLC;
 
+    /** 人工点击 PLC 反馈信号时的确认密码 */
+    public static final String MANUAL_PLC_PASSWORD = "503833";
+
+
+    /**
+     * 人工改 PLC 反馈前校验密码;取消或错误则返回 false。
+     */
+    public static boolean verifyManualPlcPassword(Component parent) {
+        JPasswordField pwdField = new JPasswordField(12);
+        int opt = JOptionPane.showConfirmDialog(
+                parent != null ? parent : mesClientFrame,
+                pwdField,
+                "请输入操作密码",
+                JOptionPane.OK_CANCEL_OPTION,
+                JOptionPane.PLAIN_MESSAGE);
+        if (opt != JOptionPane.OK_OPTION) {
+            return false;
+        }
+        String input = new String(pwdField.getPassword());
+        if (!MANUAL_PLC_PASSWORD.equals(input)) {
+            JOptionPane.showMessageDialog(
+                    parent != null ? parent : mesClientFrame,
+                    "密码错误",
+                    "提示窗口",
+                    JOptionPane.WARNING_MESSAGE);
+            return false;
+        }
+        return true;
+    }
 
     public static void main(String[] args) {
 
@@ -167,7 +204,12 @@ public class MesClient extends JFrame {
 
         mes_gw_des = OprnoUtil.getGwDes(mes_line_sn,mes_gw);
 
-        log.info(mes_gw + ";" + mes_gw_des + ";" + mes_server_ip + ";" + mes_tcp_port + ";" + mes_heart_beat_cycle);
+        // PLC
+        String plcIp = pro.getProperty("mes.plc_ip", "10.88.10.80");
+        s7PLC = new S7PLC(EPlcType.S1200, plcIp);
+
+
+        log.info(mes_gw + ";" + mes_gw_des + ";" + mes_server_ip + ";" + mes_tcp_port + ";" + mes_heart_beat_cycle + ";plc=" + plcIp);
 
         // 2. 读取工位信息并填充到 oprnoMap(自动跳过二维码字段)
         loadOprnoMap(pro);
@@ -200,29 +242,26 @@ public class MesClient extends JFrame {
     }
 
     /**
-     * 创建工作面板
+     * 创建工作面板:OP170A-C 三台 CNC(无上料架统一读码区)
      */
     private void createOprnoPanel(JPanel parentPanel){
-
         List<String> oprnoCodes = new ArrayList<>(oprnoMap.keySet());
-        Collections.sort(oprnoCodes); // 排序,确保输入框顺序固定
+        Collections.sort(oprnoCodes);
         int fieldY = 0;
         for (String oprnoCode : oprnoCodes) {
-            // 按照一行四个的列进行布局
-            int columnIndex = fieldY % 5;
-            int rowIndex = fieldY / 5;
+            int columnIndex = fieldY % 3;
+            int rowIndex = fieldY / 3;
             MesClientComponent mesClientComponent = new MesClientComponent(oprnoMap.get(oprnoCode));
-            mesClientComponent.setBounds(columnIndex * MesClientComponent.workWidth, rowIndex * MesClientComponent.workHeight, MesClientComponent.workWidth, MesClientComponent.workHeight);
+            mesClientComponent.setBounds(
+                    columnIndex * MesClientComponent.workWidth,
+                    rowIndex * MesClientComponent.workHeight,
+                    MesClientComponent.workWidth,
+                    MesClientComponent.workHeight);
             parentPanel.add(mesClientComponent);
-            // 将组件添加到映射中,以便通过工位号找到对应的组件
             componentMap.put(oprnoCode, mesClientComponent);
             fieldY++;
-
         }
-
-
     }
-
     //启动心跳包程序
     public static java.util.Timer heartBeatTimer;
     public static java.util.Timer heartBeatIconTimer;
@@ -415,6 +454,27 @@ public class MesClient extends JFrame {
         }
     }
 
+    /** 点击工件码弹窗显示二维码 */
+    public static void createQRCode(String s, String title) {
+        if (s == null || s.trim().isEmpty()) {
+            return;
+        }
+        s = s.trim();
+        try {
+            BitMatrix bitMatrix = new QRCodeWriter().encode(s, BarcodeFormat.QR_CODE, 200, 200);
+            BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
+            JDialog qrDialog = new JDialog(mesClientFrame, title == null ? "" : title, Dialog.ModalityType.APPLICATION_MODAL);
+            qrDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+            qrDialog.setSize(250, 250);
+            qrDialog.setLocationRelativeTo(mesClientFrame);
+            qrDialog.setResizable(false);
+            qrDialog.getContentPane().add(new JLabel(new ImageIcon(qrImage)), BorderLayout.CENTER);
+            qrDialog.setVisible(true);
+        } catch (Exception e) {
+            log.error("生成二维码失败", e);
+        }
+    }
+
     public static void logoff() {
         welcomeWin.setVisible(true);
         mesClientFrame.setVisible(false);
@@ -486,18 +546,6 @@ public class MesClient extends JFrame {
         });
         settingMenu.add(resetTcpMenu);
 
-        JMenuItem resetTcpMenu_1 = new JMenuItem("刷新工件");
-        resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
-        resetTcpMenu_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        resetTcpMenu_1.addMouseListener(new MouseAdapter() {
-            @Override
-            public void mousePressed(MouseEvent e) {
-                super.mouseClicked(e);
-                resetScanA();
-            }
-        });
-        settingMenu.add(resetTcpMenu_1);
-
         contentPane = new JPanel();
         contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
         setContentPane(contentPane);
@@ -578,7 +626,7 @@ public class MesClient extends JFrame {
         JPanel indexPanelA = new JPanel();
         indexScrollPaneA = new JScrollPane(indexPanelA);
         indexPanelA.setLayout(null);
-        indexPanelA.setPreferredSize(new Dimension(5*MesClientComponent.workWidth, 4*MesClientComponent.workHeight)); // 根据实际内容调整高度
+        indexPanelA.setPreferredSize(new Dimension(3*MesClientComponent.workWidth, MesClientComponent.workHeight + 40)); // OP170 一行三台 CNC
         indexScrollPaneA.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
         indexScrollPaneA.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
         product_sn = new JTextField();
@@ -700,9 +748,9 @@ public class MesClient extends JFrame {
         tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
 
 
-        indexPanelB = new JPanel();
+        indexPanelB = new JPanel(new BorderLayout());
+        indexPanelB.setPreferredSize(new Dimension(990, 580));
         searchScrollPane = new JScrollPane(indexPanelB);
-        indexPanelB.setLayout(null);
 
 		tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
 
@@ -731,6 +779,66 @@ public class MesClient extends JFrame {
         MesClient.status_menu.setText(msg);
     }
 
+    /** 工作记录:按配置机台建分标签,首次点到某机台再加载对应网页 */
+    public static void initWorkRecordTabs() {
+        if (workRecordInited) {
+            return;
+        }
+        workRecordInited = true;
+        indexPanelB.removeAll();
+        indexPanelB.setLayout(new BorderLayout());
+        workRecordTabs = new JTabbedPane();
+        workRecordTabs.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+        List<String> codes = new ArrayList<>(oprnoMap.keySet());
+        Collections.sort(codes);
+        for (String code : codes) {
+            JPanel holder = new JPanel(new BorderLayout());
+            holder.putClientProperty("oprno", code);
+            holder.putClientProperty("loaded", Boolean.FALSE);
+            workRecordTabs.addTab(code, holder);
+        }
+        workRecordTabs.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent e) {
+                loadSelectedWorkRecordTab();
+            }
+        });
+        indexPanelB.add(workRecordTabs, BorderLayout.CENTER);
+        if (workRecordTabs.getTabCount() > 0) {
+            loadSelectedWorkRecordTab();
+        }
+        indexPanelB.revalidate();
+        indexPanelB.repaint();
+    }
+
+    private static void loadSelectedWorkRecordTab() {
+        if (workRecordTabs == null) {
+            return;
+        }
+        int i = workRecordTabs.getSelectedIndex();
+        if (i < 0) {
+            return;
+        }
+        Component c = workRecordTabs.getComponentAt(i);
+        if (!(c instanceof JPanel)) {
+            return;
+        }
+        JPanel holder = (JPanel) c;
+        if (Boolean.TRUE.equals(holder.getClientProperty("loaded"))) {
+            return;
+        }
+        String code = String.valueOf(holder.getClientProperty("oprno"));
+        String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesProductRecord/work?oprno=" + code + "&lineSn=" + mes_line_sn;
+        MesWebView wv = new MesWebView(url);
+        holder.add(wv, BorderLayout.CENTER);
+        holder.putClientProperty("loaded", Boolean.TRUE);
+        holder.revalidate();
+        holder.repaint();
+        if (jfxPanel == null) {
+            jfxPanel = wv;
+        }
+    }
+
     public static void getMaterailData(){
         try{
             JSONObject retObj = DataUtil.getBindMaterail();

+ 70 - 50
src/com/mes/ui/MesRevice.java

@@ -1,13 +1,13 @@
 package com.mes.ui;
 
 import com.mes.netty.ProtocolParam;
-import com.mes.component.MyDialog;
 import com.mes.component.MesClientComponent;
 import com.mes.util.ErrorMsg;
 
-import javax.swing.*;
-import java.awt.*;
-
+/**
+ * MES 回包处理:OP170 各 CNC(OP170A-C) 质量检查 / 开工 / 结果提交。
+ * 无上料架统一读码区,回包按工位号路由到对应面板。
+ */
 public class MesRevice {
 
     private static void setStatusByMsgOprno(String mes_msg, String msg, int error) {
@@ -32,85 +32,105 @@ public class MesRevice {
     }
 
     // 质量查询
-    public static void checkQualityRevice(String processMsgRet,String mes_msg){
-        try{
-            if(processMsgRet.equalsIgnoreCase("UD")) {
-                String oprno = ProtocolParam.getOprno(mes_msg).trim();
-                MesClientComponent component = MesClient.componentMap.get(oprno);
-                if (component == null) {
-                    MesClient.setMenuStatus("未找到工位面板:" + oprno, -1);
-                    return;
+    public static void checkQualityRevice(String processMsgRet, String mes_msg) {
+        try {
+            String rawSn = ProtocolParam.getSn(mes_msg);
+            String sn = normalizeSn(rawSn);
+
+            String oprno = ProtocolParam.getOprno(mes_msg).trim();
+            MesClientComponent component = MesClient.componentMap.get(oprno);
+            if (component == null) {
+                MesClient.setMenuStatus("未找到工位面板:" + oprno, -1);
+                return;
+            }
+            if (component.work_status != 1) {
+                // 非本工位质量检查阶段的回包忽略
+                return;
+            }
+
+            if (processMsgRet.equalsIgnoreCase("UD")) {
+                // 优先用面板上已读到的码;回包 SN 可能带线体前缀
+                String panelSn = component.productSn.getText();
+                if (panelSn != null && !panelSn.trim().isEmpty()) {
+                    sn = panelSn.trim();
                 }
-                MesClient.s7PLC.writeBoolean(component.oprnoClass.getMes_in(), true);
-                DataUtil.startWorkByGw(MesClient.nettyClient,ProtocolParam.getSn(mes_msg).trim(),MesClient.user20,component.oprnoClass.getOprno());
-                component.setMenuStatus("质量检查合格,开始加工", 0);
-                component.work_status = 2;
-            }else {
+                component.onQualityPass(sn);
+            } else {
                 String lmsg = ErrorMsg.getErrorMsg(processMsgRet, ProtocolParam.getLx(mes_msg));
-                setStatusByMsgOprno(mes_msg, lmsg, -1);
+                component.onQualityFail(lmsg);
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
     // 开始回复处理
-    public static void startRevice(String processMsgRet,String mes_msg){
-        try{
-            if(processMsgRet.equalsIgnoreCase("UD")) {
+    public static void startRevice(String processMsgRet, String mes_msg) {
+        try {
+            if (processMsgRet.equalsIgnoreCase("UD")) {
+                String oprno = ProtocolParam.getOprno(mes_msg);
+                if (oprno != null) {
+                    MesClientComponent component = MesClient.componentMap.get(oprno.trim());
+                    if (component != null) {
+                        component.setMenuStatus("开工记录成功,加工中", 0);
+                    }
+                }
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
-    // 绑定
-    public static void bindRevice(String processMsgRet,String mes_msg){
-        try{
-            if(processMsgRet.equalsIgnoreCase("OK")) {
-
-            }else{
-
+    public static void bindRevice(String processMsgRet, String mes_msg) {
+        try {
+            if (processMsgRet.equalsIgnoreCase("OK")) {
+            } else {
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
-    // 解绑
-    public static void unbindRevice(String processMsgRet,String mes_msg){
-        try{
-            if(processMsgRet.equalsIgnoreCase("OK")) {
-
-            }else{
-
+    public static void unbindRevice(String processMsgRet, String mes_msg) {
+        try {
+            if (processMsgRet.equalsIgnoreCase("OK")) {
+            } else {
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
-    // 上传质量
-    public static void updateResultRevice(String processMsgRet,String mes_msg){
-        try{
+    // 上传质量(工位 OK/NG 记录)
+    public static void updateResultRevice(String processMsgRet, String mes_msg) {
+        try {
             String oprno = ProtocolParam.getOprno(mes_msg).trim();
             MesClientComponent component = MesClient.componentMap.get(oprno);
-            if(processMsgRet.equalsIgnoreCase("OK")) {
+            if (processMsgRet.equalsIgnoreCase("OK")) {
                 if (component == null) {
                     MesClient.setMenuStatus("未找到工位面板:" + oprno, -1);
                     return;
                 }
-                MesClient.s7PLC.writeBoolean(component.oprnoClass.getMes_out(),true);
-                MesClient.s7PLC.writeBoolean(component.oprnoClass.getProcess_ok(),false);
-                component.setMenuStatus("提交成功", 0);
-                component.work_status = 3;
-            }else{
+                component.setMenuStatus("结果记录成功", 0);
+            } else {
                 String lmsg = ErrorMsg.getErrorMsg(processMsgRet, ProtocolParam.getLx(mes_msg));
                 setStatusByMsgOprno(mes_msg, lmsg, -1);
-                component.work_status = 0;
             }
-        }catch (Exception e){
+        } catch (Exception e) {
             e.printStackTrace();
         }
     }
+
+    /** 去掉线体前缀与空白,便于工位 SN 比对 */
+    private static String normalizeSn(String sn) {
+        if (sn == null) {
+            return "";
+        }
+        sn = sn.trim();
+        if (MesClient.mes_line_sn != null && !MesClient.mes_line_sn.isEmpty()
+                && sn.startsWith(MesClient.mes_line_sn)) {
+            sn = sn.substring(MesClient.mes_line_sn.length()).trim();
+        }
+        return sn;
+    }
 }

+ 54 - 93
src/com/mes/ui/Oprno.java

@@ -1,49 +1,28 @@
 package com.mes.ui;
 
+/**
+ * OP170 CNC 工位点位(PLC↔MES)
+ */
 public class Oprno {
 
-    //工位号
+    /** 工位号,如 OP170A */
     public String oprno;
-    // 抓手A上料输出信号点位
-    public String hgA_out;
-    // 抓手B上料输出信号
-    public String hgB_out;
-    // mes上料允许信号
-    public String mes_in;
-    // 上料完成信号
-    public String out_ok;
-    // 加工完成信号
-    public String process_ok;
-    // Mes下料允许信号
-    public String mes_out;
-    // 加工结果OK信号
+    /** PLC→MES 上料完成 */
+    public String load_complete;
+    /** MES→PLC 上料完成反馈 */
+    public String load_feedback;
+    /** PLC→MES 下料完成 */
+    public String unload_complete;
+    /** MES→PLC 下料完成反馈 */
+    public String unload_feedback;
+    /** PLC→MES 工位结果 OK */
     public String process_result_ok;
-    // 加工结果NG信号
+    /** PLC→MES 工位结果 NG */
     public String process_result_ng;
-    // Mes屏蔽信号
-    public String mes_shield;
-    // 工件码位置
+    /** PLC→MES 工位状态(true=正常,false=故障) */
+    public String station_status;
+    /** 工位二维码 String[28] */
     public String product_sn;
-    //抓手A工件码地址
-    public String hgA_sn;
-    //抓手B工件码地址
-    public String hgB_sn;
-
-    public String getHgA_sn() {
-        return hgA_sn;
-    }
-
-    public void setHgA_sn(String hgA_sn) {
-        this.hgA_sn = hgA_sn;
-    }
-
-    public String getHgB_sn() {
-        return hgB_sn;
-    }
-
-    public void setHgB_sn(String hgB_sn) {
-        this.hgB_sn = hgB_sn;
-    }
 
     public String getOprno() {
         return oprno;
@@ -53,99 +32,81 @@ public class Oprno {
         this.oprno = oprno;
     }
 
-    public String getProduct_sn() {
-        return product_sn;
-    }
-
-    public void setProduct_sn(String product_sn) {
-        this.product_sn = product_sn;
-    }
-
-    public String getMes_shield() {
-        return mes_shield;
-    }
-
-    public void setMes_shield(String mes_shield) {
-        this.mes_shield = mes_shield;
-    }
-
-    public String getProcess_result_ng() {
-        return process_result_ng;
+    public String getLoad_complete() {
+        return load_complete;
     }
 
-    public void setProcess_result_ng(String process_result_ng) {
-        this.process_result_ng = process_result_ng;
+    public void setLoad_complete(String load_complete) {
+        this.load_complete = load_complete;
     }
 
-    public String getProcess_result_ok() {
-        return process_result_ok;
+    public String getLoad_feedback() {
+        return load_feedback;
     }
 
-    public void setProcess_result_ok(String process_result_ok) {
-        this.process_result_ok = process_result_ok;
+    public void setLoad_feedback(String load_feedback) {
+        this.load_feedback = load_feedback;
     }
 
-    public String getMes_out() {
-        return mes_out;
+    public String getUnload_complete() {
+        return unload_complete;
     }
 
-    public void setMes_out(String mes_out) {
-        this.mes_out = mes_out;
+    public void setUnload_complete(String unload_complete) {
+        this.unload_complete = unload_complete;
     }
 
-    public String getProcess_ok() {
-        return process_ok;
+    public String getUnload_feedback() {
+        return unload_feedback;
     }
 
-    public void setProcess_ok(String process_ok) {
-        this.process_ok = process_ok;
+    public void setUnload_feedback(String unload_feedback) {
+        this.unload_feedback = unload_feedback;
     }
 
-    public String getOut_ok() {
-        return out_ok;
+    public String getProcess_result_ok() {
+        return process_result_ok;
     }
 
-    public void setOut_ok(String out_ok) {
-        this.out_ok = out_ok;
+    public void setProcess_result_ok(String process_result_ok) {
+        this.process_result_ok = process_result_ok;
     }
 
-    public String getMes_in() {
-        return mes_in;
+    public String getProcess_result_ng() {
+        return process_result_ng;
     }
 
-    public void setMes_in(String mes_in) {
-        this.mes_in = mes_in;
+    public void setProcess_result_ng(String process_result_ng) {
+        this.process_result_ng = process_result_ng;
     }
 
-    public String getHgB_out() {
-        return hgB_out;
+    public String getStation_status() {
+        return station_status;
     }
 
-    public void setHgB_out(String hgB_out) {
-        this.hgB_out = hgB_out;
+    public void setStation_status(String station_status) {
+        this.station_status = station_status;
     }
 
-    public String getHgA_out() {
-        return hgA_out;
+    public String getProduct_sn() {
+        return product_sn;
     }
 
-    public void setHgA_out(String hgA_out) {
-        this.hgA_out = hgA_out;
+    public void setProduct_sn(String product_sn) {
+        this.product_sn = product_sn;
     }
 
     @Override
     public String toString() {
         return "Oprno{" +
                 "oprno='" + oprno + '\'' +
-                ", hgA_out='" + hgA_out + '\'' +
-                ", hgB_out='" + hgB_out + '\'' +
-                ", mes_in='" + mes_in + '\'' +
-                ", out_ok='" + out_ok + '\'' +
-                ", process_ok='" + process_ok + '\'' +
-                ", mes_out='" + mes_out + '\'' +
+                ", load_complete='" + load_complete + '\'' +
+                ", load_feedback='" + load_feedback + '\'' +
+                ", unload_complete='" + unload_complete + '\'' +
+                ", unload_feedback='" + unload_feedback + '\'' +
                 ", process_result_ok='" + process_result_ok + '\'' +
                 ", process_result_ng='" + process_result_ng + '\'' +
-                ", mes_shield='" + mes_shield + '\'' +
+                ", station_status='" + station_status + '\'' +
                 ", product_sn='" + product_sn + '\'' +
                 '}';
     }

+ 2 - 14
src/com/mes/ui/OprnoUtil.java

@@ -6,22 +6,10 @@ import java.util.Map;
 
 public class OprnoUtil {
     public static String[] xtoprnos = new String[]{
-            "OP040", "OP070", "OP080", "OP085","OP090", "OP095", "OP100", "OP110", "OP120",
-            "OP130", "OP140", "OP150","OP155", "OP160", "OP170","OP175", "OP180", "OP190", "OP200",
-            "OP210", "OP220", "OP230", "OP240", "OP250", "OP260", "OP270", "OP280",
-            "OP290", "OP300", "OP310", "OP320", "OP330", "OP335", "OP340", "OP350",
-            "OP360", "OP370", "OP380", "OP390", "OP400", "OP410", "OP420", "OP430",
-            "OP440", "OP450", "OP460", "OP470", "OP480", "OP490", "OP500", "OP510",
-            "OP520", "OP530", "OP540"
+            "OP170"
     };
     public static String[] xtoprnodes = new String[]{
-            "镭雕二维码", "小总成焊接", "CMT焊接","R1", "人工正面补焊", "人工反面补焊", "焊缝铣削", "焊缝打磨", "焊道检验",
-            "框架找漏", "找漏返修", "找漏复检","R2", "CNC总成正面加工", "CNC总成反面加工", "R3","总成正反面干冰清洗", "框架清洁", "框架涂胶",
-            "FDS", "清理溢胶", "冷板激光焊", "液冷板FSW", "封堵片焊接", "总成正面装配", "总成正面拉铆", "总成反面拉铆",
-            "钉头涂胶", "防爆阀拉铆", "框架终检", "静置", "半成品气密", "底护板气密", "粘贴MPP", "总成反面装配",
-            "底护板安装", "底护板复拧", "总成气密", "液冷板气密", "反面粘贴保温棉", "反面终检", "胶水固化", "型腔封堵",
-            "粘贴陶瓷胶带", "总成清洁", "蓝光检测", "总成检具", "正面终检", "CCD错漏检测", "绝缘耐压检测", "接地点检测",
-            "GP12", "下线拍照", "称重包装"
+            "总成反面CNC"
     };
     public static String[] lboprnos = new String[]{
 

+ 18 - 39
src/com/mes/util/S7PLCUtils.java

@@ -5,62 +5,41 @@ import com.mes.ui.Oprno;
 
 public class S7PLCUtils {
 
-
-    // 读取是否开始上料输出,参数为动态的几个Oprno对象,返回第一个上料状态为true的工位对象,否则返回null
-    public static Oprno isStart(S7PLC s7PLC, Oprno... oprnos){
-        // 遍历所有传入的Oprno对象
+    /** 返回第一个上料完成信号为 true 的工位 */
+    public static Oprno isStart(S7PLC s7PLC, Oprno... oprnos) {
         for (Oprno oprno : oprnos) {
-            // 检查当前工位的hgA_out和hgB_out点位
-            if (s7PLC.readBoolean(oprno.getHgA_out()) || s7PLC.readBoolean(oprno.getHgB_out())) {
-                // 如果当前工位的任一上料点位为true,返回该工位对象
+            if (s7PLC.readBoolean(oprno.getLoad_complete())) {
                 return oprno;
             }
         }
-        // 所有工位的上料点位都为false,返回null
         return null;
     }
 
-    // 读取是否加工完成输出,参数为动态的几个Oprno对象,返回第一个加工完成状态为true的工位对象,否则返回null
-    public static Oprno isFinish(S7PLC s7PLC, Oprno... oprnos){
-        // 遍历所有传入的Oprno对象
+    /** 返回第一个下料完成信号为 true 的工位 */
+    public static Oprno isFinish(S7PLC s7PLC, Oprno... oprnos) {
         for (Oprno oprno : oprnos) {
-            // 检查当前工位的加工完成点位
-            if (s7PLC.readBoolean(oprno.getProcess_ok())) {
-                // 如果当前工位的加工完成点位为true,返回该工位对象
+            if (s7PLC.readBoolean(oprno.getUnload_complete())) {
                 return oprno;
             }
         }
-        // 所有工位的加工完成点位都为false,返回null
         return null;
     }
 
-
-    // 读取工件码
-    public static String getSnInJXB(Oprno oprno, S7PLC s7PLC){
-        if (s7PLC.readBoolean(oprno.getHgA_out())){
-            return s7PLC.readString(oprno.getHgA_sn());
-        }else if (s7PLC.readBoolean(oprno.getHgB_out())){
-            return s7PLC.readString(oprno.getHgB_sn());
-        }else {
-            return "";
-        }
-    }
-
-    //从工位上读取工件码
-    public static String getSnInOprno(Oprno oprno, S7PLC s7PLC){
-        return s7PLC.readString(oprno.getProduct_sn(),50);
+    /** 读取工位二维码 */
+    public static String getSnInOprno(Oprno oprno, S7PLC s7PLC) {
+        return s7PLC.readString(oprno.getProduct_sn(), 50);
     }
 
-
-
-    //读取工位结果
-    public static Boolean getResultInOprno(Oprno oprno, S7PLC s7PLC){
+    /** 读取工位结果:OK=true,NG=false;都未置位返回 null 语义用 Boolean 包装时此处 NG 优先 */
+    public static Boolean getResultInOprno(Oprno oprno, S7PLC s7PLC) {
         Boolean resultOK = s7PLC.readBoolean(oprno.getProcess_result_ok());
         Boolean resultNG = s7PLC.readBoolean(oprno.getProcess_result_ng());
-        // 只有当NG为true时返回false
-        if (resultOK){
-            return resultOK;
-        }else return !resultOK && !resultNG;
+        if (resultNG) {
+            return false;
+        }
+        if (resultOK) {
+            return true;
+        }
+        return null;
     }
-
 }

+ 33 - 304
src/resources/config/config.properties

@@ -1,310 +1,39 @@
-mes.gw=OP175A
+mes.gw=OP170
 #mes.server_ip=127.0.0.1
-mes.server_ip=192.168.20.99
+mes.server_ip=192.168.24.99
 mes.tcp_port=3000
 
 mes.heart_beat_cycle=60
 mes.line_sn=XT
 
-
-
-
-mes.oprno.OP180A.hgA_out=DB502.0.0
-mes.oprno.OP180A.hgB_out=DB502.0.1
-mes.oprno.OP180A.mes_in=DB502.0.2
-mes.oprno.OP180A.out_ok=DB502.0.3
-mes.oprno.OP180A.process_ok=DB502.0.4
-mes.oprno.OP180A.mes_out=DB502.0.5
-mes.oprno.OP180A.process_result_ok=DB502.0.6
-mes.oprno.OP180A.process_result_ng=DB502.0.7
-mes.oprno.OP180A.mes_shield=DB502.1.0
-mes.oprno.OP180A.product_sn=DB502.2.0
-mes.oprno.OP180A.hgA_sn=DB502.270.0
-mes.oprno.OP180A.hgB_sn=DB502.336.0
-
-
-mes.oprno.OP190A.hgA_out=DB502.54.0
-mes.oprno.OP190A.hgB_out=DB502.54.1
-mes.oprno.OP190A.mes_in=DB502.54.2
-mes.oprno.OP190A.out_ok=DB502.54.3
-mes.oprno.OP190A.process_ok=DB502.54.4
-mes.oprno.OP190A.mes_out=DB502.54.5
-mes.oprno.OP190A.process_result_ok=DB502.54.6
-mes.oprno.OP190A.process_result_ng=DB502.54.7
-mes.oprno.OP190A.mes_shield=DB502.55.0
-mes.oprno.OP190A.product_sn=DB502.56.0
-mes.oprno.OP190A.hgA_sn=DB502.270.0
-mes.oprno.OP190A.hgB_sn=DB502.336.0
-
-
-mes.oprno.OP190B.hgA_out=DB502.108.0
-mes.oprno.OP190B.hgB_out=DB502.108.1
-mes.oprno.OP190B.mes_in=DB502.108.2
-mes.oprno.OP190B.out_ok=DB502.108.3
-mes.oprno.OP190B.process_ok=DB502.108.4
-mes.oprno.OP190B.mes_out=DB502.108.5
-mes.oprno.OP190B.process_result_ok=DB502.108.6
-mes.oprno.OP190B.process_result_ng=DB502.108.7
-mes.oprno.OP190B.mes_shield=DB502.109.0
-mes.oprno.OP190B.product_sn=DB502.110.0
-mes.oprno.OP190B.hgA_sn=DB502.270.0
-mes.oprno.OP190B.hgB_sn=DB502.336.0
-
-
-mes.oprno.OP190C.hgA_out=DB502.162.0
-mes.oprno.OP190C.hgB_out=DB502.162.1
-mes.oprno.OP190C.mes_in=DB502.162.2
-mes.oprno.OP190C.out_ok=DB502.162.3
-mes.oprno.OP190C.process_ok=DB502.162.4
-mes.oprno.OP190C.mes_out=DB502.162.5
-mes.oprno.OP190C.process_result_ok=DB502.162.6
-mes.oprno.OP190C.process_result_ng=DB502.162.7
-mes.oprno.OP190C.mes_shield=DB502.163.0
-mes.oprno.OP190C.product_sn=DB502.164.0
-mes.oprno.OP190C.hgA_sn=DB502.270.0
-mes.oprno.OP190C.hgB_sn=DB502.336.0
-
-
-mes.oprno.OP190D.hgA_out=DB502.216.0
-mes.oprno.OP190D.hgB_out=DB502.216.1
-mes.oprno.OP190D.mes_in=DB502.216.2
-mes.oprno.OP190D.out_ok=DB502.216.3
-mes.oprno.OP190D.process_ok=DB502.216.4
-mes.oprno.OP190D.mes_out=DB502.216.5
-mes.oprno.OP190D.process_result_ok=DB502.216.6
-mes.oprno.OP190D.process_result_ng=DB502.216.7
-mes.oprno.OP190D.mes_shield=DB502.217.0
-mes.oprno.OP190D.product_sn=DB502.218.0
-mes.oprno.OP190D.hgA_sn=DB502.270.0
-mes.oprno.OP190D.hgB_sn=DB502.336.0
-
-
-mes.oprno.OP200A.hgA_out=DB503.0.0
-mes.oprno.OP200A.hgB_out=DB503.0.1
-mes.oprno.OP200A.mes_in=DB503.0.2
-mes.oprno.OP200A.out_ok=DB503.0.3
-mes.oprno.OP200A.process_ok=DB503.0.4
-mes.oprno.OP200A.mes_out=DB503.0.5
-mes.oprno.OP200A.process_result_ok=DB503.0.6
-mes.oprno.OP200A.process_result_ng=DB503.0.7
-mes.oprno.OP200A.mes_shield=DB503.1.0
-mes.oprno.OP200A.product_sn=DB503.2.0
-mes.oprno.OP200A.hgA_sn=DB503.270.0
-mes.oprno.OP200A.hgB_sn=DB503.336.0
-
-
-mes.oprno.OP210A.hgA_out=DB503.54.0
-mes.oprno.OP210A.hgB_out=DB503.54.1
-mes.oprno.OP210A.mes_in=DB503.54.2
-mes.oprno.OP210A.out_ok=DB503.54.3
-mes.oprno.OP210A.process_ok=DB503.54.4
-mes.oprno.OP210A.mes_out=DB503.54.5
-mes.oprno.OP210A.process_result_ok=DB503.54.6
-mes.oprno.OP210A.process_result_ng=DB503.54.7
-mes.oprno.OP210A.mes_shield=DB503.55.0
-mes.oprno.OP210A.product_sn=DB503.56.0
-mes.oprno.OP210A.hgA_sn=DB503.270.0
-mes.oprno.OP210A.hgB_sn=DB503.336.0
-
-
-mes.oprno.OP210B.hgA_out=DB503.108.0
-mes.oprno.OP210B.hgB_out=DB503.108.1
-mes.oprno.OP210B.mes_in=DB503.108.2
-mes.oprno.OP210B.out_ok=DB503.108.3
-mes.oprno.OP210B.process_ok=DB503.108.4
-mes.oprno.OP210B.mes_out=DB503.108.5
-mes.oprno.OP210B.process_result_ok=DB503.108.6
-mes.oprno.OP210B.process_result_ng=DB503.108.7
-mes.oprno.OP210B.mes_shield=DB503.109.0
-mes.oprno.OP210B.product_sn=DB503.110.0
-mes.oprno.OP210B.hgA_sn=DB503.270.0
-mes.oprno.OP210B.hgB_sn=DB503.336.0
-
-
-mes.oprno.OP220A.hgA_out=DB503.162.0
-mes.oprno.OP220A.hgB_out=DB503.162.1
-mes.oprno.OP220A.mes_in=DB503.162.2
-mes.oprno.OP220A.out_ok=DB503.162.3
-mes.oprno.OP220A.process_ok=DB503.162.4
-mes.oprno.OP220A.mes_out=DB503.162.5
-mes.oprno.OP220A.process_result_ok=DB503.162.6
-mes.oprno.OP220A.process_result_ng=DB503.162.7
-mes.oprno.OP220A.mes_shield=DB503.163.0
-mes.oprno.OP220A.product_sn=DB503.164.0
-mes.oprno.OP220A.hgA_sn=DB503.270.0
-mes.oprno.OP220A.hgB_sn=DB503.336.0
-
-
-mes.oprno.OP220B.hgA_out=DB503.216.0
-mes.oprno.OP220B.hgB_out=DB503.216.1
-mes.oprno.OP220B.mes_in=DB503.216.2
-mes.oprno.OP220B.out_ok=DB503.216.3
-mes.oprno.OP220B.process_ok=DB503.216.4
-mes.oprno.OP220B.mes_out=DB503.216.5
-mes.oprno.OP220B.process_result_ok=DB503.216.6
-mes.oprno.OP220B.process_result_ng=DB503.216.7
-mes.oprno.OP220B.mes_shield=DB503.217.0
-mes.oprno.OP220B.product_sn=DB503.218.0
-mes.oprno.OP220B.hgA_sn=DB503.270.0
-mes.oprno.OP220B.hgB_sn=DB503.336.0
-
-
-mes.oprno.OP230A.hgA_out=DB504.0.0
-mes.oprno.OP230A.hgB_out=DB504.0.1
-mes.oprno.OP230A.mes_in=DB504.0.2
-mes.oprno.OP230A.out_ok=DB504.0.3
-mes.oprno.OP230A.process_ok=DB504.0.4
-mes.oprno.OP230A.mes_out=DB504.0.5
-mes.oprno.OP230A.process_result_ok=DB504.0.6
-mes.oprno.OP230A.process_result_ng=DB504.0.7
-mes.oprno.OP230A.mes_shield=DB504.1.0
-mes.oprno.OP230A.product_sn=DB504.2.0
-mes.oprno.OP230A.hgA_sn=DB504.378.0
-mes.oprno.OP230A.hgB_sn=DB504.444.0
-
-
-mes.oprno.OP240A.hgA_out=DB504.54.0
-mes.oprno.OP240A.hgB_out=DB504.54.1
-mes.oprno.OP240A.mes_in=DB504.54.2
-mes.oprno.OP240A.out_ok=DB504.54.3
-mes.oprno.OP240A.process_ok=DB504.54.4
-mes.oprno.OP240A.mes_out=DB504.54.5
-mes.oprno.OP240A.process_result_ok=DB504.54.6
-mes.oprno.OP240A.process_result_ng=DB504.54.7
-mes.oprno.OP240A.mes_shield=DB504.55.0
-mes.oprno.OP240A.product_sn=DB504.56.0
-mes.oprno.OP240A.hgA_sn=DB504.378.0
-mes.oprno.OP240A.hgB_sn=DB504.444.0
-
-
-mes.oprno.OP240B.hgA_out=DB504.108.0
-mes.oprno.OP240B.hgB_out=DB504.108.1
-mes.oprno.OP240B.mes_in=DB504.108.2
-mes.oprno.OP240B.out_ok=DB504.108.3
-mes.oprno.OP240B.process_ok=DB504.108.4
-mes.oprno.OP240B.mes_out=DB504.108.5
-mes.oprno.OP240B.process_result_ok=DB504.108.6
-mes.oprno.OP240B.process_result_ng=DB504.108.7
-mes.oprno.OP240B.mes_shield=DB504.109.0
-mes.oprno.OP240B.product_sn=DB504.110.0
-mes.oprno.OP240B.hgA_sn=DB504.378.0
-mes.oprno.OP240B.hgB_sn=DB504.444.0
-
-
-mes.oprno.OP240C.hgA_out=DB504.162.0
-mes.oprno.OP240C.hgB_out=DB504.162.1
-mes.oprno.OP240C.mes_in=DB504.162.2
-mes.oprno.OP240C.out_ok=DB504.162.3
-mes.oprno.OP240C.process_ok=DB504.162.4
-mes.oprno.OP240C.mes_out=DB504.162.5
-mes.oprno.OP240C.process_result_ok=DB504.162.6
-mes.oprno.OP240C.process_result_ng=DB504.162.7
-mes.oprno.OP240C.mes_shield=DB504.163.0
-mes.oprno.OP240C.product_sn=DB504.164.0
-mes.oprno.OP240C.hgA_sn=DB504.378.0
-mes.oprno.OP240C.hgB_sn=DB504.444.0
-
-
-mes.oprno.OP250A.hgA_out=DB504.216.0
-mes.oprno.OP250A.hgB_out=DB504.216.1
-mes.oprno.OP250A.mes_in=DB504.216.2
-mes.oprno.OP250A.out_ok=DB504.216.3
-mes.oprno.OP250A.process_ok=DB504.216.4
-mes.oprno.OP250A.mes_out=DB504.216.5
-mes.oprno.OP250A.process_result_ok=DB504.216.6
-mes.oprno.OP250A.process_result_ng=DB504.216.7
-mes.oprno.OP250A.mes_shield=DB504.217.0
-mes.oprno.OP250A.product_sn=DB504.218.0
-mes.oprno.OP250A.hgA_sn=DB504.378.0
-mes.oprno.OP250A.hgB_sn=DB504.444.0
-
-
-mes.oprno.OP250B.hgA_out=DB504.270.0
-mes.oprno.OP250B.hgB_out=DB504.270.1
-mes.oprno.OP250B.mes_in=DB504.270.2
-mes.oprno.OP250B.out_ok=DB504.270.3
-mes.oprno.OP250B.process_ok=DB504.270.4
-mes.oprno.OP250B.mes_out=DB504.270.5
-mes.oprno.OP250B.process_result_ok=DB504.270.6
-mes.oprno.OP250B.process_result_ng=DB504.270.7
-mes.oprno.OP250B.mes_shield=DB504.271.0
-mes.oprno.OP250B.product_sn=DB504.272.0
-mes.oprno.OP250B.hgA_sn=DB504.378.0
-mes.oprno.OP250B.hgB_sn=DB504.444.0
-
-
-mes.oprno.OP250C.hgA_out=DB504.324.0
-mes.oprno.OP250C.hgB_out=DB504.324.1
-mes.oprno.OP250C.mes_in=DB504.324.2
-mes.oprno.OP250C.out_ok=DB504.324.3
-mes.oprno.OP250C.process_ok=DB504.324.4
-mes.oprno.OP250C.mes_out=DB504.324.5
-mes.oprno.OP250C.process_result_ok=DB504.324.6
-mes.oprno.OP250C.process_result_ng=DB504.324.7
-mes.oprno.OP250C.mes_shield=DB504.325.0
-mes.oprno.OP250C.product_sn=DB504.326.0
-mes.oprno.OP250C.hgA_sn=DB504.378.0
-mes.oprno.OP250C.hgB_sn=DB504.444.0
-
-
-
-#mes.oprno.OP270A.hgA_out=DB32.54.0
-#mes.oprno.OP270A.hgB_out=DB32.54.1
-#mes.oprno.OP270A.mes_in=DB32.54.2
-#mes.oprno.OP270A.out_ok=DB32.54.3
-#mes.oprno.OP270A.process_ok=DB32.54.4
-#mes.oprno.OP270A.mes_out=DB32.54.5
-#mes.oprno.OP270A.product_sn=DB32.56.0
-#
-#
-#mes.oprno.OP270B.hgA_out=DB32.108.0
-#mes.oprno.OP270B.hgB_out=DB32.108.1
-#mes.oprno.OP270B.mes_in=DB32.108.2
-#mes.oprno.OP270B.out_ok=DB32.108.3
-#mes.oprno.OP270B.process_ok=DB32.108.4
-#mes.oprno.OP270B.mes_out=DB32.108.5
-#mes.oprno.OP270B.product_sn=DB32.110.0
-#
-#
-#mes.oprno.OP270C.hgA_out=DB32.162.0
-#mes.oprno.OP270C.hgB_out=DB32.162.1
-#mes.oprno.OP270C.mes_in=DB32.162.2
-#mes.oprno.OP270C.out_ok=DB32.162.3
-#mes.oprno.OP270C.process_ok=DB32.162.4
-#mes.oprno.OP270C.mes_out=DB32.162.5
-#mes.oprno.OP270C.product_sn=DB32.164.0
-
-
-
-#mes.oprno.OP280A.hgA_out=DB57.0.0
-#mes.oprno.OP280A.hgB_out=DB57.0.1
-#mes.oprno.OP280A.mes_in=DB57.0.2
-#mes.oprno.OP280A.out_ok=DB57.0.3
-#mes.oprno.OP280A.process_ok=DB57.0.4
-#mes.oprno.OP280A.mes_out=DB57.0.5
-#mes.oprno.OP280A.product_sn=DB57.2.0
-#
-#mes.oprno.OP280B.hgA_out=DB57.54.0
-#mes.oprno.OP280B.hgB_out=DB57.54.1
-#mes.oprno.OP280B.mes_in=DB57.54.2
-#mes.oprno.OP280B.out_ok=DB57.54.3
-#mes.oprno.OP280B.process_ok=DB57.54.4
-#mes.oprno.OP280B.mes_out=DB57.54.5
-#mes.oprno.OP280B.product_sn=DB57.56.0
-
-
-#mes.oprno.OP290A.hgA_out=DB57.108.0
-#mes.oprno.OP290A.hgB_out=DB57.108.1
-#mes.oprno.OP290A.mes_in=DB57.108.2
-#mes.oprno.OP290A.out_ok=DB57.108.3
-#mes.oprno.OP290A.process_ok=DB57.108.4
-#mes.oprno.OP290A.mes_out=DB57.108.5
-#mes.oprno.OP290A.product_sn=DB57.110.0
-#
-#
-#mes.oprno.OP290B.hgA_out=DB57.162.0
-#mes.oprno.OP290B.hgB_out=DB57.162.1
-#mes.oprno.OP290B.mes_in=DB57.162.2
-#mes.oprno.OP290B.out_ok=DB57.162.3
-#mes.oprno.OP290B.process_ok=DB57.162.4
-#mes.oprno.OP290B.mes_out=DB57.162.5
+# R2区域 OP170 CNC PLC
+mes.plc_ip=10.81.10.2
+
+# OP170 CNC1=A / CNC2=B / CNC3=C
+# 各机质量检查与结果提交用 OP170A-C;区号为 OP170
+mes.oprno.OP170A.load_complete=DB201.744.1
+mes.oprno.OP170A.load_feedback=DB201.762.0
+mes.oprno.OP170A.unload_complete=DB201.762.1
+mes.oprno.OP170A.unload_feedback=DB201.780.0
+mes.oprno.OP170A.process_result_ok=DB201.780.1
+mes.oprno.OP170A.process_result_ng=DB201.780.2
+mes.oprno.OP170A.station_status=DB201.780.3
+mes.oprno.OP170A.product_sn=DB201.782.0
+
+mes.oprno.OP170B.load_complete=DB201.812.1
+mes.oprno.OP170B.load_feedback=DB201.830.0
+mes.oprno.OP170B.unload_complete=DB201.830.1
+mes.oprno.OP170B.unload_feedback=DB201.848.0
+mes.oprno.OP170B.process_result_ok=DB201.848.1
+mes.oprno.OP170B.process_result_ng=DB201.848.2
+mes.oprno.OP170B.station_status=DB201.848.3
+mes.oprno.OP170B.product_sn=DB201.850.0
+
+mes.oprno.OP170C.load_complete=DB201.880.1
+mes.oprno.OP170C.load_feedback=DB201.898.0
+mes.oprno.OP170C.unload_complete=DB201.898.1
+mes.oprno.OP170C.unload_feedback=DB201.916.0
+mes.oprno.OP170C.process_result_ok=DB201.916.1
+mes.oprno.OP170C.process_result_ng=DB201.916.2
+mes.oprno.OP170C.station_status=DB201.916.3
+mes.oprno.OP170C.product_sn=DB201.918.0