张世豪
6 天以前 5d6d890cfd10466d5d14ff5177adcc888baaa0e4
src/set/Sets.java
@@ -1,9 +1,18 @@
package set;
import baseStation.BaseStation;
import zhuye.MapRenderer;
import zhuye.Shouye;
import zhuye.buttonset;
import set.Setsys;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -13,34 +22,43 @@
 */
public class Sets extends JDialog {
    private static final long serialVersionUID = 1L;
    private static final int ROW_HEIGHT = 40;
    private static final int ROW_SPACING = 25;
    private static final int ROW_HEIGHT = 50;  // 增加行高以适应分割线
    private static final int ITEM_PADDING = 16;  // 列表项内边距
    
    // 主题颜色
    private final Color THEME_COLOR;
    private final Color BACKGROUND_COLOR = new Color(250, 250, 250);
    private final Color PANEL_BACKGROUND = new Color(255, 255, 255);
    private final Color BORDER_COLOR = new Color(220, 220, 220);
    private final Color BACKGROUND_COLOR = new Color(245, 247, 250);  // 更柔和的浅灰色背景
    private final Color PANEL_BACKGROUND = new Color(255, 255, 255);  // 白色面板
    private final Color BORDER_COLOR = new Color(233, 236, 239);  // 浅边框色
    private final Color DIVIDER_COLOR = new Color(233, 236, 239);  // 分割线颜色
    
    // 设置项组件
    private JLabel mowerIdLabel;
    private JLabel baseStationIdLabel;
    private JLabel handheldMarkerLabel;
    private JLabel simCardNumberLabel;
    private JLabel baseStationSimLabel;
    private JLabel firmwareVersionLabel;
    private JLabel appVersionLabel;
    private JLabel idleTrailDurationLabel;
    private JLabel boundaryLengthVisibleLabel;
    
    private JButton mowerIdEditBtn;
    private JButton baseStationIdEditBtn;
    private JButton handheldEditBtn;
    private JButton checkUpdateBtn;
    private JButton feedbackButton;
    private JButton idleTrailEditBtn;
    
    // 数据模型
    private Setsys setData;
    private final BaseStation baseStation;
    
    public Sets(JFrame parent, Color themeColor) {
        super(parent, "系统设置", true);
        this.THEME_COLOR = themeColor;
        this.setData = new Setsys();
        this.baseStation = new BaseStation();
        initializeUI();
        loadData();
    }
@@ -49,6 +67,7 @@
        super(parent, "系统设置", true);
        this.THEME_COLOR = themeColor;
        this.setData = new Setsys();
        this.baseStation = new BaseStation();
        initializeUI();
        loadData();
    }
@@ -62,36 +81,53 @@
        setLocationRelativeTo(getParent());
        setResizable(false);
        
        // 创建主内容面板
        // 创建主内容面板(使用更柔和的浅灰色背景)
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        mainPanel.setLayout(new BorderLayout());
        mainPanel.setBackground(BACKGROUND_COLOR);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        
        // 创建设置项面板
        // 创建设置项面板(圆角白色面板)
        JPanel settingsPanel = createSettingsPanel();
        
        // 添加组件到主面板
        mainPanel.add(settingsPanel);
        mainPanel.add(Box.createVerticalGlue());
        mainPanel.add(settingsPanel, BorderLayout.CENTER);
        
        add(mainPanel, BorderLayout.CENTER);
    }
    
    private JPanel createSettingsPanel() {
        // 创建圆角白色面板容器
        JPanel container = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setColor(PANEL_BACKGROUND);
                // 绘制圆角矩形背景
                g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 16, 16);
                g2d.dispose();
            }
        };
        container.setLayout(new BorderLayout());
        container.setOpaque(false);
        // 内容面板
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setBackground(PANEL_BACKGROUND);
        panel.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER_COLOR),
            BorderFactory.createEmptyBorder(20, 20, 20, 20)
        ));
        panel.setOpaque(false);
        panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 8, 0));
        
        // 割草机编号
        JPanel mowerIdPanel = createSettingItemPanel("割草机编号", 
            setData.getMowerId() != null ? setData.getMowerId() : "未设置", true);
        mowerIdLabel = (JLabel) mowerIdPanel.getClientProperty("valueLabel");
        mowerIdEditBtn = (JButton) mowerIdPanel.getClientProperty("editButton");
        JPanel baseStationIdPanel = createSettingItemPanel("差分基准站编号",
            resolveBaseStationId(), true);
        baseStationIdLabel = (JLabel) baseStationIdPanel.getClientProperty("valueLabel");
        baseStationIdEditBtn = (JButton) baseStationIdPanel.getClientProperty("editButton");
        
        JPanel handheldPanel = createSettingItemPanel("便携打点器编号",
            setData.getHandheldMarkerId() != null ? setData.getHandheldMarkerId() : "未设置", true);
@@ -99,42 +135,81 @@
        handheldEditBtn = (JButton) handheldPanel.getClientProperty("editButton");
        // 物联卡号
        JPanel simCardPanel = createSettingItemPanel("物联卡号",
        JPanel simCardPanel = createSettingItemPanel("割草机物联网卡号",
            setData.getSimCardNumber() != null ? setData.getSimCardNumber() : "未设置", false);
        simCardNumberLabel = (JLabel) simCardPanel.getClientProperty("valueLabel");
        JPanel baseStationSimPanel = createSettingItemPanel("基准站物联网卡号",
            resolveBaseStationSimCard(), false);
        baseStationSimLabel = (JLabel) baseStationSimPanel.getClientProperty("valueLabel");
        
        // 固件版本
        JPanel firmwarePanel = createSettingItemPanel("固件版本", 
            setData.getFirmwareVersion() != null ? setData.getFirmwareVersion() : "未设置", false);
        firmwareVersionLabel = (JLabel) firmwarePanel.getClientProperty("valueLabel");
        JPanel idleTrailPanel = createSettingItemPanel("轨迹拖尾时长",
            formatIdleTrailDurationValue(), true);
        idleTrailDurationLabel = (JLabel) idleTrailPanel.getClientProperty("valueLabel");
        idleTrailEditBtn = (JButton) idleTrailPanel.getClientProperty("editButton");
        // 显示边界距离设置项
        JPanel boundaryLengthPanel = createBoundaryLengthPanel();
        boundaryLengthVisibleLabel = (JLabel) boundaryLengthPanel.getClientProperty("valueLabel");
        JPanel feedbackPanel = createFeedbackPanel();
        
        // APP版本
        JPanel appVersionPanel = createAppVersionPanel();
        
        addRowWithSpacing(panel, mowerIdPanel);
        addRowWithSpacing(panel, handheldPanel);
        addRowWithSpacing(panel, simCardPanel);
        addRowWithSpacing(panel, firmwarePanel);
        addRowWithSpacing(panel, feedbackPanel);
        panel.add(appVersionPanel);
        // 添加设置项,使用分割线分隔
        addSettingItem(panel, mowerIdPanel, true);
        addSettingItem(panel, baseStationIdPanel, true);
        addSettingItem(panel, handheldPanel, true);
        addSettingItem(panel, simCardPanel, true);
        addSettingItem(panel, baseStationSimPanel, true);
        addSettingItem(panel, firmwarePanel, true);
        addSettingItem(panel, idleTrailPanel, true);
        addSettingItem(panel, boundaryLengthPanel, true);
        addSettingItem(panel, feedbackPanel, true);
        addSettingItem(panel, appVersionPanel, false);  // 最后一项不加分割线
        
        return panel;
        container.add(panel, BorderLayout.CENTER);
        return container;
    }
    /**
     * 添加设置项(带分割线)
     */
    private void addSettingItem(JPanel container, JPanel itemPanel, boolean showDivider) {
        container.add(itemPanel);
        if (showDivider) {
            // 添加分割线
            JSeparator divider = new JSeparator();
            divider.setForeground(DIVIDER_COLOR);
            divider.setMaximumSize(new Dimension(Integer.MAX_VALUE, 1));
            divider.setAlignmentX(Component.LEFT_ALIGNMENT);
            container.add(divider);
        }
    }
    private void addRowWithSpacing(JPanel container, JPanel row) {
        container.add(row);
        container.add(Box.createRigidArea(new Dimension(0, ROW_SPACING)));
    private String formatIdleTrailDurationValue() {
        int seconds = setData != null ? setData.getIdleTrailDurationSeconds() : Setsys.DEFAULT_IDLE_TRAIL_DURATION_SECONDS;
        if (seconds <= 0) {
            seconds = Setsys.DEFAULT_IDLE_TRAIL_DURATION_SECONDS;
        }
        return seconds + "秒";
    }
    
    private JPanel createSettingItemPanel(String title, String value, boolean editable) {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setOpaque(false);  // 透明背景,由容器绘制
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
@@ -180,11 +255,12 @@
    
    private JPanel createAppVersionPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
@@ -209,28 +285,8 @@
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(appVersionLabel, gbc);
        checkUpdateBtn = new JButton("检查更新");
        checkUpdateBtn = buttonset.createStyledButton("检查更新", THEME_COLOR);
        checkUpdateBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        checkUpdateBtn.setBackground(THEME_COLOR);
        checkUpdateBtn.setForeground(Color.WHITE);
        checkUpdateBtn.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 12));
        checkUpdateBtn.setPreferredSize(new Dimension(90, 25));
        checkUpdateBtn.setMinimumSize(new Dimension(90, 25));
        checkUpdateBtn.setMaximumSize(new Dimension(90, 25));
        checkUpdateBtn.setFocusPainted(false);
        checkUpdateBtn.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                checkUpdateBtn.setBackground(new Color(
                    Math.max(THEME_COLOR.getRed() - 20, 0),
                    Math.max(THEME_COLOR.getGreen() - 20, 0),
                    Math.max(THEME_COLOR.getBlue() - 20, 0)
                ));
            }
            public void mouseExited(MouseEvent e) {
                checkUpdateBtn.setBackground(THEME_COLOR);
            }
        });
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
@@ -244,11 +300,12 @@
    private JPanel createFeedbackPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
@@ -263,30 +320,8 @@
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        feedbackButton = new JButton("反馈");
        feedbackButton = buttonset.createStyledButton("反馈", THEME_COLOR);
        feedbackButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        feedbackButton.setBackground(THEME_COLOR);
        feedbackButton.setForeground(Color.WHITE);
        feedbackButton.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
        feedbackButton.setPreferredSize(new Dimension(100, 28));
        feedbackButton.setMinimumSize(new Dimension(100, 28));
        feedbackButton.setMaximumSize(new Dimension(100, 28));
        feedbackButton.setFocusPainted(false);
        feedbackButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                feedbackButton.setBackground(new Color(
                        Math.max(THEME_COLOR.getRed() - 20, 0),
                        Math.max(THEME_COLOR.getGreen() - 20, 0),
                        Math.max(THEME_COLOR.getBlue() - 20, 0)));
            }
            @Override
            public void mouseExited(MouseEvent e) {
                feedbackButton.setBackground(THEME_COLOR);
            }
        });
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
@@ -298,6 +333,125 @@
        return panel;
    }
    
    /**
     * 创建显示边界距离设置面板
     */
    private JPanel createBoundaryLengthPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
        JLabel titleLabel = new JLabel("显示边界距离");
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(Color.BLACK);
        titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        boundaryLengthVisibleLabel = new JLabel(setData.isBoundaryLengthVisible() ? "已开启" : "已关闭");
        boundaryLengthVisibleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        boundaryLengthVisibleLabel.setForeground(Color.DARK_GRAY);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(boundaryLengthVisibleLabel, gbc);
        panel.putClientProperty("valueLabel", boundaryLengthVisibleLabel);
        // 创建切换按钮(使用图标)
        JButton toggleBtn = createBoundaryLengthToggleButton();
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(toggleBtn, gbc);
        panel.putClientProperty("toggleButton", toggleBtn);
        return panel;
    }
    /**
     * 创建边界距离显示切换按钮
     */
    private JButton createBoundaryLengthToggleButton() {
        JButton button = new JButton();
        button.setContentAreaFilled(false);
        button.setBorder(null);
        button.setFocusPainted(false);
        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
        button.setPreferredSize(new Dimension(32, 32));
        button.setMinimumSize(new Dimension(32, 32));
        button.setMaximumSize(new Dimension(32, 32));
        updateBoundaryLengthToggleButton(button);
        button.addActionListener(e -> toggleBoundaryLengthVisible(button));
        return button;
    }
    /**
     * 更新边界距离切换按钮图标
     */
    private void updateBoundaryLengthToggleButton(JButton button) {
        boolean isVisible = setData.isBoundaryLengthVisible();
        try {
            String iconPath = isVisible ? "image/open.png" : "image/close.png";
            ImageIcon icon = new ImageIcon(iconPath);
            if (icon.getIconWidth() > 0) {
                Image scaledImage = icon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                button.setIcon(new ImageIcon(scaledImage));
                button.setText(null);
            } else {
                button.setIcon(null);
                button.setText(isVisible ? "开" : "关");
            }
        } catch (Exception e) {
            button.setIcon(null);
            button.setText(isVisible ? "开" : "关");
            System.err.println("无法加载边界距离图标: " + e.getMessage());
        }
    }
    /**
     * 切换边界距离显示状态
     */
    private void toggleBoundaryLengthVisible(JButton button) {
        boolean newValue = !setData.isBoundaryLengthVisible();
        setData.setBoundaryLengthVisible(newValue);
        // 保存到配置文件
        setData.updateProperty("boundaryLengthVisible", String.valueOf(newValue));
        // 更新UI
        if (boundaryLengthVisibleLabel != null) {
            boundaryLengthVisibleLabel.setText(newValue ? "已开启" : "已关闭");
        }
        updateBoundaryLengthToggleButton(button);
        // 通知MapRenderer更新
        Shouye shouye = Shouye.getInstance();
        if (shouye != null) {
            MapRenderer renderer = shouye.getMapRenderer();
            if (renderer != null) {
                renderer.setBoundaryLengthVisible(newValue);
            }
        }
    }
    private JButton createEditButton() {
        JButton button = new JButton();
        try {
@@ -333,7 +487,50 @@
    private void loadData() {
        // 从Setsys类加载数据
        setData.initializeFromProperties();
        baseStation.load();
        updateDisplay();
        // 加载并应用上次保存的视图中心坐标
        loadViewCenterFromProperties();
    }
    /**
     * 从配置文件加载视图中心坐标并应用到MapRenderer
     */
    private void loadViewCenterFromProperties() {
        Shouye shouye = Shouye.getInstance();
        if (shouye == null) {
            return;
        }
        MapRenderer renderer = shouye.getMapRenderer();
        if (renderer == null) {
            return;
        }
        // 从配置文件读取视图中心坐标
        String viewCenterXValue = Setsys.getPropertyValue("viewCenterX");
        String viewCenterYValue = Setsys.getPropertyValue("viewCenterY");
        double savedTranslateX = 0.0;
        double savedTranslateY = 0.0;
        if (viewCenterXValue != null && !viewCenterXValue.trim().isEmpty()) {
            try {
                savedTranslateX = Double.parseDouble(viewCenterXValue.trim());
            } catch (NumberFormatException e) {
                savedTranslateX = 0.0;
            }
        }
        if (viewCenterYValue != null && !viewCenterYValue.trim().isEmpty()) {
            try {
                savedTranslateY = Double.parseDouble(viewCenterYValue.trim());
            } catch (NumberFormatException e) {
                savedTranslateY = 0.0;
            }
        }
        // 应用视图中心坐标(保持当前缩放比例)
        double currentScale = renderer.getScale();
        renderer.setViewTransform(currentScale, savedTranslateX, savedTranslateY);
    }
    
    private void updateDisplay() {
@@ -342,6 +539,10 @@
            mowerIdLabel.setText(setData.getMowerId() != null ? setData.getMowerId() : "未设置");
        }
        if (baseStationIdLabel != null) {
            baseStationIdLabel.setText(resolveBaseStationId());
        }
        if (handheldMarkerLabel != null) {
            handheldMarkerLabel.setText(setData.getHandheldMarkerId() != null ? setData.getHandheldMarkerId() : "未设置");
        }
@@ -351,12 +552,33 @@
            simCardNumberLabel.setText(setData.getSimCardNumber() != null ? 
                setData.getSimCardNumber() : "未设置");
        }
        if (baseStationSimLabel != null) {
            baseStationSimLabel.setText(resolveBaseStationSimCard());
        }
        
        // 更新固件版本显示
        if (firmwareVersionLabel != null) {
            firmwareVersionLabel.setText(setData.getFirmwareVersion() != null ? 
                setData.getFirmwareVersion() : "未设置");
        }
        if (idleTrailDurationLabel != null) {
            idleTrailDurationLabel.setText(formatIdleTrailDurationValue());
        }
        // 更新显示边界距离状态
        if (boundaryLengthVisibleLabel != null) {
            boundaryLengthVisibleLabel.setText(setData.isBoundaryLengthVisible() ? "已开启" : "已关闭");
        }
        // 更新切换按钮图标
        JPanel boundaryLengthPanel = (JPanel) boundaryLengthVisibleLabel.getParent();
        if (boundaryLengthPanel != null) {
            JButton toggleBtn = (JButton) boundaryLengthPanel.getClientProperty("toggleButton");
            if (toggleBtn != null) {
                updateBoundaryLengthToggleButton(toggleBtn);
            }
        }
        
        // 更新APP版本显示
        if (appVersionLabel != null) {
@@ -364,12 +586,46 @@
                setData.getAppVersion() : "未设置");
        }
    }
    private String resolveBaseStationSimCard() {
        if (baseStation == null) {
            return "未设置";
        }
        String value = baseStation.getIotSimCardNumber();
        if (value == null) {
            return "未设置";
        }
        String trimmed = value.trim();
        if (trimmed.isEmpty() || "-1".equals(trimmed)) {
            return "未设置";
        }
        return trimmed;
    }
    private String resolveBaseStationId() {
        if (baseStation == null) {
            return "未设置";
        }
        String value = baseStation.getDeviceId();
        if (value == null) {
            return "未设置";
        }
        String trimmed = value.trim();
        if (trimmed.isEmpty() || "-1".equals(trimmed)) {
            return "未设置";
        }
        return trimmed;
    }
    
    private void setupEventHandlers() {
        // 割草机编号编辑按钮事件
        if (mowerIdEditBtn != null) {
            mowerIdEditBtn.addActionListener(e -> editMowerId());
        }
        if (baseStationIdEditBtn != null) {
            baseStationIdEditBtn.addActionListener(e -> editBaseStationId());
        }
        
        // 检查更新按钮事件
        if (checkUpdateBtn != null) {
@@ -383,6 +639,10 @@
        if (feedbackButton != null) {
            feedbackButton.addActionListener(e -> showFeedbackDialog());
        }
        if (idleTrailEditBtn != null) {
            idleTrailEditBtn.addActionListener(e -> editIdleTrailDuration());
        }
        
    }
    
@@ -438,6 +698,97 @@
        }
    }
    private void editBaseStationId() {
        String currentValue = "未设置".equals(resolveBaseStationId()) ? "" : resolveBaseStationId();
        String newValue = (String) JOptionPane.showInputDialog(this,
                "请输入差分基准站编号:",
                "修改差分基准站编号",
                JOptionPane.QUESTION_MESSAGE,
                null,
                null,
                currentValue);
        if (newValue == null) {
            return;
        }
        newValue = newValue.trim();
        if (newValue.isEmpty()) {
            JOptionPane.showMessageDialog(this, "差分基准站编号不能为空", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        try {
            baseStation.updateByDeviceId(newValue,
                    baseStation.getInstallationCoordinates(),
                    baseStation.getIotSimCardNumber(),
                    baseStation.getDeviceActivationTime(),
                    baseStation.getDataUpdateTime());
            baseStation.load();
            if (baseStationIdLabel != null) {
                baseStationIdLabel.setText(resolveBaseStationId());
            }
            JOptionPane.showMessageDialog(this, "差分基准站编号更新成功", "成功", JOptionPane.INFORMATION_MESSAGE);
        } catch (IllegalArgumentException ex) {
            JOptionPane.showMessageDialog(this, ex.getMessage(), "输入错误", JOptionPane.WARNING_MESSAGE);
        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(this, "差分基准站编号更新失败", "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
    private void editIdleTrailDuration() {
        int currentSeconds = setData != null ? setData.getIdleTrailDurationSeconds() : Setsys.DEFAULT_IDLE_TRAIL_DURATION_SECONDS;
        if (currentSeconds <= 0) {
            currentSeconds = Setsys.DEFAULT_IDLE_TRAIL_DURATION_SECONDS;
        }
        String input = JOptionPane.showInputDialog(this,
            "请输入轨迹拖尾时长(单位:秒)",
            currentSeconds);
        if (input == null) {
            return;
        }
        String trimmed = input.trim();
        if (trimmed.isEmpty()) {
            JOptionPane.showMessageDialog(this, "轨迹拖尾时长不能为空", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        int parsedSeconds;
        try {
            parsedSeconds = Integer.parseInt(trimmed);
        } catch (NumberFormatException ex) {
            JOptionPane.showMessageDialog(this, "请输入有效的整数秒数", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        if (parsedSeconds < 5 || parsedSeconds > 600) {
            JOptionPane.showMessageDialog(this, "请输入5到600之间的秒数", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        if (setData.updateProperty("idleTrailDurationSeconds", String.valueOf(parsedSeconds))) {
            int appliedSeconds = setData.getIdleTrailDurationSeconds();
            if (idleTrailDurationLabel != null) {
                idleTrailDurationLabel.setText(appliedSeconds + "秒");
            }
            MapRenderer renderer = null;
            Shouye shouye = Shouye.getInstance();
            if (shouye != null) {
                renderer = shouye.getMapRenderer();
            }
            if (renderer != null) {
                renderer.setIdleTrailDurationSeconds(appliedSeconds);
            }
            JOptionPane.showMessageDialog(this, "轨迹拖尾时长已更新为 " + appliedSeconds + " 秒", "成功", JOptionPane.INFORMATION_MESSAGE);
        } else {
            JOptionPane.showMessageDialog(this, "轨迹拖尾时长更新失败", "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
    private void showFeedbackDialog() {
    JDialog dialog = new JDialog(this, "问题反馈咨询", true);
    dialog.setLayout(new BorderLayout(0, 12));
@@ -472,9 +823,8 @@
        photoControls.setAlignmentX(Component.LEFT_ALIGNMENT);
        JLabel photoLabel = new JLabel("选择照片(最多6张):");
        photoLabel.setFont(new Font("微软雅黑", Font.BOLD, 13));
        JButton selectPhotosButton = new JButton("选择照片");
        selectPhotosButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        selectPhotosButton.setFocusPainted(false);
    JButton selectPhotosButton = buttonset.createStyledButton("选择照片", THEME_COLOR);
    selectPhotosButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        photoControls.add(photoLabel);
        photoControls.add(selectPhotosButton);
    content.add(photoControls);
@@ -494,13 +844,11 @@
        content.add(Box.createRigidArea(new Dimension(0, 20)));
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton cancelButton = new JButton("放弃");
        JButton submitButton = new JButton("提交");
        submitButton.setBackground(THEME_COLOR);
        submitButton.setForeground(Color.WHITE);
        submitButton.setFocusPainted(false);
        cancelButton.setFocusPainted(false);
    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    JButton cancelButton = buttonset.createStyledButton("放弃", new Color(128, 128, 128));
    cancelButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
    JButton submitButton = buttonset.createStyledButton("提交", THEME_COLOR);
    submitButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        buttonPanel.add(cancelButton);
        buttonPanel.add(submitButton);