日志记录模块

pull/1/head
123 3 weeks ago
parent 98ef0e33c8
commit b7d44f76f6

@ -27,7 +27,9 @@ SOURCES += \
src/ui/main/MainWindow.cpp \ src/ui/main/MainWindow.cpp \
src/ui/dialogs/DeviceDialog.cpp \ src/ui/dialogs/DeviceDialog.cpp \
src/ui/components/DeviceCard.cpp \ src/ui/components/DeviceCard.cpp \
src/ui/components/DeviceListPanel.cpp src/ui/components/DeviceListPanel.cpp \
src/ui/components/SystemLogPanel.cpp \
src/utils/SystemLogger.cpp
# Header files - 按模块组织 # Header files - 按模块组织
HEADERS += \ HEADERS += \
@ -36,7 +38,9 @@ HEADERS += \
include/ui/main/MainWindow.h \ include/ui/main/MainWindow.h \
include/ui/dialogs/DeviceDialog.h \ include/ui/dialogs/DeviceDialog.h \
include/ui/components/DeviceCard.h \ include/ui/components/DeviceCard.h \
include/ui/components/DeviceListPanel.h include/ui/components/DeviceListPanel.h \
include/ui/components/SystemLogPanel.h \
include/utils/SystemLogger.h
# UI forms - 按模块组织 # UI forms - 按模块组织
FORMS += \ FORMS += \

@ -24,6 +24,7 @@ API文档、组件设计、技术实现细节等
**当前文档**: **当前文档**:
- `phase3_ui_refactor_plan.md` - Phase 3界面重构技术设计文档 - `phase3_ui_refactor_plan.md` - Phase 3界面重构技术设计文档
- `system_log_design.md` - 系统日志功能设计文档 (Phase 5)
**后续文档**: **后续文档**:
- `api_documentation.md` - API接口文档 - `api_documentation.md` - API接口文档
@ -52,8 +53,8 @@ API文档、组件设计、技术实现细节等
- `code_refactor_summary.md` - 代码重构和模块化改造总结 - `code_refactor_summary.md` - 代码重构和模块化改造总结
- `phase3_completion_report.md` - Phase 3界面重构完成报告 - `phase3_completion_report.md` - Phase 3界面重构完成报告
**后续文档**: **计划文档**:
- `phase2_completion_report.md` - Phase 2完成报告 - `phase5_completion_report.md` - Phase 5功能增强完成报告 (进行中)
- `testing_report.md` - 测试报告 - `testing_report.md` - 测试报告
- `performance_analysis.md` - 性能分析报告 - `performance_analysis.md` - 性能分析报告
- `final_project_report.md` - 最终项目报告 - `final_project_report.md` - 最终项目报告
@ -108,6 +109,9 @@ Git工作流程、分支策略、代码审查等
| 日期 | 文档 | 变更描述 | 作者 | | 日期 | 文档 | 变更描述 | 作者 |
|------|------|----------|------| |------|------|----------|------|
| 2025-06-18 | 全部 | 初始化文档目录结构迁移Phase 1文档 | Claude | | 2025-06-18 | 全部 | 初始化文档目录结构迁移Phase 1文档 | Claude |
| 2024-12-21 | task.md | 更新Phase 5系统日志功能开发进展 | Qt UI Developer |
| 2024-12-21 | system_log_design.md | 创建系统日志功能技术设计文档 | Qt UI Developer |
| 2024-12-21 | README.md | 更新文档索引,添加新的技术文档链接 | Qt UI Developer |
--- ---

@ -102,18 +102,25 @@
- [x] 添加数据统计图表显示 - [x] 添加数据统计图表显示
- [x] 添加系统运行状态指示器 - [x] 添加系统运行状态指示器
### Phase 5: 功能模块重构和增强 (优先级: 中) ### Phase 5: 功能模块重构和增强 (优先级: 中) 🚧 **进行中**
#### 5.1 设备管理功能增强 #### 5.1 系统日志功能开发 🚧 **当前任务**
- [x] **UI重构**: 删除重复的设备管理按钮,为系统日志让出空间
- [ ] **组件开发**: 创建SystemLogPanel组件和SystemLogger单例管理器
- [ ] **界面集成**: 使用QSplitter实现日志与设备管理的35%:65%空间分配
- [ ] **日志功能**: 实现多级别日志记录、格式化显示、过滤搜索功能
- [ ] **系统集成**: 在关键操作点集成日志记录(设备操作、数据库、地图交互)
#### 5.2 设备管理功能增强
- [ ] 重构添加设备对话框,提升用户体验 - [ ] 重构添加设备对话框,提升用户体验
- [ ] 实现设备批量管理功能 - [ ] 实现设备批量管理功能
- [ ] 添加设备配置导入/导出功能 - [ ] 添加设备配置导入/导出功能
- [ ] 实现设备连接测试功能 - [ ] 实现设备连接测试功能
#### 5.2 系统功能模块 #### 5.3 系统功能模块
- [ ] 实现系统设置管理界面 - [ ] 实现系统设置管理界面
- [ ] 添加用户权限管理功能 - [ ] 添加用户权限管理功能
- [ ] 实现操作日志记录功能 - [x] **已集成**: 操作日志记录功能(通过系统日志实现)
- [ ] 添加系统备份和恢复功能 - [ ] 添加系统备份和恢复功能
### Phase 6: 样式和主题系统 (优先级: 中) ### Phase 6: 样式和主题系统 (优先级: 中)
@ -295,11 +302,11 @@ CREATE TABLE dog_devices (
- 完整的状态指示系统和交互反馈机制 - 完整的状态指示系统和交互反馈机制
### 当前状态 🚧 ### 当前状态 🚧
**当前阶段**: Phase 4 - 地图和可视化组件优化 ✅ **已完成** **当前阶段**: Phase 5 - 功能模块重构和增强 🚧 **进行中**
**完成日期**: 2024年12月19 **开始日期**: 2024年12月21
**进展情况**: 设备卡片界面已成功集成到主窗口,地图集成完全实现,设备-地图交互功能正常 **进展情况**: Phase 4已完全完成开始Phase 5系统日志功能开发
**最新进展** (2024年12月19日): **Phase 4 最终成果** (2024年12月19日):
**组件集成完成**: DeviceListPanel已成功集成到MainWindow左侧面板 **组件集成完成**: DeviceListPanel已成功集成到MainWindow左侧面板
**设备卡片显示**: 4个测试设备2个无人机+2个机器狗正常显示 **设备卡片显示**: 4个测试设备2个无人机+2个机器狗正常显示
**过滤功能**: 设备搜索和分类过滤功能正常工作 **过滤功能**: 设备搜索和分类过滤功能正常工作
@ -310,6 +317,13 @@ CREATE TABLE dog_devices (
**设备图标系统**: 不同设备类型显示不同图标(无人机/机器狗) **设备图标系统**: 不同设备类型显示不同图标(无人机/机器狗)
**状态色彩显示**: 根据设备状态显示不同颜色(在线/警告/离线) **状态色彩显示**: 根据设备状态显示不同颜色(在线/警告/离线)
**Phase 5 最新进展** (2024年12月21日):
🚧 **UI重构开始**: 开始系统日志功能开发,移除重复的设备管理按钮
**按钮清理完成**: 成功删除MainWindow中4个重复的设备管理按钮
**空间预留**: 在左侧面板为系统日志预留350px垂直空间
🚧 **组件开发中**: 准备创建SystemLogPanel和SystemLogger组件
🎯 **目标架构**: 35%系统日志 + 65%设备管理的垂直分割布局
**Phase 4 重大里程碑达成** ✅: **Phase 4 重大里程碑达成** ✅:
- 🎯 **设备-地图集成**: 成功实现设备列表与地图的双向交互 - 🎯 **设备-地图集成**: 成功实现设备列表与地图的双向交互
- 🎯 **可视化增强**: 地图标记系统支持实时设备状态显示 - 🎯 **可视化增强**: 地图标记系统支持实时设备状态显示
@ -324,14 +338,26 @@ CREATE TABLE dog_devices (
- **设备类型图标**: 无人机和机器狗不同图标显示系统 - **设备类型图标**: 无人机和机器狗不同图标显示系统
- **交互体验**: 点击设备卡片自动聚焦到地图位置 - **交互体验**: 点击设备卡片自动聚焦到地图位置
### 下一步计划 ### Phase 5 系统日志功能开发计划
1. ✅ ~~**组件集成**: 将新的设备卡片界面集成到主窗口~~ **已完成**
2. ✅ ~~**数据库连接**: 连接真实的设备数据库,实现数据同步(当前使用测试数据)~~ **已完成** #### 当前进展 🚧
3. ✅ ~~**地图集成优化**: 优化现有地图显示和交互功能~~ **已完成** 1. ✅ **UI空间预留**: 删除重复按钮为系统日志预留350px空间
4. ✅ ~~**设备位置显示**: 在地图上实时显示设备位置标记~~ **已完成** 2. 🚧 **组件架构设计**: SystemLogPanel + SystemLogger单例设计
5. ✅ ~~**设备-地图交互**: 实现点击设备定位功能~~ **已完成** 3. 📋 **界面开发**: 实现紧凑军用风格的日志显示界面
4. 📋 **功能实现**: 多级别日志、格式化、过滤、搜索功能
5. 📋 **布局集成**: QSplitter实现35%:65%垂直分割
6. 📋 **系统集成**: 在关键操作点添加日志记录
#### 系统日志功能规格
- **日志级别**: Info, Warning, Error, Success, Debug
- **显示特性**: 时间戳、颜色编码、图标标识
- **交互功能**: 清空、暂停/恢复、级别过滤
- **性能优化**: 行数限制、内存管理、异步更新
- **集成点**: 设备操作、数据库、地图交互、错误处理
### 长期规划
6. 📋 **硬件集成准备**: 为后续硬件设备接入做接口准备 6. 📋 **硬件集成准备**: 为后续硬件设备接入做接口准备
7. 📋 **Phase 5功能增强**: 准备进入下一阶段的功能模块开发 7. 📋 **Phase 6样式优化**: 主题系统和视觉规范完善
--- ---

@ -0,0 +1,322 @@
# 系统日志功能设计文档
## 文档信息
- **文档版本**: v1.0
- **创建日期**: 2024年12月21日
- **作者**: Qt UI Developer Expert
- **项目阶段**: Phase 5 - 功能模块重构和增强
## 概述
系统日志功能是BattlefieldExplorationSystem项目Phase 5的核心特性旨在替换左侧面板重复的设备管理按钮提供系统操作的实时监控和记录功能。
### 设计目标
1. **消除功能重复**: 移除与设备管理面板重复的按钮
2. **增强系统透明度**: 实时显示关键操作信息
3. **提升调试能力**: 便于开发和维护阶段的问题追踪
4. **专业化界面**: 符合军用系统的专业要求
## 架构设计
### 整体架构
```
左侧面板布局 (使用QSplitter):
├── 系统日志面板 (SystemLogPanel) - 35% 空间
│ ├── 头部控制区 (40px)
│ ├── 日志显示区 (260-310px, 可滚动)
│ └── 状态信息区 (20px, 可选)
├── 分隔器 (QSplitter::handle) - 8px
└── 设备管理面板 (DeviceListPanel) - 65% 空间
└── 现有的设备管理功能
```
### 核心组件
#### 1. SystemLogger (单例管理器)
```cpp
class SystemLogger : public QObject
{
Q_OBJECT
public:
enum LogLevel {
Debug = 0,
Info = 1,
Warning = 2,
Error = 3,
Success = 4
};
static SystemLogger* getInstance();
void logInfo(const QString &message);
void logWarning(const QString &message);
void logError(const QString &message);
void logSuccess(const QString &message);
void logDebug(const QString &message);
signals:
void logAdded(LogLevel level, const QString &message);
private:
static SystemLogger *s_instance;
SystemLogger(QObject *parent = nullptr);
};
```
#### 2. SystemLogPanel (界面组件)
```cpp
class SystemLogPanel : public QWidget
{
Q_OBJECT
public:
explicit SystemLogPanel(QWidget *parent = nullptr);
public slots:
void addLog(SystemLogger::LogLevel level, const QString &message);
void clearLogs();
void pauseLogging();
void resumeLogging();
void setLogLevelFilter(SystemLogger::LogLevel minLevel);
private:
QTextEdit *m_logTextEdit;
QPushButton *m_clearButton;
QPushButton *m_pauseButton;
QComboBox *m_levelFilter;
QLabel *m_statusLabel;
bool m_isPaused;
SystemLogger::LogLevel m_minLevel;
int m_logCounts[5]; // 各级别日志计数
};
```
## 界面设计
### 视觉风格
**军用深蓝风格**, 与现有界面保持一致:
- **主色调**: 深蓝灰色背景 `rgb(15, 22, 32)``rgb(25, 35, 45)`
- **强调色**: 青蓝色边框 `rgba(82, 194, 242, 0.3)`
- **文字色**: 浅色文字 `rgb(220, 230, 242)`
### 组件布局
#### 头部控制区 (40px)
```
[🖥️ 系统日志] [清空] [暂停] [级别过滤▼]
```
#### 日志显示区 (主要区域)
```
HH:MM:SS.mmm 🔵 设备连接成功: UAV001
HH:MM:SS.mmm 🟡 网络延迟较高: 150ms
HH:MM:SS.mmm 🔴 数据库连接失败: 超时
HH:MM:SS.mmm 🟢 设备定位完成: DOG001
```
#### 状态信息区 (20px, 可选)
```
总计: 156 | 错误: 3 | 警告: 12 | 就绪
```
### 日志格式设计
#### 格式规范
```
[时间戳] [级别图标] [消息内容]
```
#### 级别定义
- **🔍 Debug**: 开发调试信息 (灰色 `#9E9E9E`)
- **🔵 Info**: 一般操作信息 (蓝色 `#52C2F2`)
- **🟡 Warning**: 警告信息 (黄色 `#FFD700`)
- **🔴 Error**: 错误信息 (红色 `#FF4444`)
- **🟢 Success**: 成功操作 (绿色 `#00FF7F`)
#### 格式化函数
```cpp
QString formatLogEntry(SystemLogger::LogLevel level, const QString &message)
{
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
QString levelIcon, levelColor;
switch(level) {
case Info: levelIcon = "🔵"; levelColor = "#52C2F2"; break;
case Warning: levelIcon = "🟡"; levelColor = "#FFD700"; break;
case Error: levelIcon = "🔴"; levelColor = "#FF4444"; break;
case Success: levelIcon = "🟢"; levelColor = "#00FF7F"; break;
case Debug: levelIcon = "🔍"; levelColor = "#9E9E9E"; break;
}
return QString("<span style='color: %1'>[%2] %3 %4</span>")
.arg(levelColor)
.arg(timestamp)
.arg(levelIcon)
.arg(message);
}
```
## 功能规格
### 核心功能
#### 1. 日志记录
- **多级别支持**: Debug, Info, Warning, Error, Success
- **时间戳**: 精确到毫秒的时间记录
- **颜色编码**: 不同级别使用不同颜色显示
- **图标标识**: 直观的视觉识别
#### 2. 日志管理
- **清空日志**: 一键清除所有日志记录
- **暂停/恢复**: 暂停日志更新,便于查看
- **级别过滤**: 只显示指定级别以上的日志
- **行数限制**: 自动管理内存,限制最大行数
#### 3. 高级功能
- **自动滚动**: 新日志自动滚动到底部
- **搜索功能**: 在日志中搜索关键词 (可选)
- **导出功能**: 导出日志到文件 (可选)
### 集成点
系统日志将集成到以下关键操作点:
#### 1. 设备管理操作
```cpp
// 设备添加
SystemLogger::getInstance()->logInfo("设备添加成功: " + deviceName);
// 设备连接
SystemLogger::getInstance()->logSuccess("设备连接成功: " + deviceId);
SystemLogger::getInstance()->logError("设备连接失败: " + deviceId + " - " + errorMsg);
// 设备删除
SystemLogger::getInstance()->logInfo("设备删除: " + deviceName);
```
#### 2. 数据库操作
```cpp
// 数据库连接
SystemLogger::getInstance()->logSuccess("数据库连接成功");
SystemLogger::getInstance()->logError("数据库连接失败: " + error);
// 数据操作
SystemLogger::getInstance()->logInfo("加载了 " + QString::number(count) + " 个设备");
```
#### 3. 地图交互
```cpp
// 地图操作
SystemLogger::getInstance()->logInfo("地图初始化完成");
SystemLogger::getInstance()->logSuccess("设备定位完成: " + deviceId);
```
#### 4. 系统事件
```cpp
// 系统启动
SystemLogger::getInstance()->logInfo("系统启动完成");
// 错误处理
SystemLogger::getInstance()->logWarning("网络延迟较高: " + QString::number(latency) + "ms");
```
## 性能考虑
### 内存管理
- **行数限制**: 最大500行超出自动删除最旧记录
- **异步更新**: 日志记录不阻塞主线程
- **智能刷新**: 避免频繁UI更新造成性能问题
### 用户体验
- **响应速度**: 日志添加不影响界面响应
- **视觉效果**: 平滑的滚动和更新动画
- **可用性**: 直观的控制按钮和快捷操作
## 空间分配方案
### QSplitter布局
```cpp
// 创建垂直分割器
QSplitter *leftSplitter = new QSplitter(Qt::Vertical, this);
// 系统日志面板
SystemLogPanel *logPanel = new SystemLogPanel(this);
logPanel->setMinimumHeight(200); // 最小高度
logPanel->setMaximumHeight(400); // 最大高度
// 设备管理面板
DeviceListPanel *devicePanel = new DeviceListPanel(this);
devicePanel->setMinimumHeight(300); // 最小高度
// 设置分割比例 (35% : 65%)
leftSplitter->addWidget(logPanel);
leftSplitter->addWidget(devicePanel);
leftSplitter->setSizes(QList<int>() << 350 << 650);
```
### 响应式调整
- **小屏幕**: 自动调整比例,保证最小可用空间
- **大屏幕**: 维持设计比例,提供最佳用户体验
- **用户可调**: 支持用户拖拽分割线调整比例
## 实施计划
### Phase 1: 核心组件开发
1. 创建 SystemLogger 单例管理器
2. 创建 SystemLogPanel 界面组件
3. 实现基础的日志记录和显示功能
### Phase 2: 界面集成
1. 修改 MainWindow 布局,移除重复按钮
2. 使用 QSplitter 实现分割布局
3. 集成系统日志面板到左侧面板
### Phase 3: 功能完善
1. 实现日志过滤和搜索功能
2. 添加高级控制功能 (清空、暂停等)
3. 优化性能和用户体验
### Phase 4: 系统集成
1. 在关键操作点添加日志记录
2. 完善错误处理和异常记录
3. 测试和调试整体功能
## 技术风险与应对
### 主要风险
1. **性能影响**: 频繁的日志更新可能影响界面性能
2. **内存占用**: 大量日志可能导致内存占用过高
3. **用户体验**: 日志信息过多可能干扰主要功能
### 应对策略
1. **异步处理**: 使用异步机制避免阻塞主线程
2. **智能限制**: 设置合理的行数和更新频率限制
3. **用户控制**: 提供暂停、过滤等用户控制选项
## 测试策略
### 功能测试
- 各级别日志记录和显示正确性
- 过滤和搜索功能准确性
- 清空和暂停功能可靠性
### 性能测试
- 大量日志的性能表现
- 内存使用情况监控
- 界面响应速度测试
### 集成测试
- 与现有功能的兼容性
- 空间分配的正确性
- 用户交互的流畅性
---
**文档状态**: 🟢 **已完成**
**下次更新**: 根据实施进展进行更新
**相关文档**: task.md, phase5_completion_report.md

@ -262,199 +262,38 @@ border-radius: 1px;</string>
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="deviceButtonsLayout"> <!-- 此区域将被系统日志面板替换 -->
<property name="spacing"> <widget class="QLabel" name="placeholderForSystemLog">
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="robottab">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>70</height> <height>350</height>
</size>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>机器人列表</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size> </size>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">border-image: url(:/image/res/image/tab.svg);</string> <string notr="true">color: rgb(82, 194, 242);
</property> font-size: 16px;
<property name="text"> font-weight: bold;
<string/> padding: 20px;
</property> margin: 10px;
</widget> background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
</item> stop:0 rgba(82, 194, 242, 0.1),
</layout> stop:1 rgba(45, 120, 180, 0.1));
</item> border: 2px dashed rgba(82, 194, 242, 0.5);
<item> border-radius: 8px;</string>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="addrobot">
<property name="minimumSize">
<size>
<width>0</width>
<height>85</height>
</size>
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>添加机器人</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border-image: url(:/image/res/image/robotbtn.svg);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="addUAV">
<property name="minimumSize">
<size>
<width>0</width>
<height>85</height>
</size>
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>添加无人机</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border-image: url(:/image/res/image/UAV.svg);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="UAVtab">
<property name="minimumSize">
<size>
<width>0</width>
<height>70</height>
</size>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property> </property>
<property name="text"> <property name="text">
<string>无人机列表</string> <string>🖥️ 系统日志面板
</property>
</widget> 此区域将显示系统日志信息
</item> 包括设备操作、连接状态、
<item> 地图交互等关键信息</string>
<widget class="QLabel" name="label_13">
<property name="minimumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">border-image: url(:/image/res/image/tab.svg);</string>
</property> </property>
<property name="text"> <property name="alignment">
<string/> <set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</item>
</layout>
</item>
<item> <item>
<widget class="QScrollArea" name="deviceListScrollArea"> <widget class="QScrollArea" name="deviceListScrollArea">
<property name="minimumSize"> <property name="minimumSize">

@ -0,0 +1,202 @@
/**
* @file SystemLogPanel.h
* @brief
* @author Qt UI Developer Expert
* @date 2024-12-21
* @version 1.0
*/
#ifndef SYSTEM_LOG_PANEL_H
#define SYSTEM_LOG_PANEL_H
#include <QWidget>
#include <QTextEdit>
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTimer>
#include <QDateTime>
#include <QScrollBar>
// 前向声明
class SystemLogger;
/**
* @class SystemLogPanel
* @brief
*
* BattlefieldExplorationSystemUI
*
*
*
* - Debug, Info, Warning, Error, Success
* -
* -
* - /
* -
*/
class SystemLogPanel : public QWidget
{
Q_OBJECT
public:
/**
* @brief
* @param parent
*/
explicit SystemLogPanel(QWidget *parent = nullptr);
/**
* @brief
*/
~SystemLogPanel();
/**
* @brief SystemLogger
*/
enum LogLevel {
Debug = 0, ///< 调试信息
Info = 1, ///< 一般信息
Warning = 2, ///< 警告信息
Error = 3, ///< 错误信息
Success = 4 ///< 成功信息
};
public slots:
/**
* @brief
* @param level
* @param message
*/
void addLog(LogLevel level, const QString &message);
/**
* @brief
*/
void clearLogs();
/**
* @brief
*/
void pauseLogging();
/**
* @brief
*/
void resumeLogging();
/**
* @brief
* @param minLevel
*/
void setLogLevelFilter(LogLevel minLevel);
private slots:
/**
* @brief
*/
void onClearButtonClicked();
/**
* @brief /
*/
void onPauseButtonClicked();
/**
* @brief
* @param index
*/
void onLevelFilterChanged(int index);
/**
* @brief
*/
void updateStatusInfo();
private:
/**
* @brief UI
*/
void setupUI();
/**
* @brief
*/
void setupStyle();
/**
* @brief
*/
void connectSignals();
/**
* @brief
* @param level
* @param message
* @return HTML
*/
QString formatLogEntry(LogLevel level, const QString &message);
/**
* @brief
* @param level
* @return
*/
QString getLevelIcon(LogLevel level);
/**
* @brief
* @param level
* @return
*/
QString getLevelColor(LogLevel level);
/**
* @brief
* @param level
* @return
*/
QString getLevelName(LogLevel level);
/**
* @brief
*/
void limitLogLines();
/**
* @brief
*/
void scrollToBottom();
private:
// UI组件
QTextEdit *m_logTextEdit; ///< 日志显示文本框
QPushButton *m_clearButton; ///< 清空按钮
QPushButton *m_pauseButton; ///< 暂停/恢复按钮
QComboBox *m_levelFilter; ///< 级别过滤下拉框
QLabel *m_statusLabel; ///< 状态信息标签
QLabel *m_titleLabel; ///< 标题标签
// 布局管理
QVBoxLayout *m_mainLayout; ///< 主布局
QHBoxLayout *m_controlLayout; ///< 控制按钮布局
QHBoxLayout *m_statusLayout; ///< 状态信息布局
// 状态变量
bool m_isPaused; ///< 是否暂停日志更新
LogLevel m_minLevel; ///< 最小显示级别
int m_logCounts[5]; ///< 各级别日志计数
int m_totalLogCount; ///< 总日志数量
int m_maxLogLines; ///< 最大日志行数限制
// 定时器
QTimer *m_statusUpdateTimer; ///< 状态更新定时器
// 样式常量
static const int MAX_LOG_LINES; ///< 最大日志行数
static const int STATUS_UPDATE_INTERVAL; ///< 状态更新间隔(ms)
};
#endif // SYSTEM_LOG_PANEL_H

@ -24,6 +24,7 @@
#include <QDialog> #include <QDialog>
#include <QStackedWidget> #include <QStackedWidget>
#include <QFormLayout> #include <QFormLayout>
#include <QSplitter>
// Qt控件头文件 // Qt控件头文件
#include <QPushButton> #include <QPushButton>
@ -40,6 +41,7 @@
// 自定义模块头文件 // 自定义模块头文件
// #include "AudioModule/IntelligenceUI.h" // 暂时注释掉,待实现 // #include "AudioModule/IntelligenceUI.h" // 暂时注释掉,待实现
#include "ui/components/DeviceListPanel.h" #include "ui/components/DeviceListPanel.h"
#include "ui/components/SystemLogPanel.h"
// 标准库头文件 // 标准库头文件
#include <string> #include <string>
@ -230,6 +232,11 @@ private:
*/ */
void setupDeviceListPanel(); void setupDeviceListPanel();
/**
* @brief
*/
void setupSystemLogPanel();
/** /**
* @brief * @brief
*/ */
@ -249,6 +256,8 @@ private:
Ui::MainWindow *m_ui; ///< UI界面指针 Ui::MainWindow *m_ui; ///< UI界面指针
// IntelligenceUI *m_intelligenceUI; ///< 情报传达界面指针(暂时注释掉) // IntelligenceUI *m_intelligenceUI; ///< 情报传达界面指针(暂时注释掉)
DeviceListPanel *m_deviceListPanel; ///< 设备列表面板组件 DeviceListPanel *m_deviceListPanel; ///< 设备列表面板组件
SystemLogPanel *m_systemLogPanel; ///< 系统日志面板组件
QSplitter *m_leftPanelSplitter; ///< 左侧面板分割器
QVector<QPair<QString, QString>> m_robotList; ///< 机器人列表(名称-IP地址对 QVector<QPair<QString, QString>> m_robotList; ///< 机器人列表(名称-IP地址对
QVector<QPair<QString, QString>> m_uavList; ///< 无人机列表(名称-IP地址对 QVector<QPair<QString, QString>> m_uavList; ///< 无人机列表(名称-IP地址对
// 人脸识别相关成员变量已移除(功能暂未实现) // 人脸识别相关成员变量已移除(功能暂未实现)

@ -0,0 +1,178 @@
/**
* @file SystemLogger.h
* @brief
* @author Qt UI Developer Expert
* @date 2024-12-21
* @version 1.0
*/
#ifndef SYSTEM_LOGGER_H
#define SYSTEM_LOGGER_H
#include <QObject>
#include <QString>
#include <QMutex>
#include <QDateTime>
#include <QDebug>
/**
* @class SystemLogger
* @brief
*
* SystemLogger
*
*
*
* - Debug, Info, Warning, Error, Success
* - 线
* - UI
* - 便
*
* 使
* @code
* SystemLogger::getInstance()->logInfo("设备连接成功");
* SystemLogger::getInstance()->logError("数据库连接失败");
* @endcode
*/
class SystemLogger : public QObject
{
Q_OBJECT
public:
/**
* @brief
*/
enum LogLevel {
Debug = 0, ///< 调试信息 - 开发阶段使用
Info = 1, ///< 一般信息 - 正常操作记录
Warning = 2, ///< 警告信息 - 需要注意的情况
Error = 3, ///< 错误信息 - 系统错误和异常
Success = 4 ///< 成功信息 - 重要操作成功完成
};
/**
* @brief
* @return SystemLogger
*/
static SystemLogger* getInstance();
/**
* @brief
* 退
*/
static void destroyInstance();
/**
* @brief
* @param message
*/
void logDebug(const QString &message);
/**
* @brief
* @param message
*/
void logInfo(const QString &message);
/**
* @brief
* @param message
*/
void logWarning(const QString &message);
/**
* @brief
* @param message
*/
void logError(const QString &message);
/**
* @brief
* @param message
*/
void logSuccess(const QString &message);
/**
* @brief
* @param level
* @param message
*/
void log(LogLevel level, const QString &message);
/**
* @brief
* @param enabled truefalse
*/
void setConsoleOutputEnabled(bool enabled);
/**
* @brief
* @param level
* @return
*/
static QString getLevelString(LogLevel level);
signals:
/**
* @brief
* @param level
* @param message
*
* UI
*/
void logAdded(LogLevel level, const QString &message);
private:
/**
* @brief
* @param parent
*/
explicit SystemLogger(QObject *parent = nullptr);
/**
* @brief
*/
~SystemLogger();
/**
* @brief
*/
SystemLogger(const SystemLogger&) = delete;
/**
* @brief
*/
SystemLogger& operator=(const SystemLogger&) = delete;
/**
* @brief
* @param level
* @param message
*/
void logInternal(LogLevel level, const QString &message);
/**
* @brief
* @param level
* @param message
*/
void outputToConsole(LogLevel level, const QString &message);
private:
static SystemLogger *s_instance; ///< 单例实例指针
static QMutex s_mutex; ///< 线程安全互斥锁
bool m_consoleOutputEnabled; ///< 是否启用控制台输出
QMutex m_logMutex; ///< 日志记录互斥锁
};
/**
* @brief 便
*/
#define LOG_DEBUG(msg) SystemLogger::getInstance()->logDebug(msg)
#define LOG_INFO(msg) SystemLogger::getInstance()->logInfo(msg)
#define LOG_WARNING(msg) SystemLogger::getInstance()->logWarning(msg)
#define LOG_ERROR(msg) SystemLogger::getInstance()->logError(msg)
#define LOG_SUCCESS(msg) SystemLogger::getInstance()->logSuccess(msg)
#endif // SYSTEM_LOGGER_H

@ -7,6 +7,7 @@
*/ */
#include "ui/components/DeviceCard.h" #include "ui/components/DeviceCard.h"
#include "utils/SystemLogger.h"
// Qt GUI头文件 // Qt GUI头文件
#include <QMouseEvent> #include <QMouseEvent>
@ -60,6 +61,7 @@ DeviceCard::DeviceCard(const DeviceInfo &device, QWidget *parent)
setAttribute(Qt::WA_Hover, true); setAttribute(Qt::WA_Hover, true);
qDebug() << "DeviceCard created for device:" << device.name; qDebug() << "DeviceCard created for device:" << device.name;
SystemLogger::getInstance()->logDebug(QString("创建设备卡片: %1").arg(device.name));
} }
DeviceCard::~DeviceCard() DeviceCard::~DeviceCard()
@ -436,7 +438,11 @@ void DeviceCard::refreshStatus()
void DeviceCard::mousePressEvent(QMouseEvent *event) void DeviceCard::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
setSelected(!m_isSelected); bool newSelected = !m_isSelected;
setSelected(newSelected);
if (newSelected) {
SystemLogger::getInstance()->logInfo(QString("选中设备: %1").arg(m_deviceInfo.name));
}
event->accept(); event->accept();
} }
QWidget::mousePressEvent(event); QWidget::mousePressEvent(event);
@ -523,6 +529,7 @@ void DeviceCard::paintEvent(QPaintEvent *event)
void DeviceCard::onDetailsClicked() void DeviceCard::onDetailsClicked()
{ {
qDebug() << "Details clicked for device:" << m_deviceInfo.name; qDebug() << "Details clicked for device:" << m_deviceInfo.name;
SystemLogger::getInstance()->logInfo(QString("查看设备详情: %1").arg(m_deviceInfo.name));
emit deviceDetailsRequested(m_deviceInfo.id); emit deviceDetailsRequested(m_deviceInfo.id);
} }
@ -536,10 +543,12 @@ void DeviceCard::onControlClicked()
// 当前在线,切换为离线 // 当前在线,切换为离线
newStatus = DeviceStatus::Offline; newStatus = DeviceStatus::Offline;
qDebug() << "Disconnecting device:" << m_deviceInfo.name; qDebug() << "Disconnecting device:" << m_deviceInfo.name;
SystemLogger::getInstance()->logInfo(QString("正在断开连接: %1").arg(m_deviceInfo.name));
} else { } else {
// 当前离线,切换为在线 // 当前离线,切换为在线
newStatus = DeviceStatus::Online; newStatus = DeviceStatus::Online;
qDebug() << "Connecting device:" << m_deviceInfo.name; qDebug() << "Connecting device:" << m_deviceInfo.name;
SystemLogger::getInstance()->logInfo(QString("正在连接设备: %1").arg(m_deviceInfo.name));
} }
// 更新数据库中的状态 // 更新数据库中的状态
@ -557,8 +566,13 @@ void DeviceCard::onControlClicked()
qDebug() << "Device status successfully updated:" << m_deviceInfo.name qDebug() << "Device status successfully updated:" << m_deviceInfo.name
<< "to" << (newStatus == DeviceStatus::Online ? "Online" : "Offline"); << "to" << (newStatus == DeviceStatus::Online ? "Online" : "Offline");
// 记录连接状态变更成功
QString statusText = (newStatus == DeviceStatus::Online) ? "上线" : "离线";
SystemLogger::getInstance()->logSuccess(QString("设备 %1 已%2").arg(m_deviceInfo.name).arg(statusText));
} else { } else {
qWarning() << "Failed to update device status in database for:" << m_deviceInfo.name; qWarning() << "Failed to update device status in database for:" << m_deviceInfo.name;
SystemLogger::getInstance()->logError(QString("设备状态更新失败: %1").arg(m_deviceInfo.name));
// 可以显示错误提示给用户 // 可以显示错误提示给用户
} }
} }
@ -566,6 +580,7 @@ void DeviceCard::onControlClicked()
void DeviceCard::onLocationClicked() void DeviceCard::onLocationClicked()
{ {
qDebug() << "Location clicked for device:" << m_deviceInfo.name; qDebug() << "Location clicked for device:" << m_deviceInfo.name;
SystemLogger::getInstance()->logInfo(QString("请求设备定位: %1").arg(m_deviceInfo.name));
emit deviceLocationRequested(m_deviceInfo.id); emit deviceLocationRequested(m_deviceInfo.id);
} }

@ -7,6 +7,7 @@
*/ */
#include "ui/components/DeviceListPanel.h" #include "ui/components/DeviceListPanel.h"
#include "utils/SystemLogger.h"
// Qt GUI头文件 // Qt GUI头文件
#include <QDebug> #include <QDebug>
@ -290,6 +291,7 @@ int DeviceListPanel::getOnlineDeviceCount() const
void DeviceListPanel::refreshDeviceList() void DeviceListPanel::refreshDeviceList()
{ {
qDebug() << "Refreshing device list..."; qDebug() << "Refreshing device list...";
SystemLogger::getInstance()->logInfo("正在刷新设备列表...");
// 清除现有设备卡片 // 清除现有设备卡片
clearAllDeviceCards(); clearAllDeviceCards();
@ -312,6 +314,7 @@ void DeviceListPanel::refreshDeviceList()
updateDeviceCountStats(); updateDeviceCountStats();
qDebug() << "Device list refreshed. Total devices:" << m_allDevices.size(); qDebug() << "Device list refreshed. Total devices:" << m_allDevices.size();
SystemLogger::getInstance()->logSuccess(QString("设备列表刷新完成,共加载 %1 个设备").arg(m_allDevices.size()));
} }
void DeviceListPanel::addDevice(const DeviceInfo &device) void DeviceListPanel::addDevice(const DeviceInfo &device)
@ -335,6 +338,7 @@ void DeviceListPanel::addDevice(const DeviceInfo &device)
updateDeviceCountStats(); updateDeviceCountStats();
qDebug() << "Device added:" << device.name; qDebug() << "Device added:" << device.name;
SystemLogger::getInstance()->logSuccess(QString("设备已添加: %1").arg(device.name));
} }
} }
@ -345,6 +349,15 @@ void DeviceListPanel::removeDevice(const QString &deviceId)
return; return;
} }
// 获取设备名称用于日志
QString deviceName = "未知设备";
for (const auto &device : m_allDevices) {
if (device.id == deviceId) {
deviceName = device.name;
break;
}
}
// 移除设备卡片 // 移除设备卡片
DeviceCard *card = m_deviceCards.take(deviceId); DeviceCard *card = m_deviceCards.take(deviceId);
card->deleteLater(); card->deleteLater();
@ -365,6 +378,7 @@ void DeviceListPanel::removeDevice(const QString &deviceId)
updateDeviceCountStats(); updateDeviceCountStats();
qDebug() << "Device removed:" << deviceId; qDebug() << "Device removed:" << deviceId;
SystemLogger::getInstance()->logWarning(QString("设备已移除: %1").arg(deviceName));
} }
void DeviceListPanel::updateDevice(const DeviceInfo &device) void DeviceListPanel::updateDevice(const DeviceInfo &device)
@ -469,6 +483,7 @@ QList<DeviceInfo> DeviceListPanel::loadDevicesFromDatabase()
if (db.open()) { if (db.open()) {
qDebug() << "Successfully connected to Client database"; qDebug() << "Successfully connected to Client database";
SystemLogger::getInstance()->logSuccess("成功连接到数据库");
QSqlQuery query(db); QSqlQuery query(db);
QString sql = "SELECT id, name, device_type, state, ip, port, longitude, latitude, signal_strength, battery_level FROM devices"; QString sql = "SELECT id, name, device_type, state, ip, port, longitude, latitude, signal_strength, battery_level FROM devices";
@ -513,6 +528,7 @@ QList<DeviceInfo> DeviceListPanel::loadDevicesFromDatabase()
db.close(); db.close();
} else { } else {
qWarning() << "Failed to connect to Client database:" << db.lastError().text(); qWarning() << "Failed to connect to Client database:" << db.lastError().text();
SystemLogger::getInstance()->logError("数据库连接失败");
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
qWarning() << "Database connection exception:" << e.what(); qWarning() << "Database connection exception:" << e.what();
@ -557,6 +573,7 @@ bool DeviceListPanel::deleteDeviceFromDatabase(const QString &deviceId)
if (query.exec()) { if (query.exec()) {
if (query.numRowsAffected() > 0) { if (query.numRowsAffected() > 0) {
qDebug() << "Successfully deleted device from database:" << deviceId; qDebug() << "Successfully deleted device from database:" << deviceId;
SystemLogger::getInstance()->logSuccess("设备从数据库中删除成功");
success = true; success = true;
// 从内存中移除设备 // 从内存中移除设备
@ -588,11 +605,13 @@ bool DeviceListPanel::deleteDeviceFromDatabase(const QString &deviceId)
} }
} else { } else {
qWarning() << "Failed to execute delete query:" << query.lastError().text(); qWarning() << "Failed to execute delete query:" << query.lastError().text();
SystemLogger::getInstance()->logError("数据库删除操作失败");
} }
db.close(); db.close();
} else { } else {
qWarning() << "Failed to connect to database for deletion:" << db.lastError().text(); qWarning() << "Failed to connect to database for deletion:" << db.lastError().text();
SystemLogger::getInstance()->logError("删除操作数据库连接失败");
} }
// 清理数据库连接 // 清理数据库连接

@ -0,0 +1,476 @@
/**
* @file SystemLogPanel.cpp
* @brief
* @author Qt UI Developer Expert
* @date 2024-12-21
* @version 1.0
*/
#include "ui/components/SystemLogPanel.h"
#include "utils/SystemLogger.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTextEdit>
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
#include <QTimer>
#include <QDateTime>
#include <QScrollBar>
#include <QTextCursor>
#include <QDebug>
// 静态常量定义
const int SystemLogPanel::MAX_LOG_LINES = 500;
const int SystemLogPanel::STATUS_UPDATE_INTERVAL = 2000; // 2秒
SystemLogPanel::SystemLogPanel(QWidget *parent)
: QWidget(parent)
, m_logTextEdit(nullptr)
, m_clearButton(nullptr)
, m_pauseButton(nullptr)
, m_levelFilter(nullptr)
, m_statusLabel(nullptr)
, m_titleLabel(nullptr)
, m_mainLayout(nullptr)
, m_controlLayout(nullptr)
, m_statusLayout(nullptr)
, m_isPaused(false)
, m_minLevel(Debug)
, m_totalLogCount(0)
, m_maxLogLines(MAX_LOG_LINES)
, m_statusUpdateTimer(nullptr)
{
// 初始化日志计数器
for (int i = 0; i < 5; ++i) {
m_logCounts[i] = 0;
}
setupUI();
setupStyle();
connectSignals();
// 连接到SystemLogger的信号
connect(SystemLogger::getInstance(), &SystemLogger::logAdded,
this, [this](SystemLogger::LogLevel level, const QString &message) {
addLog(static_cast<LogLevel>(level), message);
});
qDebug() << "SystemLogPanel initialized successfully";
}
SystemLogPanel::~SystemLogPanel()
{
if (m_statusUpdateTimer) {
m_statusUpdateTimer->stop();
}
qDebug() << "SystemLogPanel destroyed";
}
void SystemLogPanel::setupUI()
{
// 创建主布局
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setSpacing(4);
m_mainLayout->setContentsMargins(8, 8, 8, 10);
// 创建标题标签
m_titleLabel = new QLabel("🖥️ 系统日志", this);
m_titleLabel->setMinimumHeight(25);
m_titleLabel->setAlignment(Qt::AlignCenter);
// 创建控制按钮布局
m_controlLayout = new QHBoxLayout();
m_controlLayout->setSpacing(4);
// 创建控制按钮
m_clearButton = new QPushButton("清空", this);
m_clearButton->setMinimumSize(68, 30);
m_clearButton->setMaximumSize(68, 30);
m_pauseButton = new QPushButton("暂停", this);
m_pauseButton->setMinimumSize(68, 30);
m_pauseButton->setMaximumSize(68, 30);
// 创建级别过滤器
m_levelFilter = new QComboBox(this);
m_levelFilter->addItem("全部", static_cast<int>(Debug));
m_levelFilter->addItem("信息+", static_cast<int>(Info));
m_levelFilter->addItem("警告+", static_cast<int>(Warning));
m_levelFilter->addItem("错误+", static_cast<int>(Error));
m_levelFilter->addItem("成功", static_cast<int>(Success));
m_levelFilter->setMinimumSize(88, 30);
m_levelFilter->setMaximumSize(88, 30);
// 添加控制组件到布局
m_controlLayout->addWidget(m_clearButton);
m_controlLayout->addWidget(m_pauseButton);
m_controlLayout->addStretch();
m_controlLayout->addWidget(m_levelFilter);
// 创建日志显示文本框
m_logTextEdit = new QTextEdit(this);
m_logTextEdit->setReadOnly(true);
m_logTextEdit->setMinimumHeight(250);
m_logTextEdit->setMaximumHeight(350);
m_logTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_logTextEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
// 创建状态信息标签
m_statusLabel = new QLabel("就绪", this);
m_statusLabel->setMinimumHeight(26);
m_statusLabel->setMaximumHeight(28);
m_statusLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
// 创建状态布局
m_statusLayout = new QHBoxLayout();
m_statusLayout->setContentsMargins(0, 0, 0, 0);
m_statusLayout->addWidget(m_statusLabel);
m_statusLayout->addStretch();
// 添加所有组件到主布局
m_mainLayout->addWidget(m_titleLabel);
m_mainLayout->addLayout(m_controlLayout);
m_mainLayout->addWidget(m_logTextEdit);
m_mainLayout->addLayout(m_statusLayout);
// 创建状态更新定时器
m_statusUpdateTimer = new QTimer(this);
m_statusUpdateTimer->setInterval(STATUS_UPDATE_INTERVAL);
m_statusUpdateTimer->start();
qDebug() << "SystemLogPanel UI setup completed";
}
void SystemLogPanel::setupStyle()
{
// 主面板样式
setStyleSheet(
"SystemLogPanel {"
" background-color: rgba(25, 35, 45, 0.95);"
" border: 2px solid rgba(82, 194, 242, 0.4);"
" border-radius: 8px;"
" padding: 4px;"
"}"
);
// 标题样式
m_titleLabel->setStyleSheet(
"QLabel {"
" color: rgb(82, 194, 242);"
" font-size: 14px;"
" font-weight: bold;"
" padding: 4px 8px;"
" background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
" stop:0 rgba(82, 194, 242, 0.2),"
" stop:1 rgba(45, 120, 180, 0.2));"
" border: 1px solid rgba(82, 194, 242, 0.5);"
" border-radius: 4px;"
"}"
);
// 按钮通用样式
QString buttonStyle =
"QPushButton {"
" background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
" stop:0 rgba(45, 65, 95, 0.8),"
" stop:1 rgba(25, 40, 65, 0.8));"
" color: rgb(220, 230, 242);"
" border: 1px solid rgba(82, 194, 242, 0.5);"
" border-radius: 4px;"
" font-size: 12px;"
" font-weight: bold;"
" padding: 3px 8px;"
"}"
"QPushButton:hover {"
" background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
" stop:0 rgba(82, 194, 242, 0.6),"
" stop:1 rgba(45, 120, 180, 0.6));"
" border: 1px solid rgba(82, 194, 242, 0.8);"
"}"
"QPushButton:pressed {"
" background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
" stop:0 rgba(82, 194, 242, 0.8),"
" stop:1 rgba(45, 120, 180, 0.8));"
"}";
m_clearButton->setStyleSheet(buttonStyle);
m_pauseButton->setStyleSheet(buttonStyle);
// 下拉框样式
m_levelFilter->setStyleSheet(
"QComboBox {"
" background: rgba(25, 40, 65, 0.8);"
" color: rgb(220, 230, 242);"
" border: 1px solid rgba(82, 194, 242, 0.5);"
" border-radius: 4px;"
" padding: 3px 8px;"
" font-size: 12px;"
" font-weight: bold;"
"}"
"QComboBox::drop-down {"
" subcontrol-origin: padding;"
" subcontrol-position: top right;"
" width: 15px;"
" border-left: 1px solid rgba(82, 194, 242, 0.5);"
"}"
"QComboBox::down-arrow {"
" width: 8px;"
" height: 8px;"
"}"
"QComboBox QAbstractItemView {"
" background-color: rgba(25, 40, 65, 0.95);"
" color: rgb(220, 230, 242);"
" border: 1px solid rgba(82, 194, 242, 0.5);"
" border-radius: 4px;"
" selection-background-color: rgba(82, 194, 242, 0.3);"
"}"
);
// 文本框样式
m_logTextEdit->setStyleSheet(
"QTextEdit {"
" background-color: rgba(15, 22, 32, 0.9);"
" color: rgb(220, 230, 242);"
" border: 1px solid rgba(82, 194, 242, 0.4);"
" border-radius: 6px;"
" padding: 6px;"
" font-family: 'Consolas', 'Monaco', monospace;"
" font-size: 13px;"
" line-height: 1.4;"
" selection-background-color: rgba(82, 194, 242, 0.3);"
"}"
"QScrollBar:vertical {"
" background-color: rgba(30, 44, 62, 0.8);"
" width: 10px;"
" border-radius: 5px;"
"}"
"QScrollBar::handle:vertical {"
" background-color: rgba(82, 194, 242, 0.6);"
" border-radius: 5px;"
" min-height: 20px;"
"}"
"QScrollBar::handle:vertical:hover {"
" background-color: rgba(82, 194, 242, 0.8);"
"}"
);
// 状态标签样式
m_statusLabel->setStyleSheet(
"QLabel {"
" color: rgb(150, 180, 210);"
" font-size: 12px;"
" font-weight: normal;"
" padding: 3px 6px;"
" background: transparent;"
"}"
);
qDebug() << "SystemLogPanel styles applied";
}
void SystemLogPanel::connectSignals()
{
// 连接按钮信号
connect(m_clearButton, &QPushButton::clicked,
this, &SystemLogPanel::onClearButtonClicked);
connect(m_pauseButton, &QPushButton::clicked,
this, &SystemLogPanel::onPauseButtonClicked);
// 连接下拉框信号
connect(m_levelFilter, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &SystemLogPanel::onLevelFilterChanged);
// 连接定时器信号
connect(m_statusUpdateTimer, &QTimer::timeout,
this, &SystemLogPanel::updateStatusInfo);
qDebug() << "SystemLogPanel signals connected";
}
void SystemLogPanel::addLog(LogLevel level, const QString &message)
{
// 如果暂停则不添加日志
if (m_isPaused) {
return;
}
// 检查级别过滤
if (level < m_minLevel) {
return;
}
// 更新计数器
if (level >= 0 && level < 5) {
m_logCounts[level]++;
}
m_totalLogCount++;
// 格式化并添加日志条目
QString formattedEntry = formatLogEntry(level, message);
m_logTextEdit->append(formattedEntry);
// 限制日志行数
limitLogLines();
// 自动滚动到底部
scrollToBottom();
qDebug() << QString("Log added: [%1] %2").arg(getLevelName(level)).arg(message);
}
void SystemLogPanel::clearLogs()
{
m_logTextEdit->clear();
// 重置计数器
for (int i = 0; i < 5; ++i) {
m_logCounts[i] = 0;
}
m_totalLogCount = 0;
// 更新状态信息
updateStatusInfo();
qDebug() << "System logs cleared";
}
void SystemLogPanel::pauseLogging()
{
m_isPaused = true;
m_pauseButton->setText("恢复");
updateStatusInfo();
qDebug() << "Logging paused";
}
void SystemLogPanel::resumeLogging()
{
m_isPaused = false;
m_pauseButton->setText("暂停");
updateStatusInfo();
qDebug() << "Logging resumed";
}
void SystemLogPanel::setLogLevelFilter(LogLevel minLevel)
{
m_minLevel = minLevel;
// 更新下拉框选择
for (int i = 0; i < m_levelFilter->count(); ++i) {
if (m_levelFilter->itemData(i).toInt() == static_cast<int>(minLevel)) {
m_levelFilter->setCurrentIndex(i);
break;
}
}
qDebug() << "Log level filter set to:" << getLevelName(minLevel);
}
void SystemLogPanel::onClearButtonClicked()
{
clearLogs();
}
void SystemLogPanel::onPauseButtonClicked()
{
if (m_isPaused) {
resumeLogging();
} else {
pauseLogging();
}
}
void SystemLogPanel::onLevelFilterChanged(int index)
{
if (index >= 0 && index < m_levelFilter->count()) {
LogLevel newLevel = static_cast<LogLevel>(m_levelFilter->itemData(index).toInt());
m_minLevel = newLevel;
qDebug() << "Log level filter changed to:" << getLevelName(newLevel);
}
}
void SystemLogPanel::updateStatusInfo()
{
QString statusText = QString("总计: %1 | 错误: %2 | 警告: %3")
.arg(m_totalLogCount)
.arg(m_logCounts[Error])
.arg(m_logCounts[Warning]);
if (m_isPaused) {
statusText += " | 已暂停";
} else {
statusText += " | 运行中";
}
m_statusLabel->setText(statusText);
}
QString SystemLogPanel::formatLogEntry(LogLevel level, const QString &message)
{
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
QString levelIcon = getLevelIcon(level);
QString levelColor = getLevelColor(level);
return QString("<span style='color: %1'>[%2] %3 %4</span>")
.arg(levelColor)
.arg(timestamp)
.arg(levelIcon)
.arg(message);
}
QString SystemLogPanel::getLevelIcon(LogLevel level)
{
switch (level) {
case Debug: return "🔍";
case Info: return "🔵";
case Warning: return "🟡";
case Error: return "🔴";
case Success: return "🟢";
default: return "";
}
}
QString SystemLogPanel::getLevelColor(LogLevel level)
{
switch (level) {
case Debug: return "#9E9E9E";
case Info: return "#52C2F2";
case Warning: return "#FFD700";
case Error: return "#FF4444";
case Success: return "#00FF7F";
default: return "#FFFFFF";
}
}
QString SystemLogPanel::getLevelName(LogLevel level)
{
switch (level) {
case Debug: return "Debug";
case Info: return "Info";
case Warning: return "Warning";
case Error: return "Error";
case Success: return "Success";
default: return "Unknown";
}
}
void SystemLogPanel::limitLogLines()
{
// 获取文档和光标
QTextDocument *document = m_logTextEdit->document();
int blockCount = document->blockCount();
// 如果超过最大行数,删除最旧的行
if (blockCount > m_maxLogLines) {
QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor,
blockCount - m_maxLogLines);
cursor.removeSelectedText();
}
}
void SystemLogPanel::scrollToBottom()
{
QScrollBar *scrollBar = m_logTextEdit->verticalScrollBar();
scrollBar->setValue(scrollBar->maximum());
}

@ -8,6 +8,7 @@
#include "ui/dialogs/DeviceDialog.h" #include "ui/dialogs/DeviceDialog.h"
#include "build/ui_DeviceDialog.h" #include "build/ui_DeviceDialog.h"
#include "utils/SystemLogger.h"
// Qt headers // Qt headers
#include <QMessageBox> #include <QMessageBox>
@ -61,6 +62,7 @@ void DeviceDialog::setDeviceInfo(const QString &deviceId, const QString &name, c
const QString &createdAt, const QString &updatedAt) const QString &createdAt, const QString &updatedAt)
{ {
m_currentDeviceId = deviceId; m_currentDeviceId = deviceId;
SystemLogger::getInstance()->logInfo(QString("打开设备详情对话框: %1").arg(name));
// 设置设备图标 // 设置设备图标
setDeviceIcon(type); setDeviceIcon(type);
@ -284,6 +286,7 @@ void DeviceDialog::refreshDeviceInfo()
void DeviceDialog::onConnectClicked() void DeviceDialog::onConnectClicked()
{ {
if (!m_currentDeviceId.isEmpty()) { if (!m_currentDeviceId.isEmpty()) {
SystemLogger::getInstance()->logInfo("从详情对话框请求连接设备");
emit deviceConnectRequested(m_currentDeviceId); emit deviceConnectRequested(m_currentDeviceId);
// 记录操作日志 // 记录操作日志
@ -294,6 +297,7 @@ void DeviceDialog::onConnectClicked()
void DeviceDialog::onDisconnectClicked() void DeviceDialog::onDisconnectClicked()
{ {
if (!m_currentDeviceId.isEmpty()) { if (!m_currentDeviceId.isEmpty()) {
SystemLogger::getInstance()->logInfo("从详情对话框请求断开设备");
emit deviceDisconnectRequested(m_currentDeviceId); emit deviceDisconnectRequested(m_currentDeviceId);
// 记录操作日志 // 记录操作日志
@ -304,6 +308,7 @@ void DeviceDialog::onDisconnectClicked()
void DeviceDialog::onLocateClicked() void DeviceDialog::onLocateClicked()
{ {
if (!m_currentDeviceId.isEmpty()) { if (!m_currentDeviceId.isEmpty()) {
SystemLogger::getInstance()->logInfo("从详情对话框请求设备定位");
emit deviceLocationRequested(m_currentDeviceId); emit deviceLocationRequested(m_currentDeviceId);
// 记录操作日志 // 记录操作日志
@ -313,6 +318,7 @@ void DeviceDialog::onLocateClicked()
void DeviceDialog::onRefreshClicked() void DeviceDialog::onRefreshClicked()
{ {
SystemLogger::getInstance()->logInfo("刷新设备信息");
refreshDeviceInfo(); refreshDeviceInfo();
} }

@ -9,6 +9,7 @@
#include "ui/main/MainWindow.h" #include "ui/main/MainWindow.h"
#include "build/ui_MainWindow.h" #include "build/ui_MainWindow.h"
#include "ui/dialogs/DeviceDialog.h" #include "ui/dialogs/DeviceDialog.h"
#include "utils/SystemLogger.h"
// Qt GUI头文件 // Qt GUI头文件
#include <QWebEngineView> #include <QWebEngineView>
@ -42,11 +43,14 @@
#include <QTimer> #include <QTimer>
#include <QSpinBox> #include <QSpinBox>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QSplitter>
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, m_ui(new Ui::MainWindow) , m_ui(new Ui::MainWindow)
, m_deviceListPanel(nullptr) , m_deviceListPanel(nullptr)
, m_systemLogPanel(nullptr)
, m_leftPanelSplitter(nullptr)
// , m_intelligenceUI(nullptr) // 暂时注释掉 // , m_intelligenceUI(nullptr) // 暂时注释掉
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@ -84,22 +88,60 @@ void MainWindow::setupUI()
// 初始化随机数生成器 // 初始化随机数生成器
qsrand(QTime::currentTime().msec()); qsrand(QTime::currentTime().msec());
// 创建并集成DeviceListPanel到左侧面板 // 创建并集成SystemLogPanel和DeviceListPanel到左侧面板
setupDeviceListPanel(); setupSystemLogPanel();
// 恢复地图显示控制 // 恢复地图显示控制
setupMapDisplay(); setupMapDisplay();
// 控制添加机器人 // 注意原有的重复设备管理按钮已被移除功能集成在DeviceListPanel中
addRobotControl(m_ui->addrobot);
// 控制机器人列表 // 记录系统启动日志
robotsInfosControl(m_ui->robottab); SystemLogger::getInstance()->logInfo("系统启动完成");
} }
void MainWindow::setupDeviceListPanel() void MainWindow::setupSystemLogPanel()
{ {
// 创建系统日志面板
m_systemLogPanel = new SystemLogPanel(this);
// 创建设备列表面板 // 创建设备列表面板
m_deviceListPanel = new DeviceListPanel(this); m_deviceListPanel = new DeviceListPanel(this);
// 创建垂直分割器
m_leftPanelSplitter = new QSplitter(Qt::Vertical, this);
// 设置系统日志面板的高度限制
m_systemLogPanel->setMinimumHeight(200);
m_systemLogPanel->setMaximumHeight(400);
// 设置设备管理面板的高度限制
m_deviceListPanel->setMinimumHeight(300);
// 添加面板到分割器
m_leftPanelSplitter->addWidget(m_systemLogPanel);
m_leftPanelSplitter->addWidget(m_deviceListPanel);
// 设置分割比例 (35% : 65%)
m_leftPanelSplitter->setSizes(QList<int>() << 350 << 650);
// 设置分割器样式
m_leftPanelSplitter->setStyleSheet(
"QSplitter::handle {"
" background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
" stop:0 rgba(82, 194, 242, 0.3),"
" stop:0.5 rgba(82, 194, 242, 0.8),"
" stop:1 rgba(82, 194, 242, 0.3));"
" border-radius: 2px;"
" height: 8px;"
"}"
"QSplitter::handle:hover {"
" background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
" stop:0 rgba(82, 194, 242, 0.5),"
" stop:0.5 rgba(82, 194, 242, 1.0),"
" stop:1 rgba(82, 194, 242, 0.5));"
"}"
);
// 获取左侧面板的布局 // 获取左侧面板的布局
QVBoxLayout *leftLayout = qobject_cast<QVBoxLayout*>(m_ui->leftPanel->layout()); QVBoxLayout *leftLayout = qobject_cast<QVBoxLayout*>(m_ui->leftPanel->layout());
if (leftLayout) { if (leftLayout) {
@ -111,8 +153,8 @@ void MainWindow::setupDeviceListPanel()
} }
} }
// 将DeviceListPanel添加到左侧面板 // 将分割器添加到左侧面板
leftLayout->addWidget(m_deviceListPanel); leftLayout->addWidget(m_leftPanelSplitter);
// 连接DeviceListPanel信号 // 连接DeviceListPanel信号
connect(m_deviceListPanel, &DeviceListPanel::deviceSelected, connect(m_deviceListPanel, &DeviceListPanel::deviceSelected,
@ -126,12 +168,20 @@ void MainWindow::setupDeviceListPanel()
connect(m_deviceListPanel, &DeviceListPanel::addDeviceRequested, connect(m_deviceListPanel, &DeviceListPanel::addDeviceRequested,
this, &MainWindow::onAddDeviceRequested); this, &MainWindow::onAddDeviceRequested);
qDebug() << "DeviceListPanel integrated into left panel - original content hidden"; qDebug() << "SystemLogPanel and DeviceListPanel integrated with QSplitter (35%:65%)";
SystemLogger::getInstance()->logInfo("系统日志面板初始化完成");
} else { } else {
qWarning() << "Failed to get left panel layout"; qWarning() << "Failed to get left panel layout";
SystemLogger::getInstance()->logError("左侧面板布局获取失败");
} }
} }
void MainWindow::setupDeviceListPanel()
{
// 此方法已被setupSystemLogPanel()替代,保留以兼容可能的调用
qDebug() << "setupDeviceListPanel() is deprecated, use setupSystemLogPanel() instead";
}
void MainWindow::setupStyle() void MainWindow::setupStyle()
{ {
// 设置按钮样式 - 现代化军用风格 // 设置按钮样式 - 现代化军用风格
@ -162,10 +212,7 @@ void MainWindow::setupStyle()
"}"; "}";
// 应用样式到所有按钮 // 应用样式到所有按钮
m_ui->robottab->setStyleSheet(buttonStyle); // 注意:原有的重复设备管理按钮已被移除
m_ui->addrobot->setStyleSheet(buttonStyle);
m_ui->addUAV->setStyleSheet(buttonStyle);
m_ui->UAVtab->setStyleSheet(buttonStyle);
m_ui->UAVview->setStyleSheet(buttonStyle); m_ui->UAVview->setStyleSheet(buttonStyle);
m_ui->robotView->setStyleSheet(buttonStyle); m_ui->robotView->setStyleSheet(buttonStyle);
m_ui->robotMapping->setStyleSheet(buttonStyle); m_ui->robotMapping->setStyleSheet(buttonStyle);
@ -178,8 +225,7 @@ void MainWindow::setupStyle()
void MainWindow::connectSignals() void MainWindow::connectSignals()
{ {
// 连接按钮信号 // 连接按钮信号
connect(m_ui->addUAV, &QPushButton::clicked, this, &MainWindow::onAddUAVClicked); // 注意:原有的重复设备管理按钮信号已被移除
connect(m_ui->UAVtab, &QPushButton::clicked, this, &MainWindow::onUAVTabClicked);
connect(m_ui->UAVview, &QPushButton::clicked, this, &MainWindow::onUAVViewClicked); connect(m_ui->UAVview, &QPushButton::clicked, this, &MainWindow::onUAVViewClicked);
connect(m_ui->robotView, &QPushButton::clicked, this, &MainWindow::onRobotViewClicked); connect(m_ui->robotView, &QPushButton::clicked, this, &MainWindow::onRobotViewClicked);
connect(m_ui->robotMapping, &QPushButton::clicked, this, &MainWindow::onRobotMappingClicked); connect(m_ui->robotMapping, &QPushButton::clicked, this, &MainWindow::onRobotMappingClicked);
@ -424,6 +470,9 @@ void MainWindow::onAddRobotClicked()
m_robotList.append(qMakePair(name, ip)); m_robotList.append(qMakePair(name, ip));
QMessageBox::information(this, "成功", "机器人添加成功!"); QMessageBox::information(this, "成功", "机器人添加成功!");
// 记录成功日志
SystemLogger::getInstance()->logSuccess(QString("机器人添加成功: %1 (%2)").arg(name).arg(deviceId));
// 刷新设备列表 // 刷新设备列表
if (m_deviceListPanel) { if (m_deviceListPanel) {
m_deviceListPanel->refreshDeviceList(); m_deviceListPanel->refreshDeviceList();
@ -432,6 +481,7 @@ void MainWindow::onAddRobotClicked()
dialog->accept(); dialog->accept();
} else { } else {
QMessageBox::warning(this, "错误", "保存到数据库失败!"); QMessageBox::warning(this, "错误", "保存到数据库失败!");
SystemLogger::getInstance()->logError(QString("机器人添加失败: %1 - 数据库保存失败").arg(name));
} }
} else { } else {
QMessageBox::warning(this, "错误", "请填写完整信息!"); QMessageBox::warning(this, "错误", "请填写完整信息!");
@ -611,6 +661,9 @@ void MainWindow::onAddUAVClicked()
m_uavList.append(qMakePair(name, ip)); m_uavList.append(qMakePair(name, ip));
QMessageBox::information(this, "成功", "无人机添加成功!"); QMessageBox::information(this, "成功", "无人机添加成功!");
// 记录成功日志
SystemLogger::getInstance()->logSuccess(QString("无人机添加成功: %1 (%2)").arg(name).arg(deviceId));
// 刷新设备列表 // 刷新设备列表
if (m_deviceListPanel) { if (m_deviceListPanel) {
m_deviceListPanel->refreshDeviceList(); m_deviceListPanel->refreshDeviceList();
@ -619,6 +672,7 @@ void MainWindow::onAddUAVClicked()
dialog->accept(); dialog->accept();
} else { } else {
QMessageBox::warning(this, "错误", "保存到数据库失败!"); QMessageBox::warning(this, "错误", "保存到数据库失败!");
SystemLogger::getInstance()->logError(QString("无人机添加失败: %1 - 数据库保存失败").arg(name));
} }
} else { } else {
QMessageBox::warning(this, "错误", "请填写完整信息!"); QMessageBox::warning(this, "错误", "请填写完整信息!");
@ -724,6 +778,7 @@ void MainWindow::onDeviceControlRequested(const QString &deviceId)
void MainWindow::onDeviceLocationRequested(const QString &deviceId) void MainWindow::onDeviceLocationRequested(const QString &deviceId)
{ {
qDebug() << "Device location requested for:" << deviceId; qDebug() << "Device location requested for:" << deviceId;
SystemLogger::getInstance()->logInfo(QString("请求设备定位: %1").arg(deviceId));
// 从设备列表面板获取设备信息 // 从设备列表面板获取设备信息
if (m_deviceListPanel) { if (m_deviceListPanel) {
@ -785,6 +840,7 @@ void MainWindow::onDeviceLocationRequested(const QString &deviceId)
} }
qDebug() << QString("设备 %1 定位到位置: (%2, %3)").arg(deviceName).arg(latitude).arg(longitude); qDebug() << QString("设备 %1 定位到位置: (%2, %3)").arg(deviceName).arg(latitude).arg(longitude);
SystemLogger::getInstance()->logSuccess(QString("设备定位完成: %1 -> (%2, %3)").arg(deviceName).arg(latitude).arg(longitude));
} else { } else {
QMessageBox::warning(this, "设备定位", QMessageBox::warning(this, "设备定位",
QString("无法获取设备位置信息\n设备ID: %1").arg(deviceId)); QString("无法获取设备位置信息\n设备ID: %1").arg(deviceId));
@ -806,6 +862,7 @@ void MainWindow::onDeviceDetailsRequested(const QString &deviceId)
if (!db.open()) { if (!db.open()) {
qWarning() << "Failed to connect to database for device details:" << db.lastError().text(); qWarning() << "Failed to connect to database for device details:" << db.lastError().text();
SystemLogger::getInstance()->logError("数据库连接失败 - 无法查询设备详情");
QMessageBox::warning(this, "错误", "无法连接到数据库"); QMessageBox::warning(this, "错误", "无法连接到数据库");
return; return;
} }
@ -888,6 +945,7 @@ void MainWindow::onAddDeviceRequested(const QString &deviceType)
void MainWindow::setupMapDisplay() void MainWindow::setupMapDisplay()
{ {
qDebug() << "Setting up map display..."; qDebug() << "Setting up map display...";
SystemLogger::getInstance()->logInfo("开始设置地图显示");
// 创建WebEngineView来显示地图 // 创建WebEngineView来显示地图
QWebEngineView* webView = new QWebEngineView(m_ui->MapDisplayer); QWebEngineView* webView = new QWebEngineView(m_ui->MapDisplayer);
@ -911,9 +969,11 @@ void MainWindow::setupMapDisplay()
connect(webView, &QWebEngineView::loadFinished, this, [this](bool success) { connect(webView, &QWebEngineView::loadFinished, this, [this](bool success) {
if (success) { if (success) {
qDebug() << "Map loaded successfully, initializing device markers..."; qDebug() << "Map loaded successfully, initializing device markers...";
SystemLogger::getInstance()->logSuccess("地图加载完成");
QTimer::singleShot(1000, this, &MainWindow::initializeDeviceMarkersOnMap); QTimer::singleShot(1000, this, &MainWindow::initializeDeviceMarkersOnMap);
} else { } else {
qDebug() << "Map loading failed!"; qDebug() << "Map loading failed!";
SystemLogger::getInstance()->logError("地图加载失败");
} }
}); });
} }
@ -976,6 +1036,7 @@ bool MainWindow::addDeviceToDatabase(const QString &deviceId, const QString &nam
if (!db.open()) { if (!db.open()) {
qWarning() << "Failed to connect to database for adding device:" << db.lastError().text(); qWarning() << "Failed to connect to database for adding device:" << db.lastError().text();
SystemLogger::getInstance()->logError("数据库连接失败 - 无法添加设备");
return false; return false;
} }

@ -0,0 +1,158 @@
/**
* @file SystemLogger.cpp
* @brief
* @author Qt UI Developer Expert
* @date 2024-12-21
* @version 1.0
*/
#include "utils/SystemLogger.h"
#include <QDateTime>
#include <QDebug>
#include <QMutexLocker>
#include <QCoreApplication>
#include <iostream>
// 静态成员初始化
SystemLogger* SystemLogger::s_instance = nullptr;
QMutex SystemLogger::s_mutex;
SystemLogger::SystemLogger(QObject *parent)
: QObject(parent)
, m_consoleOutputEnabled(true)
{
qDebug() << "SystemLogger instance created";
}
SystemLogger::~SystemLogger()
{
qDebug() << "SystemLogger instance destroyed";
}
SystemLogger* SystemLogger::getInstance()
{
// 双重检查锁定模式确保线程安全
if (s_instance == nullptr) {
QMutexLocker locker(&s_mutex);
if (s_instance == nullptr) {
s_instance = new SystemLogger();
}
}
return s_instance;
}
void SystemLogger::destroyInstance()
{
QMutexLocker locker(&s_mutex);
if (s_instance != nullptr) {
delete s_instance;
s_instance = nullptr;
}
}
void SystemLogger::logDebug(const QString &message)
{
log(Debug, message);
}
void SystemLogger::logInfo(const QString &message)
{
log(Info, message);
}
void SystemLogger::logWarning(const QString &message)
{
log(Warning, message);
}
void SystemLogger::logError(const QString &message)
{
log(Error, message);
}
void SystemLogger::logSuccess(const QString &message)
{
log(Success, message);
}
void SystemLogger::log(LogLevel level, const QString &message)
{
logInternal(level, message);
}
void SystemLogger::setConsoleOutputEnabled(bool enabled)
{
QMutexLocker locker(&m_logMutex);
m_consoleOutputEnabled = enabled;
QString statusMsg = enabled ? "Console output enabled" : "Console output disabled";
qDebug() << "SystemLogger:" << statusMsg;
}
QString SystemLogger::getLevelString(LogLevel level)
{
switch (level) {
case Debug: return "DEBUG";
case Info: return "INFO";
case Warning: return "WARNING";
case Error: return "ERROR";
case Success: return "SUCCESS";
default: return "UNKNOWN";
}
}
void SystemLogger::logInternal(LogLevel level, const QString &message)
{
// 线程安全保护
QMutexLocker locker(&m_logMutex);
// 输出到控制台(如果启用)
if (m_consoleOutputEnabled) {
outputToConsole(level, message);
}
// 发出信号通知UI组件
emit logAdded(level, message);
}
void SystemLogger::outputToConsole(LogLevel level, const QString &message)
{
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
QString levelStr = getLevelString(level);
QString logLine = QString("[%1] [%2] %3").arg(timestamp, levelStr, message);
// 根据日志级别选择输出流
switch (level) {
case Error:
// 错误输出到标准错误流
std::cerr << logLine.toStdString() << std::endl;
break;
case Warning:
// 警告也输出到标准错误流
std::cerr << logLine.toStdString() << std::endl;
break;
default:
// 其他级别输出到标准输出流
std::cout << logLine.toStdString() << std::endl;
break;
}
// 同时也输出到Qt的调试系统
switch (level) {
case Debug:
qDebug().noquote() << logLine;
break;
case Info:
qInfo().noquote() << logLine;
break;
case Warning:
qWarning().noquote() << logLine;
break;
case Error:
qCritical().noquote() << logLine;
break;
case Success:
qInfo().noquote() << logLine; // 成功信息使用qInfo输出
break;
}
}
Loading…
Cancel
Save