Files
tougao/application/common/LatexContent.php
2026-02-14 14:00:05 +08:00

813 lines
38 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\common;
use think\Db;
use app\common\LatexTable;
/**
* LaTeX内容生成类
*/
class LatexContent{
//期刊相关的信息
private $iYear = 2026;//年
private $iPeriod = 1;//期
private $sAbbr = 'tmr';//期刊缩写
private $sWebsite = 'https://www.tmrjournals.com/tmr';//期刊官网
//模版地址
private $sLatexUrl = '/public/latex/';
//期刊官网接口地址
private $sJournalUrl = 'http://journalapi.tmrjournals.com/public/index.php/';//'http://zmzm.journal.dev.com/';//
//文章图片
private $sArticleIcon = '/public/articleicon/';
//文章图片
private $sArticleMainImage = '/public/articleImage/';
//编辑系统URL
private $sSubmissionUrl = 'https://submission.tmrjournals.com/';
//图片模版
private $sImageTempalte = '\begin{figure}[hbt!]
\centering
\includegraphics[width=0.75\linewidth]{{{img_url}}}
\caption{{{img_title}}}
\label{{{img_fig_sim}}}
\end{figure}' ;
//首页内容
private $sFirst = '\documentclass[
journal={{journal_abbr}},
journalname={{{{journal_title}}}},
layout=largetwo,
year={{stage_year}},%年
volume={{stage_vol}},%卷
articletype={{{{article_type}}}},
no={{stage_no}},%期
page={{stage_page}},%号
]{../tmr-tex}
\doi{{{doi}}}
\journalweb{{{website}}}
\usepackage{amsmath}
\usepackage{balance}
\usepackage[nopatch]{microtype}
\usepackage{booktabs}
\usepackage[backend=biber]{biblatex}
\usepackage{xcolor}
\usepackage{tabularray}
\addbibresource{references_{{article_id}}.bib}
\definecolor{evenRowColor}{RGB}{250,231,232}
\SetLeftRatio{{{left_ratio}}}
\setlength{\parindent}{1em}
\title{{{article_title}}}
{{author_info}}
\Correspondence{{{correspondence_info}}}
\keywords{keyword entry 1, keyword entry 2, keyword entry 3} %% First letter not capped
\authorcontributions{{{author_contribution}}}
\competinginterests{The authors declare no conflicts of interest.}
\Acknowledgments{{{article_acknowledgment}}}
\Peerreviewinformation{\textit{{{journal_title}}} thanks all anonymous reviewers for their contribution to the peer review of this paper}
\Abbreviations{{{article_abbreviation}}}
\Citation{{{article_cite}}}
\received{{{received_date}}}
\revised{{{revision_date}}}
\accepted{{{accepted_date}}}
\Availableonline{{{pub_date}}}
\EditorialAdvisoryBoard{{{editorial_advisory_board}}}
\Executiveeditor{{{executive_editor}}}
{{abstract}}
{{keywords}}
{{article_icon}}';
//正文内容
private $sMain = '\begin{document}
\twocolumn
{{tmr_highlight}}
{{article_main}}
\nocite{*}
\printbibliography[title={References}]
\balance
\end{document}';
/**
* 生成初稿-基本内容
* @param article_id 文章ID
*/
public function buildFirst($aProductionArticle = []){
//获取模版
$sTemplateInfo = $this->sFirst;
//查询期刊信息
$iJournalId = empty($aProductionArticle['journal_id']) ? 0 : $aProductionArticle['journal_id'];
if(!empty($iJournalId)){
$aWhere = ['journal_id' => $iJournalId,'state' => 0];
$aJournal = Db::name('journal')->where($aWhere)->find();
if(!empty($aJournal)){
//获取编辑信息
$aWhere = ['user_id' => $aJournal['editor_id'],'state' => 0];
$aUser = Db::name('user')->field('realname')->where($aWhere)->find();
}
}
//子刊信息
$aJournalStage = [];
$iJournalStageId = empty($aProductionArticle['journal_stage_id']) ? 0 : $aProductionArticle['journal_stage_id'];
if(!empty($iJournalStageId)){
$aJournalStage = $this->getJournalStage(['journal_stage_id' => $iJournalStageId]);
$aJournalStage = empty($aJournalStage['data']) ? [] : $aJournalStage['data'];
}
//期刊简写
$sAbbr = $this->sAbbr;//empty($aJournal['abbr']) ? $this->sAbbr : $aJournal['abbr'];
$sAbbr = strtolower($sAbbr);
$sJournalTitle = empty($aJournal['title']) ? '' : $aJournal['title'];
//年
$iYear = empty($aJournalStage['stage_year']) ? date('Y') : $aJournalStage['stage_year'];
//卷
$iVolume = empty($aJournalStage['stage_vol']) ? '' : $aJournalStage['stage_vol'];
//期
$iPeriod = empty($aJournalStage['stage_no']) ? '' : $aJournalStage['stage_no'];
//页
$sPage = empty($aProductionArticle['npp']) ? '' : $aProductionArticle['npp'];
//期刊web
$sWebsite = empty($aJournal['website']) ? $this->sWebsite : $aJournal['website'];
$aSearch = ['{{journal_abbr}}' => $sAbbr,'{{stage_year}}' => $iYear,'{{stage_vol}}' => $iVolume,'{{stage_no}}' => $iPeriod,'{{stage_page}}' => $sPage,'{{website}}' => $sWebsite,'{{journal_title}}' => $sJournalTitle];
//获取DOI
if(!empty($aProductionArticle['doi'])){
$aProductionArticle['doi'] = '10.53388/'.trim($aProductionArticle['doi'],'/');
}
$aSearch['{{doi}}'] = empty($aProductionArticle['doi']) ? '' : $aProductionArticle['doi'];
//获取作者信息
$aAuthoInfo = $this->dealAuthor(['p_article_id' => $aProductionArticle['p_article_id']]);
$aSearch['{{author_info}}'] = empty($aAuthoInfo['author']) ? '' : $aAuthoInfo['author'];
//通讯作者信息
$aSearch['{{correspondence_info}}'] = empty($aAuthoInfo['correspondence']) ? '' : $aAuthoInfo['correspondence'];
//文章基本信息处理
//标题
$sTitle = empty($aProductionArticle['title']) ? '' : $this->dealContent($aProductionArticle['title']);
if(!empty($sTitle)){
if(!empty($aProductionArticle['ltai'])){
$aLtai = explode(',', $aProductionArticle['ltai']);
foreach ($aLtai as $key => $value) {
if(empty($value)){
continue;
}
$sTitle = str_replace($value, '\textit{'.$value.'}', $sTitle);
}
}
}
$aSearch['{{article_title}}'] = $sTitle;
//author_contribution
$aSearch['{{author_contribution}}'] = empty($aProductionArticle['author_contribution']) ? '' : $this->dealContent($aProductionArticle['author_contribution']);
//acknowledgment
$aSearch['{{article_acknowledgment}}'] = empty($aProductionArticle['acknowledgment']) ? '' : $this->dealContent($aProductionArticle['acknowledgment']);
//abbreviation
$aSearch['{{article_abbreviation}}'] = empty($aProductionArticle['abbreviation']) ? '' : $this->dealContent($aProductionArticle['abbreviation']);
//文章引用信息
$sCite = $this->getArticleCite($aProductionArticle,$aJournal,$aJournalStage);
$aSearch['{{article_cite}}'] = empty($sCite) ? '' : $sCite;
//文章类型
$aSearch['{{article_type}}'] = empty($aProductionArticle['type']) ? 'ARTICLE' : strtoupper($aProductionArticle['type']);
//获取文章时间
$aTime = $this->getArticleTime(['article_id' => $aProductionArticle['article_id']]);
$aTime = empty($aTime['data']) ? [] : $aTime['data'];
$aSearch['{{received_date}}'] = empty($aTime['received_date']) ? '' : $aTime['received_date'];
$aSearch['{{revision_date}}'] = '';
if(in_array( $aSearch['{{article_type}}'], ['ARTICLE','REVIEW','MINI REVIEW'])){
$aSearch['{{revision_date}}'] = empty($aTime['revision_date']) ? '' : $aTime['revision_date'];
}
$aSearch['{{accepted_date}}'] = empty($aTime['accepted_date']) ? '' : $aTime['accepted_date'];
$aSearch['{{pub_date}}'] = empty($aProductionArticle['pub_date']) ? '' : $aProductionArticle['pub_date'];
//终审编委名字
$aSearch['{{editorial_advisory_board}}'] = empty($aTime['editorial_advisory_board']) ? '' : $aTime['editorial_advisory_board'];
//获取编辑信息
$executive_editor = empty($aProductionArticle['executive_editor']) ? '' : $this->dealContent($aProductionArticle['executive_editor']);
$executive_editor_realname = empty($aUser['realname']) ? '' : $this->dealContent($aUser['realname']);
$executive_editor = empty($executive_editor) ? $executive_editor_realname : $executive_editor;
$aSearch['{{executive_editor}}'] = $executive_editor;
//摘要替换
$sAbstract = empty($aProductionArticle['abstract']) ? '' : $this->dealContent($aProductionArticle['abstract']);
if(!empty($sAbstract)){
$aRelace = ['Background:' => '\textcolor[HTML]{0070C0}{\textbf{Background:}}','Methods:' => '\\ \textcolor[HTML]{0070C0}{\textbf{Methods:}}','Results:' => '\\ \textcolor[HTML]{0070C0}{\textbf{Results:}}','Conclusion:' => '\\ \textcolor[HTML]{0070C0}{\textbf{Conclusion:}}'];
$sAbstract = str_replace(array_keys($aRelace), array_values($aRelace), $sAbstract);
$sAbstract = '\tmrabstract{'.$sAbstract.'}';
}
$aSearch['{{abstract}}'] = $sAbstract;
//关键词
$sKeywords = empty($aProductionArticle['keywords']) ? '' : '\keywords{'.$this->dealContent($aProductionArticle['keywords']).'}';
$aSearch['{{keywords}}'] = $sKeywords;
//文章图片地址
$sIcon = empty($aProductionArticle['icon']) ? '' : $aProductionArticle['icon'];
$is_graphical_abstract = empty($aProductionArticle['is_graphical_abstract']) ? 3 : $aProductionArticle['is_graphical_abstract'];//是否显示图文摘要1是2否3未选择
if(!empty($sIcon)){
$sIconUrl = ROOT_PATH.trim($this->sArticleIcon,'/').'/'.$sIcon;
if(file_exists($sIconUrl) && $is_graphical_abstract == 1){
$sIconUrl = str_replace(ROOT_PATH.'public/', '', $sIconUrl);
$sIconUrl = '../../'.$sIconUrl;
$sIcon = $sIconUrl;
}else{
$sIcon = '';
}
// //下载图片
// $sImagePath = trim($this->sSubmissionUrl,'/').$this->sArticleIcon.'/'.$sIcon;
// $aImageInfo = $this->getImage($sImagePath,$aProductionArticle['article_id']);
// if(!empty($aImageInfo['data'])){
// $aImageInfo['data'] = './image/'.basename($aImageInfo['data']);
// $sIcon = '\KeywordImage{'.$aImageInfo['data'].'}';
// }else{
// $sIcon = '';
// }
}
$aSearch['{{article_icon}}'] = '\KeywordImage{'.$sIcon.'}';
$aSearch['{{keywords}}'] = $sKeywords;
// $aSearch['{{CLSFILEURL}}'] = ROOT_PATH.'public/latex/cls';
$aSearch['{{article_id}}'] = $aProductionArticle['article_id'];
$aSearch['is_have_icon'] = empty($sIcon) ? 2 : 1;
//计算左侧内容长度
$aRatio = $this->generateLatexDynamicColumns($aSearch);
$aSearch['{{left_ratio}}'] = empty($aRatio['left_ratio']) ? '' : $aRatio['left_ratio'];
//模版内容替换
$sTemplateInfo = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplateInfo);
//返回内容
return ['status' => 1,'msg' => 'success','data' => $sTemplateInfo];
}
/**
* 生成初稿-主内容
* @param article_id 文章ID
*/
public function buildMain($aParam = []){
//生产环境文章信息
$aProductionArticle = empty($aParam['production_article']) ? [] : $aParam['production_article'];
//参考文献信息
$aReferences = empty($aParam['references']) ? [] : $aParam['references'];
//获取模版
$sTemplateInfo = $this->sMain;
//数据替换
$aSearch = ['{{tmr_highlight}}' => '','{{article_main}}' => ''];
$sHighlight = '';
if($aProductionArticle['journal_id'] == 1){//tmr独有
$tradition_tag = empty($aProductionArticle['tradition_tag']) ? '' : strtolower( $aProductionArticle['tradition_tag']);
$tradition = empty($aProductionArticle['tradition']) ? '' : $this->dealContent($aProductionArticle['tradition']);
$pattern = '/<em[^>]*>(.*?)<\/em>/is';
$replacement = '\\emph{$1}';
// $tradition = preg_replace($pattern, $replacement, $tradition);
if(in_array($tradition_tag, ['highlight','highlights']) && !empty($tradition)){
$sHighlight .= '\highlightitem{Highlights}{'.$tradition.'}'."\n";
}
$mhoo = empty($aProductionArticle['mhoo']) ? '' : $this->dealContent( $aProductionArticle['mhoo']);
$mhoo = preg_replace($pattern, $replacement, $mhoo);
if(!empty($mhoo)){
$sHighlight .= '\highlightitem{Medical history of objective}{'.$mhoo.'}'."\n";
}
}
$aSearch['{{tmr_highlight}}'] = empty($sHighlight) ? '' : '\begin{highlight}'."\n".$sHighlight."\n".'\end{highlight}'."\n";
//查询正文信息
$aWhere = ['article_id' => $aProductionArticle['article_id'],'state' => 0];
$aArticleMain = Db::name('article_main')->field('am_id,article_id,type,content,ami_id,amt_id,is_h1,is_h2,is_h3,sort')->where($aWhere)->order('sort')->select();
if(!empty($aArticleMain)){
//查询图片
$aAmiId = array_unique(array_column($aArticleMain, 'ami_id'));
$aWhere = ['ami_id' => ['in',$aAmiId],'state' => 0];
$aArticleMainImage = Db::name('article_main_image')->field('ami_id,url,title,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')->field('amt_id,type,table_data,url,title,note')->where($aWhere)->select();
$aArticleMainTable = empty($aArticleMainTable) ? [] : array_column($aArticleMainTable, null,'amt_id');
//获取图片模版
$sImageTempalte = $this->sImageTempalte;
//长表格ID
$aLongTableId = [];
//数据处理
$iStart = 0;
$sMain = '';
//字符串处理
$oProduction = new \app\api\controller\Production;
foreach ($aArticleMain as $key => $value) {
if(empty($iStart)){
if($value['is_h1'] == 0){
continue;
}else{
$iStart = $value['am_id'];
}
}
if($value['am_id'] >= $iStart){
if($value['is_h1'] == 1){
if(empty($value['content'])){
continue;
}
$sMain .= '\section{'.$this->dealContent($value['content']).'}'."\n";
}
if($value['is_h2'] == 1){
if(empty($value['content'])){
continue;
}
$sMain .= '\subsection{'.$this->dealContent($value['content']).'}'."\n";
}
if($value['is_h3'] == 1){
if(empty($value['content'])){
continue;
}
$sMain .= '\subsubsection{'.$this->dealContent($value['content']).'}'."\n";
}
if($value['is_h1'] == 0 && $value['is_h2'] == 0 && $value['is_h3'] == 0){
if($value['type'] == 0 ){
//处理内容
$sMainContent = $this->dealContent($value['content'],$aReferences);
// //替换myh3标签
// $contentpattern = '/<myh3>(.*?)<\/myh3>/is';
// $contentreplacement = '\\subsubsection{$1}';
// $sMainContent = preg_replace($contentpattern, $contentreplacement, $sMainContent);
$sMain .= $sMainContent."\\par\n";
}
if($value['type'] == 1 ){//图片
$aImageInfo = empty($aArticleMainImage[$value['ami_id']]) ? [] : $aArticleMainImage[$value['ami_id']];
if(empty($aImageInfo['url'])){
continue;
}
$sMainImageUrl = ROOT_PATH.trim($this->sArticleMainImage,'/').'/'.$aImageInfo['url'];
if(!file_exists($sMainImageUrl)){
continue;
}
// //下载图片
// $sImagePath = trim($this->sSubmissionUrl,'/').$this->sArticleMainImage.'/'.$aImageInfo['url'];
// $aResult = $this->getImage($sImagePath,$aProductionArticle['article_id']);
// 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);
// $aImageInfo['image_url'] = $aResult['data'];
$aImageInfo['image_url'] = $sMainImageUrl;
$aDealImage = $this->dealImage($aImageInfo);
if(empty($aDealImage['data'])){
continue;
}
$sMain .= $aDealImage['data']."\\par\n";
}
if($value['type'] == 2 ){//表格
$aTableInfo = empty($aArticleMainTable[$value['amt_id']]) ? [] : $aArticleMainTable[$value['amt_id']];
if(empty($aTableInfo['table_data'])){
continue;
}
$sTableInfo = $oProduction->tableCovertLatex($value['amt_id'],$aReferences,$aTableInfo);
if($sTableInfo == 'JSON error'){
continue;
}
if($sTableInfo == 'long table'){
$aLongTableId[] = $value['amt_id'];
continue;
}
$sMain .= $sTableInfo."\\par\n";
}
}
}
}
}
$aSearch['{{article_main}}'] = empty($sMain) ? '' : $sMain."\n";
//模版内容替换
$sTemplateInfo = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplateInfo);
//返回内容
return ['status' => 1,'msg' => 'success','data' => $sTemplateInfo,'long_table_id' => $aLongTableId];
}
/**
* 生成初稿-作者信息
*/
private function dealAuthor($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];
$aAuthor = Db::name('production_article_author')->where($aWhere)->select();
if(empty($aAuthor)){
return ['status' => 3,'msg' => 'Author information is empty'];
}
//查询作者机构
$aWhere['p_article_author_id'] = ['in',array_column($aAuthor, 'p_article_author_id')];
$aAuthorOrgan = Db::name('production_article_author_to_organ')->field('p_article_author_id,p_article_organ_id')->where($aWhere)->order('p_article_author_id asc,p_article_organ_id asc')->select();
//查询机构信息
$aAuthorOrganList = [];
if(!empty($aAuthorOrgan)){
unset($aWhere['p_article_author_id']);
$aOrganId = array_unique(array_column($aAuthorOrgan, 'p_article_organ_id'));
$aWhere['p_article_organ_id'] = ['in',$aOrganId];
$aOrgan = Db::name('production_article_organ')->where($aWhere)->column('p_article_organ_id,organ_name');
if(!empty($aOrgan)) {
foreach ($aAuthorOrgan as $key => $value) {
if(empty($aOrgan[$value['p_article_organ_id']])){
continue;
}
$aAuthorOrganList[$value['p_article_author_id']][] = $aOrgan[$value['p_article_organ_id']];
}
}
}
//处理作者
$sAuthor = $sCorrespondence = '';
$iFirstNum = 0;
foreach ($aAuthor as $key => $value) {
//作者姓名
$sName = empty($value['first_name']) ? '' : $value['first_name'];
$sName = empty($sName) ? '' : $sName . ' ' .$value['last_name'];
if(empty($sName)){
$sName = empty($value['author_name']) ? '' : $value['author_name'];
}
if(empty($sName)){
continue;
}
$sAuthor .= '\author{'.$this->dealContent($sName).'}'."\n";
if(!empty($value['email']) && $value['is_report'] == 1){
$sAuthor .= '\email{'.$this->dealContent($value['email']).'}'."\n";
}
//作者机构
$aOrganList = empty($aAuthorOrganList[$value['p_article_author_id']]) ? [] : $aAuthorOrganList[$value['p_article_author_id']];
if(!empty($aOrganList)){
$i = 0;
foreach($aOrganList as $organ){
if(empty($organ)){
continue;
}
if($i == 0){
$sAuthor .= '\affiliation{'.$this->dealContent($organ).'}'."\n";
}else{
$sAuthor .= '\alsoaffiliation{'.$this->dealContent($organ).'}'."\n";
}
$i++;
}
}
if($value['is_first'] == 1){
$sAuthor .= '\firstauthor'."\n";
$iFirstNum++;
}
if(!empty($value['orcid'])){
$sAuthor .= '\orcid{'.$this->dealContent($value['orcid']).'}'."\n";
}
if($value['is_report'] == 1){
$sCorrespondenceInfo = $sName;
// if(!empty($aOrganList[0])){
// $sCorrespondence .= ','.trim($this->dealContent($aOrganList[0]),'.');
// }
if(!empty($value['mailing_address'])){//通讯地址
$value['mailing_address'] = trim($value['mailing_address']);
$sCorrespondenceInfo .= ','.trim($this->dealContent($value['mailing_address']),'.');
}
if(!empty($value['email'])){
$sCorrespondenceInfo .= '. E-mail:'.trim($this->dealContent($value['email']),'.').'.';
}else{
$sCorrespondenceInfo .= trim($sCorrespondenceInfo,'.').'.';
}
$sCorrespondence .= $sCorrespondenceInfo .' ';
}
}
if($iFirstNum == 1 && !empty($sAuthor)){
$sAuthor = str_replace('\firstauthor'."\n", '', $sAuthor);
}
return ['author' => $sAuthor,'correspondence' => trim($sCorrespondence)];
}
/**
* 生成初稿-获取期刊分期信息
*/
private function getJournalStage($aParam = []){
// 获取分期ID
$aParam = empty($aParam) ? $this->request->post() : $aParam;
//必填值验证
$iJournalStageId = empty($aParam['journal_stage_id']) ? '' : $aParam['journal_stage_id'];
if(empty($iJournalStageId)){
return json_encode(array('status' => 2,'msg' => 'Please choose journal installment' ));
}
$sUrl = $this->sJournalUrl."api/Supplementary/getJournalStage";
$aResult = object_to_array(json_decode(myPost1($sUrl,$aParam)));
return $aResult;
}
/**
* 处理文章引用
* @param string $html
* @return string
*/
private function getArticleCite($aArticle = [],$aJournal = [],$aJournalStage = []){
$no = empty($aJournalStage['stage_no']) ? ':' : '(' . $aJournalStage['stage_no'] . '):';
$jabbr = empty($aJournal['jabbr']) ? '' : $aJournal['jabbr'];
$stage_year = empty($aJournalStage['stage_year']) ? '' : $aJournalStage['stage_year'];
$stage_vol = empty($aJournalStage['stage_vol']) ? '' : $aJournalStage['stage_vol'];
$sAbbr = empty($aArticle['abbr']) ? '' : trim(trim($aArticle['abbr'],'.'));
// $aAbbr = empty( $sAbbr ) ? [] : explode(',', trim( $sAbbr ));
// if(!empty($aAbbr)){
// $sEnd = end($aAbbr);
// if($sEnd != 'et al'){
// $aThree = array_slice($aAbbr, 0,3);
// $sAbbr = implode(',', $aThree);
// if(!empty( $sAbbr ) && count($aThree) > 3){
// $sAbbr .= ', et al';
// }
// }
// }
$sCite = '';
if ($aArticle['journal_id'] == 22) {
$sCite = $sAbbr . '. ' . $aArticle['title'] . '[J]. ' . choiseJabbr($aArticle['article_id'],$jabbr) . ',' . $stage_year . ',' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi'];
$sCite = $this->dealContent($sCite);
} else {
$sCite = $this->dealContent($sAbbr) . '. ' . $this->dealContent($aArticle['title']) . '. \textit{' . $this->dealContent(choiseJabbr($aArticle['article_id'], $jabbr)) . '}. ' . $stage_year . ';' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi'];
}
return $sCite;
}
public function getArticleTime($aParam = []){
//必填值验证
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
if(empty($iArticleId)){
return array('status' => 2,'msg' => 'Please select an article' );
}
//查询文章
$aWhere = ['article_id' => $iArticleId];
$aArticle= Db::name('article')->field('ctime,received_time')->where($aWhere)->find();
if(empty($aArticle)){
return array('status' => 2,'msg' => 'The article does not exist' );
}
//查询终审-审稿记录
$aWhere = ['article_id' => $iArticleId,'state' => ['in',[1,2,3]]];
$aFinalReviewerId = Db::name('article_reviewer_final')->order('review_time desc')->where($aWhere)->column('reviewer_id');
//查询审稿人姓名
$aUserName = [];
if(!empty($aFinalReviewerId)){
$aWhere = ['user_id' => ['in',array_unique($aFinalReviewerId)],'state' => 0,'realname' => ['<>','']];
$aUserName = Db::name('user')->where($aWhere)->column('realname');
}
//获取文章记录
$aWhere = ['article_id' => $iArticleId,'state' => 0,'state_to' => ['in',[0,1,5]]];
$aArticleMsg = Db::name('article_msg')->field('state_from,state_to,ctime')->where($aWhere)->order('ctime deac')->select();
$iReceivedTime = $iRevisionTime = $iAcceptedTime = 0;
if(!empty($aArticleMsg)){
foreach ($aArticleMsg as $key => $value) {
if(empty($iReceivedTime) && $value['state_to'] == 0){
$iReceivedTime = $value['ctime'];
}
if(empty($iRevisionTime) && $value['state_to'] == 1){
$iRevisionTime = $value['ctime'];
}
if(empty($iAcceptedTime) && $value['state_to'] == 5){
$iAcceptedTime = $value['ctime'];
}
}
}
$iReceivedTime = empty($iReceivedTime) ? $aArticle['received_time'] : $iReceivedTime;
$iReceivedTime = empty($iReceivedTime) ? $aArticle['ctime'] : $iReceivedTime;
$aTime = [];
$aTime['received_date'] = empty($iReceivedTime) ? '' : $this->timestampToEnglishDate($iReceivedTime);
$aTime['revision_date'] = empty($iRevisionTime) ? '' : $this->timestampToEnglishDate($iRevisionTime);
$aTime['accepted_date'] = empty($iAcceptedTime) ? '' : $this->timestampToEnglishDate($iAcceptedTime);
$aTime['editorial_advisory_board'] = empty($aUserName) ? '' : implode(',', $aUserName);
return ['status' => 1,'msg' => 'success','data' => $aTime];
}
/**
* 时间戳转换为「d F Y」格式如 12 June 2025
* @param int $timestamp 时间戳如1749600000
* @return string 格式化后的英文日期
*/
private function timestampToEnglishDate($timestamp) {
//验证时间戳有效性
if (!is_numeric($timestamp) || $timestamp < 0) {
return '';
}
//设置本地化确保月份为英文全称兼容Linux/Windows
$locale = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'
? 'English_United States.1252'
: 'en_US.UTF-8';
setlocale(LC_TIME, $locale);
//格式化d=日无前导零、F=英文月份全称、Y=四位年 strftime的%e在Linux下是无前导零的日Windows用%#d
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$dateStr = strftime('%#d %B %Y', $timestamp); // Windows
} else {
$dateStr = strftime('%e %B %Y', $timestamp); // Linux/Mac
}
return trim($dateStr);
}
private function dealContent($content = '',$aReferences = []) {
// 空值直接返回
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);
//字符串处理
$oProduction = new \app\api\controller\Production;
$sContent = $oProduction->convertToLatex($content,$aReferences);
return $sContent;
}
/**
* @title curl 请求获取图片保存到本地
* @param sPath 图片链接地址
*/
private function getImage($sPath = '',$iId = 0){
//判断参数
if(empty($sPath) || empty($iId)){
return ['status' => 2,'msg' => 'url is empty','data' => ''];
}
//获取图片名称
$aImageInfo = pathinfo($sPath);
//图片后缀名
$sExtension = empty($aImageInfo['extension']) ? 'jpg' : $aImageInfo['extension'];
//图片地址
$sDir = ROOT_PATH.trim($this->sLatexUrl,'/').'/tex_'.$iId.'/image/';
$sImagePath = $sDir.basename($sPath);
if (file_exists($sImagePath)) {
return ['status' => 1,'msg' => 'success','data' => $sImagePath];
}
//下载图片
if (!is_dir($sDir)) {
mkdir($sDir, 0755, true);
}
//curl 请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$sPath); // 设置请求URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 设置返回数据而不是直接输出
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁用SSL验证
$response = curl_exec($ch);
if (curl_errno($ch)) {
return ['status' => 3,'msg' => 'Error:' . curl_error($ch),'data' => $sImagePath];
}
//保存图片
file_put_contents($sImagePath, $response);
curl_close($ch);
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图片代码
$sImageUrl = str_replace(ROOT_PATH.'public/', '', $sImageUrl);
$sImageUrl = '../../'.$sImageUrl;
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)];
}
/**
* 动态LaTeX 比例分栏[两栏]
*/
private function generateLatexDynamicColumns($aSearch = []) {
//数据处理
//右侧列
$sRightLen = '';
if(!empty($aSearch['{{abstract}}'])){
$sRightLen .= $aSearch['{{abstract}}'];
}
if(!empty($aSearch['{{keywords}}'])){
$sRightLen .= $aSearch['{{keywords}}'];
}
$iRightLen = mb_strlen($sRightLen, 'UTF-8');
if(!empty($aSearch['is_have_icon']) && $aSearch['is_have_icon'] == 1){
$iRightImgRatio = 0.6; // 图片宽度=0.6\textwidth
$iRightImgChar = $this->imgRatioToCharCount($iRightImgRatio);
$iRightLen = $iRightLen + $iRightImgChar;
}
//左侧列
$sLefttLen = '';
if(!empty($aSearch['{{author_contribution}}'])){
$sLefttLen .= 'Author contributions'."\n".$aSearch['{{author_contribution}}'];
}
$sLefttLen .= 'Competing interests'."\n".'The authors declare no conflicts of interest.';
if(!empty($aSearch['{{article_acknowledgment}}'])){
$sLefttLen .= 'Acknowledgments'."\n".$aSearch['{{article_acknowledgment}}'];
}
if(!empty($aSearch['{{article_abbreviation}}'])){
$sLefttLen .= 'Abbreviations'."\n".$aSearch['{{article_abbreviation}}'];
}
if(!empty($aSearch['{{article_cite}}'])){
$sLefttLen .= 'Citation'."\n".$aSearch['{{article_cite}}'];
}
if(!empty($aSearch['{{journal_title}}'])){
$sLefttLen .= 'Peer review information'."\n".$aSearch['{{journal_title}}'].' thanks all anonymous reviewers for their contribution to the peer review of this paper';
}
if(!empty($aSearch['{{editorial_advisory_board}}'])){
$sLefttLen .= 'Editorial Advisory Board: '.$aSearch['{{editorial_advisory_board}}'];
}
if(!empty($aSearch['{{executive_editor}}'])){
$sLefttLen .= 'Executive editor: '.$aSearch['{{executive_editor}}'];
}
if(!empty($aSearch['{{received_date}}'])){
$sLefttLen .= 'Received: '.$aSearch['{{received_date}}'].'; ';
}
if(!empty($aSearch['{{revision_date}}'])){
$sLefttLen .= 'Revised: '.$aSearch['{{revision_date}}'].'; ';
}
if(!empty($aSearch['{{accepted_date}}'])){
$sLefttLen .= 'Accepted:'.$aSearch['{{accepted_date}}'].'; ';
}
if(!empty($aSearch['{{pub_date}}'])){
$sLefttLen .= 'Available online: '.$aSearch['{{pub_date}}'];
}
$sLefttLen .= date('Y').' By Author(s). Published by TMR Publishing Group Limited. This is an open access article under the CC-BY license. (https://creativecommons.org/licenses/by/4.0/)';
$iLeftLen = mb_strlen($sLefttLen, 'UTF-8');
//统计总字数
$iTotalLen = $iLeftLen + $iRightLen;
$iLeftRatio = $iRightRatio = 0.5;
if($iTotalLen > 0) {
$iLeftRatio = round($iLeftLen / $iTotalLen,2);
}
if(intval($iLeftRatio*100) > 50){
$iLeftRatio = 0.5;
}
if(intval($iLeftRatio*100) < 36){
$iLeftRatio = 0.36;
}
return ['left_ratio' => $iLeftRatio];
}
/**
* 图片宽度比例 → 等效英文字符数
* @param float $fImgRatio 图片宽度占\textwidth的比例如0.5=0.5\textwidth
* @param float $fTextWidthEm 页面\textwidth的em宽度英文期刊默认36em
* @return int 英文字符数
*/
function imgRatioToCharCount($fImgRatio = 0.6, $fTextWidthEm = 36) {
if ($fImgRatio <= 0 || !is_numeric($fImgRatio)) {
return 0;
}
//计算图片宽度em
$fImgWidthEm = $fImgRatio * $fTextWidthEm;
//折算为英文字符数1em=2个英文字符
$iImgCharCount = round($fImgWidthEm * 2);
return max($iImgCharCount, 0);
}
}
?>