826220679@qq.com
2025-08-09 a8a90fd2d5040e66cc66b3da122a7f82561ff6f6
优化了欢迎页面
已修改8个文件
887 ■■■■■ 文件已修改
src/dell_targets/Dell_BaseStation.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/Dell_SystemConfiguration.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_targets/Dell_tag.java 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/udptcp/UDPPortAReceiver.java 198 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/window/WelcomeFrame.java 368 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
systemfile/Messages_en.properties 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
systemfile/Messages_zh.properties 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
systemfile/logfile/openlog.txt 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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();
    }
}
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
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();
    }
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();
    }
}
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();
        }
    }
}
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
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
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