From a8a90fd2d5040e66cc66b3da122a7f82561ff6f6 Mon Sep 17 00:00:00 2001
From: 826220679@qq.com <826220679@qq.com>
Date: 星期六, 09 八月 2025 23:32:29 +0800
Subject: [PATCH] 优化了欢迎页面

---
 src/dell_targets/Dell_BaseStation.java         |   47 +++
 systemfile/Messages_en.properties              |    9 
 src/udptcp/UDPPortAReceiver.java               |  198 ++++++------
 systemfile/Messages_zh.properties              |   11 
 src/dell_targets/Dell_tag.java                 |  163 ++++++++++
 src/window/WelcomeFrame.java                   |  368 +++++++++++++-----------
 src/dell_targets/Dell_SystemConfiguration.java |   11 
 systemfile/logfile/openlog.txt                 |   80 +++++
 8 files changed, 610 insertions(+), 277 deletions(-)

diff --git a/src/dell_targets/Dell_BaseStation.java b/src/dell_targets/Dell_BaseStation.java
index 67002d3..c58dd3b 100644
--- a/src/dell_targets/Dell_BaseStation.java
+++ b/src/dell_targets/Dell_BaseStation.java
@@ -4,18 +4,23 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 
 public class Dell_BaseStation {
-	static List<LocationBaseStation> baseStations;
+	public 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");
-
+		 if (rs == null) {
+		        // 说明底层拿不到数据,直接抛异常或打印日志
+		        throw new SQLException("DBConnector.queryTableData returned null, "
+		                             + "please check database connection & SQL.");
+		    }
 		while (rs.next()) {
 			LocationBaseStation baseStation = new LocationBaseStation();
 			baseStation.setId((int) rs.getLong("id"));
@@ -133,5 +138,43 @@
 	public static LocationBaseStation getBaseStationById(String baseStationId) {
 		return baseStationMap.get(baseStationId); // O(1)复杂度直接获取
 	}
+	
+	/**
+     * 获取所有在线状态(onlineStatus=1)的设备(高效内存操作)
+     * @return 不可修改的baseStationMap集合(避免外部修改缓存)
+     */
+    public static List<LocationBaseStation> getOnlineBaseStations() {
+        if (baseStationMap == null || baseStationMap.isEmpty()) {
+            return Collections.emptyList(); // 缓存为空时返回空集合
+        }
+
+        List<LocationBaseStation> BaseStation = new ArrayList<>();
+        for (LocationBaseStation base : baseStationMap.values()) {
+            if ("1".equals(base.getStatus())) { // 字符串比较避免NPE
+            	BaseStation.add(base);
+            }
+        }
+        return Collections.unmodifiableList(BaseStation); // 返回不可变集合
+    }
+    
+    /**
+     * 快速获取LocationTag对象的总数(使用内存缓存提高性能)
+     * @return LocationTag对象的总数
+     */
+    public static int getLocationBaseCount() {
+        if (baseStationMap == null) {
+            synchronized (LocationBaseStation.class) {
+                if (baseStationMap == null) {
+                    try {
+                    	getBaseStations(); // 初始化缓存
+                    } catch (SQLException e) {
+                        e.printStackTrace();
+                        return 0; // 初始化失败返回0
+                    }
+                }
+            }
+        }
+        return baseStationMap.size();
+    }
 
 }
\ No newline at end of file
diff --git a/src/dell_targets/Dell_SystemConfiguration.java b/src/dell_targets/Dell_SystemConfiguration.java
index 7d0a9f9..73647cb 100644
--- a/src/dell_targets/Dell_SystemConfiguration.java
+++ b/src/dell_targets/Dell_SystemConfiguration.java
@@ -15,6 +15,8 @@
 	public static boolean xytognssOpen=false;
 	public static boolean gnsstoxyOpen=false;
 	public static String language="0";
+	public static int hexport=8234;
+	public static int ascallport=7000;
     // 获取系统配置列表
     public static List<SystemConfiguration> getSystemConfigurations()  {
         // 创建配置对象列表
@@ -40,9 +42,14 @@
 			    // 数据库密码
 			    config.setDatabasePassword(rs.getString("database_password"));
 			    // HEX数据UDP接收端口
-			    config.setHexDataUdpReceivePort(rs.getString("hex_data_udp_receive_port"));
+			    String hexp=rs.getString("hex_data_udp_receive_port");
+			    hexport=Integer.parseInt(hexp);
+			    config.setHexDataUdpReceivePort(hexp);
+			    String ascll=rs.getString("ascii_data_udp_receive_port");
+			    ascallport=Integer.parseInt(ascll);;
 			    // ASCII数据UDP接收端口
-			    config.setAsciiDataUdpReceivePort(rs.getString("ascii_data_udp_receive_port"));
+			    config.setAsciiDataUdpReceivePort(ascll);
+			    
 			    // TCP数据接收端口1
 			    config.setTcpDataReceivePort1(rs.getString("tcp_data_receive_port1"));
 			    // TCP数据接收端口2
diff --git a/src/dell_targets/Dell_tag.java b/src/dell_targets/Dell_tag.java
index 1d74352..2a1f489 100644
--- a/src/dell_targets/Dell_tag.java
+++ b/src/dell_targets/Dell_tag.java
@@ -4,12 +4,21 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 public class Dell_tag {
-	static List<LocationTag> locationTags;
+	public static List<LocationTag> locationTags;
+	private static ConcurrentHashMap<String, LocationTag> tagMap; // 设备ID->标签对象的映射
 	public static List<LocationTag> getlocationTags() throws SQLException{
-		List<LocationTag> locationTags = new ArrayList<>();        
+		List<LocationTag> locationTags = new ArrayList<>();    
+		tagMap = new ConcurrentHashMap<>(); // 初始化映射
 		ResultSet rs =DBConnector.queryTableData("location_tag");
+		 if (rs == null) {
+		        // 说明底层拿不到数据,直接抛异常或打印日志
+		        throw new SQLException("DBConnector.queryTableData returned null, "
+		                             + "please check database connection & SQL.");
+		    }
 		while (rs.next()) {
 			LocationTag locationTag = new LocationTag();
 			locationTag.setId((int) rs.getLong("id"));			
@@ -98,6 +107,7 @@
 			locationTag.setIpAddress(rs.getString("ipAddress"));
 			locationTag.setIpPort(rs.getString("Interaction_Type"));
 			locationTags.add(locationTag);
+			tagMap.put(locationTag.getDeviceNumber(), locationTag); // 添加到映射
 		}
 		return locationTags;
 	}
@@ -119,6 +129,117 @@
         DBConnector.executeUpdate(sql, deviceId);
     }
     
+    /**
+     * 根据设备ID高效修改属性值
+     * @param deviceId 设备ID(device_id)
+     * @param propertyName 属性名(需与setter方法匹配)
+     * @param value 新属性值
+     */
+    public static void updateLocationTagProperty(String deviceId, String propertyName, String value) {
+        LocationTag tag = tagMap.get(deviceId);
+        if (tag == null) return; // 标签不存在则忽略
+        
+        // 根据属性名调用对应setter
+        switch (propertyName) {
+            case "id": tag.setId(Integer.parseInt(value)); break;
+            case "deviceNumber": tag.setDeviceNumber(value); break;
+            case "deviceName": tag.setDeviceName(value); break;
+            case "deviceVersion": tag.setDeviceVersion(value); break;
+            case "deviceCardNumber": tag.setDeviceCardNumber(value); break;
+            case "deviceType": tag.setDeviceType(value); break;
+            case "team": tag.setTeam(value); break;
+            case "group": tag.setGroup(value); break;
+            case "department": tag.setDepartment(value); break;
+            case "iconAddress": tag.setIconAddress(value); break;
+            case "gender": tag.setGender(value); break;
+            case "ethnicity": tag.setEthnicity(value); break;
+            case "communicationAddress": tag.setCommunicationAddress(value); break;
+            case "boundPhone": tag.setBoundPhone(value); break;
+            case "idNumber": tag.setIdNumber(value); break;
+            case "position": tag.setPosition(value); break;
+            case "boundPlateNumber": tag.setBoundPlateNumber(value); break;
+            case "faceAddress": tag.setFaceAddress(value); break;
+            case "heartRate": tag.setHeartRate(value); break;
+            case "bloodPressure": tag.setBloodPressure(value); break;
+            case "bloodOxygen": tag.setBloodOxygen(value); break;
+            case "temperature": tag.setTemperature(value); break;
+            case "sosStatus": tag.setSosStatus(value); break;
+            case "motionStatus": tag.setMotionStatus(value); break;
+            case "onlineStatus": tag.setOnlineStatus(value); break;
+            case "searchStatus": tag.setSearchStatus(value); break;
+            case "batteryStatus": tag.setBatteryStatus(value); break;
+            case "deviceBattery": tag.setDeviceBattery(value); break;
+            case "removalStatus": tag.setRemovalStatus(value); break;
+            case "collisionStatus": tag.setCollisionStatus(value); break;
+            case "elevationStatus": tag.setElevationStatus(value); break;
+            case "gatheringCount": tag.setGatheringCount(value); break;
+            case "proximityAlarm": tag.setProximityAlarm(value); break;
+            case "area": tag.setArea(value); break;
+            case "xCoordinate": tag.setXCoordinate(value); break;
+            case "yCoordinate": tag.setYCoordinate(value); break;
+            case "zCoordinate": tag.setZCoordinate(value); break;
+            case "floor": tag.setFloor(value); break;
+            case "speed": tag.setSpeed(value); break;
+            case "locationSource": tag.setLocationSource(value); break;
+            case "lastUwbSignalTime": tag.setLastUwbSignalTime(value); break;
+            case "lastSatelliteSignalTime": tag.setLastSatelliteSignalTime(value); break;
+            case "uwbTimeSlot": tag.setUwbTimeSlot(value); break;
+            case "latestRangingSeq": tag.setLatestRangingSeq(value); break;
+            case "latestRangingBaseId": tag.setLatestRangingBaseId(value); break;
+            case "latestRangingDistance": tag.setLatestRangingDistance(value); break;
+            case "latestRangingBaseCount": tag.setLatestRangingBaseCount(value); break;
+            case "latestRangingSignalStrength": tag.setLatestRangingSignalStrength(value); break;
+            case "utcTime": tag.setUtcTime(value); break;
+            case "latitude": tag.setLatitude(value); break;
+            case "longitude": tag.setLongitude(value); break;
+            case "satelliteQuality": tag.setSatelliteQuality(value); break;
+            case "hdop": tag.setHdop(value); break;
+            case "satelliteCount": tag.setSatelliteCount(value); break;
+            case "altitude": tag.setAltitude(value); break;
+            case "differentialTime": tag.setDifferentialTime(value); break;
+            case "geoidHeight": tag.setGeoidHeight(value); break;
+            case "satelliteSpeed": tag.setSatelliteSpeed(value); break;
+            case "lastBarometricValue": tag.setLastBarometricValue(value); break;
+            case "recentCoordinates": tag.setRecentCoordinates(value); break;
+            case "recentBarometricValues": tag.setRecentBarometricValues(value); break;
+            case "offlineTime": tag.setOfflineTime(value); break;
+            case "onlineTime": tag.setOnlineTime(value); break;
+            case "offlineDuration": tag.setOfflineDuration(value); break;
+            case "onlineDuration": tag.setOnlineDuration(value); break;
+            case "motionlessStartTime": tag.setMotionlessStartTime(value); break;
+            case "motionlessEndTime": tag.setMotionlessEndTime(value); break;
+            case "motionlessDuration": tag.setMotionlessDuration(value); break;
+            case "validSatelliteSignal": tag.setValidSatelliteSignal(value); break;
+            case "company": tag.setCompany(value); break;
+            case "sleepTime": tag.setSleepTime(value); break;
+            case "vibrationTime": tag.setVibrationTime(value); break;
+            case "frequency": tag.setFrequency(value); break;
+            case "motionlessTime": tag.setMotionlessTime(value); break;
+            case "accelerationValue": tag.setAccelerationValue(value); break;
+            case "imuTime": tag.setImuTime(value); break;
+            case "reserved1": tag.setReserved1(value); break;
+            case "reserved2": tag.setReserved2(value); break;
+            case "reserved3": tag.setReserved3(value); break;
+            case "reserved4": tag.setReserved4(value); break;
+            case "reserved5": tag.setReserved5(value); break;
+            case "ipAndPort": tag.setIpAndPort(value); break;
+            case "interactionType": tag.setInteractionType(value); break;
+            case "ipAddress": tag.setIpAddress(value); break;
+            case "ipPort": tag.setIpPort(value); break;
+            default: 
+                throw new IllegalArgumentException("无效属性: " + propertyName);
+        }
+    }
+    
+    /**
+     * 根据设备ID获取标签对象(高效访问)
+     * @param deviceId 设备ID
+     * @return 标签对象(不存在返回null)
+     */
+    public static LocationTag getTagByDeviceId(String deviceId) {
+        return tagMap.get(deviceId);
+    }
+    
     //获取所有的tagid
     public static List<String> getAlldeviceIds() {
         List<String> types = new ArrayList<>();
@@ -134,4 +255,42 @@
         }
         return types;
     }
+    
+    /**
+     * 获取所有在线状态(onlineStatus=1)的设备(高效内存操作)
+     * @return 不可修改的LocationTag集合(避免外部修改缓存)
+     */
+    public static List<LocationTag> getOnlineLocationTags() {
+        if (tagMap == null || tagMap.isEmpty()) {
+            return Collections.emptyList(); // 缓存为空时返回空集合
+        }
+
+        List<LocationTag> onlineTags = new ArrayList<>();
+        for (LocationTag tag : tagMap.values()) {
+            if ("1".equals(tag.getOnlineStatus())) { // 字符串比较避免NPE
+                onlineTags.add(tag);
+            }
+        }
+        return Collections.unmodifiableList(onlineTags); // 返回不可变集合
+    }
+    
+    /**
+     * 快速获取LocationTag对象的总数(使用内存缓存提高性能)
+     * @return LocationTag对象的总数
+     */
+    public static int getLocationTagCount() {
+        if (tagMap == null) {
+            synchronized (Dell_tag.class) {
+                if (tagMap == null) {
+                    try {
+                        getlocationTags(); // 初始化缓存
+                    } catch (SQLException e) {
+                        e.printStackTrace();
+                        return 0; // 初始化失败返回0
+                    }
+                }
+            }
+        }
+        return tagMap.size();
+    }
 } 
\ No newline at end of file
diff --git a/src/udptcp/UDPPortAReceiver.java b/src/udptcp/UDPPortAReceiver.java
index a72e207..fea5a80 100644
--- a/src/udptcp/UDPPortAReceiver.java
+++ b/src/udptcp/UDPPortAReceiver.java
@@ -7,106 +7,110 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dell_system.MessageViewPanel;
+import dell_targets.Dell_SystemConfiguration;
 
 public class UDPPortAReceiver {
-    public static final int PORT = 8234;
-    @SuppressWarnings("unused")
+	public static final int PORT =Dell_SystemConfiguration.hexport;
+	@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);                            
-                           // 报文查看窗口显示数据
-                            MessageViewPanel.showData(hexData, ip, port, PORT,"1");
-                            
-                        } 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;        
+		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);                            
+							// 报文查看窗口显示数据
+							MessageViewPanel.showData(hexData, ip, port, PORT,"1");
+							// +++ 增加包计数 +++
+							packetCount.incrementAndGet();  // 关键修复:增加计数器  
+						} 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 long getPacketCount() {
-        return packetCount.get();
-    }
+	// 停止接收器
+	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 long getPacketCount() {
+		return packetCount.get();
+	}
+
 }
\ No newline at end of file
diff --git a/src/window/WelcomeFrame.java b/src/window/WelcomeFrame.java
index 158957e..1fa4cb4 100644
--- a/src/window/WelcomeFrame.java
+++ b/src/window/WelcomeFrame.java
@@ -1,213 +1,237 @@
-package window; // 包声明
-import java.awt.*; // 导入AWT包
-import java.sql.Connection; // 导入数据库连接类
-import java.sql.ResultSet; // 导入结果集类
-import java.sql.Statement; // 导入SQL语句类
-import javax.swing.*; // 导入Swing包
-import javax.swing.border.EmptyBorder; // 导入空边框类
-import java.util.ResourceBundle; // 导入资源束类
-import udptcp.UDPPortAReceiver; // 导入UDP端口A接收器
-import udptcp.UDPPortBReceiver; // 导入UDP端口B接收器
-import javax.swing.plaf.basic.BasicInternalFrameUI; // 导入基础内部框架UI
+package window;
 
-public class WelcomeFrame extends JInternalFrame { // 欢迎框架类
-    private static final long serialVersionUID = 1L; // 序列化版本ID
-    private ResourceBundle messages; // 消息资源束
-    private Connection conn; // 数据库连接
-    private Timer statsTimer; // 统计定时器
-    private JLabel udpAPacketCountLabel; // UDP端口A包计数标签
-    private JLabel udpBPacketCountLabel; // UDP端口B包计数标签
-    private JLabel memoryUsageLabel; // 内存使用标签
-    private JLabel threadCountLabel; // 线程计数标签
+import java.awt.*;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.util.ResourceBundle;
+import udptcp.UDPPortAReceiver;
+import udptcp.UDPPortBReceiver;
+import dell_targets.Dell_BaseStation;
+import dell_targets.Dell_tag;
+import dell_targets.Dell_SystemConfiguration;
 
-    public WelcomeFrame(ResourceBundle messages, Connection conn) { // 构造函数
-        super("", true, true, true, true); // 调用父类构造函数,设置标题为空
-        this.messages = messages; // 初始化消息资源束
-        this.conn = conn; // 初始化数据库连接
+public class WelcomeFrame extends JInternalFrame {
+    private static final long serialVersionUID = 1L;
+    private final ResourceBundle messages;
+    private final Connection conn;
+    private Timer statsTimer;
+    private JLabel memoryUsageLabel;
+    private JLabel threadCountLabel;
+    private JLabel tagStatsLabel;
+    private JLabel baseStationStatsLabel;
+    private JLabel dbVersionLabel;
+    private JLabel udpAInfoLabel;
+    private JLabel udpBInfoLabel;
+
+    public WelcomeFrame(ResourceBundle messages, Connection conn) {
+        super("", true, true, true, true);
+        this.messages = messages;
+        this.conn = conn;
         
-        initializeFrame(); // 初始化框架
-        setContentPane(createWelcomePanel()); // 设置内容面板
-        startStatsTimer(); // 启动统计定时器
+        initializeFrame();
+        setContentPane(createWelcomePanel());
+        startStatsTimer();
     }
 
-    private void initializeFrame() { // 初始化框架方法
-        setSize(900, 700); // 设置框架大小
-        setLocation(100, 100); // 设置框架位置
-        setMaximizable(true); // 设置可最大化
-        setIconifiable(true); // 设置可图标化
-        setClosable(true); // 设置可关闭
-        setBorder(null); // 移除边框
-        setVisible(true); // 设置可见
+    private void initializeFrame() {
+        setSize(900, 700);
+        setLocation(100, 100);
+        setMaximizable(true);
+        setIconifiable(true);
+        setClosable(true);
+        setBorder(null);
         
         // 移除标题栏
-        BasicInternalFrameUI ui = (BasicInternalFrameUI) this.getUI(); // 获取UI组件
-        ui.setNorthPane(null); // 移除标题栏
+        ((javax.swing.plaf.basic.BasicInternalFrameUI)this.getUI()).setNorthPane(null);
         
         try {
-            setMaximum(true); // 尝试最大化窗口
+            setMaximum(true);
         } catch (java.beans.PropertyVetoException e) {
-            e.printStackTrace(); // 打印异常堆栈
+            e.printStackTrace();
         }
+        
+        setVisible(true); // 确保框架可见
     }
 
-    private JPanel createWelcomePanel() { // 创建欢迎面板方法
-        JPanel panel = new BackgroundPanel(); // 创建背景面板
-        panel.setLayout(new BorderLayout()); // 设置边界布局
-        panel.setBorder(new EmptyBorder(30, 30, 30, 30)); // 设置空边框
+    private JPanel createWelcomePanel() {
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.setBorder(new EmptyBorder(30, 30, 30, 30));
+        panel.setBackground(new Color(245, 248, 255));
         
-        // 创建标题面板
-        JPanel titlePanel = new JPanel(new BorderLayout()); // 创建边界布局面板
-        titlePanel.setOpaque(false); // 设置透明
+        // 标题面板
+        JPanel titlePanel = new JPanel(new BorderLayout());
+        titlePanel.setOpaque(false);
+        titlePanel.setBorder(new EmptyBorder(0, 0, 30, 0));
         
-        JLabel titleLabel = new JLabel(messages.getString("APP_NAME"), SwingConstants.CENTER); // 创建应用名称标签
-        titleLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 42)); // 设置字体
-        titleLabel.setForeground(new Color(25, 25, 112)); // 设置前景色
-        titleLabel.setBorder(new EmptyBorder(20, 0, 20, 0)); // 设置空边框
-        titleLabel.setOpaque(false); // 设置透明
+        JLabel titleLabel = new JLabel(messages.getString("APP_NAME"), SwingConstants.CENTER);
+        titleLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 42));
+        titleLabel.setForeground(new Color(25, 25, 112));
         
-        JLabel subtitleLabel = new JLabel(messages.getString("WELCOME_MSG"), SwingConstants.CENTER); // 创建欢迎消息标签
-        subtitleLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.ITALIC, 22)); // 设置字体
-        subtitleLabel.setForeground(new Color(70, 130, 180)); // 设置前景色
-        subtitleLabel.setOpaque(false); // 设置透明
+        JLabel subtitleLabel = new JLabel(messages.getString("WELCOME_MSG"), SwingConstants.CENTER);
+        subtitleLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.ITALIC, 22));
+        subtitleLabel.setForeground(new Color(70, 130, 180));
+        subtitleLabel.setBorder(new EmptyBorder(10, 0, 20, 0));
         
-        titlePanel.add(titleLabel, BorderLayout.NORTH); // 添加标题到北部
-        titlePanel.add(subtitleLabel, BorderLayout.CENTER); // 添加副标题到中部
+        titlePanel.add(titleLabel, BorderLayout.NORTH);
+        titlePanel.add(subtitleLabel, BorderLayout.CENTER);
         
-        // 创建信息面板
-        JPanel infoPanel = new JPanel(new GridLayout(0, 2, 20, 20)); // 创建网格布局面板
-        infoPanel.setBorder(new EmptyBorder(30, 50, 30, 50)); // 设置空边框
-        infoPanel.setBackground(new Color(255, 255, 255, 180)); // 设置半透明白色背景
-        infoPanel.setOpaque(true); // 设置不透明
+        // 主信息面板
+        JPanel infoPanel = new JPanel(new GridBagLayout());
+        infoPanel.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createLineBorder(new Color(200, 220, 240), 2),
+            new EmptyBorder(30, 40, 30, 40)
+        ));
+        infoPanel.setBackground(new Color(255, 255, 255, 255));
+        infoPanel.setOpaque(true);
         
-        // 添加系统状态信息
-        infoPanel.add(createInfoLabel(messages.getString("SYSTEM_STATUS"), 
-                     messages.getString("RUNNING_NORMAL"), 
-                     new Color(0, 100, 0))); // 深绿色
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(15, 15, 15, 15);
+        gbc.anchor = GridBagConstraints.WEST;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
         
-        // 添加数据库连接信息
-        infoPanel.add(createInfoLabel(messages.getString("DB_CONNECTION"), 
-                     conn != null ? messages.getString("CONNECTED") : messages.getString("DISCONNECTED"), 
-                     conn != null ? new Color(0, 100, 0) : Color.RED)); // 连接成功绿色/失败红色
+        // 第一列
+        gbc.gridx = 0;
+        gbc.gridy = 0;
         
-        try {
-            if (conn != null) { // 检查数据库连接
-                try (Statement stmt = conn.createStatement(); // 创建语句
-                     ResultSet rs = stmt.executeQuery("SELECT VERSION()")) { // 执行版本查询
-                    if (rs.next()) { // 如果有结果
-                        infoPanel.add(createInfoLabel(messages.getString("DB_VERSION"), 
-                                     rs.getString(1), 
-                                     new Color(25, 25, 112))); // 添加数据库版本
-                    }
-                }
-            }
-        } catch (Exception e) {
-            e.printStackTrace(); // 打印异常
+        // 修复1: 初始化标签并设置初始文本
+        tagStatsLabel = new JLabel("0 / 0");
+        tagStatsLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("TAG_STATS"), tagStatsLabel, new Color(0, 100, 0)), gbc);
+        
+        gbc.gridy++;
+        baseStationStatsLabel = new JLabel("0 / 0");
+        baseStationStatsLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("BASE_STATION_STATS"), baseStationStatsLabel, new Color(0, 100, 0)), gbc);
+        
+        gbc.gridy++;
+        udpAInfoLabel = new JLabel(Dell_SystemConfiguration.hexport + " - " + messages.getString("RECEIVED_PACKETS") + ": 0");
+        udpAInfoLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("UDP_PORT_A"), udpAInfoLabel, new Color(178, 34, 34)), gbc);
+        
+        gbc.gridy++;
+        udpBInfoLabel = new JLabel(Dell_SystemConfiguration.ascallport + " - " + messages.getString("RECEIVED_PACKETS") + ": 0");
+        udpBInfoLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("UDP_PORT_B"), udpBInfoLabel, new Color(178, 34, 34)), gbc);
+        
+        gbc.gridy++;
+        memoryUsageLabel = new JLabel("0 MB / 0 MB");
+        memoryUsageLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("MEMORY_USAGE"), memoryUsageLabel, new Color(148, 0, 211)), gbc);
+        
+        // 第二列
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        threadCountLabel = new JLabel("0");
+        threadCountLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("THREAD_COUNT"), threadCountLabel, new Color(148, 0, 211)), gbc);
+        
+        gbc.gridy++;
+        dbVersionLabel = new JLabel(""); // 初始为空,稍后设置
+        dbVersionLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("DB_VERSION"), dbVersionLabel, new Color(25, 25, 112)), gbc);
+        
+        gbc.gridy++;
+        JLabel dbStatusLabel = new JLabel(conn != null ? messages.getString("CONNECTED") : messages.getString("DISCONNECTED"));
+        dbStatusLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        dbStatusLabel.setForeground(conn != null ? new Color(0, 100, 0) : Color.RED);
+        infoPanel.add(createInfoRow(messages.getString("DB_STATUS"), dbStatusLabel, new Color(25, 25, 112)), gbc);
+        
+        gbc.gridy++;
+        JLabel softwareVersionLabel = new JLabel(messages.getString("APP_VERSION"));
+        softwareVersionLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        infoPanel.add(createInfoRow(messages.getString("SOFTWARE_VERSION"), softwareVersionLabel, new Color(25, 25, 112)), gbc);
+        
+        // 初始化数据库版本
+        if (conn != null && dbVersionLabel.getText().isEmpty()) {
+            updateDbVersion();
         }
-        
-        // 添加当前用户信息
-        infoPanel.add(createInfoLabel(messages.getString("CURRENT_USER"), 
-                     messages.getString("ADMIN"), 
-                     new Color(25, 25, 112))); // 深蓝色
-        
-        // 添加系统时间信息
-        infoPanel.add(createInfoLabel(messages.getString("SYSTEM_TIME"), 
-                     new java.util.Date().toString(), 
-                     new Color(25, 25, 112))); // 深蓝色
-        
-        // 添加UDP端口A统计
-        infoPanel.add(createInfoLabel(messages.getString("UDP_PORT_A"), "0", new Color(178, 34, 34))); // 砖红色
-        udpAPacketCountLabel = createInfoLabel("", "", new Color(178, 34, 34)); // 创建计数标签
-        infoPanel.add(udpAPacketCountLabel); // 添加计数标签
-        
-        // 添加UDP端口B统计
-        infoPanel.add(createInfoLabel(messages.getString("UDP_PORT_B"), "0", new Color(178, 34, 34))); // 砖红色
-        udpBPacketCountLabel = createInfoLabel("", "", new Color(178, 34, 34)); // 创建计数标签
-        infoPanel.add(udpBPacketCountLabel); // 添加计数标签
-        
-        // 添加内存使用统计
-        infoPanel.add(createInfoLabel(messages.getString("MEMORY_USAGE"), "", new Color(148, 0, 211))); // 紫罗兰色
-        memoryUsageLabel = createInfoLabel("", "", new Color(148, 0, 211)); // 创建内存标签
-        infoPanel.add(memoryUsageLabel); // 添加内存标签
-        
-        // 添加线程计数统计
-        infoPanel.add(createInfoLabel(messages.getString("THREAD_COUNT"), "", new Color(148, 0, 211))); // 紫罗兰色
-        threadCountLabel = createInfoLabel("", "", new Color(148, 0, 211)); // 创建线程标签
-        infoPanel.add(threadCountLabel); // 添加线程标签
-        
-        // 创建状态面板
-        JPanel statsPanel = new JPanel(new GridLayout(1, 4, 15, 15)); // 创建网格布局面板
-        statsPanel.setBorder(new EmptyBorder(20, 50, 10, 50)); // 设置空边框
-        statsPanel.setOpaque(false); // 设置透明
-        
-        // 添加统计盒子
-        statsPanel.add(createStatBox(messages.getString("UDP_PORT_A_STAT"), udpAPacketCountLabel)); // UDP端口A统计
-        statsPanel.add(createStatBox(messages.getString("UDP_PORT_B_STAT"), udpBPacketCountLabel)); // UDP端口B统计
-        statsPanel.add(createStatBox(messages.getString("MEMORY_USAGE_STAT"), memoryUsageLabel)); // 内存使用统计
-        statsPanel.add(createStatBox(messages.getString("THREAD_COUNT_STAT"), threadCountLabel)); // 线程计数统计
         
         // 组装主面板
-        panel.add(titlePanel, BorderLayout.NORTH); // 添加标题面板到北部
-        panel.add(infoPanel, BorderLayout.CENTER); // 添加信息面板到中部
-        panel.add(statsPanel, BorderLayout.SOUTH); // 添加状态面板到南部
+        panel.add(titlePanel, BorderLayout.NORTH);
+        panel.add(infoPanel, BorderLayout.CENTER);
         
-        return panel; // 返回面板
+        return panel;
     }
 
-    private JLabel createInfoLabel(String title, String value, Color color) { // 创建信息标签方法
-        JLabel label = new JLabel("<html><div style='text-align:center;'><b>" + title + "</b><br>" + value + "</div></html>"); // 创建带HTML格式的标签
-        label.setFont(new Font(messages.getString("FONT_NAME"), Font.PLAIN, 16)); // 设置字体
-        label.setForeground(color); // 设置前景色
-        label.setHorizontalAlignment(SwingConstants.CENTER); // 设置水平居中
-        label.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直居中
-        label.setOpaque(false); // 设置透明
-        return label; // 返回标签
+    private JPanel createInfoRow(String title, JLabel valueLabel, Color color) {
+        JPanel rowPanel = new JPanel(new BorderLayout(10, 0));
+        rowPanel.setOpaque(false);
+        
+        JLabel titleLabel = new JLabel(title + ":");
+        titleLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18));
+        titleLabel.setForeground(color.darker());
+        
+        valueLabel.setForeground(color);
+        
+        rowPanel.add(titleLabel, BorderLayout.WEST);
+        rowPanel.add(valueLabel, BorderLayout.CENTER);
+        
+        // 添加装饰器
+        JPanel decorator = new JPanel();
+        decorator.setPreferredSize(new Dimension(5, 5));
+        decorator.setBackground(color);
+        decorator.setOpaque(true);
+        rowPanel.add(decorator, BorderLayout.EAST);
+        
+        return rowPanel;
     }
     
-    private JPanel createStatBox(String title, JLabel valueLabel) { // 创建统计盒子方法
-        JPanel boxPanel = new JPanel(new BorderLayout()); // 创建边界布局面板
-        boxPanel.setBorder(BorderFactory.createCompoundBorder( // 设置复合边框
-            BorderFactory.createLineBorder(new Color(70, 130, 180), 2), // 蓝色边框
-            new EmptyBorder(15, 10, 15, 10) // 内边距
-        ));
-        boxPanel.setBackground(new Color(240, 248, 255, 220)); // 设置半透明背景
-        boxPanel.setOpaque(true); // 设置不透明
-        
-        JLabel titleLabel = new JLabel(title, SwingConstants.CENTER); // 创建标题标签
-        titleLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 18)); // 设置粗体
-        titleLabel.setForeground(new Color(25, 25, 112)); // 设置深蓝色
-        
-        valueLabel.setFont(new Font(messages.getString("FONT_NAME"), Font.BOLD, 24)); // 设置粗体大字号
-        valueLabel.setHorizontalAlignment(SwingConstants.CENTER); // 设置居中
-        
-        boxPanel.add(titleLabel, BorderLayout.NORTH); // 添加标题到北部
-        boxPanel.add(valueLabel, BorderLayout.CENTER); // 添加值标签到中部
-        
-        return boxPanel; // 返回面板
+    private void updateDbVersion() {
+        if (conn != null) {
+            try (Statement stmt = conn.createStatement();
+                 ResultSet rs = stmt.executeQuery("SELECT VERSION()")) {
+                if (rs.next()) {
+                    dbVersionLabel.setText(rs.getString(1));
+                }
+            } catch (Exception ex) {
+                dbVersionLabel.setText("N/A");
+            }
+        }
     }
     
-    private void startStatsTimer() { // 启动统计定时器方法
-        statsTimer = new Timer(1000, e -> { // 创建1秒间隔的定时器
-            // 更新UDP数据包计数
-            udpAPacketCountLabel.setText(String.valueOf(UDPPortAReceiver.getPacketCount())); // 更新端口A计数
-            udpBPacketCountLabel.setText(String.valueOf(UDPPortBReceiver.getPacketCount())); // 更新端口B计数
+    private void startStatsTimer() {
+        statsTimer = new Timer(1000, e -> {
+            // 更新UDP端口A信息
+            int packetCountA = (int) UDPPortAReceiver.getPacketCount();
+            udpAInfoLabel.setText(Dell_SystemConfiguration.hexport + " - " + 
+                                 messages.getString("RECEIVED_PACKETS") + ": " + packetCountA);
+            
+            // 更新UDP端口B信息
+            int packetCountB = (int) UDPPortBReceiver.getPacketCount();
+            udpBInfoLabel.setText(Dell_SystemConfiguration.ascallport + " - " + 
+                                  messages.getString("RECEIVED_PACKETS") + ": " + packetCountB);
             
             // 更新内存使用情况
-            Runtime runtime = Runtime.getRuntime(); // 获取运行时实例
-            long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024); // 计算已用内存(MB)
-            long maxMemory = runtime.maxMemory() / (1024 * 1024); // 计算最大内存(MB)
-            memoryUsageLabel.setText(usedMemory + " " + messages.getString("MB") + " / " + maxMemory + " " + messages.getString("MB")); // 设置内存文本
+            Runtime runtime = Runtime.getRuntime();
+            long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024);
+            long maxMemory = runtime.maxMemory() / (1024 * 1024);
+            memoryUsageLabel.setText(usedMemory + " " + messages.getString("MB") + " / " + 
+                                    maxMemory + " " + messages.getString("MB"));
             
-            // 更新线程数量
-            threadCountLabel.setText(String.valueOf(Thread.activeCount())); // 设置活动线程数
+            // 更新线程数
+            threadCountLabel.setText(String.valueOf(Thread.activeCount()));
+            
+            // 更新标签状态
+            int onlineTags = Dell_tag.getOnlineLocationTags().size();
+            int totalTags = Dell_tag.getLocationTagCount();
+            tagStatsLabel.setText(onlineTags + " / " + totalTags);
+            
+            // 更新基站状态
+            int onlineStations = Dell_BaseStation.getOnlineBaseStations().size();
+            int totalStations = Dell_BaseStation.getLocationBaseCount();
+            baseStationStatsLabel.setText(onlineStations + " / " + totalStations);
         });
-        statsTimer.start(); // 启动定时器
+        statsTimer.start();
     }
     
     @Override
-    public void dispose() { // 销毁方法
-        super.dispose(); // 调用父类销毁
-        if (statsTimer != null) { // 检查定时器
-            statsTimer.stop(); // 停止定时器
+    public void dispose() {
+        super.dispose();
+        if (statsTimer != null) {
+            statsTimer.stop();
         }
     }
 }
\ No newline at end of file
diff --git a/systemfile/Messages_en.properties b/systemfile/Messages_en.properties
index ea593dd..d565c51 100644
--- a/systemfile/Messages_en.properties
+++ b/systemfile/Messages_en.properties
@@ -1,3 +1,12 @@
+TAG_STATS = Tag Statistics  
+BASE_STATION_STATS = Base Station Statistics  
+SOFTWARE_VERSION = Software Version  
+APP_VERSION = 1.0.0  
+UDP_PORT_A = UDP Receive Port A  
+UDP_PORT_B = UDP Receive Port B  
+DB_VERSION = Database Version  
+DB_STATUS = Database Status
+RECEIVED_PACKETS=Received
 # New message viewing related resources
 MESSAGE_VIEW_ALL_TYPES=All Types
 MESSAGE_VIEW_UDP_PORT_A=UDP Port A
diff --git a/systemfile/Messages_zh.properties b/systemfile/Messages_zh.properties
index f809f94..891f3c5 100644
--- a/systemfile/Messages_zh.properties
+++ b/systemfile/Messages_zh.properties
@@ -1,3 +1,12 @@
+TAG_STATS=鏍囩缁熻
+BASE_STATION_STATS=鍩虹珯缁熻
+SOFTWARE_VERSION=杞欢鐗堟湰
+APP_VERSION=1.0.0
+UDP_PORT_A=鏁版嵁鎺ユ敹绔彛
+UDP_PORT_B=鏁版嵁鎺ユ敹绔彛
+DB_VERSION=鏁版嵁搴撶増鏈�
+DB_STATUS=鏁版嵁搴撶姸鎬�
+RECEIVED_PACKETS=鎺ユ敹
 # 鏂板鐨勬姤鏂囨煡鐪嬬浉鍏宠祫婧�
 MESSAGE_VIEW_ALL_TYPES=鎵�鏈夌被鍨�
 MESSAGE_VIEW_UDP_PORT_A=UDP绔彛A
@@ -483,8 +492,6 @@
 MESSAGE_VIEW_EMPTY_DATA=鍙戦�佸唴瀹逛笉鑳戒负绌�
 ERROR=閿欒
 # 娆㈣繋鐣岄潰鐩戞帶
-UDP_PORT_A=UDP绔彛A (8234)
-UDP_PORT_B=UDP绔彛B (7000)
 MEMORY_USAGE=鍐呭瓨浣跨敤
 THREAD_COUNT=绾跨▼鏁伴噺
 MB=MB
diff --git a/systemfile/logfile/openlog.txt b/systemfile/logfile/openlog.txt
index f8a393f..f73e05b 100644
--- a/systemfile/logfile/openlog.txt
+++ b/systemfile/logfile/openlog.txt
@@ -701,3 +701,83 @@
 工作时长: 0小时 4分钟 12秒
 -----------------------------------
 程序启动: 2025-08-09 16:32:39
+程序关闭: 2025-08-09 20:05:40
+工作时长: 3小时 33分钟 1秒
+-----------------------------------
+程序启动: 2025-08-09 20:07:08
+程序关闭: 2025-08-09 20:11:43
+工作时长: 0小时 4分钟 35秒
+-----------------------------------
+程序启动: 2025-08-09 20:11:46
+程序关闭: 2025-08-09 21:57:03
+工作时长: 1小时 45分钟 17秒
+-----------------------------------
+程序启动: 2025-08-09 21:57:05
+程序关闭: 2025-08-09 22:02:50
+工作时长: 0小时 5分钟 44秒
+-----------------------------------
+程序启动: 2025-08-09 22:12:39
+程序关闭: 2025-08-09 22:21:24
+工作时长: 0小时 8分钟 45秒
+-----------------------------------
+程序启动: 2025-08-09 22:21:26
+程序关闭: 2025-08-09 22:31:29
+工作时长: 0小时 10分钟 2秒
+-----------------------------------
+程序启动: 2025-08-09 22:31:30
+程序关闭: 2025-08-09 22:31:44
+工作时长: 0小时 0分钟 13秒
+-----------------------------------
+程序启动: 2025-08-09 22:31:59
+程序关闭: 2025-08-09 22:44:51
+工作时长: 0小时 12分钟 52秒
+-----------------------------------
+程序启动: 2025-08-09 22:44:53
+程序关闭: 2025-08-09 22:44:55
+工作时长: 0小时 0分钟 1秒
+-----------------------------------
+程序启动: 2025-08-09 22:45:33
+程序关闭: 2025-08-09 22:45:35
+工作时长: 0小时 0分钟 1秒
+-----------------------------------
+程序启动: 2025-08-09 22:46:58
+程序关闭: 2025-08-09 22:49:10
+工作时长: 0小时 2分钟 12秒
+-----------------------------------
+程序启动: 2025-08-09 22:49:12
+程序关闭: 2025-08-09 22:58:17
+工作时长: 0小时 9分钟 4秒
+-----------------------------------
+程序启动: 2025-08-09 22:58:19
+程序关闭: 2025-08-09 23:09:45
+工作时长: 0小时 11分钟 25秒
+-----------------------------------
+程序启动: 2025-08-09 23:09:47
+程序关闭: 2025-08-09 23:19:34
+工作时长: 0小时 9分钟 46秒
+-----------------------------------
+程序启动: 2025-08-09 23:19:36
+程序关闭: 2025-08-09 23:19:51
+工作时长: 0小时 0分钟 14秒
+-----------------------------------
+程序启动: 2025-08-09 23:20:10
+程序关闭: 2025-08-09 23:20:15
+工作时长: 0小时 0分钟 5秒
+-----------------------------------
+程序启动: 2025-08-09 23:21:01
+程序关闭: 2025-08-09 23:21:05
+工作时长: 0小时 0分钟 4秒
+-----------------------------------
+程序启动: 2025-08-09 23:24:49
+程序关闭: 2025-08-09 23:29:56
+工作时长: 0小时 5分钟 6秒
+-----------------------------------
+程序启动: 2025-08-09 23:29:58
+程序关闭: 2025-08-09 23:30:36
+工作时长: 0小时 0分钟 38秒
+-----------------------------------
+程序启动: 2025-08-09 23:30:38
+程序关闭: 2025-08-09 23:30:52
+工作时长: 0小时 0分钟 14秒
+-----------------------------------
+程序启动: 2025-08-09 23:30:58

--
Gitblit v1.9.3