Browse Source

走质量,提交到服务

wangxichen 2 days ago
parent
commit
247951d106

+ 12 - 1
src/com/mes/netty/NettyClientHandler.java

@@ -1,6 +1,7 @@
 package com.mes.netty;
 
 import com.mes.ui.MesClient;
+import com.mes.ui.MesRevice;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
@@ -47,7 +48,17 @@ public class NettyClientHandler extends ChannelInboundHandlerAdapter {
         String processMsgRet = MesMsgUtils.processMsg(mes_msg, msg_type);
         log.info("| TCP返回报文结果: {}", processMsgRet);
         log.info("==============================================================================");
-        // 只保留同步/心跳,业务报文(质量查询、工位结果)已去掉,无需回调处理
+        switch(msg_type) {
+            case "AQDW": // 查询质量
+                MesRevice.checkQualityRevice(processMsgRet, mes_msg);
+                break;
+            case "MKSW": // 开工
+                MesRevice.startRevice(processMsgRet, mes_msg);
+                break;
+            case "MQDW": // 工位结果
+                MesRevice.updateResultRevice(processMsgRet, mes_msg);
+                break;
+        }
     }
 
     @Override

+ 72 - 0
src/com/mes/ui/DataUtil.java

@@ -101,6 +101,78 @@ public class DataUtil {
         }
     }
 
+    // 质量查询:问MES这个工件能否加工
+    public static Boolean checkQuality(NettyClient nettyClient, String sn, String user, String mes_gw){
+        try{
+            String msgType = "AQDW";
+            String gy = "100000";
+            return sendMessage(nettyClient,msgType,gy,"",sn,"",user,"00","", mes_gw);
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    // 开工通知
+    public static Boolean startWork(NettyClient nettyClient,String sn,String user, String mes_gw){
+        try{
+            String msgType = "MKSW";
+            String gy = "";
+            return sendMessage(nettyClient,msgType,gy,"",sn,"",user,"00","", mes_gw);
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    // 提交工位结果 MQDW
+    public static Boolean sendQuality(NettyClient nettyClient,String sn,String result,String user, String mes_gw){
+        try{
+            String msgType = "MQDW";
+            String craft = "100000";
+            String lx = "";
+            String paramNums = "00";
+            String params = "";
+
+            String gw = "GW"+rightPad(mes_gw, 6);
+            String start = "aaaabbbbbABW";
+            String gy = "GY" + rightPad(craft, 6);
+            String reslx = "LX" + rightPad(lx, 2);
+            String id = Config.line_sn + rightPad(sn, 36);
+            String rs = "RS"+ rightPad(result, 2);
+            String da = "DA" + DateLocalUtils.getCurrentDate();
+            String zt = "ZT" + DateLocalUtils.getCurrentTimeHMS();
+            String yh = "YH" + rightPad(user, 20);
+            String aqdw_str = start + msgType + gw + gy + reslx + id + rs + da + zt + yh + paramNums + params;
+            log.info("向submit_record表中插入更新质量报文: {}", aqdw_str);
+            JdbcUtils.insertData(gw, gy, aqdw_str, msgType, sn);
+            JdbcUtils.insertSubmitRecord(gw, sn, aqdw_str);
+            nettyClient.future.channel().writeAndFlush(aqdw_str);
+            return true;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean sendMessage(NettyClient nettyClient,String msgType,String craft,String lx,String sn,String result,String user,String paramNums,String params, String mes_gw){
+        try{
+            String gw = "GW"+rightPad(mes_gw, 6);
+            String start = "aaaabbbbbABW";
+            String gy = "GY" + rightPad(craft, 6);
+            String reslx = "LX" + rightPad(lx, 2);
+            String id = Config.line_sn + rightPad(sn, 36);
+            String rs = "RS"+ rightPad(result, 2);
+            String da = "DA" + DateLocalUtils.getCurrentDate();
+            String zt = "ZT" + DateLocalUtils.getCurrentTimeHMS();
+            String yh = "YH" + rightPad(user, 20);
+            String aqdw_str = start + msgType + gw + gy + reslx + id + rs + da + zt + yh + paramNums + params;
+            log.info("向服务端发送TCP报文: {}", aqdw_str);
+            JdbcUtils.insertData(gw, gy, aqdw_str, msgType, sn);
+            nettyClient.future.channel().writeAndFlush(aqdw_str);
+            return true;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
     public static String rightPad(final String str, final int size) {
         if (str == null) {
             return null;

+ 17 - 5
src/com/mes/ui/LoginFrame.java

@@ -1,6 +1,7 @@
 package com.mes.ui;
 
 import com.alibaba.fastjson2.JSONObject;
+import com.mes.component.MesWebView;
 import com.mes.util.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -23,7 +24,7 @@ public class LoginFrame extends JFrame {
     static JButton scanLoginButton = new JButton("扫  码  登  录");
 
     public LoginFrame() {
-        setTitle("MES系统客户端:OP245" + " - " + Config.gw_des_1);
+        setTitle("MES系统客户端:" + OprnoUtil.formatOprno(Config.gw_1) + " - " + Config.gw_des_1);
 
         ImageIcon bg = new ImageIcon(Objects.requireNonNull(MesClient.class.getResource("/background.png")));
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@@ -163,10 +164,21 @@ public class LoginFrame extends JFrame {
                     MesClient.mesClientFrame.setVisible(true);
                     MesClient.getUser();
 
-                    // 工作记录改为本地计件,登录后刷新一次
-                    if (MesClient.workRecordPanel != null) {
-                        MesClient.workRecordPanel.reload();
-                    }
+
+                    // 工作记录/开班点检 网页按父工位号查(去掉 gw_1 的 C/D 后缀)
+                    String pageOprno = OprnoUtil.formatOprno(Config.gw_1);
+
+                    String url1 = "http://" + Config.server_ip + ":8980/js/a/mes/mesProductRecord/work?" + "oprno=" + pageOprno + "&lineSn=" + Config.line_sn;
+                    MesWebView jfxPanel = new MesWebView(url1);
+                    jfxPanel.setSize(990, 550);
+                    MesClient.indexPanelB.add(jfxPanel);
+
+
+                    String url2 = "http://" + Config.server_ip + ":8980/js/a/mes/mesProcessCheckRecord/ulist?ucode=" + user_id + "&oprno=" + pageOprno + "&lineSn=" + Config.line_sn;
+                    MesWebView jfxPanel2 = new MesWebView(url2);
+                    jfxPanel2.setSize(990, 550);
+                    MesClient.indexPanelC.add(jfxPanel2);
+
 
                     MesClient.initWarehouseData();
 //                    UpdateQualityTimer.start();  // 开启更新质量的定时任务

+ 54 - 16
src/com/mes/ui/MesClient.java

@@ -10,6 +10,7 @@ import com.google.zxing.client.j2se.MatrixToImageWriter;
 import com.google.zxing.common.BitMatrix;
 import com.google.zxing.qrcode.QRCodeWriter;
 import com.mes.component.MesRadio;
+import com.mes.component.MesWebView;
 import com.mes.netty.NettyClient;
 import com.mes.util.*;
 import org.slf4j.Logger;
@@ -42,7 +43,9 @@ public class MesClient extends JFrame {
     public static String sessionid = "";
     public static NettyClient nettyClient;
 
+    public static Boolean check_quality_result1 = false;
     public static Integer work_status1 = 0;
+    public static Boolean check_quality_result2 = false;
     public static Integer work_status2 = 0;
     
     public static Boolean isSubmitting1 = false; // 150A是否正在提交结果到MES
@@ -69,13 +72,18 @@ public class MesClient extends JFrame {
     public static MesClient mesClientFrame;
     public static JTabbedPane tabbedPane;
     public static JScrollPane indexScrollPaneA;
+    public static JScrollPane searchScrollPane;
+    public static JScrollPane searchScrollPaneDj;
 
 
 
     public static JButton heart_beat_menu;
     public static JButton user_menu;
     public static JFrame welcomeWin;
-    public static WorkRecordPanel workRecordPanel;   // 本地工作记录面板
+    public static JPanel indexPanelB;                // 工作记录(MES网页)
+    public static MesWebView jfxPanel = null;
+    public static JPanel indexPanelC;                // 开班点检(MES网页)
+    public static MesWebView jfxPanel2 = null;
     public static MesRadio mesRadioHj;
     public static JTable table;
     public static Object[] columnNames = {"物料名称", "绑定批次", "剩余次数", "操作"};
@@ -395,6 +403,7 @@ public class MesClient extends JFrame {
         MesClient.finish_ng_bt_1.setEnabled(false);
         MesClient.f_scan_data_bt_1.setEnabled(true);
         work_status1 = 0;
+        check_quality_result1 = false;
         
         //停止心跳,设备将自动停止
         heartBeatFlag = false;
@@ -433,6 +442,7 @@ public class MesClient extends JFrame {
         MesClient.finish_ng_bt_2.setEnabled(false);
         MesClient.f_scan_data_bt_2.setEnabled(true);
         work_status2 = 0;
+        check_quality_result2 = false;
         
         //停止心跳,设备将自动停止
         heartBeatFlag2 = false;
@@ -575,8 +585,16 @@ public class MesClient extends JFrame {
             //刷新界面
             mesClientFrame.repaint();
 
-            // 不做MES质量检查,前缀校验通过即启动
-            startWorkA(scanBarcode.trim());
+            if (!tcp_connect_flag) {
+                JOptionPane.showMessageDialog(mesClientFrame, "设备未连接Mes服务器", "提示窗口", JOptionPane.INFORMATION_MESSAGE);
+                return;
+            }
+
+            // 查询工件质量,合格(UD)后由 MesRevice.checkQualityRevice 回调启动设备
+            Boolean sendret = DataUtil.checkQuality(nettyClient, scanBarcode.trim(), user20, Config.gw_1);
+            if (!sendret) {
+                JOptionPane.showMessageDialog(mesClientFrame, "消息发送失败,请重试", "提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            }
         } else {
             JOptionPane.showMessageDialog(mesClientFrame, "请扫工件码", "提示窗口", JOptionPane.INFORMATION_MESSAGE);
         }
@@ -611,19 +629,30 @@ public class MesClient extends JFrame {
             //刷新界面
             mesClientFrame.repaint();
 
-            // 不做MES质量检查,前缀校验通过即启动
-            startWorkB(scanBarcode.trim());
+            if (!tcp_connect_flag) {
+                JOptionPane.showMessageDialog(mesClientFrame, "设备未连接Mes服务器", "提示窗口", JOptionPane.INFORMATION_MESSAGE);
+                return;
+            }
+
+            // 查询工件质量,合格(UD)后由 MesRevice.checkQualityRevice 回调启动设备
+            Boolean sendret = DataUtil.checkQuality(nettyClient, scanBarcode.trim(), user20, Config.gw_2);
+            if (!sendret) {
+                JOptionPane.showMessageDialog(mesClientFrame, "消息发送失败,请重试", "提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            }
         } else {
             JOptionPane.showMessageDialog(mesClientFrame, "请扫工件码", "提示窗口", JOptionPane.INFORMATION_MESSAGE);
         }
     }
 
-    // 工位1开工:不做MES质量检查,扫码通过前缀校验即启动设备
+    // 工位1开工:由质量查询回调(UD合格)触发
     public static void startWorkA(String barcode) {
         if (work_status1 != 0) {
             return;
         }
         getUser();
+        // 通知MES开始加工
+        DataUtil.startWork(nettyClient, getBarcode(barcode), user20, Config.gw_1);
+
         work_status1 = 1;
         f_scan_data_bt_1.setEnabled(false);
 
@@ -640,12 +669,15 @@ public class MesClient extends JFrame {
         setMenuState_1("设备已启动,拉铆中", 0);
     }
 
-    // 工位2开工
+    // 工位2开工:由质量查询回调(UD合格)触发
     public static void startWorkB(String barcode) {
         if (work_status2 != 0) {
             return;
         }
         getUser();
+        // 通知MES开始加工
+        DataUtil.startWork(nettyClient, getBarcode(barcode), user20, Config.gw_2);
+
         work_status2 = 1;
         f_scan_data_bt_2.setEnabled(false);
 
@@ -699,7 +731,7 @@ public class MesClient extends JFrame {
 
     public MesClient() {
         setIconImage(Toolkit.getDefaultToolkit().getImage(MesClient.class.getResource("/bg/logo.png")));
-        setTitle("MES系统客户端:OP245- " + Config.gw_des_1);
+        setTitle("MES系统客户端:" + OprnoUtil.formatOprno(Config.gw_1) + "- " + Config.gw_des_1);
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         setBounds(0, 0, 1024, 768);
 
@@ -1027,7 +1059,7 @@ public class MesClient extends JFrame {
         status_menu_1.setBounds(100, 38, 369, 53);
         indexPanelA.add(status_menu_1);
 
-        JLabel state_label_1 = new JLabel("OP245A");
+        JLabel state_label_1 = new JLabel(Config.gw_1);
         state_label_1.setHorizontalAlignment(SwingConstants.LEFT);
         state_label_1.setForeground(Color.BLACK);
         state_label_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
@@ -1163,7 +1195,7 @@ public class MesClient extends JFrame {
         status_menu_2.setBounds(597, 38, 369, 53);
         indexPanelA.add(status_menu_2);
 
-        JLabel state_label_2 = new JLabel("OP245B");
+        JLabel state_label_2 = new JLabel(Config.gw_2);
         state_label_2.setHorizontalAlignment(SwingConstants.LEFT);
         state_label_2.setForeground(Color.BLACK);
         state_label_2.setFont(new Font("微软雅黑", Font.PLAIN, 20));
@@ -1184,17 +1216,23 @@ public class MesClient extends JFrame {
         tabbedPane.addTab("工作面板", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA, null);
         tabbedPane.setEnabledAt(0, true);
 
-        // 工作记录改为读本地SQLite,不再加载MES网页
-        workRecordPanel = new WorkRecordPanel();
-        tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), workRecordPanel, null);
+        indexPanelC = new JPanel();
+        searchScrollPaneDj = new JScrollPane(indexPanelC);
+        indexPanelC.setLayout(null);
+        tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
+
+        indexPanelB = new JPanel();
+        searchScrollPane = new JScrollPane(indexPanelB);
+        indexPanelB.setLayout(null);
+        tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
 
         tabbedPane.addChangeListener(new ChangeListener() {
             @Override
             public void stateChanged(ChangeEvent e) {
                 JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
-                // 切到工作记录页时刷新本地数据
-                if (tabbedPane.getSelectedComponent() == workRecordPanel && workRecordPanel != null) {
-                    workRecordPanel.reload();
+                int selectedIndex = tabbedPane.getSelectedIndex();
+                if (selectedIndex == 1) {
+
                 }
             }
         });

+ 113 - 0
src/com/mes/ui/MesRevice.java

@@ -0,0 +1,113 @@
+package com.mes.ui;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.mes.netty.ProtocolParam;
+import com.mes.util.Config;
+import com.mes.util.ErrorMsg;
+import com.mes.util.HttpUtils;
+import com.mes.util.ModbusUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.SwingUtilities;
+
+public class MesRevice {
+    private static final Logger log = LoggerFactory.getLogger(MesRevice.class);
+
+    // 质量查询回调:UD=可以加工,其他为拦截
+    public static void checkQualityRevice(String processMsgRet, String mes_msg){
+        try{
+            String oprno = ProtocolParam.getOprno(mes_msg).trim();
+            if (Config.gw_1.equalsIgnoreCase(oprno)) {
+                if(processMsgRet.equalsIgnoreCase("UD")) {
+                    MesClient.check_quality_result1 = true;  // 质量合格,可以加工
+                    MesClient.setMenuState_1("该工件可以加工", 0);
+                    // 合格才启动设备
+                    MesClient.startWorkA(MesClient.product_sn_1.getText().trim());
+                }else {
+                    MesClient.check_quality_result1 = false;
+                    MesClient.setMenuState_1(buildErrorMsg(processMsgRet, mes_msg,
+                            MesClient.product_sn_1.getText(), Config.gw_1), -1);
+                }
+            } else if(Config.gw_2.equalsIgnoreCase(oprno)){
+                if(processMsgRet.equalsIgnoreCase("UD")) {
+                    MesClient.check_quality_result2 = true;  // 质量合格,可以加工
+                    MesClient.setMenuState_2("该工件可以加工", 0);
+                    // 合格才启动设备
+                    MesClient.startWorkB(MesClient.product_sn_2.getText().trim());
+                }else {
+                    MesClient.check_quality_result2 = false;
+                    MesClient.setMenuState_2(buildErrorMsg(processMsgRet, mes_msg,
+                            MesClient.product_sn_2.getText(), Config.gw_2), -1);
+                }
+            }
+        }catch (Exception e){
+            log.error("质量查询报文回调出现错误", e);
+        }
+    }
+
+    // 拦截原因文案;QD+LX20 时再查一次OP200恒温静置剩余时间
+    private static String buildErrorMsg(String processMsgRet, String mes_msg, String sn, String gw){
+        String lmsg = ErrorMsg.getErrorMsg(processMsgRet, ProtocolParam.getLx(mes_msg));
+        if(!"QD".equals(processMsgRet) || !"20".equals(ProtocolParam.getLx(mes_msg))){
+            return lmsg;
+        }
+        try {
+            JSONObject json = new JSONObject().fluentPut("sn", sn.trim());
+            String response = HttpUtils.sendJsonPost(
+                    String.format("http://%s:8980/js/a/mes/mesProductRecord/checkOP200State", Config.server_ip),
+                    json.toJSONString(), 2000);
+            log.info("{}检查OP200状态接口响应: {}", gw, response);
+            JSONObject jsonObject = JSON.parseObject(response);
+            if (jsonObject != null && jsonObject.getBoolean("result")) {
+                lmsg = "恒温静置还有" + jsonObject.getInteger("data") + "分钟";
+            }
+        } catch (Exception e) {
+            log.error("查询OP200状态失败: " + e.getMessage());
+        }
+        return lmsg;
+    }
+
+    // 开工回复处理
+    public static void startRevice(String processMsgRet, String mes_msg){
+        log.info("开工报文回复: {}", processMsgRet);
+    }
+
+    // 工位结果(MQDW)提交回复:成功后复位并自动弹出下一件扫码框
+    public static void updateResultRevice(String processMsgRet, String mes_msg){
+        try{
+            String oprno = ProtocolParam.getOprno(mes_msg).trim();
+            boolean ok = processMsgRet.equalsIgnoreCase("OK");
+
+            if (Config.gw_1.equalsIgnoreCase(oprno)) {
+                MesClient.isSubmitting1 = false;
+                if(!ok){
+                    MesClient.setMenuState_1("结果提交失败,请重试", -1);
+                    return;
+                }
+                ModbusUtil.clearCountA();      // 清零PLC已打/合格/不合格数量
+                // 扫码框是模态的,必须切到EDT,否则阻塞Netty线程收不到后续报文
+                SwingUtilities.invokeLater(() -> {
+                    MesClient.resetScanA();
+                    MesClient.setMenuState_1("结果提交成功,请扫下一件", 0);
+                    MesClient.scanBarcode1();
+                });
+            } else if(Config.gw_2.equalsIgnoreCase(oprno)){
+                MesClient.isSubmitting2 = false;
+                if(!ok){
+                    MesClient.setMenuState_2("结果提交失败,请重试", -1);
+                    return;
+                }
+                ModbusUtil.clearCountB();
+                SwingUtilities.invokeLater(() -> {
+                    MesClient.resetScanB();
+                    MesClient.setMenuState_2("结果提交成功,请扫下一件", 0);
+                    MesClient.scanBarcode2();
+                });
+            }
+        }catch (Exception e){
+            log.error("工位结果提交回调出现错误", e);
+        }
+    }
+}

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

@@ -16,7 +16,7 @@ public class OprnoUtil {
             "镭雕二维码","前边梁压铆,单部件拉铆","框架CMT焊接","人工补焊",
             "焊道检查","焊道打磨","","框架气密","框架反面CNC加工+去毛刺","框架反面,吹铝屑+清洁",
             "框架涂胶","液冷板安装+水冷板点焊","液冷板FSW","匙孔补焊+匙孔补焊打磨",
-            "总成正面CNC+去毛刺","总成正面,吹铝屑+清洁","总成正面装配","套筒涂胶","中吊点拉铆","封堵片焊接",
+            "总成正面CNC+去毛刺","总成正面,吹铝屑+清洁","总成正面装配","套筒涂胶","封堵片焊接","中吊点拉铆",
             "左右边梁封堵","半成品气密","VHB胶带粘贴+冷板泡棉粘贴","冷板背面涂胶",
             "底护板清洗","安装底护板","成品气密","液冷板气密","总成检具检验","箱体封堵",
             "总成清洁","粘贴云母片","CCD","终检","GP12正面","后梁底涂镭雕","GP12反面","包装"

+ 0 - 178
src/com/mes/ui/WorkRecordPanel.java

@@ -1,178 +0,0 @@
-package com.mes.ui;
-
-import com.mes.util.JdbcUtils;
-
-import javax.swing.*;
-import javax.swing.table.DefaultTableModel;
-import java.awt.*;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-
-/**
- * 本地工作记录(计件)面板
- * 数据全部来自本地 SQLite 的 work_record 表,不依赖 MES 服务器
- */
-public class WorkRecordPanel extends JPanel {
-
-    private static final String[] COLUMNS = {"工件码", "结果", "完成时间"};
-    private static final int LIMIT = 2000;
-
-    private static final Font FONT_BAR = new Font("微软雅黑", Font.PLAIN, 18);
-    private static final Font FONT_BTN = new Font("微软雅黑", Font.PLAIN, 16);
-    private static final Font FONT_SUM = new Font("微软雅黑", Font.BOLD, 20);
-    private static final Font FONT_CELL = new Font("微软雅黑", Font.PLAIN, 16);
-
-    private static final SimpleDateFormat FMT_DAY = new SimpleDateFormat("yyyy-MM-dd");
-    private static final SimpleDateFormat FMT_TIME = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-    private final JTextField fromField = new JTextField(15);
-    private final JTextField toField = new JTextField(15);
-    private final JTextField hoursField = new JTextField("8", 3);
-    private final JLabel sumLabel = new JLabel();
-    private final DefaultTableModel model = new DefaultTableModel(COLUMNS, 0) {
-        @Override
-        public boolean isCellEditable(int row, int column) {
-            return false;
-        }
-    };
-
-    public WorkRecordPanel() {
-        setLayout(new BorderLayout(0, 0));
-        setToday();
-        add(buildToolBar(), BorderLayout.NORTH);
-        add(new JScrollPane(buildTable()), BorderLayout.CENTER);
-        add(buildSumBar(), BorderLayout.SOUTH);
-        reload();
-    }
-
-    // 今日 00:00:00 ~ 23:59:59
-    private void setToday() {
-        String day = FMT_DAY.format(new Date());
-        fromField.setText(day + " 00:00:00");
-        toField.setText(day + " 23:59:59");
-    }
-
-    // 本班:从当前往前推 N 小时,N 取输入框的值,非法则用 8
-    private void setLastHours() {
-        int hours = 8;
-        try {
-            hours = Integer.parseInt(hoursField.getText().trim());
-        } catch (NumberFormatException ignore) {
-            hoursField.setText("8");
-        }
-        if (hours <= 0) {
-            hours = 8;
-            hoursField.setText("8");
-        }
-
-        Calendar c = Calendar.getInstance();
-        toField.setText(FMT_TIME.format(c.getTime()));
-        c.add(Calendar.HOUR_OF_DAY, -hours);
-        fromField.setText(FMT_TIME.format(c.getTime()));
-    }
-
-    private JPanel buildToolBar() {
-        JPanel bar = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 8));
-
-        JLabel fromLabel = new JLabel("开始:");
-        fromLabel.setFont(FONT_BAR);
-        fromField.setFont(FONT_BAR);
-        fromField.setToolTipText("支持 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss,留空为不限");
-        fromField.addActionListener(e -> reload());
-
-        JLabel toLabel = new JLabel("结束:");
-        toLabel.setFont(FONT_BAR);
-        toField.setFont(FONT_BAR);
-        toField.setToolTipText("支持 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss,留空为不限");
-        toField.addActionListener(e -> reload());
-
-        bar.add(fromLabel);
-        bar.add(fromField);
-        bar.add(toLabel);
-        bar.add(toField);
-        bar.add(button("查询", e -> reload()));
-        bar.add(button("今日", e -> {
-            setToday();
-            reload();
-        }));
-        bar.add(button("本班", e -> {
-            setLastHours();
-            reload();
-        }));
-        hoursField.setFont(FONT_BAR);
-        hoursField.setHorizontalAlignment(SwingConstants.CENTER);
-        hoursField.setToolTipText("本班时长(小时),回车即按该时长查询");
-        hoursField.addActionListener(e -> {
-            setLastHours();
-            reload();
-        });
-        bar.add(hoursField);
-        JLabel hoursLabel = new JLabel("小时");
-        hoursLabel.setFont(FONT_BAR);
-        bar.add(hoursLabel);
-
-        bar.add(button("全部", e -> {
-            fromField.setText("");
-            toField.setText("");
-            reload();
-        }));
-        return bar;
-    }
-
-    // 计件汇总条放底部,避免顶部工具条被挤换行
-    private JPanel buildSumBar() {
-        JPanel bar = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 6));
-        sumLabel.setFont(FONT_SUM);
-        sumLabel.setForeground(new Color(0, 102, 0));
-        bar.add(sumLabel);
-        return bar;
-    }
-
-    private JButton button(String text, java.awt.event.ActionListener listener) {
-        JButton bt = new JButton(text);
-        bt.setFont(FONT_BTN);
-        bt.setMargin(new Insets(4, 8, 4, 8));
-        bt.addActionListener(listener);
-        return bt;
-    }
-
-    private JTable buildTable() {
-        JTable table = new JTable(model);
-        table.setRowHeight(32);
-        table.setFont(FONT_CELL);
-        table.getTableHeader().setFont(FONT_BAR);
-        table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
-        int[] widths = {500, 100, 220};
-        for (int i = 0; i < widths.length; i++) {
-            table.getColumnModel().getColumn(i).setPreferredWidth(widths[i]);
-        }
-        return table;
-    }
-
-    /** 按当前时间范围重新加载计件汇总和明细 */
-    public void reload() {
-        String from = fromField.getText().trim();
-        String to = toField.getText().trim();
-
-        model.setRowCount(0);
-        for (Object[] row : JdbcUtils.getWorkRecords(from, to, LIMIT)) {
-            model.addRow(row);
-        }
-
-        // 汇总:合计 + 各工位计件数
-        StringBuilder sb = new StringBuilder();
-        int total = 0;
-        int totalOk = 0;
-        List<Object[]> counts = JdbcUtils.countWorkRecords(from, to);
-        for (Object[] c : counts) {
-            int cnt = (Integer) c[1];
-            int ok = (Integer) c[2];
-            total += cnt;
-            totalOk += ok;
-            sb.append("   ").append(c[0]).append(": ").append(cnt).append("件(OK ").append(ok).append(")");
-        }
-        sumLabel.setText("计件合计: " + total + "件  OK " + totalOk + "件" + sb);
-    }
-}

+ 45 - 43
src/com/mes/util/ModbusUtil.java

@@ -1,6 +1,7 @@
 package com.mes.util;
 
 import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
+import com.mes.ui.DataUtil;
 import com.mes.ui.MesClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -124,49 +125,77 @@ public class ModbusUtil {
         }
     }
 
-    // 拉铆完成:只写本地工作记录计件,不向MES提交工位结果(拉铆参数由定时任务另行上传)
+    // 拉铆完成:写本地计件 + 向MES提交工位结果(MQDW)
+    // 清零PLC和复位在 MesRevice.updateResultRevice 收到提交成功后进行
     public static void upResultA(){
+        if(MesClient.isSubmitting1){
+            return;   // 正在提交,等MES回复
+        }
         if(MesClient.product_sn_1.getText().isEmpty() || MesClient.aMax <= 0 || MesClient.sortA < MesClient.aMax){
             return;
         }
 
         String sn = MesClient.product_sn_1.getText();
         String result = MesClient.aFinish == MesClient.aMax ? "OK" : "NG";
-        // 拉铆参数照常上传,本地计件按工件码防重
+
+        // 本地计件按工件码防重(拉铆参数由定时任务另行上传,不受防重影响)
         boolean counted = JdbcUtils.insertWorkRecord(Config.gw_1, sn,
                 MesClient.aMax, MesClient.aFinish, result, MesClient.user_menu.getText());
+        if(!counted){
+            log.info("A工位工件码重复,本地不重复计件: " + sn);
+        }
 
+        MesClient.isSubmitting1 = true;
         MesClient.heartBeatFlag = false;   // 停心跳,设备停止
-        clearCount(MesClient.plcA, "A");
-        resetStationA();
-        MesClient.setMenuState_1(counted
-                ? "已完成计件(" + result + "),请扫下一件"
-                : "工件码重复,不重复计件,请扫下一件", 0);
-        refreshWorkRecord();
+        MesClient.setMenuState_1("正在提交结果", 0);
+
+        MesClient.getUser();
+        Boolean ret = DataUtil.sendQuality(MesClient.nettyClient, sn, result, MesClient.user20, Config.gw_1);
+        if(!ret){
+            MesClient.isSubmitting1 = false;
+            MesClient.setMenuState_1(MesClient.tjFlagTextErr, -1);
+        }
     }
 
-    // 拉铆完成:写本地工作记录计件
+    // 拉铆完成:写本地计件 + 向MES提交工位结果(MQDW)
     public static void upResultB(){
+        if(MesClient.isSubmitting2){
+            return;
+        }
         if(MesClient.product_sn_2.getText().isEmpty() || MesClient.bMax <= 0 || MesClient.sortB < MesClient.bMax){
             return;
         }
 
         String sn = MesClient.product_sn_2.getText();
         String result = MesClient.bFinish == MesClient.bMax ? "OK" : "NG";
-        // 拉铆参数照常上传,本地计件按工件码防重
+
         boolean counted = JdbcUtils.insertWorkRecord(Config.gw_2, sn,
                 MesClient.bMax, MesClient.bFinish, result, MesClient.user_menu.getText());
+        if(!counted){
+            log.info("B工位工件码重复,本地不重复计件: " + sn);
+        }
 
+        MesClient.isSubmitting2 = true;
         MesClient.heartBeatFlag2 = false;  // 停心跳,设备停止
-        clearCount(MesClient.plcB, "B");
-        resetStationB();
-        MesClient.setMenuState_2(counted
-                ? "已完成计件(" + result + "),请扫下一件"
-                : "工件码重复,不重复计件,请扫下一件", 0);
-        refreshWorkRecord();
+        MesClient.setMenuState_2("正在提交结果", 0);
+
+        MesClient.getUser();
+        Boolean ret = DataUtil.sendQuality(MesClient.nettyClient, sn, result, MesClient.user20, Config.gw_2);
+        if(!ret){
+            MesClient.isSubmitting2 = false;
+            MesClient.setMenuState_2(MesClient.tjFlagTextErr, -1);
+        }
     }
 
     // 清零PLC已打数量/合格数量/不合格数量
+    public static void clearCountA(){
+        clearCount(MesClient.plcA, "A");
+    }
+
+    public static void clearCountB(){
+        clearCount(MesClient.plcB, "B");
+    }
+
     private static void clearCount(ModbusTcp plc, String tag){
         try {
             if (plc != null) {
@@ -180,33 +209,6 @@ public class ModbusUtil {
         }
     }
 
-    // 工位1完成后复位,等待扫下一件
-    private static void resetStationA(){
-        MesClient.aFinish = 0;
-        MesClient.aMax = 0;
-        MesClient.sortA = 0;
-        MesClient.work_status1 = 0;
-        MesClient.product_sn_1.setText("");
-        MesClient.f_scan_data_bt_1.setEnabled(true);
-    }
-
-    // 工位2完成后复位,等待扫下一件
-    private static void resetStationB(){
-        MesClient.bFinish = 0;
-        MesClient.bMax = 0;
-        MesClient.sortB = 0;
-        MesClient.work_status2 = 0;
-        MesClient.product_sn_2.setText("");
-        MesClient.f_scan_data_bt_2.setEnabled(true);
-    }
-
-    private static void refreshWorkRecord(){
-        if (MesClient.workRecordPanel != null) {
-            // PLC定时线程里刷新表格,切回EDT
-            SwingUtilities.invokeLater(() -> MesClient.workRecordPanel.reload());
-        }
-    }
-
     // 获取控制模式
     public static short getControlModel(ModbusTcp plc){
         short control = 0;

+ 2 - 2
src/resources/config/config.properties

@@ -2,8 +2,8 @@
 #Thu Aug 06 17:48:19 CST 2026
 mes.workpiece_prefix=+KA99,+KC14,+KB98
 mes.heart_beat_cycle=60
-mes.gw_2=OP240A
-mes.gw_1=OP240B
+mes.gw_1=OP245A
+mes.gw_2=OP245C
 mes.line_sn=XT
 mes.tcp_port=3000
 mes.plc_timeout_enabled=true

+ 1 - 1
src/resources/logback.xml

@@ -4,7 +4,7 @@
 
     <!-- 定义日志文件的存储位置及文件名 -->
     <property name="LOG_HOME" value="D:/Logs"/>
-    <property name="PROJECT_NAME" value="OP150"/>
+    <property name="PROJECT_NAME" value="OP245"/>
 
     <!-- 控制台输出 -->
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">