Переглянути джерело

V1.2.6
1、修复了不一致检测不会报警的问题
2、修复了一些设置动态库的问题

Apple 3 тижнів тому
батько
коміт
58982b890c

+ 4 - 2
Server/CMakeLists.txt

@@ -25,8 +25,9 @@ file(GLOB LOCAL_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/ThreadCalculate/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/ThreadManager/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/DataManager/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/RTPServer/*.cpp
+
 
-    ${CMAKE_SOURCE_DIR}/RTPServer/*.cpp
     ${CMAKE_SOURCE_DIR}/common/DataManager/*.cpp
     ${CMAKE_SOURCE_DIR}/common/Network/*.cpp
     ${CMAKE_SOURCE_DIR}/common/GlobalInfo/*.cpp
@@ -73,8 +74,9 @@ target_include_directories(${this_exe} PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}/ThreadCalculate
     ${CMAKE_CURRENT_SOURCE_DIR}/ThreadManager
     ${CMAKE_CURRENT_SOURCE_DIR}/DataManager
+    ${CMAKE_CURRENT_SOURCE_DIR}/RTPServer
+
 
-    ${CMAKE_SOURCE_DIR}/RTPServer
     ${CMAKE_SOURCE_DIR}/common/DataManager
     ${CMAKE_SOURCE_DIR}/common/Network
     ${CMAKE_SOURCE_DIR}/common/GlobalInfo

+ 1 - 1
RTPServer/RtpOneRoadThread.cpp → Server/RTPServer/RtpOneRoadThread.cpp

@@ -249,7 +249,7 @@ bool RTPOneRoadThread::processUdpState()
         m_listClients.clear();
         m_localIP.clear();
         // m_localPort = -1;
-        emit signal_udpClosed(m_threadInfo.cardRoadInfo.pcmInfo.strPCMName);
+        emit signal_udpClosed(QString::fromStdString(m_threadInfo.cardRoadInfo.pcmInfo.strPCMName));
         /* 清空环形队列中的数据 */
         while(m_ringQueue.QueueSize() > 0)
         {

+ 1 - 1
RTPServer/RtpOneRoadThread.h → Server/RTPServer/RtpOneRoadThread.h

@@ -49,7 +49,7 @@ public:
 
 signals:
     /* 一个UDP关闭了,通知RTP服务,释放掉了一个本地端口 */
-    void signal_udpClosed(std::string pcmName);
+    void signal_udpClosed(QString pcmName);
     /* 用来触发槽函数 do_timerSendData 用于立刻处理UDP状态  */
     void signal_timerSendData();
 

+ 2 - 2
RTPServer/RtpServer.cpp → Server/RTPServer/RtpServer.cpp

@@ -208,9 +208,9 @@ void RTPServer::do_receiveMessage()
 }
 
 /* 一个通道UDP关闭的信号 */
-void RTPServer::do_udpClosed(std::string pcmName)
+void RTPServer::do_udpClosed(QString pcmName)
 {
-    SPDLOG_LOGGER_DEBUG(m_logger, "接收到释放本地端口的信号: 声卡PCM通道信息: {}", pcmName);
+    SPDLOG_LOGGER_DEBUG(m_logger, "接收到释放本地端口的信号: 声卡PCM通道信息: {}", pcmName.toStdString());
     
     // for(auto it = m_mapSoundCardRoadPorts.begin(); it != m_mapSoundCardRoadPorts.end(); ++it)
     // {

+ 1 - 1
RTPServer/RtpServer.h → Server/RTPServer/RtpServer.h

@@ -54,7 +54,7 @@ private slots:
     void do_receiveMessage();
 
     /* 接收到释放端口的信号 */
-    void do_udpClosed(std::string pcmName);
+    void do_udpClosed(QString pcmName);
 
     /* 处理心跳超时 */
     void do_heartbeatTimeout();

+ 0 - 0
RTPServer/Rtpcommon.cpp → Server/RTPServer/Rtpcommon.cpp


+ 0 - 0
RTPServer/Rtpcommon.h → Server/RTPServer/Rtpcommon.h


+ 19 - 11
Server/ThreadCalculate/ConsistencyCompareThread.cpp

@@ -276,11 +276,7 @@ bool ConsistencyCompareThread::compareConsistency()
         SPDLOG_LOGGER_ERROR(m_logger, "{} 一致性比对失败,可能是文件格式不支持或动态库加载失败", m_logBase);
         return false;
     }
-    /* 计算比对耗时 */
-    std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
-    std::chrono::duration<double> duration = endTime - startTime;
-    SPDLOG_LOGGER_DEBUG(m_logger, "{} 一致性比对耗时: {}ms", m_logBase, 
-        std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
+    
     /* 如果高相似度小于1,将两个通道反过来对比一下 */
     if(result->highest_similarity < 1)
     {
@@ -298,12 +294,21 @@ bool ConsistencyCompareThread::compareConsistency()
     //     m_logBase, m_wavFilePath1.fileName, m_wavFilePath2.fileName, result->highest_similarity, result->average_similarity);
 
     /* 保存结果 */
-    m_consistencyResult.AddResult(result->highest_similarity / 100.0);
-    m_similarity = result->highest_similarity / 100.0; // 保存相似度
+    double highestSimilarity = result->highest_similarity / 100.0; // 将相似度转换为0-1范围
+    double averageSimilarity = result->average_similarity / 100.0; // 将相似度转换为0-1范围
+    m_consistencyResult.AddResult(highestSimilarity);
+    m_similarity = highestSimilarity;
 
     delete result;
     result = nullptr;
 
+    /* 计算比对耗时 */
+    std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
+    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
+
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 一致性比对结果: 最高相似度: {:.3f}, 平均相似度: {:.3f}, 耗时: {}ms",
+        m_logBase, highestSimilarity, averageSimilarity, duration.count());
+
     return true;
 }
 
@@ -312,9 +317,12 @@ bool ConsistencyCompareThread::compareConsistency()
 /* 根据动态库返回的结果计算一致性 */
 bool ConsistencyCompareThread::computeResult()
 {
-    std::string strAIValue, strAIValueNot;
-    auto consistencyState = m_consistencyResult.computeConsistency(m_numCompareContinue, m_fConsistencyThreshold, strAIValue);
-    auto notConsisencyState = m_consistencyResult.computeNotConsistency(m_numCompareContinue, m_fNotConsistencyThreshold, strAIValueNot);
+    std::string strConInfo, strNotConInfo;
+    auto consistencyState = m_consistencyResult.computeConsistency(m_numCompareContinue, m_fConsistencyThreshold, strConInfo);
+    auto notConsisencyState = m_consistencyResult.computeNotConsistency(m_numCompareContinue, m_fNotConsistencyThreshold, strNotConInfo);
+
+    SPDLOG_LOGGER_DEBUG(m_logger, "{} 此次一致性计算结果: {}, 不一致性计算结果: {}, 一致性说明: {}, 不一致说明: {}",
+        m_logBase, static_cast<int>(consistencyState), static_cast<int>(notConsisencyState), strConInfo, strNotConInfo);
 
     if (eConsistencyState::eCS_Consistency == consistencyState)
     {
@@ -322,7 +330,7 @@ bool ConsistencyCompareThread::computeResult()
         m_isConsistency.store(true);
         m_isConsistencyWarning.store(false);
     }
-    else if(eConsistencyState::eCS_Consistency == notConsisencyState)
+    else if(eConsistencyState::eCS_NotConsistency == notConsisencyState)
     {
         /* 计算出的不一致性是确定的 */
         m_isConsistency.store(false);

+ 1 - 1
Server/ThreadManager/ThreadWriteDBManager.cpp

@@ -289,7 +289,7 @@ bool ThreadWriteDBManager::processFilePath(QString& strFilePath)
         注意: 这个函数需要在删除数据库记录之前执行,删除文件路径是从数据库中读取的 */
 void ThreadWriteDBManager::deleteTimeoutFile()
 {
-    if(m_lastDeleteFileTime.secsTo(m_currentTime) < 6)
+    if(m_lastDeleteFileTime.secsTo(m_currentTime) < 600)
     {
         return; // 十分钟检查一次
     }

+ 2 - 2
Server/ThreadRecord/AudioRecord/AudioRecord.cpp

@@ -166,8 +166,8 @@ bool AudioRecord::openRecordChannel(const std::string &deviceName)
 	 * 周期大小是指一个周期有多少个采样点,缓冲区大小是周期大小 * 周期个数,这里不需要设置周期个数
 	 * 直接设置缓冲区大小,系统会自动计算周期个数,缓冲区是个环形队列
 	 * 周期大小最好设置成可以被采样率的整数除尽,每次取出1秒数据的时候,间隔相差时间最短 */
-	snd_pcm_uframes_t buffer_size = m_sampleRate / 5; 		// 设置缓冲区大小为采样率的1/5秒
-	snd_pcm_uframes_t period_size = buffer_size / 10;	 	// 设置周期大小为缓冲区大小的1/10秒
+	// snd_pcm_uframes_t buffer_size = m_sampleRate / 5; 		// 设置缓冲区大小为采样率的1/5秒
+	// snd_pcm_uframes_t period_size = buffer_size / 10;	 	// 设置周期大小为缓冲区大小的1/10秒
 
 	_snd_pcm_format bit_frame = _snd_pcm_format::SND_PCM_FORMAT_UNKNOWN;
 	if(m_bitDepth == 8)

+ 2 - 0
SettingLibrary/CMakeLists.txt

@@ -39,6 +39,7 @@ file(GLOB LOCAL_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/AICompare/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Basic/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Basic/TableHeader/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Basic/TableDelegate/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/CheckPeriod/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/CheckPeriod/CPushButtonTime/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Database/*.cpp
@@ -105,6 +106,7 @@ target_include_directories(${libName} PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/AICompare
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Basic
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Basic/TableHeader
+    ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Basic/TableDelegate
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/CheckPeriod
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/CheckPeriod/CPushButtonTime
     ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Database

+ 126 - 0
SettingLibrary/Modules/Basic/TableDelegate/DelegateCheckBox.cpp

@@ -0,0 +1,126 @@
+#include "DelegateCheckBox.h"
+
+
+
+#include <QCheckBox>
+#include <QPainter>
+#include <QApplication>
+#include <QStyleOptionViewItem>
+
+#include "spdlog/spdlog.h"
+
+
+DelegateCheckBox::DelegateCheckBox(QObject *parent) 
+    : QStyledItemDelegate(parent)
+{
+}
+
+
+DelegateCheckBox::~DelegateCheckBox()
+{
+
+}
+
+QWidget* DelegateCheckBox::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    // QCheckBox *checkBox = new QCheckBox(parent);
+    // checkBox->setText("Check me");
+    // return checkBox;
+    return nullptr;
+}
+
+void DelegateCheckBox::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+
+}
+
+void DelegateCheckBox::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+
+}
+
+void DelegateCheckBox::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+
+}
+
+
+void DelegateCheckBox::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    /* 获取复选框状态 */
+    Qt::CheckState checkState = static_cast<Qt::CheckState>(index.data(Qt::CheckStateRole).toInt());
+    /* 获取文本 */
+    QString text = index.data(Qt::DisplayRole).toString();
+
+    /* 自定义颜色 */
+    QColor backgroundColor = QColor(255, 255, 255);     /* 背景色 */
+    QColor hightLightColor = QColor("#EEF2FF");       /* 选中高亮颜色 */
+
+
+    /* ------------------------ 绘制背景 ------------------------ */
+    if (option.state & QStyle::State_Selected) 
+    {
+        painter->fillRect(option.rect, hightLightColor);
+        // SPDLOG_INFO("选中状态: {}, 选中颜色: {}", true, hightLightColor.name().toStdString());
+    } else 
+    {
+        painter->fillRect(option.rect, backgroundColor);
+        // SPDLOG_INFO("选中状态: {}, 选中颜色: {}", false, opt.palette.base().color().name().toStdString());
+    }
+
+    /* ------------------------ 绘制选择框 ------------------------ */
+    QRect selectIconRect = QRect(option.rect.left() + 12, option.rect.top() + (option.rect.height() - 20) / 2, 20, 20);
+    QString selectIconPath = GetCheckboxImage(checkState);
+    painter->drawPixmap(selectIconRect, QPixmap(selectIconPath));
+    
+
+    // QStyleOptionButton checkBoxOption;
+    // QRect checkBoxRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkBoxOption);
+    // checkBoxOption.rect = QRect(option.rect.left(), option.rect.top() + (option.rect.height() - checkBoxRect.height()) / 2, checkBoxRect.width(), checkBoxRect.height());
+    // checkBoxOption.state = QStyle::State_Enabled | (checked ? QStyle::State_On : QStyle::State_Off);
+
+    // 绘制复选框
+    // QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxOption, painter);
+
+    // 绘制文本
+    QRect textRect = option.rect;
+    textRect.setLeft(selectIconRect.right() + 4); // 复选框后留点间距
+    painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, text);
+}
+
+
+
+
+
+bool DelegateCheckBox::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
+{
+    // if (event->type() == QEvent::MouseButtonRelease) 
+    // {
+    //     // Handle checkbox toggle logic here
+    //     bool currentState = index.data(Qt::CheckStateRole).toBool();
+    //     model->setData(index, !currentState, Qt::CheckStateRole);
+    //     return true;
+    // }
+    return QStyledItemDelegate::editorEvent(event, model, option, index);
+}
+
+
+QString DelegateCheckBox::GetCheckboxImage(Qt::CheckState state) const
+{
+    if(state == Qt::Unchecked)
+    {
+        return ":/icon/unchecked.png";
+    }else {
+        return ":/icon/checked.png";
+    }
+    // else if(state == Qt::PartiallyChecked)
+    // {
+    //     return ":/icon/partially_checked.png";
+    // }
+    // else if(state == Qt::Checked)
+    // {
+    //     return ":/icon/checked.png";
+    // }
+    return "";
+}
+

+ 34 - 0
SettingLibrary/Modules/Basic/TableDelegate/DelegateCheckBox.h

@@ -0,0 +1,34 @@
+#ifndef __DELEGATE_CHECKBOX_H__
+#define __DELEGATE_CHECKBOX_H__
+
+
+#include <QStyledItemDelegate>
+
+
+class DelegateCheckBox : public QStyledItemDelegate
+{
+    Q_OBJECT
+
+public:
+    explicit DelegateCheckBox(QObject *parent = nullptr);
+    ~DelegateCheckBox() override;
+
+    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
+    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
+    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+
+    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+
+protected:
+    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
+
+private:
+    /* 获取图片 */
+    QString GetCheckboxImage(Qt::CheckState state) const;
+
+};
+
+
+
+#endif // __DELEGATE_CHECKBOX_H__

+ 1 - 0
SettingLibrary/Modules/Basic/TableHeader/baseheader.h

@@ -23,6 +23,7 @@ public:
     void SetCheckable(bool value);
     void SetChecked(Qt::CheckState state);
     QString GetText(int logicalIndex);//获取表头名称 add by wl 2023-06-26
+    Qt::CheckState GetChecked() const { return m_checkState; }      /* 获取checkBox状态,add by ztl,2025-08-22 */
 protected:
     void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override;
 

+ 199 - 65
SettingLibrary/Modules/Basic/compareitemlistdialog.cpp

@@ -1,4 +1,4 @@
-#include "compareitemlistdialog.h"
+#include "compareitemlistdialog.h"
 #include "ui_compareitemlistwidget.h"
 
 
@@ -13,6 +13,7 @@
 #include "warning.h"
 #include "compareitemdetailwidget.h"
 #include "baseheader.h"
+#include "DelegateCheckBox.h"
 
 
 /* 重载比较函数 */
@@ -65,7 +66,7 @@ CompareItemListDialog::CompareItemListDialog(QWidget *parent) :
     /* 设置标题 */
     setTitle("对比项列表", QSize(120, 18));
 
-    UIStyle.registerWidget(widgetContent);
+    // UIStyle.registerWidget(widgetContent);
     
 
     // SPDLOG_LOGGER_DEBUG(m_logger, "ObjectName: {}", widgetContent->objectName().toStdString());
@@ -79,12 +80,11 @@ CompareItemListDialog::CompareItemListDialog(QWidget *parent) :
     connect(ui->pBtn_enableCPItem, &QPushButton::clicked, this, &CompareItemListDialog::do_pBtn_enable_Clicked);
     connect(ui->pBtn_disableCPItem, &QPushButton::clicked, this, &CompareItemListDialog::do_pBtn_disable_Clicked);
 
-    connect(ui->tableView, &QTableView::doubleClicked, this, &CompareItemListDialog::do_tableView_doubleClicked);
 
     /* 初始化表格 */
     initTable();
 
-    
+    UIStyle.registerWidget(widgetContent);
 }
 
 CompareItemListDialog::~CompareItemListDialog()
@@ -145,7 +145,7 @@ void CompareItemListDialog::do_pBtn_add_Clicked()
 void CompareItemListDialog::do_pBtn_delete_Clicked()
 {
     /* 获取是否有选中的行 */
-    QModelIndexList selectedRows = ui->tableView->selectionModel()->selectedRows();
+    const QModelIndexList selectedRows = ui->tableView->selectionModel()->selectedRows();
     if(selectedRows.isEmpty())
     {
         TipWidget::display(TipWidget::OPERATOR_WARN, "请先选择要删除的对比项", GInfo.getTopWindow());
@@ -164,12 +164,36 @@ void CompareItemListDialog::do_pBtn_delete_Clicked()
     for(const QModelIndex& index : selectedRows)
     {
         /* 获取对比项ID */
-        int nID = m_model->data(m_model->index(index.row(), 0), m_userRole_CompareItemID).toInt();
+        // int nID = m_model->data(m_model->index(index.row(), 0), m_userRole_CompareItemID).toInt();
+        // int nID = m_model->data(index, m_userRole_CompareItemID).toInt();
+        int nID = index.data(m_userRole_CompareItemID).toInt();
+        // SPDLOG_LOGGER_INFO(m_logger, "删除对比项ID: {}", nID);
         /* 从全局对比项数据中删除 */
         CIData.removeCompareItem(nID);
-        /* 从表格模型中删除 */
-        m_model->removeRow(index.row());
+        
     }
+
+    /* 删除表格中的数据,需要倒叙删除,因为 selectedRows 也会继续向 m_model 获取数据 */
+    for (int i = selectedRows.size() - 1; i >= 0; --i) 
+    {
+        m_model->removeRow(selectedRows[i].row());
+    }
+    // for(const QModelIndex& index : selectedRows)
+    // {
+    //     /* 获取对比项ID */
+    //     int nID = index.data(m_userRole_CompareItemID).toInt();
+    //     SPDLOG_LOGGER_WARN(m_logger, "删除对比项ID: {}", nID);
+
+    //     /* 从表格模型中删除 */
+    //     for(int i = 0; i < m_model->rowCount(); ++i)
+    //     {
+    //         if(m_model->data(m_model->index(i, 0), m_userRole_CompareItemID).toInt() == nID)
+    //         {
+    //             m_model->removeRow(i);
+    //             break;
+    //         }
+    //     }
+    // }
 }
 
 /* 点击了编辑按钮 */
@@ -231,34 +255,37 @@ void CompareItemListDialog::do_pBtn_enable_Clicked()
         TipWidget::display(TipWidget::OPERATOR_WARN, "请先选择要修改的对比项", GInfo.getTopWindow());
         return;
     }
-    /* 只取出第一个 */
-    QModelIndex index = selectedRows.first();
-    /* 获取对比项ID */
-    int nID = m_model->data(m_model->index(index.row(), 0), m_userRole_CompareItemID).toInt();
-    /* 查找对比项信息 */
-    CompareItemInfo_t ciInfo = CIData.findCompareItemByID(nID);
-    if(ciInfo.nID < 0)
-    {
-        TipWidget::display(TipWidget::OPERATOR_WARN, "对比项不存在,无法启用", GInfo.getTopWindow());
-        SPDLOG_LOGGER_WARN(m_logger, "对比项ID {} 不存在,无法启用", nID);
-        return;
-    }
-    /* 判断是否已经启用 */
-    if(ciInfo.isEnable)
-    {
-        TipWidget::display(TipWidget::OPERATOR_OK, "对比项已经处于启用状态", GInfo.getTopWindow());
-        return; /* 如果已经启用,直接返回 */
-    }
-    /* 修改对比项状态为启用 */
-    ciInfo.isEnable = true;
-    if(!CIData.modifyCompareItem(ciInfo))
+    for(auto& index : selectedRows)
     {
-        TipWidget::display(TipWidget::OPERATOR_WARN, "对比项启用失败,请稍后重试", GInfo.getTopWindow());
-        SPDLOG_LOGGER_ERROR(m_logger, "对比项ID {} 启用失败", nID);
-        return;
+        /* 获取对比项ID */
+        int nID = m_model->data(m_model->index(index.row(), 0), m_userRole_CompareItemID).toInt();
+        /* 查找对比项信息 */
+        CompareItemInfo_t ciInfo = CIData.findCompareItemByID(nID);
+        if(ciInfo.nID < 0)
+        {
+            TipWidget::display(TipWidget::OPERATOR_WARN, "对比项不存在,无法启用", GInfo.getTopWindow());
+            SPDLOG_LOGGER_WARN(m_logger, "对比项ID {} 不存在,无法启用", nID);
+            return;
+        }
+        /* 判断是否已经启用 */
+        if(ciInfo.isEnable)
+        {
+            // TipWidget::display(TipWidget::OPERATOR_OK, "对比项已经处于启用状态", GInfo.getTopWindow());
+            return; /* 如果已经启用,直接返回 */
+        }
+        /* 修改对比项状态为启用 */
+        ciInfo.isEnable = true;
+        if(!CIData.modifyCompareItem(ciInfo))
+        {
+            TipWidget::display(TipWidget::OPERATOR_WARN, "对比项启用失败,请稍后重试", GInfo.getTopWindow());
+            SPDLOG_LOGGER_ERROR(m_logger, "对比项ID {} 启用失败", nID);
+            return;
+        }
+        /* 更新表格中的状态 */
+        m_model->setData(m_model->index(index.row(), 1), "启用");
     }
-    /* 更新表格中的状态 */
-    m_model->setData(m_model->index(index.row(), 1), "启用");
+
+    
 }
 
 /* 禁用对比项 */
@@ -271,34 +298,35 @@ void CompareItemListDialog::do_pBtn_disable_Clicked()
         TipWidget::display(TipWidget::OPERATOR_WARN, "请先选择要修改的对比项", GInfo.getTopWindow());
         return;
     }
-    /* 只取出第一个 */
-    QModelIndex index = selectedRows.first();
-    /* 获取对比项ID */
-    int nID = m_model->data(m_model->index(index.row(), 0), m_userRole_CompareItemID).toInt();
-    /* 查找对比项信息 */
-    CompareItemInfo_t ciInfo = CIData.findCompareItemByID(nID);
-    if(ciInfo.nID < 0)
-    {
-        TipWidget::display(TipWidget::OPERATOR_WARN, "对比项不存在,无法禁用", GInfo.getTopWindow());
-        SPDLOG_LOGGER_WARN(m_logger, "对比项ID {} 不存在,无法禁用", nID);
-        return;
-    }
-    /* 判断是否已经启用 */
-    if(!ciInfo.isEnable)
+    for(auto& index : selectedRows)
     {
-        TipWidget::display(TipWidget::OPERATOR_OK, "对比项已经处于禁用状态", GInfo.getTopWindow());
-        return;
-    }
-    /* 修改对比项状态为启用 */
-    ciInfo.isEnable = false;
-    if(!CIData.modifyCompareItem(ciInfo))
-    {
-        TipWidget::display(TipWidget::OPERATOR_WARN, "对比项禁用失败,请稍后重试", GInfo.getTopWindow());
-        SPDLOG_LOGGER_ERROR(m_logger, "对比项ID {} 禁用失败", nID);
-        return;
+        /* 获取对比项ID */
+        int nID = m_model->data(m_model->index(index.row(), 0), m_userRole_CompareItemID).toInt();
+        /* 查找对比项信息 */
+        CompareItemInfo_t ciInfo = CIData.findCompareItemByID(nID);
+        if(ciInfo.nID < 0)
+        {
+            TipWidget::display(TipWidget::OPERATOR_WARN, "对比项不存在,无法禁用", GInfo.getTopWindow());
+            SPDLOG_LOGGER_WARN(m_logger, "对比项ID {} 不存在,无法禁用", nID);
+            return;
+        }
+        /* 判断是否已经启用 */
+        if(!ciInfo.isEnable)
+        {
+            // TipWidget::display(TipWidget::OPERATOR_OK, "对比项已经处于禁用状态", GInfo.getTopWindow());
+            return;
+        }
+        /* 修改对比项状态为启用 */
+        ciInfo.isEnable = false;
+        if(!CIData.modifyCompareItem(ciInfo))
+        {
+            TipWidget::display(TipWidget::OPERATOR_WARN, "对比项禁用失败,请稍后重试", GInfo.getTopWindow());
+            SPDLOG_LOGGER_ERROR(m_logger, "对比项ID {} 禁用失败", nID);
+            return;
+        }
+        /* 更新表格中的状态 */
+        m_model->setData(m_model->index(index.row(), 1), "未启用");
     }
-    /* 更新表格中的状态 */
-    m_model->setData(m_model->index(index.row(), 1), "未启用");
 }
 
 
@@ -330,6 +358,99 @@ void CompareItemListDialog::do_tableView_doubleClicked(const QModelIndex &index)
 }
 
 
+/* 表格点击了一行 */
+void CompareItemListDialog::do_tableView_clicked(const QModelIndex &index)
+{
+    if(index.column() == 4)
+    {
+        /* 打开对比项详情弹窗 */
+        do_tableView_doubleClicked(index);
+        return;
+    }
+    // int row = index.row();
+    // /* 修改第一列状态 */
+    // bool currentState = m_model->data(m_model->index(row, 0), Qt::CheckStateRole).toBool();
+    // bool nextState = !currentState;
+    // m_model->setData(m_model->index(row, 0), nextState, Qt::CheckStateRole);
+}
+
+/* 修改了选择行的状态 */
+void CompareItemListDialog::do_selectChanged(const QItemSelection &selected, const QItemSelection &deselected)
+{
+    /* 这里获取的是选中的所有单元格数目 */
+    QModelIndexList selectedRows = selected.indexes();
+    QModelIndexList deselectedRows = deselected.indexes();
+    if(selectedRows.isEmpty() && deselectedRows.isEmpty())
+    {
+        /* 如果没有选中行,直接返回 */
+        return;
+    }
+
+    /* 更新第一列的状态 */
+    for(const QModelIndex& index : selectedRows)
+    {
+        // bool currentState = m_model->data(m_model->index(index.row(), 0), Qt::CheckStateRole).toBool();
+        m_model->setData(m_model->index(index.row(), 0), Qt::Checked, Qt::CheckStateRole);
+    }
+    /* 如果有取消选择的行,更新第一列状态 */
+    for(const QModelIndex& index : deselectedRows)
+    {
+        // bool currentState = m_model->data(m_model->index(index.row(), 0), Qt::CheckStateRole).toBool();
+        m_model->setData(m_model->index(index.row(), 0), Qt::Unchecked, Qt::CheckStateRole);
+    }
+    
+    /* 更新标题栏选中的状态,下面获取的才是真正的选中的行 */
+    int selectedCount = ui->tableView->selectionModel()->selectedRows().size();
+    Qt::CheckState headerState = Qt::Unchecked;
+    if(selectedCount == m_model->rowCount())
+    {
+        headerState = Qt::CheckState::Checked;
+    }else if(selectedCount == 0)
+    {
+        headerState = Qt::CheckState::Unchecked;
+    }else {
+        headerState = Qt::CheckState::PartiallyChecked;
+    }
+
+    // SPDLOG_LOGGER_INFO(m_logger, "选中行数: {}, 总行数: {}, 标题状态: {}", selectedCount, m_model->rowCount(), static_cast<int>(headerState));
+    /* 如果选中的行数等于总行数,说明全部选中 */
+    auto header = qobject_cast<BaseHeader*>(ui->tableView->horizontalHeader());
+    if(header)
+    {
+        header->SetChecked(headerState);
+    }
+
+}
+
+
+/* 点击了标题栏选择框 */
+void CompareItemListDialog::do_headerSelect_clicked(bool state)
+{
+    auto header = qobject_cast<BaseHeader*>(ui->tableView->horizontalHeader());
+    if(header == nullptr)
+    {
+        return;
+    }
+    if(state)
+    {
+        for(int i = 0; i < m_model->rowCount(); ++i)
+        {
+            /* 设置第一列为选中状态 */
+            m_model->setData(m_model->index(i, 0), Qt::Checked, Qt::CheckStateRole);
+            ui->tableView->selectionModel()->select(m_model->index(i, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+        }
+    }else 
+    {
+        for(int i = 0; i < m_model->rowCount(); ++i)
+        {
+            /* 设置第一列为未选中状态 */
+            m_model->setData(m_model->index(i, 0), Qt::Unchecked, Qt::CheckStateRole);
+            ui->tableView->selectionModel()->select(m_model->index(i, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+        }
+    }
+}
+
+
 /* 初始化表格 */
 void CompareItemListDialog::initTable()
 {
@@ -351,20 +472,27 @@ void CompareItemListDialog::initTable()
     // m_sortModel->setSortRole(QtUserRole::UserRole_Time); /* 设置排序角色 */
     ui->tableView->setModel(m_model);
 
-    // 设置选择模式为整行选择
+    /* 设置标题头部代理 */
     auto oneHeader = new BaseHeader(ui->tableView);
     oneHeader->SetCheckable(true);
     ui->tableView->setHorizontalHeader(oneHeader);
-    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
+
+    /* 设置选择属性 */
+    ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection); /* 可多选 */
     ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
 
+    /* 设置第一列代理 */
+    auto checkBoxDelegate = new DelegateCheckBox(ui->tableView);
+    /* 设置多种选择状态 */
+    ui->tableView->setItemDelegateForColumn(0, checkBoxDelegate);
+
     /*--------------------------- 设置横向标题 -------------------------------*/
     /* 设置横向标题可见 */
     ui->tableView->horizontalHeader()->setVisible(true);
     /* 设置标题左对齐 */
     ui->tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
-    /* 设置横向标题可点击 */
-    ui->tableView->horizontalHeader()->setSectionsClickable(false);
+    /* 设置横向标题可点击 */
+    ui->tableView->horizontalHeader()->setSectionsClickable(true);
 
     /*--------------------------- 设置列 -------------------------------*/
     /* 设置每列的高度 */
@@ -390,6 +518,13 @@ void CompareItemListDialog::initTable()
     ui->tableView->setColumnWidth(3, 280);  /* 第四列宽度 */
     ui->tableView->setColumnWidth(4, 96);   /* 第五列宽度 */
 
+    /* 连接点击信号 */
+    // connect(ui->tableView, &QTableView::doubleClicked, this, &CompareItemListDialog::do_tableView_doubleClicked);
+    connect(ui->tableView, &QTableView::clicked, this, &CompareItemListDialog::do_tableView_clicked);
+    connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
+            this, &CompareItemListDialog::do_selectChanged);
+    connect(oneHeader, &BaseHeader::sig_Checked, this, &CompareItemListDialog::do_headerSelect_clicked);
+
     /* 测试用,加入两列数据 */
     // for(int i = 0; i < 10; ++i)
     // {
@@ -429,7 +564,6 @@ void CompareItemListDialog::addRow(CompareItemTableItem_t tableItem)
     /* 这个字体设置为蓝色 */
     item4->setForeground(QBrush("#438EFF"));
     items.append(item4);
-    
 
     m_model->appendRow(items);
 }

+ 7 - 0
SettingLibrary/Modules/Basic/compareitemlistdialog.h

@@ -67,6 +67,13 @@ private slots:
     /* 显示详情 */
     void do_tableView_doubleClicked(const QModelIndex &index);
 
+    /* 表格点击了一行 */
+    void do_tableView_clicked(const QModelIndex &index);
+    /* 修改了选择行的状态 */
+    void do_selectChanged(const QItemSelection &selected, const QItemSelection &deselected);
+    /* 点击了标题栏选择框 */
+    void do_headerSelect_clicked(bool state);
+
 private:
     /* 初始化表格 */
     void initTable();

+ 3 - 1
文档/保存的命令.txt

@@ -1 +1,3 @@
-scp ACAServer TEST@192.1.2.129:~/Desktop
+scp ACAServer TEST@192.1.2.129:~/Desktop
+
+scp ACAServer TEST@192.1.2.129:~/Desktop/ACA对比系统/files/bin