Merge branch 'main' of https://bdgit.educoder.net/pp3xivymc/Software_Architecture
	
		
	
				
					
				
			
						commit
						ab677d5a12
					
				@ -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>
 | 
				
			||||
@ -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/
 | 
				
			||||
@ -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;
 | 
				
			||||
}
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue