From 9d1164e33684a870028634b1a09aa3e8367514e1 Mon Sep 17 00:00:00 2001 From: anxinglong <2910824064@qq.com> Date: Mon, 29 Jun 2026 18:50:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=88=86=E6=9E=90=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=EF=BC=88=E5=8F=AF?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=AD=98=E5=9C=A8=E9=97=AE=E9=A2=98=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=95=88=E7=8E=87=E5=88=BB=E5=BA=A6?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=EF=BC=88=E5=8A=9F=E8=83=BD=E6=9C=AA=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/EfficiencyScale.cpp | 14 + src/EfficiencyScale.h | 22 + src/EfficiencyScale.ui | 342 +++++++++ src/MainWindow.cpp | 26 +- src/MainWindow.h | 4 + src/MainWindow.ui | 11 +- .../NuclideAnalysisView.cpp | 2 + src/analysisReport/reportgenerator.cpp | 687 ++++++++++++++++++ src/analysisReport/reportgenerator.h | 68 ++ src/analysisReport/reportwidget.cpp | 345 +++++++++ src/analysisReport/reportwidget.h | 96 +++ src/analysisReport/spectrumdata.cpp | 109 +++ src/analysisReport/spectrumdata.h | 114 +++ src/src.pro | 23 +- 14 files changed, 1857 insertions(+), 6 deletions(-) create mode 100644 src/EfficiencyScale.cpp create mode 100644 src/EfficiencyScale.h create mode 100644 src/EfficiencyScale.ui create mode 100644 src/analysisReport/reportgenerator.cpp create mode 100644 src/analysisReport/reportgenerator.h create mode 100644 src/analysisReport/reportwidget.cpp create mode 100644 src/analysisReport/reportwidget.h create mode 100644 src/analysisReport/spectrumdata.cpp create mode 100644 src/analysisReport/spectrumdata.h diff --git a/src/EfficiencyScale.cpp b/src/EfficiencyScale.cpp new file mode 100644 index 0000000..ccc0953 --- /dev/null +++ b/src/EfficiencyScale.cpp @@ -0,0 +1,14 @@ +#include "EfficiencyScale.h" +#include "ui_EfficiencyScale.h" + +EfficiencyScale::EfficiencyScale(QWidget *parent) + : QDialog(parent) + , ui(new Ui::EfficiencyScale) +{ + ui->setupUi(this); +} + +EfficiencyScale::~EfficiencyScale() +{ + delete ui; +} diff --git a/src/EfficiencyScale.h b/src/EfficiencyScale.h new file mode 100644 index 0000000..a87ae40 --- /dev/null +++ b/src/EfficiencyScale.h @@ -0,0 +1,22 @@ +#ifndef EFFICIENCYSCALE_H +#define EFFICIENCYSCALE_H + +#include + +namespace Ui { +class EfficiencyScale; +} + +class EfficiencyScale : public QDialog +{ + Q_OBJECT + +public: + explicit EfficiencyScale(QWidget *parent = nullptr); + ~EfficiencyScale(); + +private: + Ui::EfficiencyScale *ui; +}; + +#endif // EFFICIENCYSCALE_H diff --git a/src/EfficiencyScale.ui b/src/EfficiencyScale.ui new file mode 100644 index 0000000..84db787 --- /dev/null +++ b/src/EfficiencyScale.ui @@ -0,0 +1,342 @@ + + + EfficiencyScale + + + + 0 + 0 + 1173 + 709 + + + + Dialog + + + + + + 效率刻度管理列表 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 添加 + + + + + + + 删除 + + + + + + + + + + + + + + + + + + 效率刻度信息 + + + + + + + + + 85 + 0 + + + + 效率刻度命名: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + 85 + 0 + + + + 备注说明: + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + 保存 + + + + + + + 另存为 + + + + + + + + + + + 公式拟合 + + + + + + 拟合公式: + + + + + + + + + + 0 + 0 + + + + + + + + 拟合 + + + + + + + + + + 287 + 0 + + + + y = a + bx + + + + + + + + 287 + 0 + + + + a = 1.21823, b = -5.0542 + + + + + + + + + + Qt::Horizontal + + + + + + + 效率刻度拟合数据 + + + + + + + + + 新增 + + + + + + + 删除 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + + + + + + + + 0 + 0 + + + + true + + + + 序号 + + + + + 能量(key) + + + + + 净计数率 + + + + + 探测效率 + + + + + 拟合效率 + + + + + 误差 + + + + + 刻度日期 + + + + + + + + + + + diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ed4b66e..62e63e5 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -36,6 +36,7 @@ #include "EnergyScaleDataModel.h" #include "EnergyCountPlotView.h" #include "ParticleCountPlotView.h" +#include "reportwidget.h" #include #include "csv.h" #include @@ -868,4 +869,27 @@ void MainWindow::onParticleEnergyDataUpdated(const QString &energySpectrumFilena // 更新数据表格 // updataTable(); -} \ No newline at end of file +} +void MainWindow::on_action_analysisReport_triggered() +{ + ReportWidget *widget = new ReportWidget(); + widget->show(); +} + +#include "EfficiencyScale.h" +void MainWindow::on_action_efficiency_scale_mrg_triggered() +{ + // QDialog energy_scale_mrg_dlg; + // energy_scale_mrg_dlg.setObjectName("EfficiencyScaleFormDlg"); + // energy_scale_mrg_dlg.setWindowTitle(QStringLiteral(u"效率刻度管理")); + // energy_scale_mrg_dlg.setWindowFlags(energy_scale_mrg_dlg.windowFlags() | Qt::WindowMaximizeButtonHint); + EfficiencyScale* efficiency_scale_mrg_form = new EfficiencyScale(); + efficiency_scale_mrg_form->setWindowTitle(QStringLiteral(u"效率刻度管理")); + efficiency_scale_mrg_form->setWindowFlags(efficiency_scale_mrg_form->windowFlags() | Qt::WindowMaximizeButtonHint); + + // QHBoxLayout* hlayout = new QHBoxLayout; + // hlayout->addWidget(efficiency_scale_mrg_form); + // efficiency_scale_mrg_form.setLayout(hlayout); + efficiency_scale_mrg_form->exec(); +} + diff --git a/src/MainWindow.h b/src/MainWindow.h index 6d20e48..2bddd6c 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -106,6 +106,10 @@ private slots: void onMeasureStopped(bool success, const QString& message); void onDeviceStatusMessage(const QString& msg); + void on_action_analysisReport_triggered(); + + void on_action_efficiency_scale_mrg_triggered(); + private: QMutex _mutex_info_output; QPlainTextEdit* _plain_edit_info_output; diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 4c6a27e..3cfca22 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -20,7 +20,7 @@ 0 0 1079 - 22 + 21 @@ -112,6 +112,7 @@ + @@ -230,6 +231,14 @@ QAction::TextHeuristicRole + + + 分析报告自动生成 + + + QAction::NoRole + + diff --git a/src/NuclideAnalysisView/NuclideAnalysisView.cpp b/src/NuclideAnalysisView/NuclideAnalysisView.cpp index 82fa6bd..231a4f8 100644 --- a/src/NuclideAnalysisView/NuclideAnalysisView.cpp +++ b/src/NuclideAnalysisView/NuclideAnalysisView.cpp @@ -321,6 +321,8 @@ void NuclideAnalysisView::onActionPlotClear() m_allFitResults.clear(); + m_nuclideTable->setRowCount(0); + m_bSelecting = false; m_bSelectHS = false; diff --git a/src/analysisReport/reportgenerator.cpp b/src/analysisReport/reportgenerator.cpp new file mode 100644 index 0000000..1ca94ef --- /dev/null +++ b/src/analysisReport/reportgenerator.cpp @@ -0,0 +1,687 @@ +#include "reportgenerator.h" +#include +#include +#include + +ReportGenerator::ReportGenerator() +{ +} + +void ReportGenerator::setData(const SpectrumReportData &data) +{ + m_data = data; +} + +QString ReportGenerator::formatScientific(double value, int precision) const +{ + if (value == 0.0) { + return QString("0.0000E+00"); + } + + // 格式化为科学计数法,类似 2.7056E-01 + QString result = QString::number(value, 'E', precision); + + // 确保指数部分有两位 + QStringList parts = result.split('E'); + if (parts.size() == 2) { + QString mantissa = parts[0]; + QString exponent = parts[1]; + + // 处理指数符号和位数 + QChar sign = exponent[0]; + QString num = exponent.mid(1); + bool ok; + int expNum = num.toInt(&ok); + if (ok) { + exponent = QString("%1%2").arg(sign).arg(QString::number(expNum).rightJustified(2, '0')); + } + result = QString("%1E%2").arg(mantissa).arg(exponent); + } + + return result; +} + +QString ReportGenerator::formatDecimal(double value, int precision) const +{ + return QString::number(value, 'f', precision); +} + +QString ReportGenerator::formatDateTime(const QDateTime &dt) const +{ + return dt.toString("yyyy/M/d hh:mm:ss"); +} + +QString ReportGenerator::generateHtmlHeader() const +{ + return R"( + + + + + 符合能谱分析报告 + + + +)"; +} + +QString ReportGenerator::generateMeasurementSection() const +{ + QString html; + html += QString("
能谱文件:%1
") + .arg(m_data.measurement.spectrumFile); + + html += "
测量参数
"; + html += ""; + html += QString("" + "") + .arg(formatDateTime(m_data.measurement.startTime)) + .arg(formatDecimal(m_data.measurement.liveTime, 0)); + html += QString("" + "") + .arg(formatDecimal(m_data.measurement.realTime, 0)) + .arg(formatDecimal(m_data.measurement.deadTime, 2)); + html += "
开始时间:%1活时间(S):%2
实时间(S):%1死时间:%2 %
"; + + return html; +} + +QString ReportGenerator::generateCalibrationSection() const +{ + QString html; + html += "
刻度
"; + html += ""; + html += QString("" + "") + .arg(m_data.calibration.fileName) + .arg(m_data.calibration.standardSource); + html += "
文件:%1刻度标准源:%2
"; + + // 能量刻度 + html += "
"; + html += "
能量刻度
"; + html += ""; + html += QString("" + "") + .arg(formatDateTime(m_data.calibration.energy.generateTime)) + .arg(formatDecimal(m_data.calibration.energy.intercept, 3)); + html += QString("" + "") + .arg(formatDecimal(m_data.calibration.energy.slope, 3)) + .arg(formatScientific(m_data.calibration.energy.quadratic, 3)); + html += "
生成时间:%1截距:%2 keV
斜率:%1 keV/ch二次项系数:%2 keV/(ch^2)
"; + html += "
"; + + // 效率刻度 + html += "
"; + html += "
效率刻度
"; + html += ""; + html += QString("" + "") + .arg(formatDateTime(m_data.calibration.efficiency.generateTime)) + .arg(formatDecimal(m_data.calibration.efficiency.inflectionEnergy, 2)); + html += QString("" + "") + .arg(m_data.calibration.efficiency.aboveInflection) + .arg(formatDecimal(m_data.calibration.efficiency.aboveError, 2)); + html += QString("" + "") + .arg(m_data.calibration.efficiency.belowInflection) + .arg(formatDecimal(m_data.calibration.efficiency.belowError, 2)); + html += QString("") + .arg(m_data.calibration.efficiency.logEquation); + html += "
生成时间:%1拐点能量(keV):%2
拐点以上:%1误差:%2%
拐点以下:%1误差:%2%
效率对数方程式:%1
"; + html += "
"; + + return html; +} + +QString ReportGenerator::generateNuclideLibSection() const +{ + QString html; + html += "
核素库
"; + html += ""; + html += QString("" + "") + .arg(m_data.nuclideLib.fileName) + .arg(formatDecimal(m_data.nuclideLib.peakMatchWidth, 3)); + html += "
文件:%1峰匹配宽度(keV):%2 * FWHM
"; + + return html; +} + +QString ReportGenerator::generateAnalysisSection() const +{ + QString html; + html += "
分析参数
"; + html += ""; + html += QString("" + "") + .arg(formatDecimal(m_data.analysis.startEnergy, 2)) + .arg(formatDecimal(m_data.analysis.endEnergy, 2)); + html += QString("" + "") + .arg(formatDecimal(m_data.analysis.statErrorLimit, 3)) + .arg(formatScientific(m_data.analysis.activityRatio, 4)); + html += QString("") + .arg(m_data.analysis.mdaMethod); + html += "
起始能量(keV):%1终止能量(keV):%2
统计误差限值:%1%活度比例系数:%2
探测限计算方法:%1
"; + + return html; +} + +QString ReportGenerator::generatePeakTableSection() const +{ + QString html; + html += "
能 谱 峰 一 览 表
"; + html += ""; + + // 表头 - 第一行 + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + + // 表头 - 第二行 + html += ""; + html += ""; // 峰子项1 + html += ""; // 峰子项2 + html += ""; // 峰子项3 + html += ""; // 峰子项4 + html += ""; + + // 数据行(8列,与表头对应) + for (const auto& peak : m_data.peaks) { + html += ""; + html += QString("").arg(peak.nuclide); + html += QString("").arg(formatScientific(peak.avgActivity, 4)); + html += QString("").arg(formatDecimal(peak.avgUncertainty, 2)); + html += QString("").arg(formatDecimal(peak.energy, 2)); + html += QString("").arg(formatScientific(peak.peakActivity, 3)); + html += QString("").arg(formatDecimal(peak.peakUncertainty, 2)); + html += QString("").arg(formatScientific(peak.mda, 3)); + html += QString("").arg(peak.remark); + html += ""; + } + + html += "
核素平均活度(贝克Bq)不确定度备注
能量keV活度(贝克Bq)不确定度最小可探测活度(MDA)(贝克Bq)
%1%1%1%%1%1%1%%1%1
"; + + // 峰提示码说明 + html += "
"; + html += "
峰提示码说明:
"; + html += "
G - γ射线
"; + html += "
X - X射线
"; + html += "
ec - 内转换电子
"; + html += "
"; + + return html; +} + +QString ReportGenerator::generateSignatureSection() const +{ + QString html; + html += "
"; + html += QString("
分析员:%1
") + .arg(m_data.signature.analyst); + html += QString("
审查员:%1
") + .arg(m_data.signature.reviewer); + html += QString("
实验室:%1
") + .arg(m_data.signature.laboratory); + html += QString("
日 期:%1
") + .arg(m_data.signature.reportDate.toString("yyyy年MM月dd日")); + html += "
"; + + return html; +} + +QString ReportGenerator::generateHtmlFooter() const +{ + return "\n"; +} + +QString ReportGenerator::generateHtmlReport() const +{ + QString html; + html += generateHtmlHeader(); + html += "
符合能谱分析报告
"; + html += generateMeasurementSection(); + html += generateCalibrationSection(); + html += generateNuclideLibSection(); + html += generateAnalysisSection(); + html += generatePeakTableSection(); + html += generateSignatureSection(); + html += generateHtmlFooter(); + + return html; +} + +QString ReportGenerator::generateTextReport() const +{ + QString text; + QTextStream stream(&text); + + stream << QStringLiteral(u"符合能谱分析报告\n"); + stream << "========================================\n\n"; + + stream << QStringLiteral(u"能谱文件: ") << m_data.measurement.spectrumFile << "\n\n"; + + stream << QStringLiteral(u"测量参数\n"); + stream << "----------------------------------------\n"; + stream << QStringLiteral(u" 开始时间: ") << formatDateTime(m_data.measurement.startTime) << "\n"; + stream << QStringLiteral(u" 活时间: ") << formatDecimal(m_data.measurement.liveTime, 0) << "\n"; + stream << QStringLiteral(u" 实时间: ") << formatDecimal(m_data.measurement.realTime, 0) << "\n"; + stream << QStringLiteral(u" 死时间: ") << formatDecimal(m_data.measurement.deadTime, 2) << " %\n\n"; + + stream << QStringLiteral(u"刻度\n"); + stream << "----------------------------------------\n"; + stream << QStringLiteral(u" 文件: ") << m_data.calibration.fileName << "\n\n"; + + stream << QStringLiteral(u" 能量刻度\n"); + stream << QStringLiteral(u" 生成时间: ") << formatDateTime(m_data.calibration.energy.generateTime) << "\n"; + stream << QStringLiteral(u" 截距: ") << formatDecimal(m_data.calibration.energy.intercept, 3) << " keV\n"; + stream << QStringLiteral(u" 斜率: ") << formatDecimal(m_data.calibration.energy.slope, 3) << " keV/ch\n"; + stream << QStringLiteral(u" 二次项系数: ") << formatScientific(m_data.calibration.energy.quadratic, 3) << " keV/(ch^2)\n\n"; + + stream << QStringLiteral(u" 效率刻度\n"); + stream << QStringLiteral(u" 生成时间: ") << formatDateTime(m_data.calibration.efficiency.generateTime) << "\n"; + stream << QStringLiteral(u" 拐点能量: " )<< formatDecimal(m_data.calibration.efficiency.inflectionEnergy, 2) << " keV\n"; + stream << QStringLiteral(u" 拐点以上: ") << m_data.calibration.efficiency.aboveInflection + << QStringLiteral(u" 误差 = ") << formatDecimal(m_data.calibration.efficiency.aboveError, 2) << " %\n"; + stream << QStringLiteral(u" 拐点以下: ") << m_data.calibration.efficiency.belowInflection + << QStringLiteral(u" 误差 = ") << formatDecimal(m_data.calibration.efficiency.belowError, 2) << " %\n"; + stream << QStringLiteral(u" 效率对数方程式: ") << m_data.calibration.efficiency.logEquation << "\n\n"; + + stream << QStringLiteral(u"核素库\n"); + stream << "----------------------------------------\n"; + stream << QStringLiteral(u" 文件名: ") << m_data.nuclideLib.fileName << "\n"; + stream << QStringLiteral(u" 峰匹配宽度: ") << formatDecimal(m_data.nuclideLib.peakMatchWidth, 3) << " * FWHM (keV)\n\n"; + + stream << QStringLiteral(u"分析参数\n"); + stream << QStringLiteral(u"----------------------------------------\n"); + stream << QStringLiteral(u" 起始能量: " )<< formatDecimal(m_data.analysis.startEnergy, 2) << " keV\n"; + stream << QStringLiteral(u" 终止能量: ") << formatDecimal(m_data.analysis.endEnergy, 2) << " keV\n"; + stream << QStringLiteral(u" 统计误差限值: ") << formatDecimal(m_data.analysis.statErrorLimit, 3) << "%\n"; + stream << QStringLiteral(u" 活度比例系数: ") << formatScientific(m_data.analysis.activityRatio, 4) << "\n"; + stream << QStringLiteral(u" 探测限计算方法: " )<< m_data.analysis.mdaMethod << "\n\n"; + + stream << QStringLiteral(u"********************* 能 谱 峰 一 览 表 ******************\n\n"); + stream << QString("%1 %2 %3 %4 %5 %6 %7\n") + .arg("核素", -10) + .arg("平均活度(Bq)", -15) + .arg("能量(keV)", -12) + .arg("峰活度(Bq)", -15) + .arg("MDA(Bq)", -15) + .arg("提示码", -8) + .arg("备注", -6); + stream << "------------------------------------------------------------------------\n"; + + for (const auto& peak : m_data.peaks) { + stream << QString("%1 %2 %3 %4 %5 %6 %7\n") + .arg(peak.nuclide, -10) + .arg(formatScientific(peak.avgActivity, 4), -15) + .arg(formatDecimal(peak.energy, 2), -12) + .arg(formatScientific(peak.peakActivity, 3), -15) + .arg(formatScientific(peak.mda, 3), -15) + .arg(peak.peakCode, -8) + .arg(peak.remark, -6); + } + + stream << "\n\n"; + stream << QStringLiteral(u"分析员: " )<< m_data.signature.analyst << "\n"; + stream << QStringLiteral(u"审查员: " )<< m_data.signature.reviewer << "\n"; + stream << QStringLiteral(u"实验室: " )<< m_data.signature.laboratory << "\n"; + stream << QStringLiteral(u"日 期: ") << m_data.signature.reportDate.toString("yyyy年MM月dd日") << "\n"; + + return text; +} + +bool ReportGenerator::saveToFile(const QString &filePath) const +{ + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return false; + } + + QTextStream out(&file); + out.setCodec("UTF-8"); + + if (filePath.endsWith(".html", Qt::CaseInsensitive) || + filePath.endsWith(".htm", Qt::CaseInsensitive)) { + out << generateHtmlReport(); + } else { + out << generateTextReport(); + } + + file.close(); + return true; +} + +QString ReportGenerator::generateWordReport() const +{ + QString html; + QTextStream stream(&html); + + stream << "\n"; + stream << "\n"; + stream << "\n"; + stream << "符合能谱分析报告\n"; + stream << "\n"; + stream << "\n"; + stream << "\n"; + stream << "\n"; + + // 报告标题 + stream << QStringLiteral(u"
符合能谱分析报告
\n"); + + // 能谱文件 + stream << QStringLiteral(u"
能谱文件:%1
\n") + .arg(m_data.measurement.spectrumFile); + + // 测量参数 + stream << QStringLiteral(u"
测量参数
\n"); + stream << "\n"; + stream << QStringLiteral(u"\n") + .arg(formatDateTime(m_data.measurement.startTime)) + .arg(formatDecimal(m_data.measurement.liveTime, 0)); + stream << QStringLiteral(u"\n") + .arg(formatDecimal(m_data.measurement.realTime, 0)) + .arg(formatDecimal(m_data.measurement.deadTime, 2)); + stream << "
开始时间:%1活时间(S):%2
实时间(S):%1死时间:%2 %
\n"; + + // 刻度 + stream << QStringLiteral(u"
刻度
\n"); + stream << "\n"; + stream << QStringLiteral(u"\n") + .arg(m_data.calibration.fileName) + .arg(m_data.calibration.standardSource); + stream << "
文件:%1刻度标准源:%2
\n"; + + // 能量刻度 + stream << "
\n"; + stream << QStringLiteral(u"
能量刻度
\n"); + stream << "\n"; + stream << QStringLiteral(u"\n") + .arg(formatDateTime(m_data.calibration.energy.generateTime)) + .arg(formatDecimal(m_data.calibration.energy.intercept, 3)); + stream << QStringLiteral(u"\n") + .arg(formatDecimal(m_data.calibration.energy.slope, 3)) + .arg(formatScientific(m_data.calibration.energy.quadratic, 3)); + stream << "
生成时间:%1截距:%2 keV
斜率:%1 keV/ch二次项系数:%2 keV/(ch^2)
\n"; + stream << "
\n"; + + // 效率刻度 + stream << "
\n"; + stream << QStringLiteral(u"
效率刻度
\n"); + stream << "\n"; + stream << QStringLiteral(u"\n") + .arg(formatDateTime(m_data.calibration.efficiency.generateTime)) + .arg(formatDecimal(m_data.calibration.efficiency.inflectionEnergy, 2)); + stream << QStringLiteral(u"\n") + .arg(m_data.calibration.efficiency.aboveInflection) + .arg(formatDecimal(m_data.calibration.efficiency.aboveError, 2)); + stream << QStringLiteral(u"\n") + .arg(m_data.calibration.efficiency.belowInflection) + .arg(formatDecimal(m_data.calibration.efficiency.belowError, 2)); + stream << QStringLiteral(u"\n") + .arg(m_data.calibration.efficiency.logEquation); + stream << "
生成时间:%1拐点能量(keV):%2
拐点以上:%1误差:%2%
拐点以下:%1误差:%2%
效率对数方程式:%1
\n"; + stream << "
\n"; + + // 核素库 + stream << QStringLiteral(u"
核素库
\n"); + stream << "\n"; + stream << QStringLiteral(u"\n") + .arg(m_data.nuclideLib.fileName) + .arg(formatDecimal(m_data.nuclideLib.peakMatchWidth, 3)); + stream << "
文件:%1峰匹配宽度(keV):%2 * FWHM
\n"; + + // 分析参数 + stream << QStringLiteral(u"
分析参数
\n"); + stream << "\n"; + stream << QStringLiteral(u"\n") + .arg(formatDecimal(m_data.analysis.startEnergy, 2)) + .arg(formatDecimal(m_data.analysis.endEnergy, 2)); + stream << QStringLiteral(u"\n") + .arg(formatDecimal(m_data.analysis.statErrorLimit, 3)) + .arg(formatScientific(m_data.analysis.activityRatio, 4)); + stream << QStringLiteral(u"\n") + .arg(m_data.analysis.mdaMethod); + stream << "
起始能量(keV):%1终止能量(keV):%2
统计误差限值:%1%活度比例系数:%2
探测限计算方法:%1
\n"; + + // 能谱峰一览表 + stream << QStringLiteral(u"
能 谱 峰 一 览 表
\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n"); + + for (const auto& peak : m_data.peaks) { + stream << QStringLiteral(u"\n"); + stream << QStringLiteral(u"\n").arg(peak.nuclide); + stream << QStringLiteral(u"\n").arg(formatScientific(peak.avgActivity, 4)); + stream << QStringLiteral(u"\n").arg(formatDecimal(peak.avgUncertainty, 2)); + stream << QStringLiteral(u"\n").arg(formatDecimal(peak.energy, 2)); + stream << QStringLiteral(u"\n").arg(formatScientific(peak.peakActivity, 3)); + stream << QStringLiteral(u"\n").arg(formatDecimal(peak.peakUncertainty, 2)); + stream << QStringLiteral(u"\n").arg(formatScientific(peak.mda, 3)); + stream << QStringLiteral(u"\n").arg(peak.remark); + stream << QStringLiteral(u"\n"); + } + + stream << QStringLiteral(u"
核素平均活度(贝克Bq)不确定度备注
能量keV活度(贝克Bq)不确定度最小可探测活度(MDA)(贝克Bq)
%1%1%1%%1%1%1%%1%1
\n"); + + // 峰提示码说明 + stream << QStringLiteral(u"
\n"); + stream << QStringLiteral(u"
峰提示码说明:
\n"); + stream << QStringLiteral(u"
G - γ射线
\n"); + stream << QStringLiteral(u"
X - X射线
\n"); + stream << QStringLiteral(u"
ec - 内转换电子
\n"); + stream << QStringLiteral(u"
\n"); + // 签名 + stream << "
\n"; + stream << QStringLiteral(u"
分析员:%1
\n") + .arg(m_data.signature.analyst); + stream << QStringLiteral(u"
审查员:%1
\n") + .arg(m_data.signature.reviewer); + stream << QStringLiteral(u"
实验室:%1
\n") + .arg(m_data.signature.laboratory); + stream << QStringLiteral(u"
日 期:%1
\n") + .arg(m_data.signature.reportDate.toString("yyyy年MM月dd日")); + stream << "
\n"; + + stream << "\n"; + stream << "\n"; + + return html; +} + +bool ReportGenerator::saveToWordFile(const QString &filePath) const +{ + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return false; + } + + QTextStream out(&file); + out.setCodec("UTF-8"); + out << generateWordReport(); + file.close(); + + return true; +} \ No newline at end of file diff --git a/src/analysisReport/reportgenerator.h b/src/analysisReport/reportgenerator.h new file mode 100644 index 0000000..c9d41f2 --- /dev/null +++ b/src/analysisReport/reportgenerator.h @@ -0,0 +1,68 @@ +#ifndef REPORTGENERATOR_H +#define REPORTGENERATOR_H + +#include "spectrumdata.h" +#include + +class ReportGenerator +{ +public: + ReportGenerator(); + + // 设置报告数据 + void setData(const SpectrumReportData& data); + + // 生成HTML格式报告 + QString generateHtmlReport() const; + + // 生成Word格式报告 + QString generateWordReport() const; + + // 生成简化版文本报告 + QString generateTextReport() const; + + // 保存报告到文件 + bool saveToFile(const QString& filePath) const; + + // 保存为Word文档 + bool saveToWordFile(const QString& filePath) const; + + +private: + SpectrumReportData m_data; + + // 格式化数字为科学计数法字符串 + QString formatScientific(double value, int precision = 4) const; + + // 格式化浮点数 + QString formatDecimal(double value, int precision = 2) const; + + // 格式化日期时间 + QString formatDateTime(const QDateTime& dt) const; + + // 生成HTML头部 + QString generateHtmlHeader() const; + + // 生成测量参数部分 + QString generateMeasurementSection() const; + + // 生成刻度部分 + QString generateCalibrationSection() const; + + // 生成核素库部分 + QString generateNuclideLibSection() const; + + // 生成分析参数部分 + QString generateAnalysisSection() const; + + // 生成能谱峰一览表 + QString generatePeakTableSection() const; + + // 生成签名部分 + QString generateSignatureSection() const; + + // 生成HTML尾部 + QString generateHtmlFooter() const; +}; + +#endif // REPORTGENERATOR_H \ No newline at end of file diff --git a/src/analysisReport/reportwidget.cpp b/src/analysisReport/reportwidget.cpp new file mode 100644 index 0000000..9a461bb --- /dev/null +++ b/src/analysisReport/reportwidget.cpp @@ -0,0 +1,345 @@ +#include "reportwidget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +ReportWidget::ReportWidget(QWidget *parent) + : QWidget(parent) +{ + setupUi(); + setupConnections(); + loadSampleData(); +} + +void ReportWidget::setupUi() +{ + auto* mainLayout = new QVBoxLayout(this); + + // 顶部按钮栏 + auto* btnLayout = new QHBoxLayout(); + m_sampleBtn = new QPushButton("加载示例数据", this); + m_refreshBtn = new QPushButton("刷新报告", this); + m_exportHtmlBtn = new QPushButton("导出HTML", this); + m_exportWordBtn = new QPushButton("导出Word", this); + m_exportTextBtn = new QPushButton("导出文本", this); + + btnLayout->addWidget(m_sampleBtn); + btnLayout->addStretch(); + btnLayout->addWidget(m_refreshBtn); + btnLayout->addWidget(m_exportHtmlBtn); + btnLayout->addWidget(m_exportWordBtn); + btnLayout->addWidget(m_exportTextBtn); + mainLayout->addLayout(btnLayout); + + // 标签页 + m_tabWidget = new QTabWidget(this); + + // HTML预览页 + m_htmlView = new QTextBrowser(this); + m_htmlView->setOpenExternalLinks(true); + m_tabWidget->addTab(m_htmlView, "HTML预览"); + + // 文本预览页 + m_textView = new QTextEdit(this); + m_textView->setReadOnly(true); + m_tabWidget->addTab(m_textView, "文本预览"); + + // 数据编辑页 + m_dataEditWidget = new QWidget(this); + auto* dataLayout = new QVBoxLayout(m_dataEditWidget); + + // 测量参数组 + auto* measureGroup = new QGroupBox("测量参数", this); + auto* measureLayout = new QFormLayout(measureGroup); + m_spectrumFileEdit = new QLineEdit(this); + m_startTimeEdit = new QLineEdit(this); + m_liveTimeEdit = new QLineEdit(this); + m_realTimeEdit = new QLineEdit(this); + m_deadTimeEdit = new QLineEdit(this); + + measureLayout->addRow("能谱文件:", m_spectrumFileEdit); + measureLayout->addRow("开始时间 (yyyy/M/d hh:mm:ss):", m_startTimeEdit); + measureLayout->addRow("活时间 (秒):", m_liveTimeEdit); + measureLayout->addRow("实时间 (秒):", m_realTimeEdit); + measureLayout->addRow("死时间 (%):", m_deadTimeEdit); + dataLayout->addWidget(measureGroup); + + // 刻度参数组 + auto* calibGroup = new QGroupBox("刻度参数", this); + auto* calibLayout = new QFormLayout(calibGroup); + m_calibFileEdit = new QLineEdit(this); + m_energyInterceptEdit = new QLineEdit(this); + m_energySlopeEdit = new QLineEdit(this); + m_energyQuadraticEdit = new QLineEdit(this); + + calibLayout->addRow("刻度文件:", m_calibFileEdit); + calibLayout->addRow("能量截距 (keV):", m_energyInterceptEdit); + calibLayout->addRow("能量斜率 (keV/ch):", m_energySlopeEdit); + calibLayout->addRow("二次项系数 (keV/(ch^2)):", m_energyQuadraticEdit); + dataLayout->addWidget(calibGroup); + + // 核素库与分析参数 + auto* paramGroup = new QGroupBox("核素库与分析参数", this); + auto* paramLayout = new QFormLayout(paramGroup); + m_nuclideLibEdit = new QLineEdit(this); + m_peakMatchWidthEdit = new QLineEdit(this); + m_startEnergyEdit = new QLineEdit(this); + m_endEnergyEdit = new QLineEdit(this); + m_statErrorEdit = new QLineEdit(this); + + paramLayout->addRow("核素库文件:", m_nuclideLibEdit); + paramLayout->addRow("峰匹配宽度 (*FWHM):", m_peakMatchWidthEdit); + paramLayout->addRow("起始能量 (keV):", m_startEnergyEdit); + paramLayout->addRow("终止能量 (keV):", m_endEnergyEdit); + paramLayout->addRow("统计误差限值 (%):", m_statErrorEdit); + dataLayout->addWidget(paramGroup); + + // 峰数据表格 + auto* peakGroup = new QGroupBox("能谱峰数据", this); + auto* peakLayout = new QVBoxLayout(peakGroup); + m_peakTable = new QTableWidget(this); + m_peakTable->setColumnCount(7); + m_peakTable->setHorizontalHeaderLabels( + QStringList() << "核素" << "平均活度(Bq)" << "能量(keV)" + << "峰活度(Bq)" << "MDA(Bq)" << "提示码" << "备注"); + m_peakTable->horizontalHeader()->setStretchLastSection(true); + m_peakTable->setRowCount(10); // 预留10行 + peakLayout->addWidget(m_peakTable); + dataLayout->addWidget(peakGroup); + + // 签名信息 + auto* signGroup = new QGroupBox("签名信息", this); + auto* signLayout = new QFormLayout(signGroup); + m_analystEdit = new QLineEdit(this); + m_reviewerEdit = new QLineEdit(this); + m_laboratoryEdit = new QLineEdit(this); + m_reportDateEdit = new QLineEdit(this); + + signLayout->addRow("分析员:", m_analystEdit); + signLayout->addRow("审查员:", m_reviewerEdit); + signLayout->addRow("实验室:", m_laboratoryEdit); + signLayout->addRow("报告日期 (yyyy-MM-dd):", m_reportDateEdit); + dataLayout->addWidget(signGroup); + + dataLayout->addStretch(); + m_tabWidget->addTab(m_dataEditWidget, "数据编辑"); + + mainLayout->addWidget(m_tabWidget); + + resize(1000, 700); + setWindowTitle("能谱分析报告生成器"); +} + +void ReportWidget::setupConnections() +{ + connect(m_sampleBtn, &QPushButton::clicked, this, &ReportWidget::loadSampleData); + connect(m_refreshBtn, &QPushButton::clicked, this, &ReportWidget::refreshReport); + connect(m_exportHtmlBtn, &QPushButton::clicked, this, &ReportWidget::exportHtml); + connect(m_exportWordBtn, &QPushButton::clicked, this, &ReportWidget::exportWord); + connect(m_exportTextBtn, &QPushButton::clicked, this, &ReportWidget::exportText); +} + +void ReportWidget::setReportData(const SpectrumReportData &data) +{ + m_data = data; + m_generator.setData(m_data); + + // 更新UI + m_spectrumFileEdit->setText(m_data.measurement.spectrumFile); + m_startTimeEdit->setText(m_data.measurement.startTime.toString("yyyy/M/d hh:mm:ss")); + m_liveTimeEdit->setText(QString::number(m_data.measurement.liveTime)); + m_realTimeEdit->setText(QString::number(m_data.measurement.realTime)); + m_deadTimeEdit->setText(QString::number(m_data.measurement.deadTime)); + + m_calibFileEdit->setText(m_data.calibration.fileName); + m_energyInterceptEdit->setText(QString::number(m_data.calibration.energy.intercept)); + m_energySlopeEdit->setText(QString::number(m_data.calibration.energy.slope)); + m_energyQuadraticEdit->setText(QString::number(m_data.calibration.energy.quadratic, 'E', 3)); + + m_nuclideLibEdit->setText(m_data.nuclideLib.fileName); + m_peakMatchWidthEdit->setText(QString::number(m_data.nuclideLib.peakMatchWidth)); + + m_startEnergyEdit->setText(QString::number(m_data.analysis.startEnergy)); + m_endEnergyEdit->setText(QString::number(m_data.analysis.endEnergy)); + m_statErrorEdit->setText(QString::number(m_data.analysis.statErrorLimit)); + + m_analystEdit->setText(m_data.signature.analyst); + m_reviewerEdit->setText(m_data.signature.reviewer); + m_laboratoryEdit->setText(m_data.signature.laboratory); + m_reportDateEdit->setText(m_data.signature.reportDate.toString("yyyy-MM-dd")); + + updatePeakTable(); + refreshReport(); +} + +SpectrumReportData ReportWidget::reportData() const +{ + return m_data; +} + +void ReportWidget::refreshReport() +{ + updateDataFromUi(); + m_generator.setData(m_data); + + // 更新HTML预览 + m_htmlView->setHtml(m_generator.generateHtmlReport()); + + // 更新文本预览 + m_textView->setPlainText(m_generator.generateTextReport()); +} + +void ReportWidget::updateDataFromUi() +{ + // 测量参数 + m_data.measurement.spectrumFile = m_spectrumFileEdit->text(); + m_data.measurement.startTime = QDateTime::fromString(m_startTimeEdit->text(), "yyyy/M/d hh:mm:ss"); + m_data.measurement.liveTime = m_liveTimeEdit->text().toDouble(); + m_data.measurement.realTime = m_realTimeEdit->text().toDouble(); + m_data.measurement.deadTime = m_deadTimeEdit->text().toDouble(); + + // 刻度 + m_data.calibration.fileName = m_calibFileEdit->text(); + m_data.calibration.energy.intercept = m_energyInterceptEdit->text().toDouble(); + m_data.calibration.energy.slope = m_energySlopeEdit->text().toDouble(); + m_data.calibration.energy.quadratic = m_energyQuadraticEdit->text().toDouble(); + + // 核素库 + m_data.nuclideLib.fileName = m_nuclideLibEdit->text(); + m_data.nuclideLib.peakMatchWidth = m_peakMatchWidthEdit->text().toDouble(); + + // 分析参数 + m_data.analysis.startEnergy = m_startEnergyEdit->text().toDouble(); + m_data.analysis.endEnergy = m_endEnergyEdit->text().toDouble(); + m_data.analysis.statErrorLimit = m_statErrorEdit->text().toDouble(); + + // 签名 + m_data.signature.analyst = m_analystEdit->text(); + m_data.signature.reviewer = m_reviewerEdit->text(); + m_data.signature.laboratory = m_laboratoryEdit->text(); + m_data.signature.reportDate = QDate::fromString(m_reportDateEdit->text(), "yyyy-MM-dd"); + + // 峰数据(从表格读取) + m_data.clearPeaks(); + for (int row = 0; row < m_peakTable->rowCount(); ++row) { + QTableWidgetItem* nuclideItem = m_peakTable->item(row, 0); + if (!nuclideItem || nuclideItem->text().isEmpty()) { + continue; + } + + SpectrumPeak peak; + peak.nuclide = nuclideItem->text(); + + QTableWidgetItem* avgItem = m_peakTable->item(row, 1); + if (avgItem) peak.avgActivity = avgItem->text().toDouble(); + + QTableWidgetItem* energyItem = m_peakTable->item(row, 2); + if (energyItem) peak.energy = energyItem->text().toDouble(); + + QTableWidgetItem* peakActItem = m_peakTable->item(row, 3); + if (peakActItem) peak.peakActivity = peakActItem->text().toDouble(); + + QTableWidgetItem* mdaItem = m_peakTable->item(row, 4); + if (mdaItem) peak.mda = mdaItem->text().toDouble(); + + QTableWidgetItem* codeItem = m_peakTable->item(row, 5); + if (codeItem) peak.peakCode = codeItem->text(); + + QTableWidgetItem* remarkItem = m_peakTable->item(row, 6); + if (remarkItem) peak.remark = remarkItem->text(); + + m_data.addPeak(peak); + } +} + +void ReportWidget::updatePeakTable() +{ + m_peakTable->setRowCount(m_data.peakCount() + 5); // 多留几行 + + for (int i = 0; i < m_data.peakCount(); ++i) { + const auto& peak = m_data.peaks[i]; + m_peakTable->setItem(i, 0, new QTableWidgetItem(peak.nuclide)); + m_peakTable->setItem(i, 1, new QTableWidgetItem(QString::number(peak.avgActivity, 'E', 4))); + m_peakTable->setItem(i, 2, new QTableWidgetItem(QString::number(peak.energy, 'f', 2))); + m_peakTable->setItem(i, 3, new QTableWidgetItem(QString::number(peak.peakActivity, 'E', 3))); + m_peakTable->setItem(i, 4, new QTableWidgetItem(QString::number(peak.mda, 'E', 3))); + m_peakTable->setItem(i, 5, new QTableWidgetItem(peak.peakCode)); + m_peakTable->setItem(i, 6, new QTableWidgetItem(peak.remark)); + } +} + +void ReportWidget::exportHtml() +{ + QString fileName = QFileDialog::getSaveFileName( + this, "导出HTML报告", "能谱分析报告.html", + "HTML文件 (*.html *.htm);;所有文件 (*.*)"); + + if (fileName.isEmpty()) { + return; + } + + updateDataFromUi(); + m_generator.setData(m_data); + + if (m_generator.saveToFile(fileName)) { + QMessageBox::information(this, "成功", "HTML报告导出成功!"); + } else { + QMessageBox::warning(this, "失败", "导出失败,请检查文件路径。"); + } +} + +void ReportWidget::exportWord() +{ + QString fileName = QFileDialog::getSaveFileName( + this, "导出Word报告", "能谱分析报告.doc", + "Word文档 (*.doc);;所有文件 (*.*)"); + + if (fileName.isEmpty()) { + return; + } + + updateDataFromUi(); + m_generator.setData(m_data); + + if (m_generator.saveToWordFile(fileName)) { + QMessageBox::information(this, "成功", "Word报告导出成功!\n可用 Microsoft Word 或 WPS 打开查看。"); + } else { + QMessageBox::warning(this, "失败", "导出失败,请检查文件路径。"); + } +} + +void ReportWidget::exportText() +{ + QString fileName = QFileDialog::getSaveFileName( + this, "导出文本报告", "能谱分析报告.txt", + "文本文件 (*.txt);;所有文件 (*.*)"); + + if (fileName.isEmpty()) { + return; + } + + updateDataFromUi(); + m_generator.setData(m_data); + + if (m_generator.saveToFile(fileName)) { + QMessageBox::information(this, "成功", "文本报告导出成功!"); + } else { + QMessageBox::warning(this, "失败", "导出失败,请检查文件路径。"); + } +} + +void ReportWidget::loadSampleData() +{ + SpectrumReportData data; + data.fillSampleData(); + setReportData(data); +} \ No newline at end of file diff --git a/src/analysisReport/reportwidget.h b/src/analysisReport/reportwidget.h new file mode 100644 index 0000000..07af140 --- /dev/null +++ b/src/analysisReport/reportwidget.h @@ -0,0 +1,96 @@ +#ifndef REPORTWIDGET_H +#define REPORTWIDGET_H + +#include +#include "spectrumdata.h" +#include "reportgenerator.h" + +class QTextEdit; +class QPushButton; +class QTabWidget; +class QTableWidget; +class QLabel; +class QLineEdit; +class QFormLayout; +class QTextBrowser; + +class ReportWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ReportWidget(QWidget *parent = nullptr); + + // 设置报告数据 + void setReportData(const SpectrumReportData& data); + + // 获取当前数据 + SpectrumReportData reportData() const; + +public slots: + // 刷新报告显示 + void refreshReport(); + + // 导出HTML报告 + void exportHtml(); + + // 导出Word报告 + void exportWord(); + + // 导出文本报告 + void exportText(); + + // 加载示例数据 + void loadSampleData(); + +private: + void setupUi(); + void setupConnections(); + void updateDataFromUi(); + void updatePeakTable(); + + // UI组件 + QTabWidget* m_tabWidget; + QTextBrowser* m_htmlView; + QTextEdit* m_textView; + QWidget* m_dataEditWidget; + + // 数据编辑组件 + QLineEdit* m_spectrumFileEdit; + QLineEdit* m_startTimeEdit; + QLineEdit* m_liveTimeEdit; + QLineEdit* m_realTimeEdit; + QLineEdit* m_deadTimeEdit; + + QLineEdit* m_calibFileEdit; + QLineEdit* m_energyInterceptEdit; + QLineEdit* m_energySlopeEdit; + QLineEdit* m_energyQuadraticEdit; + + QLineEdit* m_nuclideLibEdit; + QLineEdit* m_peakMatchWidthEdit; + + QLineEdit* m_startEnergyEdit; + QLineEdit* m_endEnergyEdit; + QLineEdit* m_statErrorEdit; + + QTableWidget* m_peakTable; + + QLineEdit* m_analystEdit; + QLineEdit* m_reviewerEdit; + QLineEdit* m_laboratoryEdit; + QLineEdit* m_reportDateEdit; + + // 按钮 + QPushButton* m_refreshBtn; + QPushButton* m_exportHtmlBtn; + QPushButton* m_exportWordBtn; + QPushButton* m_exportTextBtn; + QPushButton* m_sampleBtn; + + // 数据 + SpectrumReportData m_data; + ReportGenerator m_generator; +}; + +#endif // REPORTWIDGET_H \ No newline at end of file diff --git a/src/analysisReport/spectrumdata.cpp b/src/analysisReport/spectrumdata.cpp new file mode 100644 index 0000000..4fdbc0d --- /dev/null +++ b/src/analysisReport/spectrumdata.cpp @@ -0,0 +1,109 @@ +#include "spectrumdata.h" + +SpectrumReportData::SpectrumReportData() +{ +} + +void SpectrumReportData::addPeak(const SpectrumPeak &peak) +{ + peaks.append(peak); +} + +void SpectrumReportData::clearPeaks() +{ + peaks.clear(); +} + +int SpectrumReportData::peakCount() const +{ + return peaks.size(); +} + +void SpectrumReportData::fillSampleData() +{ + // 测量参数 + measurement.spectrumFile = "3#-20250416"; + measurement.startTime = QDateTime(QDate(2025, 4, 16), QTime(20, 1, 22)); + measurement.liveTime = 86400.0; + measurement.realTime = 86444.0; + measurement.deadTime = 0.05; + + // 刻度信息 + calibration.fileName = "刻度文件.Clb"; + calibration.standardSource = "Co60"; + + // 能量刻度 + calibration.energy.generateTime = QDateTime(QDate(2025, 3, 21), QTime(11, 3, 28)); + calibration.energy.intercept = 0.057; + calibration.energy.slope = 0.090; + calibration.energy.quadratic = -3.127e-9; + + // 效率刻度 + calibration.efficiency.generateTime = QDateTime(QDate(2025, 3, 21), QTime(11, 2, 50)); + calibration.efficiency.inflectionEnergy = 80.00; + calibration.efficiency.aboveInflection = "一次方程"; + calibration.efficiency.aboveError = 0.0; + calibration.efficiency.belowInflection = "二次方程"; + calibration.efficiency.belowError = 0.0; + calibration.efficiency.logEquation = + "-1.164361E+01 + (4.475904E+00*Log(E)) + (-5.221437E-01*Log(E)^2)"; + + // 核素库 + nuclideLib.fileName = "Xe131m-131-133主要射线.Lib"; + nuclideLib.peakMatchWidth = 0.500; + + // 分析参数 + analysis.startEnergy = 0.96; + analysis.endEnergy = 271.36; + analysis.statErrorLimit = 30.000; + analysis.activityRatio = 1.0; + analysis.mdaMethod = "传统方法"; + + // 能谱峰数据 + peaks.clear(); + + SpectrumPeak peak1; + peak1.nuclide = "XE-133"; + peak1.nuclideCode = "I"; + peak1.avgActivity = 2.7056e-01; + peak1.avgUncertainty = 0.02; + peak1.energy = 81.00; + peak1.peakActivity = 2.706e-01; + peak1.peakUncertainty = 0.02; + peak1.mda = 3.393e-02; + peak1.peakCode = "@"; + peak1.remark = "G"; + peaks.append(peak1); + + SpectrumPeak peak2; + peak2.nuclide = "XE-131M"; + peak2.nuclideCode = "T"; + peak2.avgActivity = 0.0; + peak2.avgUncertainty = 0.01; + peak2.energy = 163.93; + peak2.peakActivity = 2.220e-01; + peak2.peakUncertainty = 0.01; + peak2.mda = 4.506e-01; + peak2.peakCode = "%"; + peak2.remark = "G"; + peaks.append(peak2); + + SpectrumPeak peak3; + peak3.nuclide = "XE-133M"; + peak3.nuclideCode = "I"; + peak3.avgActivity = 0.0; + peak3.avgUncertainty = 0.02; + peak3.energy = 233.22; + peak3.peakActivity = 0.0; + peak3.peakUncertainty = 0.02; + peak3.mda = 9.827e-02; + peak3.peakCode = "%"; + peak3.remark = "G"; + peaks.append(peak3); + + // 签名信息 + signature.analyst = "XESPM-III"; + signature.reviewer = "管理员"; + signature.laboratory = "GAMMASPEC"; + signature.reportDate = QDate(2025, 11, 13); +} \ No newline at end of file diff --git a/src/analysisReport/spectrumdata.h b/src/analysisReport/spectrumdata.h new file mode 100644 index 0000000..4ad8dbd --- /dev/null +++ b/src/analysisReport/spectrumdata.h @@ -0,0 +1,114 @@ +#ifndef SPECTRUMDATA_H +#define SPECTRUMDATA_H + +#include +#include +#include + +// 能量刻度参数 +struct EnergyCalibration { + QDateTime generateTime; // 生成时间 + double intercept = 0.0; // 截距 (keV) + double slope = 0.0; // 斜率 (keV/ch) + double quadratic = 0.0; // 二次项系数 (keV/(ch^2)) +}; + +// 效率刻度参数 +struct EfficiencyCalibration { + QDateTime generateTime; // 生成时间 + double inflectionEnergy = 0.0; // 拐点能量 (keV) + QString aboveInflection; // 拐点以上方法 + double aboveError = 0.0; // 拐点以上误差 + QString belowInflection; // 拐点以下方法 + double belowError = 0.0; // 拐点以下误差 + QString logEquation; // 效率对数方程式 +}; + +// 刻度信息 +struct Calibration { + QString fileName; // 刻度文件名 + EnergyCalibration energy; // 能量刻度 + EfficiencyCalibration efficiency; // 效率刻度 + QString standardSource; // 刻度标准源 +}; + +// 核素库信息 +struct NuclideLibrary { + QString fileName; // 库文件名 + double peakMatchWidth = 0.0; // 峰匹配宽度 (*FWHM, keV) +}; + +// 分析参数 +struct AnalysisParameters { + double startEnergy = 0.0; // 起始能量 (keV) + double endEnergy = 0.0; // 终止能量 (keV) + double statErrorLimit = 0.0; // 统计误差限值 (%) + double activityRatio = 0.0; // 活度比例系数 + QString mdaMethod; // 探测限计算方法 +}; + +// 单个峰数据 +struct SpectrumPeak { + QString nuclide; // 核素名称 + QString nuclideCode; // 核素提示码 + double avgActivity = 0.0; // 平均活度 (Bq) + double avgUncertainty = 0.0; // 平均活度不确定度 (%) + double energy = 0.0; // 峰能量 (keV) + double peakActivity = 0.0; // 峰活度 (Bq) + double peakUncertainty = 0.0;// 峰活度不确定度 (%) + double mda = 0.0; // 最小可探测活度 MDA (Bq) + QString peakCode; // 峰提示码 + QString remark; // 备注 +}; + +// 测量参数 +struct MeasurementParams { + QString spectrumFile; // 能谱文件名 + QDateTime startTime; // 开始时间 + double liveTime = 0.0; // 活时间 (秒) + double realTime = 0.0; // 实时间 (秒) + double deadTime = 0.0; // 死时间 (%) +}; + +// 报告签名信息 +struct ReportSignature { + QString analyst; // 分析员 + QString reviewer; // 审查员 + QString laboratory; // 实验室 + QDate reportDate; // 报告日期 +}; + +// 完整的能谱报告数据 +class SpectrumReportData +{ +public: + SpectrumReportData(); + + // 测量参数 + MeasurementParams measurement; + + // 刻度信息 + Calibration calibration; + + // 核素库 + NuclideLibrary nuclideLib; + + // 分析参数 + AnalysisParameters analysis; + + // 能谱峰列表 + QVector peaks; + + // 签名信息 + ReportSignature signature; + + // 工具方法 + void addPeak(const SpectrumPeak& peak); + void clearPeaks(); + int peakCount() const; + + // 示例数据填充 + void fillSampleData(); +}; + +#endif // SPECTRUMDATA_H \ No newline at end of file diff --git a/src/src.pro b/src/src.pro index 42421c8..bb7769b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,6 +1,8 @@ TARGET = EnergySpectrumAnalyer -QT += core gui widgets concurrent datavisualization network sql +QT += core gui widgets concurrent datavisualization network sql xml +QT += gui-private + CONFIG += c++17 release msvc { @@ -41,7 +43,9 @@ INCLUDEPATH += \ $${PWD}/AntiConformEnergySpectrumView\ $${PWD}/CoincidenceEventTimeView\ $${PWD}/NuclideAnalysisView \ - $${PWD}/BackgroundTaskListView + $${PWD}/BackgroundTaskListView \ + $${PWD}/analysisReport + DEPENDPATH += \ @@ -64,7 +68,9 @@ DEPENDPATH += \ $${PWD}/AntiConformEnergySpectrumView\ $${PWD}/CoincidenceEventTimeView\ $${PWD}/NuclideAnalysisView \ - $${PWD}/BackgroundTaskListView + $${PWD}/BackgroundTaskListView \ + $${PWD}/analysisReport + SOURCES += \ @@ -78,6 +84,7 @@ SOURCES += \ CustomQwtPlot.cpp \ DataProcessWorkPool.cpp \ DeviceConnectManagement.cpp \ + EfficiencyScale.cpp \ EnergyCountPeakFitView/EnergyCountPeakFitView.cpp \ EnergyCountPeakFitView/PeakFitParamsDialog.cpp \ EnergyCountPeakFitView/PlotRectItem.cpp \ @@ -121,6 +128,9 @@ SOURCES += \ ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.cpp \ NuclideLib/NuclideLib.cpp \ AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.cpp \ + analysisReport/reportgenerator.cpp \ + analysisReport/reportwidget.cpp \ + analysisReport/spectrumdata.cpp \ main.cpp HEADERS += \ @@ -135,6 +145,7 @@ HEADERS += \ CustomQwtPlot.h \ DataProcessWorkPool.h \ DeviceConnectManagement.h \ + EfficiencyScale.h \ EnergyCountPeakFitView/EnergyCountPeakFitView.h \ EnergyCountPeakFitView/PeakFitParamsDialog.h \ EnergyCountPeakFitView/PlotRectItem.h \ @@ -179,13 +190,17 @@ HEADERS += \ EnergyCountPeakFitView/EnergyCountPeakFitView.h \ ConformToTheEnergySpectrum/ConformToTheEnergySpectrum.h \ NuclideLib/NuclideLib.h \ - AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.h + AntiConformEnergySpectrumView/AntiConformEnergySpectrumView.h \ + analysisReport/reportgenerator.h \ + analysisReport/reportwidget.h \ + analysisReport/spectrumdata.h FORMS += \ 2DSpectralCompliance/TwoDSpectralCompliance.ui \ AboutDlg.ui \ CountRateAnalysisView/CountRateAnalysisView.ui \ DeviceConnectManagement.ui \ + EfficiencyScale.ui \ EnergyScaleForm.ui \ MainWindow.ui \ MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.ui \