张世豪
7 天以前 68b1f4e85c29164d5de189262282454f9a0b1cc0
src/set/Sets.java
@@ -1,9 +1,20 @@
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.io.File;
import java.util.ArrayList;
import java.util.List;
/**
 * 设置对话框 - 参考Shouye.java样式
@@ -21,20 +32,30 @@
    
    // 设置项组件
    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 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();
    }
@@ -43,6 +64,7 @@
        super(parent, "系统设置", true);
        this.THEME_COLOR = themeColor;
        this.setData = new Setsys();
        this.baseStation = new BaseStation();
        initializeUI();
        loadData();
    }
@@ -86,28 +108,62 @@
            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);
        handheldMarkerLabel = (JLabel) handheldPanel.getClientProperty("valueLabel");
        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 feedbackPanel = createFeedbackPanel();
        
        // APP版本
        JPanel appVersionPanel = createAppVersionPanel();
        
        addRowWithSpacing(panel, mowerIdPanel);
        addRowWithSpacing(panel, simCardPanel);
        addRowWithSpacing(panel, firmwarePanel);
        panel.add(appVersionPanel);
    addRowWithSpacing(panel, mowerIdPanel);
    addRowWithSpacing(panel, baseStationIdPanel);
        addRowWithSpacing(panel, handheldPanel);
    addRowWithSpacing(panel, simCardPanel);
    addRowWithSpacing(panel, baseStationSimPanel);
    addRowWithSpacing(panel, firmwarePanel);
    addRowWithSpacing(panel, idleTrailPanel);
    addRowWithSpacing(panel, feedbackPanel);
    addRowWithSpacing(panel, appVersionPanel);
        
        return panel;
    }
    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 void addRowWithSpacing(JPanel container, JPanel row) {
        container.add(row);
        container.add(Box.createRigidArea(new Dimension(0, ROW_SPACING)));
@@ -194,28 +250,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;
@@ -226,6 +262,40 @@
        return panel;
    }
    private JPanel createFeedbackPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        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));
        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);
        feedbackButton = buttonset.createStyledButton("反馈", THEME_COLOR);
        feedbackButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(feedbackButton, gbc);
        return panel;
    }
    
    private JButton createEditButton() {
        JButton button = new JButton();
@@ -262,7 +332,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() {
@@ -270,18 +383,34 @@
        if (mowerIdLabel != null) {
            mowerIdLabel.setText(setData.getMowerId() != null ? setData.getMowerId() : "未设置");
        }
        if (baseStationIdLabel != null) {
            baseStationIdLabel.setText(resolveBaseStationId());
        }
        if (handheldMarkerLabel != null) {
            handheldMarkerLabel.setText(setData.getHandheldMarkerId() != null ? setData.getHandheldMarkerId() : "未设置");
        }
        
        // 更新物联卡号显示
        if (simCardNumberLabel != null) {
            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());
        }
        
        // 更新APP版本显示
        if (appVersionLabel != null) {
@@ -289,17 +418,63 @@
                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) {
            checkUpdateBtn.addActionListener(e -> checkForUpdates());
        }
        if (handheldEditBtn != null) {
            handheldEditBtn.addActionListener(e -> editHandheldMarkerId());
        }
        if (feedbackButton != null) {
            feedbackButton.addActionListener(e -> showFeedbackDialog());
        }
        if (idleTrailEditBtn != null) {
            idleTrailEditBtn.addActionListener(e -> editIdleTrailDuration());
        }
        
    }
    
@@ -327,6 +502,271 @@
            }
        }
    }
    private void editHandheldMarkerId() {
        String currentValue = setData.getHandheldMarkerId() != null ? setData.getHandheldMarkerId() : "";
        String newValue = (String) JOptionPane.showInputDialog(this,
                "请输入便携打点器编号:",
                "修改便携打点器编号",
                JOptionPane.QUESTION_MESSAGE,
                null,
                null,
                currentValue);
        if (newValue == null) {
            return;
        }
        newValue = newValue.trim();
        if (!newValue.isEmpty()) {
            if (setData.updateProperty("handheldMarkerId", newValue)) {
                if (handheldMarkerLabel != null) {
                    handheldMarkerLabel.setText(newValue);
                }
                JOptionPane.showMessageDialog(this, "便携打点器编号更新成功", "成功", JOptionPane.INFORMATION_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(this, "便携打点器编号更新失败", "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    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));
    dialog.setResizable(false);
    dialog.setPreferredSize(new Dimension(400, 800));
    dialog.setSize(new Dimension(400, 800));
    dialog.setMinimumSize(new Dimension(400, 800));
    JPanel content = new JPanel();
    content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
    content.setBorder(BorderFactory.createEmptyBorder(20, 24, 20, 24));
    dialog.add(content, BorderLayout.CENTER);
        JLabel descriptionLabel = new JLabel("问题描述:");
        descriptionLabel.setFont(new Font("微软雅黑", Font.BOLD, 13));
        descriptionLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        content.add(descriptionLabel);
        content.add(Box.createRigidArea(new Dimension(0, 8)));
        JTextArea descriptionArea = new JTextArea(5, 30);
        descriptionArea.setLineWrap(true);
        descriptionArea.setWrapStyleWord(true);
        descriptionArea.setFont(new Font("微软雅黑", Font.PLAIN, 13));
        JScrollPane scrollPane = new JScrollPane(descriptionArea);
        scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
        content.add(scrollPane);
        content.add(Box.createRigidArea(new Dimension(0, 16)));
        JPanel photoControls = new JPanel(new FlowLayout(FlowLayout.LEFT, 12, 0));
        photoControls.setAlignmentX(Component.LEFT_ALIGNMENT);
        JLabel photoLabel = new JLabel("选择照片(最多6张):");
        photoLabel.setFont(new Font("微软雅黑", Font.BOLD, 13));
    JButton selectPhotosButton = buttonset.createStyledButton("选择照片", THEME_COLOR);
    selectPhotosButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        photoControls.add(photoLabel);
        photoControls.add(selectPhotosButton);
    content.add(photoControls);
    content.add(Box.createRigidArea(new Dimension(0, 20)));
        JPanel photoGrid = new JPanel(new GridLayout(2, 3, 12, 12));
        photoGrid.setAlignmentX(Component.LEFT_ALIGNMENT);
        photoGrid.setMaximumSize(new Dimension(Integer.MAX_VALUE, 220));
        List<JLabel> photoSlots = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            JLabel slot = buildPhotoSlot();
            photoGrid.add(slot);
            photoSlots.add(slot);
        }
        content.add(photoGrid);
        content.add(Box.createRigidArea(new Dimension(0, 20)));
    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);
        dialog.add(buttonPanel, BorderLayout.SOUTH);
        List<File> selectedPhotos = new ArrayList<>();
        selectPhotosButton.addActionListener(e -> {
            JFileChooser chooser = new JFileChooser();
            chooser.setMultiSelectionEnabled(true);
            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            chooser.setFileFilter(new FileNameExtensionFilter("图片文件", "jpg", "jpeg", "png", "bmp", "gif", "webp"));
            if (chooser.showOpenDialog(dialog) == JFileChooser.APPROVE_OPTION) {
                File[] files = chooser.getSelectedFiles();
                if (files != null) {
                    if (selectedPhotos.size() >= 6) {
                        JOptionPane.showMessageDialog(dialog, "已达到6张照片上限", "提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                    for (File file : files) {
                        if (selectedPhotos.size() >= 6) {
                            break;
                        }
                        if (file != null && file.exists() && file.isFile()) {
                            selectedPhotos.add(file);
                        }
                    }
                    updatePhotoPreview(photoSlots, selectedPhotos);
                }
            }
        });
        cancelButton.addActionListener(e -> dialog.dispose());
        submitButton.addActionListener(e -> {
            String description = descriptionArea.getText() != null ? descriptionArea.getText().trim() : "";
            if (description.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "请填写问题描述", "提示", JOptionPane.WARNING_MESSAGE);
                descriptionArea.requestFocusInWindow();
                return;
            }
            // 提交逻辑占位
            JOptionPane.showMessageDialog(dialog,
                    "反馈已提交,感谢您的支持!\n描述字数:" + description.length() + ",照片数量:" + selectedPhotos.size(),
                    "提交成功",
                    JOptionPane.INFORMATION_MESSAGE);
            dialog.dispose();
        });
        dialog.pack();
        dialog.setLocationRelativeTo(this);
        dialog.setVisible(true);
    }
    private JLabel buildPhotoSlot() {
        JLabel slot = new JLabel();
        slot.setPreferredSize(new Dimension(100, 100));
        slot.setMinimumSize(new Dimension(100, 100));
        slot.setOpaque(true);
        slot.setBackground(new Color(245, 245, 245));
        slot.setHorizontalAlignment(SwingConstants.CENTER);
        slot.setVerticalAlignment(SwingConstants.CENTER);
        slot.setBorder(BorderFactory.createLineBorder(new Color(220, 220, 220), 1));
        slot.setText("+");
        slot.setFont(new Font("微软雅黑", Font.BOLD, 18));
        slot.setForeground(new Color(180, 180, 180));
        return slot;
    }
    private void updatePhotoPreview(List<JLabel> slots, List<File> photos) {
        for (int i = 0; i < slots.size(); i++) {
            JLabel slot = slots.get(i);
            if (i < photos.size()) {
                File photo = photos.get(i);
                ImageIcon icon = new ImageIcon(photo.getAbsolutePath());
                Image scaled = icon.getImage().getScaledInstance(100, 100, Image.SCALE_SMOOTH);
                slot.setIcon(new ImageIcon(scaled));
                slot.setText(null);
            } else {
                slot.setIcon(null);
                slot.setText("+");
            }
        }
    }
    
    private void checkForUpdates() {
        // 模拟检查更新过程