Merge remote-tracking branch 'origin/master'

This commit is contained in:
wangjinlei
2026-01-07 11:42:18 +08:00
2 changed files with 150 additions and 67 deletions

View File

@@ -3298,9 +3298,14 @@ class Production extends Base
echo $res;
}
public function tableCovertLatex($amt_id, $references)
public function tableCovertLatex($amt_id, $references,$aTableInfo = [])
{
$table_info = $this->article_main_table_obj->where('amt_id', $amt_id)->find();
if(empty($aTableInfo)){
$table_info = $this->article_main_table_obj->where('amt_id', $amt_id)->find();
}else{
$table_info = $aTableInfo;
}
$tableData = json_decode($table_info['table_data'], true);
// 检查JSON解码是否成功
@@ -3615,7 +3620,7 @@ class Production extends Base
}
//查询文章
$aWhere = ['p_article_id' => $iPArticleId,'state' => 0];
$aWhere = ['p_article_id' => $iPArticleId,'state' => ['in',[0,2]]];
$aProductionArticle = Db::name('production_article')->where($aWhere)->find();
if(empty($aProductionArticle)){
return json_encode(array('status' => 3,'msg' => 'No articles found' ));
@@ -3638,20 +3643,87 @@ class Production extends Base
return json_encode(array('status' => 5,'msg' => 'Article content retrieval failed'));
}
//获取参考文献
$aResult = $this->creatReferences($aProductionArticle);
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
$sMsg = empty($aResult['msg']) ? 'Content generation failed-Reference' : $aResult['msg'];
$aResult = empty($aResult['data']) ? [] : $aResult['data'];
$sReferences = empty($aResult['references']) ? '' : $aResult['references'];//参考文献内容
$aReferencesLists = empty($aResult['references_list']) ? [] : $aResult['references_list'];//参考文献数组
if($iStatus != 1){
return json_encode(array('status' => 8,'msg' => $sMsg));
}
if(empty($sReferences)){
return json_encode(array('status' => 9,'msg' => 'Article content retrieval failed'));
}
//生成主内容
$aResult = $oLatexContent->buildMain($aProductionArticle);
$aResult = $oLatexContent->buildMain(['production_article' => $aProductionArticle,'references' => $aReferencesLists]);
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
$sMsg = empty($aResult['msg']) ? 'Content generation failed-Main' : $aResult['msg'];
$sMainTemplateInfo = empty($aResult['data']) ? '' : $aResult['data'];
if($iStatus != 1){
return json_encode(array('status' => 4,'msg' => $sMsg));
return json_encode(array('status' => 6,'msg' => $sMsg));
}
if(empty($sMainTemplateInfo)){
return json_encode(array('status' => 5,'msg' => 'Article content retrieval failed'));
return json_encode(array('status' => 7,'msg' => 'Article content retrieval failed'));
}
//生成文件
//创建基础目录
$sDir = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $iPArticleId;
if (!is_dir($sDir)) {
mkdir($sDir, 0755, true);
}
//生成Reference文件
$sFileUrl = $sDir. DS . 'references_' . $iPArticleId . '.bib';
file_put_contents($sFileUrl, $sReferences);
if(!file_exists($sFileUrl)){
return json_encode(array('status' => 10,'msg' => 'Reference file generation failed'));
}
//生成运行文件.tex
$sTexName = 'article_' . $iPArticleId;
$sTexFileUrl = $sDir. DS . $sTexName .'.tex';
$sTemplateInfo = $sFirstTemplateInfo."\n".$sMainTemplateInfo;
file_put_contents($sTexFileUrl, $sTemplateInfo);
return json_encode(array('status' => 1,'msg' => 'PDF generated successfully'));
}
/**
* 生成初稿-参考文献
* @param p_article_id 生产环境文章信息
*/
private function creatReferences($aParam = []){
$aParam = empty($aParam) ? $this->request->post() : $aParam;
//必填值验证
$iPArticleId = empty($aParam['p_article_id']) ? '' : $aParam['p_article_id'];
if(empty($iPArticleId)){
return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
}
//查询参考文献
$aWhere = ['p_article_id' => $iPArticleId,'state' => 0];
$aReferences = Db::name('production_article_refer')->where($aWhere)->order('index asc')->select();
if(empty($aReferences)){
return json_encode(array('status' => 3,'msg' => 'No reference information found' ));
}
//参考文献处理
$sContent = "% BibTeX file generated for article ID: {$iPArticleId}\n";
$sContent .= "% Generated on " . date('Y-m-d H:i:s') . "\n\n";
$sReferences = '';
$aReferencesLists = [];
foreach ($aReferences as $value) {
$aReferencesLists[$value['index'] + 1] = $value;
$sReferencesInfo = $this->generateBibEntry($value);
if(empty($sReferencesInfo)){
continue;
}
$sReferences .= $sReferencesInfo . "\n\n";
}
if(empty($sReferences)){
return json_encode(array('status' => 4,'msg' => 'No reference information found' ));
}
$sContent .= $sReferences;
return ['status' => 1,'msg' => 'success','data' => ['references' => $sContent,'references_list' => $aReferencesLists]];
}
}

View File

@@ -14,7 +14,7 @@ class LatexContent{
//模版地址
private $sLatexUrl = '/public/latex/';
//期刊官网接口地址
private $sJournalUrl = 'http://zmzm.journal.dev.com/';//'http://journalapi.tmrjournals.com/public/index.php/';//
private $sJournalUrl = 'http://journalapi.tmrjournals.com/public/index.php/';//'http://zmzm.journal.dev.com/';//
//文章图片
private $sArticleIcon = '/public/articleicon/';
//文章图片
@@ -259,6 +259,11 @@ page={{stage_page}},%号
$aWhere = ['ami_id' => ['in',$aAmiId],'state' => 0];
$aArticleMainImage = Db::name('article_main_image')->field('ami_id,url,note')->where($aWhere)->select();
$aArticleMainImage = empty($aArticleMainImage) ? [] : array_column($aArticleMainImage, null,'ami_id');
//查询表格
$aAmtId = array_unique(array_column($aArticleMain, 'amt_id'));
$aWhere = ['amt_id' => ['in',$aAmtId],'state' => 0];
$aArticleMainTable = Db::name('article_main_table')->where($aWhere)->select();
$aArticleMainTable = empty($aArticleMainTable) ? [] : array_column($aArticleMainTable, null,'amt_id');
//获取图片模版
$sImageTempalte = $this->sImageTempalte;
//数据处理
@@ -316,16 +321,23 @@ page={{stage_page}},%号
if(empty($aResult['data'])){
continue;
}
$aImageSearch = ['{{img_url}}' => $aResult['data'],'{{img_title}}' => $aImageInfo['note'],'{{img_fig_sim}}' => 'img_fig_sim_'.$value['ami_id']];
$sImageTempalteInfo = str_replace(array_keys($aImageSearch), array_values($aImageSearch), $sImageTempalte);
$sMain .= $sImageTempalteInfo."\\par\n";
// $aImageSearch = ['{{img_url}}' => $aResult['data'],'{{img_title}}' => $aImageInfo['note'],'{{img_fig_sim}}' => 'img_fig_sim_'.$value['ami_id']];
// $sImageTempalteInfo = str_replace(array_keys($aImageSearch), array_values($aImageSearch), $sImageTempalte);
$aImageInfo['image_url'] = $aResult['data'];
$aDealImage = $this->dealImage($aImageInfo);
if(empty($aDealImage['data'])){
continue;
}
$sMain .= $aDealImage['data']."\\par\n";
}
if($value['type'] == 2 ){//表格
$sTableInfo = $oProduction->tableCovertLatex($value['amt_id'],$aReferences);
var_dump($sTableInfo);
$aTableInfo = empty($aArticleMainTable[$value['amt_id']]) ? [] : $aArticleMainTable[$value['amt_id']];
if(empty($aTableInfo['table_data'])){
continue;
}
$sTableInfo = $oProduction->tableCovertLatex($value['amt_id'],$aReferences,$aTableInfo);
$sMain .= $sTableInfo."\\par\n";
}
}
}
}
@@ -549,60 +561,8 @@ page={{stage_page}},%号
//字符串处理
$oProduction = new \app\api\controller\Production;
$sContent = $oProduction->convertToLatex($content,$aReferences);
$content = $this->htmlToLaTeX($content);
return $sContent;
}
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
$text = strtr($text, $replaceMap);
// 第二步:清理残留的特殊 span 标签(如未匹配的属性,直接删除标签保留内容)
// 匹配 <span ...> 形式的标签(任意属性),仅删除标签,保留内容
$text = preg_replace('/<span(\s+[^>]*?)?>/i', '', $text);
$text = preg_replace('/<\/span>/i', '', $text);
return $text;
}
/**
* @title curl 请求获取图片保存到本地
* @param sPath 图片链接地址
@@ -620,7 +580,7 @@ page={{stage_page}},%号
$sExtension = empty($aImageInfo['extension']) ? 'jpg' : $aImageInfo['extension'];
//图片地址
$sDir = ROOT_PATH.trim($this->sLatexUrl,'/').'/article_pdf/'.$iId.'/';
$sDir = ROOT_PATH.trim($this->sLatexUrl,'/').'/tex_'.$iId.'/image/';
$sImagePath = $sDir.basename($sPath);
if (file_exists($sImagePath)) {
return ['status' => 1,'msg' => 'success','data' => $sImagePath];
@@ -645,6 +605,57 @@ page={{stage_page}},%号
return ['status' => 1,'msg' => 'success','data' => $sImagePath];
}
/**
* @title curl 图片Latex代码封装
*/
private function dealImage($aImageInfo = []){
//获取图片路径
$sImageUrl = empty($aImageInfo['image_url']) ? '' : $aImageInfo['image_url'];
if(empty($sImageUrl)){
return ['status' => 2,'msg' => 'The image link is empty'];
}
//判断图片是否存在
if(!file_exists($sImageUrl)){
return ['status' => 3,'msg' => 'The image does not exist:'.$sImageUrl];
}
// 检测图片尺寸
$imageInfo = getimagesize($sImageUrl);
$imageWidth = $imageInfo[0]; // 图片宽度
$imageHeight = $imageInfo[1]; // 图片高度
// 定义宽度阈值例如宽度大于600像素则使用两栏
$wideImageThreshold = 600;
$isWideImage = $imageWidth > $wideImageThreshold;
// 生成LaTeX图片代码
if ($isWideImage) {
$latexLines[] = "\\begin{figure*}[htbp]"; // 使用figure*环境实现两栏
$latexLines[] = " \\centering";
$latexLines[] = " \\includegraphics[width=0.9\\textwidth]{" . $sImageUrl . "}"; // 使用全宽度
} else {
$latexLines[] = "\\begin{figure}[H]";
$latexLines[] = " \\centering";
$latexLines[] = " \\includegraphics[width=0.9\\textwidth]{" . $sImageUrl . "}";
}
if(!empty($aImageInfo['title']) && !empty($aImageInfo['note'])){
$escapedTitle = '{\fontspec{Calibri}\footnotesize\bfseries\color{figerTitleColor} '.$this->dealContent(preg_replace('/^Figure\s+\d+\s*/i', '', $aImageInfo['title']),[]).'}\\\\';
$escapedTitle .= '{\vspace{0.5em}\raggedright\small {'.$this->dealContent($aImageInfo['note'],[]).'}}';
$latexLines[] = " \\caption{" . $escapedTitle . "}";
}
if (!empty($ami_info['title'])) {
$escapedTitle = $this->dealContent(preg_replace('/^Figure\s+\d+\s*/i', '', $ami_info['title']),[]);
$latexLines[] = " \\caption{" . $escapedTitle . "}";
}
$latexLines[] = "\\end{figure" . ($isWideImage ? "*" : "") . "}";
return ['status' => 1,'msg' => 'success','data' => implode("\n", $latexLines)];
}
}
?>