latex received_time update

This commit is contained in:
wangjinlei
2025-11-14 15:40:02 +08:00
parent 32c071aea4
commit a3fb591537
2 changed files with 340 additions and 334 deletions

View File

@@ -1250,338 +1250,6 @@ class Production extends Base
// return jsonSuccess([]);
// }
/**
* 生成LaTeX文档并转换为PDF
* @return \think\response\Json
*/
public function generateLatexPdf()
{
$data = $this->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('/<img[^>]*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('/<table[^>]*tableId=[\'"]([^\'"]+)[\'"][^>]*>/i', $text, $table_matches)) {
$table_id = $table_matches[1];
// 这里可以添加表格处理逻辑
$latex .= '% 表格插入位置 (ID: ' . $table_id . ')' . "\n";
$latex .= '\begin{table}[htbp]' . "\n";
$latex .= '\centering' . "\n";
$latex .= '\caption{表格说明}' . "\n";
$latex .= '\begin{tabular}{|c|c|c|}' . "\n";
$latex .= '\hline' . "\n";
$latex .= '列1 & 列2 & 列3 \\\\' . "\n";
$latex .= '\hline' . "\n";
$latex .= '% 表格数据' . "\n";
$latex .= '\hline' . "\n";
$latex .= '\end{tabular}' . "\n";
$latex .= '\end{table}' . "\n";
}
// 普通段落文本
else {
// 移除HTML标签并转义特殊字符
$plain_text = $this->escapeLatexText(strip_tags($text));
$latex .= $plain_text . "\n\n";
}
}
// 参考文献
if (!empty($references)) {
$latex .= '\section*{References}' . "\n";
$latex .= '\begin{thebibliography}{99}' . "\n";
foreach ($references as $index => $ref) {
$ref_text = isset($ref['refer_frag']) ? $ref['refer_frag'] : $ref['refer_content'];
$latex .= '\bibitem{} ' . $this->escapeLatexText($ref_text) . "\n";
}
$latex .= '\end{thebibliography}' . "\n";
}
$latex .= '\end{document}' . "\n";
return $latex;
}
/**
* 转义LaTeX特殊字符
* @param string $text
* @return string
*/
private function escapeLatexText($text)
{
// 移除HTML标签
$text = strip_tags($text);
// 转义LaTeX特殊字符
$escape_chars = [
'\\' => '\\textbackslash{}',
'&' => '\\&',
'%' => '\\%',
'$' => '\\$',
'#' => '\\#',
'_' => '\\_',
'{' => '\\{',
'}' => '\\}',
'~' => '\\textasciitilde{}',
'^' => '\\textasciicircum{}',
'"' => '\\"{}',
'\'' => '\\\'{}',
'<' => '\\textless{}',
'>' => '\\textgreater{}',
];
foreach ($escape_chars as $char => $replacement) {
$text = str_replace($char, $replacement, $text);
}
return $text;
}
public function addProductTopic(){
$data = $this->request->post();
$rule = new Validate([
@@ -1705,8 +1373,8 @@ private function escapeLatexText($text)
$typesetInfo['website'] = $journal_info['website'];
$typesetInfo['acknowledgment'] = $p_info['acknowledgment'];
$received_info = $this->article_msg_obj->where("article_id",$p_info['article_id'])->where("state_from",4)->where("state_to",1)->find();
$received_data = $received_info?$received_info['ctime']:$article_info['ctime'];
// $received_info = $this->article_msg_obj->where("article_id",$p_info['article_id'])->where("state_from",4)->where("state_to",1)->find();
$received_data = $article_info['received_time']>0?$article_info['received_time']:$article_info['ctime'];
$typesetInfo['received_date'] = date("d F Y", $received_data);
$super_num = $this->article_author_obj->where("article_id",$p_info['article_id'])->where("state",0)->where("is_super",1)->count();