生成pdf

This commit is contained in:
chengxl
2025-12-31 16:06:35 +08:00
parent 85d441cc60
commit 838e25028f

View File

@@ -37,7 +37,7 @@ year={{stage_year}},%年
volume={{stage_vol}},%卷 volume={{stage_vol}},%卷
no={{stage_no}},%期 no={{stage_no}},%期
page={{stage_page}},%号 page={{stage_page}},%号
]{tmr-tex} ]{../tmr-tex}
\doi{{{doi}}} \doi{{{doi}}}
\journalweb{{{website}}} \journalweb{{{website}}}
@@ -49,18 +49,15 @@ page={{stage_page}},%号
\usepackage[nopatch]{microtype} \usepackage[nopatch]{microtype}
\usepackage{booktabs} \usepackage{booktabs}
\usepackage[backend=biber]{biblatex} \usepackage[backend=biber]{biblatex}
\usepackage{xcolor} % 蓝色字体(参考文献) \usepackage{xcolor}
\usepackage{multirow} % 单元格合并(必选) \usepackage{tabularray}
\usepackage{array} % 列格式居中(必选) \addbibresource{references_{{p_article_id}}.bib}
\usepackage{geometry} % 页面适配,避免内容溢出 \definecolor{evenRowColor}{RGB}{250,231,232}
\addbibresource{example.bib}
\title{{{article_title}}} \title{{{article_title}}}
{{author_info}} {{author_info}}
\addbibresource{example.bib}
{{correspondence_info}} {{correspondence_info}}
@@ -87,6 +84,8 @@ page={{stage_page}},%号
\twocolumn \twocolumn
{{tmr_highlight}} {{tmr_highlight}}
{{article_main}} {{article_main}}
\nocite{*}
\printbibliography[title={References}]
\end{document}'; \end{document}';
/** /**
* 生成初稿-基本内容 * 生成初稿-基本内容
@@ -211,6 +210,7 @@ page={{stage_page}},%号
$aSearch['{{article_icon}}'] = $sIcon; $aSearch['{{article_icon}}'] = $sIcon;
$aSearch['{{keywords}}'] = $sKeywords; $aSearch['{{keywords}}'] = $sKeywords;
$aSearch['{{CLSFILEURL}}'] = ROOT_PATH.'public/latex/cls'; $aSearch['{{CLSFILEURL}}'] = ROOT_PATH.'public/latex/cls';
$aSearch['{{p_article_id}}'] = $aProductionArticle['p_article_id'];
//模版内容替换 //模版内容替换
$sTemplateInfo = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplateInfo); $sTemplateInfo = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplateInfo);
//返回内容 //返回内容
@@ -220,8 +220,11 @@ page={{stage_page}},%号
* 生成初稿-主内容 * 生成初稿-主内容
* @param article_id 文章ID * @param article_id 文章ID
*/ */
public function buildMain($aProductionArticle = []){ public function buildMain($aParam = []){
//生产环境文章信息
$aProductionArticle = empty($aParam['production_article']) ? [] : $aParam['production_article'];
//参考文献信息
$aReferences = empty($aParam['references']) ? [] : $aParam['references'];
//获取模版 //获取模版
$sTemplateInfo = $this->sMain; $sTemplateInfo = $this->sMain;
@@ -256,17 +259,19 @@ page={{stage_page}},%号
$aWhere = ['ami_id' => ['in',$aAmiId],'state' => 0]; $aWhere = ['ami_id' => ['in',$aAmiId],'state' => 0];
$aArticleMainImage = Db::name('article_main_image')->field('ami_id,url,note')->where($aWhere)->select(); $aArticleMainImage = Db::name('article_main_image')->field('ami_id,url,note')->where($aWhere)->select();
$aArticleMainImage = empty($aArticleMainImage) ? [] : array_column($aArticleMainImage, null,'ami_id'); $aArticleMainImage = empty($aArticleMainImage) ? [] : array_column($aArticleMainImage, null,'ami_id');
//查询表格 // //查询表格
$aAmtId = array_unique(array_column($aArticleMain, 'amt_id')); // $aAmtId = array_unique(array_column($aArticleMain, 'amt_id'));
$aWhere = ['amt_id' => ['in',$aAmtId],'state' => 0]; // $aWhere = ['amt_id' => ['in',$aAmtId],'state' => 0];
$aArticleMainTable = Db::name('article_main_table')->field('amt_id,type,table_data,url,title,note')->where($aWhere)->select(); // $aArticleMainTable = Db::name('article_main_table')->field('amt_id,type,table_data,url,title,note')->where($aWhere)->select();
$aArticleMainTable = empty($aArticleMainTable) ? [] : array_column($aArticleMainTable, null,'amt_id'); // $aArticleMainTable = empty($aArticleMainTable) ? [] : array_column($aArticleMainTable, null,'amt_id');
//获取图片模版 //获取图片模版
$sImageTempalte = $this->sImageTempalte; $sImageTempalte = $this->sImageTempalte;
//数据处理 //数据处理
$iStart = 0; $iStart = 0;
$sMain = ''; $sMain = '';
$oLatexTable = new LaTeXTable; $oLatexTable = new LaTeXTable;
//字符串处理
$oProduction = new \app\api\controller\Production;
foreach ($aArticleMain as $key => $value) { foreach ($aArticleMain as $key => $value) {
if(empty($iStart)){ if(empty($iStart)){
if($value['is_h1'] == 0){ if($value['is_h1'] == 0){
@@ -296,7 +301,7 @@ page={{stage_page}},%号
} }
if($value['is_h1'] == 0 && $value['is_h2'] == 0 && $value['is_h3'] == 0){ if($value['is_h1'] == 0 && $value['is_h2'] == 0 && $value['is_h3'] == 0){
if($value['type'] == 0 ){ if($value['type'] == 0 ){
$sMain .= $this->dealContent($value['content'])."\\par\n"; $sMain .= $this->dealContent($value['content'],$aReferences)."\\par\n";
} }
if($value['type'] == 1 ){//图片 if($value['type'] == 1 ){//图片
$aImageInfo = empty($aArticleMainImage[$value['ami_id']]) ? [] : $aArticleMainImage[$value['ami_id']]; $aImageInfo = empty($aArticleMainImage[$value['ami_id']]) ? [] : $aArticleMainImage[$value['ami_id']];
@@ -321,8 +326,20 @@ page={{stage_page}},%号
$sMain .= $sImageTempalteInfo."\\par\n"; $sMain .= $sImageTempalteInfo."\\par\n";
} }
if($value['type'] == 2 ){//表格 if($value['type'] == 2 ){//表格
continue; $sTableInfo = $oProduction->tableCovertLatex($value['amt_id'],$aReferences);
var_dump($sTableInfo);
$sMain .= $sTableInfo."\\par\n";
// $aTableInfo = empty($aArticleMainTable[$value['amt_id']]) ? [] : $aArticleMainTable[$value['amt_id']];
// if(empty($aTableInfo['table_data'])){
// continue;
// }
// $aTableResult = $oLatexTable->generateTable($aTableInfo);
// var_dump($aTableResult);exit;
// if(empty($aTableResult['data'])){
// continue;
// }
} }
} }
} }
} }
@@ -536,40 +553,138 @@ page={{stage_page}},%号
/** /**
* 内容处理 * 内容处理
*/ */
private function dealContent($content = '', $target = 'latex',$iIsDeal = 1) { // private function dealContent($content = '', $target = 'latex',$iIsDeal = 1) {
// // 空值直接返回
// if (empty($content)) {
// return '';
// }
// //统一编码为UTF-8
// $content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content));
// //过滤不可见/非法字符
// $content = preg_replace('/[\x00-\x1F\x7F]/u', '', $content);
// //整合所有替换规则按优先级排序先处理HTML实体再处理LaTeX特殊字符
// $replaceRules = [
// // ========== HTML实体替换 ==========
// ' ' => '~', // HTML非断行空格 → LaTeX非断行空格
// '&nbsp' => '~', // 兼容无分号的&nbsp
// '&' => '\&', // HTML& → LaTeX转义&
// '&lt;' => '<', // HTML< → 直接保留
// '&gt;' => '>', // HTML> → 直接保留
// // ========== LaTeX特殊字符转义 ==========
// '{' => '\{', // 左花括号转义
// '}' => '\}', // 右花括号转义
// '&' => '\&', // 原生&转义(需在&amp;之后,避免覆盖)
// '%' => '\%', // 百分号转义LaTeX注释符
// '_' => '\_', // 下划线转义LaTeX下标符
// 'κ' => '$\kappa$', // 希腊字母κ → LaTeX数学环境避免乱码
// '-' => '\text{-}', // 短横线强制保留形态
// ':' => ':', // 冒号无需转义(占位,便于统一维护)
// ];
// //执行批量替换
// $content = strtr($content, $replaceRules);
// //清理多余空格/换行
// $content = preg_replace('/\s+/u', ' ', trim($content));
// if($iIsDeal == 1){
// $content = $this->htmlToLaTeX($content);
// }
// return $content;
// }
private function dealContent($content = '',$aReferences = []) {
// 空值直接返回 // 空值直接返回
if (empty($content)) { if(empty($content)){
return ''; return '';
} }
//统一编码为UTF-8 //统一编码为UTF-8
$content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content)); $content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content));
//过滤不可见/非法字符 //过滤不可见/非法字符
$content = preg_replace('/[\x00-\x1F\x7F]/u', '', $content); $content = preg_replace('/[\x00-\x1F\x7F]/u', '', $content);
//整合所有替换规则按优先级排序先处理HTML实体再处理LaTeX特殊字符
$replaceRules = [ //字符串处理
// ========== HTML实体替换 ========== $oProduction = new \app\api\controller\Production;
'&nbsp;' => '~', // HTML非断行空格 → LaTeX非断行空格 $sContent = $oProduction->convertToLatex($content,$aReferences);
'&nbsp' => '~', // 兼容无分号的&nbsp $content = $this->htmlToLaTeX($content);
'&amp;' => '\&', // HTML& → LaTeX转义& return $sContent;
'&lt;' => '<', // HTML< → 直接保留 // //整合所有替换规则按优先级排序先处理HTML实体再处理LaTeX特殊字符
'&gt;' => '>', // HTML> → 直接保留 // $replaceRules = [
// ========== LaTeX特殊字符转义 ========== // // ========== HTML实体替换 ==========
'{' => '\{', // 左花括号转义 // '&nbsp;' => '~', // HTML非断行空格 → LaTeX非断行空格
'}' => '\}', // 右花括号转义 // '&nbsp' => '~', // 兼容无分号的&nbsp
'&' => '\&', // 原生&转义(需在&amp;之后,避免覆盖) // '&amp;' => '\&', // HTML& → LaTeX转义&
'%' => '\%', // 百分号转义LaTeX注释符 // '&lt;' => '<', // HTML< → 直接保留
'_' => '\_', // 下划线转义LaTeX下标符 // '&gt;' => '>', // HTML> → 直接保留
'κ' => '$\kappa$', // 希腊字母κ → LaTeX数学环境避免乱码 // // ========== LaTeX特殊字符转义 ==========
'-' => '\text{-}', // 短横线强制保留形态 // '{' => '\{', // 左花括号转义
':' => ':', // 冒号无需转义(占位,便于统一维护) // '}' => '\}', // 右花括号转义
// '&' => '\&', // 原生&转义(需在&amp;之后,避免覆盖)
// '%' => '\%', // 百分号转义LaTeX注释符
// '_' => '\_', // 下划线转义LaTeX下标符
// 'κ' => '$\kappa$', // 希腊字母κ → LaTeX数学环境避免乱码
// '-' => '\text{-}', // 短横线强制保留形态
// ':' => ':', // 冒号无需转义(占位,便于统一维护)
// ];
// //执行批量替换
// $content = strtr($content, $replaceRules);
// //清理多余空格/换行
// $content = preg_replace('/\s+/u', ' ', trim($content));
// if($iIsDeal == 1){
// $content = $this->htmlToLaTeX($content);
// }
// return $content;
}
private function htmlToLaTeX($text = ''){
if(empty($text)){
return '';
}
$replaceMap = [
// 基础标签转换
'<i>' => '\textit{',
'</i>' => '}',
'<em>' => '\textit{',
'</em>' => '}',
'<b>' => '\textbf{',
'</b>' => '}',
'<blue>' => '\textcolor{blue}{',
'</blue>' => '}',
'<p>' => '',
'</p>' => '',
'<sub>' => '$_{',
'</sub>' => '}$',
'<sup>' => '$^{',
'</sup>' => '}$',
'~' => '--', // 波浪号→范围符
'' => '(', // 全角左括号→半角
'' => ')', // 全角右括号→半角
'(' => '(', // 重复括号去重
')' => ')',
// ========== 新增:<span> 标签处理 ==========
// 场景1纯空 <span> 标签(无属性)→ 直接删除,保留内容
'<span>' => '',
'</span>' => '',
// 场景2带蓝色样式的 <span style="color:blue"> → 转为 LaTeX 蓝色命令
'<span style="color:blue">' => '\textcolor{blue}{',
'<span style="color: Blue;">' => '\textcolor{blue}{', // 兼容大小写/空格
'<span style="color:red">' => '\textcolor{red}{', // 扩展:红色
'</span>' => '}', // 所有 span 闭标签统一转为 }(匹配开标签的 LaTeX 命令)
// 扩展:其他常用 span 样式(按需添加)
'<span style="font-weight:bold">' => '\textbf{',
'<span style="font-style:italic">' => '\textit{',
]; ];
//执行批量替换 // 第一步:替换所有标签(优先处理带属性的 span再处理空 span
$content = strtr($content, $replaceRules); $text = strtr($text, $replaceMap);
//清理多余空格/换行
$content = preg_replace('/\s+/u', ' ', trim($content)); // 第二步:清理残留的特殊 span 标签(如未匹配的属性,直接删除标签保留内容)
return $content; // 匹配 <span ...> 形式的标签(任意属性),仅删除标签,保留内容
$text = preg_replace('/<span(\s+[^>]*?)?>/i', '', $text);
$text = preg_replace('/<\/span>/i', '', $text);
return $text;
} }
/** /**
* @title curl 请求获取图片保存到本地 * @title curl 请求获取图片保存到本地