Merge pull request '合并' (#7) from main into huaijin
	
		
	
				
					
				
			
						commit
						d25af828cb
					
				@ -0,0 +1,49 @@
 | 
				
			||||
# 编译生成文件 (Build artifacts)
 | 
				
			||||
build/
 | 
				
			||||
*.o
 | 
				
			||||
*.so
 | 
				
			||||
*.dll
 | 
				
			||||
*.exe
 | 
				
			||||
moc_*.cpp
 | 
				
			||||
ui_*.h
 | 
				
			||||
qrc_*.cpp
 | 
				
			||||
Makefile
 | 
				
			||||
 | 
				
			||||
# Qt临时文件 (Qt temporary files)
 | 
				
			||||
*.pro.user
 | 
				
			||||
*.pro.user.*
 | 
				
			||||
.qmake.stash
 | 
				
			||||
 | 
				
			||||
# 个人配置文件 (Personal configuration files)
 | 
				
			||||
# 忽略个人数据库配置,避免团队成员间的配置冲突
 | 
				
			||||
# Ignore personal database configuration to avoid conflicts between team members
 | 
				
			||||
src/Client/config/database.ini
 | 
				
			||||
 | 
				
			||||
# 环境配置文件 (Environment configuration files)
 | 
				
			||||
.env
 | 
				
			||||
.env.local
 | 
				
			||||
.env.development
 | 
				
			||||
.env.production
 | 
				
			||||
 | 
				
			||||
# 日志文件 (Log files)
 | 
				
			||||
*.log
 | 
				
			||||
logs/
 | 
				
			||||
 | 
				
			||||
# 临时文件 (Temporary files)
 | 
				
			||||
*.tmp
 | 
				
			||||
*.temp
 | 
				
			||||
*~
 | 
				
			||||
 | 
				
			||||
# IDE配置文件 (IDE configuration files)
 | 
				
			||||
.vscode/
 | 
				
			||||
.idea/
 | 
				
			||||
*.swp
 | 
				
			||||
*.swo
 | 
				
			||||
 | 
				
			||||
# 系统文件 (System files)
 | 
				
			||||
.DS_Store
 | 
				
			||||
Thumbs.db
 | 
				
			||||
 | 
				
			||||
# 备份文件 (Backup files)
 | 
				
			||||
*.bak
 | 
				
			||||
*.backup
 | 
				
			||||
@ -0,0 +1,126 @@
 | 
				
			||||
<execution>
 | 
				
			||||
  <constraint>
 | 
				
			||||
    ## 学术项目界面约束
 | 
				
			||||
    - **评分时间限制**:界面需要在短时间内给老师留下深刻印象
 | 
				
			||||
    - **演示环境约束**:需要适应课堂投影和不同显示设备
 | 
				
			||||
    - **功能展示要求**:界面必须能清晰展现所有核心功能
 | 
				
			||||
    - **团队协作体现**:界面需要体现团队分工和技术整合
 | 
				
			||||
    - **文档配合约束**:界面设计需要与技术文档保持一致
 | 
				
			||||
  </constraint>
 | 
				
			||||
 | 
				
			||||
  <rule>
 | 
				
			||||
    ## 学术界面强制标准
 | 
				
			||||
    - **功能完整性优先**:所有要求功能必须有对应界面入口
 | 
				
			||||
    - **专业性体现必须**:界面必须体现学生的技术水平
 | 
				
			||||
    - **演示友好性**:界面必须便于课堂演示和功能展示
 | 
				
			||||
    - **创新点突出**:必须有超出基本要求的设计亮点
 | 
				
			||||
    - **稳定性保证**:演示过程中不能出现界面错误
 | 
				
			||||
  </rule>
 | 
				
			||||
 | 
				
			||||
  <guideline>
 | 
				
			||||
    ## 学术界面设计指南
 | 
				
			||||
    - **第一印象优化**:应用启动后的首屏要专业美观
 | 
				
			||||
    - **核心功能突出**:主要功能入口要显眼易找
 | 
				
			||||
    - **技术深度展现**:通过界面细节体现技术实力
 | 
				
			||||
    - **用户引导清晰**:操作流程要直观易懂
 | 
				
			||||
    - **错误处理完善**:异常情况要有友好提示
 | 
				
			||||
  </guideline>
 | 
				
			||||
 | 
				
			||||
  <process>
 | 
				
			||||
    ## 学术界面标准化流程
 | 
				
			||||
    
 | 
				
			||||
    ### 评分标准对齐检查
 | 
				
			||||
    ```mermaid
 | 
				
			||||
    graph TD
 | 
				
			||||
        A[功能完整性检查] --> B[专业美观度评估]
 | 
				
			||||
        B --> C[用户体验测试]
 | 
				
			||||
        C --> D[技术深度体现]
 | 
				
			||||
        D --> E[创新亮点识别]
 | 
				
			||||
        E --> F[演示效果验证]
 | 
				
			||||
        F --> G{达到学术标准?}
 | 
				
			||||
        G -->|是| H[标准合格]
 | 
				
			||||
        G -->|否| I[针对性改进]
 | 
				
			||||
        I --> A
 | 
				
			||||
    ```
 | 
				
			||||
    
 | 
				
			||||
    ### 老师评分视角模拟
 | 
				
			||||
    ```mermaid
 | 
				
			||||
    flowchart LR
 | 
				
			||||
        A[应用启动] --> B[第一印象评分]
 | 
				
			||||
        B --> C[功能演示] 
 | 
				
			||||
        C --> D[交互体验]
 | 
				
			||||
        D --> E[技术亮点]
 | 
				
			||||
        E --> F[整体评价]
 | 
				
			||||
        F --> G[最终评分]
 | 
				
			||||
    ```
 | 
				
			||||
    
 | 
				
			||||
    **评分关键节点:**
 | 
				
			||||
    1. **启动印象** (20%):应用启动速度和首屏效果
 | 
				
			||||
    2. **功能展示** (30%):核心功能的界面表现
 | 
				
			||||
    3. **交互体验** (25%):操作流程的流畅度
 | 
				
			||||
    4. **技术深度** (15%):界面体现的技术水平
 | 
				
			||||
    5. **创新亮点** (10%):超出预期的设计创新
 | 
				
			||||
 | 
				
			||||
    ### 差异化竞争策略
 | 
				
			||||
    ```mermaid
 | 
				
			||||
    mindmap
 | 
				
			||||
      root((竞争优势))
 | 
				
			||||
        技术深度
 | 
				
			||||
          复杂QSS样式
 | 
				
			||||
          自定义控件
 | 
				
			||||
          高级布局技巧
 | 
				
			||||
        视觉设计
 | 
				
			||||
          现代化UI风格
 | 
				
			||||
          专业配色方案
 | 
				
			||||
          精致图标设计
 | 
				
			||||
        交互创新
 | 
				
			||||
          流畅动画效果
 | 
				
			||||
          智能操作引导
 | 
				
			||||
          个性化设置
 | 
				
			||||
        功能完整
 | 
				
			||||
          全面功能覆盖
 | 
				
			||||
          异常处理完善
 | 
				
			||||
          性能优化到位
 | 
				
			||||
    ```
 | 
				
			||||
  </process>
 | 
				
			||||
 | 
				
			||||
  <criteria>
 | 
				
			||||
    ## 学术界面评分标准
 | 
				
			||||
    
 | 
				
			||||
    ### 功能完整性 (30分)
 | 
				
			||||
    - ✅ 所有要求功能都有界面入口 (10分)
 | 
				
			||||
    - ✅ 功能操作流程完整清晰 (10分)
 | 
				
			||||
    - ✅ 异常情况处理完善 (5分)
 | 
				
			||||
    - ✅ 界面与功能逻辑一致 (5分)
 | 
				
			||||
 | 
				
			||||
    ### 专业美观度 (25分)
 | 
				
			||||
    - ✅ 整体视觉设计专业 (8分)
 | 
				
			||||
    - ✅ 色彩搭配协调统一 (6分)
 | 
				
			||||
    - ✅ 控件样式现代美观 (6分)
 | 
				
			||||
    - ✅ 布局合理有序 (5分)
 | 
				
			||||
 | 
				
			||||
    ### 用户体验 (20分)
 | 
				
			||||
    - ✅ 操作流程直观简洁 (8分)
 | 
				
			||||
    - ✅ 界面响应及时准确 (6分)
 | 
				
			||||
    - ✅ 错误提示友好明确 (3分)
 | 
				
			||||
    - ✅ 学习成本低 (3分)
 | 
				
			||||
 | 
				
			||||
    ### 技术深度 (15分)
 | 
				
			||||
    - ✅ Qt技术运用熟练 (6分)
 | 
				
			||||
    - ✅ 代码结构清晰规范 (4分)
 | 
				
			||||
    - ✅ 性能优化到位 (3分)
 | 
				
			||||
    - ✅ 跨平台兼容性好 (2分)
 | 
				
			||||
 | 
				
			||||
    ### 创新亮点 (10分)
 | 
				
			||||
    - ✅ 有超出基本要求的设计 (4分)
 | 
				
			||||
    - ✅ 技术实现有创新性 (3分)
 | 
				
			||||
    - ✅ 用户体验有独特之处 (2分)
 | 
				
			||||
    - ✅ 整体方案有思考深度 (1分)
 | 
				
			||||
 | 
				
			||||
    ### 演示效果加分项
 | 
				
			||||
    - 🌟 界面启动给人惊艳感 (+2分)
 | 
				
			||||
    - 🌟 功能演示流畅无卡顿 (+2分)
 | 
				
			||||
    - 🌟 细节处理体现工匠精神 (+1分)
 | 
				
			||||
    - 🌟 整体方案体现团队协作 (+1分)
 | 
				
			||||
  </criteria>
 | 
				
			||||
</execution>
 | 
				
			||||
@ -0,0 +1,266 @@
 | 
				
			||||
# Qt 5.15 界面开发核心知识
 | 
				
			||||
 | 
				
			||||
## QSS样式表精通
 | 
				
			||||
 | 
				
			||||
### 基础语法结构
 | 
				
			||||
```css
 | 
				
			||||
/* 选择器语法 */
 | 
				
			||||
QWidget { background-color: #f0f0f0; }
 | 
				
			||||
QPushButton#myButton { color: blue; }
 | 
				
			||||
QLabel[class="title"] { font-size: 18px; }
 | 
				
			||||
 | 
				
			||||
/* 伪状态选择器 */
 | 
				
			||||
QPushButton:hover { background-color: #e0e0e0; }
 | 
				
			||||
QPushButton:pressed { background-color: #d0d0d0; }
 | 
				
			||||
QPushButton:disabled { color: gray; }
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### 现代化按钮样式
 | 
				
			||||
```css
 | 
				
			||||
QPushButton {
 | 
				
			||||
    background-color: #4CAF50;
 | 
				
			||||
    border: none;
 | 
				
			||||
    color: white;
 | 
				
			||||
    padding: 8px 16px;
 | 
				
			||||
    border-radius: 4px;
 | 
				
			||||
    font-size: 14px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QPushButton:hover {
 | 
				
			||||
    background-color: #45a049;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QPushButton:pressed {
 | 
				
			||||
    background-color: #3d8b40;
 | 
				
			||||
}
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### 输入框美化
 | 
				
			||||
```css
 | 
				
			||||
QLineEdit {
 | 
				
			||||
    border: 2px solid #ddd;
 | 
				
			||||
    border-radius: 6px;
 | 
				
			||||
    padding: 8px;
 | 
				
			||||
    font-size: 14px;
 | 
				
			||||
    background-color: white;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QLineEdit:focus {
 | 
				
			||||
    border-color: #4CAF50;
 | 
				
			||||
    outline: none;
 | 
				
			||||
}
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 布局管理器精通
 | 
				
			||||
 | 
				
			||||
### QVBoxLayout 垂直布局
 | 
				
			||||
```cpp
 | 
				
			||||
QVBoxLayout *layout = new QVBoxLayout;
 | 
				
			||||
layout->addWidget(titleLabel);
 | 
				
			||||
layout->addSpacing(10);  // 添加间距
 | 
				
			||||
layout->addWidget(contentWidget);
 | 
				
			||||
layout->addStretch();    // 添加弹性空间
 | 
				
			||||
layout->setContentsMargins(20, 20, 20, 20);  // 设置边距
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### QGridLayout 网格布局
 | 
				
			||||
```cpp
 | 
				
			||||
QGridLayout *gridLayout = new QGridLayout;
 | 
				
			||||
gridLayout->addWidget(label1, 0, 0);
 | 
				
			||||
gridLayout->addWidget(lineEdit1, 0, 1);
 | 
				
			||||
gridLayout->addWidget(label2, 1, 0);
 | 
				
			||||
gridLayout->addWidget(lineEdit2, 1, 1);
 | 
				
			||||
gridLayout->setColumnStretch(1, 1);  // 第二列可拉伸
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### QHBoxLayout 水平布局
 | 
				
			||||
```cpp
 | 
				
			||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
 | 
				
			||||
buttonLayout->addStretch();
 | 
				
			||||
buttonLayout->addWidget(okButton);
 | 
				
			||||
buttonLayout->addWidget(cancelButton);
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 控件美化技巧
 | 
				
			||||
 | 
				
			||||
### QTableWidget 表格美化
 | 
				
			||||
```css
 | 
				
			||||
QTableWidget {
 | 
				
			||||
    gridline-color: #e0e0e0;
 | 
				
			||||
    background-color: white;
 | 
				
			||||
    alternate-background-color: #f9f9f9;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QTableWidget::item {
 | 
				
			||||
    padding: 8px;
 | 
				
			||||
    border: none;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QTableWidget::item:selected {
 | 
				
			||||
    background-color: #4CAF50;
 | 
				
			||||
    color: white;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QHeaderView::section {
 | 
				
			||||
    background-color: #f5f5f5;
 | 
				
			||||
    padding: 8px;
 | 
				
			||||
    border: 1px solid #ddd;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
}
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### QComboBox 下拉框美化
 | 
				
			||||
```css
 | 
				
			||||
QComboBox {
 | 
				
			||||
    border: 2px solid #ddd;
 | 
				
			||||
    border-radius: 6px;
 | 
				
			||||
    padding: 6px;
 | 
				
			||||
    min-width: 120px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QComboBox::drop-down {
 | 
				
			||||
    border: none;
 | 
				
			||||
    width: 20px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QComboBox::down-arrow {
 | 
				
			||||
    image: url(:/icons/down-arrow.png);
 | 
				
			||||
    width: 12px;
 | 
				
			||||
    height: 12px;
 | 
				
			||||
}
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 自定义控件开发
 | 
				
			||||
 | 
				
			||||
### 自定义按钮类
 | 
				
			||||
```cpp
 | 
				
			||||
class CustomButton : public QPushButton {
 | 
				
			||||
    Q_OBJECT
 | 
				
			||||
public:
 | 
				
			||||
    CustomButton(const QString &text, QWidget *parent = nullptr);
 | 
				
			||||
    
 | 
				
			||||
protected:
 | 
				
			||||
    void paintEvent(QPaintEvent *event) override;
 | 
				
			||||
    void enterEvent(QEvent *event) override;
 | 
				
			||||
    void leaveEvent(QEvent *event) override;
 | 
				
			||||
    
 | 
				
			||||
private:
 | 
				
			||||
    bool m_hovered;
 | 
				
			||||
    QPropertyAnimation *m_animation;
 | 
				
			||||
};
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### 渐变背景实现
 | 
				
			||||
```cpp
 | 
				
			||||
void CustomWidget::paintEvent(QPaintEvent *event) {
 | 
				
			||||
    QPainter painter(this);
 | 
				
			||||
    painter.setRenderHint(QPainter::Antialiasing);
 | 
				
			||||
    
 | 
				
			||||
    QLinearGradient gradient(0, 0, 0, height());
 | 
				
			||||
    gradient.setColorAt(0, QColor(240, 240, 240));
 | 
				
			||||
    gradient.setColorAt(1, QColor(220, 220, 220));
 | 
				
			||||
    
 | 
				
			||||
    painter.fillRect(rect(), gradient);
 | 
				
			||||
}
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 信号槽机制优化
 | 
				
			||||
 | 
				
			||||
### Lambda表达式连接
 | 
				
			||||
```cpp
 | 
				
			||||
connect(button, &QPushButton::clicked, [this]() {
 | 
				
			||||
    // 处理点击事件
 | 
				
			||||
    updateUI();
 | 
				
			||||
});
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### 自定义信号定义
 | 
				
			||||
```cpp
 | 
				
			||||
class CustomWidget : public QWidget {
 | 
				
			||||
    Q_OBJECT
 | 
				
			||||
signals:
 | 
				
			||||
    void dataChanged(const QString &data);
 | 
				
			||||
    void statusUpdated(int status);
 | 
				
			||||
    
 | 
				
			||||
public slots:
 | 
				
			||||
    void onDataReceived(const QByteArray &data);
 | 
				
			||||
    void onStatusChanged(bool connected);
 | 
				
			||||
};
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 性能优化技巧
 | 
				
			||||
 | 
				
			||||
### 减少重绘次数
 | 
				
			||||
```cpp
 | 
				
			||||
// 批量更新时禁用重绘
 | 
				
			||||
widget->setUpdatesEnabled(false);
 | 
				
			||||
// 执行多个更新操作
 | 
				
			||||
widget->setUpdatesEnabled(true);
 | 
				
			||||
widget->update();  // 手动触发重绘
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### 使用样式表缓存
 | 
				
			||||
```cpp
 | 
				
			||||
// 在类初始化时设置样式表,避免重复设置
 | 
				
			||||
static const QString buttonStyle = 
 | 
				
			||||
    "QPushButton { background-color: #4CAF50; }";
 | 
				
			||||
button->setStyleSheet(buttonStyle);
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 响应式设计
 | 
				
			||||
 | 
				
			||||
### 自适应布局
 | 
				
			||||
```cpp
 | 
				
			||||
void MainWindow::resizeEvent(QResizeEvent *event) {
 | 
				
			||||
    QMainWindow::resizeEvent(event);
 | 
				
			||||
    
 | 
				
			||||
    // 根据窗口大小调整布局
 | 
				
			||||
    if (width() < 800) {
 | 
				
			||||
        // 小屏幕布局
 | 
				
			||||
        switchToCompactLayout();
 | 
				
			||||
    } else {
 | 
				
			||||
        // 大屏幕布局
 | 
				
			||||
        switchToNormalLayout();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### DPI适配
 | 
				
			||||
```cpp
 | 
				
			||||
// 获取系统DPI缩放比例
 | 
				
			||||
qreal dpiScale = qApp->devicePixelRatio();
 | 
				
			||||
int scaledSize = static_cast<int>(16 * dpiScale);
 | 
				
			||||
font.setPixelSize(scaledSize);
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 国际化支持
 | 
				
			||||
 | 
				
			||||
### 文本国际化
 | 
				
			||||
```cpp
 | 
				
			||||
// 在代码中使用tr()函数
 | 
				
			||||
button->setText(tr("确定"));
 | 
				
			||||
label->setText(tr("用户名:"));
 | 
				
			||||
 | 
				
			||||
// 在.pro文件中添加
 | 
				
			||||
TRANSLATIONS += app_zh_CN.ts app_en_US.ts
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
## 调试和测试
 | 
				
			||||
 | 
				
			||||
### 样式表调试
 | 
				
			||||
```cpp
 | 
				
			||||
// 运行时修改样式表进行调试
 | 
				
			||||
#ifdef QT_DEBUG
 | 
				
			||||
    widget->setStyleSheet("border: 1px solid red;");  // 调试边框
 | 
				
			||||
#endif
 | 
				
			||||
```
 | 
				
			||||
 | 
				
			||||
### 性能监控
 | 
				
			||||
```cpp
 | 
				
			||||
// 使用QElapsedTimer监控性能
 | 
				
			||||
QElapsedTimer timer;
 | 
				
			||||
timer.start();
 | 
				
			||||
// 执行耗时操作
 | 
				
			||||
qDebug() << "操作耗时:" << timer.elapsed() << "ms";
 | 
				
			||||
```
 | 
				
			||||
@ -0,0 +1,19 @@
 | 
				
			||||
<role>
 | 
				
			||||
  <personality>
 | 
				
			||||
    @!thought://remember
 | 
				
			||||
    @!thought://recall
 | 
				
			||||
    @!thought://ui-design-thinking
 | 
				
			||||
    @!thought://academic-standards-awareness
 | 
				
			||||
  </personality>
 | 
				
			||||
  
 | 
				
			||||
  <principle>
 | 
				
			||||
    @!execution://qt-optimization-workflow
 | 
				
			||||
    @!execution://academic-ui-standards
 | 
				
			||||
  </principle>
 | 
				
			||||
  
 | 
				
			||||
  <knowledge>
 | 
				
			||||
    @!knowledge://qt-ui-development
 | 
				
			||||
    @!knowledge://ui-ux-principles
 | 
				
			||||
    @!knowledge://academic-project-standards
 | 
				
			||||
  </knowledge>
 | 
				
			||||
</role>
 | 
				
			||||
											
												Binary file not shown.
											
										
									
								@ -0,0 +1,14 @@
 | 
				
			||||
cmake_minimum_required(VERSION 2.14)
 | 
				
			||||
project(faceLightClient2)
 | 
				
			||||
 | 
				
			||||
set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -O3 -march=native -Wall")
 | 
				
			||||
set(CMAKE_CXX_STANDARD 11)
 | 
				
			||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
 | 
				
			||||
 | 
				
			||||
include_directories(include)
 | 
				
			||||
link_directories(lib)
 | 
				
			||||
 | 
				
			||||
add_executable(faceLightClient2 main2.cpp)
 | 
				
			||||
target_link_libraries(faceLightClient2 libfaceLight_SDK_arm64.so)
 | 
				
			||||
 | 
				
			||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 
 | 
				
			||||
@ -1,63 +0,0 @@
 | 
				
			||||
# Qt/C++ build files
 | 
				
			||||
build/
 | 
				
			||||
bin/
 | 
				
			||||
*.o
 | 
				
			||||
*.obj
 | 
				
			||||
*.so
 | 
				
			||||
*.dll
 | 
				
			||||
*.dylib
 | 
				
			||||
*.a
 | 
				
			||||
*.lib
 | 
				
			||||
*.exe
 | 
				
			||||
 | 
				
			||||
# Qt specific files
 | 
				
			||||
moc_*.cpp
 | 
				
			||||
moc_*.h
 | 
				
			||||
qrc_*.cpp
 | 
				
			||||
ui_*.h
 | 
				
			||||
Makefile*
 | 
				
			||||
*.pro.user
 | 
				
			||||
*.pro.user.*
 | 
				
			||||
 | 
				
			||||
# IDE files
 | 
				
			||||
.vscode/
 | 
				
			||||
.idea/
 | 
				
			||||
*.kate-swp
 | 
				
			||||
*~
 | 
				
			||||
 | 
				
			||||
# Temporary files
 | 
				
			||||
*.tmp
 | 
				
			||||
*.temp
 | 
				
			||||
.DS_Store
 | 
				
			||||
Thumbs.db
 | 
				
			||||
 | 
				
			||||
# Debug/Release directories
 | 
				
			||||
debug/
 | 
				
			||||
release/
 | 
				
			||||
Debug/
 | 
				
			||||
Release/
 | 
				
			||||
 | 
				
			||||
# CMake
 | 
				
			||||
CMakeCache.txt
 | 
				
			||||
CMakeFiles/
 | 
				
			||||
cmake_install.cmake
 | 
				
			||||
 | 
				
			||||
# Android build files
 | 
				
			||||
android/build/
 | 
				
			||||
android/.gradle/
 | 
				
			||||
android/local.properties
 | 
				
			||||
 | 
				
			||||
# Backup files
 | 
				
			||||
*.bak
 | 
				
			||||
*.backup
 | 
				
			||||
*~
 | 
				
			||||
 | 
				
			||||
# Log files
 | 
				
			||||
*.log
 | 
				
			||||
 | 
				
			||||
# Core dumps
 | 
				
			||||
core
 | 
				
			||||
core.*
 | 
				
			||||
 | 
				
			||||
# Documentation directory
 | 
				
			||||
doc/
 | 
				
			||||
											
												Binary file not shown.
											
										
									
								@ -0,0 +1,94 @@
 | 
				
			||||
#ifndef FACELIGHTCONTROL_H
 | 
				
			||||
#define FACELIGHTCONTROL_H
 | 
				
			||||
 | 
				
			||||
#include <QMainWindow>
 | 
				
			||||
#include <QPushButton>
 | 
				
			||||
#include <QVBoxLayout>
 | 
				
			||||
#include <QHBoxLayout>
 | 
				
			||||
#include <QLabel>
 | 
				
			||||
#include <QProcess>
 | 
				
			||||
#include <QMessageBox>
 | 
				
			||||
#include <QDebug>
 | 
				
			||||
#include <QComboBox>
 | 
				
			||||
#include <QTextEdit>
 | 
				
			||||
#include <QProgressBar>
 | 
				
			||||
#include <QTimer>
 | 
				
			||||
#include <QSpinBox>
 | 
				
			||||
#include <QSlider>
 | 
				
			||||
#include <QGroupBox>
 | 
				
			||||
#include <QLineEdit>
 | 
				
			||||
#include <QFormLayout>
 | 
				
			||||
 | 
				
			||||
QT_BEGIN_NAMESPACE
 | 
				
			||||
namespace Ui {
 | 
				
			||||
class FaceLightControl;
 | 
				
			||||
}
 | 
				
			||||
QT_END_NAMESPACE
 | 
				
			||||
 | 
				
			||||
class FaceLightControl : public QMainWindow
 | 
				
			||||
{
 | 
				
			||||
    Q_OBJECT
 | 
				
			||||
 | 
				
			||||
public:
 | 
				
			||||
    FaceLightControl(QWidget *parent = nullptr);
 | 
				
			||||
    ~FaceLightControl();
 | 
				
			||||
 | 
				
			||||
private slots:
 | 
				
			||||
    // 基础控制按钮
 | 
				
			||||
    void on_setAllLeds_clicked();
 | 
				
			||||
    void on_setSingleLed_clicked();
 | 
				
			||||
    void on_startColorCycle_clicked();
 | 
				
			||||
    void on_stopColorCycle_clicked();
 | 
				
			||||
    void on_applyCustomPattern_clicked();
 | 
				
			||||
    void on_turnOffAllLeds_clicked();
 | 
				
			||||
    
 | 
				
			||||
    // SSH连接设置
 | 
				
			||||
    void on_saveSshSettings_clicked();
 | 
				
			||||
    void on_testConnection_clicked();
 | 
				
			||||
    
 | 
				
			||||
    // 高级控制
 | 
				
			||||
    void on_rgbAlternating_clicked();
 | 
				
			||||
    void on_quickPresets_clicked();
 | 
				
			||||
    
 | 
				
			||||
    // SSH进程处理
 | 
				
			||||
    void onSshProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
 | 
				
			||||
    void onSshProcessError(QProcess::ProcessError error);
 | 
				
			||||
    
 | 
				
			||||
    // 颜色循环定时器
 | 
				
			||||
    void onColorCycleTimer();
 | 
				
			||||
 | 
				
			||||
private:
 | 
				
			||||
    Ui::FaceLightControl *ui;
 | 
				
			||||
    QProcess *sshProcess;
 | 
				
			||||
    QString currentCommand;
 | 
				
			||||
    
 | 
				
			||||
    // SSH连接信息
 | 
				
			||||
    QString m_sshHost;
 | 
				
			||||
    QString m_sshUser;
 | 
				
			||||
    QString m_sshPassword;
 | 
				
			||||
    QString m_jumpHost;
 | 
				
			||||
    QString m_jumpUser;
 | 
				
			||||
    QString m_jumpPassword;
 | 
				
			||||
    
 | 
				
			||||
    // 颜色循环控制
 | 
				
			||||
    QTimer *colorCycleTimer;
 | 
				
			||||
    QStringList cycleColors;
 | 
				
			||||
    int currentColorIndex;
 | 
				
			||||
    bool isCycling;
 | 
				
			||||
    
 | 
				
			||||
    // 核心方法
 | 
				
			||||
    void executeSSHCommand(const QString &command, const QString &description);
 | 
				
			||||
    void updateSshSettings();
 | 
				
			||||
    
 | 
				
			||||
    // UI设置和状态更新
 | 
				
			||||
    void setupUI();
 | 
				
			||||
    void updateStatus(const QString &message, bool isError = false);
 | 
				
			||||
    void setupColorCycle();
 | 
				
			||||
    
 | 
				
			||||
    // 命令构建方法
 | 
				
			||||
    QString buildFaceLightCommand(const QString &mode, const QString &color = "", 
 | 
				
			||||
                                 int ledIndex = -1, int delay = 2000, 
 | 
				
			||||
                                 int times = -1, const QString &pattern = "");
 | 
				
			||||
};
 | 
				
			||||
 | 
				
			||||
#endif // FACELIGHTCONTROL_H 
 | 
				
			||||
@ -0,0 +1,702 @@
 | 
				
			||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||
<ui version="4.0">
 | 
				
			||||
 <class>FaceLightControl</class>
 | 
				
			||||
 <widget class="QMainWindow" name="FaceLightControl">
 | 
				
			||||
  <property name="geometry">
 | 
				
			||||
   <rect>
 | 
				
			||||
    <x>0</x>
 | 
				
			||||
    <y>0</y>
 | 
				
			||||
    <width>1000</width>
 | 
				
			||||
    <height>900</height>
 | 
				
			||||
   </rect>
 | 
				
			||||
  </property>
 | 
				
			||||
  <property name="windowTitle">
 | 
				
			||||
   <string>机器狗面部灯光控制系统</string>
 | 
				
			||||
  </property>
 | 
				
			||||
  <property name="styleSheet">
 | 
				
			||||
   <string notr="true">QMainWindow {
 | 
				
			||||
    background-color: rgb(24, 33, 45);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QPushButton {
 | 
				
			||||
    background-color: rgb(30, 44, 62);
 | 
				
			||||
    color: rgb(220, 230, 240);
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.5);
 | 
				
			||||
    border-radius: 8px;
 | 
				
			||||
    padding: 12px 20px;
 | 
				
			||||
    font-size: 14px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
    min-height: 35px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QPushButton:hover {
 | 
				
			||||
    background-color: rgb(50, 70, 95);
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.8);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QPushButton:pressed {
 | 
				
			||||
    background-color: rgb(40, 60, 85);
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 1.0);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QLabel {
 | 
				
			||||
    color: rgb(220, 230, 240);
 | 
				
			||||
    font-size: 14px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QComboBox, QSpinBox, QLineEdit {
 | 
				
			||||
    background-color: rgb(30, 44, 62);
 | 
				
			||||
    color: rgb(220, 230, 240);
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.5);
 | 
				
			||||
    border-radius: 5px;
 | 
				
			||||
    padding: 8px;
 | 
				
			||||
    font-size: 14px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QTextEdit {
 | 
				
			||||
    background-color: rgb(15, 22, 32);
 | 
				
			||||
    color: rgb(220, 230, 240);
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.3);
 | 
				
			||||
    border-radius: 5px;
 | 
				
			||||
    font-family: "Courier New", monospace;
 | 
				
			||||
    font-size: 12px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QProgressBar {
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.5);
 | 
				
			||||
    border-radius: 5px;
 | 
				
			||||
    text-align: center;
 | 
				
			||||
    background-color: rgb(30, 44, 62);
 | 
				
			||||
    color: rgb(220, 230, 240);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QProgressBar::chunk {
 | 
				
			||||
    background-color: rgba(0, 168, 255, 0.8);
 | 
				
			||||
    border-radius: 3px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QGroupBox {
 | 
				
			||||
    font-size: 16px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
    color: rgb(0, 168, 255);
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.4);
 | 
				
			||||
    border-radius: 10px;
 | 
				
			||||
    margin-top: 15px;
 | 
				
			||||
    padding-top: 10px;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QGroupBox::title {
 | 
				
			||||
    subcontrol-origin: margin;
 | 
				
			||||
    subcontrol-position: top center;
 | 
				
			||||
    padding: 0 15px;
 | 
				
			||||
    background-color: rgb(24, 33, 45);
 | 
				
			||||
}</string>
 | 
				
			||||
  </property>
 | 
				
			||||
  <widget class="QWidget" name="centralwidget">
 | 
				
			||||
   <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||
    <property name="spacing">
 | 
				
			||||
     <number>20</number>
 | 
				
			||||
    </property>
 | 
				
			||||
    <property name="leftMargin">
 | 
				
			||||
     <number>30</number>
 | 
				
			||||
    </property>
 | 
				
			||||
    <property name="topMargin">
 | 
				
			||||
     <number>20</number>
 | 
				
			||||
    </property>
 | 
				
			||||
    <property name="rightMargin">
 | 
				
			||||
     <number>30</number>
 | 
				
			||||
    </property>
 | 
				
			||||
    <property name="bottomMargin">
 | 
				
			||||
     <number>20</number>
 | 
				
			||||
    </property>
 | 
				
			||||
    <item>
 | 
				
			||||
     <widget class="QLabel" name="titleLabel">
 | 
				
			||||
      <property name="text">
 | 
				
			||||
       <string>💡 机器狗面部灯光控制系统</string>
 | 
				
			||||
      </property>
 | 
				
			||||
      <property name="alignment">
 | 
				
			||||
       <set>Qt::AlignCenter</set>
 | 
				
			||||
      </property>
 | 
				
			||||
      <property name="styleSheet">
 | 
				
			||||
       <string notr="true">QLabel {
 | 
				
			||||
    color: rgb(0, 168, 255);
 | 
				
			||||
    font-size: 32px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
    padding: 20px;
 | 
				
			||||
    background: qlineargradient(x1:0, y1:0, x2:1, y2:1, 
 | 
				
			||||
                stop:0 rgba(0, 168, 255, 0.1), 
 | 
				
			||||
                stop:1 rgba(0, 120, 180, 0.1));
 | 
				
			||||
    border: 2px solid rgba(0, 168, 255, 0.3);
 | 
				
			||||
    border-radius: 15px;
 | 
				
			||||
}</string>
 | 
				
			||||
      </property>
 | 
				
			||||
     </widget>
 | 
				
			||||
    </item>
 | 
				
			||||
    
 | 
				
			||||
    <item>
 | 
				
			||||
     <widget class="QGroupBox" name="sshSettingsGroup">
 | 
				
			||||
      <property name="title">
 | 
				
			||||
       <string>🔗 SSH连接设置</string>
 | 
				
			||||
      </property>
 | 
				
			||||
      <layout class="QVBoxLayout" name="sshLayout">
 | 
				
			||||
       <item>
 | 
				
			||||
        <layout class="QHBoxLayout" name="connectionLayout">
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QGroupBox" name="jumpHostGroup">
 | 
				
			||||
           <property name="title">
 | 
				
			||||
            <string>跳板机设置</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QGroupBox { font-size: 14px; color: rgb(180, 190, 200); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <layout class="QFormLayout" name="jumpFormLayout">
 | 
				
			||||
            <item row="0" column="0">
 | 
				
			||||
             <widget class="QLabel" name="jumpIpLabel">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>跳板机IP:</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="0" column="1">
 | 
				
			||||
             <widget class="QLineEdit" name="lineEditJumpIp">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>192.168.12.1</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="1" column="0">
 | 
				
			||||
             <widget class="QLabel" name="jumpUserLabel">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>用户名:</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="1" column="1">
 | 
				
			||||
             <widget class="QLineEdit" name="lineEditJumpUsername">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>pi</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="2" column="0">
 | 
				
			||||
             <widget class="QLabel" name="jumpPasswordLabel">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>密码:</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="2" column="1">
 | 
				
			||||
             <widget class="QLineEdit" name="lineEditJumpPassword">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>123</string>
 | 
				
			||||
              </property>
 | 
				
			||||
              <property name="echoMode">
 | 
				
			||||
               <enum>QLineEdit::Password</enum>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
           </layout>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QGroupBox" name="targetHostGroup">
 | 
				
			||||
           <property name="title">
 | 
				
			||||
            <string>目标机器狗设置</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QGroupBox { font-size: 14px; color: rgb(180, 190, 200); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <layout class="QFormLayout" name="targetFormLayout">
 | 
				
			||||
            <item row="0" column="0">
 | 
				
			||||
             <widget class="QLabel" name="targetIpLabel">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>机器狗IP:</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="0" column="1">
 | 
				
			||||
             <widget class="QLineEdit" name="lineEditTargetIp">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>192.168.123.13</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="1" column="0">
 | 
				
			||||
             <widget class="QLabel" name="targetUserLabel">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>用户名:</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="1" column="1">
 | 
				
			||||
             <widget class="QLineEdit" name="lineEditTargetUsername">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>unitree</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="2" column="0">
 | 
				
			||||
             <widget class="QLabel" name="targetPasswordLabel">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>密码:</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
            <item row="2" column="1">
 | 
				
			||||
             <widget class="QLineEdit" name="lineEditTargetPassword">
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>123</string>
 | 
				
			||||
              </property>
 | 
				
			||||
              <property name="echoMode">
 | 
				
			||||
               <enum>QLineEdit::Password</enum>
 | 
				
			||||
              </property>
 | 
				
			||||
             </widget>
 | 
				
			||||
            </item>
 | 
				
			||||
           </layout>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
        </layout>
 | 
				
			||||
       </item>
 | 
				
			||||
       
 | 
				
			||||
       <item>
 | 
				
			||||
        <layout class="QHBoxLayout" name="sshButtonLayout">
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="saveSshSettings">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>💾 保存设置</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="testConnection">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🔍 测试连接</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         <item>
 | 
				
			||||
          <spacer name="horizontalSpacer">
 | 
				
			||||
           <property name="orientation">
 | 
				
			||||
            <enum>Qt::Horizontal</enum>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="sizeHint">
 | 
				
			||||
            <size>
 | 
				
			||||
             <width>40</width>
 | 
				
			||||
             <height>20</height>
 | 
				
			||||
            </size>
 | 
				
			||||
           </property>
 | 
				
			||||
          </spacer>
 | 
				
			||||
         </item>
 | 
				
			||||
        </layout>
 | 
				
			||||
       </item>
 | 
				
			||||
       
 | 
				
			||||
       <item>
 | 
				
			||||
        <widget class="QLabel" name="connectionStatusLabel">
 | 
				
			||||
         <property name="text">
 | 
				
			||||
          <string>连接状态: 等待设置...</string>
 | 
				
			||||
         </property>
 | 
				
			||||
         <property name="styleSheet">
 | 
				
			||||
          <string notr="true">color: rgb(160, 170, 180); font-size: 12px;</string>
 | 
				
			||||
         </property>
 | 
				
			||||
        </widget>
 | 
				
			||||
       </item>
 | 
				
			||||
      </layout>
 | 
				
			||||
     </widget>
 | 
				
			||||
    </item>
 | 
				
			||||
    
 | 
				
			||||
    <item>
 | 
				
			||||
     <layout class="QHBoxLayout" name="mainControlLayout">
 | 
				
			||||
      <item>
 | 
				
			||||
       <widget class="QGroupBox" name="basicControlGroup">
 | 
				
			||||
        <property name="title">
 | 
				
			||||
         <string>🎨 基础控制</string>
 | 
				
			||||
        </property>
 | 
				
			||||
        <layout class="QVBoxLayout" name="basicControlLayout">
 | 
				
			||||
         <item>
 | 
				
			||||
          <layout class="QFormLayout" name="colorFormLayout">
 | 
				
			||||
           <item row="0" column="0">
 | 
				
			||||
            <widget class="QLabel" name="colorLabel">
 | 
				
			||||
             <property name="text">
 | 
				
			||||
              <string>颜色选择:</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item row="0" column="1">
 | 
				
			||||
            <widget class="QComboBox" name="colorComboBox">
 | 
				
			||||
             <item>
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>Red</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </item>
 | 
				
			||||
             <item>
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>Green</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </item>
 | 
				
			||||
             <item>
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>Blue</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </item>
 | 
				
			||||
             <item>
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>Yellow</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </item>
 | 
				
			||||
             <item>
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>White</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </item>
 | 
				
			||||
             <item>
 | 
				
			||||
              <property name="text">
 | 
				
			||||
               <string>Black</string>
 | 
				
			||||
              </property>
 | 
				
			||||
             </item>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item row="1" column="0">
 | 
				
			||||
            <widget class="QLabel" name="ledIndexLabel">
 | 
				
			||||
             <property name="text">
 | 
				
			||||
              <string>LED索引:</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item row="1" column="1">
 | 
				
			||||
            <widget class="QSpinBox" name="ledIndexSpinBox">
 | 
				
			||||
             <property name="maximum">
 | 
				
			||||
              <number>11</number>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
          </layout>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="setAllLeds">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>💡 设置所有LED</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(45, 125, 65);
 | 
				
			||||
    font-size: 16px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(65, 145, 85); }
 | 
				
			||||
QPushButton:pressed { background-color: rgb(55, 135, 75); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="setSingleLed">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🔆 设置单个LED</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(85, 125, 165);
 | 
				
			||||
    font-size: 16px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(105, 145, 185); }
 | 
				
			||||
QPushButton:pressed { background-color: rgb(95, 135, 175); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="turnOffAllLeds">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🌑 关闭所有LED</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(120, 60, 60);
 | 
				
			||||
    font-size: 16px;
 | 
				
			||||
    font-weight: bold;
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(140, 80, 80); }
 | 
				
			||||
QPushButton:pressed { background-color: rgb(130, 70, 70); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
        </layout>
 | 
				
			||||
       </widget>
 | 
				
			||||
      </item>
 | 
				
			||||
      
 | 
				
			||||
      <item>
 | 
				
			||||
       <widget class="QGroupBox" name="advancedControlGroup">
 | 
				
			||||
        <property name="title">
 | 
				
			||||
         <string>⚡ 高级控制</string>
 | 
				
			||||
        </property>
 | 
				
			||||
        <layout class="QVBoxLayout" name="advancedControlLayout">
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QLabel" name="cycleLabel">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🔄 颜色循环设置:</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">font-weight: bold; color: rgb(0, 168, 255);</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <layout class="QFormLayout" name="cycleFormLayout">
 | 
				
			||||
           <item row="0" column="0">
 | 
				
			||||
            <widget class="QLabel" name="cycleDelayLabel">
 | 
				
			||||
             <property name="text">
 | 
				
			||||
              <string>延时(ms):</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item row="0" column="1">
 | 
				
			||||
            <widget class="QSpinBox" name="cycleDelaySpinBox">
 | 
				
			||||
             <property name="minimum">
 | 
				
			||||
              <number>100</number>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="maximum">
 | 
				
			||||
              <number>10000</number>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="value">
 | 
				
			||||
              <number>1000</number>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="suffix">
 | 
				
			||||
              <string> ms</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item row="1" column="0">
 | 
				
			||||
            <widget class="QLabel" name="cycleTimesLabel">
 | 
				
			||||
             <property name="text">
 | 
				
			||||
              <string>循环次数:</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item row="1" column="1">
 | 
				
			||||
            <widget class="QSpinBox" name="cycleTimesSpinBox">
 | 
				
			||||
             <property name="minimum">
 | 
				
			||||
              <number>-1</number>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="maximum">
 | 
				
			||||
              <number>100</number>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="value">
 | 
				
			||||
              <number>5</number>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="specialValueText">
 | 
				
			||||
              <string>无限循环</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
          </layout>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <layout class="QHBoxLayout" name="cycleButtonLayout">
 | 
				
			||||
           <item>
 | 
				
			||||
            <widget class="QPushButton" name="startColorCycle">
 | 
				
			||||
             <property name="text">
 | 
				
			||||
              <string>▶️ 开始循环</string>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="styleSheet">
 | 
				
			||||
              <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(45, 125, 65);
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(65, 145, 85); }</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
           <item>
 | 
				
			||||
            <widget class="QPushButton" name="stopColorCycle">
 | 
				
			||||
             <property name="text">
 | 
				
			||||
              <string>⏹️ 停止循环</string>
 | 
				
			||||
             </property>
 | 
				
			||||
             <property name="styleSheet">
 | 
				
			||||
              <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(165, 85, 45);
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(185, 105, 65); }</string>
 | 
				
			||||
             </property>
 | 
				
			||||
            </widget>
 | 
				
			||||
           </item>
 | 
				
			||||
          </layout>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QLabel" name="patternLabel">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🎭 自定义图案:</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">font-weight: bold; color: rgb(0, 168, 255);</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QLineEdit" name="patternLineEdit">
 | 
				
			||||
           <property name="placeholderText">
 | 
				
			||||
            <string>例如: 0:red,3:green,6:blue</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="applyCustomPattern">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🎨 应用自定义图案</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="rgbAlternating">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🌈 RGB交替模式</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
        </layout>
 | 
				
			||||
       </widget>
 | 
				
			||||
      </item>
 | 
				
			||||
      
 | 
				
			||||
      <item>
 | 
				
			||||
       <widget class="QGroupBox" name="presetGroup">
 | 
				
			||||
        <property name="title">
 | 
				
			||||
         <string>⚡ 快速预设</string>
 | 
				
			||||
        </property>
 | 
				
			||||
        <layout class="QVBoxLayout" name="presetLayout">
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="preset1">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🔴 预设1: 红色</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(180, 60, 60);
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(200, 80, 80); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="preset2">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🔵 预设2: 蓝色</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(60, 60, 180);
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(80, 80, 200); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="preset3">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>🟢 预设3: 绿色</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(60, 180, 60);
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(80, 200, 80); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <widget class="QPushButton" name="preset4">
 | 
				
			||||
           <property name="text">
 | 
				
			||||
            <string>⚪ 预设4: 白色</string>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="styleSheet">
 | 
				
			||||
            <string notr="true">QPushButton {
 | 
				
			||||
    background-color: rgb(140, 140, 140);
 | 
				
			||||
    color: rgb(30, 30, 30);
 | 
				
			||||
}
 | 
				
			||||
QPushButton:hover { background-color: rgb(160, 160, 160); }</string>
 | 
				
			||||
           </property>
 | 
				
			||||
          </widget>
 | 
				
			||||
         </item>
 | 
				
			||||
         
 | 
				
			||||
         <item>
 | 
				
			||||
          <spacer name="presetSpacer">
 | 
				
			||||
           <property name="orientation">
 | 
				
			||||
            <enum>Qt::Vertical</enum>
 | 
				
			||||
           </property>
 | 
				
			||||
           <property name="sizeHint">
 | 
				
			||||
            <size>
 | 
				
			||||
             <width>20</width>
 | 
				
			||||
             <height>40</height>
 | 
				
			||||
            </size>
 | 
				
			||||
           </property>
 | 
				
			||||
          </spacer>
 | 
				
			||||
         </item>
 | 
				
			||||
        </layout>
 | 
				
			||||
       </widget>
 | 
				
			||||
      </item>
 | 
				
			||||
     </layout>
 | 
				
			||||
    </item>
 | 
				
			||||
    
 | 
				
			||||
    <item>
 | 
				
			||||
     <widget class="QProgressBar" name="progressBar">
 | 
				
			||||
      <property name="value">
 | 
				
			||||
       <number>0</number>
 | 
				
			||||
      </property>
 | 
				
			||||
      <property name="textVisible">
 | 
				
			||||
       <bool>true</bool>
 | 
				
			||||
      </property>
 | 
				
			||||
     </widget>
 | 
				
			||||
    </item>
 | 
				
			||||
    
 | 
				
			||||
    <item>
 | 
				
			||||
     <widget class="QLabel" name="logLabel">
 | 
				
			||||
      <property name="text">
 | 
				
			||||
       <string>📋 执行日志:</string>
 | 
				
			||||
      </property>
 | 
				
			||||
      <property name="styleSheet">
 | 
				
			||||
       <string notr="true">font-size: 16px; font-weight: bold; color: rgb(0, 168, 255);</string>
 | 
				
			||||
      </property>
 | 
				
			||||
     </widget>
 | 
				
			||||
    </item>
 | 
				
			||||
    
 | 
				
			||||
    <item>
 | 
				
			||||
     <widget class="QTextEdit" name="logTextEdit">
 | 
				
			||||
      <property name="minimumSize">
 | 
				
			||||
       <size>
 | 
				
			||||
        <width>0</width>
 | 
				
			||||
        <height>200</height>
 | 
				
			||||
       </size>
 | 
				
			||||
      </property>
 | 
				
			||||
      <property name="readOnly">
 | 
				
			||||
       <bool>true</bool>
 | 
				
			||||
      </property>
 | 
				
			||||
     </widget>
 | 
				
			||||
    </item>
 | 
				
			||||
   </layout>
 | 
				
			||||
  </widget>
 | 
				
			||||
  
 | 
				
			||||
  <widget class="QMenuBar" name="menubar">
 | 
				
			||||
   <property name="geometry">
 | 
				
			||||
    <rect>
 | 
				
			||||
     <x>0</x>
 | 
				
			||||
     <y>0</y>
 | 
				
			||||
     <width>1000</width>
 | 
				
			||||
     <height>22</height>
 | 
				
			||||
    </rect>
 | 
				
			||||
   </property>
 | 
				
			||||
  </widget>
 | 
				
			||||
  
 | 
				
			||||
  <widget class="QStatusBar" name="statusbar"/>
 | 
				
			||||
 </widget>
 | 
				
			||||
 <resources/>
 | 
				
			||||
 <connections/>
 | 
				
			||||
</ui> 
 | 
				
			||||
@ -0,0 +1,47 @@
 | 
				
			||||
# 战场探索系统数据库配置文件示例
 | 
				
			||||
# Database Configuration Example for BattlefieldExplorationSystem
 | 
				
			||||
# 
 | 
				
			||||
# 这是一个示例配置文件,展示了常见的配置选项
 | 
				
			||||
# This is an example configuration file showing common configuration options
 | 
				
			||||
 | 
				
			||||
[Database]
 | 
				
			||||
# 数据库服务器地址 (Database server host)
 | 
				
			||||
host=localhost
 | 
				
			||||
 | 
				
			||||
# 数据库端口 (Database port)
 | 
				
			||||
port=3306
 | 
				
			||||
 | 
				
			||||
# 数据库名称 (Database name)
 | 
				
			||||
databaseName=Client
 | 
				
			||||
 | 
				
			||||
# 数据库用户名 (Database username)
 | 
				
			||||
username=root
 | 
				
			||||
 | 
				
			||||
# 数据库密码 (Database password)
 | 
				
			||||
password=example_password
 | 
				
			||||
 | 
				
			||||
# 连接超时时间,单位毫秒 (Connection timeout in milliseconds)
 | 
				
			||||
connectionTimeout=30000
 | 
				
			||||
 | 
				
			||||
# 数据库驱动名称 (Database driver name)
 | 
				
			||||
driverName=QMYSQL
 | 
				
			||||
 | 
				
			||||
# 其他常见配置示例:
 | 
				
			||||
# Other common configuration examples:
 | 
				
			||||
 | 
				
			||||
# 使用不同的数据库服务器
 | 
				
			||||
# Using different database server
 | 
				
			||||
# host=192.168.1.100
 | 
				
			||||
# port=3306
 | 
				
			||||
 | 
				
			||||
# 使用不同的数据库名称
 | 
				
			||||
# Using different database name
 | 
				
			||||
# databaseName=BattlefieldSystem
 | 
				
			||||
 | 
				
			||||
# 使用不同的用户名
 | 
				
			||||
# Using different username
 | 
				
			||||
# username=battlefield_user
 | 
				
			||||
 | 
				
			||||
# 更长的连接超时时间
 | 
				
			||||
# Longer connection timeout
 | 
				
			||||
# connectionTimeout=60000
 | 
				
			||||
@ -0,0 +1,198 @@
 | 
				
			||||
/**
 | 
				
			||||
 * @file DatabaseConfig.cpp
 | 
				
			||||
 * @brief 数据库配置类实现
 | 
				
			||||
 * @author BattlefieldExplorationSystem Team
 | 
				
			||||
 * @date 2024-01-01
 | 
				
			||||
 * @version 2.0
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
#include "core/database/DatabaseConfig.h"
 | 
				
			||||
#include <QDir>
 | 
				
			||||
#include <QStandardPaths>
 | 
				
			||||
#include <QCoreApplication>
 | 
				
			||||
#include <QDebug>
 | 
				
			||||
 | 
				
			||||
// 静态成员初始化
 | 
				
			||||
DatabaseConfig* DatabaseConfig::m_instance = nullptr;
 | 
				
			||||
 | 
				
			||||
DatabaseConfig* DatabaseConfig::getInstance()
 | 
				
			||||
{
 | 
				
			||||
    if (m_instance == nullptr) {
 | 
				
			||||
        m_instance = new DatabaseConfig();
 | 
				
			||||
    }
 | 
				
			||||
    return m_instance;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseConfig::DatabaseConfig()
 | 
				
			||||
    : m_host("localhost")
 | 
				
			||||
    , m_port(3306)
 | 
				
			||||
    , m_databaseName("Client")
 | 
				
			||||
    , m_username("root")
 | 
				
			||||
    , m_password("hzk200407140238")
 | 
				
			||||
    , m_connectTimeout(30)
 | 
				
			||||
    , m_maxConnections(10)
 | 
				
			||||
    , m_settings(nullptr)
 | 
				
			||||
{
 | 
				
			||||
    initDefaultConfig();
 | 
				
			||||
    loadConfig();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseConfig::~DatabaseConfig()
 | 
				
			||||
{
 | 
				
			||||
    if (m_settings) {
 | 
				
			||||
        delete m_settings;
 | 
				
			||||
        m_settings = nullptr;
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseConfig::initDefaultConfig()
 | 
				
			||||
{
 | 
				
			||||
    // 初始化默认数据库配置
 | 
				
			||||
    m_host = "localhost";
 | 
				
			||||
    m_port = 3306;
 | 
				
			||||
    m_databaseName = "Client";
 | 
				
			||||
    m_username = "root";
 | 
				
			||||
    m_password = "hzk200407140238";
 | 
				
			||||
    m_connectTimeout = 30;
 | 
				
			||||
    m_maxConnections = 10;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseConfig::getHost() const
 | 
				
			||||
{
 | 
				
			||||
    return m_host;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
int DatabaseConfig::getPort() const
 | 
				
			||||
{
 | 
				
			||||
    return m_port;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseConfig::getDatabaseName() const
 | 
				
			||||
{
 | 
				
			||||
    return m_databaseName;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseConfig::getUsername() const
 | 
				
			||||
{
 | 
				
			||||
    return m_username;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseConfig::getPassword() const
 | 
				
			||||
{
 | 
				
			||||
    return m_password;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
int DatabaseConfig::getConnectTimeout() const
 | 
				
			||||
{
 | 
				
			||||
    return m_connectTimeout;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
int DatabaseConfig::getMaxConnections() const
 | 
				
			||||
{
 | 
				
			||||
    return m_maxConnections;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseConfig::setDatabaseConfig(const QString& host, int port, const QString& dbName,
 | 
				
			||||
                                     const QString& username, const QString& password)
 | 
				
			||||
{
 | 
				
			||||
    m_host = host;
 | 
				
			||||
    m_port = port;
 | 
				
			||||
    m_databaseName = dbName;
 | 
				
			||||
    m_username = username;
 | 
				
			||||
    m_password = password;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConfig::loadConfig(const QString& configPath)
 | 
				
			||||
{
 | 
				
			||||
    QString configFile = configPath;
 | 
				
			||||
    if (configFile.isEmpty()) {
 | 
				
			||||
        // 使用默认配置文件路径
 | 
				
			||||
        configFile = QCoreApplication::applicationDirPath() + "/config/database.ini";
 | 
				
			||||
        
 | 
				
			||||
        // 如果应用程序目录没有配置文件,尝试用户配置目录
 | 
				
			||||
        if (!QDir(configFile).exists()) {
 | 
				
			||||
            QString userConfigDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
 | 
				
			||||
            configFile = userConfigDir + "/BattlefieldExplorationSystem/database.ini";
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    if (m_settings) {
 | 
				
			||||
        delete m_settings;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    m_settings = new QSettings(configFile, QSettings::IniFormat);
 | 
				
			||||
    
 | 
				
			||||
    if (!QDir(configFile).exists()) {
 | 
				
			||||
        qDebug() << "Database config file not found, using defaults:" << configFile;
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    // 读取数据库配置
 | 
				
			||||
    m_settings->beginGroup("Database");
 | 
				
			||||
    m_host = m_settings->value("host", m_host).toString();
 | 
				
			||||
    m_port = m_settings->value("port", m_port).toInt();
 | 
				
			||||
    m_databaseName = m_settings->value("databaseName", m_databaseName).toString();
 | 
				
			||||
    m_username = m_settings->value("username", m_username).toString();
 | 
				
			||||
    m_password = m_settings->value("password", m_password).toString();
 | 
				
			||||
    m_settings->endGroup();
 | 
				
			||||
 | 
				
			||||
    // 读取连接池配置
 | 
				
			||||
    m_settings->beginGroup("ConnectionPool");
 | 
				
			||||
    m_connectTimeout = m_settings->value("connectTimeout", m_connectTimeout).toInt();
 | 
				
			||||
    m_maxConnections = m_settings->value("maxConnections", m_maxConnections).toInt();
 | 
				
			||||
    m_settings->endGroup();
 | 
				
			||||
 | 
				
			||||
    qDebug() << "Database config loaded from:" << configFile;
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConfig::saveConfig(const QString& configPath)
 | 
				
			||||
{
 | 
				
			||||
    QString configFile = configPath;
 | 
				
			||||
    if (configFile.isEmpty()) {
 | 
				
			||||
        configFile = QCoreApplication::applicationDirPath() + "/config/database.ini";
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    // 确保配置目录存在
 | 
				
			||||
    QDir configDir = QFileInfo(configFile).absoluteDir();
 | 
				
			||||
    if (!configDir.exists()) {
 | 
				
			||||
        configDir.mkpath(".");
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    if (m_settings) {
 | 
				
			||||
        delete m_settings;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    m_settings = new QSettings(configFile, QSettings::IniFormat);
 | 
				
			||||
 | 
				
			||||
    // 保存数据库配置
 | 
				
			||||
    m_settings->beginGroup("Database");
 | 
				
			||||
    m_settings->setValue("host", m_host);
 | 
				
			||||
    m_settings->setValue("port", m_port);
 | 
				
			||||
    m_settings->setValue("databaseName", m_databaseName);
 | 
				
			||||
    m_settings->setValue("username", m_username);
 | 
				
			||||
    m_settings->setValue("password", m_password);
 | 
				
			||||
    m_settings->endGroup();
 | 
				
			||||
 | 
				
			||||
    // 保存连接池配置
 | 
				
			||||
    m_settings->beginGroup("ConnectionPool");
 | 
				
			||||
    m_settings->setValue("connectTimeout", m_connectTimeout);
 | 
				
			||||
    m_settings->setValue("maxConnections", m_maxConnections);
 | 
				
			||||
    m_settings->endGroup();
 | 
				
			||||
 | 
				
			||||
    m_settings->sync();
 | 
				
			||||
    
 | 
				
			||||
    qDebug() << "Database config saved to:" << configFile;
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseConnectionInfo DatabaseConfig::getConnectionInfo() const
 | 
				
			||||
{
 | 
				
			||||
    DatabaseConnectionInfo info;
 | 
				
			||||
    info.hostName = m_host;
 | 
				
			||||
    info.port = m_port;
 | 
				
			||||
    info.databaseName = m_databaseName;
 | 
				
			||||
    info.username = m_username;
 | 
				
			||||
    info.password = m_password;
 | 
				
			||||
    return info;
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,348 @@
 | 
				
			||||
/**
 | 
				
			||||
 * @file DatabaseHelper.cpp
 | 
				
			||||
 * @brief 数据库助手类实现
 | 
				
			||||
 * @author BattlefieldExplorationSystem Team
 | 
				
			||||
 * @date 2024-01-01
 | 
				
			||||
 * @version 2.0
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
#include "core/database/DatabaseHelper.h"
 | 
				
			||||
#include "core/database/DatabaseConfig.h"
 | 
				
			||||
#include <QSqlDriver>
 | 
				
			||||
#include <QThread>
 | 
				
			||||
#include <QDateTime>
 | 
				
			||||
#include <QDebug>
 | 
				
			||||
#include <QUuid>
 | 
				
			||||
 | 
				
			||||
// 静态成员初始化
 | 
				
			||||
DatabaseHelper* DatabaseHelper::m_instance = nullptr;
 | 
				
			||||
QMutex DatabaseHelper::m_mutex;
 | 
				
			||||
QMap<QString, QSqlDatabase> DatabaseHelper::m_connections;
 | 
				
			||||
int DatabaseHelper::m_connectionCounter = 0;
 | 
				
			||||
 | 
				
			||||
DatabaseHelper* DatabaseHelper::getInstance()
 | 
				
			||||
{
 | 
				
			||||
    QMutexLocker locker(&m_mutex);
 | 
				
			||||
    if (m_instance == nullptr) {
 | 
				
			||||
        m_instance = new DatabaseHelper();
 | 
				
			||||
    }
 | 
				
			||||
    return m_instance;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseHelper::DatabaseHelper()
 | 
				
			||||
{
 | 
				
			||||
    // 初始化数据库助手
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseHelper::~DatabaseHelper()
 | 
				
			||||
{
 | 
				
			||||
    closeAllConnections();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseHelper::generateConnectionName()
 | 
				
			||||
{
 | 
				
			||||
    QMutexLocker locker(&m_mutex);
 | 
				
			||||
    return QString("Connection_%1_%2").arg(++m_connectionCounter).arg(reinterpret_cast<quintptr>(QThread::currentThreadId()));
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QSqlDatabase DatabaseHelper::createConnection(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    QString connName = connectionName;
 | 
				
			||||
    if (connName.isEmpty()) {
 | 
				
			||||
        connName = generateConnectionName();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    QMutexLocker locker(&m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    // 如果连接已存在且有效,直接返回
 | 
				
			||||
    if (m_connections.contains(connName)) {
 | 
				
			||||
        QSqlDatabase existingDb = m_connections[connName];
 | 
				
			||||
        if (existingDb.isValid() && existingDb.isOpen()) {
 | 
				
			||||
            return existingDb;
 | 
				
			||||
        } else {
 | 
				
			||||
            // 移除无效连接
 | 
				
			||||
            m_connections.remove(connName);
 | 
				
			||||
            QSqlDatabase::removeDatabase(connName);
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    // 创建新连接
 | 
				
			||||
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", connName);
 | 
				
			||||
    
 | 
				
			||||
    if (!configureConnection(db)) {
 | 
				
			||||
        qWarning() << "Failed to configure database connection:" << connName;
 | 
				
			||||
        QSqlDatabase::removeDatabase(connName);
 | 
				
			||||
        return QSqlDatabase();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    if (!db.open()) {
 | 
				
			||||
        qWarning() << "Failed to open database connection:" << connName << db.lastError().text();
 | 
				
			||||
        QSqlDatabase::removeDatabase(connName);
 | 
				
			||||
        return QSqlDatabase();
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    m_connections[connName] = db;
 | 
				
			||||
    qDebug() << "Database connection created:" << connName;
 | 
				
			||||
    return db;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QSqlDatabase DatabaseHelper::createTempConnection(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    QString tempConnName = connectionName + "_" + QUuid::createUuid().toString(QUuid::WithoutBraces);
 | 
				
			||||
    return createConnection(tempConnName);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::configureConnection(QSqlDatabase& db)
 | 
				
			||||
{
 | 
				
			||||
    DatabaseConfig* config = DatabaseConfig::getInstance();
 | 
				
			||||
    
 | 
				
			||||
    db.setHostName(config->getHost());
 | 
				
			||||
    db.setPort(config->getPort());
 | 
				
			||||
    db.setDatabaseName(config->getDatabaseName());
 | 
				
			||||
    db.setUserName(config->getUsername());
 | 
				
			||||
    db.setPassword(config->getPassword());
 | 
				
			||||
    
 | 
				
			||||
    // 设置连接选项
 | 
				
			||||
    db.setConnectOptions("MYSQL_OPT_CONNECT_TIMEOUT=" + QString::number(config->getConnectTimeout()) +
 | 
				
			||||
                        ";MYSQL_OPT_RECONNECT=1");
 | 
				
			||||
    
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseHelper::closeConnection(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    QMutexLocker locker(&m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    if (m_connections.contains(connectionName)) {
 | 
				
			||||
        QSqlDatabase db = m_connections[connectionName];
 | 
				
			||||
        if (db.isOpen()) {
 | 
				
			||||
            db.close();
 | 
				
			||||
        }
 | 
				
			||||
        m_connections.remove(connectionName);
 | 
				
			||||
        QSqlDatabase::removeDatabase(connectionName);
 | 
				
			||||
        qDebug() << "Database connection closed:" << connectionName;
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseHelper::closeAllConnections()
 | 
				
			||||
{
 | 
				
			||||
    QMutexLocker locker(&m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    QStringList connectionNames = m_connections.keys();
 | 
				
			||||
    for (const QString& name : connectionNames) {
 | 
				
			||||
        QSqlDatabase db = m_connections[name];
 | 
				
			||||
        if (db.isOpen()) {
 | 
				
			||||
            db.close();
 | 
				
			||||
        }
 | 
				
			||||
        QSqlDatabase::removeDatabase(name);
 | 
				
			||||
    }
 | 
				
			||||
    m_connections.clear();
 | 
				
			||||
    qDebug() << "All database connections closed";
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::isConnectionValid(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    QMutexLocker locker(&m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    if (!m_connections.contains(connectionName)) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlDatabase db = m_connections[connectionName];
 | 
				
			||||
    return db.isValid() && db.isOpen();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QSqlQuery DatabaseHelper::executeQuery(const QString& query, const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    QString connName = connectionName;
 | 
				
			||||
    if (connName.isEmpty()) {
 | 
				
			||||
        connName = generateConnectionName();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlDatabase db = createConnection(connName);
 | 
				
			||||
    if (!db.isValid()) {
 | 
				
			||||
        qWarning() << "Invalid database connection for query execution";
 | 
				
			||||
        return QSqlQuery();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlQuery sqlQuery(db);
 | 
				
			||||
    if (!sqlQuery.exec(query)) {
 | 
				
			||||
        qWarning() << "Query execution failed:" << query << sqlQuery.lastError().text();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return sqlQuery;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::beginTransaction(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    if (!isConnectionValid(connectionName)) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlDatabase db = m_connections[connectionName];
 | 
				
			||||
    return db.transaction();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::commitTransaction(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    if (!isConnectionValid(connectionName)) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlDatabase db = m_connections[connectionName];
 | 
				
			||||
    return db.commit();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::rollbackTransaction(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    if (!isConnectionValid(connectionName)) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlDatabase db = m_connections[connectionName];
 | 
				
			||||
    return db.rollback();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseHelper::getLastError(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    if (!isConnectionValid(connectionName)) {
 | 
				
			||||
        return "Invalid connection";
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    QSqlDatabase db = m_connections[connectionName];
 | 
				
			||||
    return db.lastError().text();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::testConnection()
 | 
				
			||||
{
 | 
				
			||||
    QSqlDatabase testDb = createConnection("TestConnection");
 | 
				
			||||
    bool success = testDb.isValid() && testDb.isOpen();
 | 
				
			||||
    closeConnection("TestConnection");
 | 
				
			||||
    return success;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::initializeDatabase()
 | 
				
			||||
{
 | 
				
			||||
    qDebug() << "Initializing database...";
 | 
				
			||||
    
 | 
				
			||||
    if (!testConnection()) {
 | 
				
			||||
        qWarning() << "Database connection test failed";
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return createTables();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::createTables()
 | 
				
			||||
{
 | 
				
			||||
    QSqlDatabase db = createConnection("InitConnection");
 | 
				
			||||
    if (!db.isValid()) {
 | 
				
			||||
        qWarning() << "Failed to create database connection for table creation";
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    bool success = true;
 | 
				
			||||
    success &= createDevicesTable(db);
 | 
				
			||||
    success &= createOperationLogsTable(db);
 | 
				
			||||
    success &= createSystemConfigTable(db);
 | 
				
			||||
    
 | 
				
			||||
    closeConnection("InitConnection");
 | 
				
			||||
    
 | 
				
			||||
    if (success) {
 | 
				
			||||
        qDebug() << "Database tables created successfully";
 | 
				
			||||
    } else {
 | 
				
			||||
        qWarning() << "Failed to create some database tables";
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return success;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::createDevicesTable(QSqlDatabase& db)
 | 
				
			||||
{
 | 
				
			||||
    QSqlQuery query(db);
 | 
				
			||||
    QString sql = R"(
 | 
				
			||||
        CREATE TABLE IF NOT EXISTS devices (
 | 
				
			||||
            id VARCHAR(50) PRIMARY KEY,
 | 
				
			||||
            name VARCHAR(100) NOT NULL,
 | 
				
			||||
            device_type ENUM('uav', 'dog') NOT NULL,
 | 
				
			||||
            ip VARCHAR(15) NOT NULL,
 | 
				
			||||
            port INT NOT NULL,
 | 
				
			||||
            state INT NOT NULL DEFAULT 0,
 | 
				
			||||
            longitude DOUBLE DEFAULT 0.0,
 | 
				
			||||
            latitude DOUBLE DEFAULT 0.0,
 | 
				
			||||
            signal_strength INT DEFAULT 0,
 | 
				
			||||
            battery_level INT DEFAULT 100,
 | 
				
			||||
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 | 
				
			||||
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 | 
				
			||||
            INDEX idx_device_type (device_type),
 | 
				
			||||
            INDEX idx_state (state)
 | 
				
			||||
        )
 | 
				
			||||
    )";
 | 
				
			||||
    
 | 
				
			||||
    if (!query.exec(sql)) {
 | 
				
			||||
        qWarning() << "Failed to create devices table:" << query.lastError().text();
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::createOperationLogsTable(QSqlDatabase& db)
 | 
				
			||||
{
 | 
				
			||||
    QSqlQuery query(db);
 | 
				
			||||
    QString sql = R"(
 | 
				
			||||
        CREATE TABLE IF NOT EXISTS device_operation_logs (
 | 
				
			||||
            id INT AUTO_INCREMENT PRIMARY KEY,
 | 
				
			||||
            device_id VARCHAR(50) NOT NULL,
 | 
				
			||||
            device_type ENUM('uav', 'dog') NOT NULL,
 | 
				
			||||
            operation VARCHAR(100) NOT NULL,
 | 
				
			||||
            operation_result VARCHAR(20) NOT NULL,
 | 
				
			||||
            operator VARCHAR(50) NOT NULL,
 | 
				
			||||
            operation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 | 
				
			||||
            INDEX idx_device_id (device_id),
 | 
				
			||||
            INDEX idx_operation_time (operation_time)
 | 
				
			||||
        )
 | 
				
			||||
    )";
 | 
				
			||||
    
 | 
				
			||||
    if (!query.exec(sql)) {
 | 
				
			||||
        qWarning() << "Failed to create operation logs table:" << query.lastError().text();
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseHelper::createSystemConfigTable(QSqlDatabase& db)
 | 
				
			||||
{
 | 
				
			||||
    QSqlQuery query(db);
 | 
				
			||||
    QString sql = R"(
 | 
				
			||||
        CREATE TABLE IF NOT EXISTS system_config (
 | 
				
			||||
            config_key VARCHAR(100) PRIMARY KEY,
 | 
				
			||||
            config_value TEXT,
 | 
				
			||||
            description VARCHAR(255),
 | 
				
			||||
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 | 
				
			||||
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
 | 
				
			||||
        )
 | 
				
			||||
    )";
 | 
				
			||||
    
 | 
				
			||||
    if (!query.exec(sql)) {
 | 
				
			||||
        qWarning() << "Failed to create system config table:" << query.lastError().text();
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 插入默认配置
 | 
				
			||||
    QString insertDefaults = R"(
 | 
				
			||||
        INSERT IGNORE INTO system_config (config_key, config_value, description) VALUES
 | 
				
			||||
        ('map.default_center_lon', '116.4', '默认地图中心经度'),
 | 
				
			||||
        ('map.default_center_lat', '39.9', '默认地图中心纬度'),
 | 
				
			||||
        ('system.version', '2.0.0', '系统版本'),
 | 
				
			||||
        ('system.name', 'BattlefieldExplorationSystem', '系统名称')
 | 
				
			||||
    )";
 | 
				
			||||
    
 | 
				
			||||
    if (!query.exec(insertDefaults)) {
 | 
				
			||||
        qWarning() << "Failed to insert default config:" << query.lastError().text();
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,475 @@
 | 
				
			||||
/**
 | 
				
			||||
 * @file DatabaseManager.cpp
 | 
				
			||||
 * @brief 数据库连接管理器实现
 | 
				
			||||
 * @author BattlefieldExplorationSystem Team
 | 
				
			||||
 * @date 2025-06-30
 | 
				
			||||
 * @version 2.0
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
#include "core/database/DatabaseManager.h"
 | 
				
			||||
#include "utils/ConfigManager.h"
 | 
				
			||||
 | 
				
			||||
// C++标准库头文件
 | 
				
			||||
#include <chrono>
 | 
				
			||||
#include <stdexcept>
 | 
				
			||||
 | 
				
			||||
// Qt头文件
 | 
				
			||||
#include <QCoreApplication>
 | 
				
			||||
#include <QDebug>
 | 
				
			||||
#include <QSqlDatabase>
 | 
				
			||||
#include <QSqlQuery>
 | 
				
			||||
#include <QThread>
 | 
				
			||||
#include <QUuid>
 | 
				
			||||
 | 
				
			||||
// DatabaseConnection 实现
 | 
				
			||||
 | 
				
			||||
DatabaseConnection::DatabaseConnection(const QString& connectionName, bool autoReconnect)
 | 
				
			||||
    : m_connectionName(connectionName)
 | 
				
			||||
    , m_autoReconnect(autoReconnect)
 | 
				
			||||
    , m_isValid(false)
 | 
				
			||||
{
 | 
				
			||||
    if (QSqlDatabase::contains(m_connectionName)) {
 | 
				
			||||
        m_database = QSqlDatabase::database(m_connectionName);
 | 
				
			||||
    } else {
 | 
				
			||||
        // 创建新连接
 | 
				
			||||
        ConfigManager& config = ConfigManager::getInstance();
 | 
				
			||||
        
 | 
				
			||||
        m_database = QSqlDatabase::addDatabase("QMYSQL", m_connectionName);
 | 
				
			||||
        m_database.setHostName(config.getDatabaseHost());
 | 
				
			||||
        m_database.setPort(config.getDatabasePort());
 | 
				
			||||
        m_database.setDatabaseName(config.getDatabaseName());
 | 
				
			||||
        m_database.setUserName(config.getDatabaseUser());
 | 
				
			||||
        
 | 
				
			||||
        QString password = config.getDatabasePassword();
 | 
				
			||||
        if (password.isEmpty()) {
 | 
				
			||||
            qCritical() << "Database password not configured! Set BES_DB_PASSWORD environment variable.";
 | 
				
			||||
            return;
 | 
				
			||||
        }
 | 
				
			||||
        m_database.setPassword(password);
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 尝试打开连接
 | 
				
			||||
    m_isValid = m_database.open();
 | 
				
			||||
    if (!m_isValid) {
 | 
				
			||||
        qWarning() << "Failed to open database connection:" << m_database.lastError().text();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseConnection::~DatabaseConnection()
 | 
				
			||||
{
 | 
				
			||||
    if (m_database.isOpen()) {
 | 
				
			||||
        m_database.close();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    if (!m_connectionName.isEmpty() && QSqlDatabase::contains(m_connectionName)) {
 | 
				
			||||
        QSqlDatabase::removeDatabase(m_connectionName);
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseConnection::DatabaseConnection(DatabaseConnection&& other) noexcept
 | 
				
			||||
    : m_connectionName(std::move(other.m_connectionName))
 | 
				
			||||
    , m_database(std::move(other.m_database))
 | 
				
			||||
    , m_autoReconnect(other.m_autoReconnect)
 | 
				
			||||
    , m_isValid(other.m_isValid)
 | 
				
			||||
{
 | 
				
			||||
    other.m_isValid = false;
 | 
				
			||||
    other.m_connectionName.clear();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseConnection& DatabaseConnection::operator=(DatabaseConnection&& other) noexcept
 | 
				
			||||
{
 | 
				
			||||
    if (this != &other) {
 | 
				
			||||
        // 清理当前资源
 | 
				
			||||
        if (m_database.isOpen()) {
 | 
				
			||||
            m_database.close();
 | 
				
			||||
        }
 | 
				
			||||
        if (!m_connectionName.isEmpty() && QSqlDatabase::contains(m_connectionName)) {
 | 
				
			||||
            QSqlDatabase::removeDatabase(m_connectionName);
 | 
				
			||||
        }
 | 
				
			||||
        
 | 
				
			||||
        // 移动资源
 | 
				
			||||
        m_connectionName = std::move(other.m_connectionName);
 | 
				
			||||
        m_database = std::move(other.m_database);
 | 
				
			||||
        m_autoReconnect = other.m_autoReconnect;
 | 
				
			||||
        m_isValid = other.m_isValid;
 | 
				
			||||
        
 | 
				
			||||
        other.m_isValid = false;
 | 
				
			||||
        other.m_connectionName.clear();
 | 
				
			||||
    }
 | 
				
			||||
    return *this;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConnection::isValid() const
 | 
				
			||||
{
 | 
				
			||||
    return m_isValid && m_database.isOpen();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QSqlDatabase& DatabaseConnection::database()
 | 
				
			||||
{
 | 
				
			||||
    if (!isValid()) {
 | 
				
			||||
        if (m_autoReconnect && !reconnect()) {
 | 
				
			||||
            throw std::runtime_error("Database connection is not available and reconnection failed");
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
    return m_database;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
const QSqlDatabase& DatabaseConnection::database() const
 | 
				
			||||
{
 | 
				
			||||
    if (!isValid()) {
 | 
				
			||||
        throw std::runtime_error("Database connection is not available");
 | 
				
			||||
    }
 | 
				
			||||
    return m_database;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
std::unique_ptr<QSqlQuery> DatabaseConnection::executeQuery(const QString& sql)
 | 
				
			||||
{
 | 
				
			||||
    auto query = std::make_unique<QSqlQuery>(database());
 | 
				
			||||
    
 | 
				
			||||
    if (!query->exec(sql)) {
 | 
				
			||||
        qWarning() << "Query execution failed:" << query->lastError().text();
 | 
				
			||||
        qWarning() << "SQL:" << sql;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return query;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
std::unique_ptr<QSqlQuery> DatabaseConnection::executePreparedQuery(const QString& sql, 
 | 
				
			||||
                                                                   const QVariantList& bindings)
 | 
				
			||||
{
 | 
				
			||||
    auto query = std::make_unique<QSqlQuery>(database());
 | 
				
			||||
    
 | 
				
			||||
    if (!query->prepare(sql)) {
 | 
				
			||||
        qWarning() << "Query preparation failed:" << query->lastError().text();
 | 
				
			||||
        qWarning() << "SQL:" << sql;
 | 
				
			||||
        return query;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 绑定参数
 | 
				
			||||
    for (const auto& binding : bindings) {
 | 
				
			||||
        query->addBindValue(binding);
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    if (!query->exec()) {
 | 
				
			||||
        qWarning() << "Prepared query execution failed:" << query->lastError().text();
 | 
				
			||||
        qWarning() << "SQL:" << sql;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return query;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConnection::beginTransaction()
 | 
				
			||||
{
 | 
				
			||||
    if (!isValid()) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    return m_database.transaction();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConnection::commitTransaction()
 | 
				
			||||
{
 | 
				
			||||
    if (!isValid()) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    return m_database.commit();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConnection::rollbackTransaction()
 | 
				
			||||
{
 | 
				
			||||
    if (!isValid()) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    return m_database.rollback();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QSqlError DatabaseConnection::lastError() const
 | 
				
			||||
{
 | 
				
			||||
    return m_database.lastError();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseConnection::reconnect()
 | 
				
			||||
{
 | 
				
			||||
    if (m_database.isOpen()) {
 | 
				
			||||
        m_database.close();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    m_isValid = m_database.open();
 | 
				
			||||
    if (!m_isValid) {
 | 
				
			||||
        qWarning() << "Reconnection failed:" << m_database.lastError().text();
 | 
				
			||||
    } else {
 | 
				
			||||
        qDebug() << "Database reconnection successful for:" << m_connectionName;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return m_isValid;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
// DatabaseManager 实现
 | 
				
			||||
 | 
				
			||||
std::unique_ptr<DatabaseManager> DatabaseManager::m_instance = nullptr;
 | 
				
			||||
std::mutex DatabaseManager::m_instanceMutex;
 | 
				
			||||
 | 
				
			||||
DatabaseManager& DatabaseManager::getInstance()
 | 
				
			||||
{
 | 
				
			||||
    std::lock_guard<std::mutex> lock(m_instanceMutex);
 | 
				
			||||
    if (!m_instance) {
 | 
				
			||||
        m_instance.reset(new DatabaseManager());
 | 
				
			||||
    }
 | 
				
			||||
    return *m_instance;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseManager::DatabaseManager(QObject* parent)
 | 
				
			||||
    : QObject(parent)
 | 
				
			||||
    , m_maxConnections(10)
 | 
				
			||||
    , m_connectionCounter(0)
 | 
				
			||||
    , m_initialized(false)
 | 
				
			||||
    , m_databaseAvailable(false)
 | 
				
			||||
    , m_configManager(&ConfigManager::getInstance())
 | 
				
			||||
    , m_totalConnectionsCreated(0)
 | 
				
			||||
    , m_totalQueriesExecuted(0)
 | 
				
			||||
    , m_failedConnections(0)
 | 
				
			||||
{
 | 
				
			||||
    // 私有构造函数
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseManager::~DatabaseManager()
 | 
				
			||||
{
 | 
				
			||||
    closeAllConnections();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseManager::initialize(int maxConnections)
 | 
				
			||||
{
 | 
				
			||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    if (m_initialized) {
 | 
				
			||||
        qWarning() << "DatabaseManager already initialized";
 | 
				
			||||
        return true;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    m_maxConnections = maxConnections;
 | 
				
			||||
    
 | 
				
			||||
    // 确保配置管理器已初始化
 | 
				
			||||
    if (!m_configManager->contains("database/host")) {
 | 
				
			||||
        if (!m_configManager->initialize()) {
 | 
				
			||||
            qCritical() << "Failed to initialize ConfigManager";
 | 
				
			||||
            return false;
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 测试初始连接
 | 
				
			||||
    auto testConnection = getConnection("test_connection");
 | 
				
			||||
    if (testConnection && testConnection->isValid()) {
 | 
				
			||||
        m_databaseAvailable = true;
 | 
				
			||||
        qDebug() << "Database is available";
 | 
				
			||||
    } else {
 | 
				
			||||
        m_databaseAvailable = false;
 | 
				
			||||
        qWarning() << "Database is not available";
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 启动健康检查
 | 
				
			||||
    startHealthCheckTimer();
 | 
				
			||||
    
 | 
				
			||||
    m_initialized = true;
 | 
				
			||||
    
 | 
				
			||||
    emit databaseAvailabilityChanged(m_databaseAvailable);
 | 
				
			||||
    
 | 
				
			||||
    qDebug() << "DatabaseManager initialized with max connections:" << m_maxConnections;
 | 
				
			||||
    return true;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
std::unique_ptr<DatabaseConnection> DatabaseManager::getConnection(const QString& connectionName)
 | 
				
			||||
{
 | 
				
			||||
    std::unique_ptr<DatabaseConnection> connection;
 | 
				
			||||
    
 | 
				
			||||
    {
 | 
				
			||||
        std::lock_guard<std::mutex> lock(m_mutex);
 | 
				
			||||
        
 | 
				
			||||
        QString actualConnectionName = connectionName.isEmpty() ? 
 | 
				
			||||
                                     generateConnectionName() : connectionName;
 | 
				
			||||
        
 | 
				
			||||
        // 检查是否超过最大连接数
 | 
				
			||||
        if (m_activeConnections.size() >= static_cast<size_t>(m_maxConnections)) {
 | 
				
			||||
            qWarning() << "Maximum connections reached:" << m_maxConnections;
 | 
				
			||||
            return nullptr;
 | 
				
			||||
        }
 | 
				
			||||
        
 | 
				
			||||
        connection = std::make_unique<DatabaseConnection>(actualConnectionName);
 | 
				
			||||
        
 | 
				
			||||
        if (connection->isValid()) {
 | 
				
			||||
            m_activeConnections.push_back(actualConnectionName);
 | 
				
			||||
            ++m_totalConnectionsCreated;
 | 
				
			||||
        } else {
 | 
				
			||||
            ++m_failedConnections;
 | 
				
			||||
            return nullptr;
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 发送状态更新信号
 | 
				
			||||
    emit poolStatusChanged(static_cast<int>(m_activeConnections.size()), m_maxConnections);
 | 
				
			||||
    
 | 
				
			||||
    return connection;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseManager::testConnection()
 | 
				
			||||
{
 | 
				
			||||
    auto connection = getConnection("health_check");
 | 
				
			||||
    if (!connection || !connection->isValid()) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    auto query = connection->executeQuery("SELECT 1");
 | 
				
			||||
    return query && query->next();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseManager::getPoolStatistics() const
 | 
				
			||||
{
 | 
				
			||||
    std::lock_guard<std::mutex> lock(m_statsMutex);
 | 
				
			||||
    
 | 
				
			||||
    return QString("DatabaseManager Statistics:\n"
 | 
				
			||||
                  "- Active connections: %1/%2\n"
 | 
				
			||||
                  "- Total connections created: %3\n"
 | 
				
			||||
                  "- Total queries executed: %4\n"
 | 
				
			||||
                  "- Failed connections: %5\n"
 | 
				
			||||
                  "- Database available: %6")
 | 
				
			||||
           .arg(m_activeConnections.size())
 | 
				
			||||
           .arg(m_maxConnections)
 | 
				
			||||
           .arg(m_totalConnectionsCreated)
 | 
				
			||||
           .arg(m_totalQueriesExecuted)
 | 
				
			||||
           .arg(m_failedConnections)
 | 
				
			||||
           .arg(m_databaseAvailable ? "Yes" : "No");
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseManager::closeAllConnections()
 | 
				
			||||
{
 | 
				
			||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    // 移除所有活跃连接
 | 
				
			||||
    for (const auto& connectionName : m_activeConnections) {
 | 
				
			||||
        if (QSqlDatabase::contains(connectionName)) {
 | 
				
			||||
            QSqlDatabase::removeDatabase(connectionName);
 | 
				
			||||
        }
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    m_activeConnections.clear();
 | 
				
			||||
    m_availableConnections.clear();
 | 
				
			||||
    
 | 
				
			||||
    qDebug() << "All database connections closed";
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseManager::isDatabaseAvailable() const
 | 
				
			||||
{
 | 
				
			||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
				
			||||
    return m_databaseAvailable;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseManager::performHealthCheck()
 | 
				
			||||
{
 | 
				
			||||
    bool wasAvailable = m_databaseAvailable;
 | 
				
			||||
    m_databaseAvailable = testConnection();
 | 
				
			||||
    
 | 
				
			||||
    if (wasAvailable != m_databaseAvailable) {
 | 
				
			||||
        emit databaseAvailabilityChanged(m_databaseAvailable);
 | 
				
			||||
        qDebug() << "Database availability changed to:" << m_databaseAvailable;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    // 清理失效的连接
 | 
				
			||||
    cleanupIdleConnections();
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseManager::cleanupIdleConnections()
 | 
				
			||||
{
 | 
				
			||||
    std::lock_guard<std::mutex> lock(m_mutex);
 | 
				
			||||
    
 | 
				
			||||
    // 移除无效的连接名称
 | 
				
			||||
    auto it = std::remove_if(m_activeConnections.begin(), m_activeConnections.end(),
 | 
				
			||||
                            [](const QString& connectionName) {
 | 
				
			||||
                                if (!QSqlDatabase::contains(connectionName)) {
 | 
				
			||||
                                    return true;
 | 
				
			||||
                                }
 | 
				
			||||
                                QSqlDatabase db = QSqlDatabase::database(connectionName);
 | 
				
			||||
                                return !db.isOpen();
 | 
				
			||||
                            });
 | 
				
			||||
    
 | 
				
			||||
    if (it != m_activeConnections.end()) {
 | 
				
			||||
        int cleaned = static_cast<int>(std::distance(it, m_activeConnections.end()));
 | 
				
			||||
        m_activeConnections.erase(it, m_activeConnections.end());
 | 
				
			||||
        qDebug() << "Cleaned up" << cleaned << "idle connections";
 | 
				
			||||
        
 | 
				
			||||
        emit poolStatusChanged(static_cast<int>(m_activeConnections.size()), m_maxConnections);
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
QString DatabaseManager::generateConnectionName()
 | 
				
			||||
{
 | 
				
			||||
    return QString("connection_%1_%2")
 | 
				
			||||
           .arg(reinterpret_cast<qintptr>(QThread::currentThreadId()))
 | 
				
			||||
           .arg(++m_connectionCounter);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DatabaseManager::startHealthCheckTimer()
 | 
				
			||||
{
 | 
				
			||||
    m_healthCheckTimer = std::make_unique<QTimer>(this);
 | 
				
			||||
    connect(m_healthCheckTimer.get(), &QTimer::timeout,
 | 
				
			||||
            this, &DatabaseManager::performHealthCheck);
 | 
				
			||||
    
 | 
				
			||||
    // 每30秒检查一次
 | 
				
			||||
    m_healthCheckTimer->start(30000);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
// DatabaseTransaction 实现
 | 
				
			||||
 | 
				
			||||
DatabaseTransaction::DatabaseTransaction(DatabaseConnection& connection)
 | 
				
			||||
    : m_connection(connection)
 | 
				
			||||
    , m_committed(false)
 | 
				
			||||
    , m_active(false)
 | 
				
			||||
{
 | 
				
			||||
    m_active = m_connection.beginTransaction();
 | 
				
			||||
    if (!m_active) {
 | 
				
			||||
        qWarning() << "Failed to begin transaction:" << m_connection.lastError().text();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DatabaseTransaction::~DatabaseTransaction()
 | 
				
			||||
{
 | 
				
			||||
    if (m_active && !m_committed) {
 | 
				
			||||
        // 自动回滚未提交的事务
 | 
				
			||||
        rollback();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseTransaction::commit()
 | 
				
			||||
{
 | 
				
			||||
    if (!m_active || m_committed) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    bool success = m_connection.commitTransaction();
 | 
				
			||||
    if (success) {
 | 
				
			||||
        m_committed = true;
 | 
				
			||||
        m_active = false;
 | 
				
			||||
    } else {
 | 
				
			||||
        qWarning() << "Failed to commit transaction:" << m_connection.lastError().text();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return success;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseTransaction::rollback()
 | 
				
			||||
{
 | 
				
			||||
    if (!m_active) {
 | 
				
			||||
        return false;
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    bool success = m_connection.rollbackTransaction();
 | 
				
			||||
    m_active = false;
 | 
				
			||||
    
 | 
				
			||||
    if (!success) {
 | 
				
			||||
        qWarning() << "Failed to rollback transaction:" << m_connection.lastError().text();
 | 
				
			||||
    }
 | 
				
			||||
    
 | 
				
			||||
    return success;
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
bool DatabaseTransaction::isActive() const
 | 
				
			||||
{
 | 
				
			||||
    return m_active;
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,545 @@
 | 
				
			||||
/**
 | 
				
			||||
 * @file DroneControlDialog.cpp
 | 
				
			||||
 * @brief 无人机控制对话框实现
 | 
				
			||||
 * @author Qt UI Optimizer
 | 
				
			||||
 * @date 2024-07-04
 | 
				
			||||
 * @version 1.0
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
#include "ui/dialogs/DroneControlDialog.h"
 | 
				
			||||
#include "styles/ModernStyleManager.h"
 | 
				
			||||
 | 
				
			||||
#include <QApplication>
 | 
				
			||||
#include <QDesktopWidget>
 | 
				
			||||
#include <QMessageBox>
 | 
				
			||||
#include <QDateTime>
 | 
				
			||||
 | 
				
			||||
DroneControlDialog::DroneControlDialog(QWidget *parent)
 | 
				
			||||
    : QDialog(parent)
 | 
				
			||||
    , m_mainLayout(nullptr)
 | 
				
			||||
    , m_contentLayout(nullptr)
 | 
				
			||||
    , m_isMappingActive(false)
 | 
				
			||||
    , m_isNavigationActive(false)
 | 
				
			||||
    , m_isPhotoTransmissionActive(false)
 | 
				
			||||
    , m_isPersonRecognitionActive(false)
 | 
				
			||||
    , m_isFlying(false)
 | 
				
			||||
    , m_statusUpdateTimer(new QTimer(this))
 | 
				
			||||
{
 | 
				
			||||
    setupUI();
 | 
				
			||||
    applyStyles();
 | 
				
			||||
    connectSignals();
 | 
				
			||||
    
 | 
				
			||||
    // 启动状态更新定时器
 | 
				
			||||
    m_statusUpdateTimer->start(1000);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
DroneControlDialog::~DroneControlDialog()
 | 
				
			||||
{
 | 
				
			||||
    if (m_statusUpdateTimer) {
 | 
				
			||||
        m_statusUpdateTimer->stop();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::setupUI()
 | 
				
			||||
{
 | 
				
			||||
    setWindowTitle("🚁 无人机控制中心");
 | 
				
			||||
    setModal(false);
 | 
				
			||||
    setMinimumSize(900, 700);
 | 
				
			||||
    resize(1000, 750);
 | 
				
			||||
    
 | 
				
			||||
    // 窗口居中显示
 | 
				
			||||
    QRect screenGeometry = QApplication::desktop()->screenGeometry();
 | 
				
			||||
    int x = (screenGeometry.width() - this->width()) / 2;
 | 
				
			||||
    int y = (screenGeometry.height() - this->height()) / 2;
 | 
				
			||||
    move(x, y);
 | 
				
			||||
    
 | 
				
			||||
    m_mainLayout = new QVBoxLayout(this);
 | 
				
			||||
    m_mainLayout->setSpacing(20);
 | 
				
			||||
    m_mainLayout->setContentsMargins(20, 20, 20, 20);
 | 
				
			||||
    
 | 
				
			||||
    // 标题
 | 
				
			||||
    QLabel *titleLabel = new QLabel("🚁 无人机控制中心");
 | 
				
			||||
    titleLabel->setObjectName("DialogTitle");
 | 
				
			||||
    titleLabel->setAlignment(Qt::AlignCenter);
 | 
				
			||||
    titleLabel->setStyleSheet(
 | 
				
			||||
        "font-size: 24px; "
 | 
				
			||||
        "font-weight: bold; "
 | 
				
			||||
        "color: #0078d4; "
 | 
				
			||||
        "padding: 10px; "
 | 
				
			||||
        "border-bottom: 2px solid #0078d4; "
 | 
				
			||||
        "margin-bottom: 10px;"
 | 
				
			||||
    );
 | 
				
			||||
    m_mainLayout->addWidget(titleLabel);
 | 
				
			||||
    
 | 
				
			||||
    // 主内容区域
 | 
				
			||||
    m_contentLayout = new QHBoxLayout();
 | 
				
			||||
    m_contentLayout->setSpacing(20);
 | 
				
			||||
    
 | 
				
			||||
    setupFlightControlModule();
 | 
				
			||||
    setupMissionControlModule();
 | 
				
			||||
    setupStatusMonitorModule();
 | 
				
			||||
    
 | 
				
			||||
    m_mainLayout->addLayout(m_contentLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 底部按钮
 | 
				
			||||
    QHBoxLayout *buttonLayout = new QHBoxLayout();
 | 
				
			||||
    buttonLayout->addStretch();
 | 
				
			||||
    
 | 
				
			||||
    QPushButton *closeBtn = new QPushButton("关闭");
 | 
				
			||||
    closeBtn->setObjectName("CloseBtn");
 | 
				
			||||
    closeBtn->setMinimumSize(100, 40);
 | 
				
			||||
    connect(closeBtn, &QPushButton::clicked, this, &QDialog::close);
 | 
				
			||||
    
 | 
				
			||||
    buttonLayout->addWidget(closeBtn);
 | 
				
			||||
    m_mainLayout->addLayout(buttonLayout);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::setupFlightControlModule()
 | 
				
			||||
{
 | 
				
			||||
    m_flightControlGroup = new QGroupBox("✈️ 飞行控制");
 | 
				
			||||
    m_flightControlGroup->setObjectName("ControlGroup");
 | 
				
			||||
    m_flightControlGroup->setMinimumWidth(280);
 | 
				
			||||
    
 | 
				
			||||
    QVBoxLayout *flightLayout = new QVBoxLayout(m_flightControlGroup);
 | 
				
			||||
    flightLayout->setSpacing(15);
 | 
				
			||||
    
 | 
				
			||||
    // 基础飞行控制按钮
 | 
				
			||||
    QGridLayout *basicControlLayout = new QGridLayout();
 | 
				
			||||
    basicControlLayout->setSpacing(10);
 | 
				
			||||
    
 | 
				
			||||
    m_takeoffBtn = new QPushButton("🚀 起飞");
 | 
				
			||||
    m_takeoffBtn->setObjectName("PrimaryBtn");
 | 
				
			||||
    m_takeoffBtn->setMinimumHeight(50);
 | 
				
			||||
    
 | 
				
			||||
    m_landBtn = new QPushButton("🛬 降落");
 | 
				
			||||
    m_landBtn->setObjectName("WarningBtn");
 | 
				
			||||
    m_landBtn->setMinimumHeight(50);
 | 
				
			||||
    m_landBtn->setEnabled(false);
 | 
				
			||||
    
 | 
				
			||||
    m_hoverBtn = new QPushButton("⏸️ 悬停");
 | 
				
			||||
    m_hoverBtn->setObjectName("InfoBtn");
 | 
				
			||||
    m_hoverBtn->setMinimumHeight(50);
 | 
				
			||||
    m_hoverBtn->setEnabled(false);
 | 
				
			||||
    
 | 
				
			||||
    m_returnHomeBtn = new QPushButton("🏠 返航");
 | 
				
			||||
    m_returnHomeBtn->setObjectName("SuccessBtn");
 | 
				
			||||
    m_returnHomeBtn->setMinimumHeight(50);
 | 
				
			||||
    m_returnHomeBtn->setEnabled(false);
 | 
				
			||||
    
 | 
				
			||||
    basicControlLayout->addWidget(m_takeoffBtn, 0, 0);
 | 
				
			||||
    basicControlLayout->addWidget(m_landBtn, 0, 1);
 | 
				
			||||
    basicControlLayout->addWidget(m_hoverBtn, 1, 0);
 | 
				
			||||
    basicControlLayout->addWidget(m_returnHomeBtn, 1, 1);
 | 
				
			||||
    
 | 
				
			||||
    flightLayout->addLayout(basicControlLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 高度和速度控制
 | 
				
			||||
    QLabel *altitudeLabel = new QLabel("飞行高度 (m):");
 | 
				
			||||
    m_altitudeSlider = new QSlider(Qt::Horizontal);
 | 
				
			||||
    m_altitudeSlider->setRange(1, 100);
 | 
				
			||||
    m_altitudeSlider->setValue(10);
 | 
				
			||||
    m_altitudeSlider->setEnabled(false);
 | 
				
			||||
    
 | 
				
			||||
    QLabel *speedLabel = new QLabel("飞行速度 (m/s):");
 | 
				
			||||
    m_speedSlider = new QSlider(Qt::Horizontal);
 | 
				
			||||
    m_speedSlider->setRange(1, 20);
 | 
				
			||||
    m_speedSlider->setValue(5);
 | 
				
			||||
    m_speedSlider->setEnabled(false);
 | 
				
			||||
    
 | 
				
			||||
    flightLayout->addWidget(altitudeLabel);
 | 
				
			||||
    flightLayout->addWidget(m_altitudeSlider);
 | 
				
			||||
    flightLayout->addWidget(speedLabel);
 | 
				
			||||
    flightLayout->addWidget(m_speedSlider);
 | 
				
			||||
    
 | 
				
			||||
    // 紧急停止按钮
 | 
				
			||||
    m_emergencyStopBtn = new QPushButton("🚨 紧急停止");
 | 
				
			||||
    m_emergencyStopBtn->setObjectName("DangerBtn");
 | 
				
			||||
    m_emergencyStopBtn->setMinimumHeight(60);
 | 
				
			||||
    m_emergencyStopBtn->setStyleSheet(
 | 
				
			||||
        "QPushButton {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #e74c3c, stop:1 #c0392b);"
 | 
				
			||||
        "  color: white;"
 | 
				
			||||
        "  font-size: 16px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  border: 2px solid #e74c3c;"
 | 
				
			||||
        "  border-radius: 8px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton:hover {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #c0392b, stop:1 #a93226);"
 | 
				
			||||
        "}"
 | 
				
			||||
    );
 | 
				
			||||
    
 | 
				
			||||
    flightLayout->addWidget(m_emergencyStopBtn);
 | 
				
			||||
    flightLayout->addStretch();
 | 
				
			||||
    
 | 
				
			||||
    m_contentLayout->addWidget(m_flightControlGroup);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::setupMissionControlModule()
 | 
				
			||||
{
 | 
				
			||||
    m_missionControlGroup = new QGroupBox("🎯 任务控制");
 | 
				
			||||
    m_missionControlGroup->setObjectName("ControlGroup");
 | 
				
			||||
    m_missionControlGroup->setMinimumWidth(280);
 | 
				
			||||
    
 | 
				
			||||
    QVBoxLayout *missionLayout = new QVBoxLayout(m_missionControlGroup);
 | 
				
			||||
    missionLayout->setSpacing(15);
 | 
				
			||||
    
 | 
				
			||||
    // 任务模式选择
 | 
				
			||||
    QLabel *modeLabel = new QLabel("任务模式:");
 | 
				
			||||
    m_missionModeCombo = new QComboBox();
 | 
				
			||||
    m_missionModeCombo->addItems({"手动控制", "自主巡航", "目标跟踪", "区域扫描"});
 | 
				
			||||
    m_missionModeCombo->setMinimumHeight(35);
 | 
				
			||||
    
 | 
				
			||||
    missionLayout->addWidget(modeLabel);
 | 
				
			||||
    missionLayout->addWidget(m_missionModeCombo);
 | 
				
			||||
    
 | 
				
			||||
    // 功能控制按钮
 | 
				
			||||
    m_mappingBtn = new QPushButton("🗺️ 开始建图");
 | 
				
			||||
    m_mappingBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_mappingBtn->setMinimumHeight(50);
 | 
				
			||||
    m_mappingBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    m_navigationBtn = new QPushButton("🧭 导航避障");
 | 
				
			||||
    m_navigationBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_navigationBtn->setMinimumHeight(50);
 | 
				
			||||
    m_navigationBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    m_photoBtn = new QPushButton("📸 照片传输");
 | 
				
			||||
    m_photoBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_photoBtn->setMinimumHeight(50);
 | 
				
			||||
    m_photoBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    m_recognitionBtn = new QPushButton("👁️ 人物识别");
 | 
				
			||||
    m_recognitionBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_recognitionBtn->setMinimumHeight(50);
 | 
				
			||||
    m_recognitionBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    missionLayout->addWidget(m_mappingBtn);
 | 
				
			||||
    missionLayout->addWidget(m_navigationBtn);
 | 
				
			||||
    missionLayout->addWidget(m_photoBtn);
 | 
				
			||||
    missionLayout->addWidget(m_recognitionBtn);
 | 
				
			||||
    missionLayout->addStretch();
 | 
				
			||||
    
 | 
				
			||||
    m_contentLayout->addWidget(m_missionControlGroup);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::setupStatusMonitorModule()
 | 
				
			||||
{
 | 
				
			||||
    m_statusGroup = new QGroupBox("📊 状态监控");
 | 
				
			||||
    m_statusGroup->setObjectName("ControlGroup");
 | 
				
			||||
    m_statusGroup->setMinimumWidth(320);
 | 
				
			||||
    
 | 
				
			||||
    QVBoxLayout *statusLayout = new QVBoxLayout(m_statusGroup);
 | 
				
			||||
    statusLayout->setSpacing(15);
 | 
				
			||||
    
 | 
				
			||||
    // 电池状态
 | 
				
			||||
    QHBoxLayout *batteryLayout = new QHBoxLayout();
 | 
				
			||||
    m_batteryLabel = new QLabel("电池电量:");
 | 
				
			||||
    m_batteryProgress = new QProgressBar();
 | 
				
			||||
    m_batteryProgress->setRange(0, 100);
 | 
				
			||||
    m_batteryProgress->setValue(85);
 | 
				
			||||
    m_batteryProgress->setTextVisible(true);
 | 
				
			||||
    m_batteryProgress->setFormat("%p%");
 | 
				
			||||
    
 | 
				
			||||
    batteryLayout->addWidget(m_batteryLabel);
 | 
				
			||||
    batteryLayout->addWidget(m_batteryProgress);
 | 
				
			||||
    statusLayout->addLayout(batteryLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 飞行参数
 | 
				
			||||
    QGridLayout *paramLayout = new QGridLayout();
 | 
				
			||||
    paramLayout->addWidget(new QLabel("飞行高度:"), 0, 0);
 | 
				
			||||
    m_altitudeLabel = new QLabel("0.0 m");
 | 
				
			||||
    m_altitudeLabel->setStyleSheet("font-weight: bold; color: #0078d4;");
 | 
				
			||||
    paramLayout->addWidget(m_altitudeLabel, 0, 1);
 | 
				
			||||
    
 | 
				
			||||
    paramLayout->addWidget(new QLabel("飞行速度:"), 1, 0);
 | 
				
			||||
    m_speedLabel = new QLabel("0.0 m/s");
 | 
				
			||||
    m_speedLabel->setStyleSheet("font-weight: bold; color: #0078d4;");
 | 
				
			||||
    paramLayout->addWidget(m_speedLabel, 1, 1);
 | 
				
			||||
    
 | 
				
			||||
    paramLayout->addWidget(new QLabel("GPS状态:"), 2, 0);
 | 
				
			||||
    m_gpsLabel = new QLabel("🔴 未连接");
 | 
				
			||||
    paramLayout->addWidget(m_gpsLabel, 2, 1);
 | 
				
			||||
    
 | 
				
			||||
    paramLayout->addWidget(new QLabel("连接状态:"), 3, 0);
 | 
				
			||||
    m_connectionLabel = new QLabel("🟢 已连接");
 | 
				
			||||
    paramLayout->addWidget(m_connectionLabel, 3, 1);
 | 
				
			||||
    
 | 
				
			||||
    statusLayout->addLayout(paramLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 日志显示
 | 
				
			||||
    QLabel *logLabel = new QLabel("系统日志:");
 | 
				
			||||
    m_logTextEdit = new QTextEdit();
 | 
				
			||||
    m_logTextEdit->setMaximumHeight(200);
 | 
				
			||||
    m_logTextEdit->setReadOnly(true);
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 无人机控制系统启动").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 等待连接无人机...").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    
 | 
				
			||||
    statusLayout->addWidget(logLabel);
 | 
				
			||||
    statusLayout->addWidget(m_logTextEdit);
 | 
				
			||||
    
 | 
				
			||||
    m_contentLayout->addWidget(m_statusGroup);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::applyStyles()
 | 
				
			||||
{
 | 
				
			||||
    // 应用现代样式管理器
 | 
				
			||||
    ModernStyleManager* styleManager = ModernStyleManager::getInstance();
 | 
				
			||||
 | 
				
			||||
    // 应用按钮样式
 | 
				
			||||
    styleManager->applyButtonStyle(m_takeoffBtn, ModernStyleManager::ButtonStyle::Primary);
 | 
				
			||||
    styleManager->applyButtonStyle(m_landBtn, ModernStyleManager::ButtonStyle::Warning);
 | 
				
			||||
    styleManager->applyButtonStyle(m_hoverBtn, ModernStyleManager::ButtonStyle::Info);
 | 
				
			||||
    styleManager->applyButtonStyle(m_returnHomeBtn, ModernStyleManager::ButtonStyle::Success);
 | 
				
			||||
    styleManager->applyButtonStyle(m_emergencyStopBtn, ModernStyleManager::ButtonStyle::Danger);
 | 
				
			||||
 | 
				
			||||
    // 设置对话框样式
 | 
				
			||||
    setStyleSheet(
 | 
				
			||||
        "QDialog {"
 | 
				
			||||
        "  background-color: #f8f9fa;"
 | 
				
			||||
        "  border: 1px solid #dee2e6;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QGroupBox {"
 | 
				
			||||
        "  font-size: 16px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  color: #495057;"
 | 
				
			||||
        "  border: 2px solid #dee2e6;"
 | 
				
			||||
        "  border-radius: 8px;"
 | 
				
			||||
        "  margin-top: 10px;"
 | 
				
			||||
        "  padding-top: 10px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QGroupBox::title {"
 | 
				
			||||
        "  subcontrol-origin: margin;"
 | 
				
			||||
        "  left: 10px;"
 | 
				
			||||
        "  padding: 0 8px 0 8px;"
 | 
				
			||||
        "  background-color: #f8f9fa;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QSlider::groove:horizontal {"
 | 
				
			||||
        "  border: 1px solid #bbb;"
 | 
				
			||||
        "  background: white;"
 | 
				
			||||
        "  height: 10px;"
 | 
				
			||||
        "  border-radius: 4px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QSlider::handle:horizontal {"
 | 
				
			||||
        "  background: #0078d4;"
 | 
				
			||||
        "  border: 1px solid #5c5c5c;"
 | 
				
			||||
        "  width: 18px;"
 | 
				
			||||
        "  margin: -2px 0;"
 | 
				
			||||
        "  border-radius: 3px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QProgressBar {"
 | 
				
			||||
        "  border: 2px solid #dee2e6;"
 | 
				
			||||
        "  border-radius: 5px;"
 | 
				
			||||
        "  text-align: center;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QProgressBar::chunk {"
 | 
				
			||||
        "  background-color: #28a745;"
 | 
				
			||||
        "  border-radius: 3px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QTextEdit {"
 | 
				
			||||
        "  border: 1px solid #dee2e6;"
 | 
				
			||||
        "  border-radius: 4px;"
 | 
				
			||||
        "  background-color: white;"
 | 
				
			||||
        "  font-family: 'Consolas', monospace;"
 | 
				
			||||
        "  font-size: 12px;"
 | 
				
			||||
        "}"
 | 
				
			||||
    );
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::connectSignals()
 | 
				
			||||
{
 | 
				
			||||
    // 飞行控制信号连接
 | 
				
			||||
    connect(m_takeoffBtn, &QPushButton::clicked, this, &DroneControlDialog::onTakeoffClicked);
 | 
				
			||||
    connect(m_landBtn, &QPushButton::clicked, this, &DroneControlDialog::onLandClicked);
 | 
				
			||||
    connect(m_hoverBtn, &QPushButton::clicked, this, &DroneControlDialog::onHoverClicked);
 | 
				
			||||
    connect(m_returnHomeBtn, &QPushButton::clicked, this, &DroneControlDialog::onReturnHomeClicked);
 | 
				
			||||
    connect(m_emergencyStopBtn, &QPushButton::clicked, this, &DroneControlDialog::onEmergencyStop);
 | 
				
			||||
 | 
				
			||||
    // 任务控制信号连接
 | 
				
			||||
    connect(m_mappingBtn, &QPushButton::clicked, this, &DroneControlDialog::onMappingToggle);
 | 
				
			||||
    connect(m_navigationBtn, &QPushButton::clicked, this, &DroneControlDialog::onNavigationToggle);
 | 
				
			||||
    connect(m_photoBtn, &QPushButton::clicked, this, &DroneControlDialog::onPhotoTransmissionToggle);
 | 
				
			||||
    connect(m_recognitionBtn, &QPushButton::clicked, this, &DroneControlDialog::onPersonRecognitionToggle);
 | 
				
			||||
 | 
				
			||||
    // 状态更新定时器
 | 
				
			||||
    connect(m_statusUpdateTimer, &QTimer::timeout, [this]() {
 | 
				
			||||
        // 模拟状态更新
 | 
				
			||||
        static int counter = 0;
 | 
				
			||||
        counter++;
 | 
				
			||||
 | 
				
			||||
        if (m_isFlying) {
 | 
				
			||||
            // 模拟电池消耗
 | 
				
			||||
            int currentBattery = m_batteryProgress->value();
 | 
				
			||||
            if (currentBattery > 0 && counter % 10 == 0) {
 | 
				
			||||
                m_batteryProgress->setValue(currentBattery - 1);
 | 
				
			||||
            }
 | 
				
			||||
 | 
				
			||||
            // 更新电池颜色
 | 
				
			||||
            if (currentBattery > 50) {
 | 
				
			||||
                m_batteryProgress->setStyleSheet("QProgressBar::chunk { background-color: #28a745; }");
 | 
				
			||||
            } else if (currentBattery > 20) {
 | 
				
			||||
                m_batteryProgress->setStyleSheet("QProgressBar::chunk { background-color: #ffc107; }");
 | 
				
			||||
            } else {
 | 
				
			||||
                m_batteryProgress->setStyleSheet("QProgressBar::chunk { background-color: #dc3545; }");
 | 
				
			||||
            }
 | 
				
			||||
        }
 | 
				
			||||
    });
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
// 槽函数实现
 | 
				
			||||
void DroneControlDialog::onTakeoffClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isFlying = true;
 | 
				
			||||
    m_takeoffBtn->setEnabled(false);
 | 
				
			||||
    m_landBtn->setEnabled(true);
 | 
				
			||||
    m_hoverBtn->setEnabled(true);
 | 
				
			||||
    m_returnHomeBtn->setEnabled(true);
 | 
				
			||||
    m_altitudeSlider->setEnabled(true);
 | 
				
			||||
    m_speedSlider->setEnabled(true);
 | 
				
			||||
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 无人机起飞中...").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    m_gpsLabel->setText("🟢 GPS已锁定");
 | 
				
			||||
 | 
				
			||||
    // 模拟起飞过程
 | 
				
			||||
    QTimer::singleShot(2000, [this]() {
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 无人机起飞成功,当前高度: %2m").arg(
 | 
				
			||||
            QDateTime::currentDateTime().toString("hh:mm:ss")).arg(m_altitudeSlider->value()));
 | 
				
			||||
        updateDroneStatus(m_batteryProgress->value(), m_altitudeSlider->value(), m_speedSlider->value());
 | 
				
			||||
    });
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onLandClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isFlying = false;
 | 
				
			||||
    m_takeoffBtn->setEnabled(true);
 | 
				
			||||
    m_landBtn->setEnabled(false);
 | 
				
			||||
    m_hoverBtn->setEnabled(false);
 | 
				
			||||
    m_returnHomeBtn->setEnabled(false);
 | 
				
			||||
    m_altitudeSlider->setEnabled(false);
 | 
				
			||||
    m_speedSlider->setEnabled(false);
 | 
				
			||||
 | 
				
			||||
    // 停止所有任务
 | 
				
			||||
    if (m_isMappingActive) onMappingToggle();
 | 
				
			||||
    if (m_isNavigationActive) onNavigationToggle();
 | 
				
			||||
    if (m_isPhotoTransmissionActive) onPhotoTransmissionToggle();
 | 
				
			||||
    if (m_isPersonRecognitionActive) onPersonRecognitionToggle();
 | 
				
			||||
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 无人机降落中...").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
 | 
				
			||||
    QTimer::singleShot(3000, [this]() {
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 无人机安全降落").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        updateDroneStatus(m_batteryProgress->value(), 0.0, 0.0);
 | 
				
			||||
    });
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onHoverClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 无人机进入悬停模式").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    updateDroneStatus(m_batteryProgress->value(), m_altitudeSlider->value(), 0.0);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onReturnHomeClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 无人机开始返航").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
 | 
				
			||||
    // 停止所有任务
 | 
				
			||||
    if (m_isMappingActive) onMappingToggle();
 | 
				
			||||
    if (m_isNavigationActive) onNavigationToggle();
 | 
				
			||||
    if (m_isPhotoTransmissionActive) onPhotoTransmissionToggle();
 | 
				
			||||
    if (m_isPersonRecognitionActive) onPersonRecognitionToggle();
 | 
				
			||||
 | 
				
			||||
    QTimer::singleShot(5000, [this]() {
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 无人机返航完成").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        onLandClicked();
 | 
				
			||||
    });
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onEmergencyStop()
 | 
				
			||||
{
 | 
				
			||||
    QMessageBox::StandardButton reply = QMessageBox::warning(this, "紧急停止",
 | 
				
			||||
        "确定要执行紧急停止吗?这将立即停止所有操作!",
 | 
				
			||||
        QMessageBox::Yes | QMessageBox::No);
 | 
				
			||||
 | 
				
			||||
    if (reply == QMessageBox::Yes) {
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 🚨 执行紧急停止!").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        onLandClicked();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onMappingToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isMappingActive = !m_isMappingActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isMappingActive) {
 | 
				
			||||
        m_mappingBtn->setText("🗺️ 停止建图");
 | 
				
			||||
        m_mappingBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始自主建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startMapping();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_mappingBtn->setText("🗺️ 开始建图");
 | 
				
			||||
        m_mappingBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止自主建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopMapping();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onNavigationToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isNavigationActive = !m_isNavigationActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isNavigationActive) {
 | 
				
			||||
        m_navigationBtn->setText("🧭 停止导航");
 | 
				
			||||
        m_navigationBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始导航避障").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startNavigation();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_navigationBtn->setText("🧭 导航避障");
 | 
				
			||||
        m_navigationBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止导航避障").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopNavigation();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onPhotoTransmissionToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isPhotoTransmissionActive = !m_isPhotoTransmissionActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isPhotoTransmissionActive) {
 | 
				
			||||
        m_photoBtn->setText("📸 停止传输");
 | 
				
			||||
        m_photoBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始照片传输").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startPhotoTransmission();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_photoBtn->setText("📸 照片传输");
 | 
				
			||||
        m_photoBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止照片传输").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopPhotoTransmission();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::onPersonRecognitionToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isPersonRecognitionActive = !m_isPersonRecognitionActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isPersonRecognitionActive) {
 | 
				
			||||
        m_recognitionBtn->setText("👁️ 停止识别");
 | 
				
			||||
        m_recognitionBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始人物识别").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startPersonRecognition();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_recognitionBtn->setText("👁️ 人物识别");
 | 
				
			||||
        m_recognitionBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止人物识别").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopPersonRecognition();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void DroneControlDialog::updateDroneStatus(int battery, double altitude, double speed)
 | 
				
			||||
{
 | 
				
			||||
    m_batteryProgress->setValue(battery);
 | 
				
			||||
    m_altitudeLabel->setText(QString("%1 m").arg(altitude, 0, 'f', 1));
 | 
				
			||||
    m_speedLabel->setText(QString("%1 m/s").arg(speed, 0, 'f', 1));
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,630 @@
 | 
				
			||||
/**
 | 
				
			||||
 * @file RobotDogControlDialog.cpp
 | 
				
			||||
 * @brief 机器狗控制对话框实现
 | 
				
			||||
 * @author Qt UI Optimizer
 | 
				
			||||
 * @date 2024-07-04
 | 
				
			||||
 * @version 1.0
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
#include "ui/dialogs/RobotDogControlDialog.h"
 | 
				
			||||
#include "styles/ModernStyleManager.h"
 | 
				
			||||
 | 
				
			||||
#include <QApplication>
 | 
				
			||||
#include <QDesktopWidget>
 | 
				
			||||
#include <QMessageBox>
 | 
				
			||||
#include <QDateTime>
 | 
				
			||||
 | 
				
			||||
RobotDogControlDialog::RobotDogControlDialog(QWidget *parent)
 | 
				
			||||
    : QDialog(parent)
 | 
				
			||||
    , m_mainLayout(nullptr)
 | 
				
			||||
    , m_contentLayout(nullptr)
 | 
				
			||||
    , m_isMappingActive(false)
 | 
				
			||||
    , m_isNavigationActive(false)
 | 
				
			||||
    , m_isPhotoTransmissionActive(false)
 | 
				
			||||
    , m_isPersonRecognitionActive(false)
 | 
				
			||||
    , m_isMoving(false)
 | 
				
			||||
    , m_currentPosture("站立")
 | 
				
			||||
    , m_statusUpdateTimer(new QTimer(this))
 | 
				
			||||
{
 | 
				
			||||
    setupUI();
 | 
				
			||||
    applyStyles();
 | 
				
			||||
    connectSignals();
 | 
				
			||||
    
 | 
				
			||||
    // 启动状态更新定时器
 | 
				
			||||
    m_statusUpdateTimer->start(1000);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
RobotDogControlDialog::~RobotDogControlDialog()
 | 
				
			||||
{
 | 
				
			||||
    if (m_statusUpdateTimer) {
 | 
				
			||||
        m_statusUpdateTimer->stop();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::setupUI()
 | 
				
			||||
{
 | 
				
			||||
    setWindowTitle("🐕 机器狗控制中心");
 | 
				
			||||
    setModal(false);
 | 
				
			||||
    setMinimumSize(900, 700);
 | 
				
			||||
    resize(1000, 750);
 | 
				
			||||
    
 | 
				
			||||
    // 窗口居中显示
 | 
				
			||||
    QRect screenGeometry = QApplication::desktop()->screenGeometry();
 | 
				
			||||
    int x = (screenGeometry.width() - this->width()) / 2;
 | 
				
			||||
    int y = (screenGeometry.height() - this->height()) / 2;
 | 
				
			||||
    move(x, y);
 | 
				
			||||
    
 | 
				
			||||
    m_mainLayout = new QVBoxLayout(this);
 | 
				
			||||
    m_mainLayout->setSpacing(20);
 | 
				
			||||
    m_mainLayout->setContentsMargins(20, 20, 20, 20);
 | 
				
			||||
    
 | 
				
			||||
    // 标题
 | 
				
			||||
    QLabel *titleLabel = new QLabel("🐕 机器狗控制中心");
 | 
				
			||||
    titleLabel->setObjectName("DialogTitle");
 | 
				
			||||
    titleLabel->setAlignment(Qt::AlignCenter);
 | 
				
			||||
    titleLabel->setStyleSheet(
 | 
				
			||||
        "font-size: 24px; "
 | 
				
			||||
        "font-weight: bold; "
 | 
				
			||||
        "color: #16a085; "
 | 
				
			||||
        "padding: 10px; "
 | 
				
			||||
        "border-bottom: 2px solid #16a085; "
 | 
				
			||||
        "margin-bottom: 10px;"
 | 
				
			||||
    );
 | 
				
			||||
    m_mainLayout->addWidget(titleLabel);
 | 
				
			||||
    
 | 
				
			||||
    // 主内容区域
 | 
				
			||||
    m_contentLayout = new QHBoxLayout();
 | 
				
			||||
    m_contentLayout->setSpacing(20);
 | 
				
			||||
    
 | 
				
			||||
    setupMovementControlModule();
 | 
				
			||||
    setupMissionControlModule();
 | 
				
			||||
    setupStatusMonitorModule();
 | 
				
			||||
    
 | 
				
			||||
    m_mainLayout->addLayout(m_contentLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 底部按钮
 | 
				
			||||
    QHBoxLayout *buttonLayout = new QHBoxLayout();
 | 
				
			||||
    buttonLayout->addStretch();
 | 
				
			||||
    
 | 
				
			||||
    QPushButton *closeBtn = new QPushButton("关闭");
 | 
				
			||||
    closeBtn->setObjectName("CloseBtn");
 | 
				
			||||
    closeBtn->setMinimumSize(100, 40);
 | 
				
			||||
    connect(closeBtn, &QPushButton::clicked, this, &QDialog::close);
 | 
				
			||||
    
 | 
				
			||||
    buttonLayout->addWidget(closeBtn);
 | 
				
			||||
    m_mainLayout->addLayout(buttonLayout);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::setupMovementControlModule()
 | 
				
			||||
{
 | 
				
			||||
    m_movementControlGroup = new QGroupBox("🎮 运动控制");
 | 
				
			||||
    m_movementControlGroup->setObjectName("ControlGroup");
 | 
				
			||||
    m_movementControlGroup->setMinimumWidth(280);
 | 
				
			||||
    
 | 
				
			||||
    QVBoxLayout *movementLayout = new QVBoxLayout(m_movementControlGroup);
 | 
				
			||||
    movementLayout->setSpacing(15);
 | 
				
			||||
    
 | 
				
			||||
    // 方向控制按钮 - 十字布局
 | 
				
			||||
    QGridLayout *directionLayout = new QGridLayout();
 | 
				
			||||
    directionLayout->setSpacing(10);
 | 
				
			||||
    
 | 
				
			||||
    m_forwardBtn = new QPushButton("⬆️ 前进");
 | 
				
			||||
    m_forwardBtn->setObjectName("DirectionBtn");
 | 
				
			||||
    m_forwardBtn->setMinimumHeight(50);
 | 
				
			||||
    
 | 
				
			||||
    m_backwardBtn = new QPushButton("⬇️ 后退");
 | 
				
			||||
    m_backwardBtn->setObjectName("DirectionBtn");
 | 
				
			||||
    m_backwardBtn->setMinimumHeight(50);
 | 
				
			||||
    
 | 
				
			||||
    m_leftBtn = new QPushButton("⬅️ 左转");
 | 
				
			||||
    m_leftBtn->setObjectName("DirectionBtn");
 | 
				
			||||
    m_leftBtn->setMinimumHeight(50);
 | 
				
			||||
    
 | 
				
			||||
    m_rightBtn = new QPushButton("➡️ 右转");
 | 
				
			||||
    m_rightBtn->setObjectName("DirectionBtn");
 | 
				
			||||
    m_rightBtn->setMinimumHeight(50);
 | 
				
			||||
    
 | 
				
			||||
    m_stopBtn = new QPushButton("⏹️ 停止");
 | 
				
			||||
    m_stopBtn->setObjectName("StopBtn");
 | 
				
			||||
    m_stopBtn->setMinimumHeight(50);
 | 
				
			||||
    
 | 
				
			||||
    // 十字布局
 | 
				
			||||
    directionLayout->addWidget(m_forwardBtn, 0, 1);
 | 
				
			||||
    directionLayout->addWidget(m_leftBtn, 1, 0);
 | 
				
			||||
    directionLayout->addWidget(m_stopBtn, 1, 1);
 | 
				
			||||
    directionLayout->addWidget(m_rightBtn, 1, 2);
 | 
				
			||||
    directionLayout->addWidget(m_backwardBtn, 2, 1);
 | 
				
			||||
    
 | 
				
			||||
    movementLayout->addLayout(directionLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 姿态控制按钮
 | 
				
			||||
    QLabel *postureLabel = new QLabel("姿态控制:");
 | 
				
			||||
    movementLayout->addWidget(postureLabel);
 | 
				
			||||
    
 | 
				
			||||
    QHBoxLayout *postureLayout = new QHBoxLayout();
 | 
				
			||||
    postureLayout->setSpacing(10);
 | 
				
			||||
    
 | 
				
			||||
    m_standBtn = new QPushButton("🧍 站立");
 | 
				
			||||
    m_standBtn->setObjectName("PostureBtn");
 | 
				
			||||
    m_standBtn->setMinimumHeight(45);
 | 
				
			||||
    
 | 
				
			||||
    m_lieDownBtn = new QPushButton("🛌 趴下");
 | 
				
			||||
    m_lieDownBtn->setObjectName("PostureBtn");
 | 
				
			||||
    m_lieDownBtn->setMinimumHeight(45);
 | 
				
			||||
    
 | 
				
			||||
    m_jumpBtn = new QPushButton("🦘 跳跃");
 | 
				
			||||
    m_jumpBtn->setObjectName("PostureBtn");
 | 
				
			||||
    m_jumpBtn->setMinimumHeight(45);
 | 
				
			||||
    
 | 
				
			||||
    postureLayout->addWidget(m_standBtn);
 | 
				
			||||
    postureLayout->addWidget(m_lieDownBtn);
 | 
				
			||||
    postureLayout->addWidget(m_jumpBtn);
 | 
				
			||||
    movementLayout->addLayout(postureLayout);
 | 
				
			||||
    
 | 
				
			||||
    // 速度控制
 | 
				
			||||
    QLabel *speedLabel = new QLabel("移动速度:");
 | 
				
			||||
    m_speedSlider = new QSlider(Qt::Horizontal);
 | 
				
			||||
    m_speedSlider->setRange(1, 10);
 | 
				
			||||
    m_speedSlider->setValue(5);
 | 
				
			||||
    
 | 
				
			||||
    movementLayout->addWidget(speedLabel);
 | 
				
			||||
    movementLayout->addWidget(m_speedSlider);
 | 
				
			||||
    
 | 
				
			||||
    // 紧急停止按钮
 | 
				
			||||
    m_emergencyStopBtn = new QPushButton("🚨 紧急停止");
 | 
				
			||||
    m_emergencyStopBtn->setObjectName("DangerBtn");
 | 
				
			||||
    m_emergencyStopBtn->setMinimumHeight(60);
 | 
				
			||||
    m_emergencyStopBtn->setStyleSheet(
 | 
				
			||||
        "QPushButton {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #e74c3c, stop:1 #c0392b);"
 | 
				
			||||
        "  color: white;"
 | 
				
			||||
        "  font-size: 16px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  border: 2px solid #e74c3c;"
 | 
				
			||||
        "  border-radius: 8px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton:hover {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #c0392b, stop:1 #a93226);"
 | 
				
			||||
        "}"
 | 
				
			||||
    );
 | 
				
			||||
    
 | 
				
			||||
    movementLayout->addWidget(m_emergencyStopBtn);
 | 
				
			||||
    movementLayout->addStretch();
 | 
				
			||||
    
 | 
				
			||||
    m_contentLayout->addWidget(m_movementControlGroup);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::setupMissionControlModule()
 | 
				
			||||
{
 | 
				
			||||
    m_missionControlGroup = new QGroupBox("🎯 任务控制");
 | 
				
			||||
    m_missionControlGroup->setObjectName("ControlGroup");
 | 
				
			||||
    m_missionControlGroup->setMinimumWidth(280);
 | 
				
			||||
    
 | 
				
			||||
    QVBoxLayout *missionLayout = new QVBoxLayout(m_missionControlGroup);
 | 
				
			||||
    missionLayout->setSpacing(15);
 | 
				
			||||
    
 | 
				
			||||
    // 任务模式选择
 | 
				
			||||
    QLabel *modeLabel = new QLabel("任务模式:");
 | 
				
			||||
    m_missionModeCombo = new QComboBox();
 | 
				
			||||
    m_missionModeCombo->addItems({"手动控制", "自主巡逻", "目标跟踪", "区域探索", "护卫模式"});
 | 
				
			||||
    m_missionModeCombo->setMinimumHeight(35);
 | 
				
			||||
    
 | 
				
			||||
    missionLayout->addWidget(modeLabel);
 | 
				
			||||
    missionLayout->addWidget(m_missionModeCombo);
 | 
				
			||||
    
 | 
				
			||||
    // 功能控制按钮
 | 
				
			||||
    m_mappingBtn = new QPushButton("🗺️ 开始建图");
 | 
				
			||||
    m_mappingBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_mappingBtn->setMinimumHeight(50);
 | 
				
			||||
    m_mappingBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    m_navigationBtn = new QPushButton("🧭 导航避障");
 | 
				
			||||
    m_navigationBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_navigationBtn->setMinimumHeight(50);
 | 
				
			||||
    m_navigationBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    m_photoBtn = new QPushButton("📸 照片传输");
 | 
				
			||||
    m_photoBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_photoBtn->setMinimumHeight(50);
 | 
				
			||||
    m_photoBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    m_recognitionBtn = new QPushButton("👁️ 人物识别");
 | 
				
			||||
    m_recognitionBtn->setObjectName("FunctionBtn");
 | 
				
			||||
    m_recognitionBtn->setMinimumHeight(50);
 | 
				
			||||
    m_recognitionBtn->setCheckable(true);
 | 
				
			||||
    
 | 
				
			||||
    missionLayout->addWidget(m_mappingBtn);
 | 
				
			||||
    missionLayout->addWidget(m_navigationBtn);
 | 
				
			||||
    missionLayout->addWidget(m_photoBtn);
 | 
				
			||||
    missionLayout->addWidget(m_recognitionBtn);
 | 
				
			||||
    missionLayout->addStretch();
 | 
				
			||||
    
 | 
				
			||||
    m_contentLayout->addWidget(m_missionControlGroup);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::setupStatusMonitorModule()
 | 
				
			||||
{
 | 
				
			||||
    m_statusGroup = new QGroupBox("📊 状态监控");
 | 
				
			||||
    m_statusGroup->setObjectName("ControlGroup");
 | 
				
			||||
    m_statusGroup->setMinimumWidth(320);
 | 
				
			||||
 | 
				
			||||
    QVBoxLayout *statusLayout = new QVBoxLayout(m_statusGroup);
 | 
				
			||||
    statusLayout->setSpacing(15);
 | 
				
			||||
 | 
				
			||||
    // 电池状态
 | 
				
			||||
    QHBoxLayout *batteryLayout = new QHBoxLayout();
 | 
				
			||||
    m_batteryLabel = new QLabel("电池电量:");
 | 
				
			||||
    m_batteryProgress = new QProgressBar();
 | 
				
			||||
    m_batteryProgress->setRange(0, 100);
 | 
				
			||||
    m_batteryProgress->setValue(90);
 | 
				
			||||
    m_batteryProgress->setTextVisible(true);
 | 
				
			||||
    m_batteryProgress->setFormat("%p%");
 | 
				
			||||
 | 
				
			||||
    batteryLayout->addWidget(m_batteryLabel);
 | 
				
			||||
    batteryLayout->addWidget(m_batteryProgress);
 | 
				
			||||
    statusLayout->addLayout(batteryLayout);
 | 
				
			||||
 | 
				
			||||
    // 运行参数
 | 
				
			||||
    QGridLayout *paramLayout = new QGridLayout();
 | 
				
			||||
    paramLayout->addWidget(new QLabel("移动速度:"), 0, 0);
 | 
				
			||||
    m_speedLabel = new QLabel("0.0 m/s");
 | 
				
			||||
    m_speedLabel->setStyleSheet("font-weight: bold; color: #16a085;");
 | 
				
			||||
    paramLayout->addWidget(m_speedLabel, 0, 1);
 | 
				
			||||
 | 
				
			||||
    paramLayout->addWidget(new QLabel("设备温度:"), 1, 0);
 | 
				
			||||
    m_temperatureLabel = new QLabel("35.2°C");
 | 
				
			||||
    m_temperatureLabel->setStyleSheet("font-weight: bold; color: #16a085;");
 | 
				
			||||
    paramLayout->addWidget(m_temperatureLabel, 1, 1);
 | 
				
			||||
 | 
				
			||||
    paramLayout->addWidget(new QLabel("当前姿态:"), 2, 0);
 | 
				
			||||
    m_postureLabel = new QLabel("🧍 站立");
 | 
				
			||||
    paramLayout->addWidget(m_postureLabel, 2, 1);
 | 
				
			||||
 | 
				
			||||
    paramLayout->addWidget(new QLabel("连接状态:"), 3, 0);
 | 
				
			||||
    m_connectionLabel = new QLabel("🟢 已连接");
 | 
				
			||||
    paramLayout->addWidget(m_connectionLabel, 3, 1);
 | 
				
			||||
 | 
				
			||||
    statusLayout->addLayout(paramLayout);
 | 
				
			||||
 | 
				
			||||
    // 日志显示
 | 
				
			||||
    QLabel *logLabel = new QLabel("系统日志:");
 | 
				
			||||
    m_logTextEdit = new QTextEdit();
 | 
				
			||||
    m_logTextEdit->setMaximumHeight(200);
 | 
				
			||||
    m_logTextEdit->setReadOnly(true);
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗控制系统启动").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗已连接,当前状态:待命").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
 | 
				
			||||
    statusLayout->addWidget(logLabel);
 | 
				
			||||
    statusLayout->addWidget(m_logTextEdit);
 | 
				
			||||
 | 
				
			||||
    m_contentLayout->addWidget(m_statusGroup);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::applyStyles()
 | 
				
			||||
{
 | 
				
			||||
    // 应用现代样式管理器
 | 
				
			||||
    ModernStyleManager* styleManager = ModernStyleManager::getInstance();
 | 
				
			||||
 | 
				
			||||
    // 设置对话框样式
 | 
				
			||||
    setStyleSheet(
 | 
				
			||||
        "QDialog {"
 | 
				
			||||
        "  background-color: #f8f9fa;"
 | 
				
			||||
        "  border: 1px solid #dee2e6;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QGroupBox {"
 | 
				
			||||
        "  font-size: 16px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  color: #495057;"
 | 
				
			||||
        "  border: 2px solid #dee2e6;"
 | 
				
			||||
        "  border-radius: 8px;"
 | 
				
			||||
        "  margin-top: 10px;"
 | 
				
			||||
        "  padding-top: 10px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QGroupBox::title {"
 | 
				
			||||
        "  subcontrol-origin: margin;"
 | 
				
			||||
        "  left: 10px;"
 | 
				
			||||
        "  padding: 0 8px 0 8px;"
 | 
				
			||||
        "  background-color: #f8f9fa;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton#DirectionBtn {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #16a085, stop:1 #138d75);"
 | 
				
			||||
        "  color: white;"
 | 
				
			||||
        "  font-size: 14px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  border: 2px solid #16a085;"
 | 
				
			||||
        "  border-radius: 8px;"
 | 
				
			||||
        "  padding: 8px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton#DirectionBtn:hover {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #138d75, stop:1 #117a65);"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton#DirectionBtn:pressed {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #117a65, stop:1 #0e6b5d);"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton#StopBtn {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #e67e22, stop:1 #d35400);"
 | 
				
			||||
        "  color: white;"
 | 
				
			||||
        "  font-size: 14px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  border: 2px solid #e67e22;"
 | 
				
			||||
        "  border-radius: 8px;"
 | 
				
			||||
        "  padding: 8px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QPushButton#PostureBtn {"
 | 
				
			||||
        "  background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
 | 
				
			||||
        "              stop:0 #3498db, stop:1 #2980b9);"
 | 
				
			||||
        "  color: white;"
 | 
				
			||||
        "  font-size: 13px;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "  border: 2px solid #3498db;"
 | 
				
			||||
        "  border-radius: 6px;"
 | 
				
			||||
        "  padding: 6px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QSlider::groove:horizontal {"
 | 
				
			||||
        "  border: 1px solid #bbb;"
 | 
				
			||||
        "  background: white;"
 | 
				
			||||
        "  height: 10px;"
 | 
				
			||||
        "  border-radius: 4px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QSlider::handle:horizontal {"
 | 
				
			||||
        "  background: #16a085;"
 | 
				
			||||
        "  border: 1px solid #5c5c5c;"
 | 
				
			||||
        "  width: 18px;"
 | 
				
			||||
        "  margin: -2px 0;"
 | 
				
			||||
        "  border-radius: 3px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QProgressBar {"
 | 
				
			||||
        "  border: 2px solid #dee2e6;"
 | 
				
			||||
        "  border-radius: 5px;"
 | 
				
			||||
        "  text-align: center;"
 | 
				
			||||
        "  font-weight: bold;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QProgressBar::chunk {"
 | 
				
			||||
        "  background-color: #28a745;"
 | 
				
			||||
        "  border-radius: 3px;"
 | 
				
			||||
        "}"
 | 
				
			||||
        "QTextEdit {"
 | 
				
			||||
        "  border: 1px solid #dee2e6;"
 | 
				
			||||
        "  border-radius: 4px;"
 | 
				
			||||
        "  background-color: white;"
 | 
				
			||||
        "  font-family: 'Consolas', monospace;"
 | 
				
			||||
        "  font-size: 12px;"
 | 
				
			||||
        "}"
 | 
				
			||||
    );
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::connectSignals()
 | 
				
			||||
{
 | 
				
			||||
    // 运动控制信号连接
 | 
				
			||||
    connect(m_forwardBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onMoveForwardClicked);
 | 
				
			||||
    connect(m_backwardBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onMoveBackwardClicked);
 | 
				
			||||
    connect(m_leftBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onTurnLeftClicked);
 | 
				
			||||
    connect(m_rightBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onTurnRightClicked);
 | 
				
			||||
    connect(m_stopBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onStopClicked);
 | 
				
			||||
 | 
				
			||||
    // 姿态控制信号连接
 | 
				
			||||
    connect(m_standBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onStandClicked);
 | 
				
			||||
    connect(m_lieDownBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onLieDownClicked);
 | 
				
			||||
    connect(m_jumpBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onJumpClicked);
 | 
				
			||||
 | 
				
			||||
    // 紧急停止
 | 
				
			||||
    connect(m_emergencyStopBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onEmergencyStop);
 | 
				
			||||
 | 
				
			||||
    // 任务控制信号连接
 | 
				
			||||
    connect(m_mappingBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onMappingToggle);
 | 
				
			||||
    connect(m_navigationBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onNavigationToggle);
 | 
				
			||||
    connect(m_photoBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onPhotoTransmissionToggle);
 | 
				
			||||
    connect(m_recognitionBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onPersonRecognitionToggle);
 | 
				
			||||
 | 
				
			||||
    // 速度滑块
 | 
				
			||||
    connect(m_speedSlider, &QSlider::valueChanged, [this](int value) {
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 速度设置为: %2").arg(
 | 
				
			||||
            QDateTime::currentDateTime().toString("hh:mm:ss")).arg(value));
 | 
				
			||||
    });
 | 
				
			||||
 | 
				
			||||
    // 状态更新定时器
 | 
				
			||||
    connect(m_statusUpdateTimer, &QTimer::timeout, [this]() {
 | 
				
			||||
        // 模拟状态更新
 | 
				
			||||
        static int counter = 0;
 | 
				
			||||
        counter++;
 | 
				
			||||
 | 
				
			||||
        if (m_isMoving) {
 | 
				
			||||
            // 模拟电池消耗
 | 
				
			||||
            int currentBattery = m_batteryProgress->value();
 | 
				
			||||
            if (currentBattery > 0 && counter % 15 == 0) {
 | 
				
			||||
                m_batteryProgress->setValue(currentBattery - 1);
 | 
				
			||||
            }
 | 
				
			||||
 | 
				
			||||
            // 更新电池颜色
 | 
				
			||||
            if (currentBattery > 50) {
 | 
				
			||||
                m_batteryProgress->setStyleSheet("QProgressBar::chunk { background-color: #28a745; }");
 | 
				
			||||
            } else if (currentBattery > 20) {
 | 
				
			||||
                m_batteryProgress->setStyleSheet("QProgressBar::chunk { background-color: #ffc107; }");
 | 
				
			||||
            } else {
 | 
				
			||||
                m_batteryProgress->setStyleSheet("QProgressBar::chunk { background-color: #dc3545; }");
 | 
				
			||||
            }
 | 
				
			||||
 | 
				
			||||
            // 模拟温度变化
 | 
				
			||||
            static double temperature = 35.2;
 | 
				
			||||
            temperature += (qrand() % 21 - 10) * 0.1; // ±1度随机变化
 | 
				
			||||
            if (temperature < 30.0) temperature = 30.0;
 | 
				
			||||
            if (temperature > 45.0) temperature = 45.0;
 | 
				
			||||
            m_temperatureLabel->setText(QString("%1°C").arg(temperature, 0, 'f', 1));
 | 
				
			||||
 | 
				
			||||
            // 温度颜色警告
 | 
				
			||||
            if (temperature > 40.0) {
 | 
				
			||||
                m_temperatureLabel->setStyleSheet("font-weight: bold; color: #dc3545;");
 | 
				
			||||
            } else if (temperature > 38.0) {
 | 
				
			||||
                m_temperatureLabel->setStyleSheet("font-weight: bold; color: #ffc107;");
 | 
				
			||||
            } else {
 | 
				
			||||
                m_temperatureLabel->setStyleSheet("font-weight: bold; color: #16a085;");
 | 
				
			||||
            }
 | 
				
			||||
        }
 | 
				
			||||
    });
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
// 运动控制槽函数实现
 | 
				
			||||
void RobotDogControlDialog::onMoveForwardClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isMoving = true;
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗开始前进").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    updateRobotStatus(m_batteryProgress->value(), m_speedSlider->value() * 0.5, 35.5);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onMoveBackwardClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isMoving = true;
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗开始后退").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    updateRobotStatus(m_batteryProgress->value(), m_speedSlider->value() * 0.3, 35.3);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onTurnLeftClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isMoving = true;
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗开始左转").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    updateRobotStatus(m_batteryProgress->value(), m_speedSlider->value() * 0.2, 35.1);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onTurnRightClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isMoving = true;
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗开始右转").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    updateRobotStatus(m_batteryProgress->value(), m_speedSlider->value() * 0.2, 35.1);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onStopClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_isMoving = false;
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗停止移动").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    updateRobotStatus(m_batteryProgress->value(), 0.0, 34.8);
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onStandClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_currentPosture = "站立";
 | 
				
			||||
    m_postureLabel->setText("🧍 站立");
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗切换到站立姿态").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onLieDownClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_currentPosture = "趴下";
 | 
				
			||||
    m_postureLabel->setText("🛌 趴下");
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗切换到趴下姿态").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
 | 
				
			||||
    // 趴下时停止移动
 | 
				
			||||
    if (m_isMoving) {
 | 
				
			||||
        onStopClicked();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onJumpClicked()
 | 
				
			||||
{
 | 
				
			||||
    m_logTextEdit->append(QString("[%1] 机器狗执行跳跃动作").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
 | 
				
			||||
    // 跳跃后恢复站立姿态
 | 
				
			||||
    QTimer::singleShot(1000, [this]() {
 | 
				
			||||
        onStandClicked();
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 跳跃动作完成").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
    });
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onEmergencyStop()
 | 
				
			||||
{
 | 
				
			||||
    QMessageBox::StandardButton reply = QMessageBox::warning(this, "紧急停止",
 | 
				
			||||
        "确定要执行紧急停止吗?这将立即停止所有操作!",
 | 
				
			||||
        QMessageBox::Yes | QMessageBox::No);
 | 
				
			||||
 | 
				
			||||
    if (reply == QMessageBox::Yes) {
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 🚨 执行紧急停止!").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        onStopClicked();
 | 
				
			||||
 | 
				
			||||
        // 停止所有任务
 | 
				
			||||
        if (m_isMappingActive) onMappingToggle();
 | 
				
			||||
        if (m_isNavigationActive) onNavigationToggle();
 | 
				
			||||
        if (m_isPhotoTransmissionActive) onPhotoTransmissionToggle();
 | 
				
			||||
        if (m_isPersonRecognitionActive) onPersonRecognitionToggle();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
// 任务控制槽函数实现
 | 
				
			||||
void RobotDogControlDialog::onMappingToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isMappingActive = !m_isMappingActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isMappingActive) {
 | 
				
			||||
        m_mappingBtn->setText("🗺️ 停止建图");
 | 
				
			||||
        m_mappingBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始自主建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startMapping();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_mappingBtn->setText("🗺️ 开始建图");
 | 
				
			||||
        m_mappingBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止自主建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopMapping();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onNavigationToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isNavigationActive = !m_isNavigationActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isNavigationActive) {
 | 
				
			||||
        m_navigationBtn->setText("🧭 停止导航");
 | 
				
			||||
        m_navigationBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始导航避障").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startNavigation();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_navigationBtn->setText("🧭 导航避障");
 | 
				
			||||
        m_navigationBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止导航避障").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopNavigation();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onPhotoTransmissionToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isPhotoTransmissionActive = !m_isPhotoTransmissionActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isPhotoTransmissionActive) {
 | 
				
			||||
        m_photoBtn->setText("📸 停止传输");
 | 
				
			||||
        m_photoBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始照片传输").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startPhotoTransmission();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_photoBtn->setText("📸 照片传输");
 | 
				
			||||
        m_photoBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止照片传输").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopPhotoTransmission();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::onPersonRecognitionToggle()
 | 
				
			||||
{
 | 
				
			||||
    m_isPersonRecognitionActive = !m_isPersonRecognitionActive;
 | 
				
			||||
 | 
				
			||||
    if (m_isPersonRecognitionActive) {
 | 
				
			||||
        m_recognitionBtn->setText("👁️ 停止识别");
 | 
				
			||||
        m_recognitionBtn->setStyleSheet("background-color: #dc3545; color: white;");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 开始人物识别").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit startPersonRecognition();
 | 
				
			||||
    } else {
 | 
				
			||||
        m_recognitionBtn->setText("👁️ 人物识别");
 | 
				
			||||
        m_recognitionBtn->setStyleSheet("");
 | 
				
			||||
        m_logTextEdit->append(QString("[%1] 停止人物识别").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
 | 
				
			||||
        emit stopPersonRecognition();
 | 
				
			||||
    }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
void RobotDogControlDialog::updateRobotStatus(int battery, double speed, double temperature)
 | 
				
			||||
{
 | 
				
			||||
    m_batteryProgress->setValue(battery);
 | 
				
			||||
    m_speedLabel->setText(QString("%1 m/s").arg(speed, 0, 'f', 1));
 | 
				
			||||
    m_temperatureLabel->setText(QString("%1°C").arg(temperature, 0, 'f', 1));
 | 
				
			||||
}
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue