From a3fb591537e9d8f0c1fab4eaa1a6c13952332a1a Mon Sep 17 00:00:00 2001
From: wangjinlei <751475802@qq.com>
Date: Fri, 14 Nov 2025 15:40:02 +0800
Subject: [PATCH] latex received_time update
---
application/api/controller/Latex.php | 338 ++++++++++++++++++++++
application/api/controller/Production.php | 336 +--------------------
2 files changed, 340 insertions(+), 334 deletions(-)
create mode 100644 application/api/controller/Latex.php
diff --git a/application/api/controller/Latex.php b/application/api/controller/Latex.php
new file mode 100644
index 0000000..ada2341
--- /dev/null
+++ b/application/api/controller/Latex.php
@@ -0,0 +1,338 @@
+request->post();
+ $rule = new Validate([
+ 'p_article_id' => 'require|number'
+ ]);
+
+ if (!$rule->check($data)) {
+ return jsonError($rule->getError());
+ }
+
+ try {
+ // 获取文章信息
+ $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find();
+ if (!$p_info) {
+ return jsonError('文章实例不存在');
+ }
+
+ // 获取作者信息
+ $authors = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select();
+
+ // 获取机构信息
+ $organs = $this->production_article_organ_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select();
+
+ // 获取正文内容
+ $main_contents = $this->production_article_main_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->order('p_main_id')->select();
+
+ // 获取参考文献
+ $references = $this->production_article_refer_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->order('index')->select();
+
+ // 构建LaTeX内容
+ $latex_content = $this->buildLatexContent($p_info, $authors, $organs, $main_contents, $references);
+
+ // 创建临时目录
+ $temp_dir = ROOT_PATH . 'public' . DS . 'temp_latex' . DS;
+ if (!is_dir($temp_dir)) {
+ mkdir($temp_dir, 0755, true);
+ }
+
+ // 生成唯一的文件名
+ $filename = 'article_' . $p_info['p_article_id'] . '_' . time();
+ $tex_file = $temp_dir . $filename . '.tex';
+ $pdf_file = $temp_dir . $filename . '.pdf';
+
+ // 写入LaTeX文件
+ file_put_contents($tex_file, $latex_content);
+
+ // 执行LaTeX编译命令生成PDF
+ $command = sprintf(
+ 'cd %s && pdflatex -interaction=nonstopmode -output-directory=%s %s',
+ escapeshellarg($temp_dir),
+ escapeshellarg($temp_dir),
+ escapeshellarg($tex_file)
+ );
+
+ // 执行命令
+ $output = [];
+ $return_var = 0;
+ exec($command, $output, $return_var);
+
+ // 检查PDF是否生成成功
+ if (!file_exists($pdf_file) || filesize($pdf_file) == 0) {
+ return jsonError('PDF生成失败,请检查LaTeX内容或系统环境');
+ }
+
+ // 移动PDF到正式目录
+ $pdf_dir = ROOT_PATH . 'public' . DS . 'latex_pdfs' . DS;
+ if (!is_dir($pdf_dir)) {
+ mkdir($pdf_dir, 0755, true);
+ }
+
+ $final_pdf_path = $pdf_dir . $filename . '.pdf';
+ rename($pdf_file, $final_pdf_path);
+
+ // 清理临时文件
+ if (file_exists($tex_file)) {
+ unlink($tex_file);
+ }
+
+ // 清理辅助文件(.aux, .log等)
+ $aux_file = $temp_dir . $filename . '.aux';
+ $log_file = $temp_dir . $filename . '.log';
+ if (file_exists($aux_file)) unlink($aux_file);
+ if (file_exists($log_file)) unlink($log_file);
+
+ // 返回PDF路径
+ $relative_path = 'latex_pdfs/' . $filename . '.pdf';
+ return jsonSuccess([
+ 'pdf_url' => $relative_path,
+ 'message' => 'PDF生成成功'
+ ]);
+
+ } catch (\Exception $e) {
+ return jsonError('生成过程中发生错误: ' . $e->getMessage());
+ }
+ }
+
+ /**
+ * 构建LaTeX文档内容
+ * @param $p_info
+ * @param $authors
+ * @param $organs
+ * @param $main_contents
+ * @param $references
+ * @return string
+ */
+ private function buildLatexContent($p_info, $authors, $organs, $main_contents, $references)
+ {
+ // 构建机构映射
+ $organ_map = [];
+ foreach ($organs as $index => $organ) {
+ $organ_map[$organ['p_article_organ_id']] = $index + 1;
+ }
+
+ // LaTeX文档开始
+ $latex = '\documentclass[twocolumn]{article}' . "\n";
+ $latex .= '\usepackage[utf8]{inputenc}' . "\n";
+ $latex .= '\usepackage[T1]{fontenc}' . "\n";
+ $latex .= '\usepackage{geometry}' . "\n";
+ $latex .= '\usepackage{graphicx}' . "\n";
+ $latex .= '\usepackage{amsmath}' . "\n";
+ $latex .= '\usepackage{amsfonts}' . "\n";
+ $latex .= '\usepackage{amssymb}' . "\n";
+ $latex .= '\usepackage{setspace}' . "\n";
+ $latex .= '\usepackage{titlesec}' . "\n";
+ $latex .= '\usepackage{hyperref}' . "\n";
+ $latex .= '\usepackage{caption}' . "\n";
+ $latex .= '\usepackage{multicol}' . "\n";
+ $latex .= '\usepackage{abstract}' . "\n";
+
+ $latex .= '\geometry{left=1.5cm,right=1.5cm,top=2.5cm,bottom=2.5cm}' . "\n";
+ $latex .= '\setstretch{1.5}' . "\n";
+
+ $latex .= '\title{' . $this->escapeLatexText($p_info['title']) . '}' . "\n";
+
+ // 处理作者和机构
+ if (!empty($authors)) {
+ $author_text = '';
+ $affiliations = [];
+
+ foreach ($authors as $author) {
+ if ($author_text !== '') {
+ $author_text .= ', ';
+ }
+ $author_text .= $this->escapeLatexText($author['first_name'] . ' ' . $author['last_name']);
+
+ // 获取作者的机构
+ $author_organs = $this->production_article_author_to_organ_obj
+ ->where('p_article_author_id', $author['p_article_author_id'])
+ ->where('state', 0)
+ ->select();
+
+ foreach ($author_organs as $ao) {
+ if (isset($organ_map[$ao['p_article_organ_id']])) {
+ $author_text .= '$^{' . $organ_map[$ao['p_article_organ_id']] . '}$';
+ }
+ }
+
+ if ($author['is_report'] == 1) {
+ $author_text .= '$^{*}$';
+ }
+ }
+
+ $latex .= '\author{' . $author_text . "\n";
+
+ // 添加机构信息
+ foreach ($organs as $index => $organ) {
+ $latex .= '\\\\$' . ($index + 1) . '$ ' . $this->escapeLatexText($organ['organ_name']) . "\n";
+ }
+ if (!empty($authors)) {
+ // 查找通讯作者
+ $corresponding_authors = array_filter($authors, function($author) {
+ return $author['is_report'] == 1;
+ });
+
+ if (!empty($corresponding_authors)) {
+ $corr_author = reset($corresponding_authors);
+ $latex .= '\\\\$*$ Corresponding author: ' .
+ $this->escapeLatexText($corr_author['email']) . "\n";
+ }
+ }
+
+ $latex .= '}' . "\n";
+ }
+
+ $latex .= '\date{}' . "\n";
+ $latex .= '\begin{document}' . "\n";
+ $latex .= '\maketitle' . "\n";
+
+ // 摘要
+ if (!empty($p_info['abstract'])) {
+ $latex .= '\begin{abstract}' . "\n";
+ $latex .= $this->escapeLatexText($p_info['abstract']) . "\n";
+ $latex .= '\end{abstract}' . "\n";
+ }
+
+ // 关键词
+ if (!empty($p_info['keywords'])) {
+ $latex .= '\textbf{Keywords:} ' . $this->escapeLatexText($p_info['keywords']) . "\n";
+ $latex .= '\sectionbreak' . "\n";
+ }
+
+ // 正文内容
+ $in_section = false;
+ $section_count = 0;
+
+ foreach ($main_contents as $content) {
+ $text = trim($content['content']);
+
+ // 跳过空内容
+ if (empty($text)) {
+ continue;
+ }
+
+ // 检查是否是标题
+ $clean_text = strip_tags($text);
+ $lower_text = strtolower($clean_text);
+
+ // 判断是否为章节标题
+ if (stripos($lower_text, 'introduction') === 0 ||
+ stripos($lower_text, 'methods') === 0 ||
+ stripos($lower_text, 'results') === 0 ||
+ stripos($lower_text, 'discussion') === 0 ||
+ stripos($lower_text, 'conclusion') === 0 ||
+ stripos($lower_text, 'references') === 0) {
+
+ // 结束前一节
+ if ($in_section) {
+ $latex .= "\n" . '\sectionbreak' . "\n";
+ }
+
+ // 开始新节
+ $section_count++;
+ $section_title = $this->escapeLatexText($clean_text);
+ $latex .= '\section{' . $section_title . '}' . "\n";
+ $in_section = true;
+ }
+ // 检查是否是图片或表格占位符
+ else if (preg_match('/]*imageId=[\'"]([^\'"]+)[\'"][^>]*>/i', $text, $img_matches)) {
+ $image_id = $img_matches[1];
+ // 这里可以添加图片处理逻辑
+ $latex .= '% 图片插入位置 (ID: ' . $image_id . ')' . "\n";
+ $latex .= '\begin{figure}[htbp]' . "\n";
+ $latex .= '\centering' . "\n";
+ $latex .= '\includegraphics[width=0.8\textwidth]{image_' . $image_id . '}' . "\n";
+ $latex .= '\caption{图片说明}' . "\n";
+ $latex .= '\end{figure}' . "\n";
+ }
+ else if (preg_match('/