src/chushihua/Chushihua.java
@@ -1,11 +1,11 @@ package chushihua; import java.sql.SQLException; import dell_Fence.Dell_Fence; import dell_anchor.Dell_BaseStation; import dell_map.Dell_Map; import dell_suanfa.Dell_GroupManagement; import dell_suanfa.Dell_LayerManagement; import dell_system.Dell_company; import dell_targets.Dell_BaseStation; import dell_targets.Dell_SystemConfiguration; import dell_targets.Dell_tag; import udptcp.UDPPortAReceiver; @@ -13,6 +13,7 @@ public class Chushihua { public static void getchushihua() { try { Dell_SystemConfiguration.getSystemConfigurations(); Dell_tag.getlocationTags(); Dell_BaseStation.getBaseStations(); UDPPortAReceiver.startReceiver(); @@ -21,7 +22,6 @@ Dell_company.getAllCompanies(); Dell_LayerManagement.getAllLayers(); Dell_GroupManagement.getAllGroups(); Dell_SystemConfiguration.getSystemConfigurations(); if(Dell_SystemConfiguration.gnsstoxyOpen) {Dell_Map.get_foor_xycs();} } catch (SQLException e) { // TODO èªå¨çæç catch å src/dell55AAData/Dell55AA02Parser.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,66 @@ package dell55AAData; import dell_targets.Dell_BaseStation; 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åè) /** * è§£æ55AA02æ ¼å¼çåºç«æ°æ® * @param message æ¥æ¶å°çæ°æ®ï¼åå è¿å¶åç¬¦ä¸²ï¼ */ public static void parseAndUpdate(String message) { // 1. åºç¡æ ¡éª if (message == null || message.length() < MIN_LENGTH) { return; } // 2. 头鍿 ¡éªï¼åºå®å¼å¤´åç¬¦ä¸²ï¼ for (int i = 0; i < EXPECTED_HEADER.length(); i++) { if (message.charAt(i) != EXPECTED_HEADER.charAt(i)) { return; } } // 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) }); // 4. è§£æåæ¥ç¶æï¼1åèï¼ char syncChar = message.charAt(SYNC_STATUS_START + 1); // åç¶æå符 String syncStatus = (syncChar == '0') ? "0" : "1"; // 5. è§£ææ°åå¼ï¼4åèå°ç«¯åºï¼ int pressure = 0; for (int i = 0; i < 8; i += 2) { int idx = PRESSURE_START + i; // 使ç¨HexUtilsçå¿«éè½¬æ¢æ¹æ³ 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) { Dell_BaseStation.updateBaseStationProperty(baseId, "syncStatus", syncStatus); Dell_BaseStation.updateBaseStationProperty(baseId, "barometerReading", pressure); } } src/dell_anchor/BaseStationAdjacentConfigPanel.java
@@ -1,6 +1,7 @@ package dell_anchor; import databases.DBConnector; import dell_targets.Dell_BaseStation; import targets.LocationBaseStation; import javax.swing.*; src/dell_anchor/BaseStationManagementPanel.java
@@ -1,6 +1,8 @@ package dell_anchor; import databases.DBConnector; import dell_targets.Dell_BaseStation; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.table.*; src/dell_anchor/BaseStationSyncConfigPanel.java
@@ -1,5 +1,7 @@ package dell_anchor; import databases.DBConnector; import dell_targets.Dell_BaseStation; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.table.*; src/dell_anchor/Dell_BaseStation.java
ÎļþÒÑɾ³ý src/dell_system/MessageViewPanel.java
@@ -7,13 +7,11 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import dell_targets.Dell_MessageType; import dell_targets.Dell_tag; import publicsWay.Languages; import udptcp.UDPPortAReceiver; import udptcp.UDPPortBReceiver; @@ -28,7 +26,7 @@ // UIç»ä»¶å£°æ private JButton btnStart, btnPause, btnClear, btnSend; // æ§å¶æé®ï¼å¼å§ãæåãæ¸ é¤ãåé private static JComboBox<String> cbDataType; // 䏿æ¡ï¼æ°æ®ç±»åãåè®®ã设å¤ID private JComboBox<String> cbProtocol; private static JComboBox<String> cbProtocol; private static JComboBox<String> cbDeviceId; private static JComboBox<String> cbRemoteDevice; // è¿ç¨è®¾å¤ä¸ææ¡ private static JCheckBox chkAutoSave; // å¤éæ¡ï¼èªå¨ä¿åãæ¾ç¤ºæ¥æºãåå è¿å¶æ¾ç¤ºãASCIIæ¾ç¤º @@ -46,8 +44,6 @@ // ç¶æåé private static boolean isCapturing = false; // æ¯å¦æ£å¨æè·æ°æ®çæ å¿ // å卿æè¿ç¨è®¾å¤(IP:端å£) private static Set<String> remoteDevices = new HashSet<>(); // ä¿®æ¹ä¸ºMapåå¨è®¾å¤åå ¶æ¬å°ç«¯å£ private static Map<String, Integer> remoteDeviceLocalPortMap = new HashMap<>(); // æé 彿° @@ -55,6 +51,9 @@ this.messages = messages; // åå§åæ¶æ¯èµæºå initializeUI(); // åå§åç¨æ·çé¢ } public void addNotify() { super.addNotify(); @@ -333,24 +332,16 @@ } } // å 载设å¤IDå表 private void loadDeviceIds() { // ä»Dell_tagç±»è·åææè®¾å¤ID List<String> tags = Dell_tag.getAlldeviceIds(); // éå设å¤IDå表并添å å°ä¸ææ¡ for (String tag : tags) { cbDeviceId.addItem(tag); } } // å è½½æ°æ®ç±»å private void loadtyps() { // ä»Dell_tagç±»è·åææè®¾å¤ID List<String> typs = Dell_MessageType.getAllMessageTypes(); // éå设å¤IDå表并添å å°ä¸ææ¡ for (String typ : typs) { cbDataType.addItem(typ); } cbDataType.removeAllItems(); // æ·»å å½é åé项 cbDataType.addItem(messages.getString("MESSAGE_VIEW_ALL_TYPES")); cbDataType.addItem(messages.getString("MESSAGE_VIEW_UDP_PORT_A")); cbDataType.addItem(messages.getString("MESSAGE_VIEW_UDP_PORT_B")); cbDataType.addItem(messages.getString("MESSAGE_VIEW_TCP_PORT")); cbDataType.addItem(messages.getString("MESSAGE_VIEW_MQTT_PORT")); } // 设置æé®å¨ä½ @@ -385,11 +376,13 @@ // åéæ°æ®å°è¿ç¨è®¾å¤ private void sendData() { // ä½¿ç¨æ°æ¹æ³è·åå½åèµæºå ResourceBundle currentMessages = Languages.getCurrentMessages(); String selectedDevice = (String) cbRemoteDevice.getSelectedItem(); if (selectedDevice == null || selectedDevice.equals(messages.getString("MESSAGE_VIEW_ALL_DEVICES"))) { if (selectedDevice == null || selectedDevice.equals(currentMessages.getString("MESSAGE_VIEW_ALL_DEVICES"))) { JOptionPane.showMessageDialog(this, messages.getString("MESSAGE_VIEW_SELECT_DEVICE"), messages.getString("WARNING"), currentMessages.getString("MESSAGE_VIEW_SELECT_DEVICE"), currentMessages.getString("WARNING"), JOptionPane.WARNING_MESSAGE); return; } @@ -399,7 +392,7 @@ if (localPort == null) { JOptionPane.showMessageDialog(this, "æ æ³ç¡®å®è®¾å¤çæ¥æ¶ç«¯å£", messages.getString("ERROR"), currentMessages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); return; } @@ -408,8 +401,8 @@ String[] parts = selectedDevice.split(":"); if (parts.length != 2) { JOptionPane.showMessageDialog(this, messages.getString("MESSAGE_VIEW_INVALID_DEVICE"), messages.getString("ERROR"), currentMessages.getString("MESSAGE_VIEW_INVALID_DEVICE"), currentMessages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); return; } @@ -420,8 +413,8 @@ port = Integer.parseInt(parts[1]); } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(this, messages.getString("MESSAGE_VIEW_INVALID_PORT"), messages.getString("ERROR"), currentMessages.getString("MESSAGE_VIEW_INVALID_PORT"), currentMessages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); return; } @@ -429,8 +422,8 @@ String dataToSend = txtSendData.getText(); if (dataToSend.isEmpty()) { JOptionPane.showMessageDialog(this, messages.getString("MESSAGE_VIEW_EMPTY_DATA"), messages.getString("WARNING"), currentMessages.getString("MESSAGE_VIEW_EMPTY_DATA"), currentMessages.getString("WARNING"), JOptionPane.WARNING_MESSAGE); return; } @@ -503,26 +496,67 @@ } // æè·æ°æ®çæ ¸å¿æ¹æ³ public static void captureData(String rawData, String ip, int port, int localPort, String timestamp) { // æ£æ¥çªå£æ¯å¦å¯è§ // ä¿®æ¹éç¨æ°æ®æ¾ç¤ºæ¹æ³ public static void showData(String rawData, String ip, int port, int localPort, String deviceId) { if (!isWindowVisible) { return; } String formattedData = formatData(rawData,ip,port,timestamp); // æ ¼å¼åæ°æ® // è·åå½åéæ© String selectedDataType = (String) cbDataType.getSelectedItem(); String selectedProtocol = (String) cbProtocol.getSelectedItem(); String selectedDeviceId = (String) cbDeviceId.getSelectedItem(); // ä½¿ç¨æ°æ¹æ³è·åå½åèµæºå ResourceBundle messages = Languages.getCurrentMessages(); String allTypes = messages.getString("MESSAGE_VIEW_ALL_TYPES"); String allProtocols = messages.getString("MESSAGE_VIEW_ALL_PROTOCOLS"); String allDevices = messages.getString("MESSAGE_VIEW_ALL_DEVICES"); String udpPortA = messages.getString("MESSAGE_VIEW_UDP_PORT_A"); String udpPortB = messages.getString("MESSAGE_VIEW_UDP_PORT_B"); String udpProtocol = "UDP"; // ç´æ¥ä½¿ç¨åè®®åç§° // æ£æ¥æ°æ®ç±»åè¿æ»¤ boolean dataTypeMatch = selectedDataType.equals(allTypes) || (localPort == UDPPortAReceiver.PORT && selectedDataType.equals(udpPortA)) || (localPort == UDPPortBReceiver.PORT && selectedDataType.equals(udpPortB)); // æ£æ¥åè®®è¿æ»¤ boolean protocolMatch = selectedProtocol.equals(allProtocols) || (localPort == UDPPortAReceiver.PORT && selectedProtocol.equals(udpProtocol)) || (localPort == UDPPortBReceiver.PORT && selectedProtocol.equals(udpProtocol)); // æ£æ¥è®¾å¤IDè¿æ»¤ boolean deviceIdMatch=false; if("1".equals(deviceId)) { deviceIdMatch=true; }else { deviceIdMatch = selectedDeviceId.equals(allDevices) || (deviceId != null && deviceId.equals(selectedDeviceId)); } // åªæå½æææ¡ä»¶é½å¹é æ¶ææ¾ç¤º if (!(dataTypeMatch && protocolMatch && deviceIdMatch)) { return; } // çææ¯«ç§çº§æ¶é´æ³ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); String timestamp = sdf.format(new Date()); String formattedData = formatData(rawData, ip, port, timestamp); if(isCapturing) { // æ·»å è¿ç¨è®¾å¤å°ä¸ææ¡ addRemoteDevice(ip, port, localPort); // ç¡®ä¿è°ç¨å¸¦ç«¯å£åæ°çæ¹æ³ // è·åå½åéæ©ç设å¤IDåæ°æ®ç±»å String deviceId = cbDeviceId.getSelectedItem().toString(); String dataType = cbDataType.getSelectedItem().toString(); addRemoteDevice(ip, port, localPort); // å¨EDT线ç¨ä¸æ´æ°UI SwingUtilities.invokeLater(() -> { txtDataView.append(formattedData + "\n"); // æ·»å æ°æ®å°ææ¬åºå // èªå¨æ»å¨å°åºé¨ txtDataView.append(formattedData + "\n"); txtDataView.setCaretPosition(txtDataView.getDocument().getLength()); }); } // 妿å¯ç¨äºèªå¨ä¿åï¼åä¿åå°æä»¶ if (chkAutoSave.isSelected()) { saveToFile(formattedData); @@ -530,29 +564,56 @@ } // æ ¼å¼åæ°æ®æ¾ç¤º // ä¿®æ¹æ ¼å¼æ¾ç¤ºæ¹æ³ï¼æ¯ææ··åæ ¼å¼ private static String formatData(String rawData, String ip, int port,String timestamp) { StringBuilder formatted = new StringBuilder(); // 使ç¨StringBuilderæå»ºæ ¼å¼åå符串 // 妿å¯ç¨äºæ¾ç¤ºæ¥æºï¼æ·»å æ¶é´æ³åæºå°å StringBuilder formatted = new StringBuilder(); // ä½¿ç¨æ°æ¹æ³è·åå½åèµæºå ResourceBundle messages = Languages.getCurrentMessages(); // æ¾ç¤ºæ¥æºä¿¡æ¯ if (chkShowSource.isSelected()) { formatted.append("["+timestamp+";"+ip+":"+port+"]"); // æ·»å æ¨¡ææºå°å formatted.append("[") .append(timestamp) .append("][") .append(ip) .append(":") .append(port) .append("] "); } // æ ¹æ®æ¾ç¤ºéé¡¹æ ¼å¼åæ°æ® if (chkHexDisplay.isSelected() && chkAsciiDisplay.isSelected()) { // åæ¶æ¾ç¤ºåå è¿å¶åASCII formatted.append(toHexString(rawData)) // æ·»å åå è¿å¶è¡¨ç¤º .append(" | ") // æ·»å åé符 .append(rawData); // æ·»å åå§ASCIIæ°æ® formatted.append(formatHexString(rawData)) .append(" | ") .append(hexToAscii(rawData)) .append(" [") .append(messages.getString("MESSAGE_VIEW_MIXED_FORMAT")) .append("]"); } else if (chkHexDisplay.isSelected()) { // ä» æ¾ç¤ºåå è¿å¶ formatted.append(toHexString(rawData)); formatted.append(formatHexString(rawData)) .append(" [") .append(messages.getString("MESSAGE_VIEW_HEX_FORMAT")) .append("]"); } else if (chkAsciiDisplay.isSelected()) { formatted.append(hexToAscii(rawData)) .append(" [") .append(messages.getString("MESSAGE_VIEW_ASCII_FORMAT")) .append("]"); } else { // é»è®¤æ¾ç¤ºåå§ASCIIæ°æ® formatted.append(rawData); formatted.append(hexToAscii(rawData)); } return formatted.toString(); // è¿åæ ¼å¼ååçå符串 return formatted.toString(); } // ä¿®æ¹è®¾å¤IDå è½½æ¹æ³ private void loadDeviceIds() { cbDeviceId.removeAllItems(); cbDeviceId.addItem(messages.getString("MESSAGE_VIEW_ALL_DEVICES")); List<String> tags = Dell_tag.getAlldeviceIds(); for (String tag : tags) { cbDeviceId.addItem(tag); } } // å°å符串转æ¢ä¸ºåå è¿å¶è¡¨ç¤º @@ -563,7 +624,25 @@ } return hex.toString().trim(); // è¿åå¹¶å»é¤æ«å°¾ç©ºæ ¼ } // æ ¼å¼ååå è¿å¶åç¬¦ä¸²ï¼æ¯ä¸¤ä¸ªå符å ç©ºæ ¼ï¼ private static String formatHexString(String hex) { StringBuilder formatted = new StringBuilder(); for (int i = 0; i < hex.length(); i += 2) { if (i > 0) formatted.append(" "); formatted.append(hex.substring(i, Math.min(i + 2, hex.length()))); } return formatted.toString(); } // å°åå è¿å¶å符串转æ¢ä¸ºASCII private static String hexToAscii(String hexStr) { StringBuilder output = new StringBuilder(); for (int i = 0; i < hexStr.length(); i += 2) { String str = hexStr.substring(i, i + 2); output.append((char) Integer.parseInt(str, 16)); } return output.toString(); } // ä¿åæ°æ®å°æä»¶ private static void saveToFile(String data) { SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd"); // æä»¶æ¥ææ ¼å¼ src/dell_targets/Dell_BaseStation.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,137 @@ package dell_targets; import databases.DBConnector; import targets.LocationBaseStation; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; public class Dell_BaseStation { static List<LocationBaseStation> baseStations; private static ConcurrentHashMap<String, LocationBaseStation> baseStationMap; // 以åºç«ID为é®çæ å° public static List<LocationBaseStation> getBaseStations() throws SQLException { baseStations = new ArrayList<>(); baseStationMap = new ConcurrentHashMap<>(); // ä¿®å¤ï¼åå§åæ å° ResultSet rs = DBConnector.queryTableData("location_base_station"); while (rs.next()) { LocationBaseStation baseStation = new LocationBaseStation(); baseStation.setId((int) rs.getLong("id")); baseStation.setCode(rs.getString("base_station_id")); baseStation.setStatus(rs.getString("statuss")); baseStation.setXCoordinate(rs.getString("x_coordinate")); baseStation.setYCoordinate(rs.getString("y_coordinate")); baseStation.setZCoordinate(rs.getString("z_coordinate")); baseStation.setLongitude(rs.getString("longitude")); baseStation.setLatitude(rs.getString("latitude")); baseStation.setElevation(rs.getString("elevation")); baseStation.setHorizontalAngle(rs.getString("horizontal_angle")); baseStation.setPitchAngle(rs.getString("pitch_angle")); baseStation.setFloor(rs.getString("located_layer")); baseStation.setGroup(rs.getString("located_group")); baseStation.setRange(rs.getString("range")); baseStation.setSyncStatus(rs.getString("sync_status")); baseStation.setSyncType(rs.getString("sync_type")); baseStation.setSyncBaseStation(rs.getString("sync_base_station")); baseStation.setIpAddress(rs.getString("ip_address")); baseStation.setPort(rs.getString("ports")); baseStation.setFirmwareVersion(rs.getString("firmware_version")); baseStation.setJudgmentDistance(rs.getString("judgment_distance")); baseStation.setBattery(rs.getString("battery")); baseStation.setCalibrationDistance(rs.getString("calibration_distance")); baseStation.setSignalSendTime(rs.getString("signal_transmission_time")); baseStation.setCommunicationGroup(rs.getString("communication_group")); baseStation.setIconAddress(rs.getString("icon_url")); baseStation.setOnlineTime(rs.getString("online_time")); baseStation.setOfflineTime(rs.getString("offline_time")); baseStation.setOfflineDuration(rs.getString("offline_duration")); baseStation.setAlgorithmDimension(rs.getString("algorithm_dimension")); baseStation.setBottomHeight(rs.getString("located_bottom_height")); baseStation.setTopHeight(rs.getString("located_top_height")); baseStation.setIsBarometricStation(rs.getString("barometric_base_station")); baseStation.setSwitchDistance(rs.getString("handover_distance")); baseStation.setMaxDistance(rs.getString("maximum_distance")); baseStation.setOutputAllRanging(rs.getString("output_all_base_station_ranging")); baseStation.setCompany(rs.getString("company")); baseStation.setCrossLayerHeight(rs.getString("cross_layer_height")); baseStation.setCrossLayerGroup(rs.getString("cross_layer_group")); baseStation.setRequiredDistance(rs.getString("must_pass_distance")); baseStation.setAdjacent1(rs.getString("adjacent1")); baseStation.setAdjacent2(rs.getString("adjacent2")); baseStation.setAdjacent3(rs.getString("adjacent3")); baseStation.setAdjacent4(rs.getString("adjacent4")); baseStation.setAdjacent5(rs.getString("adjacent5")); baseStation.setAdjacent6(rs.getString("adjacent6")); baseStation.setAdjacent7(rs.getString("adjacent7")); baseStation.setAdjacent8(rs.getString("adjacent8")); baseStation.setAdjacent9(rs.getString("adjacent9")); baseStation.setAdjacent10(rs.getString("adjacent10")); baseStation.setReserved1(rs.getString("reserved1")); baseStation.setReserved2(rs.getString("reserved2")); baseStation.setReserved3(rs.getString("reserved3")); baseStation.setReserved4(rs.getString("reserved4")); baseStation.setReserved5(rs.getString("reserved5")); baseStation.setReserved6(rs.getString("reserved6")); baseStation.setReserved7(rs.getString("reserved7")); baseStation.setReserved8(rs.getString("reserved8")); baseStation.setReserved9(rs.getString("reserved9")); baseStation.setReserved10(rs.getString("reserved10")); baseStation.setReserved11(rs.getString("reserved11")); baseStation.setReserved12(rs.getString("reserved12")); baseStation.setReserved13(rs.getString("reserved13")); baseStation.setReserved14(rs.getString("reserved14")); baseStation.setReserved15(rs.getString("reserved15")); baseStation.setReserved16(rs.getString("reserved16")); baseStations.add(baseStation); baseStationMap.put(baseStation.getCode(), baseStation); // 以åºç«ID为é®åå ¥æ å° } return baseStations; } /** * æ ¹æ®åºç«IDé«æä¿®æ¹å±æ§å¼ * @param baseStationId åºç«IDï¼base_station_idï¼ * @param propertyName 屿§åï¼éä¸setteræ¹æ³å¹é ï¼ * @param value æ°å±æ§å¼ */ public static void updateBaseStationProperty(String baseStationId, String propertyName, String value) { LocationBaseStation station = baseStationMap.get(baseStationId); if (station == null) return; // åºç«ä¸åå¨åå¿½ç¥ // æ ¹æ®å±æ§åè°ç¨å¯¹åºsetterï¼é«æå¹é é«é¢å±æ§ï¼ switch (propertyName) { case "status": station.setStatus(value); break; // æ´æ°ç¶æ case "battery": station.setBattery(value); break; // æ´æ°çµé case "ipAddress": station.setIpAddress(value); break; // æ´æ°IPå°å case "onlineTime": station.setOnlineTime(value); break; // æ´æ°ä¸çº¿æ¶é´ case "offlineTime": station.setOfflineTime(value); break; // æ´æ°ç¦»çº¿æ¶é´ case "offlineDuration": station.setOfflineDuration(value); break; // æ´æ°ç¦»çº¿æ¶é¿ case "syncStatus": station.setSyncStatus(value); break; //åæ¥ç¶æ case "barometerReading": station.setBarometerReading(value); break; //åæ¥ç¶æ // æ·»å å ¶ä»é«é¢å±æ§... default: throw new IllegalArgumentException("䏿¯æå±æ§: " + propertyName); } } /** * æ ¹æ®åºç«IDè·ååºç«å¯¹è±¡ï¼é«æè®¿é®ï¼ * @param baseStationId åºç«ID * @return åºç«å¯¹è±¡ï¼ä¸åå¨åè¿ånullï¼ */ public static LocationBaseStation getBaseStationById(String baseStationId) { return baseStationMap.get(baseStationId); // O(1)å¤æåº¦ç´æ¥è·å } } src/dell_targets/Dell_SystemConfiguration.java
@@ -14,6 +14,7 @@ static List<SystemConfiguration> configs; public static boolean xytognssOpen=false; public static boolean gnsstoxyOpen=false; public static String language="0"; // è·åç³»ç»é ç½®å表 public static List<SystemConfiguration> getSystemConfigurations() { // å建é 置对象å表 @@ -158,8 +159,10 @@ config.setRealTimeTrajectoryDuration(rs.getString("real_time_trajectory_duration")); // 宿¶è½¨è¿¹é¢è² config.setRealTimeTrajectoryColor(rs.getString("real_time_trajectory_color")); String langua=rs.getString("system_language"); language=langua; // ç³»ç»è¯è¨ config.setSystemLanguage(rs.getString("system_language")); config.setSystemLanguage(langua); // JNAæ¥å¿å¼å ³ config.setJnaLogSwitch(rs.getString("jna_log_switch")); // æ¶é´çåé æ¹å¼ src/publicsWay/Languages.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,53 @@ package publicsWay; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.Locale; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import dell_targets.Dell_SystemConfiguration; public class Languages { // ä¿®æ¹åçèµæºå è½½æ¹æ³ public static ResourceBundle getCurrentMessages() { // æ ¹æ®ç³»ç»é ç½®å³å®è¯è¨ Locale locale = "1".equals(Dell_SystemConfiguration.language) ? Locale.ENGLISH : Locale.SIMPLIFIED_CHINESE; // 使ç¨ä¸Windows.javaç¸åçå è½½é»è¾ String fileName = locale.equals(Locale.ENGLISH) ? "Messages_en.properties" : "Messages_zh.properties"; File langFile = new File("systemfile/" + fileName); if (!langFile.exists()) { System.err.println("é»è®¤èµæºæä»¶æªæ¾å°: " + langFile.getAbsolutePath()); try { return ResourceBundle.getBundle("systemfile.Messages", locale); } catch (Exception e) { System.err.println("åå¤èµæºå 载失败: " + e.getMessage()); // è¿å空å é¿å å´©æº return new ResourceBundle() { @Override protected Object handleGetObject(String key) { return "!" + key + "!"; } @Override public Enumeration<String> getKeys() { return java.util.Collections.emptyEnumeration(); } }; } } try (InputStream inputStream = new FileInputStream(langFile)) { return new PropertyResourceBundle(inputStream); } catch (IOException e) { System.err.println("æ æ³å è½½èµæºæä»¶: " + e.getMessage()); return ResourceBundle.getBundle("systemfile.Messages", locale); } } } src/publicsWay/UwbDataParser.java
@@ -131,10 +131,5 @@ this.buttonStatus = buttonStatus; } @Override public String toString() { return String.format("å åº: %d, æ ç¾: %s, åºç«: %s, è·ç¦»: %d mm, çµé: %d%%, æé®: %d", sequence, tagId, baseId, distance, battery, buttonStatus); } } } src/targets/LocationBaseStation.java
@@ -66,6 +66,7 @@ private String reserved14; // å¤ç¨ 14 private String reserved15; // å¤ç¨ 15 private String reserved16; // å¤ç¨ 16 private String barometerReading;//æ°åè®¡å¼ // Getter and Setter methods public int getId() { @@ -595,4 +596,36 @@ public void setReserved16(String reserved16) { this.reserved16 = reserved16; } public String getxCoordinate() { return xCoordinate; } public String getyCoordinate() { return yCoordinate; } public String getzCoordinate() { return zCoordinate; } public String getBarometerReading() { return barometerReading; } 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 setBarometerReading(String barometerReading) { this.barometerReading = barometerReading; } } src/udptcp/DellHexBaowen.java
ÎļþÒÑɾ³ý src/udptcp/HexBaowen.java
ÎļþÒÑɾ³ý src/udptcp/PacketParser.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,163 @@ package udptcp; import java.util.ArrayList; import java.util.List; // éå½å为PacketParserï¼è¡¨ç¤ºæ°æ®å è§£æå¨ public class PacketParser { // æ·»å åå è¿å¶å符æ°ç»å¸¸é private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); // ç¼å²åºåèæ°ç» private byte[] buffer = new byte[4096]; // å½åç¼å²åºæææ°æ®é¿åº¦ private int bufferLength = 0; // è¿½å æ°æ°æ®å°ç¼å²åº public void appendData(byte[] newData, int length) { // æ£æ¥ç¼å²åºæ¯å¦è¶³å¤ if (bufferLength + length > buffer.length) { // å建æ°çæ´å¤§ç¼å²åº byte[] newBuffer = new byte[bufferLength + length]; // å¤å¶åææ°æ® System.arraycopy(buffer, 0, newBuffer, 0, bufferLength); buffer = newBuffer; } // è¿½å æ°æ°æ® System.arraycopy(newData, 0, buffer, bufferLength, length); // æ´æ°ç¼å²åºé¿åº¦ bufferLength += length; } // æ°å¢æ¹æ³ï¼åèæ°ç»è½¬åå è¿å¶å符串 public static String bytesToHexString(byte[] bytes) { if (bytes == null) return ""; char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = HEX_ARRAY[v >>> 4]; hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; } return new String(hexChars); } // è§£æç¼å²åºä¸çææå®æ´æ°æ®å public List<DataPacket> parsePackets() { List<DataPacket> packets = new ArrayList<>(); int index = 0; // å½åè§£æä½ç½®ç´¢å¼ // éåç¼å²åºæ¥æ¾å®æ´æ°æ®å while (index <= bufferLength - 4) { // ç¡®ä¿æè¶³å¤æ°æ®æ£æ¥å 头 // æ£æ¥å 头æ è¯ 0x55 0xAA if (buffer[index] == 0x55 && (buffer[index + 1] & 0xFF) == 0xAA) { // è·åå ç±»åï¼ç¬¬3åèï¼ int packetType = buffer[index + 2] & 0xFF; // è·åæ°æ®é¿åº¦ï¼ç¬¬4åèï¼ int dataLenField = buffer[index + 3] & 0xFF; // 计ç®å®æ´å é¿åº¦ï¼å 头+æ°æ®+æ ¡éªï¼ int totalPacketLen = 4 + dataLenField + 2; // å¢å 2åèæ ¡éªä½ // æ£æ¥æ¯å¦æè¶³å¤æ°æ®ææå®æ´å if (index + totalPacketLen > bufferLength) { break; // æ°æ®ä¸è¶³ï¼çå¾ æ´å¤æ°æ® } // æå宿´æ°æ®å byte[] packetData = new byte[totalPacketLen]; System.arraycopy(buffer, index, packetData, 0, totalPacketLen); // éªè¯æ ¡éªå if (verifyChecksum(packetData)) { // è§£æåä¸ªæ°æ®å DataPacket packet = parseSinglePacket(packetType, packetData); if (packet != null) { packets.add(packet); // æ·»å å°ç»æå表 } index += totalPacketLen; // ç§»å¨å°ä¸ä¸ä¸ªå } else { index++; // æ ¡éªå¤±è´¥ï¼è·³è¿å½ååè } } else { index++; // éå 头æ è¯ï¼ç»§ç»æ¥æ¾ } } // æ¸ çå·²å¤çæ°æ® if (index > 0) { int remaining = bufferLength - index; if (remaining > 0) { // ç§»å¨å©ä½æ°æ®å°ç¼å²åºå¼å¤´ System.arraycopy(buffer, index, buffer, 0, remaining); } bufferLength = remaining; // æ´æ°ç¼å²åºé¿åº¦ } return packets; } // æ ¡éªæ°æ®å 宿´æ§ private boolean verifyChecksum(byte[] packet) { int len = packet.length; if (len < 4) return false; // é¿åº¦ä¸è¶³ int sum = 0; // 计ç®ä»ç¬¬3åèå°åæ°ç¬¬3åèçåï¼è·³è¿å å¤´åæ ¡éªä½ï¼ for (int i = 2; i < len - 2; i++) { sum += packet[i] & 0xFF; } // ååå¾å°16使 ¡éªå sum = ~sum & 0xFFFF; // æåå ä¸çæ ¡éªåï¼å°ç«¯æ ¼å¼ï¼ int receivedChecksum = ((packet[len - 1] & 0xFF) << 8) | (packet[len - 2] & 0xFF); // æ¯è¾æ ¡éªå return sum == receivedChecksum; } // è§£æåä¸ªæ°æ®å private DataPacket parseSinglePacket(int packetType, byte[] packet) { // åå»ºæ°æ®å 对象ï¼å å«å ç±»åï¼ return new DataPacket(packetType, packet); } // æ°æ®å å é¨ç±» public static class DataPacket { private final int packetType; // å ç±»å private final byte[] packet;//å æ°æ® public DataPacket(int packetType, byte[] packet) { this.packetType = packetType; this.packet = packet; } // è·åå ç±»å public int getPacketType() { return packetType; } // å æ°æ® public byte[] getPacket() { return packet; } } // HEXå符串转åèæ°ç» public static byte[] hexStringToBytes(String hex) { // ç§»é¤ç©ºæ ¼ hex = hex.replaceAll("\\s", ""); int len = hex.length(); // åå»ºç»ææ°ç» byte[] data = new byte[len / 2]; // æ¯ä¸¤ä¸ªå符转æ¢ä¸ä¸ªåè for (int i = 0; i < len; i += 2) { // é«ä½è½¬æ¢ int high = Character.digit(hex.charAt(i), 16) << 4; // ä½ä½è½¬æ¢ int low = Character.digit(hex.charAt(i + 1), 16); data[i / 2] = (byte) (high | low); } return data; } } src/udptcp/PacketProcessingSystem.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,104 @@ package udptcp; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import dell55AAData.Dell55AA01Parser; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class PacketProcessingSystem { // 线ç¨å®å ¨çæ¥æåå¨éåï¼éå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; // æ¥æåå¨ç»æ 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; } } // æ¥æ¶ç«¯å卿¥æï¼UDPPortAReceiverä¸è°ç¨ï¼ public static void storePacket(String ip, int port, String hexData) { 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(() -> { PacketParser bufferManager = new PacketParser(); while (isRunning.get()) { HexPacket packet = packetQueue.poll(); if (packet == null) { Thread.yield(); // éå为空æ¶è®©åºCPU continue; } try { // 转æ¢HEX为åèæ°æ® byte[] rawData = PacketParser.hexStringToBytes(packet.hexData); // 追å å°ç¼å²åºå¹¶è§£æ bufferManager.appendData(rawData, rawData.length); List<PacketParser.DataPacket> parsedPackets = bufferManager.parsePackets(); // å¤çè§£æåçæ°æ®å for (PacketParser.DataPacket p : parsedPackets) { // æ ¹æ®å 头类åè·¯ç±å°ä¸åè§£æå¨ switch (p.getPacketType()) { case 0x01: processType01(p);break; case 0x02: processType02(p);break; default: System.err.println("æªç¥å ç±»å: " + p.getPacketType()); } } } 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(); } } // 示ä¾è§£ææ¹æ³ï¼éæ ¹æ®å®é åè®®å®ç°ï¼ private static void processType01(PacketParser.DataPacket packet) { String hexData = PacketParser.bytesToHexString(packet.getPacket()); Dell55AA01Parser.parse(hexData); } private static void processType02(PacketParser.DataPacket packet) { System.out.println("å¤ç55AA02å : " + packet); // å®é ä¸å¡é»è¾ } // å ¶ä»ç±»åå¤çæ¹æ³... } src/udptcp/TCPDiffDataReceiver.java
ÎļþÒÑɾ³ý src/udptcp/UDPPortAReceiver.java
@@ -2,8 +2,6 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; @@ -12,41 +10,35 @@ public class UDPPortAReceiver { public static final int PORT = 8234; @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 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()); packetCount.incrementAndGet(); // è·åå½åæ¶é´åæ¶é´æ³ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(new Date()); int timestamp = (int)(System.currentTimeMillis() / 1000); // ä¿åå°HexBaowenéå // è°ç¨æ¶æ·»å æ¬å°ç«¯å£åæ° HexBaowen.intsert(ip, hexData, time, port, LOCAL_PORT, timestamp); PacketProcessingSystem.storePacket(ip, port, hexData); // æ¥ææ¥ççªå£æ¾ç¤ºæ°æ® MessageViewPanel.showData(hexData, ip, port, PORT,"1"); } catch (Exception e) { System.err.println("Error processing UDP-A packet: " + e.getMessage()); src/udptcp/UDPPortBReceiver.java
@@ -2,21 +2,20 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; import dell_system.MessageViewPanel; public class UDPPortBReceiver { public static final int PORT = 7000; @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 int LOCAL_PORT = PORT; // å®ä¹æ¬å°ç«¯å£ // å¯å¨æ¥æ¶å¨çéææ¹æ³ public static void startReceiver() { @@ -37,15 +36,8 @@ String ip = packet.getAddress().getHostAddress(); int port = packet.getPort(); String hexData = bytesToHex(packet.getData(), packet.getLength()); packetCount.incrementAndGet(); // è·åå½åæ¶é´åæ¶é´æ³ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(new Date()); int timestamp = (int)(System.currentTimeMillis() / 1000); // ä¿åå°HexBaowenéå // è°ç¨æ¶æ·»å æ¬å°ç«¯å£åæ° HexBaowen.intsert(ip, hexData, time, port, LOCAL_PORT, timestamp); PacketProcessingSystem.storePacket(ip, port, hexData); } catch (Exception e) { System.err.println("Error processing UDP-A packet: " + e.getMessage()); @@ -73,7 +65,6 @@ executor.shutdown(); } // åéæ°æ®å°æå®è®¾å¤ // åéæ°æ®å°æå®è®¾å¤ public static void sendData(String ip, int port, String data, boolean isHex) { try { src/window/Windows.java
@@ -17,6 +17,7 @@ import dell_map.Dell_Map; import dell_map.MapViewer; import dell_targets.Dell_SystemConfiguration; import targets.Mapdata; public class Windows extends JFrame { @@ -82,6 +83,16 @@ createLanguageMenu(); } // æ°å¢æ¹æ³ï¼æ ¹æ®ç³»ç»é ç½®è·åå½åè¯è¨ç¯å¢ public Locale getSystemLocale() { return "1".equals(Dell_SystemConfiguration.language) ? Locale.ENGLISH : Locale.SIMPLIFIED_CHINESE; } // æ°å¢æ¹æ³ï¼ä¾å ¶ä»ç±»è·åå½åè¯è¨ç¯å¢ public Locale getCurrentLocale() { return this.currentLocale; } private ResourceBundle loadResourceBundle(Locale locale) { String fileName = locale.equals(Locale.ENGLISH) ? systemfile/Messages_en.properties
@@ -1,3 +1,17 @@ # New message viewing related resources MESSAGE_VIEW_ALL_TYPES=All Types MESSAGE_VIEW_UDP_PORT_A=UDP Port A MESSAGE_VIEW_UDP_PORT_B=UDP Port B MESSAGE_VIEW_TCP_PORT=TCP Port MESSAGE_VIEW_MQTT_PORT=MQTT Port MESSAGE_VIEW_ALL_DEVICES=All Devices MESSAGE_VIEW_ALL_PROTOCOLS=All Protocols MESSAGE_VIEW_SHOW_DATA=Show Data MESSAGE_VIEW_DATA_SOURCE=Data Source MESSAGE_VIEW_FILTERED_DATA=Filtered Data MESSAGE_VIEW_HEX_FORMAT=HEX Format MESSAGE_VIEW_ASCII_FORMAT=ASCII Format MESSAGE_VIEW_MIXED_FORMAT=Mixed Format # New Resource Key-Value Pairs packet.count.format=Packets Received: %d label.id=Label ID systemfile/Messages_zh.properties
@@ -1,3 +1,17 @@ # æ°å¢çæ¥ææ¥çç¸å ³èµæº MESSAGE_VIEW_ALL_TYPES=ææç±»å MESSAGE_VIEW_UDP_PORT_A=UDP端å£A MESSAGE_VIEW_UDP_PORT_B=UDP端å£B MESSAGE_VIEW_TCP_PORT=TCPç«¯å£ MESSAGE_VIEW_MQTT_PORT=MQTTç«¯å£ MESSAGE_VIEW_ALL_DEVICES=ææè®¾å¤ MESSAGE_VIEW_ALL_PROTOCOLS=ææåè®® MESSAGE_VIEW_SHOW_DATA=æ¾ç¤ºæ°æ® MESSAGE_VIEW_DATA_SOURCE=æ°æ®æ¥æº MESSAGE_VIEW_FILTERED_DATA=å·²è¿æ»¤æ°æ® MESSAGE_VIEW_HEX_FORMAT=HEXæ ¼å¼ MESSAGE_VIEW_ASCII_FORMAT=ASCIIæ ¼å¼ MESSAGE_VIEW_MIXED_FORMAT=æ··åæ ¼å¼ # æ°å¢èµæºé®å¼å¯¹ packet.count.format=æ¶å°æ°æ®:%dæ¡ label.id=æ ç¾ç¼å· systemfile/logfile/openlog.txt
@@ -634,3 +634,70 @@ ç¨åºå ³é: 2025-08-08 23:06:23 工使¶é¿: 0å°æ¶ 0åé 41ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 10:43:53 ç¨åºå ³é: 2025-08-09 15:09:35 工使¶é¿: 4å°æ¶ 25åé 41ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:09:38 ç¨åºå ³é: 2025-08-09 15:09:41 工使¶é¿: 0å°æ¶ 0åé 2ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:21:34 ç¨åºå¯å¨: 2025-08-09 15:26:45 ç¨åºå ³é: 2025-08-09 15:26:49 工使¶é¿: 0å°æ¶ 5åé 15ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:26:51 ç¨åºå¯å¨: 2025-08-09 15:28:12 ç¨åºå ³é: 2025-08-09 15:29:23 工使¶é¿: 0å°æ¶ 1åé 10ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:29:25 ç¨åºå ³é: 2025-08-09 15:30:53 工使¶é¿: 0å°æ¶ 1åé 27ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:30:55 ç¨åºå ³é: 2025-08-09 15:31:19 工使¶é¿: 0å°æ¶ 0åé 23ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:31:22 ç¨åºå ³é: 2025-08-09 15:36:19 工使¶é¿: 0å°æ¶ 4åé 57ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:36:21 ç¨åºå ³é: 2025-08-09 15:38:36 工使¶é¿: 0å°æ¶ 2åé 15ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 15:38:39 ç¨åºå ³é: 2025-08-09 16:03:25 工使¶é¿: 0å°æ¶ 24åé 46ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:03:28 ç¨åºå ³é: 2025-08-09 16:03:42 工使¶é¿: 0å°æ¶ 0åé 14ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:13:27 ç¨åºå ³é: 2025-08-09 16:16:14 工使¶é¿: 0å°æ¶ 2åé 46ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:16:17 ç¨åºå ³é: 2025-08-09 16:16:37 工使¶é¿: 0å°æ¶ 0åé 19ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:19:34 ç¨åºå ³é: 2025-08-09 16:21:03 工使¶é¿: 0å°æ¶ 1åé 29ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:21:05 ç¨åºå ³é: 2025-08-09 16:22:09 工使¶é¿: 0å°æ¶ 1åé 3ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:22:10 ç¨åºå ³é: 2025-08-09 16:28:22 工使¶é¿: 0å°æ¶ 6åé 11ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:28:24 ç¨åºå ³é: 2025-08-09 16:32:37 工使¶é¿: 0å°æ¶ 4åé 12ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-09 16:32:39