Compare commits

...

13 Commits
master ... dev

33 changed files with 45051 additions and 0 deletions

View File

@ -0,0 +1,76 @@
cmake_minimum_required(VERSION 3.5)
project(ChartLogGeneration VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets PrintSupport)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets PrintSupport)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
qcustomplot.cpp
qcustomplot.h
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(ChartLogGeneration
MANUAL_FINALIZATION
${PROJECT_SOURCES}
settingsdialog.cpp settingsdialog.ui
settingsdialog.h
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET ChartLogGeneration APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
if(ANDROID)
add_library(ChartLogGeneration SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(ChartLogGeneration
${PROJECT_SOURCES}
)
endif()
endif()
# target_link_libraries(ChartLogGeneration PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(ChartLogGeneration PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::PrintSupport)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.ChartLogGeneration)
endif()
set_target_properties(ChartLogGeneration PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS ChartLogGeneration
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(ChartLogGeneration)
endif()

View File

@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

View File

@ -0,0 +1,178 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
customPlot = new QCustomPlot(this);
plotGraph();
settingsDialog = new SettingsDialog(curves.size(), this);
QVector<QColor> curves_color = settingsDialog->getCurveColors();
for(int i=0; i< curves.size(); ++i){
curves[i]->setPen(QPen(curves_color[i]));
}
QPushButton *saveButton = new QPushButton("Save Graph", this);
connect(saveButton, &QPushButton::clicked, this, &MainWindow::saveGraph);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(customPlot);
layout->addWidget(saveButton);
ui->centralwidget->setLayout(layout);
// 连接customPlot的双击信号到槽函数
connect(customPlot, &QCustomPlot::mouseDoubleClick, this, &MainWindow::openSettingsDialog);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::plotGraph()
{
curves.clear();
QVector<double> I_values, t_values;
QVector<QCPCurveData> curve0, curve1, curve2, curve3, curve4, curve5;
// 生成函数曲线数据
for (int i = 1; i <= 100; ++i) {
double I = qPow(10, 1.0 + 3.0 * i / 100.0); // 从10到10000的对数值
double epsilon = 1e-10;
double Tp = 1;
double I_op = 100;
double t = 80 * Tp / ((qPow(I / I_op, 2) - 1) + epsilon);
if (t > 0) {
I_values.append(I);
t_values.append(t);
}
}
// 定义其他曲线数据
curve0 << QCPCurveData(0, 10, 1000) << QCPCurveData(1, 30, 100) << QCPCurveData(2, 100, 10) << QCPCurveData(3, 1000, 1) << QCPCurveData(4, 3000, 0.1);
curve1 << QCPCurveData(0, 10, 1000) << QCPCurveData(1, 30, 300) << QCPCurveData(2, 100, 30) << QCPCurveData(3, 1000, 3) << QCPCurveData(4, 3000, 0.3);
curve2 << QCPCurveData(0, 10, 1000) << QCPCurveData(1, 30, 200) << QCPCurveData(2, 100, 20) << QCPCurveData(3, 1000, 2) << QCPCurveData(4, 3000, 0.2);
curve3 << QCPCurveData(0, 15, 500) << QCPCurveData(1, 40, 50) << QCPCurveData(2, 150, 5) << QCPCurveData(3, 1500, 0.5) << QCPCurveData(4, 5000, 0.05);
curve4 << QCPCurveData(0, 10, 800) << QCPCurveData(1, 30, 80) << QCPCurveData(2, 100, 8) << QCPCurveData(3, 1000, 0.8) << QCPCurveData(4, 3000, 0.08);
curve5 << QCPCurveData(0, 20, 1000) << QCPCurveData(1, 60, 150) << QCPCurveData(2, 200, 15) << QCPCurveData(3, 2000, 1.5) << QCPCurveData(4, 6000, 0.15);
// 创建曲线并添加到图表中
QCPCurve *curveFunction = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curveFunction);
QCPCurve *curve0Plot = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curve0Plot);
QCPCurve *curve1Plot = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curve1Plot);
QCPCurve *curve2Plot = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curve2Plot);
QCPCurve *curve3Plot = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curve3Plot);
QCPCurve *curve4Plot = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curve4Plot);
QCPCurve *curve5Plot = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
curves.append(curve5Plot);
curveFunction->setData(I_values, t_values);
curveFunction->setPen(QPen(Qt::DashLine));
// curveFunction->setPen(QPen(Qt::black, 1, Qt::DashLine));
curve0Plot->data()->set(curve0, true);
// curve0Plot->setPen(QPen(Qt::blue));
curve1Plot->data()->set(curve1, true);
// curve1Plot->setPen(QPen(Qt::green));
curve2Plot->data()->set(curve2, true);
// curve2Plot->setPen(QPen(QColorConstants::Svg::purple));
curve3Plot->data()->set(curve3, true);
// curve3Plot->setPen(QPen(QColorConstants::Svg::orange));
curve4Plot->data()->set(curve4, true);
// curve4Plot->setPen(QPen(Qt::red));
curve5Plot->data()->set(curve5, true);
// curve5Plot->setPen(QPen(QColorConstants::Svg::brown));
// 设置对数坐标轴
customPlot->xAxis->setScaleType(QCPAxis::stLogarithmic);
customPlot->yAxis->setScaleType(QCPAxis::stLogarithmic);
customPlot->xAxis->setLabel("Axis-X");
customPlot->yAxis->setLabel("Axis-Y");
customPlot->xAxis->setRange(5, 10000);
customPlot->yAxis->setRange(0.01, 1000);
// 启用缩放拖动
customPlot->setInteraction(QCP::iRangeZoom, true); // 缩放
customPlot->setInteraction(QCP::iRangeDrag, true); // 拖动
// 设置可以通过滚轮缩放的轴
customPlot->axisRect()->setRangeZoom(Qt::Horizontal | Qt::Vertical); // 水平和垂直方向都可以缩放
customPlot->axisRect()->setRangeZoomAxes(customPlot->xAxis, customPlot->yAxis); // 指定X和Y轴
// 设置缩放的缩放速度
customPlot->axisRect()->setRangeZoomFactor(0.9);
// 显示网格
customPlot->xAxis->grid()->setSubGridVisible(true);
customPlot->yAxis->grid()->setSubGridVisible(true);
// 显示图表
customPlot->replot();
}
void MainWindow::saveGraph()
{
QString filePath = QFileDialog::getSaveFileName(this, "Save Graph", "", "PNG Files (*.png);;All Files (*)");
if (!filePath.isEmpty()) {
customPlot->savePng(filePath);
}
}
void MainWindow::openSettingsDialog()
{
if (settingsDialog->exec() == QDialog::Accepted) {
// 从settingsDialog获取设置并应用到customPlot
// 获取轴范围
double xMin = settingsDialog->getXMin();
double xMax = settingsDialog->getXMax();
double yMin = settingsDialog->getYMin();
double yMax = settingsDialog->getYMax();
customPlot->xAxis->setRange(xMin, xMax);
customPlot->yAxis->setRange(yMin, yMax);
// 设置曲线颜色
// QColor curveColor1 = settingsDialog->getCurveColor(0);
// QColor curveColor2 = settingsDialog->getCurveColor(1);
// customPlot->graph(0)->setPen(QPen(curveColor1));
// customPlot->graph(1)->setPen(QPen(curveColor2));
QVector<QColor> curves_color = settingsDialog->getCurveColors();
for(int i=0; i< curves.size(); ++i){
curves[i]->setPen(QPen(curves_color[i]));
}
// 设置背景颜色
QColor backgroundColor = settingsDialog->getBackgroundColor();
customPlot->setBackground(backgroundColor);
// 设置网格可见性
bool gridVisible = settingsDialog->isGridVisible();
customPlot->xAxis->grid()->setVisible(gridVisible);
customPlot->yAxis->grid()->setVisible(gridVisible);
// 重新绘制图表
customPlot->replot();
}
}

View File

@ -0,0 +1,33 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "qcustomplot.h"
#include "settingsdialog.h" // 引入设置对话框头文件
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void saveGraph();
void openSettingsDialog();
private:
Ui::MainWindow *ui;
QCustomPlot *customPlot;
SettingsDialog *settingsDialog;
QVector<QCPCurve*> curves;
void plotGraph();
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>曲线编辑</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
#include "settingsdialog.h"
SettingsDialog::SettingsDialog(int curveCount, QWidget *parent) :
QDialog(parent),
// curveColors{Qt::blue, Qt::green},
backgroundColor(Qt::white)
{
initializeCurveColors(100, 123);
// 创建UI元素
QLabel *xMinLabel = new QLabel("X Axis Min:", this);
xMinLineEdit = new QLineEdit(this);
xMinLineEdit->setText("5");
QLabel *xMaxLabel = new QLabel("X Axis Max:", this);
xMaxLineEdit = new QLineEdit(this);
xMaxLineEdit->setText("10000");
QLabel *yMinLabel = new QLabel("Y Axis Min:", this);
yMinLineEdit = new QLineEdit(this);
yMinLineEdit->setText("0.01");
QLabel *yMaxLabel = new QLabel("Y Axis Max:", this);
yMaxLineEdit = new QLineEdit(this);
yMaxLineEdit->setText("1000");
QLabel *backgroundColorLabel = new QLabel("Background Color:", this);
backgroundColorButton = new QPushButton(this);
updateColorButton(backgroundColorButton, backgroundColor);
gridCheckBox = new QCheckBox("Show Grid", this);
gridCheckBox->setChecked(true);
// 设置布局
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(xMinLabel, 0, 0);
layout->addWidget(xMinLineEdit, 0, 1);
layout->addWidget(xMaxLabel, 1, 0);
layout->addWidget(xMaxLineEdit, 1, 1);
layout->addWidget(yMinLabel, 2, 0);
layout->addWidget(yMinLineEdit, 2, 1);
layout->addWidget(yMaxLabel, 3, 0);
layout->addWidget(yMaxLineEdit, 3, 1);
// 添加曲线颜色按钮
setupCurveColorButtons(curveCount);
layout->addWidget(backgroundColorLabel, 4 + curveCount, 0);
layout->addWidget(backgroundColorButton, 4 + curveCount, 1);
layout->addWidget(gridCheckBox, 5 + curveCount, 0, 1, 2);
// 确认和取消按钮
QPushButton *okButton = new QPushButton("OK", this);
QPushButton *cancelButton = new QPushButton("Cancel", this);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout, 6 + curveCount, 0, 1, 2);
// 设置对话框的主要布局
setLayout(layout);
// 连接按钮信号到槽
connect(backgroundColorButton, &QPushButton::clicked, this, [=](){
QColor color = QColorDialog::getColor(backgroundColor, this);
if (color.isValid()) {
backgroundColor = color;
updateColorButton(backgroundColorButton, backgroundColor);
}
});
for (int i = 0; i < curveColorButtons.size(); ++i) {
connect(curveColorButtons[i], &QPushButton::clicked, this, [=]() {
QColor color = QColorDialog::getColor(curveColors[i], this);
if (color.isValid()) {
curveColors[i] = color;
updateColorButton(curveColorButtons[i], color);
}
});
}
connect(okButton, &QPushButton::clicked, this, &QDialog::accept);
connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
}
SettingsDialog::~SettingsDialog() = default;
double SettingsDialog::getXMin() const { return xMinLineEdit->text().toDouble(); }
double SettingsDialog::getXMax() const { return xMaxLineEdit->text().toDouble(); }
double SettingsDialog::getYMin() const { return yMinLineEdit->text().toDouble(); }
double SettingsDialog::getYMax() const { return yMaxLineEdit->text().toDouble(); }
QColor SettingsDialog::getCurveColor(int index) const {
if (index >= 0 && index < curveColors.size()) {
return curveColors[index];
}
return QColor(Qt::black);
}
QColor SettingsDialog::getBackgroundColor() const {
return backgroundColor;
}
QVector<QColor> SettingsDialog::getCurveColors() const {
return curveColors;
}
bool SettingsDialog::isGridVisible() const {
return gridCheckBox->isChecked();
}
void SettingsDialog::setupCurveColorButtons(int curveCount) {
QStringList labels;
for (int i = 0; i < curveCount; ++i) {
labels << QString("Curve %1 Color:").arg(i+1);
}
QGridLayout *layout = qobject_cast<QGridLayout*>(this->layout());
qDeleteAll(curveColorButtons);
curveColorButtons.clear();
for (int i = 0; i < labels.size(); ++i) {
QLabel *label = new QLabel(labels[i], this);
QPushButton *button = new QPushButton(this);
// 这里假设curveColors有足够的元素如果不确定填充默认颜色
if (i < curveColors.size()) {
updateColorButton(button, curveColors[i]);
} else {
updateColorButton(button, Qt::white);
}
layout->addWidget(label, 4 + i, 0);
layout->addWidget(button, 4 + i, 1);
curveColorButtons.append(button);
}
}
void SettingsDialog::initializeCurveColors(int size, quint32 seed){
curveColors.resize(size);
QRandomGenerator random(seed);
// 生成随机颜色并填充 QVector
for (int i = 0; i < curveColors.size(); ++i) {
int red = random.bounded(256);
int green = random.bounded(256);
int blue = random.bounded(256);
curveColors[i] = QColor(red, green, blue);
}
}
void SettingsDialog::updateColorButton(QPushButton *button, const QColor &color) {
button->setStyleSheet(QString("background-color: %1").arg(color.name()));
}

View File

@ -0,0 +1,54 @@
#ifndef SETTINGSDIALOG__H
#define SETTINGSDIALOG__H
#include <QDialog>
#include <QColorDialog>
#include <QCheckBox>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QVector>
#include <QRandomGenerator>
class SettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit SettingsDialog(int curveCount, QWidget *parent = nullptr);
~SettingsDialog();
double getXMin() const;
double getXMax() const;
double getYMin() const;
double getYMax() const;
QColor getCurveColor(int index) const;
QColor getBackgroundColor() const;
QVector<QColor> getCurveColors() const;
bool isGridVisible() const;
private:
QLineEdit *xMinLineEdit;
QLineEdit *xMaxLineEdit;
QLineEdit *yMinLineEdit;
QLineEdit *yMaxLineEdit;
QVector<QPushButton*> curveColorButtons;
QPushButton *backgroundColorButton;
QVector<QColor> curveColors;
QColor backgroundColor;
QCheckBox *gridCheckBox;
void setupCurveColorButtons(int curveCount);
void initializeCurveColors(int size, quint32 seed);
void updateColorButton(QPushButton *button, const QColor &color);
};
#endif // SETTINGSDIALOG__H

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>settingsdialog</class>
<widget class="QDialog" name="settingsdialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>30</x>
<y>240</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>settingsdialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>settingsdialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,19 @@
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
template_dir = os.path.join(BASE_DIR, 'input')
output_dir = os.path.join(BASE_DIR, 'output')
os.makedirs(output_dir, exist_ok=True)
output_html_path = os.path.join(output_dir, 'generated_report.html')
output_excel_html_path = os.path.join(output_dir, 'excel_generated_report.html')
output_pdf_path = os.path.join(output_dir, 'generated_report.pdf')
output_docx_path = os.path.join(output_dir, 'generated_report.docx')
output_excel_path = os.path.join(output_dir, 'excel_generated_report.xlsx')
report_html_path = os.path.join(template_dir, 'report_template.html')
image_path = os.path.join(template_dir, 'image.png')

View File

@ -0,0 +1,54 @@
from jinja2 import Environment, FileSystemLoader
import config
from process.inference import html2excel_pandas
def render_html(template, output_file_path):
sheets_data = [
{
'name': 'Personal Info',
'columns': ['Name', 'Age', 'Occupation'],
'data': [
['Alice', 30, 'Engineer'],
['Bob', 25, 'Data Scientist'],
['Charlie', 35, 'Teacher']
]
},
{
'name': 'Scores',
'columns': ['Name', 'Math', 'Science', 'English'],
'data': [
['Alice', 85, 92, 88],
['Bob', 78, 81, 86],
['Charlie', 93, 89, 91]
]
},
{
'name': 'Attendance',
'columns': ['Name', 'January', 'February', 'March'],
'data': [
['Alice', 'Present', 'Absent', 'Present'],
['Bob', 'Absent', 'Present', 'Present'],
['Charlie', 'Present', 'Present', 'Present']
]
}
]
# 渲染模板
html_content = template.render(sheets=sheets_data)
with open(output_file_path, 'w', encoding='utf-8') as f:
f.write(html_content)
def main():
env = Environment(loader=FileSystemLoader(config.template_dir))
template = env.get_template("excel_template.html")
render_html(template, config.output_excel_html_path)
html2excel_pandas(config.output_excel_html_path, config.output_excel_path)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ report_title }}</title>
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
color: #333;
line-height: 1.6;
}
header {
background: #4CAF50;
color: white;
padding: 20px 0;
text-align: center;
}
header h1 {
margin: 0;
font-size: 2em;
}
nav {
background: #333;
color: white;
overflow: hidden;
}
nav a {
float: left;
/* display: block; */
color: white;
text-align: center;
padding: 14px 20px;
text-decoration: none;
}
nav a:hover {
background-color: #ddd;
color: black;
}
.container {
padding: 20px;
}
h2 {
color: #4CAF50;
font-size: 1.5em;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
margin-bottom: 20px;
}
h3 {
color: #333;
font-size: 1.3em;
margin-bottom: 10px;
}
p {
font-size: 1em;
line-height: 1.6;
margin-bottom: 20px;
}
.section {
margin-bottom: 40px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
padding: 8px;
text-align: left;
}
th {
background-color: #4CAF50;
color: white;
}
.highlight {
background-color: #ffff99;
}
footer {
background: #333;
color: white;
text-align: center;
padding: 10px 0;
position: relative;
width: 100%;
bottom: 0;
margin-top: 20px; /* 增加顶部边距以避免覆盖内容 */
}
.image-container {
width: 200px;
margin: 0 auto; /* 居中对齐 */
}
.image-container img {
width: 100%;
height: auto; /* 保持纵横比 */
}
</style>
</head>
<body>
<header>
<h1>{{ report_title }}</h1>
</header>
<nav>
<a href="#section1">章节划分</a>
<a href="#section2">静态描述内容</a>
<a href="#section3">动态加载内容</a>
<a href="#section4">报告命名规则</a>
<a href="#section5">版本管理</a>
<a href="#section6">分类属性</a>
<a href="#section7">表格数据</a>
<a href="#section8">高亮内容</a>
<a href="#section9">图片展示</a>
<a href="#section10">联系信息</a>
</nav>
<div class="container">
{% block content %}{% endblock %}
</div>
<footer>
<div>版本信息:{{ version_management.current_version }} - {{ version_management.description }} - {{ version_management.status }}</div>
<div>&copy; eCL3000 报告生成系统</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Base Template{% endblock %}</title>
<style>
body {
font-family: Arial, sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: left;
}
</style>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>

View File

@ -0,0 +1,28 @@
{% extends "excel_base_template.html" %}
{% block title %}Excel Report{% endblock %}
{% block content %}
<h1>Excel Report</h1>
{% for sheet in sheets %}
<h2>{{ sheet.name }}</h2>
<table>
<thead>
<tr>
{% for column in sheet.columns %}
<th>{{ column }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in sheet.data %}
<tr>
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% endblock %}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,95 @@
{% extends "base_template.html" %}
{% block content %}
<div id="section1" class="section">
<h2>章节划分</h2>
{% for section in sections %}
<div class="section">
<h3>{{ section.title }}</h3>
<p>{{ section.content }}</p>
</div>
{% endfor %}
</div>
<div id="section2" class="section">
<h2>静态描述内容</h2>
{% for component in static_descriptions %}
<div class="component">
<h3>{{ component.name }}</h3>
<p>{{ component.description }}</p>
</div>
{% endfor %}
</div>
<div id="section3" class="section">
<h2>动态加载内容</h2>
{% for content in dynamic_contents %}
<div class="content">
<p>{{ content }}</p>
</div>
{% endfor %}
</div>
<div id="section4" class="section">
<h2>报告实例化后的命名规则</h2>
<p>{{ naming_rules }}</p>
</div>
<div id="section5" class="section">
<h2>版本管理</h2>
<p>当前版本:{{ version_management.current_version }}</p>
<p>版本描述:{{ version_management.description }}</p>
<p>版本状态:{{ version_management.status }}</p>
</div>
<div id="section6" class="section">
<h2>报告模板的分类属性</h2>
<p>{{ classification_attributes }}</p>
</div>
<div id="section7" class="section">
<h2>表格数据</h2>
<table>
<tr>
<th>列1</th>
<th>列2</th>
<th>列3</th>
</tr>
{% for row in table_data %}
<tr>
<td>{{ row.col1 }}</td>
<td>{{ row.col2 }}</td>
<td>{{ row.col3 }}</td>
</tr>
{% endfor %}
</table>
</div>
<div id="section8" class="section">
<h2>高亮内容</h2>
<p class="highlight">{{ highlight_content }}</p>
</div>
<div id="section9" class="section">
<h2>图片展示</h2>
{% for image in images %}
<!-- <div class="image-container"> -->
<!-- <img src="{{ image.src }}" alt="{{ image.alt }}"> -->
<div style="text-align: center; margin-bottom: 10px;">
<img src="{{ image.src }}" alt="{{ image.alt }}" style="width: 200px; height: auto;">
<p>{{ image.caption }}</p>
</div>
{% endfor %}
</div>
<div id="section10" class="section">
<h2>联系信息</h2>
{% if contact %}
<p>联系人:{{ contact.name }}</p>
<p>电话:{{ contact.phone }}</p>
<p>邮箱:{{ contact.email }}</p>
{% else %}
<p>暂无联系信息。</p>
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,190 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Excel Report</title>
<style>
body {
font-family: Arial, sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: left;
}
</style>
</head>
<body>
<h1>Excel Report</h1>
<h2>Personal Info</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Occupation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>30</td>
<td>Engineer</td>
</tr>
<tr>
<td>Bob</td>
<td>25</td>
<td>Data Scientist</td>
</tr>
<tr>
<td>Charlie</td>
<td>35</td>
<td>Teacher</td>
</tr>
</tbody>
</table>
<h2>Scores</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Math</th>
<th>Science</th>
<th>English</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>85</td>
<td>92</td>
<td>88</td>
</tr>
<tr>
<td>Bob</td>
<td>78</td>
<td>81</td>
<td>86</td>
</tr>
<tr>
<td>Charlie</td>
<td>93</td>
<td>89</td>
<td>91</td>
</tr>
</tbody>
</table>
<h2>Attendance</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>January</th>
<th>February</th>
<th>March</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>Present</td>
<td>Absent</td>
<td>Present</td>
</tr>
<tr>
<td>Bob</td>
<td>Absent</td>
<td>Present</td>
<td>Present</td>
</tr>
<tr>
<td>Charlie</td>
<td>Present</td>
<td>Present</td>
<td>Present</td>
</tr>
</tbody>
</table>
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1,246 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电动机起动分析报告</title>
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
color: #333;
line-height: 1.6;
}
header {
background: #4CAF50;
color: white;
padding: 20px 0;
text-align: center;
}
header h1 {
margin: 0;
font-size: 2em;
}
nav {
background: #333;
color: white;
overflow: hidden;
}
nav a {
float: left;
/* display: block; */
color: white;
text-align: center;
padding: 14px 20px;
text-decoration: none;
}
nav a:hover {
background-color: #ddd;
color: black;
}
.container {
padding: 20px;
}
h2 {
color: #4CAF50;
font-size: 1.5em;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
margin-bottom: 20px;
}
h3 {
color: #333;
font-size: 1.3em;
margin-bottom: 10px;
}
p {
font-size: 1em;
line-height: 1.6;
margin-bottom: 20px;
}
.section {
margin-bottom: 40px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
padding: 8px;
text-align: left;
}
th {
background-color: #4CAF50;
color: white;
}
.highlight {
background-color: #ffff99;
}
footer {
background: #333;
color: white;
text-align: center;
padding: 10px 0;
position: relative;
width: 100%;
bottom: 0;
margin-top: 20px; /* 增加顶部边距以避免覆盖内容 */
}
.image-container {
width: 200px;
margin: 0 auto; /* 居中对齐 */
}
.image-container img {
width: 100%;
height: auto; /* 保持纵横比 */
}
</style>
</head>
<body>
<header>
<h1>电动机起动分析报告</h1>
</header>
<nav>
<a href="#section1">章节划分</a>
<a href="#section2">静态描述内容</a>
<a href="#section3">动态加载内容</a>
<a href="#section4">报告命名规则</a>
<a href="#section5">版本管理</a>
<a href="#section6">分类属性</a>
<a href="#section7">表格数据</a>
<a href="#section8">高亮内容</a>
<a href="#section9">图片展示</a>
<a href="#section10">联系信息</a>
</nav>
<div class="container">
<div id="section1" class="section">
<h2>章节划分</h2>
<div class="section">
<h3>章节一</h3>
<p>内容一</p>
</div>
<div class="section">
<h3>章节二</h3>
<p>内容二</p>
</div>
</div>
<div id="section2" class="section">
<h2>静态描述内容</h2>
<div class="component">
<h3>组件1</h3>
<p>这是组件1的静态描述内容。</p>
</div>
<div class="component">
<h3>组件2</h3>
<p>这是组件2的静态描述内容。</p>
</div>
</div>
<div id="section3" class="section">
<h2>动态加载内容</h2>
<div class="content">
<p>动态内容1</p>
</div>
<div class="content">
<p>动态内容2</p>
</div>
</div>
<div id="section4" class="section">
<h2>报告实例化后的命名规则</h2>
<p>报告的命名规则包括...</p>
</div>
<div id="section5" class="section">
<h2>版本管理</h2>
<p>当前版本1.0</p>
<p>版本描述:初始版本</p>
<p>版本状态:可用</p>
</div>
<div id="section6" class="section">
<h2>报告模板的分类属性</h2>
<p>电动机态势感知类</p>
</div>
<div id="section7" class="section">
<h2>表格数据</h2>
<table>
<tr>
<th>列1</th>
<th>列2</th>
<th>列3</th>
</tr>
<tr>
<td>数据1-1</td>
<td>数据1-2</td>
<td>数据1-3</td>
</tr>
<tr>
<td>数据2-1</td>
<td>数据2-2</td>
<td>数据2-3</td>
</tr>
</table>
</div>
<div id="section8" class="section">
<h2>高亮内容</h2>
<p class="highlight">这是高亮显示的内容。</p>
</div>
<div id="section9" class="section">
<h2>图片展示</h2>
<!-- <div class="image-container"> -->
<!-- <img src="/home/dengjinlai/ReportGeneration/ReportGeneration/input/image.png" alt="图片1"> -->
<div style="text-align: center; margin-bottom: 10px;">
<img src="/home/dengjinlai/ReportGeneration/ReportGeneration/input/image.png" alt="图片1" style="width: 200px; height: auto;">
<p>这是一张示例图片1</p>
</div>
<!-- <div class="image-container"> -->
<!-- <img src="/home/dengjinlai/ReportGeneration/ReportGeneration/input/image.png" alt="图片2"> -->
<div style="text-align: center; margin-bottom: 10px;">
<img src="/home/dengjinlai/ReportGeneration/ReportGeneration/input/image.png" alt="图片2" style="width: 200px; height: auto;">
<p>这是一张示例图片2</p>
</div>
</div>
<div id="section10" class="section">
<h2>联系信息</h2>
<p>联系人:张三</p>
<p>电话1234567890</p>
<p>邮箱zhangsan@example.com</p>
</div>
</div>
<footer>
<div>版本信息1.0 - 初始版本 - 可用</div>
<div>&copy; eCL3000 报告生成系统</div>
</footer>
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1,103 @@
import aspose.words as aw
import pdfkit
from docx import Document
from docx.oxml.ns import qn
import pandas as pd
# from docx.oxml import OxmlElement
def remove_mark_from_doc(doc):
# 移除aspose库的标记
def remove_images_from_element(element):
#移除嵌入的图片
for paragraph in element.paragraphs:
for run in paragraph.runs:
drawing_elements = run._element.findall(qn('w:drawing'))
for drawing in drawing_elements:
drawing.getparent().remove(drawing)
pict_elements = run._element.findall(qn('w:pict'))
for pict in pict_elements:
pict.getparent().remove(pict)
def remove_text_from_element(element, text_to_remove=None):
# 移除aspose的标记此处为页脚处的
if text_to_remove == None:
text_to_remove = "Evaluation Only. Created with Aspose.Words. Copyright 2003-2024 Aspose Pty Ltd."
for paragraph in element.paragraphs:
if text_to_remove in paragraph.text:
# 清除特定文本
paragraph.clear()
for section in doc.sections:
header = section.header
footer = section.footer
remove_images_from_element(header)
remove_text_from_element(footer)
#删除第一段落
if doc.paragraphs:
first_paragraph = doc.paragraphs[0]
p = first_paragraph._element
p.getparent().remove(p)
def html2docx_aspose(html_path, docx_path):
doc = aw.Document(html_path)
doc.save(docx_path,aw.SaveFormat.DOCX)
doc = Document(docx_path)
remove_mark_from_doc(doc)
doc.save(docx_path)
print("word报告生成成功")
def html2pdf_pdfkit(html_path, pdf_path):
# 将HTML文件转换为PDF
options = {
'page-size': 'Letter',
'margin-top': '0.35in',
'margin-right': '0.75in',
'margin-bottom': '0.75in',
'margin-left': '0.75in',
'encoding': "UTF-8",
'no-outline': None,
'enable-local-file-access': None
}
pdfkit.from_file(html_path, pdf_path, options=options)
print("pdf报告生成成功")
def html2excel_pandas(html_path, excel_path):
# 将HTML文件转换为EXCEL
tables = pd.read_html(html_path)
# 创建一个Excel工作簿
with pd.ExcelWriter(excel_path) as writer:
# 写入到Excel的不同工作表中
for i, df in enumerate(tables):
sheet_name = f'Sheet{i+1}'
df.to_excel(writer, sheet_name=sheet_name, index=False)
print("excel文件生成成功")
###############################备选方案
def html2docx_pypandoc(html_path, docx_path):
import pypandoc
pypandoc.convert_file(html_path, 'docx', outputfile=docx_path)
print("Word报告生成成功")
def html2docx_spire(html_path, docx_path):
from spire.doc import FileFormat,XHTMLValidationType,Document
# from spire.doc.common import *
document = Document()
document.LoadFromFile(html_path, FileFormat.Html, XHTMLValidationType.none)
document.SaveToFile(docx_path, FileFormat.Docx2016)
document.Close()

View File

@ -0,0 +1,60 @@
from jinja2 import Environment, FileSystemLoader
import config
from process.inference import html2docx_aspose, html2pdf_pdfkit
def render_html(template, output_file_path):
# 定义报告数据
report_data = {
'report_title': '电动机起动分析报告',
'sections': [
{'title': '章节一', 'content': '内容一'},
{'title': '章节二', 'content': '内容二'}
],
'static_descriptions': [
{'name': '组件1', 'description': '这是组件1的静态描述内容。'},
{'name': '组件2', 'description': '这是组件2的静态描述内容。'}
],
'dynamic_contents': ['动态内容1', '动态内容2'],
'naming_rules': '报告的命名规则包括...',
'version_management': {
'current_version': '1.0',
'description': '初始版本',
'status': '可用'
},
'classification_attributes': '电动机态势感知类',
'table_data': [
{'col1': '数据1-1', 'col2': '数据1-2', 'col3': '数据1-3'},
{'col1': '数据2-1', 'col2': '数据2-2', 'col3': '数据2-3'}
],
'highlight_content': '这是高亮显示的内容。',
'images': [
{'src': config.image_path, 'alt': '图片1', 'caption': '这是一张示例图片1'},
{'src': config.image_path, 'alt': '图片2', 'caption': '这是一张示例图片2'}
],
'contact': {
'name': '张三',
'phone': '1234567890',
'email': 'zhangsan@example.com'
}
}
# 渲染模板
report_html = template.render(report_data)
with open(output_file_path, 'w', encoding='utf-8') as f:
f.write(report_html)
def main():
env = Environment(loader=FileSystemLoader(config.template_dir))
template = env.get_template("report_template.html")
render_html(template, config.output_html_path)
html2pdf_pdfkit(config.output_html_path, config.output_pdf_path)
html2docx_aspose(config.output_html_path, config.output_docx_path)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,22 @@
# sudo apt-get install pandoc
python-docx==1.1.2
pypandoc==1.13
pandas==2.2.2
opencv-python==4.10.0.84
openpyxl==3.1.4
Jinja2==3.1.4
aspose-words==24.7.0
# matplotlib==3.9.1.post1
# scip==1.14.0
# Spire.Doc==12.7.1
# html2docx==1.6.0
# sudo dpkg -i libssl1.0.0_1.0.2g-1ubuntu4.20_amd64.deb
# wget http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.0.0_1.0.2g-1ubuntu4.20_amd64.deb

View File

@ -0,0 +1,60 @@
import openpyxl
from openpyxl.styles import Font, Alignment, PatternFill
from openpyxl.worksheet.table import Table, TableStyleInfo
# 创建一个新的工作簿
workbook = openpyxl.Workbook()
# 获取默认的工作表
sheet = workbook.active
sheet.title = 'Sales Data'
# 设置列宽
sheet.column_dimensions['A'].width = 20
sheet.column_dimensions['B'].width = 15
sheet.column_dimensions['C'].width = 15
sheet.column_dimensions['D'].width = 15
# 写入标题行
title_font = Font(bold=True, color="FFFFFF")
title_fill = PatternFill(start_color="0072BA", end_color="0072BA", fill_type="solid")
title_alignment = Alignment(horizontal="center", vertical="center")
title_row = ['Product', 'Sales Q1', 'Sales Q2', 'Sales Q3']
sheet.append(title_row) # 添加标题行数据
# 添加数据
data = [
('Product A', 1000, 1200, 1100),
('Product B', 800, 900, 950),
('Product C', 1100, 1000, 1200),
('Product D', 950, 1100, 1050),
]
for row in data:
sheet.append(row)
# 创建第二个工作表
sheet2 = workbook.create_sheet(title='Summary')
# 写入数据到第二个工作表
summary_data = [
('Total Sales', sum(row[1] for row in data), sum(row[2] for row in data), sum(row[3] for row in data)),
]
for row in summary_data:
sheet2.append(row)
# 创建一个Excel表格对象
table = Table(displayName="SalesTable", ref="A1:D6")
style = TableStyleInfo(name="xmlColumnPr", showFirstColumn=False,
showLastColumn=False, showRowStripes=True, showColumnStripes=True)
table.tableStyleInfo = style
# 将表格添加到工作表
sheet.add_table(table)
# 保存工作簿
workbook.save('example.xlsx')
print("Excel文件已生成")

View File

@ -0,0 +1,12 @@
from html2docx import html2docx
with open("output/generated_report.html") as fp:
html = fp.read()
# html2docx() returns an io.BytesIO() object. The HTML must be valid.
buf = html2docx(html, title="My Document")
with open("my.docx", "wb") as fp:
fp.write(buf.getvalue())

View File

@ -0,0 +1,12 @@
from spire.doc import FileFormat,XHTMLValidationType,Document
# from spire.doc.common import *
# 创建Document类的对象
document = Document()
# 加载一个HTML文件
document.LoadFromFile("output/generated_report.html", FileFormat.Html, XHTMLValidationType.none)
# 将HTML文件保存为.docx格式
document.SaveToFile("Html文件转为Word2.docx", FileFormat.Docx2016)
document.Close()

View File

@ -0,0 +1,61 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_curves_and_function(curves, function, file_path):
# 创建图表和轴
fig, ax = plt.subplots(figsize=(10, 8))
# 设置x轴和y轴的对数刻度
ax.set_xscale('log')
ax.set_yscale('log')
# 设置网格
ax.grid(True, which="both", ls="--", linewidth=0.5)
# 生成函数曲线
I_values = np.logspace(1, 4, 100) # 生成从 10 到 10000 的等比数据点
t_values = function(I_values)
# 把t_values中的负值变为not a number
t_values = np.where(t_values > 0, t_values, np.nan)
# 绘制曲线
ax.plot(I_values, t_values, label='Function Curve', color='black', linestyle='--')
ax.annotate('Function Curve', xy=(I_values[-1], t_values[-1]), textcoords="offset points", xytext=(-20, 10), ha='center')
for label, data in curves.items():
ax.plot(data['x'], data['y'], label=label, color=data['color'])
ax.annotate(label, xy=(data['x'][-1], data['y'][-1]), textcoords="offset points", xytext=(10, -10), ha='center')
# 设置标签和标题
ax.set_xlabel('Axis-X', fontsize=12)
ax.set_ylabel('Axis-Y', fontsize=12)
ax.set_title('Example of a logarithmic graph', fontsize=14)
# 设置轴限
ax.set_xlim([5, 10000])
ax.set_ylim([0.01, 1000])
# 保存图表
plt.savefig(file_path)
# plt.show()
if __name__ == "__main__":
curves = {
'Curve0': {'x': [10, 30, 100, 1000, 3000], 'y': [1000, 100, 10, 1, 0.1], 'color': 'blue'},
'Curve1': {'x': [10, 30, 100, 1000, 3000], 'y': [1000, 300, 30, 3, 0.3], 'color': 'green'},
'Curve2': {'x': [10, 30, 100, 1000, 3000], 'y': [1000, 200, 20, 2, 0.2], 'color': 'purple'},
'Curve3': {'x': [15, 40, 150, 1500, 5000], 'y': [500, 50, 5, 0.5, 0.05], 'color': 'orange'},
'Curve4': {'x': [10, 30, 100, 1000, 3000], 'y': [800, 80, 8, 0.8, 0.08], 'color': 'red'},
'Curve5': {'x': [20, 60, 200, 2000, 6000], 'y': [1000, 150, 15, 1.5, 0.15], 'color': 'brown'}
}
Tp = 1
I_op = 100
# 定义函数表达式
def function_expression(I_values):
epsilon = 1e-10
return 80 * Tp / (((I_values / I_op) ** 2 - 1) + epsilon)
plot_curves_and_function(curves, function_expression, file_path="log_chart.png")

View File

@ -0,0 +1,25 @@
import cv2
def resize_image(input_path, output_path, new_width=200):
# 读取原始图片
img = cv2.imread(input_path, cv2.IMREAD_UNCHANGED)
# 计算新的高度,保持纵横比
height, width = img.shape[:2]
width_percent = (new_width / float(width))
new_height = int((float(height) * width_percent))
# 调整图片大小
# resized_img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_LANCZOS4)
resized_img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_AREA)
# 保存调整后的图片
cv2.imwrite(output_path, resized_img)
print(f"图片已保存为 {output_path}")
if __name__ == "__main__":
resize_image("./input/image.png","temp2.png")