瀏覽代碼

生产记录传递

day01-init 3 天之前
父節點
當前提交
767efbdc62
共有 3 個文件被更改,包括 407 次插入17 次删除
  1. 9 4
      src/com/mes/ui/LoginFrame.java
  2. 314 12
      src/com/mes/ui/MesClient.java
  3. 84 1
      src/com/mes/util/QMParamsDAO.java

+ 9 - 4
src/com/mes/ui/LoginFrame.java

@@ -177,10 +177,15 @@ public class LoginFrame extends JFrame {
                     MesClient.panel5.add(webView5);
                     System.out.println(url5);
 
-                    String url2 = "http://" + Config.server_ip + ":8980/js/a/mes/mesProcessCheckRecord/ulist?ucode=" + user_id + "&oprno=OP400" + "&lineSn=" + Config.line_sn;
-                    MesWebView jfxPanel2 = new MesWebView(url2);
-                    jfxPanel2.setSize(990, 550);
-                    MesClient.indexPanelC.add(jfxPanel2);
+                    String url2a = "http://" + Config.server_ip + ":8980/js/a/mes/mesProcessCheckRecord/ulist?ucode=" + user_id + "&oprno=" + Config.gw_1 + "&lineSn=" + Config.line_sn;
+                    MesWebView djAView = new MesWebView(url2a);
+                    djAView.setSize(990, 550);
+                    MesClient.indexPanelDjA.add(djAView);
+
+                    String url2b = "http://" + Config.server_ip + ":8980/js/a/mes/mesProcessCheckRecord/ulist?ucode=" + user_id + "&oprno=" + Config.gw_2 + "&lineSn=" + Config.line_sn;
+                    MesWebView djBView = new MesWebView(url2b);
+                    djBView.setSize(990, 550);
+                    MesClient.indexPanelDjB.add(djBView);
 
                     String url4 = "http://" + Config.server_ip + ":8980/js/a/mes/mesProcessUserRecord/submitView?oprno=OP400";
                     MesWebView webView4 = new MesWebView(url4);

+ 314 - 12
src/com/mes/ui/MesClient.java

@@ -36,13 +36,14 @@ public class MesClient extends JFrame {
     public static String user20 = "";
     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;
 
-
+    // 记录扫码工件码的时间,用于限制提交必须在扫码后满30秒
+    public static long scan_time1 = 0L;
+    public static long scan_time2 = 0L;
     public static JButton finish_ok_bt_1;
     public static JButton finish_ng_bt_1;
     public static JTextField product_sn_1;
@@ -50,7 +51,6 @@ public class MesClient extends JFrame {
     public static JButton status_menu_1;
     public static JTextField pressureText_1;                                // 压力值显示文本框
     public static JTextField leakText_1;                                    // 压力值显示文本框
-
     public static JButton finish_ok_bt_2;
     public static JButton finish_ng_bt_2;
     public static JTextField product_sn_2;
@@ -58,14 +58,13 @@ public class MesClient extends JFrame {
     public static JButton status_menu_2;
     public static JTextField pressureText_2;                // 压力值显示文本框
     public static JTextField leakText_2;                   // 压力值显示文本框
-
-
     public static JPanel contentPane;
     public static MesClient mesClientFrame;
     public static JTabbedPane tabbedPane;
     public static JScrollPane indexScrollPaneA;
     public static JScrollPane searchScrollPane;
-    public static JScrollPane searchScrollPaneDj;
+    public static JScrollPane searchScrollPaneDjA;
+    public static JScrollPane searchScrollPaneDjB;
 
     public static JPanel panel4;
     public static JScrollPane scrollPane4;
@@ -78,13 +77,32 @@ public class MesClient extends JFrame {
     public static JFrame welcomeWin;
     public static JPanel indexPanelB;
     public static MesWebView jfxPanel = null;
-    public static JPanel indexPanelC;
-    public static MesWebView jfxPanel2 = null;
+    public static JPanel indexPanelDjA;
+    public static JPanel indexPanelDjB;
+    public static MesWebView jfxPanelDjA = null;
+    public static MesWebView jfxPanelDjB = null;
     public static MesRadio mesRadioHj;
     public static JTable table;
     public static Object[] columnNames = {"物料名称", "绑定批次", "剩余次数", "操作"};
     public static Object[][] rowData = null;
 
+    // 记录查询(仿照 OP370-AUTO:工件码/测试日期/压力/泄漏值/结果)
+    public static JTable recordTable_1;
+    public static Object[] recordColumnNames_1 = {"工件码", "测试日期", "压力", "泄漏值", "结果"};
+    public static Object[][] recordRowData_1 = new Object[12][5];
+    public static JLabel recordPageLabel_1;
+    public static int recordPageNo_1 = 1;
+    public static int recordTotalPages_1 = 0;
+    public static JTextField recordSearchField_1;
+
+    public static JTable recordTable_2;
+    public static Object[] recordColumnNames_2 = {"工件码", "测试日期", "压力", "泄漏值", "结果"};
+    public static Object[][] recordRowData_2 = new Object[12][5];
+    public static JLabel recordPageLabel_2;
+    public static int recordPageNo_2 = 1;
+    public static int recordTotalPages_2 = 0;
+    public static JTextField recordSearchField_2;
+
     String currentSerialPort1 = Config.portName1;
     String currentSerialPort2 = Config.portName2;
 
@@ -197,6 +215,7 @@ public class MesClient extends JFrame {
         MesClient.finish_ng_bt_1.setEnabled(false);
         MesClient.f_scan_data_bt_1.setEnabled(true);
         product_sn_1.setText("");
+        scan_time1 = 0L;
 //        leakText_1.setText("");
 //        pressureText_1.setText("");
 //        MesClient.setMenuState_1("请扫工件码", 0);
@@ -210,6 +229,7 @@ public class MesClient extends JFrame {
         MesClient.finish_ng_bt_2.setEnabled(false);
         MesClient.f_scan_data_bt_2.setEnabled(true);
         product_sn_2.setText("");
+        scan_time2 = 0L;
 //        leakText_2.setText("");
 //        pressureText_2.setText("");
 //        MesClient.setMenuState_2("请扫工件码", 0);
@@ -298,6 +318,7 @@ public class MesClient extends JFrame {
         String scanBarcode = MesClient.scanQrcode1();
         if (scanBarcode != null && !scanBarcode.equalsIgnoreCase("")) {
             product_sn_1.setText(scanBarcode);
+            scan_time1 = System.currentTimeMillis();
             //刷新界面
             mesClientFrame.repaint();
 
@@ -331,6 +352,7 @@ public class MesClient extends JFrame {
         String scanBarcode = MesClient.scanQrcode2();
         if (scanBarcode != null && !scanBarcode.equalsIgnoreCase("")) {
             product_sn_2.setText(scanBarcode);
+            scan_time2 = System.currentTimeMillis();
             //刷新界面
             mesClientFrame.repaint();
 
@@ -798,10 +820,15 @@ public class MesClient extends JFrame {
         tabbedPane.addTab("工作面板", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA, null);
         tabbedPane.setEnabledAt(0, true);
 
-        indexPanelC = new JPanel();
-        searchScrollPaneDj = new JScrollPane(indexPanelC);
-        indexPanelC.setLayout(null);
-        tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
+        indexPanelDjA = new JPanel();
+        searchScrollPaneDjA = new JScrollPane(indexPanelDjA);
+        indexPanelDjA.setLayout(null);
+        tabbedPane.addTab(Config.gw_1 + "开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDjA, null);
+
+        indexPanelDjB = new JPanel();
+        searchScrollPaneDjB = new JScrollPane(indexPanelDjB);
+        indexPanelDjB.setLayout(null);
+        tabbedPane.addTab(Config.gw_2 + "开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDjB, null);
 
         indexPanelB = new JPanel();
         searchScrollPane = new JScrollPane(indexPanelB);
@@ -831,8 +858,283 @@ public class MesClient extends JFrame {
                 if (selectedIndex == 1) {
 
                 }
+
+                // 切换 tab 时刷新记录查询(保持与 OP370-AUTO 一致:打开页面自动刷新)
+                // gw_1记录 tab index: 3, gw_2记录 tab index: 4(前面有 工作面板/开班点检A/开班点检B)
+                if (selectedIndex == 3) {
+                    loadRecordData_1();
+                } else if (selectedIndex == 4) {
+                    loadRecordData_2();
+                }
+            }
+        });
+
+        // 初始化两条线的“记录查询”界面
+        initRecordPanel_1(indexPanelB);
+        initRecordPanel_2(panel5);
+    }
+
+    private static void initRecordPanel_1(JPanel container) {
+        // 顶部搜索栏
+        JPanel top = new JPanel();
+        top.setBounds(0, 0, 990, 50);
+        top.setLayout(null);
+        container.add(top);
+
+        recordSearchField_1 = new JTextField();
+        recordSearchField_1.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+        recordSearchField_1.setForeground(Color.BLACK);
+        recordSearchField_1.setBounds(10, 5, 371, 40);
+        top.add(recordSearchField_1);
+
+        JButton searchBtn = new JButton("搜索");
+        searchBtn.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        searchBtn.setBounds(385, 5, 90, 40);
+        top.add(searchBtn);
+        searchBtn.addActionListener(e -> {
+            recordPageNo_1 = 1;
+            loadRecordData_1();
+        });
+
+        JButton resetBtn = new JButton("重置");
+        resetBtn.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        resetBtn.setBounds(475, 5, 90, 40);
+        top.add(resetBtn);
+        resetBtn.addActionListener(e -> {
+            recordSearchField_1.setText("");
+            recordPageNo_1 = 1;
+            loadRecordData_1();
+        });
+
+        JButton btnPrevious = new JButton("上一页");
+        btnPrevious.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        btnPrevious.setBounds(680, 5, 100, 40);
+        top.add(btnPrevious);
+        btnPrevious.addActionListener(e -> {
+            if (recordPageNo_1 > 1) {
+                recordPageNo_1--;
+                loadRecordData_1();
+            }
+        });
+
+        recordPageLabel_1 = new JLabel("0/0");
+        recordPageLabel_1.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        recordPageLabel_1.setHorizontalAlignment(SwingConstants.CENTER);
+        recordPageLabel_1.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
+        recordPageLabel_1.setBounds(780, 5, 100, 40);
+        top.add(recordPageLabel_1);
+
+        JButton btnNext = new JButton("下一页");
+        btnNext.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        btnNext.setBounds(880, 5, 100, 40);
+        top.add(btnNext);
+        btnNext.addActionListener(e -> {
+            if (recordPageNo_1 < recordTotalPages_1) {
+                recordPageNo_1++;
+                loadRecordData_1();
+            }
+        });
+
+        // 表格区域
+        JPanel tablePanel = new JPanel();
+        tablePanel.setBounds(0, 49, 990, 518);
+        tablePanel.setLayout(new GridLayout(0, 1, 0, 0));
+        container.add(tablePanel);
+
+        recordTable_1 = new JTable(recordRowData_1, recordColumnNames_1) {
+            public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+        };
+        recordTable_1.setRowHeight(40);
+        recordTable_1.setEnabled(true);
+        recordTable_1.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+
+        javax.swing.table.DefaultTableCellRenderer centerRenderer = new javax.swing.table.DefaultTableCellRenderer();
+        centerRenderer.setHorizontalAlignment(JLabel.CENTER);
+        recordTable_1.setDefaultRenderer(Object.class, centerRenderer);
+
+        JScrollPane scrollPane = new JScrollPane(recordTable_1);
+        tablePanel.add(scrollPane);
+
+        // 初次加载
+        loadRecordData_1();
+    }
+
+    private static void initRecordPanel_2(JPanel container) {
+        JPanel top = new JPanel();
+        top.setBounds(0, 0, 990, 50);
+        top.setLayout(null);
+        container.add(top);
+
+        recordSearchField_2 = new JTextField();
+        recordSearchField_2.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+        recordSearchField_2.setForeground(Color.BLACK);
+        recordSearchField_2.setBounds(10, 5, 371, 40);
+        top.add(recordSearchField_2);
+
+        JButton searchBtn = new JButton("搜索");
+        searchBtn.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        searchBtn.setBounds(385, 5, 90, 40);
+        top.add(searchBtn);
+        searchBtn.addActionListener(e -> {
+            recordPageNo_2 = 1;
+            loadRecordData_2();
+        });
+
+        JButton resetBtn = new JButton("重置");
+        resetBtn.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        resetBtn.setBounds(475, 5, 90, 40);
+        top.add(resetBtn);
+        resetBtn.addActionListener(e -> {
+            recordSearchField_2.setText("");
+            recordPageNo_2 = 1;
+            loadRecordData_2();
+        });
+
+        JButton btnPrevious = new JButton("上一页");
+        btnPrevious.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        btnPrevious.setBounds(680, 5, 100, 40);
+        top.add(btnPrevious);
+        btnPrevious.addActionListener(e -> {
+            if (recordPageNo_2 > 1) {
+                recordPageNo_2--;
+                loadRecordData_2();
+            }
+        });
+
+        recordPageLabel_2 = new JLabel("0/0");
+        recordPageLabel_2.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        recordPageLabel_2.setHorizontalAlignment(SwingConstants.CENTER);
+        recordPageLabel_2.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
+        recordPageLabel_2.setBounds(780, 5, 100, 40);
+        top.add(recordPageLabel_2);
+
+        JButton btnNext = new JButton("下一页");
+        btnNext.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        btnNext.setBounds(880, 5, 100, 40);
+        top.add(btnNext);
+        btnNext.addActionListener(e -> {
+            if (recordPageNo_2 < recordTotalPages_2) {
+                recordPageNo_2++;
+                loadRecordData_2();
             }
         });
+
+        JPanel tablePanel = new JPanel();
+        tablePanel.setBounds(0, 49, 990, 518);
+        tablePanel.setLayout(new GridLayout(0, 1, 0, 0));
+        container.add(tablePanel);
+
+        recordTable_2 = new JTable(recordRowData_2, recordColumnNames_2) {
+            public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+        };
+        recordTable_2.setRowHeight(40);
+        recordTable_2.setEnabled(true);
+        recordTable_2.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+
+        javax.swing.table.DefaultTableCellRenderer centerRenderer = new javax.swing.table.DefaultTableCellRenderer();
+        centerRenderer.setHorizontalAlignment(JLabel.CENTER);
+        recordTable_2.setDefaultRenderer(Object.class, centerRenderer);
+
+        JScrollPane scrollPane = new JScrollPane(recordTable_2);
+        tablePanel.add(scrollPane);
+
+        loadRecordData_2();
+    }
+
+    private static void clearRecordRowData(Object[][] rowData) {
+        for (int i = 0; i < rowData.length; i++) {
+            for (int j = 0; j < rowData[i].length; j++) {
+                rowData[i][j] = null;
+            }
+        }
+    }
+
+    private static void loadRecordData_1() {
+        clearRecordRowData(recordRowData_1);
+
+        int pageSize = 12;
+        int offset = (recordPageNo_1 - 1) * pageSize;
+        String snLike = recordSearchField_1 == null ? "" : recordSearchField_1.getText();
+
+        int totalItems = QMParamsDAO.countByOprnoAndSnLike(Config.gw_1, snLike);
+        if (totalItems <= 0) {
+            recordTotalPages_1 = 0;
+            if (recordPageLabel_1 != null) recordPageLabel_1.setText("0/0");
+            if (recordTable_1 != null) recordTable_1.repaint();
+            return;
+        }
+
+        recordTotalPages_1 = (int) Math.ceil((double) totalItems / (double) pageSize);
+        if (recordPageNo_1 > recordTotalPages_1) recordPageNo_1 = recordTotalPages_1;
+        if (recordPageLabel_1 != null) recordPageLabel_1.setText(recordPageNo_1 + "/" + recordTotalPages_1);
+
+        java.util.List<java.util.Map<String, Object>> rows = QMParamsDAO.queryByOprnoAndSnLike(Config.gw_1, snLike, pageSize, offset);
+        int rowIndex = 0;
+        for (java.util.Map<String, Object> r : rows) {
+            if (rowIndex >= recordRowData_1.length) break;
+            String sn = r.get("sn") == null ? "" : String.valueOf(r.get("sn"));
+            String recordTime = r.get("record_time") == null ? "" : String.valueOf(r.get("record_time"));
+            String pressure = (r.get("pressure_value") == null ? "" : String.valueOf(r.get("pressure_value")))
+                    + (r.get("pressure_unit") == null ? "" : String.valueOf(r.get("pressure_unit")));
+            String leak = (r.get("leak_value") == null ? "" : String.valueOf(r.get("leak_value")))
+                    + (r.get("leak_unit") == null ? "" : String.valueOf(r.get("leak_unit")));
+            String result = r.get("test_result") == null ? "" : String.valueOf(r.get("test_result"));
+
+            recordRowData_1[rowIndex][0] = sn;
+            recordRowData_1[rowIndex][1] = recordTime;
+            recordRowData_1[rowIndex][2] = pressure;
+            recordRowData_1[rowIndex][3] = leak;
+            recordRowData_1[rowIndex][4] = result;
+            rowIndex++;
+        }
+
+        if (recordTable_1 != null) recordTable_1.repaint();
+    }
+
+    private static void loadRecordData_2() {
+        clearRecordRowData(recordRowData_2);
+
+        int pageSize = 12;
+        int offset = (recordPageNo_2 - 1) * pageSize;
+        String snLike = recordSearchField_2 == null ? "" : recordSearchField_2.getText();
+
+        int totalItems = QMParamsDAO.countByOprnoAndSnLike(Config.gw_2, snLike);
+        if (totalItems <= 0) {
+            recordTotalPages_2 = 0;
+            if (recordPageLabel_2 != null) recordPageLabel_2.setText("0/0");
+            if (recordTable_2 != null) recordTable_2.repaint();
+            return;
+        }
+
+        recordTotalPages_2 = (int) Math.ceil((double) totalItems / (double) pageSize);
+        if (recordPageNo_2 > recordTotalPages_2) recordPageNo_2 = recordTotalPages_2;
+        if (recordPageLabel_2 != null) recordPageLabel_2.setText(recordPageNo_2 + "/" + recordTotalPages_2);
+
+        java.util.List<java.util.Map<String, Object>> rows = QMParamsDAO.queryByOprnoAndSnLike(Config.gw_2, snLike, pageSize, offset);
+        int rowIndex = 0;
+        for (java.util.Map<String, Object> r : rows) {
+            if (rowIndex >= recordRowData_2.length) break;
+            String sn = r.get("sn") == null ? "" : String.valueOf(r.get("sn"));
+            String recordTime = r.get("record_time") == null ? "" : String.valueOf(r.get("record_time"));
+            String pressure = (r.get("pressure_value") == null ? "" : String.valueOf(r.get("pressure_value")))
+                    + (r.get("pressure_unit") == null ? "" : String.valueOf(r.get("pressure_unit")));
+            String leak = (r.get("leak_value") == null ? "" : String.valueOf(r.get("leak_value")))
+                    + (r.get("leak_unit") == null ? "" : String.valueOf(r.get("leak_unit")));
+            String result = r.get("test_result") == null ? "" : String.valueOf(r.get("test_result"));
+
+            recordRowData_2[rowIndex][0] = sn;
+            recordRowData_2[rowIndex][1] = recordTime;
+            recordRowData_2[rowIndex][2] = pressure;
+            recordRowData_2[rowIndex][3] = leak;
+            recordRowData_2[rowIndex][4] = result;
+            rowIndex++;
+        }
+
+        if (recordTable_2 != null) recordTable_2.repaint();
     }
 
     public static void setMenuState_1(String msg, int error) {

+ 84 - 1
src/com/mes/util/QMParamsDAO.java

@@ -12,7 +12,9 @@ import java.util.Map;
 
 public class QMParamsDAO {
     public static final Logger log =  LoggerFactory.getLogger(QMParamsDAO.class);
-    private static final Connection conn = JdbcUtils.conn;
+    private static Connection conn() {
+        return JdbcUtils.conn;
+    }
 
     private QMParamsDAO() {}
 
@@ -37,6 +39,12 @@ public class QMParamsDAO {
                 "state CHAR(1)                         -- 状态 (0 ->未提交,1 ->已提交)\n" +
                 ")";
 
+        Connection conn = conn();
+        if (conn == null) {
+            log.error("创建qm_params表失败: 数据库未连接");
+            return;
+        }
+
         try (Statement stmt = conn.createStatement()) {
             stmt.executeUpdate(qmParams);
             log.info("创建qm_params表成功");
@@ -56,6 +64,12 @@ public class QMParamsDAO {
                 + "leak_value, pressure_unit, leak_unit, fill_time, stabilize_time, "
                 + "test_time, record_time,state,work_num) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,0,?)";
 
+        Connection conn = conn();
+        if (conn == null) {
+            log.error("qm_params表插入数据失败: 数据库未连接");
+            return;
+        }
+
         try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
 
             pstmt.setString(1, oprno);
@@ -97,6 +111,12 @@ public class QMParamsDAO {
             sql += " LIMIT " + limit;
         }
 
+        Connection conn = conn();
+        if (conn == null) {
+            log.error("查询qm_params失败: 数据库未连接");
+            return params;
+        }
+
         try (Statement stmt = conn.createStatement();
              ResultSet rs = stmt.executeQuery(sql)) {
 
@@ -119,6 +139,12 @@ public class QMParamsDAO {
     public static void markAsSubmitted(int id) {
         String sql = "UPDATE qm_params SET state = '1' WHERE id = ?";
 
+        Connection conn = conn();
+        if (conn == null) {
+            log.error("更新qm_params失败: 数据库未连接");
+            return;
+        }
+
         try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
 
             pstmt.setInt(1, id);
@@ -128,6 +154,63 @@ public class QMParamsDAO {
         }
     }
 
+    public static int countByOprnoAndSnLike(String oprno, String snLike) {
+        Connection conn = conn();
+        if (conn == null) return 0;
+
+        String sql = "SELECT count(*) AS total FROM qm_params WHERE oprno = ?"
+                + ((snLike != null && !snLike.trim().isEmpty()) ? " AND sn LIKE ?" : "");
+
+        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+            pstmt.setString(1, oprno);
+            if (snLike != null && !snLike.trim().isEmpty()) {
+                pstmt.setString(2, "%" + snLike.trim() + "%");
+            }
+            try (ResultSet rs = pstmt.executeQuery()) {
+                if (rs.next()) return rs.getInt("total");
+            }
+        } catch (SQLException e) {
+            handleSQLException(e);
+        }
+        return 0;
+    }
+
+    public static List<Map<String, Object>> queryByOprnoAndSnLike(String oprno, String snLike, int limit, int offset) {
+        List<Map<String, Object>> params = new ArrayList<>();
+        Connection conn = conn();
+        if (conn == null) return params;
+
+        String sql = "SELECT * FROM qm_params WHERE oprno = ?"
+                + ((snLike != null && !snLike.trim().isEmpty()) ? " AND sn LIKE ?" : "")
+                + " ORDER BY id DESC LIMIT ? OFFSET ?";
+
+        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
+            int idx = 1;
+            pstmt.setString(idx++, oprno);
+            if (snLike != null && !snLike.trim().isEmpty()) {
+                pstmt.setString(idx++, "%" + snLike.trim() + "%");
+            }
+            pstmt.setInt(idx++, limit);
+            pstmt.setInt(idx, offset);
+
+            try (ResultSet rs = pstmt.executeQuery()) {
+                ResultSetMetaData metaData = rs.getMetaData();
+                int columnCount = metaData.getColumnCount();
+                while (rs.next()) {
+                    Map<String, Object> param = new HashMap<>();
+                    for (int i = 1; i <= columnCount; i++) {
+                        param.put(metaData.getColumnName(i), rs.getObject(i));
+                    }
+                    params.add(param);
+                }
+            }
+        } catch (SQLException e) {
+            handleSQLException(e);
+        }
+
+        return params;
+    }
+
     private static void handleSQLException(SQLException e) {
         log.error("qm_params表操作报错", e);
     }