From 1bda9524add969e315d870f284046ecf1097f956 Mon Sep 17 00:00:00 2001 From: 826220679@qq.com <826220679@qq.com> Date: 星期日, 24 八月 2025 18:01:25 +0800 Subject: [PATCH] 修改 --- src/dell55AAData/Dell55AA12HighPerf.java | 36 src/dell55AAData/Dell55AA01Parser.java | 163 +- src/dell_targets/TagManagementPanel.java | 142 ++ src/dell_targets/Dell_tag.java | 305 +++++ src/window/WelcomeFrame.java | 2 src/databases/DBConnector.java | 57 + systemfile/logfile/openlog.txt | 294 +++++ src/dell_system/SettingsPanelContent.java | 20 src/dell_system/CompanyManagementPanel.java | 64 src/udptcp/UDPPortAReceiver.java | 3 src/dell55AAData/DellGngga.java | 77 + src/dell_targets/TagTypeManagementPanel.java | 57 src/udptcp/UDPPortBReceiver.java | 198 +- src/dell_targets/SatelliteDevicePanel.java | 483 ++++++++ src/dell55AAData/XTB.java | 60 + src/publicsWay/TableUtils.java | 123 + src/dell_anchor/BaseStationManagementPanel.java | 186 +- src/publicsWay/TrackData.java | 177 +++ src/dell_system/SerialPacketParser.java | 4 src/targets/LocationTag.java | 46 src/chushihua/Chushihua.java | 8 src/publicsWay/PacketProcessingSystemB.java | 252 ++++ src/window/NavigationTreeFactory.java | 3 src/dell_system/MessageViewPanel.java | 31 src/dell_targets/Dell_SystemConfiguration.java | 16 src/dell55AAData/Dell55AA02Parser.java | 85 src/publicsWay/PacketProcessingSystem.java | 4 systemfile/Messages_en.properties | 42 systemfile/Messages_zh.properties | 43 src/scheduled_task/TrackTableManager.java | 119 +- src/window/ContentPanelFactory.java | 3 src/publicsWay/ButtonUtils.java | 40 src/publicsWay/TrackDataBatchInserter.java | 122 ++ 33 files changed, 2,771 insertions(+), 494 deletions(-) diff --git a/src/chushihua/Chushihua.java b/src/chushihua/Chushihua.java index eb33bb9..978d302 100644 --- a/src/chushihua/Chushihua.java +++ b/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(); diff --git a/src/databases/DBConnector.java b/src/databases/DBConnector.java index 1d89561..edf9e0e 100644 --- a/src/databases/DBConnector.java +++ b/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; + } + } + } \ No newline at end of file diff --git a/src/dell55AAData/Dell55AA01Parser.java b/src/dell55AAData/Dell55AA01Parser.java index 7e6cdff..da46771 100644 --- a/src/dell55AAData/Dell55AA01Parser.java +++ b/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) { diff --git a/src/dell55AAData/Dell55AA02Parser.java b/src/dell55AAData/Dell55AA02Parser.java index 741ae5e..6ad5b14 100644 --- a/src/dell55AAData/Dell55AA02Parser.java +++ b/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)); } + + + } \ No newline at end of file diff --git a/src/dell55AAData/Dell55AA12HighPerf.java b/src/dell55AAData/Dell55AA12HighPerf.java index 46f169a..d27ad7f 100644 --- a/src/dell55AAData/Dell55AA12HighPerf.java +++ b/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; } diff --git a/src/dell55AAData/DellGngga.java b/src/dell55AAData/DellGngga.java new file mode 100644 index 0000000..d3c4074 --- /dev/null +++ b/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; } +} \ No newline at end of file diff --git a/src/dell55AAData/XTB.java b/src/dell55AAData/XTB.java new file mode 100644 index 0000000..f7fcd73 --- /dev/null +++ b/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; } +} diff --git a/src/dell_anchor/BaseStationManagementPanel.java b/src/dell_anchor/BaseStationManagementPanel.java index b5c7650..9f6cbd6 100644 --- a/src/dell_anchor/BaseStationManagementPanel.java +++ b/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; diff --git a/src/dell_system/CompanyManagementPanel.java b/src/dell_system/CompanyManagementPanel.java index 7fc187f..84c795a 100644 --- a/src/dell_system/CompanyManagementPanel.java +++ b/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; diff --git a/src/dell_system/MessageViewPanel.java b/src/dell_system/MessageViewPanel.java index aaab8a1..c99f8b2 100644 --- a/src/dell_system/MessageViewPanel.java +++ b/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()); }); diff --git a/src/dell_system/SerialPacketParser.java b/src/dell_system/SerialPacketParser.java index c523447..43b5a31 100644 --- a/src/dell_system/SerialPacketParser.java +++ b/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(); diff --git a/src/dell_system/SettingsPanelContent.java b/src/dell_system/SettingsPanelContent.java index 08b7aab..ded27cb 100644 --- a/src/dell_system/SettingsPanelContent.java +++ b/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)); // 设置大小 // 添加保存操作监听器 diff --git a/src/dell_targets/Dell_SystemConfiguration.java b/src/dell_targets/Dell_SystemConfiguration.java index 73647cb..294899a 100644 --- a/src/dell_targets/Dell_SystemConfiguration.java +++ b/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")); // 基站离线判断时长 diff --git a/src/dell_targets/Dell_tag.java b/src/dell_targets/Dell_tag.java index 2a1f489..bad10aa 100644 --- a/src/dell_targets/Dell_tag.java +++ b/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; + } } \ No newline at end of file diff --git a/src/dell_targets/SatelliteDevicePanel.java b/src/dell_targets/SatelliteDevicePanel.java new file mode 100644 index 0000000..406252f --- /dev/null +++ b/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; + } +} \ No newline at end of file diff --git a/src/dell_targets/TagManagementPanel.java b/src/dell_targets/TagManagementPanel.java index 06daa66..35b29d5 100644 --- a/src/dell_targets/TagManagementPanel.java +++ b/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) { diff --git a/src/dell_targets/TagTypeManagementPanel.java b/src/dell_targets/TagTypeManagementPanel.java index 24f23b1..8b434ca 100644 --- a/src/dell_targets/TagTypeManagementPanel.java +++ b/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; diff --git a/src/publicsWay/ButtonUtils.java b/src/publicsWay/ButtonUtils.java new file mode 100644 index 0000000..dcd3926 --- /dev/null +++ b/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; + } +} \ No newline at end of file diff --git a/src/publicsWay/PacketProcessingSystem.java b/src/publicsWay/PacketProcessingSystem.java index 24dcf5c..8d9bdad 100644 --- a/src/publicsWay/PacketProcessingSystem.java +++ b/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); // 实际业务逻辑 } diff --git a/src/publicsWay/PacketProcessingSystemB.java b/src/publicsWay/PacketProcessingSystemB.java new file mode 100644 index 0000000..6b3ed9f --- /dev/null +++ b/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); + + } + + + +} \ No newline at end of file diff --git a/src/publicsWay/TableUtils.java b/src/publicsWay/TableUtils.java index 248c617..6545e35 100644 --- a/src/publicsWay/TableUtils.java +++ b/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); + } } \ No newline at end of file diff --git a/src/publicsWay/TrackData.java b/src/publicsWay/TrackData.java new file mode 100644 index 0000000..39dd18e --- /dev/null +++ b/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; + } +} diff --git a/src/publicsWay/TrackDataBatchInserter.java b/src/publicsWay/TrackDataBatchInserter.java new file mode 100644 index 0000000..fd38d48 --- /dev/null +++ b/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(); + } + } +} diff --git a/src/scheduled_task/TrackTableManager.java b/src/scheduled_task/TrackTableManager.java index 9107b6e..887e2d1 100644 --- a/src/scheduled_task/TrackTableManager.java +++ b/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; diff --git a/src/targets/LocationTag.java b/src/targets/LocationTag.java index 8759f85..21b56fe 100644 --- a/src/targets/LocationTag.java +++ b/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; + } } \ No newline at end of file diff --git a/src/publicsWay/UDPPortAReceiver.java b/src/udptcp/UDPPortAReceiver.java similarity index 98% rename from src/publicsWay/UDPPortAReceiver.java rename to src/udptcp/UDPPortAReceiver.java index 2c68130..6739b3f 100644 --- a/src/publicsWay/UDPPortAReceiver.java +++ b/src/udptcp/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; diff --git a/src/udptcp/UDPPortBReceiver.java b/src/udptcp/UDPPortBReceiver.java index 9ba1dd9..63185c3 100644 --- a/src/udptcp/UDPPortBReceiver.java +++ b/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(); + } } \ No newline at end of file diff --git a/src/window/ContentPanelFactory.java b/src/window/ContentPanelFactory.java index 6e9b00d..26044ea 100644 --- a/src/window/ContentPanelFactory.java +++ b/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); diff --git a/src/window/NavigationTreeFactory.java b/src/window/NavigationTreeFactory.java index 3e767c6..f2fc369 100644 --- a/src/window/NavigationTreeFactory.java +++ b/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); // 算法节点 (一级) diff --git a/src/window/WelcomeFrame.java b/src/window/WelcomeFrame.java index 7867f43..8d081b6 100644 --- a/src/window/WelcomeFrame.java +++ b/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 { diff --git a/systemfile/Messages_en.properties b/systemfile/Messages_en.properties index 0ae7fd4..db77d58 100644 --- a/systemfile/Messages_en.properties +++ b/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 diff --git a/systemfile/Messages_zh.properties b/systemfile/Messages_zh.properties index 2f3aebe..540df4c 100644 --- a/systemfile/Messages_zh.properties +++ b/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=杞欢鐗堟湰 diff --git a/systemfile/logfile/openlog.txt b/systemfile/logfile/openlog.txt index 0f4e122..a9ea94c 100644 --- a/systemfile/logfile/openlog.txt +++ b/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 -- Gitblit v1.9.3