| | |
| | | private static final Color DARK_LIGHT_COLOR = new Color(26, 43, 68); |
| | | private static final Color TEXT_COLOR = new Color(224, 224, 224); |
| | | private static final Color TEXT_LIGHT_COLOR = new Color(160, 200, 255); |
| | | private static final Color DELETE_COLOR = new Color(231, 76, 60); // 删除按钮颜色 |
| | | private static final Color ACTIVE_BUTTON_COLOR = new Color(41, 128, 185); // 激活按钮颜色 |
| | | |
| | | private JPanel mainPanel; |
| | | private JLabel titleLabel; |
| | | private JButton logButton; // 日志记录按钮 |
| | | private JButton errorLogButton; // 错误日志按钮 |
| | | private JButton backButton; |
| | | private JButton deleteAllButton; |
| | | |
| | | // 文本域组件 |
| | | private JScrollPane textScrollPane; |
| | | private JTextArea contentTextArea; |
| | | |
| | | // 当前显示的日志类型 |
| | | private String currentLogType = "log"; // "log" 或 "error" |
| | | |
| | | public lishijilu(JFrame parent) { |
| | | super(parent, "", true); |
| | | initializeUI(); |
| | | setupEventListeners(); |
| | | loadLogContent(); // 加载日志内容 |
| | | loadLogContent(); // 默认加载操作日志 |
| | | } |
| | | |
| | | private void initializeUI() { |
| | |
| | | headerPanel.setOpaque(false); |
| | | headerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 12, 0)); |
| | | |
| | | // 标题 |
| | | titleLabel = new JLabel("历史记录"); |
| | | titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 22)); |
| | | titleLabel.setForeground(TEXT_COLOR); |
| | | // 创建日志类型选择按钮面板 |
| | | JPanel logTypePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0)); |
| | | logTypePanel.setOpaque(false); |
| | | |
| | | // 返回按钮 - 使用不透明设计 |
| | | // 日志记录按钮 |
| | | logButton = new JButton("日志记录"); |
| | | logButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); |
| | | logButton.setBackground(ACTIVE_BUTTON_COLOR); // 默认激活状态 |
| | | logButton.setForeground(Color.WHITE); |
| | | logButton.setOpaque(true); |
| | | logButton.setFocusPainted(false); |
| | | logButton.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); |
| | | logButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); |
| | | |
| | | // 错误日志按钮 |
| | | errorLogButton = new JButton("错误日志"); |
| | | errorLogButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); |
| | | errorLogButton.setBackground(PRIMARY_COLOR); // 默认非激活状态 |
| | | errorLogButton.setForeground(Color.WHITE); |
| | | errorLogButton.setOpaque(true); |
| | | errorLogButton.setFocusPainted(false); |
| | | errorLogButton.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); |
| | | errorLogButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); |
| | | |
| | | logTypePanel.add(logButton); |
| | | logTypePanel.add(errorLogButton); |
| | | |
| | | // 操作按钮面板 |
| | | JPanel actionButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0)); |
| | | actionButtonPanel.setOpaque(false); |
| | | |
| | | // 删除全部记录按钮 |
| | | deleteAllButton = new JButton("删除全部"); |
| | | deleteAllButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); |
| | | deleteAllButton.setBackground(DELETE_COLOR); |
| | | deleteAllButton.setForeground(Color.WHITE); |
| | | deleteAllButton.setOpaque(true); |
| | | deleteAllButton.setFocusPainted(false); |
| | | deleteAllButton.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); |
| | | deleteAllButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); |
| | | |
| | | // 返回按钮 |
| | | backButton = new JButton("关闭"); |
| | | backButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); |
| | | backButton.setBackground(PRIMARY_COLOR); |
| | |
| | | backButton.setFocusPainted(false); |
| | | backButton.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); |
| | | backButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); |
| | | |
| | | actionButtonPanel.add(deleteAllButton); |
| | | actionButtonPanel.add(backButton); |
| | | |
| | | // 按钮悬停效果 |
| | | setupButtonHoverEffects(); |
| | | |
| | | headerPanel.add(logTypePanel, BorderLayout.WEST); |
| | | headerPanel.add(actionButtonPanel, BorderLayout.EAST); |
| | | |
| | | return headerPanel; |
| | | } |
| | | |
| | | private void setupButtonHoverEffects() { |
| | | // 日志按钮悬停效果 |
| | | logButton.addMouseListener(new java.awt.event.MouseAdapter() { |
| | | public void mouseEntered(java.awt.event.MouseEvent evt) { |
| | | if (!currentLogType.equals("log")) { |
| | | logButton.setBackground(brighterColor(PRIMARY_COLOR)); |
| | | } |
| | | } |
| | | |
| | | public void mouseExited(java.awt.event.MouseEvent evt) { |
| | | if (!currentLogType.equals("log")) { |
| | | logButton.setBackground(PRIMARY_COLOR); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | // 错误日志按钮悬停效果 |
| | | errorLogButton.addMouseListener(new java.awt.event.MouseAdapter() { |
| | | public void mouseEntered(java.awt.event.MouseEvent evt) { |
| | | if (!currentLogType.equals("error")) { |
| | | errorLogButton.setBackground(brighterColor(PRIMARY_COLOR)); |
| | | } |
| | | } |
| | | |
| | | public void mouseExited(java.awt.event.MouseEvent evt) { |
| | | if (!currentLogType.equals("error")) { |
| | | errorLogButton.setBackground(PRIMARY_COLOR); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | // 删除按钮悬停效果 |
| | | deleteAllButton.addMouseListener(new java.awt.event.MouseAdapter() { |
| | | public void mouseEntered(java.awt.event.MouseEvent evt) { |
| | | deleteAllButton.setBackground(brighterColor(DELETE_COLOR)); |
| | | } |
| | | |
| | | public void mouseExited(java.awt.event.MouseEvent evt) { |
| | | deleteAllButton.setBackground(DELETE_COLOR); |
| | | } |
| | | }); |
| | | |
| | | // 返回按钮悬停效果 |
| | | backButton.addMouseListener(new java.awt.event.MouseAdapter() { |
| | |
| | | backButton.setBackground(PRIMARY_COLOR); |
| | | } |
| | | }); |
| | | |
| | | JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); |
| | | titlePanel.setOpaque(false); |
| | | titlePanel.add(titleLabel); |
| | | |
| | | JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
| | | buttonPanel.setOpaque(false); |
| | | buttonPanel.add(backButton); |
| | | |
| | | headerPanel.add(titlePanel, BorderLayout.WEST); |
| | | headerPanel.add(buttonPanel, BorderLayout.EAST); |
| | | |
| | | return headerPanel; |
| | | } |
| | | |
| | | private JPanel createContentPanel() { |
| | |
| | | backButton.addActionListener(e -> { |
| | | dispose(); |
| | | }); |
| | | |
| | | // 删除全部记录按钮 |
| | | deleteAllButton.addActionListener(e -> { |
| | | deleteAllRecords(); |
| | | }); |
| | | |
| | | // 日志记录按钮 |
| | | logButton.addActionListener(e -> { |
| | | switchToLogType("log"); |
| | | }); |
| | | |
| | | // 错误日志按钮 |
| | | errorLogButton.addActionListener(e -> { |
| | | switchToLogType("error"); |
| | | }); |
| | | } |
| | | |
| | | // 切换日志类型 |
| | | private void switchToLogType(String logType) { |
| | | if (currentLogType.equals(logType)) { |
| | | return; // 已经是当前类型,无需切换 |
| | | } |
| | | |
| | | currentLogType = logType; |
| | | |
| | | // 更新按钮状态 |
| | | if (logType.equals("log")) { |
| | | logButton.setBackground(ACTIVE_BUTTON_COLOR); |
| | | errorLogButton.setBackground(PRIMARY_COLOR); |
| | | } else { |
| | | logButton.setBackground(PRIMARY_COLOR); |
| | | errorLogButton.setBackground(ACTIVE_BUTTON_COLOR); |
| | | } |
| | | |
| | | // 加载对应类型的日志内容 |
| | | loadLogContent(); |
| | | } |
| | | |
| | | // 删除全部记录的方法 |
| | | private void deleteAllRecords() { |
| | | // 确认对话框 |
| | | String logTypeName = currentLogType.equals("log") ? "操作" : "错误"; |
| | | int result = JOptionPane.showConfirmDialog( |
| | | this, |
| | | "确定要删除所有" + logTypeName + "记录吗?此操作不可恢复!", |
| | | "确认删除", |
| | | JOptionPane.YES_NO_OPTION, |
| | | JOptionPane.WARNING_MESSAGE |
| | | ); |
| | | |
| | | if (result == JOptionPane.YES_OPTION) { |
| | | try { |
| | | String fileName = currentLogType.equals("log") ? "log.properties" : "err.properties"; |
| | | File logFile = new File(fileName); |
| | | |
| | | if (logFile.exists()) { |
| | | // 创建空的Properties对象并写入文件 |
| | | Properties emptyProps = new Properties(); |
| | | try (FileOutputStream out = new FileOutputStream(logFile); |
| | | OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8")) { |
| | | emptyProps.store(writer, "发卡机" + logTypeName + "记录 - 所有记录已清空"); |
| | | } |
| | | |
| | | // 更新文本域显示 |
| | | contentTextArea.setText("所有" + logTypeName + "记录已成功删除。\n\n日志文件已清空。"); |
| | | |
| | | // 显示成功消息 |
| | | JOptionPane.showMessageDialog( |
| | | this, |
| | | "所有" + logTypeName + "记录已成功删除。", |
| | | "删除成功", |
| | | JOptionPane.INFORMATION_MESSAGE |
| | | ); |
| | | } else { |
| | | contentTextArea.setText(logTypeName + "日志文件不存在,无需删除。"); |
| | | } |
| | | |
| | | } catch (IOException ex) { |
| | | ex.printStackTrace(); |
| | | JOptionPane.showMessageDialog( |
| | | this, |
| | | "删除记录时出错: " + ex.getMessage(), |
| | | "错误", |
| | | JOptionPane.ERROR_MESSAGE |
| | | ); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 加载日志内容 |
| | | private void loadLogContent() { |
| | | File logFile = new File("log.properties"); |
| | | String fileName = currentLogType.equals("log") ? "log.properties" : "err.properties"; |
| | | String logTypeName = currentLogType.equals("log") ? "操作" : "错误"; |
| | | |
| | | File logFile = new File(fileName); |
| | | |
| | | if (!logFile.exists()) { |
| | | contentTextArea.setText("日志文件不存在。"); |
| | | contentTextArea.setText(logTypeName + "日志文件不存在。"); |
| | | return; |
| | | } |
| | | |
| | | Properties logProps = new Properties(); |
| | | try (FileInputStream in = new FileInputStream(logFile)) { |
| | | logProps.load(in); |
| | | try (FileInputStream in = new FileInputStream(logFile); |
| | | InputStreamReader reader = new InputStreamReader(in, "UTF-8")) { |
| | | |
| | | logProps.load(reader); |
| | | |
| | | // 检查记录数量,如果超过1000条则删除旧记录 |
| | | if (logProps.size() > 1000) { |
| | | trimLogProperties(logProps); |
| | | trimLogProperties(logProps, fileName); |
| | | } |
| | | |
| | | // 构建显示内容 |
| | | StringBuilder content = new StringBuilder(); |
| | | content.append("日志文件内容 (").append(logProps.size()).append(" 条记录):\n\n"); |
| | | content.append(logTypeName).append("日志内容 (").append(logProps.size()).append(" 条记录):\n\n"); |
| | | |
| | | // 按时间戳排序显示 |
| | | logProps.stringPropertyNames().stream() |
| | | .sorted((a, b) -> Long.compare(Long.parseLong(b), Long.parseLong(a))) |
| | | .sorted((a, b) -> { |
| | | try { |
| | | // 从键中提取时间戳部分进行比较 |
| | | long timeA = extractTimestampFromKey(a); |
| | | long timeB = extractTimestampFromKey(b); |
| | | return Long.compare(timeB, timeA); // 降序排列,最新的在前 |
| | | } catch (Exception e) { |
| | | return b.compareTo(a); // 如果提取失败,使用字符串比较 |
| | | } |
| | | }) |
| | | .forEach(key -> { |
| | | String value = logProps.getProperty(key); |
| | | content.append("时间戳: ").append(key).append("\n"); |
| | | content.append("内容: ").append(value).append("\n"); |
| | | content.append("时间: ").append(extractTimeFromValue(value)).append("\n"); |
| | | content.append("内容: ").append(extractOperationFromValue(value)).append("\n"); |
| | | content.append("----------------------------------------\n"); |
| | | }); |
| | | |
| | |
| | | |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | contentTextArea.setText("加载日志文件时出错: " + e.getMessage()); |
| | | } catch (NumberFormatException e) { |
| | | contentTextArea.setText("日志文件格式错误。"); |
| | | contentTextArea.setText("加载" + logTypeName + "日志文件时出错: " + e.getMessage()); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | contentTextArea.setText("处理" + logTypeName + "日志内容时出错: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | // 从键中提取时间戳 |
| | | private long extractTimestampFromKey(String key) { |
| | | try { |
| | | // 键的格式: log_时间戳_UUID 或 error_时间戳_UUID |
| | | String[] parts = key.split("_"); |
| | | if (parts.length >= 2) { |
| | | return Long.parseLong(parts[1]); |
| | | } |
| | | } catch (Exception e) { |
| | | // 如果解析失败,返回0 |
| | | } |
| | | return 0L; |
| | | } |
| | | |
| | | // 从值中提取时间部分 |
| | | private String extractTimeFromValue(String value) { |
| | | if (value == null) return "未知时间"; |
| | | // 值的格式: [2025-11-21 14:44:39] 取卡操作:卡槽19被管理员取卡 |
| | | int start = value.indexOf('['); |
| | | int end = value.indexOf(']'); |
| | | if (start >= 0 && end > start) { |
| | | return value.substring(start + 1, end); |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | // 从值中提取操作部分 |
| | | private String extractOperationFromValue(String value) { |
| | | if (value == null) return "未知内容"; |
| | | // 值的格式: [2025-11-21 14:44:39] 取卡操作:卡槽19被管理员取卡 |
| | | int end = value.indexOf(']'); |
| | | if (end >= 0 && end + 1 < value.length()) { |
| | | return value.substring(end + 1).trim(); |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | // 修剪日志属性,只保留最新的1000条记录 |
| | | private void trimLogProperties(Properties logProps) { |
| | | private void trimLogProperties(Properties logProps, String fileName) { |
| | | // 按时间戳排序,保留最新的1000条 |
| | | logProps.stringPropertyNames().stream() |
| | | .sorted((a, b) -> Long.compare(Long.parseLong(b), Long.parseLong(a))) |
| | | .sorted((a, b) -> { |
| | | try { |
| | | long timeA = extractTimestampFromKey(a); |
| | | long timeB = extractTimestampFromKey(b); |
| | | return Long.compare(timeB, timeA); |
| | | } catch (Exception e) { |
| | | return b.compareTo(a); |
| | | } |
| | | }) |
| | | .skip(1000) |
| | | .forEach(logProps::remove); |
| | | |
| | | // 保存修剪后的属性 |
| | | try (FileOutputStream out = new FileOutputStream("log.properties")) { |
| | | logProps.store(out, "UWB人员定位卡发卡机历史记录 - 自动修剪至1000条记录"); |
| | | try (FileOutputStream out = new FileOutputStream(fileName); |
| | | OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8")) { |
| | | String logTypeName = fileName.equals("log.properties") ? "操作" : "错误"; |
| | | logProps.store(writer, "发卡机" + logTypeName + "记录 - 自动修剪至1000条记录"); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | |
| | | dialog.setVisible(true); |
| | | }); |
| | | } |
| | | |
| | | } |