826220679@qq.com
18 小时以前 1bda9524add969e315d870f284046ecf1097f956
修改
已添加7个文件
已修改25个文件
已重命名1个文件
3265 ■■■■ 文件已修改
src/chushihua/Chushihua.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/databases/DBConnector.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell55AAData/Dell55AA01Parser.java 163 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell55AAData/Dell55AA02Parser.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell55AAData/Dell55AA12HighPerf.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell55AAData/DellGngga.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell55AAData/XTB.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_anchor/BaseStationManagementPanel.java 186 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/CompanyManagementPanel.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/MessageViewPanel.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/SerialPacketParser.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/SettingsPanelContent.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/Dell_SystemConfiguration.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/Dell_tag.java 305 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/SatelliteDevicePanel.java 483 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/TagManagementPanel.java 142 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/TagTypeManagementPanel.java 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicsWay/ButtonUtils.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicsWay/PacketProcessingSystem.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicsWay/PacketProcessingSystemB.java 252 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicsWay/TableUtils.java 123 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicsWay/TrackData.java 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/publicsWay/TrackDataBatchInserter.java 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/scheduled_task/TrackTableManager.java 119 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/targets/LocationTag.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/udptcp/UDPPortAReceiver.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/udptcp/UDPPortBReceiver.java 198 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/window/ContentPanelFactory.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/window/NavigationTreeFactory.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/window/WelcomeFrame.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
systemfile/Messages_en.properties 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
systemfile/Messages_zh.properties 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
systemfile/logfile/openlog.txt 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/chushihua/Chushihua.java
@@ -8,7 +8,9 @@
import dell_targets.Dell_BaseStation;
import dell_targets.Dell_SystemConfiguration;
import dell_targets.Dell_tag;
import publicsWay.UDPPortAReceiver;
import scheduled_task.TrackTableManager;
import udptcp.UDPPortAReceiver;
import udptcp.UDPPortBReceiver;
public class Chushihua {
    public static void getchushihua()  {
@@ -17,12 +19,14 @@
            Dell_tag.getlocationTags();
            Dell_BaseStation.getBaseStations();
            UDPPortAReceiver.startReceiver();
            UDPPortBReceiver.startReceiver();
            Dell_Map.getAllMaps();
            Dell_Fence.getAllFences();
            Dell_company.getAllCompanies();
            Dell_LayerManagement.getAllLayers();
            Dell_GroupManagement.getAllGroups();            
            if(Dell_SystemConfiguration.gnsstoxyOpen) {Dell_Map.get_foor_xycs();}
            if(Dell_SystemConfiguration.gnsstoxyOpen) {Dell_Map.get_foor_xycs();}
            TrackTableManager.Start();//生成归轨迹表
        } catch (SQLException e) {
            // TODO è‡ªåŠ¨ç”Ÿæˆçš„ catch å—
            e.printStackTrace();
src/databases/DBConnector.java
@@ -95,6 +95,8 @@
                    case "FIELD_VALIDATION_FAIL": return "字段验证失败";
                    case "DEVICE_ID_EXISTS": return "设备编号已存在";
                    case "INVALID_NUMBER_FORMAT": return "无效的数字格式"; 
                    case "DB_DDL_ERROR": return "执行DDL语句失败";
                    case "DB_BATCH_INSERT_ERROR": return "批量插入失败";
                    // æ·»åŠ ç¼ºå¤±çš„é”®
                    case "DB_QUERY_ERROR": return "数据库查询失败";
                    default: 
@@ -117,6 +119,8 @@
                            "FIELD_VALIDATION_FAIL",
                            "DEVICE_ID_EXISTS",
                            "INVALID_NUMBER_FORMAT",
                            "DB_DDL_ERROR",
                            "DB_BATCH_INSERT_ERROR",
                            "DB_QUERY_ERROR"  // æ·»åŠ ç¼ºå¤±çš„é”®
                    )
                );
@@ -497,4 +501,57 @@
        return pstmt.executeQuery();
    }
    
 // åœ¨DBConnector类中添加以下方法
    /**
     * æ£€æŸ¥è¡¨æ˜¯å¦å­˜åœ¨
     */
    public static boolean tableExists(String tableName) {
        try (Connection conn = connectToDatabase()) {
            if (conn == null) return false;
            try (ResultSet rs = conn.getMetaData().getTables(null, null, tableName, null)) {
                return rs.next();
            }
        } catch (SQLException e) {
            logError("DB_QUERY_ERROR", "检查表是否存在失败: " + e.getMessage());
            return false;
        }
    }
    /**
     * æ‰§è¡ŒDDL语句(创建表等)
     */
    public static boolean executeDDL(String ddlSQL) {
        try (Connection conn = connectToDatabase();
             Statement stmt = conn.createStatement()) {
            stmt.execute(ddlSQL);
            return true;
        } catch (SQLException e) {
            logError("DB_DDL_ERROR", "执行DDL语句失败: " + e.getMessage() + "\nDDL: " + ddlSQL);
            return false;
        }
    }
    /**
     * æ‰§è¡Œæ‰¹é‡æ›´æ–°æ“ä½œ
     */
    public static int executeBatchUpdate(String sql, List<Object[]> paramsList) {
        try (Connection conn = connectToDatabase();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            for (Object[] params : paramsList) {
                for (int i = 0; i < params.length; i++) {
                    pstmt.setObject(i + 1, params[i]);
                }
                pstmt.addBatch();
            }
            int[] results = pstmt.executeBatch();
            return results.length;
        } catch (SQLException e) {
            logError("DB_BATCH_INSERT_ERROR", "批量插入失败: " + e.getMessage() + "\nSQL: " + sql);
            return 0;
        }
    }
}
src/dell55AAData/Dell55AA01Parser.java
@@ -22,7 +22,7 @@
        public int distance;      // è·ç¦»(毫米)
        public int power;         // ç”µé‡(0-100)
        public int buttonPressed; // æŒ‰é’®çŠ¶æ€
        public boolean buttonPressed2;
        public void reset() {
            sequenceNum = 0;
            tagId = "";
@@ -30,6 +30,7 @@
            distance = 0;
            power = 0;
            buttonPressed = 0;
            buttonPressed2=false;
        }
    }
@@ -39,98 +40,110 @@
     * @return è§£æžç»“æžœ(错误时返回null)
     */
    public static ParseResult parse(String message, String ip, int port) {
        if (message == null || message.isEmpty()) {
            return null;
        }
        if (message == null || message.isEmpty()) {
            return null;
        }
        // æ¸…洗数据:移除所有非十六进制字符
        char[] cleanedMessage = cleanMessage(message);
        // æ¸…洗数据:移除所有非十六进制字符
        char[] cleanedMessage = cleanMessage(message);
        // æ•°æ®æ ¡éªŒ
        if (cleanedMessage == null || cleanedMessage.length < MIN_LENGTH) {
            return null;
        }
        // æ•°æ®æ ¡éªŒ
        if (cleanedMessage == null || cleanedMessage.length < MIN_LENGTH) {
            return null;
        }
        // åè®®å¤´æ ¡éªŒ (55AA01)
        if (!new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) {
            return null;
        }
        // åè®®å¤´æ ¡éªŒ (55AA01)
        if (!new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) {
            return null;
        }
        ParseResult result = RESULT_CACHE.get();
        result.reset();
        ParseResult result = RESULT_CACHE.get();
        result.reset();
        try {
            if (cleanedMessage.length < 30) { // ç¡®ä¿æœ‰è¶³å¤Ÿé•¿åº¦è®¿é—®charAt(28)
                return null;
            }
        try {
            if (cleanedMessage.length < 30) { // ç¡®ä¿æœ‰è¶³å¤Ÿé•¿åº¦è®¿é—®charAt(28)
                return null;
            }
            // è§£æžåºåˆ—号 (位置8-9)
            result.sequenceNum = HexUtils.fastHexToByte(cleanedMessage[8], cleanedMessage[9]);
            // è§£æžåºåˆ—号 (位置8-9)
            result.sequenceNum = HexUtils.fastHexToByte(cleanedMessage[8], cleanedMessage[9]);
            // è§£æžæ ‡ç­¾ID (位置10-13, å°ç«¯åº)
            result.tagId = new String(new char[]{
                    cleanedMessage[12], cleanedMessage[13], // é«˜ä½
                    cleanedMessage[10], cleanedMessage[11]  // ä½Žä½
            });
            // è§£æžæ ‡ç­¾ID (位置10-13, å°ç«¯åº)
            result.tagId = new String(new char[]{
                    cleanedMessage[12], cleanedMessage[13], // é«˜ä½
                    cleanedMessage[10], cleanedMessage[11]  // ä½Žä½
            });
            // è§£æžé”šç‚¹ID (位置14-17, å°ç«¯åº)
            result.anchorId = new String(new char[]{
                    cleanedMessage[16], cleanedMessage[17], // é«˜ä½
                    cleanedMessage[14], cleanedMessage[15]  // ä½Žä½
            });
            // è§£æžé”šç‚¹ID (位置14-17, å°ç«¯åº)
            result.anchorId = new String(new char[]{
                    cleanedMessage[16], cleanedMessage[17], // é«˜ä½
                    cleanedMessage[14], cleanedMessage[15]  // ä½Žä½
            });
            // è§£æžè·ç¦» (位置18-25, 4字节小端整数)
            int b0 = HexUtils.fastHexToByte(cleanedMessage[18], cleanedMessage[19]); // æœ€ä½Žä½
            int b1 = HexUtils.fastHexToByte(cleanedMessage[20], cleanedMessage[21]);
            int b2 = HexUtils.fastHexToByte(cleanedMessage[22], cleanedMessage[23]);
            int b3 = HexUtils.fastHexToByte(cleanedMessage[24], cleanedMessage[25]); // æœ€é«˜ä½
            int raw = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
            result.distance = raw; // ä¿æŒåŽŸå§‹æ•´æ•°å€¼
            // è§£æžè·ç¦» (位置18-25, 4字节小端整数)
            int b0 = HexUtils.fastHexToByte(cleanedMessage[18], cleanedMessage[19]); // æœ€ä½Žä½
            int b1 = HexUtils.fastHexToByte(cleanedMessage[20], cleanedMessage[21]);
            int b2 = HexUtils.fastHexToByte(cleanedMessage[22], cleanedMessage[23]);
            int b3 = HexUtils.fastHexToByte(cleanedMessage[24], cleanedMessage[25]); // æœ€é«˜ä½
            int raw = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
            result.distance = raw; // ä¿æŒåŽŸå§‹æ•´æ•°å€¼
            // è§£æžç”µé‡ (位置26-27)
            result.power = HexUtils.fastHexToByte(cleanedMessage[26], cleanedMessage[27]);
            // è§£æžç”µé‡ (位置26-27)
            result.power = HexUtils.fastHexToByte(cleanedMessage[26], cleanedMessage[27]);
            // è§£æžæŒ‰é’®çŠ¶æ€ (位置28-29)
            result.buttonPressed = HexUtils.fastHexToByte(cleanedMessage[28], cleanedMessage[29]);
            // è§£æžæŒ‰é’®çŠ¶æ€ (位置28-29)
            result.buttonPressed = HexUtils.fastHexToByte(cleanedMessage[28], cleanedMessage[29]);
            result.buttonPressed2 =result.buttonPressed==1;
            // æ—¥å¿—和更新操作可以考虑优化或减少调用频率
            if (MessageViewPanel.isWindowVisible) {
                StringBuilder sb = new StringBuilder();
                sb.append("55AA01 Seq:")
                  .append(result.sequenceNum)
                  .append(",Tagid:")
                  .append(result.tagId)
                  .append(",Anchorid:")
                  .append(result.anchorId)
                  .append(",Distance:")
                  .append(result.distance)
                  .append(",Power:")
                  .append(result.power)
                  .append(",Button:")
                  .append(result.buttonPressed);
                MessageViewPanel.showData(sb.toString(), ip, port, 0, "UDPA", "55AA01", "ALL");
            }
            // æ—¥å¿—和更新操作可以考虑优化或减少调用频率
            String hexData = "55AA01 åŒ…序:" + result.sequenceNum + ",标签编号:" + result.tagId + ",基站编号:" + result.anchorId +
                    ",距离:" + result.distance + ",电量:" + result.power +
                    ",按钮状态:" + result.buttonPressed;
            MessageViewPanel.showData(hexData, ip, port, 0, "UDPA", "55AA01", "ALL");
            String time = EfficientTimeFormatter.getCurrentTimeFormatted();
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "ipAddress", ip);
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "port", port + "");
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "status", "1");
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "onlineTime", time);
            String time = EfficientTimeFormatter.getCurrentTimeFormatted();
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "ipAddress", ip);
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "port", port + "");
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "status", "1");
            Dell_BaseStation.updateBaseStationProperty(result.anchorId, "onlineTime", time);
            Dell_tag.updateLocationTagProperty(result.tagId, "sosStatus", result.buttonPressed + "");
            Dell_tag.updateLocationTagProperty(result.tagId, "onlineStatus", "1");
            Dell_tag.updateLocationTagProperty(result.tagId, "lastUwbSignalTime", time);
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingSeq", result.sequenceNum + "");
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingBaseId", result.anchorId);
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingDistance", result.distance + "");
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingBaseCount", "1");
            Dell_tag.updateLocationTagProperty(result.tagId, "sosStatus", result.buttonPressed + "");
            Dell_tag.updateLocationTagProperty(result.tagId, "onlineStatus", "1");
            Dell_tag.updateLocationTagProperty(result.tagId, "lastUwbSignalTime", time);
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingSeq", result.sequenceNum + "");
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingBaseId", result.anchorId);
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingDistance", result.distance + "");
            Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingBaseCount", "1");
        } catch (IndexOutOfBoundsException | NumberFormatException e) {
            System.err.println("Parsing error in packet from " + ip + ":" + port);
            return null;
        }
        } catch (IndexOutOfBoundsException | NumberFormatException e) {
            System.err.println("Parsing error in packet from " + ip + ":" + port);
            return null;
        }
        return result;
        return result;
    }
    private static char[] cleanMessage(String message) {
        char[] cleaned = new char[message.length()];
        int j = 0;
        for (char c : message.toCharArray()) {
            if (Character.isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
                cleaned[j++] = Character.toUpperCase(c);
            }
        }
        if (j == 0) return null;
        return Arrays.copyOf(cleaned, j);
        char[] cleaned = new char[message.length()];
        int j = 0;
        for (char c : message.toCharArray()) {
            if (Character.isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
                cleaned[j++] = Character.toUpperCase(c);
            }
        }
        if (j == 0) return null;
        return Arrays.copyOf(cleaned, j);
    }
    public static void updateBase(String baseStationId, String propertyName, String value) {
src/dell55AAData/Dell55AA02Parser.java
@@ -1,44 +1,42 @@
package dell55AAData;
import dell_system.MessageViewPanel;
import dell_targets.Dell_BaseStation;
import publicsWay.EfficientTimeFormatter;
public class Dell55AA02Parser {
    private static final String EXPECTED_HEADER = "55AA02";
    private static final int MIN_LENGTH = 36; // 18字节 * 2字符/字节
    private static final int BASE_ID_START = 8;   // åŸºç«™ID起始位置(第4字节)
    private static final int SYNC_STATUS_START = 12; // åŒæ­¥çŠ¶æ€èµ·å§‹ä½ç½®(第5字节)
    private static final int PRESSURE_START = 14; // æ°”压值起始位置(第6字节)
    private static final int SYNC_STATUS_START = 12;  // åŒæ­¥çŠ¶æ€èµ·å§‹ä½ç½®(第5字节)
    private static final int PRESSURE_START = 14;     // æ°”压值起始位置(第6字节)
    private static final int MIN_MESSAGE_LENGTH = 22; // æœ€å°æœ‰æ•ˆæ•°æ®é•¿åº¦
    // é‡ç”¨StringBuilder减少内存分配
    private static final ThreadLocal<StringBuilder> hexDataBuilder =
            ThreadLocal.withInitial(() -> new StringBuilder(64));
    /**
     * è§£æž55AA02格式的基站数据
     * é«˜æ•ˆè§£æž55AA02格式的基站数据
     * @param message æŽ¥æ”¶åˆ°çš„æ•°æ®ï¼ˆåå…­è¿›åˆ¶å­—符串)
     */
    public static void parseAndUpdate(String message) {
    public static void parse(String message, String ip, int port) {
        // 1. åŸºç¡€æ ¡éªŒ
        if (message == null || message.length() < MIN_LENGTH) {
        if (message == null || message.length() < MIN_MESSAGE_LENGTH) {
            return;
        }
        // 2. å¤´éƒ¨æ ¡éªŒï¼ˆå›ºå®šå¼€å¤´å­—符串)
        for (int i = 0; i < EXPECTED_HEADER.length(); i++) {
            if (message.charAt(i) != EXPECTED_HEADER.charAt(i)) {
                return;
            }
        }
        // 2. è§£æžæ ‡ç­¾ID (位置8-11, å°ç«¯åº)
        char c8 = message.charAt(8);
        char c9 = message.charAt(9);
        char c10 = message.charAt(10);
        char c11 = message.charAt(11);
        // 3. è§£æžåŸºç«™ID(原始数据字符串)
        String baseId = new String(new char[]{
                message.charAt(BASE_ID_START),
                message.charAt(BASE_ID_START + 1),
                message.charAt(BASE_ID_START + 2),
                message.charAt(BASE_ID_START + 3)
        });
        // ç›´æŽ¥æž„建baseId字符串
        String baseId = new String(new char[]{c10, c11, c8, c9});
        // 4. è§£æžåŒæ­¥çŠ¶æ€ï¼ˆ1字节)
        char syncChar = message.charAt(SYNC_STATUS_START + 1); // å–状态字符
        String syncStatus = (syncChar == '0') ? "0" : "1";
        // 3. è§£æžåŒæ­¥çŠ¶æ€ï¼ˆ1字节)
        char syncStatusChar = message.charAt(SYNC_STATUS_START + 1);
        String syncStatus = (syncStatusChar == '0') ? "0" : "1";
        // 5. è§£æžæ°”压值(4字节小端序)
        // 4. é«˜æ•ˆè§£æžæ°”压值(4字节小端序)
        int pressure = 0;
        for (int i = 0; i < 8; i += 2) {
            int idx = PRESSURE_START + i;
@@ -46,21 +44,34 @@
            int byteValue = HexUtils.fastHexToByte(message.charAt(idx), message.charAt(idx + 1));
            pressure |= (byteValue << (i * 4)); // å°ç«¯åˆå¹¶
        }
        String pressureStr = String.valueOf(pressure);
        // 6. æ›´æ–°åŸºç«™æ•°æ®
        updateBaseStationData(baseId, syncStatus ,pressureStr);
    }
    /**
     * æ›´æ–°åŸºç«™æ•°æ®
     * @param baseId åŸºç«™ID
     * @param syncStatus åŒæ­¥çŠ¶æ€
     * @param pressure æ°”压值字符串
     */
    private static void updateBaseStationData(String baseId, String syncStatus, String pressure) {
        // 5. æ›´æ–°åŸºç«™æ•°æ®
        if (MessageViewPanel.isWindowVisible) {
            StringBuilder sb = hexDataBuilder.get();
            sb.setLength(0);
            sb.append("55AA02 AnchorHeart,Anchorid:")
            .append(baseId)
            .append(",SyncStatus:")
            .append(syncStatus)
            .append(",Pressure:")
            .append(pressure);
            MessageViewPanel.showData(sb.toString(), ip, port, 0, "UDPA", "55AA02", baseId);
        }
        // å»¶è¿Ÿåˆ›å»ºæ—¶é—´å­—符串直到必要时刻
        String time = EfficientTimeFormatter.getCurrentTimeFormatted();
        // ä½¿ç”¨é¢„分配字符串常量减少内存分配
        Dell_BaseStation.updateBaseStationProperty(baseId, "ipAddress", ip);
        Dell_BaseStation.updateBaseStationProperty(baseId, "port", Integer.toString(port));
        Dell_BaseStation.updateBaseStationProperty(baseId, "status", "1");
        Dell_BaseStation.updateBaseStationProperty(baseId, "onlineTime", time);
        Dell_BaseStation.updateBaseStationProperty(baseId, "syncStatus", syncStatus);
        Dell_BaseStation.updateBaseStationProperty(baseId, "barometerReading", pressure);
        Dell_BaseStation.updateBaseStationProperty(baseId, "barometerReading", Integer.toString(pressure));
    }
}
src/dell55AAData/Dell55AA12HighPerf.java
@@ -1,5 +1,7 @@
package dell55AAData;
import dell_system.MessageViewPanel;
public class Dell55AA12HighPerf {
    
    // åè®®å¸¸é‡
@@ -8,6 +10,9 @@
    private static final int MIN_LENGTH = 34; // æœ€å°æ•°æ®é•¿åº¦
    private static final ThreadLocal<ParseResult> RESULT_CACHE = // è§£æžç»“果缓存
        ThreadLocal.withInitial(ParseResult::new);
 // é‡ç”¨StringBuilder减少内存分配
     private static final ThreadLocal<StringBuilder> hexDataBuilder =
             ThreadLocal.withInitial(() -> new StringBuilder(64));
    // è§£æžç»“果类
    public static class ParseResult { 
@@ -84,6 +89,37 @@
        // è§£æžé”šç‚¹ä¿¡æ¯
        parseAnchorInfo(chars, result);
        
        if (MessageViewPanel.isWindowVisible) {
            // ç»„装基站信息
            StringBuilder ids = new StringBuilder();
            StringBuilder dists = new StringBuilder();
            StringBuilder powers = new StringBuilder();
            for (int i = 0; i < result.anchorCount; i++) {
                if (i > 0) {
                    ids.append(',');
                    dists.append(',');
                    powers.append(',');
                }
                ids.append(result.anchorIds[i]);
                dists.append(result.distances[i]);
                powers.append(result.anchorPowers[i]);
            }
            StringBuilder sb = hexDataBuilder.get();
              sb.append("55AA12 ,Seq:").append(result.sequenceNum)
              .append(",Tagid:").append(result.tagId)
              .append(",Power: ").append(result.power).append("%")
              .append(",button:").append(result.sosButtonPressed)
              .append(",Static:").append(result.isStatic )
              .append(",Sleep:").append(result.isSleeping )
              .append(",State:").append(result.vibrationState )
              .append(",TagRemoved:").append(result.tagRemoved)
              .append(",TagHeight:").append(result.tagHeight)
              .append(",AncNum:").append(result.anchorCount)
              .append(",AncIds:[").append(ids)
              .append("],Dis:[").append(dists)
              .append("],AncPowers:[").append(powers).append("]").append('\n');
            MessageViewPanel.showData(sb.toString(), ip, port, 0, "UDPA", "55AA12",result.tagId);
        }
        return result;
    }
src/dell55AAData/DellGngga.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package dell55AAData;
public class DellGngga {
    // è§£æžç»“果存储
    private String utcTime; // UTC时间
    private String latitude; // çº¬åº¦
    private String latHemisphere; // çº¬åº¦åŠçƒï¼ˆN/S)
    private String longitude; // ç»åº¦
    private String lonHemisphere; // ç»åº¦åŠçƒï¼ˆE/W)
    private String quality; // å®šä½è´¨é‡æŒ‡ç¤ºå™¨
    private String satellites; // ä½¿ç”¨çš„卫星数量
    private String hdop; // æ°´å¹³ç²¾åº¦å› å­
    private String altitude; // æµ·æ‹”高度
    private String altitudeUnit; // æµ·æ‹”高度单位
    private String geoidHeight; // å¤§åœ°æ°´å‡†é¢é«˜åº¦
    private String geoidHeightUnit; // å¤§åœ°æ°´å‡†é¢é«˜åº¦å•位
    private String differentialTime; // å·®åˆ†æ—¶é—´ï¼ˆç§’)
    private String checksum = ""; // æ ¡éªŒå’Œ
    private String deviceId; // è®¾å¤‡ID
    private String battery; // ç”µæ± ç”µé‡
    private String signalStrength; // ä¿¡å·å¼ºåº¦
    private String reserve1; // ä¿ç•™å­—段1
    private String reserve2; // ä¿ç•™å­—段2
    private String reserve3; // ä¿ç•™å­—段3
    public void parse(String data) {
        // ç›´æŽ¥æŒ‰é€—号分割字段
        String[] fields = data.split(",");
        // éªŒè¯å­—段数量
        if (fields.length < 21) return;
        // ç›´æŽ¥èµ‹å€¼å„个字段
        utcTime = fields[1];
        latitude = fields[2];
        latHemisphere = fields[3];
        longitude = fields[4];
        lonHemisphere = fields[5];
        quality = fields[6];
        satellites = fields[7];
        hdop = fields[8];
        altitude = fields[9];
        altitudeUnit = fields[10];
        geoidHeight = fields[11];
        geoidHeightUnit = fields[12];
        differentialTime = fields[13];
        checksum = fields[14];
        deviceId = fields[15];
        battery = fields[16];
        signalStrength = fields[17];
        reserve1 = fields[18];
        reserve2 = fields[19];
        reserve3 = fields[20];
    }
    // ===== ç»“果获取方法 =====
    public String getUtcTime() { return utcTime; }
    public String getLatitude() { return latitude; }
    public String getLatHemisphere() { return latHemisphere; }
    public String getLongitude() { return longitude; }
    public String getLonHemisphere() { return lonHemisphere; }
    public String getQuality() { return quality; }
    public String getSatellites() { return satellites; }
    public String getHdop() { return hdop; }
    public String getAltitude() { return altitude; }
    public String getAltitudeUnit() { return altitudeUnit; }
    public String getGeoidHeight() { return geoidHeight; }
    public String getGeoidHeightUnit() { return geoidHeightUnit; }
    public String getDifferentialTime() { return differentialTime; }
    public String getChecksum() { return checksum; }
    public String getDeviceId() { return deviceId; }
    public String getBattery() { return battery; }
    public String getSignalStrength() { return signalStrength; }
    public String getReserve1() { return reserve1; }
    public String getReserve2() { return reserve2; }
    public String getReserve3() { return reserve3; }
}
src/dell55AAData/XTB.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package dell55AAData;
public class XTB {
    // è§£æžç»“果存储
    private String header;         // åŒ…头
    private String deviceId;       // è®¾å¤‡ç¼–号
    private String battery;        // ç”µé‡
    private String version;        // ç‰ˆæœ¬å·
    private String ccid;           // CCID
    private String button;         // æŒ‰é”®
    private String rtcmSource;     // RTCMÔ´
    // ç”¨äºŽé«˜æ•ˆè§£æžçš„临时变量
    private int startIndex;
    private int endIndex;
    private String data;
    public void parse(String data) {
        this.data = data;
        int fieldCount = 0;
        startIndex = 0;
        endIndex = 0;
        // å¿«é€ŸéåŽ†å­—ç¬¦ä¸²è§£æžå­—æ®µ
        for (int i = 0; i < data.length(); i++) {
            if (data.charAt(i) == ',' || i == data.length() - 1) {
                endIndex = (i == data.length() - 1) ? i + 1 : i;
                assignField(fieldCount, startIndex, endIndex);
                fieldCount++;
                startIndex = i + 1;
                // å¦‚果已经解析了所有7个字段,提前退出
                if (fieldCount >= 7) break;
            }
        }
    }
    private void assignField(int fieldIndex, int start, int end) {
        switch (fieldIndex) {
            case 0: header = data.substring(start, end); break;
            case 1: deviceId = data.substring(start, end); break;
            case 2: battery = data.substring(start, end); break;
            case 3: version = data.substring(start, end); break;
            case 4: ccid = data.substring(start, end); break;
            case 5: button = data.substring(start, end); break;
            case 6:
                // å¯¹äºŽæœ€åŽä¸€ä¸ªå­—段,需要确保获取到字符串末尾
                rtcmSource = data.substring(start);
                break;
        }
    }
    // ===== ç»“果获取方法 =====
    public String getHeader() { return header; }
    public String getDeviceId() { return deviceId; }
    public String getBattery() { return battery; }
    public String getVersion() { return version; }
    public String getCcid() { return ccid; }
    public String getButton() { return button; }
    public String getRtcmSource() { return rtcmSource; }
}
src/dell_anchor/BaseStationManagementPanel.java
@@ -2,12 +2,12 @@
import databases.DBConnector;
import dell_targets.Dell_BaseStation;
import publicsWay.ButtonUtils;
import publicsWay.TableUtils;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLException;
import java.util.*;
import java.util.List;
@@ -28,49 +28,56 @@
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        
        // åˆ›å»ºæœç´¢é¢æ¿
        JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
        searchPanel.setBorder(BorderFactory.createTitledBorder(getMessage("SEARCH")));
        // é¡¶éƒ¨æ“ä½œé¢æ¿
        JPanel topPanel = new JPanel(new BorderLayout(5, 5));
        topPanel.setBorder(BorderFactory.createTitledBorder(messages.getString("QUICK_OPERATION")));
        
        // åˆ›å»ºæœç´¢ç»„ä»¶
        // æœç´¢é¢æ¿
        JPanel searchInputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        JLabel searchLabel = new JLabel(messages.getString("BASE_STATION_ID") + ":");
        searchField = new JTextField(15);
        JButton searchButton = new JButton(getMessage("SEARCH"));
        JButton refreshButton = new JButton(getMessage("REFRESH"));
        JButton addButton = new JButton(getMessage("ADD"));
        JButton editButton = new JButton(getMessage("EDIT"));
        JButton deleteButton = new JButton(getMessage("DELETE"));
        refreshButton.addActionListener(e -> loadBaseStationData());
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
        buttonPanel.add(searchButton);
        buttonPanel.add(refreshButton);
        buttonPanel.add(addButton);
        buttonPanel.add(editButton);
        buttonPanel.add(deleteButton);
        searchPanel.add(searchField, BorderLayout.CENTER);
        searchPanel.add(buttonPanel, BorderLayout.EAST);
        
        // æ·»åŠ æŒ‰é’®äº‹ä»¶ç›‘å¬å™¨
        addButton.addActionListener(e -> addNewBaseStation());
        editButton.addActionListener(e -> editSelectedBaseStation());
        deleteButton.addActionListener(e -> deleteSelectedBaseStations());
        searchButton.addActionListener(new SearchAction());
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton searchButton = ButtonUtils.createBlueButton(messages.getString("SEARCH"));
        JButton resetButton = ButtonUtils.createBlueButton(messages.getString("RESET"));
        JButton refreshButton = ButtonUtils.createBlueButton(messages.getString("REFRESH"));
        JButton addButton = ButtonUtils.createBlueButton(messages.getString("ADD"));
        JButton editButton = ButtonUtils.createBlueButton(messages.getString("EDIT"));
        JButton deleteButton = ButtonUtils.createBlueButton(messages.getString("DELETE"));
        searchInputPanel.add(searchLabel);
        searchInputPanel.add(searchField);
        searchInputPanel.add(searchButton);
        searchInputPanel.add(resetButton);
        searchInputPanel.add(refreshButton);
        // æ“ä½œæŒ‰é’®é¢æ¿
        JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
        actionPanel.add(addButton);
        actionPanel.add(editButton);
        actionPanel.add(deleteButton);
        // å°†æœç´¢é¢æ¿å’Œæ“ä½œæŒ‰é’®é¢æ¿æ”¾åœ¨ä¸€è¡Œ
        JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
        rowPanel.add(searchInputPanel);
        rowPanel.add(actionPanel);
        topPanel.add(rowPanel, BorderLayout.CENTER);
        // åˆ›å»ºè¡¨æ ¼åˆ—名
        String[] columnNames = {
            getMessage("INDEX"),
            getMessage("BASE_STATION_ID"),
            getMessage("BASE_STATION_STATUS"),
            getMessage("X_COORD"),
            getMessage("Y_COORD"),
            getMessage("Z_COORD"),
            getMessage("LAYER"),
            getMessage("GROUP"),
            getMessage("PORT"),
            getMessage("FIRMWARE_VERSION"),
            getMessage("ONLINE_TIME"),
            getMessage("COMPANY")
            messages.getString("INDEX"),
            messages.getString("BASE_STATION_ID"),
            messages.getString("BASE_STATION_STATUS"),
            messages.getString("X_COORD"),
            messages.getString("Y_COORD"),
            messages.getString("Z_COORD"),
            messages.getString("LAYER"),
            messages.getString("GROUP"),
            messages.getString("PORT"),
            messages.getString("FIRMWARE_VERSION"),
            messages.getString("ONLINE_TIME"),
            messages.getString("COMPANY")
        };
        
        // åˆ›å»ºè¡¨æ ¼æ¨¡åž‹
@@ -81,14 +88,16 @@
            }
        };
        
        // åˆ›å»ºè¡¨æ ¼
        // åˆ›å»ºè¡¨æ ¼ - ä½¿ç”¨TableUtils中的方法
        baseStationTable = new JTable(tableModel);
        TableUtils.setupTableStyle(baseStationTable);
        TableUtils.setupTableHeaderStyle(baseStationTable);
        baseStationTable.setAutoCreateRowSorter(true);
        baseStationTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        
        // è®¾ç½®åˆ—宽
        TableColumnModel columnModel = baseStationTable.getColumnModel();
        columnModel.getColumn(0).setPreferredWidth(30);  // åºå·
        columnModel.getColumn(0).setPreferredWidth(30);  // ç´¢å¼•
        columnModel.getColumn(1).setPreferredWidth(100); // åŸºç«™ç¼–号
        columnModel.getColumn(2).setPreferredWidth(70);  // ×´Ì¬
        columnModel.getColumn(3).setPreferredWidth(70);  // X坐标
@@ -101,31 +110,30 @@
        columnModel.getColumn(10).setPreferredWidth(120); // ä¸Šçº¿æ—¶é—´
        columnModel.getColumn(11).setPreferredWidth(100); // æ‰€å±žå…¬å¸
        
        // è®¾ç½®è¡¨å¤´æ ·å¼
        JTableHeader header = baseStationTable.getTableHeader();
        // è®¾ç½®è¡¨å¤´å·¦å¯¹é½
        header.setDefaultRenderer(new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus, int row, int column) {
                super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                setHorizontalAlignment(SwingConstants.LEFT);
                setBackground(Color.GRAY);
                setForeground(Color.WHITE);
                setFont(getFont().deriveFont(Font.BOLD));
                return this;
            }
        });
        // åº”用单元格渲染器到所有列 - ä½¿ç”¨TableUtils中的方法
        DefaultTableCellRenderer cellRenderer = TableUtils.createCenteredCellRenderer();
        for (int i = 0; i < baseStationTable.getColumnCount(); i++) {
            baseStationTable.getColumnModel().getColumn(i).setCellRenderer(cellRenderer);
        }
        
        JScrollPane scrollPane = new JScrollPane(baseStationTable);
        scrollPane.setPreferredSize(new Dimension(1200, 500));
        scrollPane.setBorder(BorderFactory.createEmptyBorder()); // ç§»é™¤æ»šåŠ¨é¢æ¿è¾¹æ¡†
        
        // æ·»åŠ ç»„ä»¶
        add(searchPanel, BorderLayout.NORTH);
        add(topPanel, BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);
        
        // åŠ è½½æ•°æ®
        loadBaseStationData();
        // æ·»åŠ äº‹ä»¶ç›‘å¬å™¨
        searchButton.addActionListener(e -> searchBaseStations());
        resetButton.addActionListener(e -> resetSearch());
        refreshButton.addActionListener(e -> loadBaseStationData());
        addButton.addActionListener(e -> addNewBaseStation());
        editButton.addActionListener(e -> editSelectedBaseStation());
        deleteButton.addActionListener(e -> deleteSelectedBaseStations());
    }
    
    private void loadBaseStationData() {
@@ -163,6 +171,36 @@
                bs.getCompany()
            });
        }
    }
    // æœç´¢åŸºç«™
    private void searchBaseStations() {
        String keyword = searchField.getText().trim();
        if (keyword.isEmpty()) {
            updateTable(allBaseStations);
            return;
        }
        List<LocationBaseStation> filtered = new ArrayList<>();
        for (LocationBaseStation bs : allBaseStations) {
            if ((bs.getCode() != null && bs.getCode().toLowerCase().contains(keyword.toLowerCase())) ||
                (bs.getCompany() != null && bs.getCompany().toLowerCase().contains(keyword.toLowerCase()))) {
                filtered.add(bs);
            }
        }
        if (filtered.isEmpty()) {
            JOptionPane.showMessageDialog(this, getMessage("SEARCH_NO_RESULTS"),
                    getMessage("INFO"), JOptionPane.INFORMATION_MESSAGE);
        }
        updateTable(filtered);
    }
    // é‡ç½®æœç´¢
    private void resetSearch() {
        searchField.setText("");
        updateTable(allBaseStations);
    }
    
    // æ·»åŠ æ–°åŸºç«™
@@ -272,7 +310,7 @@
            return false;
        }
        
        // HEX格式验证(0-9, A-F)
        // HEX格式验证(0-9, A-F)
        if (!Pattern.matches("[0-9A-Fa-f]+", bs.getCode())) {
            JOptionPane.showMessageDialog(this, getMessage("INVALID_HEX_FORMAT"),
                                        getMessage("ERROR"), JOptionPane.ERROR_MESSAGE);
@@ -446,32 +484,6 @@
        return result > 0;
    }
    
    // æœç´¢åŠŸèƒ½
    private class SearchAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String keyword = searchField.getText().trim();
            if (keyword.isEmpty()) {
                updateTable(allBaseStations);
                return;
            }
            List<LocationBaseStation> filteredList = new ArrayList<>();
            for (LocationBaseStation bs : allBaseStations) {
                if (matchesKeyword(bs, keyword)) {
                    filteredList.add(bs);
                }
            }
            updateTable(filteredList);
        }
        private boolean matchesKeyword(LocationBaseStation bs, String keyword) {
            return (bs.getCode() != null && bs.getCode().contains(keyword)) ||
                   (bs.getCompany() != null && bs.getCompany().contains(keyword));
        }
    }
    private String getMessage(String key) {
        try {
            return messages.getString(key);
@@ -580,8 +592,8 @@
        // æŒ‰é’®é¢æ¿
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton okButton = new JButton(messages.getString("OK"));
        JButton cancelButton = new JButton(messages.getString("CANCEL"));
        JButton okButton = ButtonUtils.createBlueButton(messages.getString("OK"));
        JButton cancelButton = ButtonUtils.createBlueButton(messages.getString("CANCEL"));
        okButton.addActionListener(e -> {
            confirmed = true;
src/dell_system/CompanyManagementPanel.java
@@ -9,6 +9,9 @@
import java.util.*;
import java.util.List;
import java.util.ResourceBundle;
import publicsWay.ButtonUtils; // æ·»åŠ ButtonUtils导入
import publicsWay.TableUtils; // æ·»åŠ TableUtils导入
public class CompanyManagementPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    private JTable companyTable;
@@ -18,33 +21,36 @@
    private JTextField searchField;
    @SuppressWarnings("serial")
    public CompanyManagementPanel(ResourceBundle messages) {
    public CompanyManagementPanel(ResourceBundle messages) {
        this.messages = messages;
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
     // é¡¶éƒ¨é¢æ¿
        // é¡¶éƒ¨æ“ä½œé¢æ¿
        JPanel topPanel = new JPanel(new BorderLayout(5, 5));
        topPanel.setBorder(BorderFactory.createTitledBorder(getMessage("QKOP")));
        topPanel.setBorder(BorderFactory.createTitledBorder(getMessage("QUICK_OPERATION")));
        // å·¦ä¾§æœç´¢è¾“入组件
        JPanel searchInputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        JLabel searchLabel = new JLabel(getMessage("COMPANY_NAME") + ":");
        searchField = new JTextField(20);
        JButton searchButton = new JButton(getMessage("SEARCH"));
        JButton resetButton = new JButton(getMessage("RESET"));
        searchField = new JTextField(15);
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton searchButton = ButtonUtils.createBlueButton(getMessage("SEARCH"));
        JButton resetButton = ButtonUtils.createBlueButton(getMessage("RESET"));
        JButton refreshButton = ButtonUtils.createBlueButton(getMessage("REFRESH"));
        searchInputPanel.add(searchLabel);
        searchInputPanel.add(searchField);
        searchInputPanel.add(searchButton);
        searchInputPanel.add(resetButton);
        searchInputPanel.add(refreshButton);
        // å³ä¾§æ“ä½œæŒ‰é’®
        JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
        JButton addButton = new JButton(getMessage("ADD"));
        JButton editButton = new JButton(getMessage("EDIT"));
        JButton deleteButton = new JButton(getMessage("DELETE"));
        JButton refreshButton = new JButton(getMessage("REFRESH"));
        JButton addButton = ButtonUtils.createBlueButton(getMessage("ADD"));
        JButton editButton = ButtonUtils.createBlueButton(getMessage("EDIT"));
        JButton deleteButton = ButtonUtils.createBlueButton(getMessage("DELETE"));
        actionPanel.add(addButton);
        actionPanel.add(editButton);
@@ -52,9 +58,11 @@
        actionPanel.add(refreshButton);
        // å°†å·¦ä¾§æœç´¢å’Œå³ä¾§æ“ä½œæ·»åŠ åˆ°æœç´¢é¢æ¿
        topPanel.add(searchInputPanel, BorderLayout.CENTER);
        topPanel.add(actionPanel, BorderLayout.EAST);
        JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
        rowPanel.add(searchInputPanel);
        rowPanel.add(actionPanel);
        topPanel.add(rowPanel, BorderLayout.CENTER);
        
        // åˆ›å»ºè¡¨æ ¼åˆ—名
        String[] columnNames = {
@@ -72,8 +80,10 @@
            }
        };
        
        // åˆ›å»ºè¡¨æ ¼
        // åˆ›å»ºè¡¨æ ¼ - ä½¿ç”¨TableUtils中的方法
        companyTable = new JTable(tableModel);
        TableUtils.setupTableStyle(companyTable);
        TableUtils.setupTableHeaderStyle(companyTable);
        companyTable.setAutoCreateRowSorter(true);
        companyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
@@ -83,29 +93,15 @@
        companyTable.getColumnModel().getColumn(2).setPreferredWidth(100);
        companyTable.getColumnModel().getColumn(3).setPreferredWidth(200);
        
        // è®¾ç½®è¡¨å¤´æ ·å¼
        JTableHeader header = companyTable.getTableHeader();
        header.setBackground(Color.GRAY);
        header.setForeground(Color.WHITE);
        header.setFont(header.getFont().deriveFont(Font.BOLD));
        // åˆ›å»ºè¡¨å¤´æ¸²æŸ“器
        DefaultTableCellRenderer headerRenderer = new DefaultTableCellRenderer() {
            {
                setHorizontalAlignment(SwingConstants.LEFT);
                setBackground(Color.GRAY);
                setForeground(Color.WHITE);
                setFont(getFont().deriveFont(Font.BOLD));
            }
        };
        // åº”用表头渲染器
        // åº”用单元格渲染器到所有列 - ä½¿ç”¨TableUtils中的方法
        DefaultTableCellRenderer cellRenderer = TableUtils.createCenteredCellRenderer();
        for (int i = 0; i < companyTable.getColumnCount(); i++) {
            companyTable.getColumnModel().getColumn(i).setHeaderRenderer(headerRenderer);
            companyTable.getColumnModel().getColumn(i).setCellRenderer(cellRenderer);
        }
        
        JScrollPane scrollPane = new JScrollPane(companyTable);
        scrollPane.setPreferredSize(new Dimension(800, 400));
        scrollPane.setBorder(BorderFactory.createEmptyBorder()); // ç§»é™¤æ»šåŠ¨é¢æ¿è¾¹æ¡†
        
        // æ·»åŠ ç»„ä»¶
        add(topPanel, BorderLayout.NORTH);
@@ -414,8 +410,8 @@
            // æŒ‰é’®é¢æ¿
            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            JButton okButton = new JButton(getMessage("OK"));
            JButton cancelButton = new JButton(getMessage("CANCEL"));
            JButton okButton = ButtonUtils.createBlueButton(getMessage("OK"));
            JButton cancelButton = ButtonUtils.createBlueButton(getMessage("CANCEL"));
            okButton.addActionListener(e -> {
                confirmed = true;
src/dell_system/MessageViewPanel.java
@@ -12,7 +12,7 @@
import java.util.ResourceBundle;
import dell_targets.Dell_tag;
import publicsWay.Languages;
import publicsWay.UDPPortAReceiver;
import udptcp.UDPPortAReceiver;
import udptcp.UDPPortBReceiver;
public class MessageViewPanel extends JPanel {
@@ -32,6 +32,9 @@
    private JRadioButton rdoSendHex;
    private JRadioButton rdoSendAscii;
    private JCheckBox chkAppendNewline;
 // æ·»åŠ å¸¸é‡å®šä¹‰æœ€å¤§è¡Œæ•°
    private static final int MAX_LINES = 10000;
    private static final int TRIM_LINES = 5000; // å½“超过最大行数时保留的行数
    
    private static final ThreadLocal<StringBuilder> SB =
            ThreadLocal.withInitial(() -> new StringBuilder(256));
@@ -100,7 +103,7 @@
                "ALL", 
                "55AA01", "55AA02", "55AA03", "55AA05", "55AA07", 
                "55AA0A", "55AA0C", "55AA12", "55AA14", "55AA20",
                "GNGGA", "XTB"
                "GNGGA", "XTB", "GBGGA", "SSGGA"
        });
        protocolPanel.add(cbProtocol, BorderLayout.CENTER);
        add(protocolPanel, gbc);
@@ -400,6 +403,18 @@
        SwingUtilities.invokeLater(() -> {
            txtDataView.append(displayData.toString() + "\n");
            // æ£€æŸ¥å¹¶é™åˆ¶è¡Œæ•°
            int lineCount = txtDataView.getLineCount();
            if (lineCount > MAX_LINES) {
                try {
                    int end = txtDataView.getLineEndOffset(TRIM_LINES - 1);
                    txtDataView.replaceRange("", 0, end);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            txtDataView.setCaretPosition(txtDataView.getDocument().getLength());
        });
    }
@@ -459,6 +474,18 @@
            SwingUtilities.invokeLater(() -> {
                txtDataView.append(finalText);
                txtDataView.append("\n");
                // æ£€æŸ¥å¹¶é™åˆ¶è¡Œæ•°
                int lineCount = txtDataView.getLineCount();
                if (lineCount > MAX_LINES) {
                    try {
                        int end = txtDataView.getLineEndOffset(TRIM_LINES - 1);
                        txtDataView.replaceRange("", 0, end);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                txtDataView.setCaretPosition(txtDataView.getDocument().getLength());
            });
src/dell_system/SerialPacketParser.java
@@ -38,7 +38,7 @@
                return sb.toString();
            }
            String button = r.buttonPressed ? bundle.getString("yes") : bundle.getString("no");
            String button = r.buttonPressed2 ? bundle.getString("yes") : bundle.getString("no");
            sb.append(bundle.getString("label.sequence")).append(": ").append(r.sequenceNum).append(',')
              .append(bundle.getString("label.id")).append(": ").append(r.tagId).append(',')
              .append(bundle.getString("label.anchor_ids")).append(": ").append(r.anchorId).append(',')
@@ -47,7 +47,7 @@
              .append(bundle.getString("status.button")).append(": ").append(button);
        } else if (hex.startsWith("55AA12")) {
            ParseResult r = Dell55AA12HighPerf.parse(hex);
            ParseResult r = Dell55AA12HighPerf.parse(hex,"127.0.0.1",0);
            if (r == null) {
                sb.append(bundle.getString("parser.invalid")).append(" 55AA12");
                return sb.toString();
src/dell_system/SettingsPanelContent.java
@@ -29,10 +29,11 @@
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import targets.SystemConfiguration;
import publicsWay.ButtonUtils; // æ–°å¢žå¯¼å…¥
@SuppressWarnings("serial")
public class SettingsPanelContent extends JPanel {
    private ResourceBundle messages; // å¤šè¯­è¨€èµ„源包
    private ResourceBundle messages; // è¯­è¨€èµ„源包
    private Map<String, JComponent> settingComponents; // è®¾ç½®ç»„件映射
    private SystemConfiguration currentConfig; // å½“前系统配置
    private int settingIndex = 1; // è®¾ç½®é¡¹ç´¢å¼•
@@ -148,7 +149,7 @@
        
        // æ·»åŠ ç»„åˆæ¡†è®¾ç½®
        addComboBoxSetting("REALTIME_TRAJECTORY_COLOR", "realTimeTrajectoryColor",
                new String[]{"红色", "绿色", "黑色", "紫色", "黄色"},
                new String[]{"红色", "绿色", "黑色", "蓝色", "黄色"},
                new Integer[]{1, 2, 3, 4, 5});
        addComboBoxSetting("SYSTEM_LANGUAGE", "systemLanguage",
                new String[]{"中文", "英文", "法文", "阿拉伯文"},
@@ -246,7 +247,8 @@
        gbcButton.anchor = GridBagConstraints.WEST; // å·¦å¯¹é½
        gbcButton.insets = new Insets(5, 0, 5, 5); // è¾¹è·
        JButton confirmButton = new JButton(messages.getString("SAVE")); // "保存"按钮
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton confirmButton = ButtonUtils.createBlueButton(messages.getString("SAVE")); // "保存"按钮
        confirmButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        confirmButton.setPreferredSize(new Dimension(80, 30)); // è®¾ç½®å¤§å°
        // æ·»åŠ ä¿å­˜æ“ä½œç›‘å¬å™¨
@@ -310,7 +312,8 @@
        gbcButton.anchor = GridBagConstraints.WEST; // å·¦å¯¹é½
        gbcButton.insets = new Insets(5, 0, 5, 5); // è¾¹è·
        JButton confirmButton = new JButton(messages.getString("SAVE")); // "保存"按钮
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton confirmButton = ButtonUtils.createBlueButton(messages.getString("SAVE")); // "保存"按钮
        confirmButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        confirmButton.setPreferredSize(new Dimension(80, 30)); // è®¾ç½®å¤§å°
        // æ·»åŠ ä¿å­˜æ“ä½œç›‘å¬å™¨
@@ -399,7 +402,8 @@
        gbcButton.anchor = GridBagConstraints.WEST; // å·¦å¯¹é½
        gbcButton.insets = new Insets(5, 0, 5, 5); // è¾¹è·
        JButton confirmButton = new JButton(messages.getString("SAVE")); // "保存"按钮
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton confirmButton = ButtonUtils.createBlueButton(messages.getString("SAVE")); // "保存"按钮
        confirmButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        confirmButton.setPreferredSize(new Dimension(80, 30)); // è®¾ç½®å¤§å°
        // æ·»åŠ ä¿å­˜æ“ä½œç›‘å¬å™¨
@@ -487,7 +491,8 @@
        gbcButton.anchor = GridBagConstraints.WEST; // å·¦å¯¹é½
        gbcButton.insets = new Insets(5, 0, 5, 5); // è¾¹è·
        JButton confirmButton = new JButton(messages.getString("SAVE")); // "保存"按钮
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton confirmButton = ButtonUtils.createBlueButton(messages.getString("SAVE")); // "保存"按钮
        confirmButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        confirmButton.setPreferredSize(new Dimension(80, 30)); // è®¾ç½®å¤§å°
        // æ·»åŠ ä¿å­˜æ“ä½œç›‘å¬å™¨
@@ -576,7 +581,8 @@
        gbcButton.anchor = GridBagConstraints.WEST; // å·¦å¯¹é½
        gbcButton.insets = new Insets(5, 0, 5, 5); // è¾¹è·
        JButton confirmButton = new JButton(messages.getString("SAVE")); // "保存"按钮
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton confirmButton = ButtonUtils.createBlueButton(messages.getString("SAVE")); // "保存"按钮
        confirmButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        confirmButton.setPreferredSize(new Dimension(80, 30)); // è®¾ç½®å¤§å°
        // æ·»åŠ ä¿å­˜æ“ä½œç›‘å¬å™¨
src/dell_targets/Dell_SystemConfiguration.java
@@ -17,6 +17,7 @@
    public static String language="0";
    public static int hexport=8234;
    public static int ascallport=7000;
    public static int TrajectoryRetentionDays=30;//轨迹保存天数
    // èŽ·å–ç³»ç»Ÿé…ç½®åˆ—è¡¨
    public static List<SystemConfiguration> getSystemConfigurations()  {
        // åˆ›å»ºé…ç½®å¯¹è±¡åˆ—表
@@ -61,7 +62,20 @@
                // ä½ç½®è½¬å‘é—´éš”
                config.setLocationForwardingInterval(rs.getString("location_forwarding_interval"));
                // è½¨è¿¹ä¿å­˜å¤©æ•°
                config.setTrajectorySaveDays(rs.getString("trajectory_save_days"));
                String savedays=rs.getString("trajectory_save_days");
                if (savedays != null && !savedays.trim().isEmpty()) {
                    try {
                        TrajectoryRetentionDays= Integer.parseInt(savedays);
                        if (TrajectoryRetentionDays <= 0) {
                            // å¦‚果转换后的值不是正整数,可以抛出异常或设置为默认值
                            throw new IllegalArgumentException("The value must be a positive integer.");
                        }
                    } catch (NumberFormatException e) {
                        // å¦‚果字符串不是有效的整数格式,可以抛出异常或设置为默认值
                        System.err.println("Invalid number format: " + savedays);
                    }
                }
                config.setTrajectorySaveDays(savedays);
                // æ ‡ç­¾ç¦»çº¿åˆ¤æ–­æ—¶é•¿
                config.setTagOfflineJudgmentDuration(rs.getString("tag_offline_judgment_duration"));
                // åŸºç«™ç¦»çº¿åˆ¤æ–­æ—¶é•¿
src/dell_targets/Dell_tag.java
@@ -21,7 +21,7 @@
            }
        while (rs.next()) {
            LocationTag locationTag = new LocationTag();
            locationTag.setId((int) rs.getLong("id"));
            locationTag.setId((int) rs.getLong("id"));
            locationTag.setDeviceNumber(rs.getString("device_id"));
            locationTag.setDeviceName(rs.getString("device_name"));
            locationTag.setDeviceVersion(rs.getString("device_version"));
@@ -90,7 +90,11 @@
            locationTag.setMotionlessEndTime(rs.getString("stationary_end_time"));
            locationTag.setMotionlessDuration(rs.getString("stationary_duration"));
            locationTag.setValidSatelliteSignal(rs.getString("tag_valid_satellite_signal"));
            locationTag.setCompany(rs.getString("company"));
            String company=rs.getString("company");
            if (company == null || company.trim().isEmpty() || company.equals("-1") ) {
                company = "Unknown";
            }
            locationTag.setCompany(company);
            locationTag.setSleepTime(rs.getString("sleep_time"));
            locationTag.setVibrationTime(rs.getString("vibration_time"));
            locationTag.setFrequency(rs.getString("frequency"));
@@ -106,6 +110,257 @@
            locationTag.setInteractionType(rs.getString("Interaction_Type"));
            locationTag.setIpAddress(rs.getString("ipAddress"));
            locationTag.setIpPort(rs.getString("Interaction_Type"));
            locationTag.setId((int) rs.getLong("id"));
            String deviceNumber = rs.getString("device_id");
            if (deviceNumber == null || deviceNumber.trim().isEmpty() || deviceNumber.equals("-1")) {
                deviceNumber = "Unknown";
            }
            locationTag.setDeviceNumber(deviceNumber);
            String deviceName = rs.getString("device_name");
            if (deviceName == null || deviceName.trim().isEmpty() || deviceName.equals("-1")) {
                deviceName = "Unknown";
            }
            locationTag.setDeviceName(deviceName);
            String deviceVersion = rs.getString("device_version");
            if (deviceVersion == null || deviceVersion.trim().isEmpty() || deviceVersion.equals("-1")) {
                deviceVersion = "Unknown";
            }
            locationTag.setDeviceVersion(deviceVersion);
            String deviceCardNumber = rs.getString("device_card_number");
            if (deviceCardNumber == null || deviceCardNumber.trim().isEmpty() || deviceCardNumber.equals("-1")) {
                deviceCardNumber = "Unknown";
            }
            locationTag.setDeviceCardNumber(deviceCardNumber);
            String deviceType = rs.getString("device_type");
            if (deviceType == null || deviceType.trim().isEmpty() || deviceType.equals("-1")) {
                deviceType = "Unknown";
            }
            locationTag.setDeviceType(deviceType);
            String team = rs.getString("affiliated_class");
            if (team == null || team.trim().isEmpty() || team.equals("-1")) {
                team = "Unknown";
            }
            locationTag.setTeam(team);
            String group = rs.getString("affiliated_group");
            if (group == null || group.trim().isEmpty() || group.equals("-1")) {
                group = "Unknown";
            }
            locationTag.setGroup(group);
            String department = rs.getString("department");
            if (department == null || department.trim().isEmpty() || department.equals("-1")) {
                department = "Unknown";
            }
            locationTag.setDepartment(department);
            String iconAddress = rs.getString("icon_url");
            if (iconAddress == null || iconAddress.trim().isEmpty() || iconAddress.equals("-1")) {
                iconAddress = "Unknown";
            }
            locationTag.setIconAddress(iconAddress);
            String gender = rs.getString("gender");
            if (gender == null || gender.trim().isEmpty() || gender.equals("-1")) {
                gender = "Unknown";
            }
            locationTag.setGender(gender);
            String ethnicity = rs.getString("ethnic_group");
            if (ethnicity == null || ethnicity.trim().isEmpty() || ethnicity.equals("-1")) {
                ethnicity = "Unknown";
            }
            locationTag.setEthnicity(ethnicity);
            String communicationAddress = rs.getString("communication_address");
            if (communicationAddress == null || communicationAddress.trim().isEmpty() || communicationAddress.equals("-1")) {
                communicationAddress = "Unknown";
            }
            locationTag.setCommunicationAddress(communicationAddress);
            String boundPhone = rs.getString("bound_phone");
            if (boundPhone == null || boundPhone.trim().isEmpty() || boundPhone.equals("-1")) {
                boundPhone = "Unknown";
            }
            locationTag.setBoundPhone(boundPhone);
            String idNumber = rs.getString("id_card_number");
            if (idNumber == null || idNumber.trim().isEmpty() || idNumber.equals("-1")) {
                idNumber = "Unknown";
            }
            locationTag.setIdNumber(idNumber);
            String position = rs.getString("personnel_position");
            if (position == null || position.trim().isEmpty() || position.equals("-1")) {
                position = "Unknown";
            }
            locationTag.setPosition(position);
            String boundPlateNumber = rs.getString("bound_license_plate");
            if (boundPlateNumber == null || boundPlateNumber.trim().isEmpty() || boundPlateNumber.equals("-1")) {
                boundPlateNumber = "Unknown";
            }
            locationTag.setBoundPlateNumber(boundPlateNumber);
            String faceAddress = rs.getString("face_image_url");
            if (faceAddress == null || faceAddress.trim().isEmpty() || faceAddress.equals("-1")) {
                faceAddress = "Unknown";
            }
            locationTag.setFaceAddress(faceAddress);
            String heartRate = rs.getString("heart_rate");
            if (heartRate == null || heartRate.trim().isEmpty() || heartRate.equals("-1")) {
                heartRate = "Unknown";
            }
            locationTag.setHeartRate(heartRate);
            String bloodPressure = rs.getString("blood_pressure");
            if (bloodPressure == null || bloodPressure.trim().isEmpty() || bloodPressure.equals("-1")) {
                bloodPressure = "Unknown";
            }
            locationTag.setBloodPressure(bloodPressure);
            String bloodOxygen = rs.getString("blood_oxygen");
            if (bloodOxygen == null || bloodOxygen.trim().isEmpty() || bloodOxygen.equals("-1")) {
                bloodOxygen = "Unknown";
            }
            locationTag.setBloodOxygen(bloodOxygen);
            String temperature = rs.getString("body_temperature");
            if (temperature == null || temperature.trim().isEmpty() || temperature.equals("-1")) {
                temperature = "Unknown";
            }
            locationTag.setTemperature(temperature);
            String sosStatus = rs.getString("sos_status");
            if (sosStatus == null || sosStatus.trim().isEmpty() || sosStatus.equals("-1")) {
                sosStatus = "Unknown";
            }
            locationTag.setSosStatus(sosStatus);
            String motionStatus = rs.getString("motion_status");
            if (motionStatus == null || motionStatus.trim().isEmpty() || motionStatus.equals("-1")) {
                motionStatus = "Unknown";
            }
            locationTag.setMotionStatus(motionStatus);
            String onlineStatus = rs.getString("online_status");
            if (onlineStatus == null || onlineStatus.trim().isEmpty() || onlineStatus.equals("-1")) {
                onlineStatus = "Unknown";
            }
            locationTag.setOnlineStatus(onlineStatus);
            String searchStatus = rs.getString("search_status");
            if (searchStatus == null || searchStatus.trim().isEmpty() || searchStatus.equals("-1")) {
                searchStatus = "Unknown";
            }
            locationTag.setSearchStatus(searchStatus);
            String batteryStatus = rs.getString("battery_status");
            if (batteryStatus == null || batteryStatus.trim().isEmpty() || batteryStatus.equals("-1")) {
                batteryStatus = "Unknown";
            }
            locationTag.setBatteryStatus(batteryStatus);
            String deviceBattery = rs.getString("device_battery");
            if (deviceBattery == null || deviceBattery.trim().isEmpty() || deviceBattery.equals("-1")) {
                deviceBattery = "Unknown";
            }
            locationTag.setDeviceBattery(deviceBattery);
            String removalStatus = rs.getString("removal_status");
            if (removalStatus == null || removalStatus.trim().isEmpty() || removalStatus.equals("-1")) {
                removalStatus = "Unknown";
            }
            locationTag.setRemovalStatus(removalStatus);
            String collisionStatus = rs.getString("collision_status");
            if (collisionStatus == null || collisionStatus.trim().isEmpty() || collisionStatus.equals("-1")) {
                collisionStatus = "Unknown";
            }
            locationTag.setCollisionStatus(collisionStatus);
            String elevationStatus = rs.getString("climbing_status");
            if (elevationStatus == null || elevationStatus.trim().isEmpty() || elevationStatus.equals("-1")) {
                elevationStatus = "Unknown";
            }
            locationTag.setElevationStatus(elevationStatus);
            String gatheringCount = rs.getString("gathering_count");
            if (gatheringCount == null || gatheringCount.trim().isEmpty() || gatheringCount.equals("-1")) {
                gatheringCount = "Unknown";
            }
            locationTag.setGatheringCount(gatheringCount);
            String proximityAlarm = rs.getString("proximity_alarm");
            if (proximityAlarm == null || proximityAlarm.trim().isEmpty() || proximityAlarm.equals("-1")) {
                proximityAlarm = "Unknown";
            }
            locationTag.setProximityAlarm(proximityAlarm);
            String area = rs.getString("current_area");
            if (area == null || area.trim().isEmpty() || area.equals("-1")) {
                area = "Unknown";
            }
            locationTag.setArea(area);
            String xCoordinate = rs.getString("x_coordinate");
            if (xCoordinate == null || xCoordinate.trim().isEmpty() || xCoordinate.equals("-1")) {
                xCoordinate = "Unknown";
            }
            locationTag.setXCoordinate(xCoordinate);
            String yCoordinate = rs.getString("y_coordinate");
            if (yCoordinate == null || yCoordinate.trim().isEmpty() || yCoordinate.equals("-1")) {
                yCoordinate = "Unknown";
            }
            locationTag.setYCoordinate(yCoordinate);
            String zCoordinate = rs.getString("z_coordinate");
            if (zCoordinate == null || zCoordinate.trim().isEmpty() || zCoordinate.equals("-1")) {
                zCoordinate = "Unknown";
            }
            locationTag.setZCoordinate(zCoordinate);
            String floor = rs.getString("current_floor");
            if (floor == null || floor.trim().isEmpty() || floor.equals("-1")) {
                floor = "Unknown";
            }
            locationTag.setFloor(floor);
            String speed = rs.getString("movement_speed");
            if (speed == null || speed.trim().isEmpty() || speed.equals("-1")) {
                speed = "Unknown";
            }
            locationTag.setSpeed(speed);
            String locationSource = rs.getString("position_source");
            if (locationSource == null || locationSource.trim().isEmpty() || locationSource.equals("-1")) {
                locationSource = "Unknown";
            }
            locationTag.setLocationSource(locationSource);
            String lastUwbSignalTime = rs.getString("last_uwb_signal_time");
            if (lastUwbSignalTime == null || lastUwbSignalTime.trim().isEmpty() || lastUwbSignalTime.equals("-1")) {
                lastUwbSignalTime = "Unknown";
            }
            locationTag.setLastUwbSignalTime(lastUwbSignalTime);
            String lastSatelliteSignalTime = rs.getString("last_satellite_signal_time");
            if (lastSatelliteSignalTime == null || lastSatelliteSignalTime.trim().isEmpty() || lastSatelliteSignalTime.equals("-1")) {
                lastSatelliteSignalTime = "Unknown";
            }
            locationTag.setAutoUpgraded("Unknown");
            locationTag.setIsSatelliteDevice("-1");
            locationTag.setRTKsource("Unknown");
            locationTags.add(locationTag);
            tagMap.put(locationTag.getDeviceNumber(), locationTag); // æ·»åŠ åˆ°æ˜ å°„
        }
@@ -226,6 +481,9 @@
            case "interactionType": tag.setInteractionType(value); break;
            case "ipAddress": tag.setIpAddress(value); break;
            case "ipPort": tag.setIpPort(value); break;
            case "gnGgaDataTime": tag.setGnGgaDataTime(value); break;
            case "isSatelliteDevice": tag.setIsSatelliteDevice(value);break;
            case "RTKsource": tag.setRTKsource(value);break;
            default: 
                throw new IllegalArgumentException("无效属性: " + propertyName);
        }
@@ -293,4 +551,47 @@
        }
        return tagMap.size();
    }
    /**
     * æ ¹æ®å•个属性查询LocationTag对象
     * @param propertyName å±žæ€§åï¼ˆdeviceNumber/deviceVersion/company)
     * @param propertyValue å±žæ€§å€¼
     * @return æ»¡è¶³æ¡ä»¶çš„LocationTag对象列表
     */
    public static List<LocationTag> getLocationTagsByProperty(String propertyName, String propertyValue) {
        if (tagMap == null || tagMap.isEmpty()) {
            try {
                getlocationTags(); // åˆå§‹åŒ–数据
            } catch (SQLException e) {
                e.printStackTrace();
                return Collections.emptyList();
            }
        }
        List<LocationTag> result = new ArrayList<>();
        for (LocationTag tag : tagMap.values()) {
            switch (propertyName) {
                case "deviceNumber":
                    if (propertyValue.equals(tag.getDeviceNumber())) {
                        result.add(tag);
                    }
                    break;
                case "deviceVersion":
                    if (propertyValue.equals(tag.getDeviceVersion())) {
                        result.add(tag);
                    }
                    break;
                case "company":
                    if (propertyValue.equals(tag.getCompany())) {
                        result.add(tag);
                    }
                    break;
                default:
                    throw new IllegalArgumentException("不支持的属性: " + propertyName);
            }
        }
        return result;
    }
src/dell_targets/SatelliteDevicePanel.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,483 @@
package dell_targets;
import targets.LocationTag;
import dell_targets.Dell_tag;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.*;
import java.util.List;
import java.util.ResourceBundle;
import publicsWay.ButtonUtils; // å¯¼å…¥ButtonUtils
import publicsWay.TableUtils; // å¯¼å…¥TableUtils
public class SatelliteDevicePanel extends JPanel {
    private static final long serialVersionUID = 1L;
    private JTable deviceTable;
    private DefaultTableModel tableModel;
    private List<LocationTag> allDevices;
    private ResourceBundle messages;
    private JTextField searchField;
    private JComboBox<String> upgradeConditionCombo;
    private JTextField upgradeValueField;
    private JButton startUpgradeButton;
    private JTextField firmwareUrlField; // å›ºä»¶å‡çº§æ–‡æœ¬åŸŸ
    public static String FirmwareURL="";//固件升级地址
    public static boolean isOpenUpgrade=false;//是否开启了升级功能
    public static List<LocationTag> needUpgradeList=null;//需要升级的设备集合
    @SuppressWarnings("serial")
    public SatelliteDevicePanel(ResourceBundle messages) {
        this.messages = messages;
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        // æ·»åŠ çª—å£å…³é—­ç›‘å¬å™¨
        addWindowCloseListener();
        // é¡¶éƒ¨æ“ä½œé¢æ¿
        JPanel topPanel = new JPanel(new BorderLayout(5, 5));
        topPanel.setBorder(BorderFactory.createTitledBorder(messages.getString("QUICK_OPERATION")));
        // æœç´¢é¢æ¿
        JPanel searchInputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        JLabel searchLabel = new JLabel(messages.getString("DEVICE_NUMBER") + ":");
        searchField = new JTextField(15);
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton searchButton = ButtonUtils.createBlueButton(messages.getString("SEARCH"));
        JButton resetButton = ButtonUtils.createBlueButton(messages.getString("RESET"));
        JButton refreshButton = ButtonUtils.createBlueButton(messages.getString("REFRESH"));
        searchInputPanel.add(searchLabel);
        searchInputPanel.add(searchField);
        searchInputPanel.add(searchButton);
        searchInputPanel.add(resetButton);
        searchInputPanel.add(refreshButton);
        // å‡çº§æ¡ä»¶é¢æ¿
        JPanel upgradePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
        upgradeConditionCombo = new JComboBox<>(new String[]{
                messages.getString("SET_UPGRADE_CONDITIONS"),
                messages.getString("BY_VERSION"),
                messages.getString("BY_NUMBER"),
                messages.getString("BY_SELECTED_DEVICE"),
                messages.getString("BY_COMPANY_NAME")
        });
        upgradeValueField = new JTextField(15);
        startUpgradeButton = ButtonUtils.createBlueButton(messages.getString("START_UPGRADE"));
        // æ–°å¢žå›ºä»¶åœ°å€æ–‡æœ¬æ¡†
        JLabel firmwareUrlLabel = new JLabel(messages.getString("FIRMWARE_URL") + ":");
        firmwareUrlField = new JTextField(20);
        firmwareUrlField.setToolTipText(messages.getString("ENTER_FIRMWARE_DOWNLOAD_URL"));
        upgradePanel.add(upgradeConditionCombo);
        upgradePanel.add(upgradeValueField);
        upgradePanel.add(firmwareUrlLabel);
        upgradePanel.add(firmwareUrlField);
        upgradePanel.add(startUpgradeButton);
        // æ“ä½œæŒ‰é’®é¢æ¿
        JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
        // å°†æœç´¢é¢æ¿ã€å‡çº§é¢æ¿å’Œæ“ä½œé¢æ¿æ”¾åœ¨ä¸€è¡Œ
        JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
        rowPanel.add(searchInputPanel);
        rowPanel.add(upgradePanel);
        rowPanel.add(actionPanel);
        topPanel.add(rowPanel, BorderLayout.CENTER);
        // åˆ›å»ºè¡¨æ ¼åˆ—名 - å¢žåŠ æ‰€å±žå…¬å¸å’ŒæŒ‡ä»¤å‘é€åˆ—
        String[] columnNames = {
                messages.getString("SELECT"),
                messages.getString("INDEX"),
                messages.getString("COMPANY"), // æ–°å¢žæ‰€å±žå…¬å¸åˆ—
                messages.getString("DEVICE_NUMBER"),
                messages.getString("LONGITUDE"),
                messages.getString("LATITUDE"),
                messages.getString("ALTITUDE"),
                messages.getString("STATUS"),
                messages.getString("SATELLITE_COUNT"),
                messages.getString("DIFFERENTIAL_TIME"),
                messages.getString("RtkSource"),
                messages.getString("VERSION"),
                messages.getString("CARD_NUMBER"),
                messages.getString("ADDRESS"),
                messages.getString("PORT"),
                messages.getString("COMMAND_SEND"), // æ–°å¢žæŒ‡ä»¤å‘送列
                messages.getString("UPDATE_TIME")
        };
        // åˆ›å»ºè¡¨æ ¼æ¨¡åž‹
        tableModel = new DefaultTableModel(columnNames, 0) {
            @Override
            public boolean isCellEditable(int row, int column) {
                // åªæœ‰é€‰æ‹©åˆ—和指令发送列可编辑
                return column == 0 || column == 14;
            }
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                // é€‰æ‹©åˆ—使用Boolean类型
                if (columnIndex == 0) {
                    return Boolean.class;
                }
                return Object.class;
            }
        };
        // åˆ›å»ºè¡¨æ ¼ - ä½¿ç”¨TableUtils中的方法
        deviceTable = new JTable(tableModel);
        TableUtils.setupTableStyle(deviceTable);
        TableUtils.setupTableHeaderStyle(deviceTable);
        deviceTable.setAutoCreateRowSorter(true);
        deviceTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        // æ›´æ–°åˆ—宽设置,增加差分源列的宽度
        deviceTable.getColumnModel().getColumn(0).setPreferredWidth(50);
        deviceTable.getColumnModel().getColumn(1).setPreferredWidth(50);
        deviceTable.getColumnModel().getColumn(2).setPreferredWidth(100);
        deviceTable.getColumnModel().getColumn(3).setPreferredWidth(100);
        deviceTable.getColumnModel().getColumn(4).setPreferredWidth(80);
        deviceTable.getColumnModel().getColumn(5).setPreferredWidth(80);
        deviceTable.getColumnModel().getColumn(6).setPreferredWidth(80);
        deviceTable.getColumnModel().getColumn(7).setPreferredWidth(60);
        deviceTable.getColumnModel().getColumn(8).setPreferredWidth(80);
        deviceTable.getColumnModel().getColumn(9).setPreferredWidth(100);
        deviceTable.getColumnModel().getColumn(10).setPreferredWidth(100); // å·®åˆ†æºåˆ—宽度
        deviceTable.getColumnModel().getColumn(11).setPreferredWidth(80);
        deviceTable.getColumnModel().getColumn(12).setPreferredWidth(100);
        deviceTable.getColumnModel().getColumn(13).setPreferredWidth(120);
        deviceTable.getColumnModel().getColumn(14).setPreferredWidth(80);
        deviceTable.getColumnModel().getColumn(15).setPreferredWidth(100);
        deviceTable.getColumnModel().getColumn(16).setPreferredWidth(150);
        // åº”用单元格渲染器到所有列 - ä½¿ç”¨TableUtils中的方法
        DefaultTableCellRenderer cellRenderer = TableUtils.createCenteredCellRenderer();
        for (int i = 0; i < deviceTable.getColumnCount(); i++) {
            deviceTable.getColumnModel().getColumn(i).setCellRenderer(cellRenderer);
        }
        // ç‰¹æ®Šå¤„理选择列(复选框)
        TableColumn selectColumn = deviceTable.getColumnModel().getColumn(0);
        selectColumn.setCellRenderer(new DefaultTableCellRenderer() {
            private JCheckBox checkBox = new JCheckBox();
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus,
                    int row, int column) {
                if (value instanceof Boolean) {
                    checkBox.setSelected((Boolean) value);
                }
                checkBox.setHorizontalAlignment(SwingConstants.CENTER);
                // è®¾ç½®äº¤æ›¿è¡Œé¢œè‰²
                if (!isSelected) {
                    if (row % 2 == 0) {
                        checkBox.setBackground(new Color(240, 240, 200)); // æ·¡é»„色
                    } else {
                        checkBox.setBackground(Color.WHITE); // ç™½è‰²
                    }
                } else {
                    checkBox.setBackground(new Color(200, 220, 240)); // é€‰ä¸­è¡Œçš„蓝色
                }
                checkBox.setOpaque(true);
                return checkBox;
            }
        });
        JScrollPane scrollPane = new JScrollPane(deviceTable);
        scrollPane.setPreferredSize(new Dimension(1200, 400));
        scrollPane.setBorder(BorderFactory.createEmptyBorder()); // ç§»é™¤æ»šåŠ¨é¢æ¿è¾¹æ¡†
        // æ·»åŠ ç»„ä»¶
        add(topPanel, BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);
        // åŠ è½½æ•°æ®
        loadDeviceData();
        // æ·»åŠ äº‹ä»¶ç›‘å¬å™¨
        searchButton.addActionListener(e -> searchDevices());
        resetButton.addActionListener(e -> resetSearch());
        refreshButton.addActionListener(e -> loadDeviceData());
        startUpgradeButton.addActionListener(e -> startUpgrade());
        // æ·»åŠ è¡¨æ ¼æ¨¡åž‹ç›‘å¬å™¨ï¼Œç”¨äºŽè‡ªåŠ¨æ›´æ–°é€‰ä¸­è®¾å¤‡åˆ°æ–‡æœ¬æ¡†
        tableModel.addTableModelListener(e -> {
            if (e.getColumn() == 0 && messages.getString("BY_SELECTED_DEVICE").equals(upgradeConditionCombo.getSelectedItem())) {
                updateSelectedDevicesToTextField();
            }
        });
        // æ·»åŠ å‡çº§æ¡ä»¶ç»„åˆæ¡†ç›‘å¬å™¨
        upgradeConditionCombo.addActionListener(e -> {
            if (messages.getString("BY_SELECTED_DEVICE").equals(upgradeConditionCombo.getSelectedItem())) {
                updateSelectedDevicesToTextField();
            }
        });
    }
    // æ›´æ–°é€‰ä¸­è®¾å¤‡åˆ°æ–‡æœ¬æ¡†
    private void updateSelectedDevicesToTextField() {
        List<String> selectedDevices = new ArrayList<>();
        for (int i = 0; i < tableModel.getRowCount(); i++) {
            Boolean isSelected = (Boolean) tableModel.getValueAt(i, 0);
            if (isSelected != null && isSelected) {
                String deviceNumber = (String) tableModel.getValueAt(i, 3); // è®¾å¤‡ç¼–号在第3列
                selectedDevices.add(deviceNumber);
            }
        }
        upgradeValueField.setText(String.join(",", selectedDevices));
    }
    // æŒ‰é’®æ¸²æŸ“器
    class ButtonRenderer extends JButton implements TableCellRenderer {
        private static final long serialVersionUID = 1L;
        public ButtonRenderer() {
            setOpaque(true);
        }
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus,
                int row, int column) {
            setText((value == null) ? "" : value.toString());
            return this;
        }
    }
    // æŒ‰é’®ç¼–辑器
    class ButtonEditor extends DefaultCellEditor {
        private static final long serialVersionUID = 1L;
        private String label;
        private JButton button;
        public ButtonEditor(JCheckBox checkBox) {
            super(checkBox);
            button = new JButton();
            button.setOpaque(true);
            button.addActionListener(e -> fireEditingStopped());
        }
        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                boolean isSelected, int row, int column) {
            label = (value == null) ? "" : value.toString();
            button.setText(label);
            return button;
        }
        @Override
        public Object getCellEditorValue() {
            return label;
        }
    }
    private void loadDeviceData() {
        try {
            allDevices = Dell_tag.getOnlineLocationTags();
            updateTable(allDevices);
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(this, messages.getString("DATA_LOAD_ERROR") + ": " + ex.getMessage(),
                    messages.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
        }
    }
    // æœç´¢è®¾å¤‡
    private void searchDevices() {
        String keyword = searchField.getText().trim();
        if (keyword.isEmpty()) {
            updateTable(allDevices);
            return;
        }
        List<LocationTag> filtered = new ArrayList<>();
        for (LocationTag device : allDevices) {
            if (device.getDeviceNumber() != null &&
                    device.getDeviceNumber().toLowerCase().contains(keyword.toLowerCase())) {
                filtered.add(device);
            }
        }
        if (filtered.isEmpty()) {
            JOptionPane.showMessageDialog(this, messages.getString("SEARCH_NO_RESULTS"),
                    messages.getString("INFO"), JOptionPane.INFORMATION_MESSAGE);
        }
        updateTable(filtered);
    }
    // é‡ç½®æœç´¢
    private void resetSearch() {
        searchField.setText("");
        updateTable(allDevices);
    }
    private void updateTable(List<LocationTag> devices) {
        tableModel.setRowCount(0);
        int index = 1;
        for (LocationTag device : devices) {
            tableModel.addRow(new Object[]{
                    false, // é€‰æ‹©åˆ—
                    index++,
                    device.getCompany(), // æ–°å¢žå…¬å¸åˆ—
                    device.getDeviceNumber(),
                    device.getLongitude(),
                    device.getLatitude(),
                    device.getAltitude(),
                    device.getSatelliteQuality(),
                    device.getSatelliteCount(),
                    device.getDifferentialTime(),
                    device.getRTKsource(), // æ–°å¢žå·®åˆ†æºæ•°æ®
                    device.getDeviceVersion(),
                    device.getDeviceCardNumber(),
                    device.getIpAddress(),
                    device.getIpPort(),
                    device.getAutoUpgraded(),// æŒ‡ä»¤å‘送按钮
                    device.getGnGgaDataTime()
            });
        }
    }
    // å¯åŠ¨å‡çº§
    private void startUpgrade() {
        int dex = upgradeConditionCombo.getSelectedIndex();
        String value = upgradeValueField.getText().trim();
        String firmwareUrl = firmwareUrlField.getText().trim();
        if (firmwareUrl.isEmpty()) {
            JOptionPane.showMessageDialog(this, messages.getString("FIRMWARE_URL_REQUIRED"),
                    messages.getString("WARNING"), JOptionPane.WARNING_MESSAGE);
            return;
        }
        if (value.isEmpty()) {
            JOptionPane.showMessageDialog(this, messages.getString("UPGRADE_VALUE_REQUIRED"),
                    messages.getString("WARNING"), JOptionPane.WARNING_MESSAGE);
            return;
        }
        List<LocationTag> devicesToUpgrade = new ArrayList<>();
        // æ ¹æ®æ¡ä»¶æ‰§è¡Œå‡çº§é€»è¾‘
        if (dex == 3) {
            // èŽ·å–é€‰ä¸­çš„è®¾å¤‡
            for (int i = 0; i < tableModel.getRowCount(); i++) {
                Boolean isSelected = (Boolean) tableModel.getValueAt(i, 0);
                if (isSelected != null && isSelected) {
                    String deviceNumber = (String) tableModel.getValueAt(i, 3);
                    LocationTag device = Dell_tag.getTagByDeviceId(deviceNumber);
                    if (device != null) {
                        devicesToUpgrade.add(device);
                    }
                }
            }
            if (devicesToUpgrade.isEmpty()) {
                JOptionPane.showMessageDialog(this, messages.getString("SELECT_DEVICE_TO_UPGRADE"),
                        messages.getString("WARNING"), JOptionPane.WARNING_MESSAGE);
                return;
            }
        } else if (dex == 1) {
            // æ‰§è¡ŒæŒ‰ç‰ˆæœ¬å‡çº§
            devicesToUpgrade = Dell_tag.getLocationTagsByProperty("deviceVersion", value);
        } else if (dex == 2) {
            // æ‰§è¡ŒæŒ‰è®¾å¤‡ç¼–号升级 - ä¿®å¤é€»è¾‘错误
            String[] tagIds = value.split("[\\s,;]+"); // ä½¿ç”¨æ­£åˆ™è¡¨è¾¾å¼åˆ†å‰²å¤šç§åˆ†éš”符
            for (String tagId : tagIds) {
                List<LocationTag> devicesForId = Dell_tag.getLocationTagsByProperty("deviceNumber", tagId.trim());
                if (devicesForId != null) {
                    devicesToUpgrade.addAll(devicesForId);
                }
            }
        } else if (dex == 4) {
            // æ‰§è¡ŒæŒ‰å…¬å¸åç§°å‡çº§
            devicesToUpgrade = Dell_tag.getLocationTagsByProperty("company", value);
        }
        // éªŒè¯æ˜¯å¦æœ‰è®¾å¤‡éœ€è¦å‡çº§
        if (devicesToUpgrade.isEmpty()) {
            JOptionPane.showMessageDialog(this, messages.getString("NO_DEVICES_TO_UPGRADE"),
                    messages.getString("WARNING"), JOptionPane.WARNING_MESSAGE);
            return;
        }
        FirmwareURL = firmwareUrl; // å›ºä»¶å‡çº§åœ°å€
        isOpenUpgrade = true; // æ˜¯å¦å¼€å¯äº†å‡çº§åŠŸèƒ½
        needUpgradeList = devicesToUpgrade; // éœ€è¦å‡çº§çš„设备集合
        // æ‰§è¡Œå‡çº§
        performUpgrade(devicesToUpgrade, firmwareUrl);
    }
    private void performUpgrade(List<LocationTag> devices, String firmwareUrl) {
        // æž„建设备编号列表字符串
        StringBuilder deviceListBuilder = new StringBuilder();
        int maxDisplay = 20;
        int displayCount = Math.min(devices.size(), maxDisplay);
        for (int i = 0; i < displayCount; i++) {
            if (i > 0) {
                deviceListBuilder.append(", ");
            }
            deviceListBuilder.append(devices.get(i).getDeviceNumber());
        }
        if (devices.size() > maxDisplay) {
            deviceListBuilder.append(messages.getString("UPGRADE_DEVICE_ELLIPSIS"))
                             .append(devices.size())
                             .append(messages.getString("UPGRADE_DEVICE_UNIT"));
        }
        // åˆ›å»ºåŒ…含设备列表和固件地址的完整消息
        String message = messages.getString("UPGRADE_CONFIRMATION_HEADER") +
                         deviceListBuilder.toString() +
                         "\n\n" + messages.getString("FIRMWARE_URL_LABEL") + ": " + firmwareUrl +
                         "\n\n" + String.format(messages.getString("TOTAL_DEVICES_COUNT"), devices.size());
        JOptionPane.showMessageDialog(this,
                message,
                messages.getString("INFO"), JOptionPane.INFORMATION_MESSAGE);
    }
    // æ·»åŠ çª—å£å…³é—­ç›‘å¬å™¨
    private void addWindowCloseListener() {
        // èŽ·å–é¡¶å±‚çª—å£
        Window window = SwingUtilities.getWindowAncestor(this);
        if (window != null) {
            window.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    isOpenUpgrade = false;
                }
                @Override
                public void windowClosed(WindowEvent e) {
                    isOpenUpgrade = false;
                }
            });
        }
    }
    public static String getFirmwareURL() {
        return FirmwareURL;
    }
    public static boolean isOpenUpgrade() {
        return isOpenUpgrade;
    }
    public static List<LocationTag> getNeedUpgradeList() {
        return needUpgradeList;
    }
}
src/dell_targets/TagManagementPanel.java
@@ -2,13 +2,16 @@
import targets.LocationTag;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import java.util.List;
import java.util.ResourceBundle;
import publicsWay.ButtonUtils;  // Added import
public class TagManagementPanel extends JPanel {
    private static final long serialVersionUID = 1L;
@@ -21,31 +24,39 @@
    public TagManagementPanel(ResourceBundle messages) {
        this.messages = messages;
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        
        // åˆ›å»ºæœç´¢é¢æ¿
        JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
        searchPanel.setBorder(BorderFactory.createTitledBorder(messages.getString("SEARCH")));
        // åˆ›å»ºé¡¶éƒ¨é¢æ¿
        JPanel topPanel = new JPanel(new BorderLayout(5, 5));
        topPanel.setBorder(BorderFactory.createTitledBorder(messages.getString("SEARCH")));
        
        // åˆ›å»ºæœç´¢æ–‡æœ¬æ¡†å’ŒæŒ‰é’®
        searchField = new JTextField(10); // ç¼©çŸ­æœç´¢æ–‡æœ¬æ¡†é•¿åº¦
        JButton searchButton = new JButton(messages.getString("SEARCH"));
        JButton refreshButton = new JButton(messages.getString("REFRESH")); // æ·»åŠ åˆ·æ–°æŒ‰é’®
        refreshButton.addActionListener(e -> loadTagData()); // ç»‘定刷新动作
        // å·¦ä¾§æœç´¢ç»„件面板
        JPanel searchInputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        JLabel searchLabel = new JLabel(messages.getString("DEVICE_NUMBER") + ":");
        searchField = new JTextField(20);
        // ä½¿ç”¨ButtonUtils创建按钮
        JButton searchButton = ButtonUtils.createBlueButton(messages.getString("SEARCH"));
        JButton resetButton = ButtonUtils.createBlueButton(messages.getString("RESET"));
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
        buttonPanel.add(searchButton);
        buttonPanel.add(refreshButton);
        searchInputPanel.add(searchLabel);
        searchInputPanel.add(searchField);
        searchInputPanel.add(searchButton);
        searchInputPanel.add(resetButton);
        searchPanel.add(searchField, BorderLayout.CENTER);
        searchPanel.add(buttonPanel, BorderLayout.EAST);
        // åˆ›å»ºæ“ä½œæŒ‰é’®é¢æ¿
        JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
        JButton addButton = new JButton(messages.getString("ADD"));
        JButton deleteButton = new JButton(messages.getString("DELETE"));
        // å³ä¾§æ“ä½œæŒ‰é’®é¢æ¿
        JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
        JButton addButton = ButtonUtils.createBlueButton(messages.getString("ADD"));
        JButton deleteButton = ButtonUtils.createBlueButton(messages.getString("DELETE"));
        JButton refreshButton = ButtonUtils.createBlueButton(messages.getString("REFRESH"));
        actionPanel.add(addButton);
        actionPanel.add(deleteButton);
        actionPanel.add(refreshButton);
        // å°†å·¦ä¾§æœç´¢å’Œå³ä¾§æ“ä½œæ·»åŠ åˆ°é¡¶éƒ¨é¢æ¿
        topPanel.add(searchInputPanel, BorderLayout.CENTER);
        topPanel.add(actionPanel, BorderLayout.EAST);
        
        // åˆ›å»ºè¡¨æ ¼ - æŒ‰ç…§è¡¨5要求修改列名
        String[] columnNames = {
@@ -75,6 +86,13 @@
        tagTable.setAutoCreateRowSorter(true);
        tagTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        // è®¾ç½®è¡¨æ ¼æ ·å¼ - åŽ»æŽ‰ç«–çº¿ï¼Œåªæ˜¾ç¤ºæ¨ªçº¿ï¼Œæ …æ æ•ˆæžœ
        tagTable.setShowVerticalLines(false); // ä¸æ˜¾ç¤ºç«–线
        tagTable.setShowHorizontalLines(true); // æ˜¾ç¤ºæ¨ªçº¿
        tagTable.setGridColor(new Color(220, 220, 220)); // è®¾ç½®ç½‘格线颜色为浅灰色
        tagTable.setIntercellSpacing(new Dimension(0, 1)); // è®¾ç½®å•元格间距,增加行间距
        tagTable.setRowHeight(25); // è®¾ç½®è¡Œé«˜
        // è®¾ç½®åˆ—宽
        tagTable.getColumnModel().getColumn(0).setPreferredWidth(30);
        tagTable.getColumnModel().getColumn(1).setPreferredWidth(100);
@@ -88,19 +106,95 @@
        tagTable.getColumnModel().getColumn(9).setPreferredWidth(120); // ä¸Šçº¿æ—¶é—´
        tagTable.getColumnModel().getColumn(10).setPreferredWidth(100);
        
        // è®¾ç½®è¡¨å¤´æ ·å¼
        JTableHeader header = tagTable.getTableHeader();
        header.setBackground(new Color(70, 130, 180)); // é’¢è“è‰²è¡¨å¤´
        header.setForeground(Color.WHITE);
        header.setFont(header.getFont().deriveFont(Font.BOLD));
        header.setPreferredSize(new Dimension(header.getWidth(), 30)); // å¢žåŠ è¡¨å¤´é«˜åº¦
        // åˆ›å»ºè¡¨å¤´æ¸²æŸ“器
        DefaultTableCellRenderer headerRenderer = new DefaultTableCellRenderer() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                setHorizontalAlignment(SwingConstants.CENTER);
                setBackground(new Color(70, 130, 180)); // é’¢è“è‰²è¡¨å¤´
                setForeground(Color.WHITE);
                setFont(getFont().deriveFont(Font.BOLD));
                setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); // å¢žåŠ è¡¨å¤´å†…è¾¹è·
            }
        };
        // åº”用表头渲染器
        for (int i = 0; i < tagTable.getColumnCount(); i++) {
            tagTable.getColumnModel().getColumn(i).setHeaderRenderer(headerRenderer);
        }
        // åˆ›å»ºå•元格渲染器,实现栅栏效果
        DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                         boolean isSelected, boolean hasFocus,
                                                         int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                // è®¾ç½®äº¤æ›¿è¡Œé¢œè‰²
                if (!isSelected) {
                    if (row % 2 == 0) {
                        c.setBackground(new Color(240, 240, 200)); // æµ…灰色
                    } else {
                        c.setBackground(Color.WHITE); // ç™½è‰²
                    }
                } else {
                    c.setBackground(new Color(200, 220, 240)); // é€‰ä¸­è¡Œçš„蓝色
                }
                // è®¾ç½®å•元格对齐方式
                if (column == 0) { // ç´¢å¼•列居中
                    setHorizontalAlignment(SwingConstants.CENTER);
                } else if (column == 5) { // ç”µæ± ç”µé‡åˆ—居中
                    setHorizontalAlignment(SwingConstants.CENTER);
                } else {
                    setHorizontalAlignment(SwingConstants.CENTER);
                }
                // è®¾ç½®å•元格边框
                setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); // å·¦å³å†…边距
                return c;
            }
        };
        // åº”用单元格渲染器到所有列
        for (int i = 0; i < tagTable.getColumnCount(); i++) {
            tagTable.getColumnModel().getColumn(i).setCellRenderer(cellRenderer);
        }
        JScrollPane scrollPane = new JScrollPane(tagTable);
        scrollPane.setPreferredSize(new Dimension(1200, 400));
        scrollPane.setBorder(BorderFactory.createEmptyBorder()); // ç§»é™¤æ»šåŠ¨é¢æ¿è¾¹æ¡†
        
        // æ·»åŠ ç»„ä»¶
        add(searchPanel, BorderLayout.NORTH);
        add(topPanel, BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);
        add(actionPanel, BorderLayout.SOUTH);
        
        // åŠ è½½æ•°æ®
        loadTagData();
        
        // æ·»åŠ äº‹ä»¶ç›‘å¬å™¨
        searchButton.addActionListener(new SearchAction());
        resetButton.addActionListener(e -> resetSearch());
        refreshButton.addActionListener(e -> loadTagData());
        addButton.addActionListener(e -> {
            AddTagDialog dialog = new AddTagDialog((Frame) SwingUtilities.getWindowAncestor(TagManagementPanel.this), messages);
            dialog.setVisible(true);
@@ -194,6 +288,12 @@
        }
    }
    
    // é‡ç½®æœç´¢
    private void resetSearch() {
        searchField.setText("");
        updateTable(allTags);
    }
    private class SearchAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
src/dell_targets/TagTypeManagementPanel.java
@@ -11,6 +11,8 @@
import java.util.List;
import java.util.ResourceBundle;
import java.nio.charset.StandardCharsets;
import publicsWay.ButtonUtils; // å¯¼å…¥ButtonUtils
import publicsWay.TableUtils; // å¯¼å…¥TableUtils
public class TagTypeManagementPanel extends JPanel {
    private static final long serialVersionUID = 1L;
@@ -20,7 +22,7 @@
    private ResourceBundle messages;
    @SuppressWarnings("serial")
    public TagTypeManagementPanel(ResourceBundle messages) {
    public TagTypeManagementPanel(ResourceBundle messages) {
        this.messages = messages;
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
@@ -31,10 +33,12 @@
        
        // åˆ›å»ºæŒ‰é’®é¢æ¿
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
        JButton addButton = new JButton(getMessage("ADD"));
        JButton editButton = new JButton(getMessage("EDIT"));
        JButton deleteButton = new JButton(getMessage("DELETE"));
        JButton refreshButton = new JButton(getMessage("REFRESH"));
        // ä½¿ç”¨ButtonUtils创建蓝色按钮
        JButton addButton = ButtonUtils.createBlueButton(getMessage("ADD"));
        JButton editButton = ButtonUtils.createBlueButton(getMessage("EDIT"));
        JButton deleteButton = ButtonUtils.createBlueButton(getMessage("DELETE"));
        JButton refreshButton = ButtonUtils.createBlueButton(getMessage("REFRESH"));
        
        buttonPanel.add(addButton);
        buttonPanel.add(editButton);
@@ -57,10 +61,17 @@
            public boolean isCellEditable(int row, int column) {
                return false;
            }
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return Object.class;
            }
        };
        
        // åˆ›å»ºè¡¨æ ¼
        // åˆ›å»ºè¡¨æ ¼ - ä½¿ç”¨TableUtils中的方法
        typeTable = new JTable(tableModel);
        TableUtils.setupTableStyle(typeTable);
        TableUtils.setupTableHeaderStyle(typeTable);
        typeTable.setAutoCreateRowSorter(true);
        typeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
@@ -70,29 +81,15 @@
        typeTable.getColumnModel().getColumn(2).setPreferredWidth(150);
        typeTable.getColumnModel().getColumn(3).setPreferredWidth(200);
        
        // è®¾ç½®è¡¨å¤´æ ·å¼ï¼ˆå·¦å¯¹é½ï¼‰
        JTableHeader header = typeTable.getTableHeader();
        header.setBackground(Color.GRAY);
        header.setForeground(Color.WHITE);
        header.setFont(header.getFont().deriveFont(Font.BOLD));
        // åˆ›å»ºè¡¨å¤´æ¸²æŸ“器(左对齐)
        DefaultTableCellRenderer headerRenderer = new DefaultTableCellRenderer() {
            {
                setHorizontalAlignment(SwingConstants.LEFT);
                setBackground(Color.GRAY);
                setForeground(Color.WHITE);
                setFont(getFont().deriveFont(Font.BOLD));
            }
        };
        // åº”用表头渲染器
        // åº”用单元格渲染器到所有列 - ä½¿ç”¨TableUtils中的方法
        DefaultTableCellRenderer cellRenderer = TableUtils.createCenteredCellRenderer();
        for (int i = 0; i < typeTable.getColumnCount(); i++) {
            typeTable.getColumnModel().getColumn(i).setHeaderRenderer(headerRenderer);
            typeTable.getColumnModel().getColumn(i).setCellRenderer(cellRenderer);
        }
        
        JScrollPane scrollPane = new JScrollPane(typeTable);
        scrollPane.setPreferredSize(new Dimension(800, 400));
        scrollPane.setBorder(BorderFactory.createEmptyBorder()); // ç§»é™¤æ»šåŠ¨é¢æ¿è¾¹æ¡†
        
        // æ·»åŠ ç»„ä»¶
        add(topPanel, BorderLayout.NORTH);
@@ -148,7 +145,7 @@
    
    private String getInteractionCodeFromIndex(int index) {
        switch (index) {
            case 0: return "1"; // éœ‡åЍ
            case 0: return "1"; // æŒ¯åЍ
            case 1: return "2"; // èœ‚鸣
            case 2: return "3"; // TTS
            case 3: return "4"; // æ— 
@@ -330,7 +327,7 @@
        fieldValues.put("interaction_type", type.getInteractionType());
        fieldValues.put("save_time", type.getSaveTime()); // æ›´æ–°æ—¶é—´
        
        // ç›´æŽ¥ä½¿ç”¨ä¼ å…¥çš„ type å¯¹è±¡çš„ ID
        // ç›´æŽ¥ä½¿ç”¨ä¼ å…¥çš„type对象的ID
        if (type.getId() == null || type.getId().trim().isEmpty()) {
            JOptionPane.showMessageDialog(this, getMessage("TAG_TYPE_NOT_FOUND"),
                                        getMessage("ERROR"), JOptionPane.ERROR_MESSAGE);
@@ -404,7 +401,7 @@
            // äº¤äº’类型
            JLabel interactionLabel = new JLabel(getMessage("INTERACTION_TYPE") + ": *");
            String[] options = {
                getMessage("VIBRATION"), // éœ‡åЍ
                getMessage("VIBRATION"), // æŒ¯åЍ
                getMessage("BEEP"),      // èœ‚鸣
                getMessage("TTS"),       // è¯­éŸ³
                getMessage("NONE")       // æ— 
@@ -436,8 +433,10 @@
            // æŒ‰é’®é¢æ¿
            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            JButton okButton = new JButton(getMessage("OK"));
            JButton cancelButton = new JButton(getMessage("CANCEL"));
            // ä½¿ç”¨ButtonUtils创建蓝色按钮
            JButton okButton = ButtonUtils.createBlueButton(getMessage("OK"));
            JButton cancelButton = ButtonUtils.createBlueButton(getMessage("CANCEL"));
            okButton.addActionListener(e -> {
                confirmed = true;
src/publicsWay/ButtonUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package publicsWay;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ButtonUtils {
    /**
     * åˆ›å»ºè“è‰²æ ·å¼æŒ‰é’®çš„通用方法
     * @param text æŒ‰é’®æ–‡æœ¬
     * @return é…ç½®å¥½æ ·å¼çš„JButton
     */
    public static JButton createBlueButton(String text) {
        JButton button = new JButton(text);
        button.setBackground(new Color(0, 120, 215)); // è“è‰²èƒŒæ™¯
        button.setForeground(Color.WHITE); // ç™½è‰²æ–‡å­—
        button.setFocusPainted(false);
        button.setOpaque(true);
        button.setBorderPainted(false);
        button.setFont(button.getFont().deriveFont(Font.BOLD)); // åŠ ç²—å­—ä½“
        // æ·»åŠ é¼ æ ‡æ‚¬åœæ•ˆæžœ
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                button.setBackground(Color.GRAY); // é¼ æ ‡æ‚¬åœæ—¶å˜ä¸ºç°è‰²
                button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); // é¼ æ ‡å˜ä¸ºæ‰‹åž‹
            }
            @Override
            public void mouseExited(MouseEvent e) {
                button.setBackground(new Color(0, 120, 215)); // é¼ æ ‡ç¦»å¼€æ—¶æ¢å¤è“è‰²
                button.setCursor(Cursor.getDefaultCursor()); // é¼ æ ‡æ¢å¤é»˜è®¤å½¢çж
            }
        });
        return button;
    }
}
src/publicsWay/PacketProcessingSystem.java
@@ -3,6 +3,7 @@
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import dell55AAData.Dell55AA01Parser;
import dell55AAData.Dell55AA02Parser;
import dell55AAData.Dell55AA12HighPerf;
import java.util.concurrent.ExecutorService;
@@ -84,6 +85,7 @@
                    // å¤„理解析后的数据包
                    for (PacketParser.DataPacket p : parsedPackets) {
                        // æ ¹æ®åŒ…头类型路由到不同解析器
//                        System.out.println(p.getPacketType());
                        switch (p.getPacketType()) {
                            case 0x01:
                                processType01(p,ip,port);break;
@@ -122,7 +124,7 @@
    private static void processType02(PacketParser.DataPacket packet,String ip,int port) {
        String hexData = PacketParser.bytesToHexString(packet.getPacket());
        System.out.println("处理55AA02包: " + packet);
        Dell55AA02Parser.parse(hexData,ip,port);
        // å®žé™…业务逻辑
    }
    
src/publicsWay/PacketProcessingSystemB.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,252 @@
package publicsWay;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import dell55AAData.DellGngga;
import dell55AAData.XTB;
import java.util.regex.Matcher;
import dell_system.MessageViewPanel;
import dell_targets.Dell_tag;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PacketProcessingSystemB {
    // çº¿ç¨‹å®‰å…¨çš„æŠ¥æ–‡å­˜å‚¨é˜Ÿåˆ—(集合A)
    private static final ConcurrentLinkedQueue<HexPacket> packetQueue = new ConcurrentLinkedQueue<>();
    private static final AtomicBoolean isRunning = new AtomicBoolean(false);
    private static final ExecutorService parserExecutor = Executors.newSingleThreadExecutor();
    private static Thread parserThread;
    private static boolean a1 = true;
    // å¯é‡ç”¨çš„DellGngga实例(线程安全)
    private static final ThreadLocal<DellGngga> dellGnggaParser = ThreadLocal.withInitial(DellGngga::new);
    private static final ThreadLocal<XTB> dellXTB = ThreadLocal.withInitial(XTB::new);
    // æŠ¥æ–‡å­˜å‚¨ç»“æž„
    public static class HexPacket {
        public final String ip;
        public final int port;
        public final String hexData;
        public final long timestamp;
        public HexPacket(String ip, int port, String hexData, long timestamp) {
            this.ip = ip;
            this.port = port;
            this.hexData = hexData;
            this.timestamp = timestamp;
        }
        public String getIp() {
            return ip;
        }
        public int getPort() {
            return port;
        }
        public String getHexData() {
            return hexData;
        }
        public long getTimestamp() {
            return timestamp;
        }
    }
    // æŽ¥æ”¶ç«¯å­˜å‚¨æŠ¥æ–‡ï¼ˆUDPPortAReceiver中调用)
    public static void storePacket(String ip, int port, String hexData) {
        if (a1) {
            startProcessing();
            a1 = false;
        }
        if (packetQueue.size() < 100000) { // é™åˆ¶é˜Ÿåˆ—大小防止OOM
            packetQueue.offer(new HexPacket(ip, port, hexData, System.currentTimeMillis()));
        }
    }
    // å¯åŠ¨è§£æžç³»ç»Ÿ
    public static void startProcessing() {
        if (isRunning.get()) return;
        isRunning.set(true);
        parserThread = new Thread(() -> {
            while (isRunning.get()) {
                HexPacket packet = packetQueue.poll();
                if (packet == null) {
                    Thread.yield(); // é˜Ÿåˆ—为空时让出CPU
                    continue;
                }
                try {
                    String receivedata = packet.hexData;
                    String ip = packet.getIp();
                    int port = packet.getPort();
                    processData(receivedata, ip, port);
                } catch (Exception e) {
                    System.err.println("解析错误: " + e.getMessage());
                }
            }
        });
        parserThread.setDaemon(true);
        parserThread.start();
    }
    // åœæ­¢è§£æžç³»ç»Ÿ
    public static void stopProcessing() {
        isRunning.set(false);
        parserExecutor.shutdownNow();
        if (parserThread != null) {
            parserThread.interrupt();
        }
    }
    public static void processData(String receivedata, String ip, int port) {
        // åŽ»æŽ‰å›žè½¦æ¢è¡Œç¬¦
        receivedata = receivedata.replaceAll("[\\r\\n]+", "");
        // è½¬å¤§å†™
        receivedata = receivedata.toUpperCase();
        // å®šä¹‰æ­£åˆ™è¡¨è¾¾å¼ï¼ŒåŒ¹é…ä»¥ $GNGGA、$XTB、$SSGGA、$GBGGA æˆ– 55AA å¼€å¤´çš„æ•°æ®
        String regex = "(\\$GNGGA[^$]*|\\$XTB[^$]*|\\$SSGGA[^$]*|\\$GBGGA[^$]*|55AA[^$]*)";
        // ä½¿ç”¨æ­£åˆ™è¡¨è¾¾å¼åˆ†å‰²å­—符串
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(receivedata);
        // éåŽ†åŒ¹é…åˆ°çš„æ•°æ®
        while (matcher.find()) {
            String data = matcher.group(1);
            if (data.startsWith("$GNGGA")) {
                handleGNGGA(data, ip, port);
            } else if (data.startsWith("$XTB")) {
                handleXTB(data, ip, port);
            } else if (data.startsWith("$SSGGA")) {
                handleSSGGA(data, ip, port);
            } else if (data.startsWith("$GBGGA")) {
                handleGBGGA(data, ip, port);
            } else if (data.startsWith("55AA")) {
                handle55AA(data, ip, port);
            }
        }
    }
    private static void handleGNGGA(String data, String ip, int port) {// å¤„理$GNGGA数据
        MessageViewPanel.showData(data, ip, port, 0, "UDPB", "GNGGA", "ALL");
        // ä½¿ç”¨å¯é‡ç”¨çš„解析器实例解析数据
        dellGGA(data, ip,port);
    }
    private static void handleXTB(String data, String ip, int port) {
        // å¤„理$XTB数据
        MessageViewPanel.showData(data, ip, port, 0, "UDPB", "XTB", "ALL");
        // å…·ä½“解析逻辑
        dellXTB(data,ip,port) ;
    }
    private static void handleSSGGA(String data, String ip, int port) {
        // å¤„理$SSGGA数据
        MessageViewPanel.showData(data, ip, port, 0, "UDPB", "SSGGA", "ALL");
        dellGGA(data, ip,port);
        // å…·ä½“解析逻辑
    }
    private static void handleGBGGA(String data, String ip, int port) {
        // å¤„理$GBGGA数据
        MessageViewPanel.showData(data, ip, port, 0, "UDPB", "GBGGA", "ALL");
        // å…·ä½“解析逻辑
        dellGGA(data, ip,port);
    }
    private static void handle55AA(String data, String ip, int port) {
        // å¤„理55AA数据
        System.out.println("Handling 55AA: " + data);
        // å…·ä½“解析逻辑
    }
    private static void dellGGA(String data, String ip, int port) {
        DellGngga parser = dellGnggaParser.get();
        parser.parse(data);
        String utcTime= parser.getUtcTime();
        String latitude = parser.getLatitude(); // èŽ·å–çº¬åº¦å€¼
        String latHemisphere = parser.getLatHemisphere(); // èŽ·å–çº¬åº¦åŠçƒï¼ˆN或S)
        String longitude = parser.getLongitude(); // èŽ·å–ç»åº¦å€¼
        String lonHemisphere = parser.getLonHemisphere(); // èŽ·å–ç»åº¦åŠçƒï¼ˆE或W)
        String quality = parser.getQuality(); // èŽ·å–GPS定位质量
        String satellites = parser.getSatellites(); // èŽ·å–ä½¿ç”¨çš„å«æ˜Ÿæ•°é‡
        String hdop = parser.getHdop(); // èŽ·å–æ°´å¹³ç²¾åº¦å› å­
        String altitude = parser.getAltitude(); // èŽ·å–æµ·æ‹”é«˜åº¦
        String altitudeUnit = parser.getAltitudeUnit(); // èŽ·å–æµ·æ‹”å•ä½
        String geoidHeight = parser.getGeoidHeight(); // èŽ·å–å¤§åœ°æ°´å‡†é¢é«˜åº¦
        String geoidHeightUnit = parser.getGeoidHeightUnit(); // èŽ·å–å¤§åœ°æ°´å‡†é¢é«˜åº¦å•ä½
        String differentialTime = parser.getDifferentialTime(); // èŽ·å–å·®åˆ†æ—¶é—´
        String checksum = parser.getChecksum(); // èŽ·å–æ ¡éªŒå’Œ
        String deviceId = parser.getDeviceId(); // èŽ·å–è®¾å¤‡ID
        String battery = parser.getBattery(); // èŽ·å–ç”µæ± ç”µé‡
        String signalStrength = parser.getSignalStrength(); // èŽ·å–ä¿¡å·å¼ºåº¦
        String reserve1 = parser.getReserve1(); // èŽ·å–ä¿ç•™å­—æ®µ1
        String reserve2 = parser.getReserve2(); // èŽ·å–ä¿ç•™å­—æ®µ2
        String reserve3 = parser.getReserve3(); // èŽ·å–ä¿ç•™å­—æ®µ3
        String portStr = String.valueOf(port); // å°†ç«¯å£å·è½¬æ¢ä¸ºå­—符串
        String time = EfficientTimeFormatter.getCurrentTimeFormatted();
        Dell_tag.updateLocationTagProperty(deviceId, "utcTime",utcTime);
        Dell_tag.updateLocationTagProperty(deviceId, "deviceBattery",time);
        Dell_tag.updateLocationTagProperty(deviceId, "lastSatelliteSignalTime",time);
        Dell_tag.updateLocationTagProperty(deviceId, "gnGgaDataTime",time);
        Dell_tag.updateLocationTagProperty(deviceId, "latitude",latitude);
        Dell_tag.updateLocationTagProperty(deviceId, "longitude",longitude);
        Dell_tag.updateLocationTagProperty(deviceId, "satelliteQuality",quality);
        Dell_tag.updateLocationTagProperty(deviceId, "satelliteCount",satellites);
        Dell_tag.updateLocationTagProperty(deviceId, "altitude",altitude);
        Dell_tag.updateLocationTagProperty(deviceId, "ipAddress",ip);
        Dell_tag.updateLocationTagProperty(deviceId, "ipPort",portStr);
        Dell_tag.updateLocationTagProperty(deviceId, "onlineStatus","1");
        Dell_tag.updateLocationTagProperty(deviceId, "isSatelliteDevice","1");
        Dell_tag.updateLocationTagProperty(deviceId, "differentialTime",differentialTime);
        // åˆ›å»ºTrackData对象并添加到批量插入器
        TrackData trackData = new TrackData(
            parser.getDeviceId(),
            parser.getUtcTime(),
            parser.getLatitude(),
            parser.getLongitude(),
            parser.getQuality(),
            parser.getSatellites(),
            parser.getHdop(),
            parser.getAltitude(),
            parser.getGeoidHeight(),
            parser.getDifferentialTime(),
            parser.getBattery()
        );
        TrackDataBatchInserter.addTrackData(trackData);
    }
    private static void dellXTB(String data, String ip, int port) {
        String portStr = String.valueOf(port); // å°†ç«¯å£å·è½¬æ¢ä¸ºå­—符串
        XTB parser = dellXTB.get();
        parser.parse(data);
        String deviceId=parser.getDeviceId();// è®¾å¤‡ç¼–号
        String battery=parser.getBattery();// ç”µé‡
        String version=parser.getVersion();// ç‰ˆæœ¬å·
        String ccid=parser.getCcid();   // CCID
        String button=parser.getButton(); // æŒ‰é”®
        String rtcmSource=parser.getRtcmSource();
        Dell_tag.updateLocationTagProperty(deviceId, "ipAddress",ip);
        Dell_tag.updateLocationTagProperty(deviceId, "ipPort",portStr);
        Dell_tag.updateLocationTagProperty(deviceId, "RTKsource",rtcmSource);
        Dell_tag.updateLocationTagProperty(deviceId, "sosStatus",button);
        Dell_tag.updateLocationTagProperty(deviceId, "deviceCardNumber",ccid);
        Dell_tag.updateLocationTagProperty(deviceId, "deviceVersion",version);
    }
}
src/publicsWay/TableUtils.java
@@ -1,47 +1,110 @@
package publicsWay; // åŒ…声明
import javax.swing.*; // å¯¼å…¥Swing组件
import javax.swing.table.DefaultTableCellRenderer; // å¯¼å…¥è¡¨æ ¼å•元格渲染器
import javax.swing.table.DefaultTableModel; // å¯¼å…¥é»˜è®¤è¡¨æ ¼æ¨¡åž‹
import java.awt.*; // å¯¼å…¥AWT图形组件
package publicsWay;
public class TableUtils { // è¡¨æ ¼å·¥å…·ç±»
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import java.awt.*;
public class TableUtils {
    
    // åˆ›å»ºé€šç”¨è¡¨æ ¼çš„æ–¹æ³•
    // Create a styled table with specified column names
    @SuppressWarnings("serial")
    public static JTable createCommonTable(String[] columnNames) { // é™æ€æ–¹æ³•可直接调用
        // åˆ›å»ºè¡¨æ ¼æ¨¡åž‹ - åŒ¿åå†…部类扩展DefaultTableModel
        DefaultTableModel model = new DefaultTableModel(columnNames, 0) { // åˆå§‹åŒ–表格模型
    public static JTable createCommonTable(String[] columnNames) {
        // Create table model
        DefaultTableModel model = new DefaultTableModel(columnNames, 0) {
            @Override
            public boolean isCellEditable(int row, int column) { // é‡å†™å•元格可编辑性
                return false; // æ‰€æœ‰å•元格不可编辑
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        
        // åˆ›å»ºè¡¨æ ¼å®žä¾‹
        JTable table = new JTable(model); // ä½¿ç”¨è‡ªå®šä¹‰æ¨¡åž‹åˆ›å»ºè¡¨æ ¼
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // è®¾ç½®å•选模式
        // Create table instance
        JTable table = new JTable(model);
        table.setAutoCreateRowSorter(true);
        table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        
        // åˆ›å»ºè¡¨å¤´æ¸²æŸ“器
        DefaultTableCellRenderer headerRenderer = createHeaderRenderer(); // è°ƒç”¨æ¸²æŸ“器创建方法
        // Apply table styling
        setupTableStyle(table);
        
        // åº”用表头渲染器到所有列
        for (int i = 0; i < table.getColumnCount(); i++) { // éåŽ†æ‰€æœ‰åˆ—
            table.getColumnModel().getColumn(i).setHeaderRenderer(headerRenderer); // è®¾ç½®åˆ—头渲染器
        }
        // Apply header styling
        setupTableHeaderStyle(table);
        
        return table; // è¿”回配置好的表格实例
        return table;
    }
    
    // åˆ›å»ºè¡¨å¤´æ¸²æŸ“器
    // Setup basic table styling
    public static void setupTableStyle(JTable table) {
        table.setShowVerticalLines(false);
        table.setShowHorizontalLines(true);
        table.setGridColor(new Color(220, 220, 220));
        table.setIntercellSpacing(new Dimension(0, 1));
        table.setRowHeight(25);
    }
    // Setup table header styling
    public static void setupTableHeaderStyle(JTable table) {
        JTableHeader header = table.getTableHeader();
        header.setBackground(new Color(70, 130, 180));
        header.setForeground(Color.WHITE);
        header.setFont(header.getFont().deriveFont(Font.BOLD));
        header.setPreferredSize(new Dimension(header.getWidth(), 30));
        // Create and apply header renderer
        DefaultTableCellRenderer headerRenderer = createHeaderRenderer();
        for (int i = 0; i < table.getColumnCount(); i++) {
            table.getColumnModel().getColumn(i).setHeaderRenderer(headerRenderer);
        }
    }
    // Create header renderer
    @SuppressWarnings("serial")
    private static DefaultTableCellRenderer createHeaderRenderer() { // ç§æœ‰å·¥å…·æ–¹æ³•
        return new DefaultTableCellRenderer() { // è¿”回匿名内部类实例
            { // å®žä¾‹åˆå§‹åŒ–块
                setHorizontalAlignment(SwingConstants.LEFT); // è®¾ç½®è¡¨å¤´æ–‡æœ¬å·¦å¯¹é½
                setBackground(Color.GRAY); // è®¾ç½®è¡¨å¤´èƒŒæ™¯ä¸ºç°è‰²
                setForeground(Color.WHITE); // è®¾ç½®è¡¨å¤´æ–‡å­—为白色
                setFont(getFont().deriveFont(Font.BOLD)); // è®¾ç½®è¡¨å¤´å­—体加粗
    private static DefaultTableCellRenderer createHeaderRenderer() {
        return new DefaultTableCellRenderer() {
            {
                setHorizontalAlignment(SwingConstants.CENTER);
                setBackground(new Color(70, 130, 180));
                setForeground(Color.WHITE);
                setFont(getFont().deriveFont(Font.BOLD));
                setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            }
        };
    }
    // Create cell renderer with zebra striping
    @SuppressWarnings("serial")
    public static DefaultTableCellRenderer createCellRenderer(int alignment) {
        return new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus,
                    int row, int column) {
                Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                // Set alternating row colors
                if (!isSelected) {
                    if (row % 2 == 0) {
                        c.setBackground(new Color(240, 240, 200));
                    } else {
                        c.setBackground(Color.WHITE);
                    }
                } else {
                    c.setBackground(new Color(200, 220, 240));
                }
                // Set cell alignment
                setHorizontalAlignment(alignment);
                // Set cell padding
                setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
                return c;
            }
        };
    }
    // Create centered cell renderer with zebra striping (most common case)
    public static DefaultTableCellRenderer createCenteredCellRenderer() {
        return createCellRenderer(SwingConstants.CENTER);
    }
}
src/publicsWay/TrackData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,177 @@
package publicsWay;
public class TrackData {
    public String deviceNumber; // è®¾å¤‡ç¼–号
    public String deviceName; // è®¾å¤‡åç§°
    public String xCoordinate; // X坐标
    public String yCoordinate; // Y坐标
    public String zCoordinate; // Z坐标
    public String layer; // å±‚级
    public String battery; // ç”µæ± ç”µé‡
    public String utcTimes; // UTC时间
    public String latitude; // çº¬åº¦
    public String longitude; // ç»åº¦
    public String positioningQuality; // å®šä½è´¨é‡
    public String satelliteCount; // å«æ˜Ÿæ•°é‡
    public String hdop; // æ°´å¹³ç²¾åº¦å› å­
    public String altitude; // æµ·æ‹”高度
    public String geoidHeight; // åœ°çƒé«˜ç¨‹
    public String differentialTime; // å·®åˆ†æ—¶é—´
    public String source; // æ•°æ®æ¥æº
    public String company; // å…¬å¸åç§°
    public String saveTime; // ä¿å­˜æ—¶é—´
    public TrackData(
            String deviceNumber, // è®¾å¤‡ç¼–号
            String deviceName, // è®¾å¤‡åç§°
            String xCoordinate, // X坐标
            String yCoordinate, // Y坐标
            String zCoordinate, // Z坐标
            String layer, // å±‚级
            String battery, // ç”µæ± ç”µé‡
            String utcTimes, // UTC时间
            String latitude, // çº¬åº¦
            String longitude, // ç»åº¦
            String positioningQuality, // å®šä½è´¨é‡
            String satelliteCount, // å«æ˜Ÿæ•°é‡
            String hdop, // æ°´å¹³ç²¾åº¦å› å­
            String altitude, // æµ·æ‹”高度
            String geoidHeight, // åœ°çƒé«˜ç¨‹
            String differentialTime, // å·®åˆ†æ—¶é—´
            String source, // æ•°æ®æ¥æº
            String company, // å…¬å¸åç§°
            String saveTime) {
        this.deviceNumber = deviceNumber;
        this.deviceName = deviceName; // è¡¥å……初始化
        this.xCoordinate = xCoordinate; // è¡¥å……初始化
        this.yCoordinate = yCoordinate; // è¡¥å……初始化
        this.zCoordinate = zCoordinate; // è¡¥å……初始化
        this.layer = layer; // è¡¥å……初始化
        this.battery = battery;
        this.utcTimes = utcTimes;
        this.latitude = latitude;
        this.longitude = longitude;
        this.positioningQuality = positioningQuality;
        this.satelliteCount = satelliteCount;
        this.hdop = hdop;
        this.altitude = altitude;
        this.geoidHeight = geoidHeight;
        this.differentialTime = differentialTime;
        this.source = source; // ä½¿ç”¨ä¼ å…¥çš„ source å‚æ•°
        this.company = company; // è¡¥å……初始化
        this.saveTime = saveTime; // ä½¿ç”¨ä¼ å…¥çš„ saveTime å‚æ•°
    }
    public String getDeviceNumber() {
        return deviceNumber;
    }
    public String getDeviceName() {
        return deviceName;
    }
    public String getxCoordinate() {
        return xCoordinate;
    }
    public String getyCoordinate() {
        return yCoordinate;
    }
    public String getzCoordinate() {
        return zCoordinate;
    }
    public String getLayer() {
        return layer;
    }
    public String getBattery() {
        return battery;
    }
    public String getUtcTimes() {
        return utcTimes;
    }
    public String getLatitude() {
        return latitude;
    }
    public String getLongitude() {
        return longitude;
    }
    public String getPositioningQuality() {
        return positioningQuality;
    }
    public String getSatelliteCount() {
        return satelliteCount;
    }
    public String getHdop() {
        return hdop;
    }
    public String getAltitude() {
        return altitude;
    }
    public String getGeoidHeight() {
        return geoidHeight;
    }
    public String getDifferentialTime() {
        return differentialTime;
    }
    public String getSource() {
        return source;
    }
    public String getCompany() {
        return company;
    }
    public String getSaveTime() {
        return saveTime;
    }
    public void setDeviceNumber(String deviceNumber) {
        this.deviceNumber = deviceNumber;
    }
    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }
    public void setxCoordinate(String xCoordinate) {
        this.xCoordinate = xCoordinate;
    }
    public void setyCoordinate(String yCoordinate) {
        this.yCoordinate = yCoordinate;
    }
    public void setzCoordinate(String zCoordinate) {
        this.zCoordinate = zCoordinate;
    }
    public void setLayer(String layer) {
        this.layer = layer;
    }
    public void setBattery(String battery) {
        this.battery = battery;
    }
    public void setUtcTimes(String utcTimes) {
        this.utcTimes = utcTimes;
    }
    public void setLatitude(String latitude) {
        this.latitude = latitude;
    }
    public void setLongitude(String longitude) {
        this.longitude = longitude;
    }
    public void setPositioningQuality(String positioningQuality) {
        this.positioningQuality = positioningQuality;
    }
    public void setSatelliteCount(String satelliteCount) {
        this.satelliteCount = satelliteCount;
    }
    public void setHdop(String hdop) {
        this.hdop = hdop;
    }
    public void setAltitude(String altitude) {
        this.altitude = altitude;
    }
    public void setGeoidHeight(String geoidHeight) {
        this.geoidHeight = geoidHeight;
    }
    public void setDifferentialTime(String differentialTime) {
        this.differentialTime = differentialTime;
    }
    public void setSource(String source) {
        this.source = source;
    }
    public void setCompany(String company) {
        this.company = company;
    }
    public void setSaveTime(String saveTime) {
        this.saveTime = saveTime;
    }
}
src/publicsWay/TrackDataBatchInserter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,122 @@
package publicsWay;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import databases.DBConnector;
import scheduled_task.TrackTableManager;
public class TrackDataBatchInserter {
    private static final int BATCH_SIZE = 1000;
    private static final long BATCH_INTERVAL_MS = 1000;
    private static final int MAX_QUEUE_SIZE = 100000;
    private static final ConcurrentLinkedQueue<TrackData> trackDataQueue = new ConcurrentLinkedQueue<>();
    private static final ScheduledExecutorService batchInsertExecutor = Executors.newSingleThreadScheduledExecutor();
    static {
        batchInsertExecutor.scheduleAtFixedRate(() -> {
            try {
                batchInsertTrackData();
            } catch (Exception e) {
                System.err.println("批量插入数据异常: " + e.getMessage());
            }
        }, BATCH_INTERVAL_MS, BATCH_INTERVAL_MS, TimeUnit.MILLISECONDS);
    }
    // æ·»åŠ æ•°æ®åˆ°é˜Ÿåˆ—
    public static void addTrackData(TrackData data) {
        if (trackDataQueue.size() < MAX_QUEUE_SIZE) {
            trackDataQueue.offer(data);
        }
    }
    private static void batchInsertTrackData() {
        if (trackDataQueue.isEmpty()) {
            return;
        }
        String tableName = "tb_track_" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
        List<TrackData> batchList = new ArrayList<>(BATCH_SIZE);
        int count = 0;
        while (count < BATCH_SIZE && !trackDataQueue.isEmpty()) {
            TrackData data = trackDataQueue.poll();
            if (data != null) {
                batchList.add(data);
                count++;
            }
        }
        if (batchList.isEmpty()) {
            return;
        }
        try {
            // ä½¿ç”¨DBConnector检查表是否存在,不存在则创建
            if (!DBConnector.tableExists(tableName)) {
                DBConnector.executeDDL(TrackTableManager.getcreateSQL(tableName));
            }
            // å‡†å¤‡æ‰¹é‡æ’入数据
            List<Object[]> paramsList = new ArrayList<>();
            for (TrackData data : batchList) {
                Object[] params = new Object[]{
                    data.getDeviceNumber(),
                    data.getDeviceName(),
                    data.getxCoordinate(),
                    data.getxCoordinate(),
                    data.getxCoordinate(),
                    data.getLayer(),
                    data.getBattery(),
                    data.getUtcTimes(),
                    data.getLatitude(),
                    data.getLongitude(),
                    data.getPositioningQuality(),
                    data.getSatelliteCount(),
                    data.getHdop(),
                    data.getAltitude(),
                    data.getGeoidHeight(),
                    data.getDifferentialTime(),
                    data.getSource(),
                    data.getCompany(),
                    data.getSaveTime()
                };
                paramsList.add(params);
            }
            // ä½¿ç”¨DBConnector进行批量插入
            String sql = "INSERT INTO " + tableName + " (device_number, device_name, x_coordinate, " +
                       "y_coordinate, z_coordinate, layer, battery, utc_times, latitude, longitude, " +
                       "positioning_quality, satellite_count, hdop, altitude, geoid_height, " +
                       "differential_time, source, company, save_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            DBConnector.executeBatchUpdate(sql, paramsList);
        } catch (Exception e) {
            System.err.println("批量插入数据表异常: " + e.getMessage());
            // å°†é”™è¯¯çš„æ•°æ®é‡æ–°æ”¾å›žé˜Ÿåˆ—
            trackDataQueue.addAll(batchList);
        }
    }
    // å…³é—­æ‰¹é‡æ’入服务
    public static void shutdown() {
        batchInsertExecutor.shutdown();
        try {
            if (!batchInsertExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                batchInsertExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            batchInsertExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}
src/scheduled_task/TrackTableManager.java
@@ -7,21 +7,18 @@
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import dell_targets.Dell_SystemConfiguration;
import databases.DBConnector;  // æ·»åР坼入
public class TrackTableManager {
    // é…ç½®å‚æ•°
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/your_database?useSSL=false";
    private static final String USERNAME = "your_username";
    private static final String PASSWORD = "your_password";
    private static final int SAVE_DAYS = 30; // è½¨è¿¹æ•°æ®ä¿å­˜å¤©æ•°
    // ç§»é™¤ç¡¬ç¼–码的数据库连接参数
    private static final int SAVE_DAYS = Dell_SystemConfiguration.TrajectoryRetentionDays;
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final String TABLE_PREFIX = "tb_track_";
    public static void main(String[] args) {
    public static void Start() {
        // åˆå§‹åŒ–时立即执行一次
        manageTables();
        manageTables();
        // åˆ›å»ºå®šæ—¶ä»»åŠ¡ï¼ˆæ¯å¤©å‡Œæ™¨1点执行)
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(
@@ -34,85 +31,85 @@
    // ä¸»ç®¡ç†é€»è¾‘
    private static void manageTables() {
        try (Connection conn = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD)) {
            // 1. åˆ›å»ºæ˜Žå¤©çš„表
            createTomorrowTable(conn);
        try {
            // 1. åˆ›å»ºæœªæ¥3天的表
            createFutureTables();
            
            // 2. åˆ é™¤è¿‡æœŸè¡¨
            deleteExpiredTables(conn);
            deleteExpiredTables();
            
        } catch (SQLException e) {
            System.err.println("数据库操作失败: " + e.getMessage());
        }
    }
    // åˆ›å»ºæ˜Žå¤©çš„表
    private static void createTomorrowTable(Connection conn) throws SQLException {
        String tomorrow = LocalDate.now().plusDays(1).format(DATE_FORMATTER);
        String tableName = TABLE_PREFIX + tomorrow;
        if (!tableExists(conn, tableName)) {
            String createSQL = "CREATE TABLE " + tableName + " (" +
                "id INT(30) PRIMARY KEY AUTO_INCREMENT COMMENT '序号'," +
                "device_number VARCHAR(30) NOT NULL COMMENT '设备编号'," +
                "device_name VARCHAR(30) COMMENT '设备名称'," +
                "x_coordinate VARCHAR(30) COMMENT 'X坐标'," +
                "y_coordinate VARCHAR(30) COMMENT 'Y坐标'," +
                "z_coordinate VARCHAR(30) COMMENT 'Z坐标'," +
                "layer VARCHAR(30) COMMENT '所在层'," +
                "battery VARCHAR(30) COMMENT '电量'," +
                "utc_times VARCHAR(30) COMMENT 'UTC时间'," +
                "latitude VARCHAR(30) COMMENT '纬度'," +
                "longitude VARCHAR(30) COMMENT '经度'," +
                "positioning_quality VARCHAR(30) COMMENT '定位质量'," +
                "satellite_count VARCHAR(30) COMMENT '卫星数量'," +
                "hdop VARCHAR(30) COMMENT '水平精度因子'," +
                "altitude VARCHAR(30) COMMENT '海拔高度'," +
                "geoid_height VARCHAR(30) COMMENT '大地水准面高度'," +
                "differential_time VARCHAR(30) COMMENT '差分时间'," +
                "source VARCHAR(30) COMMENT '定位结果来源(0=UWB,1=卫星,3=蓝牙)'," +
                "company VARCHAR(30) COMMENT '所属公司'," +
                "save_time VARCHAR(30) COMMENT '保存时间'" +
                ") ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='轨迹记录表'";
            try (Statement stmt = conn.createStatement()) {
                stmt.executeUpdate(createSQL);
                System.out.println("表创建成功: " + tableName);
            }
        } else {
            System.out.println("表已存在: " + tableName);
    // åˆ›å»ºæœªæ¥3天的表(包括明天、后天和大后天)
    private static void createFutureTables() throws SQLException {
        for (int i = 1; i <= 3; i++) {
            String futureDate = LocalDate.now().plusDays(i).format(DATE_FORMATTER);
            String tableName = TABLE_PREFIX + futureDate;
            if (!tableExists(tableName)) {
                DBConnector.executeUpdate(getcreateSQL(tableName));
            }
        }
    }
    // åˆ é™¤è¿‡æœŸè¡¨
    private static void deleteExpiredTables(Connection conn) throws SQLException {
    private static void deleteExpiredTables() throws SQLException {
        LocalDate thresholdDate = LocalDate.now().minusDays(SAVE_DAYS);
        String threshold = thresholdDate.format(DATE_FORMATTER);
        
        for (String table : getAllTrackTables(conn)) {
        for (String table : getAllTrackTables()) {
            String datePart = table.substring(TABLE_PREFIX.length());
            if (datePart.compareTo(threshold) < 0) {
                try (Statement stmt = conn.createStatement()) {
                    stmt.executeUpdate("DROP TABLE " + table);
                    System.out.println("已删除过期表: " + table);
                }
                DBConnector.executeUpdate("DROP TABLE " + table);
            }
        }
    }
    public static String getcreateSQL(String tableName) {
         String createSQL = "CREATE TABLE " + tableName + " (" +
                 "id INT(30) PRIMARY KEY AUTO_INCREMENT COMMENT '序号'," +
                 "device_number VARCHAR(30) NOT NULL COMMENT '设备编号'," +
                 "device_name VARCHAR(30) COMMENT '设备名称'," +
                 "x_coordinate VARCHAR(30) COMMENT 'X坐标'," +
                 "y_coordinate VARCHAR(30) COMMENT 'Y坐标'," +
                 "z_coordinate VARCHAR(30) COMMENT 'Z坐标'," +
                 "layer VARCHAR(30) COMMENT '所在层'," +
                 "battery VARCHAR(30) COMMENT '电量'," +
                 "utc_times VARCHAR(30) COMMENT 'UTC时间'," +
                 "latitude VARCHAR(30) COMMENT '纬度'," +
                 "longitude VARCHAR(30) COMMENT '经度'," +
                 "positioning_quality VARCHAR(30) COMMENT '定位质量'," +
                 "satellite_count VARCHAR(30) COMMENT '卫星数量'," +
                 "hdop VARCHAR(30) COMMENT '水平精度因子'," +
                 "altitude VARCHAR(30) COMMENT '海拔高度'," +
                 "geoid_height VARCHAR(30) COMMENT '大地水准面高度'," +
                 "differential_time VARCHAR(30) COMMENT '差分时间'," +
                 "source VARCHAR(30) COMMENT '定位结果来源(0=UWB,1=卫星,3=蓝牙)'," +
                 "company VARCHAR(30) COMMENT '所属公司'," +
                 "save_time VARCHAR(30) COMMENT '保存时间'" +
                 ") ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='轨迹记录表'";
        return createSQL;
    }
    // æ£€æŸ¥è¡¨æ˜¯å¦å­˜åœ¨
    private static boolean tableExists(Connection conn, String tableName) throws SQLException {
        try (ResultSet rs = conn.getMetaData().getTables(null, null, tableName, null)) {
            return rs.next();
    private static boolean tableExists(String tableName) throws SQLException {
        try (ResultSet rs = DBConnector.executeQuery(
            "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?",
            tableName)) {
            return rs.next() && rs.getInt(1) > 0;
        }
    }
    // èŽ·å–æ‰€æœ‰è½¨è¿¹è¡¨
    private static List<String> getAllTrackTables(Connection conn) throws SQLException {
    private static List<String> getAllTrackTables() throws SQLException {
        List<String> tables = new ArrayList<>();
        try (ResultSet rs = conn.getMetaData().getTables(null, null, TABLE_PREFIX + "%", null)) {
        try (ResultSet rs = DBConnector.executeQuery(
            "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name LIKE ?",
            TABLE_PREFIX + "%")) {
            while (rs.next()) {
                tables.add(rs.getString("TABLE_NAME"));
                tables.add(rs.getString("table_name"));
            }
        }
        return tables;
src/targets/LocationTag.java
@@ -90,7 +90,11 @@
    public String InteractionType;
    public String ipAddress;
    public String ipPort;
    public String gnGgaDataTime;//接收到gngga数据时间
    public String satelliteChipType;//卫星芯片类型
    public String AutoUpgraded;//完成了自动升级
    public String isSatelliteDevice;//是否是卫星定位设备,-1不知道1是0不是
    public String RTKsource;//差分源
        // Getter和Setter方法
    public int getId() {
        return id;
@@ -801,4 +805,44 @@
    public void setIpPort(String ipPort) {
        this.ipPort = ipPort;
    }
    public String getGnGgaDataTime() {
        return gnGgaDataTime;
    }
    public String getSatelliteChipType() {
        return satelliteChipType;
    }
    public void setGnGgaDataTime(String gnGgaDataTime) {
        this.gnGgaDataTime = gnGgaDataTime;
    }
    public void setSatelliteChipType(String satelliteChipType) {
        this.satelliteChipType = satelliteChipType;
    }
    public String  getAutoUpgraded() {
        return AutoUpgraded;
    }
    public void setAutoUpgraded(String autoUpgraded) {
        AutoUpgraded = autoUpgraded;
    }
    public String getIsSatelliteDevice() {
        return isSatelliteDevice;
    }
    public void setIsSatelliteDevice(String isSatelliteDevice) {
        this.isSatelliteDevice = isSatelliteDevice;
    }
    public String getRTKsource() {
        return RTKsource;
    }
    public void setRTKsource(String rTKsource) {
        RTKsource = rTKsource;
    }
}
src/udptcp/UDPPortAReceiver.java
ÎļþÃû´Ó src/publicsWay/UDPPortAReceiver.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
package publicsWay;
package udptcp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
@@ -8,6 +8,7 @@
import dell_system.MessageViewPanel;
import dell_targets.Dell_SystemConfiguration;
import publicsWay.PacketProcessingSystem;
public class UDPPortAReceiver {
    public static final int PORT =Dell_SystemConfiguration.hexport;
src/udptcp/UDPPortBReceiver.java
@@ -2,112 +2,112 @@
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import publicsWay.PacketProcessingSystem;
import dell_system.MessageViewPanel;
import dell_targets.Dell_SystemConfiguration;
import publicsWay.PacketProcessingSystemB;
public class UDPPortBReceiver {
    public static final int PORT = 7000;
    @SuppressWarnings("unused")
    public static final int PORT =Dell_SystemConfiguration.ascallport;
    @SuppressWarnings("unused")
    private static final int MAX_DEVICES = 50000;
    private static final AtomicLong packetCount = new AtomicLong(0);
    private static final ExecutorService executor = Executors.newFixedThreadPool(10);
    private static DatagramSocket socket;
    private static volatile boolean isRunning = false;
    private static Thread receiverThread;
    @SuppressWarnings("unused")
    private static final AtomicLong packetCount = new AtomicLong(0);
    private static final ExecutorService executor = Executors.newFixedThreadPool(10);
    private static DatagramSocket socket;
    private static volatile boolean isRunning = false;
    private static Thread receiverThread;
    @SuppressWarnings("unused")
    private static final int LOCAL_PORT = PORT; // å®šä¹‰æœ¬åœ°ç«¯å£
    // å¯åŠ¨æŽ¥æ”¶å™¨çš„é™æ€æ–¹æ³•
    public static void startReceiver() {
        if (isRunning) return;
        isRunning = true;
        receiverThread = new Thread(() -> {
            try {
                socket = new DatagramSocket(PORT);
                byte[] buffer = new byte[2048];
                while (isRunning) {
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    socket.receive(packet);
                    executor.execute(() -> {
                        try {
                            String ip = packet.getAddress().getHostAddress();
                            int port = packet.getPort();
                            String hexData = bytesToHex(packet.getData(), packet.getLength());
                            // è°ƒç”¨æ—¶æ·»åŠ æœ¬åœ°ç«¯å£å‚æ•°
                            PacketProcessingSystem.storePacket(ip, port, hexData);
                        } catch (Exception e) {
                            System.err.println("Error processing UDP-A packet: " + e.getMessage());
                        }
                    });
                }
            } catch (Exception e) {
                System.err.println("UDP-A Server crashed: " + e.getMessage());
            } finally {
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
            }
        });
        receiverThread.setDaemon(true);
        receiverThread.start();
    }
    // åœæ­¢æŽ¥æ”¶å™¨
    public static void stopReceiver() {
        isRunning = false;
        if (socket != null && !socket.isClosed()) {
            socket.close();
        }
        executor.shutdown();
    }
    // å‘送数据到指定设备
    public static void sendData(String ip, int port, String data, boolean isHex) {
        try {
            byte[] sendBytes;
            if (isHex) {
                // HEX格式发送:将十六进制字符串转换为字节数组
                sendBytes = hexStringToByteArray(data);
            } else {
                // ASCII格式发送:直接获取字节数组
                sendBytes = data.getBytes();
            }
            InetAddress address = InetAddress.getByName(ip);
            DatagramPacket packet = new DatagramPacket(sendBytes, sendBytes.length, address, port);
            socket.send(packet);
        } catch (Exception e) {
            System.err.println("Error sending UDP data: " + e.getMessage());
        }
    }
    private static String bytesToHex(byte[] bytes, int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(String.format("%02X", bytes[i]));
        }
        return sb.toString();
    }
    private static byte[] hexStringToByteArray(String hex) {
        hex = hex.replaceAll("\\s", ""); // ç§»é™¤æ‰€æœ‰ç©ºæ ¼
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // å¤„理每两个字符作为一个字节
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                                 + Character.digit(hex.charAt(i+1), 16));
        }
        return data;
    }
    // å¯åŠ¨æŽ¥æ”¶å™¨çš„é™æ€æ–¹æ³•
    public static void startReceiver() {
        if (isRunning) return;
    public static long getPacketCount() {
        return packetCount.get();
    }
        isRunning = true;
        receiverThread = new Thread(() -> {
            try {
                socket = new DatagramSocket(PORT);
                byte[] buffer = new byte[2048];
                while (isRunning) {
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    socket.receive(packet);
                    executor.execute(() -> {
                        try {
                            String ip = packet.getAddress().getHostAddress();
                            int port = packet.getPort();
                            //String hexData = bytesToHex(packet.getData(), packet.getLength());
                            String asciiData = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.US_ASCII);
                            // åŽ»æŽ‰å›žè½¦å’Œæ¢è¡Œ
                            asciiData = asciiData.replaceAll("\r", "").replaceAll("\n", "");
                            // è°ƒç”¨æ—¶æ·»åŠ æœ¬åœ°ç«¯å£å‚æ•°
                            PacketProcessingSystemB.storePacket(ip, port, asciiData);
                            // æŠ¥æ–‡æŸ¥çœ‹çª—口显示数据
                            MessageViewPanel.showData(asciiData, ip, port, PORT,"UDPB","ALL","ALL");
                            packetCount.incrementAndGet();  // å…³é”®ä¿®å¤ï¼šå¢žåŠ è®¡æ•°å™¨
                        } catch (Exception e) {
                            System.err.println("Error processing UDP-B packet: " + e.getMessage());
                        }
                    });
                }
            } catch (Exception e) {
                System.err.println("UDP-B Server crashed: " + e.getMessage());
            } finally {
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
            }
        });
        receiverThread.setDaemon(true);
        receiverThread.start();
    }
    // åœæ­¢æŽ¥æ”¶å™¨
    public static void stopReceiver() {
        isRunning = false;
        if (socket != null && !socket.isClosed()) {
            socket.close();
        }
        executor.shutdown();
    }
    // å‘送数据到指定设备
    public static void sendData(String ip, int port, String data, boolean isHex) {
        try {
            byte[] sendBytes;
            if (isHex) {
                // HEX格式发送:将十六进制字符串转换为字节数组
                sendBytes = hexStringToByteArray(data);
            } else {
                // ASCII格式发送:直接获取字节数组
                sendBytes = data.getBytes();
            }
            InetAddress address = InetAddress.getByName(ip);
            DatagramPacket packet = new DatagramPacket(sendBytes, sendBytes.length, address, port);
            socket.send(packet);
        } catch (Exception e) {
            System.err.println("Error sending UDP data: " + e.getMessage());
        }
    }
    private static byte[] hexStringToByteArray(String hex) {
        hex = hex.replaceAll("\\s", ""); // ç§»é™¤æ‰€æœ‰ç©ºæ ¼
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // å¤„理每两个字符作为一个字节
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i+1), 16));
        }
        return data;
    }
    public static long getPacketCount() {
        return packetCount.get();
    }
}
src/window/ContentPanelFactory.java
@@ -15,6 +15,7 @@
import dell_system.VersionInfoPanel;
import dell_targets.BatteryRecordPanel;
import dell_targets.DifferentialBaseStationManagementPanel;
import dell_targets.SatelliteDevicePanel;
import dell_targets.TagManagementPanel;
import dell_targets.TagTypeManagementPanel;
import javax.swing.*;
@@ -120,6 +121,8 @@
                panel.add(new QuickCalculationPanel(messages), BorderLayout.CENTER);
            } else if (nodeName.equals(messages.getString("Serial_Port_Tool"))) {// ä¸²å£å·¥å…·              
                panel.add(new SerialCommPanel(messages), BorderLayout.CENTER);
            }else if (nodeName.equals(messages.getString("SatelliteEquipment"))) {//卫星设备
                panel.add(new SatelliteDevicePanel(messages), BorderLayout.CENTER);
            } else {
                // å¯¹äºŽæœªå®žçŽ°åŠŸèƒ½ï¼Œæ˜¾ç¤ºå¼€å‘ä¸­æç¤º
                JLabel label = new JLabel(messages.getString("DEVELOPING") + ": " + nodeName, SwingConstants.CENTER);
src/window/NavigationTreeFactory.java
@@ -30,7 +30,8 @@
        deviceNode.add(new DefaultMutableTreeNode(messages.getString("BASE_MANAGEMENT")));      // åŸºç«™ç®¡ç†
        deviceNode.add(new DefaultMutableTreeNode(messages.getString("GATEWAY_MANAGEMENT")));   // ç½‘关管理
        deviceNode.add(new DefaultMutableTreeNode(messages.getString("DIFF_BASE")));            // å·®åˆ†åŸºç«™
        deviceNode.add(new DefaultMutableTreeNode(messages.getString("TAG_TYPE")));             // æ ‡ç­¾ç±»åž‹
        deviceNode.add(new DefaultMutableTreeNode(messages.getString("TAG_TYPE")));
        deviceNode.add(new DefaultMutableTreeNode(messages.getString("SatelliteEquipment")));  // å«æ˜Ÿè®¾å¤‡
        root.add(deviceNode);
        
        // ç®—法节点 (一级)
src/window/WelcomeFrame.java
@@ -9,10 +9,10 @@
import java.util.ResourceBundle;
import udptcp.UDPPortAReceiver;
import udptcp.UDPPortBReceiver;
import dell_targets.Dell_BaseStation;
import dell_targets.Dell_tag;
import publicsWay.UDPPortAReceiver;
import dell_targets.Dell_SystemConfiguration;
public class WelcomeFrame extends JInternalFrame {
systemfile/Messages_en.properties
@@ -1,3 +1,45 @@
RtkSource=RtkSource
UPGRADE_DEVICE_ELLIPSIS=...
UPGRADE_DEVICE_UNIT=device(s)
UPGRADE_CONFIRMATION_HEADER=Preparing to upgrade the following devices:
FIRMWARE_URL_LABEL=Firmware URL
TOTAL_DEVICES_COUNT=Total devices: %d
UPGRADE_DEVICES_WITH_URL=Preparing to upgrade %d devices, device IDs: %s, firmware address: %s
SET_UPGRADE_CONDITIONS=SetUpgradeConditions
BY_COMPANY_NAME=ByCompanyName
COMPANY = Company
COMMAND_SEND = Command Send
FIRMWARE_URL = Firmware URL
ENTER_FIRMWARE_DOWNLOAD_URL = Enter the firmware download URL
FIRMWARE_URL_REQUIRED = Firmware download URL is required
UPGRADE_DEVICES_WITH_URL = Upgrading %d devices with firmware URL: %s
SEND_COMMAND = Send Command
SatelliteEquipment=SatelliteEquipment
QUICK_OPERATION=Quick Operation
SELECT=Select
INDEX=Index
DEVICE_NUMBER=Device Number
LONGITUDE=Longitude
LATITUDE=Latitude
ALTITUDE=Altitude
STATUS=Status
SATELLITE_COUNT=Satellite Count
DIFFERENTIAL_TIME=Differential Time
VERSION=Version
CARD_NUMBER=Card Number
ADDRESS=Address
PORT=Port
UPDATE_TIME=Update Time
UPGRADE_CONDITION=Upgrade Condition
BY_VERSION=By Version
BY_NUMBER=By Number
BY_SELECTED_DEVICE=By Selected Device
START_UPGRADE=Start Upgrade
UPGRADE_VALUE_REQUIRED=Upgrade value is required
SELECT_DEVICE_TO_UPGRADE=Select device to upgrade
UPGRADE_SELECTED_DEVICES=Start upgrading the selected %d devices
UPGRADE_BY_VERSION=Start upgrading devices with version %s
UPGRADE_BY_NUMBER=Start upgrading device with number %s
TAG_STATS = Tag Statistics  
BASE_STATION_STATS = Base Station Statistics  
SOFTWARE_VERSION = Software Version  
systemfile/Messages_zh.properties
@@ -1,3 +1,46 @@
# å«æ˜Ÿè®¾å¤‡ç®¡ç†ç›¸å…³èµ„源
RtkSource=差分源
UPGRADE_DEVICE_ELLIPSIS=... (共
UPGRADE_DEVICE_UNIT=个设备)
UPGRADE_CONFIRMATION_HEADER=准备升级以下设备:\n
FIRMWARE_URL_LABEL=固件地址
TOTAL_DEVICES_COUNT=总共 %d ä¸ªè®¾å¤‡
UPGRADE_DEVICES_WITH_URL=准备升级 %d ä¸ªè®¾å¤‡ï¼Œè®¾å¤‡ç¼–号:%s,固件地址:%s
SET_UPGRADE_CONDITIONS=设置升级条件
BY_COMPANY_NAME=根据公司名称
COMPANY=所属公司
COMMAND_SEND=指令发送
FIRMWARE_URL=固件地址
ENTER_FIRMWARE_DOWNLOAD_URL=录入需要升级固件下载地址
FIRMWARE_URL_REQUIRED=请输入固件下载地址
UPGRADE_DEVICES_WITH_URL=将为%d个设备执行升级,固件地址:%s
SEND_COMMAND=发送指令
SatelliteEquipment=卫星设备
QUICK_OPERATION=快捷操作
SELECT=选择
INDEX=序号
DEVICE_NUMBER=编号
LONGITUDE=经度
LATITUDE=纬度
ALTITUDE=高程
STATUS=状态
SATELLITE_COUNT=卫星数
DIFFERENTIAL_TIME=差分时间
VERSION=版本
CARD_NUMBER=卡号
ADDRESS=地址
PORT=端口
UPDATE_TIME=更新时间
UPGRADE_CONDITION=升级条件
BY_VERSION=根据版本
BY_NUMBER=根据编号
BY_SELECTED_DEVICE=根据选中的设备
START_UPGRADE=启动升级
UPGRADE_VALUE_REQUIRED=请输入升级条件值
SELECT_DEVICE_TO_UPGRADE=请选择要升级的设备
UPGRADE_SELECTED_DEVICES=开始升级选中的 %d ä¸ªè®¾å¤‡
UPGRADE_BY_VERSION=开始升级版本为 %s çš„设备
UPGRADE_BY_NUMBER=开始升级设备编号为 %s çš„设备
TAG_STATS=标签统计
BASE_STATION_STATS=基站统计
SOFTWARE_VERSION=软件版本
systemfile/logfile/openlog.txt
@@ -960,3 +960,297 @@
工作时长: 0小时 0分钟 25秒
-----------------------------------
程序启动: 2025-08-11 23:04:55
程序关闭: 2025-08-11 23:15:52
工作时长: 0小时 10分钟 57秒
-----------------------------------
程序启动: 2025-08-12 21:50:17
程序关闭: 2025-08-12 21:52:16
工作时长: 0小时 1分钟 58秒
-----------------------------------
程序启动: 2025-08-12 21:52:33
程序关闭: 2025-08-12 21:52:57
工作时长: 0小时 0分钟 24秒
-----------------------------------
程序启动: 2025-08-12 21:52:59
程序关闭: 2025-08-12 21:57:54
工作时长: 0小时 4分钟 54秒
-----------------------------------
程序启动: 2025-08-12 21:57:56
程序关闭: 2025-08-12 21:58:34
工作时长: 0小时 0分钟 38秒
-----------------------------------
程序启动: 2025-08-12 21:58:40
程序启动: 2025-08-12 22:01:53
程序启动: 2025-08-12 22:03:37
程序启动: 2025-08-12 22:06:02
程序启动: 2025-08-12 22:12:48
程序关闭: 2025-08-12 22:15:41
工作时长: 0小时 2分钟 52秒
-----------------------------------
程序启动: 2025-08-12 22:19:13
程序启动: 2025-08-12 23:13:17
程序关闭: 2025-08-12 23:13:21
工作时长: 0小时 54分钟 8秒
-----------------------------------
程序启动: 2025-08-12 23:13:23
程序关闭: 2025-08-12 23:16:01
工作时长: 0小时 2分钟 37秒
-----------------------------------
程序启动: 2025-08-12 23:16:02
程序关闭: 2025-08-12 23:16:28
工作时长: 0小时 0分钟 25秒
-----------------------------------
程序启动: 2025-08-15 23:09:00
程序关闭: 2025-08-15 23:17:24
工作时长: 0小时 8分钟 24秒
-----------------------------------
程序启动: 2025-08-21 21:25:25
程序关闭: 2025-08-21 21:28:51
工作时长: 0小时 3分钟 25秒
-----------------------------------
程序启动: 2025-08-23 15:41:33
程序关闭: 2025-08-23 15:43:01
工作时长: 0小时 1分钟 28秒
-----------------------------------
程序启动: 2025-08-23 15:45:38
程序关闭: 2025-08-23 15:46:00
工作时长: 0小时 0分钟 21秒
-----------------------------------
程序启动: 2025-08-23 15:47:59
程序关闭: 2025-08-23 15:48:09
工作时长: 0小时 0分钟 9秒
-----------------------------------
程序启动: 2025-08-23 16:18:45
程序关闭: 2025-08-23 16:19:17
工作时长: 0小时 0分钟 32秒
-----------------------------------
程序启动: 2025-08-23 16:22:53
程序启动: 2025-08-23 16:25:27
程序关闭: 2025-08-23 16:31:00
工作时长: 0小时 5分钟 32秒
-----------------------------------
程序启动: 2025-08-23 16:31:02
程序关闭: 2025-08-23 16:31:31
工作时长: 0小时 0分钟 28秒
-----------------------------------
程序启动: 2025-08-23 16:32:43
程序关闭: 2025-08-23 16:34:04
工作时长: 0小时 1分钟 21秒
-----------------------------------
程序启动: 2025-08-23 16:35:29
程序启动: 2025-08-23 16:37:39
程序启动: 2025-08-23 16:43:57
程序关闭: 2025-08-23 16:45:05
工作时长: 0小时 1分钟 8秒
-----------------------------------
程序启动: 2025-08-23 17:01:49
程序关闭: 2025-08-23 21:13:53
工作时长: 4小时 12分钟 4秒
-----------------------------------
程序启动: 2025-08-23 21:13:57
程序关闭: 2025-08-23 21:14:07
工作时长: 0小时 0分钟 9秒
-----------------------------------
程序启动: 2025-08-23 21:15:06
程序关闭: 2025-08-23 21:55:14
工作时长: 0小时 40分钟 7秒
-----------------------------------
程序启动: 2025-08-23 21:55:16
程序关闭: 2025-08-23 21:59:33
工作时长: 0小时 4分钟 17秒
-----------------------------------
程序启动: 2025-08-23 21:59:35
程序关闭: 2025-08-23 22:01:21
工作时长: 0小时 1分钟 46秒
-----------------------------------
程序启动: 2025-08-23 22:01:23
程序关闭: 2025-08-23 22:04:10
工作时长: 0小时 2分钟 46秒
-----------------------------------
程序启动: 2025-08-23 22:04:12
程序关闭: 2025-08-23 22:05:25
工作时长: 0小时 1分钟 13秒
-----------------------------------
程序启动: 2025-08-23 22:05:27
程序关闭: 2025-08-23 22:05:48
工作时长: 0小时 0分钟 21秒
-----------------------------------
程序启动: 2025-08-23 22:06:20
程序关闭: 2025-08-23 22:06:34
工作时长: 0小时 0分钟 14秒
-----------------------------------
程序启动: 2025-08-23 22:07:49
程序关闭: 2025-08-23 22:08:14
工作时长: 0小时 0分钟 24秒
-----------------------------------
程序启动: 2025-08-23 22:08:34
程序关闭: 2025-08-23 22:10:39
工作时长: 0小时 2分钟 5秒
-----------------------------------
程序启动: 2025-08-23 22:11:06
程序关闭: 2025-08-23 22:38:24
工作时长: 0小时 27分钟 17秒
-----------------------------------
程序启动: 2025-08-23 22:38:27
程序关闭: 2025-08-23 22:38:52
工作时长: 0小时 0分钟 25秒
-----------------------------------
程序启动: 2025-08-23 22:38:57
程序启动: 2025-08-23 22:42:02
程序关闭: 2025-08-23 22:46:21
工作时长: 0小时 4分钟 19秒
-----------------------------------
程序启动: 2025-08-23 22:46:24
程序关闭: 2025-08-23 22:47:27
工作时长: 0小时 1分钟 3秒
-----------------------------------
程序启动: 2025-08-23 22:47:30
程序启动: 2025-08-23 22:59:41
程序关闭: 2025-08-23 23:00:29
工作时长: 0小时 0分钟 47秒
-----------------------------------
程序启动: 2025-08-23 23:05:46
程序关闭: 2025-08-23 23:09:25
工作时长: 0小时 3分钟 39秒
-----------------------------------
程序启动: 2025-08-24 09:46:48
程序关闭: 2025-08-24 10:31:07
工作时长: 0小时 44分钟 19秒
-----------------------------------
程序启动: 2025-08-24 10:31:09
程序关闭: 2025-08-24 10:31:14
工作时长: 0小时 0分钟 5秒
-----------------------------------
程序启动: 2025-08-24 10:34:14
程序启动: 2025-08-24 10:43:12
程序关闭: 2025-08-24 10:44:57
工作时长: 0小时 1分钟 45秒
-----------------------------------
程序启动: 2025-08-24 10:52:51
程序关闭: 2025-08-24 10:53:14
工作时长: 0小时 0分钟 22秒
-----------------------------------
程序启动: 2025-08-24 10:54:37
程序关闭: 2025-08-24 10:59:41
工作时长: 0小时 5分钟 3秒
-----------------------------------
程序启动: 2025-08-24 10:59:43
程序关闭: 2025-08-24 11:04:30
工作时长: 0小时 4分钟 47秒
-----------------------------------
程序启动: 2025-08-24 11:04:56
程序关闭: 2025-08-24 11:05:08
工作时长: 0小时 0分钟 12秒
-----------------------------------
程序启动: 2025-08-24 11:06:34
程序关闭: 2025-08-24 11:10:47
工作时长: 0小时 4分钟 12秒
-----------------------------------
程序启动: 2025-08-24 11:10:50
程序关闭: 2025-08-24 11:13:07
工作时长: 0小时 2分钟 16秒
-----------------------------------
程序启动: 2025-08-24 11:13:09
程序关闭: 2025-08-24 11:23:21
工作时长: 0小时 10分钟 12秒
-----------------------------------
程序启动: 2025-08-24 11:23:23
程序关闭: 2025-08-24 12:35:19
工作时长: 1小时 11分钟 55秒
-----------------------------------
程序启动: 2025-08-24 12:35:22
程序关闭: 2025-08-24 12:41:38
工作时长: 0小时 6分钟 15秒
-----------------------------------
程序启动: 2025-08-24 12:41:41
程序关闭: 2025-08-24 12:55:40
工作时长: 0小时 13分钟 59秒
-----------------------------------
程序启动: 2025-08-24 12:55:42
程序关闭: 2025-08-24 12:56:25
工作时长: 0小时 0分钟 42秒
-----------------------------------
程序启动: 2025-08-24 12:57:15
程序关闭: 2025-08-24 12:57:47
工作时长: 0小时 0分钟 31秒
-----------------------------------
程序启动: 2025-08-24 13:03:07
程序关闭: 2025-08-24 13:07:28
工作时长: 0小时 4分钟 20秒
-----------------------------------
程序启动: 2025-08-24 13:07:30
程序关闭: 2025-08-24 13:07:48
工作时长: 0小时 0分钟 17秒
-----------------------------------
程序启动: 2025-08-24 13:09:13
程序关闭: 2025-08-24 13:09:55
工作时长: 0小时 0分钟 41秒
-----------------------------------
程序启动: 2025-08-24 13:12:54
程序启动: 2025-08-24 13:18:23
程序关闭: 2025-08-24 13:18:27
工作时长: 0小时 5分钟 32秒
-----------------------------------
程序启动: 2025-08-24 13:18:29
程序关闭: 2025-08-24 13:19:01
工作时长: 0小时 0分钟 31秒
-----------------------------------
程序启动: 2025-08-24 13:20:34
程序关闭: 2025-08-24 13:25:22
工作时长: 0小时 4分钟 47秒
-----------------------------------
程序启动: 2025-08-24 13:25:23
程序关闭: 2025-08-24 13:26:33
工作时长: 0小时 1分钟 10秒
-----------------------------------
程序启动: 2025-08-24 13:26:36
程序关闭: 2025-08-24 13:27:25
工作时长: 0小时 0分钟 49秒
-----------------------------------
程序启动: 2025-08-24 13:40:36
程序关闭: 2025-08-24 13:41:12
工作时长: 0小时 0分钟 35秒
-----------------------------------
程序启动: 2025-08-24 13:41:35
程序关闭: 2025-08-24 13:42:05
工作时长: 0小时 0分钟 29秒
-----------------------------------
程序启动: 2025-08-24 13:43:24
程序启动: 2025-08-24 13:48:00
程序关闭: 2025-08-24 13:48:04
工作时长: 0小时 4分钟 40秒
-----------------------------------
程序启动: 2025-08-24 13:48:06
程序关闭: 2025-08-24 13:48:30
工作时长: 0小时 0分钟 24秒
-----------------------------------
程序启动: 2025-08-24 13:48:46
程序关闭: 2025-08-24 13:53:20
工作时长: 0小时 4分钟 33秒
-----------------------------------
程序启动: 2025-08-24 14:28:32
程序关闭: 2025-08-24 14:31:07
工作时长: 0小时 2分钟 34秒
-----------------------------------
程序启动: 2025-08-24 14:31:40
程序关闭: 2025-08-24 14:40:24
工作时长: 0小时 8分钟 44秒
-----------------------------------
程序启动: 2025-08-24 14:40:26
程序启动: 2025-08-24 14:51:47
程序关闭: 2025-08-24 14:51:51
工作时长: 0小时 11分钟 25秒
-----------------------------------
程序启动: 2025-08-24 14:51:53
程序关闭: 2025-08-24 16:44:14
工作时长: 1小时 52分钟 20秒
-----------------------------------
程序启动: 2025-08-24 16:44:16
程序关闭: 2025-08-24 16:56:04
工作时长: 0小时 11分钟 48秒
-----------------------------------
程序启动: 2025-08-24 16:56:06
程序关闭: 2025-08-24 17:01:59
工作时长: 0小时 5分钟 52秒
-----------------------------------
程序启动: 2025-08-24 17:02:01