Compare commits
13 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
eaa879d463 | |
|
|
e1dd28762d | |
|
|
388d24d6ac | |
|
|
bdbb616f2c | |
|
|
52a6d03899 | |
|
|
95c7522a1e | |
|
|
ee61bdf60c | |
|
|
609428be96 | |
|
|
39bade0355 | |
|
|
f1878e7fa9 | |
|
|
a69955100b | |
|
|
a7721a1797 | |
|
|
c73f848e01 |
|
|
@ -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()
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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()));
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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')
|
||||
|
|
@ -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()
|
||||
|
|
@ -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>© eCL3000 报告生成系统</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 |
|
|
@ -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 %}
|
||||
|
|
@ -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.
Binary file not shown.
|
|
@ -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>© eCL3000 报告生成系统</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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文件已生成!")
|
||||
|
|
@ -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())
|
||||
|
||||
|
||||
|
|
@ -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()
|
||||
Binary file not shown.
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
||||
Loading…
Reference in New Issue