Merge remote-tracking branch 'origin/master'

This commit is contained in:
wangjinlei
2025-12-31 16:08:34 +08:00
2 changed files with 165 additions and 46 deletions

View File

@@ -1577,7 +1577,6 @@ class Article extends Base
$update_data['rstime'] = time(); $update_data['rstime'] = time();
} }
$this->article_obj->where($where_article)->update($update_data); $this->article_obj->where($where_article)->update($update_data);
//拒稿或者录用 - 发送审稿意见 //拒稿或者录用 - 发送审稿意见
if ($article_info['journal_id'] == 1 && ($data['state'] == 3 || $data['state'] == 5)) { if ($article_info['journal_id'] == 1 && ($data['state'] == 3 || $data['state'] == 5)) {
$this->sendEmailToReviewer($data['articleId'], $data['state']); $this->sendEmailToReviewer($data['articleId'], $data['state']);
@@ -6241,4 +6240,92 @@ class Article extends Base
} }
return ['status' => 1,'msg' => 'success']; return ['status' => 1,'msg' => 'success'];
} }
/**
* 添加图片版权声明文件-编辑
*/
public function addFigureCopyrightForEditor($aParam = []){
//获取参数
$aParam = empty($aParam) ? $this->request->post() : $aParam;
//获取文章ID
$iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
if(empty($iArticleId)){
return json_encode(['status' => 2,'msg' => 'Please select the article']);
}
//用户ID
$iUserId = empty($aParam['user_id']) ? '' : $aParam['user_id'];
if(empty($iUserId)){
return json_encode(['status' => 2,'msg' => 'Please select author']);
}
// //是否上传文件
// $is_figure_copyright = empty($aParam['is_figure_copyright']) ? 3 : $aParam['is_figure_copyright'];
// if($is_figure_copyright == 3){
// return json_encode(['status' => 3,'msg' => 'Please check whether to upload the figure copyright statement']);
// }
//获取操作人信息
$aWhere = ['user_id' => $iUserId,'state' => 0];
$aUser = Db::name('user')->field('account')->where($aWhere)->find();
if(empty($aUser)){
return json_encode(['status' => 5,'msg' => 'No operator information found']);
}
//获取文章信息
$aWhere = ['article_id' => $iArticleId];
$aArticle = Db::name('article')->field('article_id,state,editor_id,journal_id')->where($aWhere)->find();
if(empty($aArticle)){
return json_encode(['status' => 6,'msg' => 'The article does not exist']);
}
//判断是否有权限操作
if($iUserId != $aArticle['editor_id']){
return json_encode(['status' => 7,'msg' => 'Unauthorized operation']);
}
//查询期刊负责编辑
$aWhere = ['journal_id' => $aArticle['journal_id'],'state' => 0];
$aJournal = Db::name('journal')->field('editor_id')->where($aWhere)->find();
if(empty($aJournal)){
return json_encode(['status' => 7,'msg' => 'No article or journal information found']);
}
if($iUserId != $aJournal['editor_id']){
return json_encode(['status' => 7,'msg' => 'No operation permission']);
}
//图片路径
// if($is_figure_copyright == 1){
//文件地址
$sUrl = empty($aParam['url']) ? '' : $aParam['url'];
if(empty($sUrl)){
return json_encode(['status' => 4,'msg' => 'Please choose to upload the file']);
}
// }
//文件类型
$sTypeName = 'figurecopyright';
$sUserAccount = empty($aUser['account']) ? '' : $aUser['account'];
Db::startTrans();
if(!empty($sUrl)){
//验证文件是否上传
$aWhere = ['file_url' => $sUrl,'state' => 0,'article_id' => $iArticleId,'type_name' => $sTypeName];
$result = Db::name('article_file')->where($aWhere)->find();
if(empty($result)){
$aInsert['article_id'] = $iArticleId;
$aInsert['user_id'] = $iUserId;
$aInsert['username'] = $sUserAccount;
$aInsert['file_url'] = $sUrl;
$aInsert['type_name'] = $sTypeName;
$aInsert['ctime'] = time();
$result = Db::name('article_file')->insertGetId($aInsert);
}
}
// //更新文章内容
// $aArticleUpdate = ['is_figure_copyright' => $is_figure_copyright];
// if(!empty($aArticleUpdate)){
// $aWhere = ['article_id' => $iArticleId];
// $update_result = Db::name('article')->where($aWhere)->limit(1)->update($aArticleUpdate);
// }
//操作日志
$aLog = ['article_id' => $iArticleId,'user_id' => $iUserId,'type' => 7,'create_time' => time(),'content' => $sUserAccount . ':Operating the article copyright statement','is_view' => 1];
Db::name('user_act_log')->insert($aLog);
Db::commit();
return json_encode(['status' => 1,'msg' => 'success']);
}
} }

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,14 @@ 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'));
$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; $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 +296,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 +321,11 @@ 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";
} }
} }
} }
} }
@@ -533,43 +536,72 @@ page={{stage_page}},%号
} }
return trim($dateStr); return trim($dateStr);
} }
/** private function dealContent($content = '',$aReferences = []) {
* 内容处理
*/
private function dealContent($content = '', $target = 'latex',$iIsDeal = 1) {
// 空值直接返回 // 空值直接返回
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;
' ' => '~', // HTML非断行空格 → LaTeX非断行空格 $sContent = $oProduction->convertToLatex($content,$aReferences);
'&nbsp' => '~', // 兼容无分号的&nbsp $content = $this->htmlToLaTeX($content);
'&' => '\&', // HTML& → LaTeX转义& return $sContent;
'&lt;' => '<', // HTML< → 直接保留 }
'&gt;' => '>', // HTML> → 直接保留 private function htmlToLaTeX($text = ''){
// ========== LaTeX特殊字符转义 ========== if(empty($text)){
'{' => '\{', // 左花括号转义 return '';
'}' => '\}', // 右花括号转义 }
'&' => '\&', // 原生&转义(需在&amp;之后,避免覆盖) $replaceMap = [
'%' => '\%', // 百分号转义LaTeX注释符 // 基础标签转换
'_' => '\_', // 下划线转义LaTeX下标符 '<i>' => '\textit{',
'κ' => '$\kappa$', // 希腊字母κ → LaTeX数学环境避免乱码 '</i>' => '}',
'-' => '\text{-}', // 短横线强制保留形态 '<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 请求获取图片保存到本地