Преглед на файлове

优化功能:pda扫码、行程管控

jingbo преди 1 ден
родител
ревизия
9d20a4659a

BIN
lib/iot-communication-1.4.4.jar


BIN
lib/iot-communication-1.5.3.jar


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

@@ -13,6 +13,38 @@ import java.util.Properties;
 
 public class DataUtil {
 
+    // 删除当前工位后台工件码
+    public static JSONObject delCurSn(String oprno, String serverIp, String lineSn) {
+        try {
+            String url = "http://" + serverIp + ":8980/js/a/mes/mesProductRecord/cancelCurSn";
+            String params = "__ajax=json&oprno=" + oprno + "&lineSn=" + lineSn + "&__sid=" + MesClient.sessionid;
+            String result = doPost(url, params);
+            if (result == null || result.equalsIgnoreCase("false")) {
+                return null;
+            }
+            return JSONObject.parseObject(result);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    // 从后台获取当前工位工件码
+    public static JSONObject getCurSn(String oprno, String serverIp, String lineSn) {
+        try {
+            String url = "http://" + serverIp + ":8980/js/a/mes/mesProductRecord/getCurSn";
+            String params = "__ajax=json&oprno=" + oprno + "&lineSn=" + lineSn + "&__sid=" + MesClient.sessionid;
+            String result = doPost(url, params);
+            if (result == null || result.equalsIgnoreCase("false")) {
+                return null;
+            }
+            return JSONObject.parseObject(result);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
     public static Boolean synrTcp(NettyClient nettyClient,String mes_gw){
         try{
             //TCP连接后,直接先发同步报文

+ 256 - 0
src/com/mes/ui/DeviceManagePanel.java

@@ -0,0 +1,256 @@
+package com.mes.ui;
+
+import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
+import com.mes.util.JdbcUtils;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 设备管理:IP、预设数量、按颗数区间的铆接参数配置
+ */
+public class DeviceManagePanel extends JPanel {
+
+    private static final String[] PARAM_COLUMNS = {"起始颗", "结束颗", "F-min", "F-max", "S-min", "S-max"};
+    private static final int CONTENT_WIDTH = 940;
+
+    private JTextField txtASet;
+    private JTextField txtBSet;
+    private JTextField txtIpA;
+    private JTextField txtIpB;
+    private DefaultTableModel tableModelA;
+    private DefaultTableModel tableModelB;
+    private JTable tableA;
+    private JTable tableB;
+
+    public DeviceManagePanel() {
+        setLayout(null);
+        setPreferredSize(new Dimension(980, 720));
+        buildUi();
+        loadConfigToUi();
+    }
+
+    private void buildUi() {
+        Font labelFont = new Font("微软雅黑", Font.PLAIN, 18);
+        Font fieldFont = new Font("微软雅黑", Font.PLAIN, 18);
+        Font hintFont = new Font("微软雅黑", Font.PLAIN, 14);
+
+        addLabel("A枪预设数量:", 20, 16, 130, 34, labelFont);
+        txtASet = addField(String.valueOf(MesClient.aSetNum), 150, 16, 120, 34, fieldFont);
+
+        addLabel("B枪预设数量:", 320, 16, 130, 34, labelFont);
+        txtBSet = addField(String.valueOf(MesClient.bSetNum), 450, 16, 120, 34, fieldFont);
+
+        addLabel("A枪IP:", 20, 58, 80, 34, labelFont);
+        txtIpA = addField(MesClient.curIpA, 100, 58, 170, 34, fieldFont);
+
+        addLabel("B枪IP:", 320, 58, 80, 34, labelFont);
+        txtIpB = addField(MesClient.curIpB, 400, 58, 170, 34, fieldFont);
+
+        addLabel("说明:S-min/S-max 为PLC原始值,界面行程显示值 = S / 1000", 20, 98, CONTENT_WIDTH, 24, hintFont);
+
+        addLabel("A枪参数区间", 20, 128, 200, 28, labelFont);
+        tableModelA = createParamTableModel();
+        tableA = createParamTable(tableModelA, 20, 156, CONTENT_WIDTH, 150);
+
+        JButton btnAddA = new JButton("A枪添加行");
+        btnAddA.setFont(labelFont);
+        btnAddA.setBounds(20, 316, 120, 32);
+        btnAddA.addActionListener(e -> tableModelA.addRow(new Object[]{"", "", "0", "0", "0", "0"}));
+        add(btnAddA);
+
+        JButton btnDelA = new JButton("A枪删除行");
+        btnDelA.setFont(labelFont);
+        btnDelA.setBounds(150, 316, 120, 32);
+        btnDelA.addActionListener(e -> removeSelectedRow(tableA, tableModelA));
+        add(btnDelA);
+
+        addLabel("B枪参数区间", 20, 360, 200, 28, labelFont);
+        tableModelB = createParamTableModel();
+        tableB = createParamTable(tableModelB, 20, 388, CONTENT_WIDTH, 150);
+
+        JButton btnAddB = new JButton("B枪添加行");
+        btnAddB.setFont(labelFont);
+        btnAddB.setBounds(20, 548, 120, 32);
+        btnAddB.addActionListener(e -> tableModelB.addRow(new Object[]{"", "", "0", "0", "0", "0"}));
+        add(btnAddB);
+
+        JButton btnDelB = new JButton("B枪删除行");
+        btnDelB.setFont(labelFont);
+        btnDelB.setBounds(150, 548, 120, 32);
+        btnDelB.addActionListener(e -> removeSelectedRow(tableB, tableModelB));
+        add(btnDelB);
+
+        JButton btnSave = new JButton("保存全部设置");
+        btnSave.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        btnSave.setBounds(380, 596, 180, 45);
+        btnSave.addActionListener(e -> saveAllConfig());
+        add(btnSave);
+
+        addLabel("每行表示「从起始颗到结束颗」使用同一套参数;开工时下发第1颗参数,每完成一颗后自动切换下一颗区间。",
+                20, 652, CONTENT_WIDTH, 40, hintFont);
+    }
+
+    private void addLabel(String text, int x, int y, int w, int h, Font font) {
+        JLabel label = new JLabel("<html>" + text + "</html>");
+        label.setFont(font);
+        label.setBounds(x, y, w, h);
+        add(label);
+    }
+
+    private JTextField addField(String text, int x, int y, int w, int h, Font font) {
+        JTextField field = new JTextField(text);
+        field.setFont(font);
+        field.setBounds(x, y, w, h);
+        add(field);
+        return field;
+    }
+
+    private DefaultTableModel createParamTableModel() {
+        return new DefaultTableModel(PARAM_COLUMNS, 0) {
+            @Override
+            public boolean isCellEditable(int row, int column) {
+                return true;
+            }
+        };
+    }
+
+    private JTable createParamTable(DefaultTableModel model, int x, int y, int w, int h) {
+        JTable table = new JTable(model);
+        table.setRowHeight(28);
+        table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+        JScrollPane scrollPane = new JScrollPane(table);
+        scrollPane.setBounds(x, y, w, h);
+        add(scrollPane);
+        return table;
+    }
+
+    private void removeSelectedRow(JTable table, DefaultTableModel model) {
+        int row = table.getSelectedRow();
+        if (row >= 0) {
+            model.removeRow(row);
+        }
+    }
+
+    private void loadConfigToUi() {
+        txtASet.setText(String.valueOf(MesClient.aSetNum));
+        txtBSet.setText(String.valueOf(MesClient.bSetNum));
+        txtIpA.setText(MesClient.curIpA);
+        txtIpB.setText(MesClient.curIpB);
+        fillTableModel(tableModelA, JdbcUtils.getRivetParams("A"));
+        fillTableModel(tableModelB, JdbcUtils.getRivetParams("B"));
+    }
+
+    private void fillTableModel(DefaultTableModel model, List<RivetParamRange> ranges) {
+        model.setRowCount(0);
+        for (RivetParamRange range : ranges) {
+            model.addRow(new Object[]{
+                    String.valueOf(range.getStartRivet()),
+                    String.valueOf(range.getEndRivet()),
+                    String.valueOf(range.getFMin()),
+                    String.valueOf(range.getFMax()),
+                    String.valueOf(range.getSMin()),
+                    String.valueOf(range.getSMax())
+            });
+        }
+    }
+
+    private List<RivetParamRange> parseTableModel(DefaultTableModel model, String gunType) throws IllegalArgumentException {
+        List<RivetParamRange> ranges = new ArrayList<>();
+        for (int i = 0; i < model.getRowCount(); i++) {
+            String startText = String.valueOf(model.getValueAt(i, 0)).trim();
+            String endText = String.valueOf(model.getValueAt(i, 1)).trim();
+            if (startText.isEmpty() && endText.isEmpty()) {
+                continue;
+            }
+            if (startText.isEmpty() || endText.isEmpty()) {
+                throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行起始颗/结束颗不能为空");
+            }
+            int start = Integer.parseInt(startText);
+            int end = Integer.parseInt(endText);
+            if (start < 1 || end < start) {
+                throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行颗数范围无效");
+            }
+            RivetParamRange range = new RivetParamRange();
+            range.setGunType(gunType);
+            range.setStartRivet(start);
+            range.setEndRivet(end);
+            range.setFMin(parseIntCell(model, i, 2));
+            range.setFMax(parseIntCell(model, i, 3));
+            range.setSMin(parseIntCell(model, i, 4));
+            range.setSMax(parseIntCell(model, i, 5));
+            ranges.add(range);
+        }
+        if (ranges.isEmpty()) {
+            throw new IllegalArgumentException(gunType + "枪至少配置一行参数区间");
+        }
+        return ranges;
+    }
+
+    private int parseIntCell(DefaultTableModel model, int row, int col) {
+        String text = String.valueOf(model.getValueAt(row, col)).trim();
+        if (text.isEmpty()) {
+            return 0;
+        }
+        return Integer.parseInt(text);
+    }
+
+    private void saveAllConfig() {
+        try {
+            short newASet = Short.parseShort(txtASet.getText().trim());
+            short newBSet = Short.parseShort(txtBSet.getText().trim());
+            String newIpA = txtIpA.getText().trim();
+            String newIpB = txtIpB.getText().trim();
+            if (newIpA.isEmpty() || newIpB.isEmpty()) {
+                JOptionPane.showMessageDialog(MesClient.mesClientFrame, "IP地址不能为空", "错误", JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+
+            List<RivetParamRange> rangesA = parseTableModel(tableModelA, "A");
+            List<RivetParamRange> rangesB = parseTableModel(tableModelB, "B");
+
+            JdbcUtils.updateConfig(newASet, newBSet, newIpA, newIpB);
+            JdbcUtils.saveRivetParams("A", rangesA);
+            JdbcUtils.saveRivetParams("B", rangesB);
+
+            MesClient.aSetNum = newASet;
+            MesClient.bSetNum = newBSet;
+            MesClient.rivetParamRangesA = rangesA;
+            MesClient.rivetParamRangesB = rangesB;
+
+            if (MesClient.param1 != null) {
+                MesClient.param1.setText(String.valueOf(MesClient.aSetNum));
+            }
+            if (MesClient.param3 != null) {
+                MesClient.param3.setText(String.valueOf(MesClient.bSetNum));
+            }
+
+            boolean ipAChanged = !newIpA.equals(MesClient.curIpA);
+            boolean ipBChanged = !newIpB.equals(MesClient.curIpB);
+            if (ipAChanged) {
+                if (MesClient.plcA != null) {
+                    MesClient.plcA.close();
+                }
+                MesClient.curIpA = newIpA;
+                MesClient.plcA = new ModbusTcp(1, MesClient.curIpA);
+            }
+            if (ipBChanged) {
+                if (MesClient.plcB != null) {
+                    MesClient.plcB.close();
+                }
+                MesClient.curIpB = newIpB;
+                MesClient.plcB = new ModbusTcp(1, MesClient.curIpB);
+            }
+
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame, "配置已保存", "提示", JOptionPane.INFORMATION_MESSAGE);
+        } catch (NumberFormatException ex) {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame, "请输入有效的数字", "错误", JOptionPane.ERROR_MESSAGE);
+        } catch (IllegalArgumentException ex) {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame, ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+}

+ 1 - 0
src/com/mes/ui/LoginFarme.java

@@ -178,6 +178,7 @@ public class LoginFarme extends JFrame {
                     MesClient.user_menu.setText(user_id);
                     MesClient.welcomeWin.setVisible(false);
                     MesClient.mesClientFrame.setVisible(true);
+                    MesClient.startGetCurSn();
 
                     if(MesClient.jfxPanel == null){
                         String url = "http://"+ MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/work?__sid="+MesClient.sessionid+"&oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn;

+ 240 - 177
src/com/mes/ui/MesClient.java

@@ -67,11 +67,9 @@ public class MesClient extends JFrame {
     public static JButton status_menu;
     public static JButton user_menu;
 
-    public static int scan_type = 0;
     public static JButton finish_ok_bt;
     public static JButton finish_ng_bt;
     public static JTextField product_sn;
-    public static JButton f_scan_data_bt_1;
 
     public static String user20 = "";
 
@@ -88,6 +86,11 @@ public class MesClient extends JFrame {
     public static JTextField param2;
     public static JTextField param3;
     public static JTextField param4;
+    // A/B枪实时拉力、行程显示
+    public static JTextField param5;
+    public static JTextField param6;
+    public static JTextField param7;
+    public static JTextField param8;
 
     public static ModbusTcp plcA;
     public static ModbusTcp plcB;
@@ -116,10 +119,21 @@ public class MesClient extends JFrame {
     public static Short deviceControl = 0; // 0=本地 1=远程
     public static Integer tjStatus = 0; // 1=提交失败
 
+    // 铆接参数区间配置(内存缓存)
+    public static List<RivetParamRange> rivetParamRangesA = new ArrayList<>();
+    public static List<RivetParamRange> rivetParamRangesB = new ArrayList<>();
+
     public static String tjFlagTextErr = "结果上传MES失败,请重试";
 
     public static String curSn = "";
 
+    // 后台拉码定时器
+    public static Timer getSnBeatTimer;
+    // 已提交质量询问、等待TCP应答的工件码
+    public static String backendPollingSn = "";
+    // 质量检查未通过的后台码,避免重复轮询
+    public static String lastRejectedBackendSn = "";
+
     public static JTable table;
     public static Object[] columnNames = { "物料名称", "绑定批次", "剩余次数", "操作" };
     public static Object[][] rowData = null;
@@ -167,6 +181,14 @@ public class MesClient extends JFrame {
         cjTimer4.schedule(new TimerTask() {
             public void run() {
                 try{
+                    // MES屏蔽时仅维持拉铆枪运行,不做空闲关机等干预
+                    if (mes_shield_flag) {
+                        if (work_status == 1) {
+                            keepGunRunningIfNeeded(plcA, sortA, aMax);
+                            keepGunRunningIfNeeded(plcB, sortB, bMax);
+                        }
+                        return;
+                    }
                     if(work_status == 1){
                         List<Boolean> yxstatus = plcA.readCoil(3128,1);
                         if(yxstatus.size() >= 1 && !yxstatus.get(0)){
@@ -203,6 +225,20 @@ public class MesClient extends JFrame {
         }, 1000,1000);
     }
 
+    // MES屏蔽期间:任务未完成时保持拉铆枪运行
+    private static void keepGunRunningIfNeeded(ModbusTcp plc, Short sort, Short max) {
+        try {
+            List<Boolean> yxstatus = plc.readCoil(3128, 1);
+            if (yxstatus.size() >= 1 && !yxstatus.get(0)) {
+                if (!curSn.isEmpty() && max > 0 && max != sort) {
+                    ModbusUtil.setPowerOn(plc);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
     //读配置文件
     private static void readProperty() throws IOException{
         String enconding = "UTF-8";
@@ -248,6 +284,13 @@ public class MesClient extends JFrame {
             plcB = new ModbusTcp(1, curIpB);
             System.out.println("未找到本地配置,使用默认值");
         }
+        loadRivetParamConfig();
+    }
+
+    // 加载铆接参数区间配置
+    public static void loadRivetParamConfig() {
+        rivetParamRangesA = JdbcUtils.getRivetParams("A");
+        rivetParamRangesB = JdbcUtils.getRivetParams("B");
     }
 
     public static void getPlcParam() {
@@ -258,7 +301,7 @@ public class MesClient extends JFrame {
         cjTimer.schedule(new TimerTask() {
             public void run() {
                 try{
-                    if(work_status == 1){
+                    if(work_status == 1 && !mes_shield_flag){
                         ModbusUtil.getDataA(plcA);
                     }
 
@@ -267,7 +310,7 @@ public class MesClient extends JFrame {
                 }
 
                 try{
-                    if(work_status == 1){
+                    if(work_status == 1 && !mes_shield_flag){
                         ModbusUtil.getDataB(plcB);
                     }
 
@@ -289,15 +332,7 @@ public class MesClient extends JFrame {
                     String cSn = ModbusUtil.getSn(plcA);
                     if(!cSn.isEmpty()){
                         if(curSn.isEmpty()){
-                            product_sn.setText(cSn);
-                            curSn = cSn;
-
-                            //发送AQDW质量询问报文,当收到返回UD才能工作
-                            getUser();
-                            Boolean sendret = DataUtil.checkQuality(nettyClient,curSn,user20);
-                            if(!sendret){
-                                MesClient.setMenuStatus("消息发送失败,请重试",-1);
-                            }
+                            submitSnForQualityCheck(cSn, true);
                         }else if(!curSn.isEmpty() && !cSn.equals(curSn)){
                             resetScanA();
                         }
@@ -432,7 +467,117 @@ public class MesClient extends JFrame {
         resetScanA();
     }
 
+    // 启动后台拉码轮询
+    public static void startGetCurSn() {
+        if (getSnBeatTimer != null) {
+            getSnBeatTimer.cancel();
+        }
+        getSnBeatTimer = new Timer();
+        getSnBeatTimer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                pollBackendSn();
+            }
+        }, 100, 1000);
+    }
+
+    // 停止后台拉码轮询
+    public static void stopGetCurSn() {
+        if (getSnBeatTimer != null) {
+            getSnBeatTimer.cancel();
+            getSnBeatTimer = null;
+        }
+    }
+
+    // 清除后台拉码中间状态
+    public static void clearBackendSnState() {
+        backendPollingSn = "";
+        lastRejectedBackendSn = "";
+    }
+
+    // 清除后台工位工件码
+    public static void clearBackendCurSn() {
+        if (sessionid != null && !sessionid.isEmpty()) {
+            DataUtil.delCurSn(mes_gw, mes_server_ip, mes_line_sn);
+        }
+    }
+
+    // 轮询后台工件码
+    public static void pollBackendSn() {
+        try {
+            if (mes_shield_flag) {
+                return;
+            }
+            if (work_status == 1) {
+                return;
+            }
+            if (sessionid == null || sessionid.isEmpty()) {
+                return;
+            }
+            if (!backendPollingSn.isEmpty()) {
+                return;
+            }
+            if (!tcp_connect_flag) {
+                return;
+            }
+
+            JSONObject result = DataUtil.getCurSn(mes_gw, mes_server_ip, mes_line_sn);
+            if (result == null || !result.containsKey("data")) {
+                return;
+            }
+            String data = result.getString("data");
+            if (data == null || data.trim().isEmpty()) {
+                return;
+            }
+            data = data.trim();
+
+            if (data.equals(lastRejectedBackendSn)) {
+                return;
+            }
+            if (!curSn.isEmpty() && data.equals(curSn.trim())) {
+                return;
+            }
+
+            submitSnForQualityCheck(data, true);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    // 提交工件码进行质量询问(手动扫码与后台拉码共用)
+    public static boolean submitSnForQualityCheck(String scanBarcode, boolean fromBackend) {
+        getUser();
+        String barcode36 = getBarcode(scanBarcode);
+        product_sn.setText(scanBarcode);
+        curSn = scanBarcode;
+        backendPollingSn = scanBarcode.trim();
+        lastRejectedBackendSn = "";
+        mesClientFrame.repaint();
+
+        if (!tcp_connect_flag) {
+            backendPollingSn = "";
+            setMenuStatus("设备未连接Mes服务器", -1);
+            return false;
+        }
+
+        Boolean sendret = DataUtil.checkQuality(nettyClient, barcode36, user20);
+        if (!sendret) {
+            backendPollingSn = "";
+            setMenuStatus("消息发送失败,请重试", -1);
+            return false;
+        }
+
+        if (fromBackend) {
+            setMenuStatus("已从后台获取工件码,质量检查中", 0);
+        }
+        return true;
+    }
+
     public static void resetScanA() {
+        // 闭环:提交完成或刷新时清除后台工位码
+        clearBackendCurSn();
+        clearBackendSnState();
+
         work_status = 0;
         check_quality_result = false;
         MesClient.finish_ok_bt.setEnabled(false);
@@ -440,8 +585,7 @@ public class MesClient extends JFrame {
         product_sn.setText("");
         curSn = "";
 
-        MesClient.f_scan_data_bt_1.setEnabled(true);
-        MesClient.setMenuStatus("请扫工件码",0);
+        MesClient.setMenuStatus("等待后台工件码",0);
 
         MesClient.aMax = 0;
         MesClient.bMax = 0;
@@ -454,6 +598,7 @@ public class MesClient extends JFrame {
         MesClient.param2.setText("");
         MesClient.param3.setText(String.valueOf(bSetNum));
         MesClient.param4.setText("");
+        resetForceStrokeDisplay();
 
         deviceControl = ModbusUtil.getControlModel(plcA);
         if(deviceControl == 1){
@@ -465,8 +610,8 @@ public class MesClient extends JFrame {
         ModbusUtil.setPowerOff(MesClient.plcA); // 远程关机
         ModbusUtil.setPowerOff(MesClient.plcB); // 远程关机
 
-        ModbusUtil.setTask(MesClient.plcA,MesClient.aSetNum);
-        ModbusUtil.setTask(MesClient.plcB,MesClient.bSetNum);
+        ModbusUtil.setTask(MesClient.plcA, MesClient.aSetNum, "A");
+        ModbusUtil.setTask(MesClient.plcB, MesClient.bSetNum, "B");
 
         updateMaterailData();
     }
@@ -504,56 +649,19 @@ public class MesClient extends JFrame {
         return barcodeRet;
     }
 
-    public static void scanBarcode() {
-        if(work_status == 1){
-            JOptionPane.showMessageDialog(mesClientFrame,"工作中,勿扫码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-            return;
-        }
-        String scanBarcodeTitle = "";
-        switch(scan_type) {
-            case 1:
-                product_sn.setText("");
-                scanBarcodeTitle = "请扫工件码";
-                break;
-        }
-
-        //弹窗扫工件码
-        String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
-        if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
-            //获取用户
-            getUser();
-            //获取扫码内容36位
-            String barcode36 = getBarcode(scanBarcode);//处理36为码
-            //工位号
-            String gw = "";
-            switch(scan_type) {
-                case 1:
-                    product_sn.setText(scanBarcode);
-                    curSn = scanBarcode;
-                    break;
-            }
-            //刷新界面
-            mesClientFrame.repaint();
-
-            if(!tcp_connect_flag) {
-                JOptionPane.showMessageDialog(mesClientFrame,"设备未连接Mes服务器","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-                return;
-            }
-
-            // 查询工件质量
-            Boolean sendret = DataUtil.checkQuality(nettyClient,barcode36,user20);
-            if(!sendret){
-                JOptionPane.showMessageDialog(mesClientFrame,"消息发送失败,请重试","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-                return;
-            }
-        }else {
-            JOptionPane.showMessageDialog(mesClientFrame,"请扫工件码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-            return;
-        }
+    // 重置拉力、行程显示
+    public static void resetForceStrokeDisplay() {
+        if (param5 != null) param5.setText("-");
+        if (param6 != null) param6.setText("-");
+        if (param7 != null) param7.setText("-");
+        if (param8 != null) param8.setText("-");
     }
 
     public static void logoff() {
 //        welcomeWin.setVisible(true);
+        stopGetCurSn();
+        clearBackendCurSn();
+        clearBackendSnState();
         mesClientFrame.setVisible(false);
 
         nettyClient = null;
@@ -636,11 +744,15 @@ public class MesClient extends JFrame {
                 if (mes_shield_flag) {
                     shieldMesMenu.setText("MES屏蔽: 开");
                     shieldMesMenu.setForeground(Color.RED);
-                    JOptionPane.showMessageDialog(mesClientFrame, "MES屏蔽已开启", "提示", JOptionPane.WARNING_MESSAGE);
+                    setMenuStatus("MES屏蔽已开启:拉铆枪保持运行,客户端暂停读取", 0);
+                    JOptionPane.showMessageDialog(mesClientFrame,
+                            "MES屏蔽已开启\n拉铆枪不会被远程关机,可继续打钉\n客户端暂停读取PLC数据及MES后台工件码",
+                            "提示", JOptionPane.WARNING_MESSAGE);
                 } else {
                     shieldMesMenu.setText("MES屏蔽: 关");
                     shieldMesMenu.setForeground(Color.BLACK);
-                    JOptionPane.showMessageDialog(mesClientFrame, "MES屏蔽已关闭", "提示", JOptionPane.INFORMATION_MESSAGE);
+                    setMenuStatus("MES屏蔽已关闭", 0);
+                    JOptionPane.showMessageDialog(mesClientFrame, "MES屏蔽已关闭,恢复正常读取", "提示", JOptionPane.INFORMATION_MESSAGE);
                 }
             }
         });
@@ -731,22 +843,10 @@ public class MesClient extends JFrame {
         product_sn.setHorizontalAlignment(SwingConstants.CENTER);
         product_sn.setEditable(false);
         product_sn.setFont(new Font("微软雅黑", Font.PLAIN, 28));
-        product_sn.setBounds(81, 70, 602, 70);
+        product_sn.setBounds(81, 70, 810, 70);
         indexPanelA.add(product_sn);
         product_sn.setColumns(10);
 
-        f_scan_data_bt_1 = new JButton("扫码");
-        f_scan_data_bt_1.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                scan_type = 1;
-                scanBarcode();
-            }
-        });
-        f_scan_data_bt_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
-        f_scan_data_bt_1.setFont(new Font("微软雅黑", Font.PLAIN, 32));
-        f_scan_data_bt_1.setBounds(693, 70, 198, 70);
-        indexPanelA.add(f_scan_data_bt_1);
-
 //        String[] hjtitles = new String[]{"焊机1","焊机2","焊机3"};
 //        String[] hjvals = new String[]{"HJ001","HJ002","HJ003"};
 //        mesRadioHj = new MesRadio(hjtitles,hjvals);
@@ -872,6 +972,62 @@ public class MesClient extends JFrame {
         param4.setBounds(608, 285, 83, 34);
         indexPanelA.add(param4);
 
+        JLabel lblForceA = new JLabel("\u62c9\u529b");
+        lblForceA.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        lblForceA.setBounds(204, 329, 50, 34);
+        indexPanelA.add(lblForceA);
+
+        param5 = new JTextField();
+        param5.setHorizontalAlignment(SwingConstants.CENTER);
+        param5.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        param5.setText("-");
+        param5.setEditable(false);
+        param5.setColumns(10);
+        param5.setBounds(260, 329, 65, 34);
+        indexPanelA.add(param5);
+
+        JLabel lblStrokeA = new JLabel("\u884c\u7a0b");
+        lblStrokeA.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        lblStrokeA.setBounds(330, 329, 50, 34);
+        indexPanelA.add(lblStrokeA);
+
+        param6 = new JTextField();
+        param6.setHorizontalAlignment(SwingConstants.CENTER);
+        param6.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        param6.setText("-");
+        param6.setEditable(false);
+        param6.setColumns(10);
+        param6.setBounds(380, 329, 65, 34);
+        indexPanelA.add(param6);
+
+        JLabel lblForceB = new JLabel("\u62c9\u529b");
+        lblForceB.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        lblForceB.setBounds(525, 329, 50, 34);
+        indexPanelA.add(lblForceB);
+
+        param7 = new JTextField();
+        param7.setHorizontalAlignment(SwingConstants.CENTER);
+        param7.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        param7.setText("-");
+        param7.setEditable(false);
+        param7.setColumns(10);
+        param7.setBounds(581, 329, 65, 34);
+        indexPanelA.add(param7);
+
+        JLabel lblStrokeB = new JLabel("\u884c\u7a0b");
+        lblStrokeB.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        lblStrokeB.setBounds(651, 329, 50, 34);
+        indexPanelA.add(lblStrokeB);
+
+        param8 = new JTextField();
+        param8.setHorizontalAlignment(SwingConstants.CENTER);
+        param8.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        param8.setText("-");
+        param8.setEditable(false);
+        param8.setColumns(10);
+        param8.setBounds(701, 329, 65, 34);
+        indexPanelA.add(param8);
+
         tabbedPane.addTab("工作面板", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA, null);
         tabbedPane.setEnabledAt(0, true);
 
@@ -890,104 +1046,11 @@ public class MesClient extends JFrame {
 
 		tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
 
-        indexPanelD = new JPanel();
-        indexPanelD.setLayout(null);
-        
-        JLabel lblASet = new JLabel("A枪预设数量:");
-        lblASet.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        lblASet.setBounds(100, 50, 150, 40);
-        indexPanelD.add(lblASet);
-        
-        JTextField txtASet = new JTextField(String.valueOf(aSetNum));
-        txtASet.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        txtASet.setBounds(260, 50, 200, 40);
-        indexPanelD.add(txtASet);
-        
-        JLabel lblBSet = new JLabel("B枪预设数量:");
-        lblBSet.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        lblBSet.setBounds(100, 110, 150, 40);
-        indexPanelD.add(lblBSet);
-        
-        JTextField txtBSet = new JTextField(String.valueOf(bSetNum));
-        txtBSet.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        txtBSet.setBounds(260, 110, 200, 40);
-        indexPanelD.add(txtBSet);
-
-        JLabel lblIpA = new JLabel("A枪IP地址:");
-        lblIpA.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        lblIpA.setBounds(100, 170, 150, 40);
-        indexPanelD.add(lblIpA);
-
-        JTextField txtIpA = new JTextField(curIpA);
-        txtIpA.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        txtIpA.setBounds(260, 170, 200, 40);
-        indexPanelD.add(txtIpA);
-
-        JLabel lblIpB = new JLabel("B枪IP地址:");
-        lblIpB.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        lblIpB.setBounds(100, 230, 150, 40);
-        indexPanelD.add(lblIpB);
-
-        JTextField txtIpB = new JTextField(curIpB);
-        txtIpB.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        txtIpB.setBounds(260, 230, 200, 40);
-        indexPanelD.add(txtIpB);
-        
-        JButton btnSave = new JButton("保存设置");
-        btnSave.setFont(new Font("微软雅黑", Font.PLAIN, 20));
-        btnSave.setBounds(180, 310, 150, 50);
-        btnSave.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                try {
-                    short newASet = Short.parseShort(txtASet.getText());
-                    short newBSet = Short.parseShort(txtBSet.getText());
-                    String newIpA = txtIpA.getText().trim();
-                    String newIpB = txtIpB.getText().trim();
-
-                    if (newIpA.isEmpty() || newIpB.isEmpty()) {
-                        JOptionPane.showMessageDialog(mesClientFrame, "IP地址不能为空", "错误", JOptionPane.ERROR_MESSAGE);
-                        return;
-                    }
-                    
-                    // 更新数据库
-                    JdbcUtils.updateConfig(newASet, newBSet, newIpA, newIpB);
-                    
-                    // 更新内存变量
-                    aSetNum = newASet;
-                    bSetNum = newBSet;
-                    
-                    // 同步更新工作面板显示的预设数量
-                    param1.setText(String.valueOf(aSetNum));
-                    param3.setText(String.valueOf(bSetNum));
-                    
-                    // 检查 IP 是否发生变化,仅在变化时重连
-                    boolean ipAChanged = !newIpA.equals(curIpA);
-                    boolean ipBChanged = !newIpB.equals(curIpB);
-
-                    if (ipAChanged) {
-                        if (plcA != null) plcA.close();
-                        curIpA = newIpA;
-                        plcA = new ModbusTcp(1, curIpA);
-                        System.out.println("A枪IP已变更,重新连接: " + curIpA);
-                    }
-
-                    if (ipBChanged) {
-                        if (plcB != null) plcB.close();
-                        curIpB = newIpB;
-                        plcB = new ModbusTcp(1, curIpB);
-                        System.out.println("B枪IP已变更,重新连接: " + curIpB);
-                    }
-                    
-                    JOptionPane.showMessageDialog(mesClientFrame, "配置已保存", "提示", JOptionPane.INFORMATION_MESSAGE);
-                } catch (NumberFormatException ex) {
-                    JOptionPane.showMessageDialog(mesClientFrame, "请输入有效的数字", "错误", JOptionPane.ERROR_MESSAGE);
-                }
-            }
-        });
-        indexPanelD.add(btnSave);
-
-        tabbedPane.addTab("设备管理", new ImageIcon(MesClient.class.getResource("/bg/menu_setting.png")), indexPanelD, null);
+        indexPanelD = new DeviceManagePanel();
+        JScrollPane scrollPanelD = new JScrollPane(indexPanelD);
+        scrollPanelD.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        scrollPanelD.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+        tabbedPane.addTab("设备管理", new ImageIcon(MesClient.class.getResource("/bg/menu_setting.png")), scrollPanelD, null);
 
 		tabbedPane.addChangeListener(new ChangeListener() {
             @Override
@@ -997,7 +1060,7 @@ public class MesClient extends JFrame {
 
                 if (selectedIndex == 3) { // 设备管理
                     String input = JOptionPane.showInputDialog(mesClientFrame, "请输入管理员密码以进入设备管理:", "权限验证", JOptionPane.QUESTION_MESSAGE);
-                    if (input != null && input.equalsIgnoreCase("mes")) {
+                    if (input != null && input.equals("503833")) {
                         lastSelectedIndex = selectedIndex;
                     } else {
                         if (input != null) {

+ 12 - 7
src/com/mes/ui/MesRevice.java

@@ -12,6 +12,7 @@ public class MesRevice {
     public static void checkQualityRevice(String processMsgRet,String mes_msg){
         try{
             if(processMsgRet.equalsIgnoreCase("UD")) {
+                MesClient.backendPollingSn = "";
                 MesClient.status_menu.setForeground(Color.GREEN);
                 MesClient.check_quality_result = true;//质量合格,可以绑定加工
                 MesClient.setMenuStatus("该工件可以加工",0);
@@ -22,6 +23,14 @@ public class MesRevice {
                 }
             }else {
                 MesClient.check_quality_result = false;
+                MesClient.backendPollingSn = "";
+                if(!MesClient.curSn.isEmpty()){
+                    MesClient.lastRejectedBackendSn = MesClient.curSn.trim();
+                }
+                // 闭环:质量不合格时清除后台工位码,避免重复拉取同一件
+                MesClient.clearBackendCurSn();
+                MesClient.product_sn.setText("");
+                MesClient.curSn = "";
                 ErrorMsg.setErrorMsg(mes_msg);
 
 //                MesClient.deviceControl = ModbusUtil.getControlModel(MesClient.plcA);
@@ -42,7 +51,6 @@ public class MesRevice {
         try{
             if(processMsgRet.equalsIgnoreCase("OK")) {
                 MesClient.work_status = 1;
-                MesClient.f_scan_data_bt_1.setEnabled(false);
                 MesClient.tjStatus = 0;
 
 //                MesClient.deviceControl = ModbusUtil.getControlModel(MesClient.plcA);
@@ -56,8 +64,8 @@ public class MesRevice {
                 ModbusUtil.setPowerOn(MesClient.plcA); // 远程开机
                 ModbusUtil.setPowerOn(MesClient.plcB); // 远程开机
 
-                ModbusUtil.setTask(MesClient.plcA,MesClient.aSetNum);
-                ModbusUtil.setTask(MesClient.plcB,MesClient.bSetNum);
+                ModbusUtil.setTask(MesClient.plcA, MesClient.aSetNum, "A");
+                ModbusUtil.setTask(MesClient.plcB, MesClient.bSetNum, "B");
             }
         }catch (Exception e){
             e.printStackTrace();
@@ -96,10 +104,7 @@ public class MesRevice {
             if(processMsgRet.equalsIgnoreCase("OK")) {
 
                 MesClient.resetScanA();
-//                MesClient.status_menu.setText("结果提交成功,请扫下一件");
-                MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
-                MesClient.scan_type = 1;
-                MesClient.scanBarcode();
+                MesClient.setMenuStatus("结果提交成功,等待下一件",0);
 
             }else{
                 MesClient.setMenuStatus("结果提交失败,请重试",-1);

+ 59 - 20
src/com/mes/ui/ModbusUtil.java

@@ -3,10 +3,25 @@ package com.mes.ui;
 import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
 import com.mes.util.JdbcUtils;
 
+import javax.swing.*;
 import java.nio.charset.Charset;
+import java.util.List;
 
 public class ModbusUtil {
 
+    // 刷新界面拉力、行程显示
+    private static void updateForceStrokeDisplay(ModbusTcp plc, JTextField forceField, JTextField strokeField) {
+        if (forceField == null || strokeField == null) {
+            return;
+        }
+        try {
+            forceField.setText(plc.readInt16(1064) + "");
+            strokeField.setText((float) plc.readInt16(1065) / 1000 + "");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
     public static void getDataA(ModbusTcp plc){
 
         // 说明预设数量有变化不能修改
@@ -17,6 +32,7 @@ public class ModbusUtil {
         // 预设数量=41129  完成数=41137
 
         Short cur = plc.readInt16(1136);
+        updateForceStrokeDisplay(plc, MesClient.param5, MesClient.param6);
 //        System.out.println("F-out:"+plc.readInt16(1064));
 //        System.out.println("S-out:"+plc.readInt16(1065));
 //        System.out.println("F-min:"+plc.readInt16(1068));
@@ -45,12 +61,11 @@ public class ModbusUtil {
 
             System.out.println("cur:"+cur);
 
-            if(MesClient.sortA == 4){
-                    plc.writeInt16(1070,(short) 2000);
-                    plc.writeInt16(1071,(short) 5000);
+            int nextRivet = cur + 1;
+            if (nextRivet <= MesClient.aMax) {
+                applyParamsForRivet(plc, MesClient.rivetParamRangesA, nextRivet);
             }
 
-
             if(!MesClient.product_sn.getText().isEmpty()){
                 JdbcUtils.insertProdData(MesClient.mes_gw, MesClient.mes_line_sn, MesClient.product_sn.getText(),"A",fout,sout,fmin,smin,fmax,smax,"1",cur+"", MesClient.user_menu.getText());
             }
@@ -66,6 +81,7 @@ public class ModbusUtil {
         // 预设数量=41129  完成数=41137
 
         Short cur = plc.readInt16(1136);
+        updateForceStrokeDisplay(plc, MesClient.param7, MesClient.param8);
 //        System.out.println("F-out:"+plc.readInt16(1064));
 //        System.out.println("S-out:"+plc.readInt16(1065));
 //        System.out.println("F-min:"+plc.readInt16(1068));
@@ -93,14 +109,11 @@ public class ModbusUtil {
             String fmax = plc.readInt16(1069)+"";
             String smax = (float)plc.readInt16(1071)/1000+"";
 
-            if(MesClient.sortB == 18){
-//                if(MesClient.bMax == 36){
-//                    plc.writeInt16(1070,(short) 4000);
-//                    plc.writeInt16(1071,(short) 5500);
-//                }
+            int nextRivet = cur + 1;
+            if (nextRivet <= MesClient.bMax) {
+                applyParamsForRivet(plc, MesClient.rivetParamRangesB, nextRivet);
             }
 
-
             System.out.println("cur:"+cur);
             if(!MesClient.product_sn.getText().isEmpty()){
                JdbcUtils.insertProdData(MesClient.mes_gw, MesClient.mes_line_sn, MesClient.product_sn.getText(),"B",fout,sout,fmin,smin,fmax,smax,"1",cur+"", MesClient.user_menu.getText());
@@ -215,8 +228,40 @@ public class ModbusUtil {
         return ret;
     }
 
+    // 查找指定颗数对应的参数区间
+    public static RivetParamRange findRivetParamRange(List<RivetParamRange> ranges, int rivetNo) {
+        if (ranges == null) {
+            return null;
+        }
+        for (RivetParamRange range : ranges) {
+            if (range.contains(rivetNo)) {
+                return range;
+            }
+        }
+        return null;
+    }
+
+    // 按颗数下发PLC拉力/行程参数
+    public static void applyParamsForRivet(ModbusTcp plc, List<RivetParamRange> ranges, int rivetNo) {
+        RivetParamRange range = findRivetParamRange(ranges, rivetNo);
+        if (range == null) {
+            System.out.println("未找到第" + rivetNo + "颗对应的参数配置");
+            return;
+        }
+        try {
+            plc.writeInt16(1068, (short) range.getFMin());
+            plc.writeInt16(1069, (short) range.getFMax());
+            plc.writeInt16(1070, (short) range.getSMin());
+            plc.writeInt16(1071, (short) range.getSMax());
+            System.out.println("下发铆接参数:第" + rivetNo + "颗, F=" + range.getFMin() + "-" + range.getFMax()
+                    + ", S=" + range.getSMin() + "-" + range.getSMax());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
     // 重置任务
-    public static void setTask(ModbusTcp plc,Short setNum){
+    public static void setTask(ModbusTcp plc, Short setNum, String gunType) {
         try{
             // 设置模式 1=标记铆接模式
             plc.writeInt16(1092,(short) 1);
@@ -225,15 +270,9 @@ public class ModbusUtil {
             plc.writeInt16(1136,(short) 0);
             plc.writeInt16(1138,(short) 0);
 
-            if(setNum == 22){
-                plc.writeInt16(1070,(short) 2500);
-                plc.writeInt16(1071,(short) 4500);
-            }
-
-            if (setNum == 40){
-                plc.writeInt16(1070,(short) 2000);
-                plc.writeInt16(1071,(short) 4000);
-            }
+            List<RivetParamRange> ranges = "A".equalsIgnoreCase(gunType)
+                    ? MesClient.rivetParamRangesA : MesClient.rivetParamRangesB;
+            applyParamsForRivet(plc, ranges, 1);
 
         }catch (Exception e){
             e.printStackTrace();

+ 87 - 0
src/com/mes/ui/RivetParamRange.java

@@ -0,0 +1,87 @@
+package com.mes.ui;
+
+/**
+ * 拉铆枪按颗数区间的PLC参数配置
+ */
+public class RivetParamRange {
+    private String gunType;
+    private int startRivet;
+    private int endRivet;
+    private int fMin;
+    private int fMax;
+    private int sMin;
+    private int sMax;
+
+    public RivetParamRange() {
+    }
+
+    public RivetParamRange(String gunType, int startRivet, int endRivet, int fMin, int fMax, int sMin, int sMax) {
+        this.gunType = gunType;
+        this.startRivet = startRivet;
+        this.endRivet = endRivet;
+        this.fMin = fMin;
+        this.fMax = fMax;
+        this.sMin = sMin;
+        this.sMax = sMax;
+    }
+
+    public String getGunType() {
+        return gunType;
+    }
+
+    public void setGunType(String gunType) {
+        this.gunType = gunType;
+    }
+
+    public int getStartRivet() {
+        return startRivet;
+    }
+
+    public void setStartRivet(int startRivet) {
+        this.startRivet = startRivet;
+    }
+
+    public int getEndRivet() {
+        return endRivet;
+    }
+
+    public void setEndRivet(int endRivet) {
+        this.endRivet = endRivet;
+    }
+
+    public int getFMin() {
+        return fMin;
+    }
+
+    public void setFMin(int fMin) {
+        this.fMin = fMin;
+    }
+
+    public int getFMax() {
+        return fMax;
+    }
+
+    public void setFMax(int fMax) {
+        this.fMax = fMax;
+    }
+
+    public int getSMin() {
+        return sMin;
+    }
+
+    public void setSMin(int sMin) {
+        this.sMin = sMin;
+    }
+
+    public int getSMax() {
+        return sMax;
+    }
+
+    public void setSMax(int sMax) {
+        this.sMax = sMax;
+    }
+
+    public boolean contains(int rivetNo) {
+        return rivetNo >= startRivet && rivetNo <= endRivet;
+    }
+}

+ 85 - 0
src/com/mes/util/JdbcUtils.java

@@ -1,6 +1,7 @@
 package com.mes.util;
 
 import com.mes.ui.ProdReq;
+import com.mes.ui.RivetParamRange;
 
 import java.sql.*;
 import java.util.ArrayList;
@@ -19,6 +20,7 @@ public class JdbcUtils {
             create_bw_record();//初始化结构表
             create_bw_prod();
             create_config_table();
+            create_rivet_param_table();
         } catch (Exception e) {
             // TODO Auto-generated catch block
         	close();//关闭数据库连接
@@ -115,6 +117,89 @@ public class JdbcUtils {
 		return config;
 	}
 
+	// 铆接参数区间配置表
+	public static void create_rivet_param_table() throws SQLException {
+		Statement statement = conn.createStatement();
+		String sql = "CREATE TABLE if not exists bw_rivet_param("
+				+ "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+				+ "gun_type VARCHAR(1), "
+				+ "start_rivet INTEGER, "
+				+ "end_rivet INTEGER, "
+				+ "f_min INTEGER, "
+				+ "f_max INTEGER, "
+				+ "s_min INTEGER, "
+				+ "s_max INTEGER, "
+				+ "sort_order INTEGER)";
+		statement.executeUpdate(sql);
+
+		ResultSet rs = statement.executeQuery("SELECT count(*) FROM bw_rivet_param");
+		if (rs.next() && rs.getInt(1) == 0) {
+			statement.executeUpdate("INSERT INTO bw_rivet_param (gun_type,start_rivet,end_rivet,f_min,f_max,s_min,s_max,sort_order) VALUES "
+					+ "('A',1,4,0,0,2000,4000,1),"
+					+ "('A',5,40,0,0,2000,5000,2),"
+					+ "('B',1,22,0,0,2500,4500,1)");
+		}
+		rs.close();
+		System.out.println("表rivet_param创建并初始化成功!");
+		statement.close();
+	}
+
+	public static java.util.List<RivetParamRange> getRivetParams(String gunType) {
+		java.util.List<RivetParamRange> list = new java.util.ArrayList<>();
+		String sql = "SELECT gun_type,start_rivet,end_rivet,f_min,f_max,s_min,s_max FROM bw_rivet_param "
+				+ "WHERE gun_type = ? ORDER BY sort_order ASC, start_rivet ASC";
+		Connection conn = JdbcUtils.getConn();
+		try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+			pstmt.setString(1, gunType);
+			ResultSet rs = pstmt.executeQuery();
+			while (rs.next()) {
+				RivetParamRange range = new RivetParamRange();
+				range.setGunType(rs.getString("gun_type"));
+				range.setStartRivet(rs.getInt("start_rivet"));
+				range.setEndRivet(rs.getInt("end_rivet"));
+				range.setFMin(rs.getInt("f_min"));
+				range.setFMax(rs.getInt("f_max"));
+				range.setSMin(rs.getInt("s_min"));
+				range.setSMax(rs.getInt("s_max"));
+				list.add(range);
+			}
+			rs.close();
+		} catch (SQLException e) {
+			e.printStackTrace();
+		}
+		return list;
+	}
+
+	public static void saveRivetParams(String gunType, java.util.List<RivetParamRange> ranges) {
+		Connection conn = JdbcUtils.getConn();
+		try {
+			PreparedStatement deleteStmt = conn.prepareStatement("DELETE FROM bw_rivet_param WHERE gun_type = ?");
+			deleteStmt.setString(1, gunType);
+			deleteStmt.executeUpdate();
+			deleteStmt.close();
+
+			String insertSql = "INSERT INTO bw_rivet_param (gun_type,start_rivet,end_rivet,f_min,f_max,s_min,s_max,sort_order) "
+					+ "VALUES (?,?,?,?,?,?,?,?)";
+			PreparedStatement insertStmt = conn.prepareStatement(insertSql);
+			for (int i = 0; i < ranges.size(); i++) {
+				RivetParamRange range = ranges.get(i);
+				insertStmt.setString(1, gunType);
+				insertStmt.setInt(2, range.getStartRivet());
+				insertStmt.setInt(3, range.getEndRivet());
+				insertStmt.setInt(4, range.getFMin());
+				insertStmt.setInt(5, range.getFMax());
+				insertStmt.setInt(6, range.getSMin());
+				insertStmt.setInt(7, range.getSMax());
+				insertStmt.setInt(8, i + 1);
+				insertStmt.executeUpdate();
+			}
+			insertStmt.close();
+			System.out.println("保存铆接参数成功:gunType=" + gunType + ", rows=" + ranges.size());
+		} catch (SQLException e) {
+			e.printStackTrace();
+		}
+	}
+
 	public static void updateConfig(short aSetNum, short bSetNum, String plcIpA, String plcIpB) {
 		String sql = "UPDATE bw_config SET a_set_num = ?, b_set_num = ?, plc_ip_a = ?, plc_ip_b = ? WHERE id = 1";
 		Connection conn = JdbcUtils.getConn();

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

@@ -1,6 +1,6 @@
 mes.gw=OP210
-#mes.server_ip=127.0.0.1
-mes.server_ip=192.168.9.180
+mes.server_ip=127.0.0.1
+#mes.server_ip=192.168.9.180
 mes.tcp_port=3000
 mes.heart_beat_cycle=60
 mes.line_sn=XT