张世豪
22 小时以前 03b0fb0ba2de86bcfff277778826547c0e37a93f
优化修改
已修改14个文件
392 ■■■■ 文件已修改
bin/chuankou/Sendmsg.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/chuankou/SerialPortService.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/chushihua/lunxun$PollingTask.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/chushihua/lunxun.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/home/Homein.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/xitongshezhi/canshushezhi$1.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/xitongshezhi/canshushezhi$2.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/xitongshezhi/canshushezhi.class 补丁 | 查看 | 原始文档 | blame | 历史
src/chuankou/Sendmsg.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/chuankou/SerialPortService.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/chushihua/lunxun.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/chushihua/lunxunzaixian.java 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/home/Homein.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/xitongshezhi/canshushezhi.java 236 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bin/chuankou/Sendmsg.class
Binary files differ
bin/chuankou/SerialPortService.class
Binary files differ
bin/chushihua/lunxun$PollingTask.class
Binary files differ
bin/chushihua/lunxun.class
Binary files differ
bin/home/Homein.class
Binary files differ
bin/xitongshezhi/canshushezhi$1.class
Binary files differ
bin/xitongshezhi/canshushezhi$2.class
Binary files differ
bin/xitongshezhi/canshushezhi.class
Binary files differ
src/chuankou/Sendmsg.java
@@ -11,8 +11,8 @@
    private static volatile SerialPortService serialService = null;
    private static volatile boolean isPortOpen = false;
    
    // 调试模式开关
    private static final boolean DEBUG_MODE = false;
    // 改为非final,支持动态控制
    private static boolean DEBUG_MODE = false;
    
    // 日期格式化
    private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS");
@@ -35,48 +35,65 @@
    }
    
    /**
     * 发送消息到串口
     * @param message 要发送的HEX格式消息
     * @return 发送成功返回true,失败返回false
     * 发送消息到串口(带重试机制)
     */
    public static boolean sendMessage(String message) {
        if (!isPortOpen || serialService == null) {
            if (DEBUG_MODE) {
                System.err.println("[" + getCurrentTime() + "] 串口未打开,无法发送数据");
            }
            return false;
        }
        
        if (message == null || message.trim().isEmpty()) {
            if (DEBUG_MODE) {
                System.err.println("[" + getCurrentTime() + "] 发送数据为空");
            }
            return false;
        }
        
        String text = message.trim();
        int retryCount = 0;
        final int MAX_RETRY = 2;
        
        while (retryCount <= MAX_RETRY) {
        try {
            // HEX格式发送
            byte[] data = hexStringToByteArray(text);
            if (data != null && serialService.send(data)) {
                // 高频调用时避免频繁的日志输出,只在调试时记录
                if (data == null) {
                    System.err.println("[" + getCurrentTime() + "] HEX转换失败,数据: " + text);
                    return false;
                }
                boolean sendResult = serialService.send(data);
                if (sendResult) {
                if (DEBUG_MODE) {
                    System.out.println("[" + getCurrentTime() + "] 发送: " + text.toUpperCase());
                        System.out.println("[" + getCurrentTime() + "] 发送成功: " + text.toUpperCase());
                }
                return true;
            } else {
                if (DEBUG_MODE) {
                    System.err.println("[" + getCurrentTime() + "] 数据发送失败");
                    retryCount++;
                    if (retryCount <= MAX_RETRY) {
                        System.err.println("[" + getCurrentTime() + "] 发送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")");
                        try {
                            Thread.sleep(50); // 重试前等待
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    } else {
                        System.err.println("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase());
                        System.err.println("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen + ", 服务: " + (serialService != null));
                        if (serialService != null) {
                            System.err.println("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen());
                }
                return false;
                    }
            }
        } catch (Exception e) {
            if (DEBUG_MODE) {
                System.err.println("[" + getCurrentTime() + "] 数据格式错误: " + e.getMessage());
            }
                System.err.println("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase());
                e.printStackTrace();
            return false;
        }
        }
        return false;
    }
    
    /**
@@ -84,7 +101,11 @@
     * @return 串口打开状态
     */
    public static boolean isPortOpen() {
        return isPortOpen && serialService != null;
        boolean open = isPortOpen && serialService != null;
        if (!open && DEBUG_MODE) {
            System.err.println("[" + getCurrentTime() + "] 串口状态检查: 未打开");
        }
        return open;
    }
    
    /**
@@ -100,7 +121,7 @@
        s = s.replaceAll("\\s+", ""); // 移除空格
        int len = s.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("HEX字符串长度必须为偶数");
            throw new IllegalArgumentException("HEX字符串长度必须为偶数,当前长度: " + len + ", 数据: " + s);
        }
        
        byte[] data = new byte[len / 2];
@@ -109,7 +130,7 @@
            int low = Character.digit(s.charAt(i + 1), 16);
            
            if (high == -1 || low == -1) {
                throw new IllegalArgumentException("无效的HEX字符: " + s.charAt(i) + s.charAt(i + 1));
                throw new IllegalArgumentException("无效的HEX字符: '" + s.charAt(i) + s.charAt(i + 1) + "' 在位置 " + i + "-" + (i+1) + ", 完整数据: " + s);
            }
            
            data[i / 2] = (byte) ((high << 4) + low);
@@ -144,12 +165,25 @@
    
    /**
     * 启用调试模式
     * 注意:这会修改静态final变量,实际项目中不建议这样做
     * 这里只是演示,实际应该通过配置文件控制
     */
    public static void enableDebugMode() {
        // 在实际项目中,应该使用可配置的方式而不是修改final变量
        // 这里只是示意,实际使用时需要重新设计
        System.out.println("调试模式已启用");
        DEBUG_MODE = true;
        System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式已启用");
    }
    /**
     * 禁用调试模式
     */
    public static void disableDebugMode() {
        DEBUG_MODE = false;
        System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式已禁用");
    }
    /**
     * 设置调试模式
     */
    public static void setDebugMode(boolean debug) {
        DEBUG_MODE = debug;
        System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式: " + (debug ? "启用" : "禁用"));
    }
}
src/chuankou/SerialPortService.java
@@ -230,14 +230,29 @@
    public boolean isOpen() {
        return port != null && port.isOpen();
    }
    /**
     * 发送数据
     * 发送数据(优化版本)
     */
    public boolean send(byte[] data) {
        if (!isOpen()) {
            return false;
        }
        return port != null && port.isOpen() && port.writeBytes(data, data.length) > 0;
        // 添加发送前的串口状态检查
        if (port == null || !port.isOpen()) {
            return false;
    }
        try {
            // 添加小延迟,避免连续发送
            Thread.sleep(2);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
        int result = port.writeBytes(data, data.length);
        return result > 0;
    }
}
src/chushihua/lunxun.java
@@ -116,9 +116,6 @@
            pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread");
            pollingThread.setDaemon(true);
            pollingThread.start();            
            if (DEBUG_ENABLED) {
                //System.out.println("轮询查询已启动,间隔: " + pollingInterval + "ms");
            }
            return true;
        } catch (Exception e) {
            System.err.println("启动轮询查询线程时发生异常: " + e.getMessage());
@@ -387,7 +384,7 @@
                                } else {
                                    consecutiveFailures++;
                                    if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
                                        System.err.println("连续失败次数过多,暂停轮询");
                                        System.err.println("lunxun连续失败次数过多,暂停轮询");
                                        pausePolling();
                                        break;
                                    }
@@ -442,7 +439,7 @@
                    if (sendResult) {
                        // 只在调试时输出,避免频繁打印
                        if (DEBUG_ENABLED) {
                            SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)", slotNumber));
                            SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)\n", slotNumber));
                        }
                        return true;
                    } else {
src/chushihua/lunxunzaixian.java
@@ -19,8 +19,8 @@
    private static Thread onlinePollingThread;
    
    // 可配置的轮询参数(不再是final)
    private static int cycleInterval = 60000; // 完整轮询周期间隔:60秒
    private static int slotInterval = 200;    // 卡槽间查询间隔:200毫秒
    private static int cycleInterval = 120000; // 完整轮询周期间隔:60秒
    private static int slotInterval = 200;    // 卡槽间查询间隔:500毫秒
    
    // 卡槽相关常量
    private static final int MIN_SLOT = 1;
@@ -302,7 +302,7 @@
                    } else {
                        consecutiveFailures++;
                        if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
                            System.err.println("连续失败次数过多,暂停在线轮询");
                            System.err.println("lunxunzaixian连续失败次数过多,暂停在线轮询");
                            pauseOnlinePolling();
                        }
                    }
@@ -365,7 +365,7 @@
            int polledCount = 0;
            int totalCardSlots = cardSlots.size();
            
            // 第二阶段:批量查询有卡卡槽
            // 第二阶段:批量查询有卡卡槽 - 修复:每个卡槽间都有间隔
            for (int i = 0; i < cardSlots.size(); i += BATCH_SIZE) {
                if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) {
                    break;
@@ -374,14 +374,26 @@
                int end = Math.min(i + BATCH_SIZE, cardSlots.size());
                List<Integer> batch = cardSlots.subList(i, end);
                
                // 批次内查询
                for (int slotNumber : batch) {
                // 批次内查询 - 修复:每个卡槽间添加间隔
                for (int j = 0; j < batch.size(); j++) {
                    int slotNumber = batch.get(j);
                    if (sendQueryToCardSlot(slotNumber)) {
                        polledCount++;
                    }
                    // 重要修复:每个卡槽查询后等待指定间隔(最后一个卡槽除外)
                    if (j < batch.size() - 1) {
                        try {
                            Thread.sleep(slotInterval); // 卡槽间间隔
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
                
                // 批次间间隔
                // 批次间间隔(保持原有逻辑)
                if (end < cardSlots.size()) {
                    try {
                        Thread.sleep(slotInterval * BATCH_SIZE);
@@ -393,12 +405,14 @@
            }
            
            if (polledCount > 0 && lunxun.DEBUG_ENABLED) {
                //System.out.println("在线轮询完成,成功查询 " + polledCount + "/" + totalCardSlots + " 个有卡卡槽");
                System.out.println("在线轮询完成,成功查询 " + polledCount + "/" + totalCardSlots + " 个有卡卡槽");
            }
            
            return polledCount > 0;
        }
        
        /**
         * 向指定有卡卡槽发送查询指令
         * @param slotNumber 卡槽编号
src/home/Homein.java
@@ -129,21 +129,13 @@
            
            if (serialConnected) {
                // 4. 串口连接成功后,启动轮询
                boolean pollingStarted = startPollingService();
                if (pollingStarted) {
                startPollingService();
                    showMainInterface();
                    //启动轮询卡状态给服务器发数据
                    lunxunkazhuangtai.startPolling();
                    //启动在线的卡状态轮询
                    lunxunzaixian.startOnlinePolling();
                } else {
                    System.err.println("轮询服务启动失败");
                    JOptionPane.showMessageDialog(null,
                        "轮询服务启动失败,应用程序无法正常运行",
                        "警告",
                        JOptionPane.WARNING_MESSAGE);
                }
            } else {
                System.err.println("串口连接失败");
                // 串口连接失败已经由SerialPortConnectionDialog处理,直接退出
src/xitongshezhi/canshushezhi.java
@@ -17,12 +17,14 @@
    private static final int SCREEN_WIDTH = 600;
    private static final int SCREEN_HEIGHT = 1024;
    
    // 颜色常量 - 使用不透明颜色
    // 颜色定义 - 使用mimaguanli.java中的颜色方案
    private static final Color BACKGROUND_COLOR = new Color(15, 28, 48);
    private static final Color CARD_COLOR = new Color(26, 43, 68);
    private static final Color PRIMARY_COLOR = new Color(52, 152, 219);
    private static final Color SECONDARY_COLOR = new Color(46, 204, 113);
    private static final Color DARK_COLOR = new Color(15, 28, 48);
    private static final Color DARK_LIGHT_COLOR = new Color(26, 43, 68);
    private static final Color TEXT_COLOR = new Color(224, 224, 224);
    private static final Color TEXT_LIGHT_COLOR = new Color(160, 200, 255);
    private static final Color FIELD_BACKGROUND = new Color(240, 240, 240);
    
    // UI组件
    private JPanel mainPanel;
@@ -58,10 +60,10 @@
            e.printStackTrace();
        }
        
        // 创建主面板 - 不透明背景
        // 创建主面板 - 使用mimaguanli的背景色
        mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());
        mainPanel.setBackground(DARK_COLOR);
        mainPanel.setBackground(BACKGROUND_COLOR);
        mainPanel.setOpaque(true);
        mainPanel.setBorder(new EmptyBorder(12, 12, 12, 12));
        
@@ -82,14 +84,18 @@
        titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 22));
        titleLabel.setForeground(TEXT_COLOR);
        
        // 关闭按钮
        // 关闭按钮 - 使用mimaguanli的按钮样式
        JButton backButton = new JButton("关闭");
        backButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
        backButton.setBackground(PRIMARY_COLOR);
        backButton.setForeground(Color.WHITE);
        backButton.setOpaque(true);
        backButton.setFocusPainted(false);
        backButton.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16));
        backButton.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(40, 120, 180), 1),
            BorderFactory.createEmptyBorder(8, 16, 8, 16)
        ));
        backButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        backButton.addActionListener(e -> dispose());
        
        // 关闭按钮悬停效果
@@ -130,12 +136,14 @@
        scrollPane.setOpaque(false);
        scrollPane.getViewport().setOpaque(false);
        
        // 基本参数设置卡片
        settingsPanel.add(createBasicSettingsCard());
        settingsPanel.add(Box.createRigidArea(new Dimension(0, 12)));
        // 自定义滚动条
        JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar();
        verticalScrollBar.setBackground(CARD_COLOR);
        verticalScrollBar.setForeground(PRIMARY_COLOR);
        verticalScrollBar.setUnitIncrement(20);
        
        // 设备参数设置卡片
        settingsPanel.add(createDeviceSettingsCard());
        // 合并的参数设置卡片
        settingsPanel.add(createMergedSettingsCard());
        settingsPanel.add(Box.createRigidArea(new Dimension(0, 12)));
        
        // 保存按钮
@@ -148,172 +156,148 @@
        return container;
    }
    
    private JPanel createBasicSettingsCard() {
    private JPanel createMergedSettingsCard() {
        JPanel card = new JPanel();
        card.setLayout(new BorderLayout());
        card.setBackground(DARK_LIGHT_COLOR);
        card.setBackground(CARD_COLOR);
        card.setOpaque(true);
        card.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(52, 152, 219, 128)),
            BorderFactory.createEmptyBorder(15, 15, 15, 15)
            BorderFactory.createLineBorder(new Color(52, 152, 219, 100), 1),
            BorderFactory.createEmptyBorder(20, 20, 20, 20)
        ));
        
        // 卡头
        JPanel cardHeader = new JPanel(new BorderLayout());
        cardHeader.setOpaque(false);
        JLabel titleLabel = new JLabel("基本参数设置");
        titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16));
        titleLabel.setForeground(TEXT_COLOR);
        cardHeader.add(titleLabel, BorderLayout.WEST);
        card.add(cardHeader, BorderLayout.NORTH);
        // 表单内容 - 使用网格布局实现标签在左,文本框在右
        // 调整行高为80像素,为60像素高的组件提供足够的间距
        JPanel formPanel = new JPanel(new GridLayout(3, 2, 10, 20));
        // 表单内容 - 使用水平布局实现标签在左,文本框在右
        JPanel formPanel = new JPanel();
        formPanel.setLayout(new BoxLayout(formPanel, BoxLayout.Y_AXIS));
        formPanel.setOpaque(false);
        formPanel.setBorder(new EmptyBorder(15, 0, 0, 0));
        
        // 发卡机编号
        JLabel deviceIdLabel = new JLabel("发卡机编号:");
        deviceIdLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
        deviceIdLabel.setForeground(TEXT_COLOR);
        formPanel.add(deviceIdLabel);
        deviceIdField = new JTextField();
        styleFormField(deviceIdField);
        formPanel.add(deviceIdField);
        formPanel.add(createHorizontalField("发卡机编号:", deviceIdField = new JTextField()));
        formPanel.add(Box.createRigidArea(new Dimension(0, 18)));
        
        // 服务器地址
        JLabel serverAddressLabel = new JLabel("服务器地址:");
        serverAddressLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
        serverAddressLabel.setForeground(TEXT_COLOR);
        formPanel.add(serverAddressLabel);
        serverAddressField = new JTextField();
        styleFormField(serverAddressField);
        formPanel.add(serverAddressField);
        formPanel.add(createHorizontalField("服务器地址:", serverAddressField = new JTextField()));
        formPanel.add(Box.createRigidArea(new Dimension(0, 18)));
        
        // 服务器端口
        JLabel serverPortLabel = new JLabel("服务器端口:");
        serverPortLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
        serverPortLabel.setForeground(TEXT_COLOR);
        formPanel.add(serverPortLabel);
        formPanel.add(createHorizontalField("服务器端口:", serverPortField = new JTextField()));
        formPanel.add(Box.createRigidArea(new Dimension(0, 18)));
        
        serverPortField = new JTextField();
        styleFormField(serverPortField);
        formPanel.add(serverPortField);
        // 卡槽总数
        formPanel.add(createHorizontalField("卡槽总数:", slotCountField = new JTextField()));
        formPanel.add(Box.createRigidArea(new Dimension(0, 18)));
        // 读卡号模式
        formPanel.add(createHorizontalComboBoxField("读卡号模式:", readModeComboBox = new JComboBox<>(new String[]{"主动模式", "被动模式"})));
        
        card.add(formPanel, BorderLayout.CENTER);
        
        return card;
    }
    
    private JPanel createDeviceSettingsCard() {
        JPanel card = new JPanel();
        card.setLayout(new BorderLayout());
        card.setBackground(DARK_LIGHT_COLOR);
        card.setOpaque(true);
        card.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(52, 152, 219, 128)),
            BorderFactory.createEmptyBorder(15, 15, 15, 15)
    private JPanel createHorizontalField(String labelText, JTextField textField) {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBackground(CARD_COLOR);
        panel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50));
        // 标签
        JLabel label = new JLabel(labelText);
        label.setFont(new Font("Microsoft YaHei", Font.BOLD, 14));
        label.setForeground(TEXT_COLOR);
        label.setPreferredSize(new Dimension(100, 30));
        // 文本框样式 - 使用mimaguanli的样式
        textField.setBackground(FIELD_BACKGROUND);
        textField.setForeground(Color.BLACK);
        textField.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200), 1),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)
        ));
        textField.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
        textField.setOpaque(true);
        textField.setPreferredSize(new Dimension(280, 42));
        
        // 卡头
        JPanel cardHeader = new JPanel(new BorderLayout());
        cardHeader.setOpaque(false);
        // 创建水平布局容器
        JPanel horizontalPanel = new JPanel(new BorderLayout());
        horizontalPanel.setBackground(CARD_COLOR);
        horizontalPanel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50));
        
        JLabel titleLabel = new JLabel("设备参数设置");
        titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16));
        titleLabel.setForeground(TEXT_COLOR);
        horizontalPanel.add(label, BorderLayout.WEST);
        horizontalPanel.add(textField, BorderLayout.CENTER);
        
        cardHeader.add(titleLabel, BorderLayout.WEST);
        card.add(cardHeader, BorderLayout.NORTH);
        // 添加间距
        horizontalPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
        
        // 表单内容 - 使用网格布局实现标签在左,输入组件在右
        // 调整行高为80像素,为60像素高的组件提供足够的间距
        JPanel formPanel = new JPanel(new GridLayout(2, 2, 10, 20));
        formPanel.setOpaque(false);
        formPanel.setBorder(new EmptyBorder(15, 0, 0, 0));
        return horizontalPanel;
    }
        
        // 卡槽总数
        JLabel slotCountLabel = new JLabel("卡槽总数:");
        slotCountLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
        slotCountLabel.setForeground(TEXT_COLOR);
        formPanel.add(slotCountLabel);
    private JPanel createHorizontalComboBoxField(String labelText, JComboBox<String> comboBox) {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBackground(CARD_COLOR);
        panel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50));
        
        slotCountField = new JTextField();
        styleFormField(slotCountField);
        formPanel.add(slotCountField);
        // 标签
        JLabel label = new JLabel(labelText);
        label.setFont(new Font("Microsoft YaHei", Font.BOLD, 14));
        label.setForeground(TEXT_COLOR);
        label.setPreferredSize(new Dimension(100, 30));
        
        // 读卡号模式
        JLabel readModeLabel = new JLabel("读卡号模式:");
        readModeLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
        readModeLabel.setForeground(TEXT_COLOR);
        formPanel.add(readModeLabel);
        // 组合框样式 - 使用mimaguanli的样式
        comboBox.setBackground(FIELD_BACKGROUND);
        comboBox.setForeground(Color.BLACK);
        comboBox.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200), 1),
            BorderFactory.createEmptyBorder(10, 12, 10, 12)
        ));
        comboBox.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
        comboBox.setOpaque(true);
        comboBox.setPreferredSize(new Dimension(280, 42));
        
        readModeComboBox = new JComboBox<>(new String[]{"主动模式", "被动模式"});
        styleComboBox(readModeComboBox);
        formPanel.add(readModeComboBox);
        // 创建水平布局容器
        JPanel horizontalPanel = new JPanel(new BorderLayout());
        horizontalPanel.setBackground(CARD_COLOR);
        horizontalPanel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50));
        
        card.add(formPanel, BorderLayout.CENTER);
        horizontalPanel.add(label, BorderLayout.WEST);
        horizontalPanel.add(comboBox, BorderLayout.CENTER);
        
        return card;
        // 添加间距
        horizontalPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
        return horizontalPanel;
    }
    
    private JPanel createSaveButton() {
        JPanel buttonPanel = new JPanel(new BorderLayout());
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.setOpaque(false);
        buttonPanel.setBorder(new EmptyBorder(10, 0, 0, 0));
        
        JButton saveButton = new JButton("保存所有设置");
        saveButton.setFont(new Font("Microsoft YaHei", Font.BOLD, 16));
        saveButton.setBackground(SECONDARY_COLOR);
        saveButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14));
        saveButton.setBackground(PRIMARY_COLOR);
        saveButton.setForeground(Color.WHITE);
        saveButton.setOpaque(true);
        saveButton.setFocusPainted(false);
        saveButton.setPreferredSize(new Dimension(0, 60)); // 高度改为60像素
        saveButton.setBorder(BorderFactory.createEmptyBorder(12, 20, 12, 20));
        saveButton.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(40, 120, 180), 1),
            BorderFactory.createEmptyBorder(8, 16, 8, 16)
        ));
        saveButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        saveButton.addActionListener(e -> saveSettings());
        
        // 按钮悬停效果
        saveButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                saveButton.setBackground(brighterColor(SECONDARY_COLOR));
                saveButton.setBackground(brighterColor(PRIMARY_COLOR));
            }
            
            public void mouseExited(java.awt.event.MouseEvent evt) {
                saveButton.setBackground(SECONDARY_COLOR);
                saveButton.setBackground(PRIMARY_COLOR);
            }
        });
        
        buttonPanel.add(saveButton, BorderLayout.CENTER);
        buttonPanel.add(saveButton);
        return buttonPanel;
    }
    private void styleFormField(JTextField field) {
        field.setPreferredSize(new Dimension(200, 60)); // 高度改为60像素
        field.setBackground(Color.WHITE); // 不透明白色背景
        field.setForeground(Color.BLACK); // 黑色文字
        field.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200)),
            BorderFactory.createEmptyBorder(8, 12, 8, 12)
        ));
        field.setFont(new Font("Microsoft YaHei", Font.PLAIN, 13));
        field.setCaretColor(Color.BLACK);
        field.setOpaque(true); // 确保不透明
    }
    private void styleComboBox(JComboBox<String> comboBox) {
        comboBox.setPreferredSize(new Dimension(200, 60)); // 高度改为60像素
        comboBox.setBackground(Color.WHITE); // 不透明白色背景
        comboBox.setForeground(Color.BLACK); // 黑色文字
        comboBox.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(new Color(200, 200, 200)),
            BorderFactory.createEmptyBorder(8, 12, 8, 12)
        ));
        comboBox.setFont(new Font("Microsoft YaHei", Font.PLAIN, 13));
        comboBox.setOpaque(true); // 确保不透明
    }
    
    private void initializeData() {