281 lines
8.0 KiB
Python
281 lines
8.0 KiB
Python
import os
|
||
import base64
|
||
import subprocess
|
||
import tempfile
|
||
from datetime import datetime
|
||
|
||
|
||
class PDFGenerator:
|
||
"""PDF 生成器类(Pandoc 版)"""
|
||
|
||
def __init__(self, main_font: str = "Noto Serif CJK SC"):
|
||
"""
|
||
初始化 PDF 生成器
|
||
|
||
Args:
|
||
main_font: Pandoc / XeLaTeX 使用的中文字体名
|
||
"""
|
||
self.main_font = main_font
|
||
|
||
def generate_pdf_from_text(
|
||
self,
|
||
text_content: str,
|
||
output_path: str = None,
|
||
title: str = "维修报告",
|
||
return_base64: bool = True
|
||
) -> dict:
|
||
"""
|
||
将 Markdown 文本内容生成 PDF 文件
|
||
|
||
Args:
|
||
text_content: Markdown 文本内容
|
||
output_path: PDF 输出路径(可选)
|
||
title: PDF 标题
|
||
return_base64: 是否返回 base64 编码内容
|
||
"""
|
||
try:
|
||
# 输出路径
|
||
if output_path is None:
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
output_path = f"temp_report_{timestamp}.pdf"
|
||
|
||
# 生成临时 Markdown 文件
|
||
with tempfile.NamedTemporaryFile(
|
||
mode="w",
|
||
suffix=".md",
|
||
delete=False,
|
||
encoding="utf-8"
|
||
) as md_file:
|
||
md_path = md_file.name
|
||
|
||
# 写入标题 + 内容
|
||
if title:
|
||
md_file.write(f"# {title}\n\n")
|
||
md_file.write(text_content.strip())
|
||
|
||
# Pandoc 命令:使用自定义 LaTeX 模板解决排版问题
|
||
cmd = [
|
||
"pandoc",
|
||
md_path,
|
||
"--pdf-engine=xelatex",
|
||
"-V", f"mainfont={self.main_font}",
|
||
"-V", "geometry:margin=2cm", # 增加页边距
|
||
"-V", "fontsize=10pt", # 字体大小
|
||
"-V", "lineskip=1.5", # 行距
|
||
"--template=template.tex", # 使用自定义模板
|
||
"-o", output_path
|
||
]
|
||
|
||
# 执行转换
|
||
subprocess.run(
|
||
cmd,
|
||
check=True,
|
||
stdout=subprocess.PIPE,
|
||
stderr=subprocess.PIPE
|
||
)
|
||
|
||
result = {
|
||
"success": True,
|
||
"file_path": output_path
|
||
}
|
||
|
||
# 返回 base64
|
||
if return_base64:
|
||
with open(output_path, "rb") as f:
|
||
result["base64_content"] = base64.b64encode(
|
||
f.read()
|
||
).decode("utf-8")
|
||
|
||
return result
|
||
|
||
except subprocess.CalledProcessError as e:
|
||
return {
|
||
"success": False,
|
||
"error": e.stderr.decode("utf-8")
|
||
}
|
||
except Exception as e:
|
||
return {
|
||
"success": False,
|
||
"error": str(e)
|
||
}
|
||
finally:
|
||
# 清理临时 md 文件
|
||
if "md_path" in locals() and os.path.exists(md_path):
|
||
os.remove(md_path)
|
||
|
||
|
||
# 创建自定义 LaTeX 模板文件 template.tex
|
||
def create_latex_template():
|
||
"""创建一个用于中文排版的 LaTeX 模板(Pandoc 正确版)"""
|
||
template = r"""
|
||
\documentclass[10pt]{article}
|
||
\usepackage[UTF8]{ctex}
|
||
\usepackage{geometry}
|
||
\usepackage{graphicx}
|
||
\usepackage{amsmath}
|
||
\usepackage{array}
|
||
\usepackage{booktabs}
|
||
\usepackage{longtable}
|
||
\usepackage{setspace}
|
||
\usepackage{fancyhdr}
|
||
\usepackage{titlesec}
|
||
\usepackage{tabularx}
|
||
\usepackage{makecell}
|
||
\usepackage{adjustbox}
|
||
\usepackage{hyperref}
|
||
% 页面设置
|
||
\geometry{margin=2cm}
|
||
\setlength{\parskip}{1em}
|
||
\setlength{\parindent}{0em}
|
||
|
||
% 字体
|
||
\setCJKmainfont{Noto Serif CJK SC}
|
||
|
||
% 标题样式
|
||
\title{\Large \textbf{$title$}}
|
||
\author{}
|
||
\date{}
|
||
|
||
% 章节标题样式
|
||
\titleformat{\section}{\large\bfseries\raggedright}{\thesection}{1em}{}
|
||
\titleformat{\subsection}{\normalsize\bfseries\raggedright}{\thesubsection}{1em}{}
|
||
|
||
|
||
% ===== Pandoc compatibility =====
|
||
\usepackage{hyperref}
|
||
\providecommand{\tightlist}{%
|
||
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
|
||
|
||
|
||
\begin{document}
|
||
|
||
\maketitle
|
||
|
||
$body$
|
||
|
||
\end{document}
|
||
"""
|
||
with open("template.tex", "w", encoding="utf-8") as f:
|
||
f.write(template)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# 生成报告函数不变,但调用前先创建模板
|
||
def generate_report_pdf(
|
||
report_content: str,
|
||
device_name: str = "未知设备",
|
||
output_dir: str = None
|
||
) -> dict:
|
||
"""
|
||
生成维修报告 PDF
|
||
"""
|
||
# 先创建模板文件
|
||
create_latex_template()
|
||
|
||
generator = PDFGenerator()
|
||
|
||
# 文件名规则不变
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
safe_device_name = device_name.replace(" ", "_").replace("/", "_")
|
||
file_name = f"{safe_device_name}_维修报告_{timestamp}.pdf"
|
||
|
||
if output_dir:
|
||
os.makedirs(output_dir, exist_ok=True)
|
||
output_path = os.path.join(output_dir, file_name)
|
||
else:
|
||
output_path = file_name
|
||
|
||
result = generator.generate_pdf_from_text(
|
||
text_content=report_content,
|
||
output_path=output_path,
|
||
title="设备维修报告",
|
||
return_base64=True
|
||
)
|
||
|
||
if result.get("success"):
|
||
result["file_name"] = file_name
|
||
|
||
return result
|
||
|
||
|
||
# 测试代码
|
||
if __name__ == "__main__":
|
||
test_md = """
|
||
三、根本原因判断
|
||
|
||
根据设备当前状态、维修方案参考和知识库检索结果,最可能的根本原因如下:
|
||
|
||
**根本原因**:缸盖密封环老化或失效
|
||
**次级原因**:启动阀卡滞或内部泄漏
|
||
|
||
---
|
||
|
||
四、原因分析说明
|
||
|
||
1. **缸盖密封环老化或失效**
|
||
- 缸盖密封环是气缸密封的关键部件,其老化或损坏会导致气缸压缩气体泄漏,压缩压力下降。
|
||
- 启动时,压缩压力不足会导致点火困难,主机启动延迟或失败。
|
||
- 此类问题在长期运行或未定期保养的设备中较为常见。
|
||
|
||
2. **启动阀卡滞或内部泄漏**
|
||
- 启动阀的功能是控制启动气进入气缸,若其卡滞或内部泄漏,将导致启动气供应不足或不及时,影响启动成功率。
|
||
- 内部泄漏还会造成启动气浪费,进一步降低启动成功率。
|
||
- 启动阀若未定期维护,容易因灰尘、杂质或润滑不良而卡滞。
|
||
|
||
3. **气缸套磨损**
|
||
- 气缸套磨损会导致气缸密封性下降,压缩气体泄漏,压缩压力不足。
|
||
- 该问题通常发生在长期运行、润滑不良或未及时更换气缸套的设备中。
|
||
|
||
4. **活塞环磨损或断裂**
|
||
- 活塞环磨损或断裂会导致气缸密封性下降,压缩气体泄漏,从而影响压缩压力。
|
||
- 该问题通常与长期运行、润滑不良或材料疲劳有关。
|
||
|
||
5. **调速系统响应异常**
|
||
- 调速系统异常可能导致主机启动时转速控制不稳,但其对压缩压力的影响相对较小,通常不是导致压缩压力不足的主要原因。
|
||
|
||
---
|
||
|
||
五、预防建议
|
||
|
||
1. 定期更换缸盖密封环
|
||
- 根据设备运行时间和使用情况,制定合理的密封环更换计划,避免因老化导致密封性能下降。
|
||
- 建议每运行 5000 小时进行一次检查,必要时更换。
|
||
|
||
2. 加强启动阀维护
|
||
- 定期清理启动阀内部积碳和杂质,保持润滑良好。
|
||
- 每 1000 小时进行一次功能测试。
|
||
|
||
3. 监控气缸套和活塞环状态
|
||
- 通过内窥镜或压力测试定期检测气缸套与活塞环磨损情况。
|
||
- 发现异常及时更换。
|
||
|
||
4. 优化润滑系统
|
||
- 使用符合标准的润滑油,确保润滑充分。
|
||
- 定期更换滤芯,防止杂质进入关键部件。
|
||
|
||
5. 定期校准调速系统
|
||
- 每季度进行一次调速系统校准,确保响应灵敏。
|
||
- 记录历史数据,建立趋势分析模型。
|
||
"""
|
||
|
||
result = generate_report_pdf(
|
||
test_md,
|
||
device_name="压缩机设备"
|
||
)
|
||
|
||
if result["success"]:
|
||
print(f"✓ PDF 生成成功:{result['file_name']}")
|
||
print(f"✓ 文件路径:{result['file_path']}")
|
||
print(f"✓ Base64 长度:{len(result['base64_content'])}")
|
||
else:
|
||
print(f"✗ PDF 生成失败:{result['error']}")
|