张世豪
2025-11-28 7acfc864d11de1fc41cabc2a5d4fad3894c2e5b0
增加发卡不成功再次发卡的逻辑
已修改8个文件
已添加1个文件
762 ■■■■■ 文件已修改
bin/.gitignore 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bin/chuankou/Sendmsg.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/chushihua/SlotManager.class 补丁 | 查看 | 原始文档 | blame | 历史
bin/home/CardMachineUI.class 补丁 | 查看 | 原始文档 | blame | 历史
src/chuankou/Sendmsg.java 670 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/chushihua/SlotManager.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/home/CardMachineUI.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/home/Fkj.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicway/TimestampUtil.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bin/.gitignore
@@ -1,7 +1,3 @@
/chuankou/
/chushihua/
/dialog/
/home/
/jiekou/
/publicway/
/xitongshezhi/
/chushihua/
/chuankou/
bin/chuankou/Sendmsg.class
Binary files differ
bin/chushihua/SlotManager.class
Binary files differ
bin/home/CardMachineUI.class
Binary files differ
src/chuankou/Sendmsg.java
@@ -6,11 +6,13 @@
import javax.swing.SwingWorker;
import chushihua.SlotManager;
import chushihua.lunxun;
import dialog.Charulog;
import dialog.Dingshidialog;
import dialog.Errlog;
import publicway.OpenDoor;
import publicway.TimestampUtil;
import xitongshezhi.SystemDebugDialog;
/**
@@ -19,333 +21,343 @@
 * ä¼˜åŒ–内存使用,避免长时间运行内存泄漏
 */
public class Sendmsg {
    // é™æ€ä¸²å£æœåŠ¡å®žä¾‹
    private static volatile SerialPortService serialService = null;
    private static final AtomicBoolean isPortOpen = new AtomicBoolean(false);
    // æ”¹ä¸ºéžfinal,支持动态控制
    private static volatile boolean DEBUG_MODE = false;
    // ä½¿ç”¨ThreadLocal保证SimpleDateFormat线程安全
    private static final ThreadLocal<SimpleDateFormat> TIME_FORMATTER =
        ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss.SSS"));
    // ç¼“存字符串构建器,减少对象创建
    private static final ThreadLocal<StringBuilder> STRING_BUILDER_CACHE =
        ThreadLocal.withInitial(() -> new StringBuilder(128));
    // è®°å½•活跃的SwingWorker,便于管理
    private static final ConcurrentHashMap<String, SwingWorker<?, ?>> ACTIVE_WORKERS =
        new ConcurrentHashMap<>();
    /**发卡服务器控制打开某个柜门调用指令
     * @param int slotId柜门编号1-60
     * @param int type 1是服务器发卡,2是管理员发卡*/
    public static boolean opendoorzhiling(int slotId,int type) {
        lunxun.setSendChaxunzhiling(false);//暂停查询指令
        try {
            // è°ƒç”¨OpenDoor生成开门指令
            String command = OpenDoor.openOneDoor(slotId, type);
            boolean sendResult = Sendmsg.sendMessage(command);
            StringBuilder mesBuilder = STRING_BUILDER_CACHE.get();
            mesBuilder.setLength(0); // æ¸…空重用
            mesBuilder.append(command).append(";type").append(type).append("控制打开").append(slotId).append("柜门");
            String mes = mesBuilder.toString();
            Charulog.logOperation(mes);
            if (lunxun.DEBUG_ENABLED) {
                SystemDebugDialog.appendAsciiData(mes);
            }
            return sendResult;
        } finally {
            // ç¡®ä¿æ¢å¤æŸ¥è¯¢æŒ‡ä»¤
            lunxun.setSendChaxunzhiling(true);
        }
    }
    /**
     * æ‰“开全部卡槽的公用静态方法
     * @param type æ“ä½œç±»åž‹ï¼š1-服务器发卡,2-管理员发卡
     */
    public static void openAllSlots(int type) {
        lunxun.setSendChaxunzhiling(false);//暂停查询指令
        String workerKey = "openAllSlots_" + System.currentTimeMillis();
        // ä½¿ç”¨SwingWorker在后台执行,避免阻塞UI
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                // éåŽ†æ‰€æœ‰å¡æ§½ï¼ˆ1-60)
                for (int slotId = 1; slotId <= 60 && !isCancelled(); slotId++) {
                    try {
                        // ç”Ÿæˆå¼€é—¨æŒ‡ä»¤
                        String command = OpenDoor.openOneDoor(slotId, type);
                        // å‘送串口指令
                        boolean sent = Sendmsg.sendMessage(command);
                        if (!sent) {
                            Errlog.logOperation("发送指令到卡槽 " + slotId + " å¤±è´¥");
                        }
                        // é—´éš”100ms,但检查是否被取消
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break; // è¢«ä¸­æ–­æ—¶é€€å‡ºå¾ªçޝ
                    } catch (Exception e) {
                        Errlog.logOperation("处理卡槽 " + slotId + " æ—¶å‘生错误: " + e.getMessage());
                        // ç»§ç»­å¤„理下一个卡槽,不中断循环
                    }
                }
                return null;
            }
            @Override
            protected void done() {
                try {
                    // æ¸…理worker引用
                    ACTIVE_WORKERS.remove(workerKey);
                    // å¯é€‰ï¼šå®ŒæˆåŽå¯ä»¥æ·»åŠ å›žè°ƒå¤„ç†
                    if (!isCancelled()) {
                        StringBuilder messageBuilder = STRING_BUILDER_CACHE.get();
                        messageBuilder.setLength(0);
                        String types = "管理员";
                        if(type == 1) {
                            types = "服务器指令";
                        }
                        messageBuilder.append(types).append("已将全部卡槽已经打开请取卡");
                        String message = messageBuilder.toString();
                        Dingshidialog.showTimedDialog(null, 5, message);
                        Charulog.logOperation(message);
                    }
                } finally {
                    // ç¡®ä¿æ¢å¤æŸ¥è¯¢æŒ‡ä»¤
                    lunxun.setSendChaxunzhiling(true);
                }
            }
        };
        // è®°å½•worker便于管理
        ACTIVE_WORKERS.put(workerKey, worker);
        worker.execute();
    }
    /**
     * å–消所有正在执行的任务
     */
    public static void cancelAllTasks() {
        ACTIVE_WORKERS.forEach((key, worker) -> {
            if (!worker.isDone()) {
                worker.cancel(true);
            }
        });
        ACTIVE_WORKERS.clear();
    }
    /**
     * è®¾ç½®ä¸²å£æœåŠ¡å®žä¾‹
     * @param service ä¸²å£æœåŠ¡å®žä¾‹
     * @param open ä¸²å£æ˜¯å¦æ‰“å¼€
     */
    public static void setSerialService(SerialPortService service, boolean open) {
        serialService = service;
        isPortOpen.set(open);
    }
    /**
     * èŽ·å–ä¸²å£æœåŠ¡å®žä¾‹
     */
    public static SerialPortService getSerialService() {
        return serialService;
    }
    /**
     * å‘送消息到串口(带重试机制)
     */
    public static boolean sendMessage(String message) {
        if (!isPortOpen.get() || serialService == null) {
            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£æœªæ‰“开,无法发送数据");
            return false;
        }
        if (message == null || message.trim().isEmpty()) {
            Errlog.logOperation("[" + getCurrentTime() + "] å‘送数据为空");
            return false;
        }
        String text = message.trim();
        int retryCount = 0;
        final int MAX_RETRY = 2;
        while (retryCount <= MAX_RETRY) {
            try {
                byte[] data = hexStringToByteArray(text);
                if (data == null) {
                    Errlog.logOperation("[" + getCurrentTime() + "] HEX转换失败,数据: " + text);
                    return false;
                }
                boolean sendResult = serialService.send(data);
                if (sendResult) {
                    if (DEBUG_MODE) {
                        System.out.println("[" + getCurrentTime() + "] å‘送成功: " + text.toUpperCase());
                    }
                    return true;
                } else {
                    retryCount++;
                    if (retryCount <= MAX_RETRY) {
                        Errlog.logOperation("[" + getCurrentTime() + "] å‘送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")");
                        try {
                            Thread.sleep(50); // é‡è¯•前等待
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    } else {
                        if (DEBUG_MODE) {
                            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£å‘送失败,指令: " + text.toUpperCase());
                            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£çŠ¶æ€ - æ‰“å¼€: " + isPortOpen.get() + ", æœåŠ¡: " + (serialService != null));
                            if (serialService != null) {
                                Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£æœåŠ¡çŠ¶æ€ - æ˜¯å¦æ‰“å¼€: " + serialService.isOpen());
                            }
                        }
                        return false;
                    }
                }
            } catch (Exception e) {
                Errlog.logOperation("[" + getCurrentTime() + "] å‘送异常,指令: " + text.toUpperCase());
                if (DEBUG_MODE) {
                    e.printStackTrace();
                }
                return false;
            }
        }
        return false;
    }
    /**
     * æ£€æŸ¥ä¸²å£æ˜¯å¦å·²æ‰“å¼€
     * @return ä¸²å£æ‰“开状态
     */
    public static boolean isPortOpen() {
        boolean open = isPortOpen.get() && serialService != null;
        if (!open && DEBUG_MODE) {
            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£çŠ¶æ€æ£€æŸ¥: æœªæ‰“å¼€");
        }
        return open;
    }
    /**
     * HEX字符串转字节数组
     * @param s HEX字符串
     * @return å­—节数组
     */
    private static byte[] hexStringToByteArray(String s) {
        if (s == null || s.isEmpty()) {
            return new byte[0];
        }
        s = s.replaceAll("\\s+", ""); // ç§»é™¤ç©ºæ ¼
        int len = s.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("HEX字符串长度必须为偶数,当前长度: " + len + ", æ•°æ®: " + s);
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            int high = Character.digit(s.charAt(i), 16);
            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) + "' åœ¨ä½ç½® " + i + "-" + (i+1) + ", å®Œæ•´æ•°æ®: " + s);
            }
            data[i / 2] = (byte) ((high << 4) + low);
        }
        return data;
    }
    /**
     * å­—节数组转HEX字符串
     * @param bytes å­—节数组
     * @return HEX字符串
     */
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return "";
        }
        StringBuilder sb = STRING_BUILDER_CACHE.get();
        sb.setLength(0);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´å­—ç¬¦ä¸²
     * @return æ—¶é—´å­—符串
     */
    private static String getCurrentTime() {
        return TIME_FORMATTER.get().format(new Date());
    }
    /**
     * å¯ç”¨è°ƒè¯•模式
     */
    public static void enableDebugMode() {
        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 ? "启用" : "禁用"));
    }
    /**
     * æ¸…理资源,防止内存泄漏
     */
    public static void cleanup() {
        cancelAllTasks();
        // æ¸…理ThreadLocal资源
        TIME_FORMATTER.remove();
        STRING_BUILDER_CACHE.remove();
        if (DEBUG_MODE) {
            System.out.println("[" + getCurrentTime() + "] Sendmsg资源清理完成");
        }
    }
    /**
     * èŽ·å–æ´»è·ƒä»»åŠ¡æ•°é‡
     */
    public static int getActiveTaskCount() {
        return ACTIVE_WORKERS.size();
    }
    // é™æ€ä¸²å£æœåŠ¡å®žä¾‹
    private static volatile SerialPortService serialService = null;
    private static final AtomicBoolean isPortOpen = new AtomicBoolean(false);
    // æ”¹ä¸ºéžfinal,支持动态控制
    private static volatile boolean DEBUG_MODE = false;
    // ä½¿ç”¨ThreadLocal保证SimpleDateFormat线程安全
    private static final ThreadLocal<SimpleDateFormat> TIME_FORMATTER =
            ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss.SSS"));
    // ç¼“存字符串构建器,减少对象创建
    private static final ThreadLocal<StringBuilder> STRING_BUILDER_CACHE =
            ThreadLocal.withInitial(() -> new StringBuilder(128));
    // è®°å½•活跃的SwingWorker,便于管理
    private static final ConcurrentHashMap<String, SwingWorker<?, ?>> ACTIVE_WORKERS =
            new ConcurrentHashMap<>();
    /**发卡服务器控制打开某个柜门调用指令
     * @param int slotId柜门编号1-60
     * @param int type 1是服务器发卡,2是管理员发卡*/
    public static boolean opendoorzhiling(int slotId,int type) {
        lunxun.setSendChaxunzhiling(false);//暂停查询指令
        try {
            // è°ƒç”¨OpenDoor生成开门指令
            String command = OpenDoor.openOneDoor(slotId, type);
            boolean sendResult = Sendmsg.sendMessage(command);
            StringBuilder mesBuilder = STRING_BUILDER_CACHE.get();
            mesBuilder.setLength(0); // æ¸…空重用
            mesBuilder.append(command).append(";type").append(type).append("控制打开").append(slotId).append("柜门");
            String mes = mesBuilder.toString();
            // èŽ·å–å½“å‰æ—¶é—´
            String currentTime = TimestampUtil.getTimestamp();
            // æ›´æ–°å¡æ§½çš„æ”¶åˆ°å‘卡指令时间
            SlotManager.slotArray[slotId-1].setReceiveCardCommandTime(currentTime);
            Charulog.logOperation(mes);
            if (lunxun.DEBUG_ENABLED) {
                SystemDebugDialog.appendAsciiData(mes);
            }
            return sendResult;
        } finally {
            // ç¡®ä¿æ¢å¤æŸ¥è¯¢æŒ‡ä»¤
            lunxun.setSendChaxunzhiling(true);
        }
    }
    /**
     * æ‰“开全部卡槽的公用静态方法
     * @param type æ“ä½œç±»åž‹ï¼š1-服务器发卡,2-管理员发卡
     */
    public static void openAllSlots(int type) {
        lunxun.setSendChaxunzhiling(false);//暂停查询指令
        String workerKey = "openAllSlots_" + System.currentTimeMillis();
        // ä½¿ç”¨SwingWorker在后台执行,避免阻塞UI
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                // éåŽ†æ‰€æœ‰å¡æ§½ï¼ˆ1-60)
                for (int slotId = 1; slotId <= 60 && !isCancelled(); slotId++) {
                    try {
                        // ç”Ÿæˆå¼€é—¨æŒ‡ä»¤
                        String command = OpenDoor.openOneDoor(slotId, type);
                        // å‘送串口指令
                        boolean sent = Sendmsg.sendMessage(command);
                        if (!sent) {
                            Errlog.logOperation("发送指令到卡槽 " + slotId + " å¤±è´¥");
                        }else {
                            // èŽ·å–å½“å‰æ—¶é—´
                            String currentTime = TimestampUtil.getTimestamp();
                            // æ›´æ–°å¡æ§½çš„æ”¶åˆ°å‘卡指令时间
                            SlotManager.slotArray[slotId-1].setReceiveCardCommandTime(currentTime);
                        }
                        // é—´éš”100ms,但检查是否被取消
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break; // è¢«ä¸­æ–­æ—¶é€€å‡ºå¾ªçޝ
                    } catch (Exception e) {
                        Errlog.logOperation("处理卡槽 " + slotId + " æ—¶å‘生错误: " + e.getMessage());
                        // ç»§ç»­å¤„理下一个卡槽,不中断循环
                    }
                }
                return null;
            }
            @Override
            protected void done() {
                try {
                    // æ¸…理worker引用
                    ACTIVE_WORKERS.remove(workerKey);
                    // å¯é€‰ï¼šå®ŒæˆåŽå¯ä»¥æ·»åŠ å›žè°ƒå¤„ç†
                    if (!isCancelled()) {
                        StringBuilder messageBuilder = STRING_BUILDER_CACHE.get();
                        messageBuilder.setLength(0);
                        String types = "管理员";
                        if(type == 1) {
                            types = "服务器指令";
                        }
                        messageBuilder.append(types).append("已将全部卡槽已经打开请取卡");
                        String message = messageBuilder.toString();
                        Dingshidialog.showTimedDialog(null, 5, message);
                        Charulog.logOperation(message);
                    }
                } finally {
                    // ç¡®ä¿æ¢å¤æŸ¥è¯¢æŒ‡ä»¤
                    lunxun.setSendChaxunzhiling(true);
                }
            }
        };
        // è®°å½•worker便于管理
        ACTIVE_WORKERS.put(workerKey, worker);
        worker.execute();
    }
    /**
     * å–消所有正在执行的任务
     */
    public static void cancelAllTasks() {
        ACTIVE_WORKERS.forEach((key, worker) -> {
            if (!worker.isDone()) {
                worker.cancel(true);
            }
        });
        ACTIVE_WORKERS.clear();
    }
    /**
     * è®¾ç½®ä¸²å£æœåŠ¡å®žä¾‹
     * @param service ä¸²å£æœåŠ¡å®žä¾‹
     * @param open ä¸²å£æ˜¯å¦æ‰“å¼€
     */
    public static void setSerialService(SerialPortService service, boolean open) {
        serialService = service;
        isPortOpen.set(open);
    }
    /**
     * èŽ·å–ä¸²å£æœåŠ¡å®žä¾‹
     */
    public static SerialPortService getSerialService() {
        return serialService;
    }
    /**
     * å‘送消息到串口(带重试机制)
     */
    public static boolean sendMessage(String message) {
        if (!isPortOpen.get() || serialService == null) {
            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£æœªæ‰“开,无法发送数据");
            return false;
        }
        if (message == null || message.trim().isEmpty()) {
            Errlog.logOperation("[" + getCurrentTime() + "] å‘送数据为空");
            return false;
        }
        String text = message.trim();
        int retryCount = 0;
        final int MAX_RETRY = 2;
        while (retryCount <= MAX_RETRY) {
            try {
                byte[] data = hexStringToByteArray(text);
                if (data == null) {
                    Errlog.logOperation("[" + getCurrentTime() + "] HEX转换失败,数据: " + text);
                    return false;
                }
                boolean sendResult = serialService.send(data);
                if (sendResult) {
                    if (DEBUG_MODE) {
                        System.out.println("[" + getCurrentTime() + "] å‘送成功: " + text.toUpperCase());
                    }
                    return true;
                } else {
                    retryCount++;
                    if (retryCount <= MAX_RETRY) {
                        Errlog.logOperation("[" + getCurrentTime() + "] å‘送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")");
                        try {
                            Thread.sleep(50); // é‡è¯•前等待
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    } else {
                        if (DEBUG_MODE) {
                            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£å‘送失败,指令: " + text.toUpperCase());
                            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£çŠ¶æ€ - æ‰“å¼€: " + isPortOpen.get() + ", æœåŠ¡: " + (serialService != null));
                            if (serialService != null) {
                                Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£æœåŠ¡çŠ¶æ€ - æ˜¯å¦æ‰“å¼€: " + serialService.isOpen());
                            }
                        }
                        return false;
                    }
                }
            } catch (Exception e) {
                Errlog.logOperation("[" + getCurrentTime() + "] å‘送异常,指令: " + text.toUpperCase());
                if (DEBUG_MODE) {
                    e.printStackTrace();
                }
                return false;
            }
        }
        return false;
    }
    /**
     * æ£€æŸ¥ä¸²å£æ˜¯å¦å·²æ‰“å¼€
     * @return ä¸²å£æ‰“开状态
     */
    public static boolean isPortOpen() {
        boolean open = isPortOpen.get() && serialService != null;
        if (!open && DEBUG_MODE) {
            Errlog.logOperation("[" + getCurrentTime() + "] ä¸²å£çŠ¶æ€æ£€æŸ¥: æœªæ‰“å¼€");
        }
        return open;
    }
    /**
     * HEX字符串转字节数组
     * @param s HEX字符串
     * @return å­—节数组
     */
    private static byte[] hexStringToByteArray(String s) {
        if (s == null || s.isEmpty()) {
            return new byte[0];
        }
        s = s.replaceAll("\\s+", ""); // ç§»é™¤ç©ºæ ¼
        int len = s.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("HEX字符串长度必须为偶数,当前长度: " + len + ", æ•°æ®: " + s);
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            int high = Character.digit(s.charAt(i), 16);
            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) + "' åœ¨ä½ç½® " + i + "-" + (i+1) + ", å®Œæ•´æ•°æ®: " + s);
            }
            data[i / 2] = (byte) ((high << 4) + low);
        }
        return data;
    }
    /**
     * å­—节数组转HEX字符串
     * @param bytes å­—节数组
     * @return HEX字符串
     */
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return "";
        }
        StringBuilder sb = STRING_BUILDER_CACHE.get();
        sb.setLength(0);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´å­—ç¬¦ä¸²
     * @return æ—¶é—´å­—符串
     */
    private static String getCurrentTime() {
        return TIME_FORMATTER.get().format(new Date());
    }
    /**
     * å¯ç”¨è°ƒè¯•模式
     */
    public static void enableDebugMode() {
        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 ? "启用" : "禁用"));
    }
    /**
     * æ¸…理资源,防止内存泄漏
     */
    public static void cleanup() {
        cancelAllTasks();
        // æ¸…理ThreadLocal资源
        TIME_FORMATTER.remove();
        STRING_BUILDER_CACHE.remove();
        if (DEBUG_MODE) {
            System.out.println("[" + getCurrentTime() + "] Sendmsg资源清理完成");
        }
    }
    /**
     * èŽ·å–æ´»è·ƒä»»åŠ¡æ•°é‡
     */
    public static int getActiveTaskCount() {
        return ACTIVE_WORKERS.size();
    }
}
src/chushihua/SlotManager.java
@@ -55,6 +55,9 @@
    private static final String CURRENT_EN = "current";
    private static final String FAULT_EN = "fault";
    private static final String UPDATE_TIME_EN = "updatetime";
    // åœ¨å±žæ€§å®šä¹‰åŒºåŸŸæ·»åŠ å¸¸é‡
    private static final String RECEIVE_CARD_COMMAND_TIME = "收到发卡指令时间";
    private static final String RECEIVE_CARD_COMMAND_TIME_EN = "receivecardcommandtime";
    /**
     * æž„造函数 - åˆå§‹åŒ–所有卡槽
@@ -81,7 +84,7 @@
            slot.setCurrent(UNKNOWN_VALUE);
            slot.setFault(UNKNOWN_VALUE);
            slot.setUpdateTime(UNKNOWN_VALUE);
            slot.setReceiveCardCommandTime(UNKNOWN_VALUE); // æ–°å¢žï¼šåˆå§‹åŒ–收到发卡指令时间为-1
            slotArray[i] = slot;
        }
@@ -165,6 +168,11 @@
        case UPDATE_TIME_EN:
            slot.setUpdateTime(value);
            break;
            // åœ¨ updateSlotAttribute æ–¹æ³•çš„ switch è¯­å¥ä¸­æ·»åŠ æ–°å±žæ€§çš„å¤„ç†
        case RECEIVE_CARD_COMMAND_TIME:
        case RECEIVE_CARD_COMMAND_TIME_EN:
            slot.setReceiveCardCommandTime(value);
            break;
        default:
            System.err.println("错误:未知的属性名称 '" + attributeName + "'");
            return false;
@@ -417,6 +425,7 @@
            slot.setCurrent(UNKNOWN_VALUE);
            slot.setFault(UNKNOWN_VALUE);
            slot.setUpdateTime(UNKNOWN_VALUE);
            slot.setReceiveCardCommandTime(UNKNOWN_VALUE); // æ–°å¢žï¼šé‡ç½®æ”¶åˆ°å‘卡指令时间
        }
        //System.out.println("所有卡槽状态已重置为未知");
    }
@@ -557,4 +566,51 @@
        
        return true;
    }
    /**
     * è½®è¯¢æ£€æŸ¥å¡æ§½çŠ¶æ€ï¼Œå¯¹æœªå–å‡ºçš„å¡æ§½é‡æ–°å‘é€å¼€é—¨æŒ‡ä»¤
     * @param type æ“ä½œç±»åž‹ï¼š1-服务器发卡,2-管理员发卡
     */
    public static void pollAndResendOpenCommand(int type) {
        // ä½¿ç”¨è‡ªå®šä¹‰çš„æ—¶é—´æ ¼å¼å™¨
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < TOTAL_SLOTS; i++) {
            Fkj slot = slotArray[i];
            int slotId = i + 1;
            // èŽ·å–æ”¶åˆ°å‘å¡æŒ‡ä»¤æ—¶é—´å’Œå¡å·
            String receiveTime = slot.getReceiveCardCommandTime();
            String cardNumber = slot.getCardNumber();
            // æ£€æŸ¥æ¡ä»¶ï¼šæ”¶åˆ°æŒ‡ä»¤æ—¶é—´ä¸ä¸º-1,卡号不等于0000
            if (!UNKNOWN_VALUE.equals(receiveTime) && !"0000".equals(cardNumber)) {
                try {
                    // è§£æžæ—¶é—´å¹¶è®¡ç®—æ—¶é—´å·®
                    LocalDateTime currentTime = LocalDateTime.now();
                    LocalDateTime receiveDateTime = LocalDateTime.parse(receiveTime, formatter);
                    long timeDiff = java.time.Duration.between(receiveDateTime, currentTime).toMillis();
                    // å¦‚果时间差小于10秒,重新发送开门指令
                    if (timeDiff < 10000) {
                        // è°ƒç”¨å‘送开门指令方法
                        boolean sendResult = chuankou.Sendmsg.opendoorzhiling(slotId, type);
                        if (sendResult) {
                            System.out.println("重新发送开门指令 - å¡æ§½" + slotId + ",卡号: " + cardNumber +
                                             ",时间差: " + timeDiff + "ms");
                        }
                        // é—´éš”50毫秒
                        Thread.sleep(50);
                    }
                } catch (Exception e) {
                    System.err.println("处理卡槽" + slotId + "时发生错误: " + e.getMessage());
                    // ç»§ç»­å¤„理下一个卡槽
                }
            }
        }
    }
}
src/home/CardMachineUI.java
@@ -855,6 +855,7 @@
            ensureSerialParserRunning(); // ç¡®ä¿ä¸²å£è§£æžå™¨è¿è¡Œ
            updateCardSlotsDisplay();
            updateStatistics();
            SlotManager.pollAndResendOpenCommand(1);//增加发卡不成功再次发卡
        });
        uiUpdateTimer.start();
    }
src/home/Fkj.java
@@ -9,6 +9,7 @@
    private String current;       // ç”µæµ
    private String fault;         // æ•…éšœ1插卡错误;2过流;3,门控故障;4过压;5欠压;
    private String updateTime;    // æ›´æ–°æ—¶é—´
    private String receiveCardCommandTime; // æ”¶åˆ°å‘卡指令时间
    
    // åŽŸæœ‰çš„getter/setter方法
    public String getSlotNumber() { return slotNumber; }
@@ -67,4 +68,12 @@
    public void setHasCard(String hasCard) {
        this.hasCard = hasCard;
    }
    // æ–°å¢žå±žæ€§çš„getter/setter方法
    public String getReceiveCardCommandTime() {
        return receiveCardCommandTime;
    }
    public void setReceiveCardCommandTime(String receiveCardCommandTime) {
        this.receiveCardCommandTime = receiveCardCommandTime;
    }
}
src/publicway/TimestampUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package publicway;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class TimestampUtil {
    /**
     * èŽ·å–å¹´æœˆæ—¥æ—¶åˆ†ç§’æ¯«ç§’çš„æ—¶é—´æˆ³
     * @return æ—¶é—´æˆ³å­—符串
     */
    public static String getTimestamp() {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        return now.format(formatter);
    }
}