diff --git a/application/api/controller/Aiarticle.php b/application/api/controller/Aiarticle.php
index eecd549..b4520a8 100644
--- a/application/api/controller/Aiarticle.php
+++ b/application/api/controller/Aiarticle.php
@@ -264,7 +264,7 @@ class Aiarticle extends Base
//是否查询作者 1是2否
$iSelectAuthor = empty($aParam['is_select_author']) ? 2 : $aParam['is_select_author'];
//查询AI生成的文章内容
- $aWhere = ['is_delete' => 2,'is_generate' => 1];
+ $aWhere = ['is_delete' => 2];//,'is_generate' => 1
if(!empty($iArticleId)){
$aWhere['article_id'] = $iArticleId;
}
@@ -292,7 +292,10 @@ class Aiarticle extends Base
}
}
- return json_encode(['status' => 1,'msg' => 'success','data' => ['ai_article' => $aAiArticle,'ai_article_author' => $aAiAuthor]]);
+ //查询结论
+ $aWhere = ['article_id' => $iArticleId,'is_delete' => 2];
+ $aArticleResult = DB::name('ai_article_results')->field('id,title,content')->where($aWhere)->select();
+ return json_encode(['status' => 1,'msg' => 'success','data' => ['ai_article' => $aAiArticle,'ai_article_author' => $aAiAuthor,'ai_article_results' => $aArticleResult]]);
}
/**
* @title 处理作者数据
@@ -376,7 +379,14 @@ class Aiarticle extends Base
//获取参数
$aParam = empty($aParam) ? $this->request->post() : $aParam;
+ //文章ID
+ $iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
+ //查询内容是否存在
+ $aWhere = ['is_delete' => 2];
+ if(empty($iArticleId)){
+ return json_encode(['status' => 2,'msg' => 'Please select the article to be modified']);
+ }
//更新AI文章内容
$oArticle = new \app\common\Article;
$aResult = json_decode($oArticle->updateAiArticle($aParam),true);
@@ -385,66 +395,101 @@ class Aiarticle extends Base
return json_encode($aResult);
}
+ //结论信息
+ $aResultInfo = empty($aParam['results']) ? [] : $aParam['results'];
+ $aResultInfo = is_array( $aResultInfo) ? $aResultInfo : json_decode($aResultInfo,true);
//更新作者信息
$aAuthorList = empty($aParam['author_list']) ? []: $aParam['author_list'];
$aAuthorList = is_array( $aAuthorList) ? $aAuthorList: json_decode($aAuthorList,true);
- if(empty($aAuthorList)){
+ if(empty($aAuthorList) && empty($aResultInfo)){
return json_encode($aResult);
}
//根据邮箱查询作者信息
- $aAuthorList = array_column($aAuthorList, null,'email');
- $aEmail = array_keys($aAuthorList);
- if(empty($aEmail)){
- return json_encode($aResult);
- }
- $aUserParam = ['email' => ['in',$aEmail]];
- $aUserInfo = Db::name('user')->field('email,user_id')->where($aUserParam)->select();
- if(empty($aUserInfo)){
- return json_encode($aResult);
- }
+ if(!empty($aAuthorList)){
+ $aAuthorList = array_column($aAuthorList, null,'email');
+ $aEmail = array_keys($aAuthorList);
+ if(empty($aEmail)){
+ return json_encode($aResult);
+ }
+ $aUserParam = ['email' => ['in',$aEmail]];
+ $aUserInfo = Db::name('user')->field('email,user_id')->where($aUserParam)->select();
+ if(empty($aUserInfo)){
+ return json_encode($aResult);
+ }
- //查询用户附表
- $aUserId = array_column($aUserInfo, 'user_id');
- $aWhere = ['reviewer_id' => ['in',$aUserId]];
- $aUserReviewer = Db::name('user_reviewer_info')->where($aWhere)->column('reviewer_id');
- //更新用户信息
- Db::startTrans();
- foreach ($aUserInfo as $key => $value) {
+ //查询用户附表
+ $aUserId = array_column($aUserInfo, 'user_id');
+ $aWhere = ['reviewer_id' => ['in',$aUserId]];
+ $aUserReviewer = Db::name('user_reviewer_info')->where($aWhere)->column('reviewer_id');
+ //更新用户信息
+ Db::startTrans();
+ foreach ($aUserInfo as $key => $value) {
- $aUser = empty($aAuthorList[$value['email']]) ? [] : $aAuthorList[$value['email']];
- if(empty($aUser)){
- continue;
- }
- //更新作者名字
- if(isset($aUser['author_name'])){
- $aUpdate = ['localname' => $aUser['author_name']];
- Db::name('user')->where('user_id',$value['user_id'])->update($aUpdate);
- }
- //更新作者简介和单位
- $aUpdateReviewer = [];
- if(isset($aUser['technical'])){
- $aUpdateReviewer['technical'] = $aUser['technical'];
- }
- if(isset($aUser['introduction'])){
- $aUpdateReviewer['introduction'] = $aUser['introduction'];
- }
- if(isset($aUser['company'])){
- $aUpdateReviewer['company'] = $aUser['company'];
- }
- if(isset($aUpdateReviewer)){
- if(in_array($value['user_id'], $aUserReviewer)){//更新
- Db::name('user_reviewer_info')->where('reviewer_id',$value['user_id'])->limit(1)->update($aUpdateReviewer);
+ $aUser = empty($aAuthorList[$value['email']]) ? [] : $aAuthorList[$value['email']];
+ if(empty($aUser)){
+ continue;
}
- if(!in_array($value['user_id'], $aUserReviewer)){//插入
- $aUpdateReviewer['reviewer_id'] = $value['user_id'];
- Db::name('user_reviewer_info')->insert($aUpdateReviewer);
+ //更新作者名字
+ if(isset($aUser['author_name'])){
+ $aUpdate = ['localname' => $aUser['author_name']];
+ Db::name('user')->where('user_id',$value['user_id'])->update($aUpdate);
+ }
+ //更新作者简介和单位
+ $aUpdateReviewer = [];
+ if(isset($aUser['technical'])){
+ $aUpdateReviewer['technical'] = $aUser['technical'];
+ }
+ if(isset($aUser['introduction'])){
+ $aUpdateReviewer['introduction'] = $aUser['introduction'];
+ }
+ if(isset($aUser['company'])){
+ $aUpdateReviewer['company'] = $aUser['company'];
+ }
+ if(isset($aUpdateReviewer)){
+ if(in_array($value['user_id'], $aUserReviewer)){//更新
+ Db::name('user_reviewer_info')->where('reviewer_id',$value['user_id'])->limit(1)->update($aUpdateReviewer);
+ }
+ if(!in_array($value['user_id'], $aUserReviewer)){//插入
+ $aUpdateReviewer['reviewer_id'] = $value['user_id'];
+ Db::name('user_reviewer_info')->insert($aUpdateReviewer);
+ }
}
}
+ Db::commit();
}
- Db::commit();
- $aResult['data'] = $aParam;
+ //更新结论
+ if(!empty($aResultInfo)){
+ Db::startTrans();
+ foreach ($aResultInfo as $key => $value) {
+ //记录ID
+ $iRecordId = empty($value['record_id']) ? 0 : $value['record_id'];
+ if(empty($iRecordId)){
+ continue;
+ }
+ //标题
+ $sTitle = empty($value['title']) ? '' : $value['title'];
+ //内容
+ $sContent = empty($value['content']) ? '' : $value['content'];
+ if(empty($sTitle) && empty($sContent)){
+ continue;
+ }
+ if(!empty($sTitle)){
+ $aUpdate['title'] = $sTitle;
+ }
+ if(!empty($sContent)){
+ $aUpdate['content'] = $sContent;
+ }
+ if(!empty($aUpdate)){
+ $aUpdate['update_time'] = time();
+ $aWhere = ['article_id' => $iArticleId,'id' => $iRecordId];
+ $result = DB::name('ai_article_results')->where($aWhere)->limit(1)->update($aUpdate);
+ }
+ }
+ Db::commit();
+ }
+ // $aResult['data'] = $aParam;
return json_encode($aResult);
}
diff --git a/application/api/controller/Article.php b/application/api/controller/Article.php
index 2a09f19..ad47d6b 100644
--- a/application/api/controller/Article.php
+++ b/application/api/controller/Article.php
@@ -536,6 +536,22 @@ class Article extends Base
$article_res['majors'] = $majors;
//查询文章作者信息
$author_res = $this->article_author_obj->where('article_id', $data['articleId'])->where('state', 0)->select();
+ //查询作者scopus chengxiaoling 20260924 start
+ if(!empty($author_res)){
+ $aEmail = array_unique(array_column($author_res, 'email'));
+ $aWhere = ['email' => ['in',$aEmail]];
+ $aUserData = Db::name('user')->field('user_id,email,scopus_index,scopus_website,google_index,wos_index')->where($aWhere)->select();
+ $aUserData = empty($aUserData) ? [] : array_column($aUserData, null,'email');
+ foreach ($author_res as $key => $value) {
+ $aUserInfo = empty($aUserData[$value['email']]) ? [] : $aUserData[$value['email']];
+ $author_res[$key]['scopus_index'] = isset($aUserInfo['scopus_index']) ? $aUserInfo['scopus_index'] : '';
+ $author_res[$key]['scopus_website'] = empty($aUserInfo['scopus_website']) ? '' : $aUserInfo['scopus_website'];
+ $author_res[$key]['google_index'] = isset($aUserInfo['google_index']) ? $aUserInfo['google_index'] : '';
+ $author_res[$key]['wos_index'] = isset($aUserInfo['wos_index']) ? $aUserInfo['wos_index'] : '';
+ $author_res[$key]['user_id'] = empty($aUserInfo['user_id']) ? 0 : $aUserInfo['user_id'];
+ }
+ }
+ //查询作者scopus chengxiaoling 20260924 end
//查询转投信息
$transfer_res = $this->article_transfer_obj->where('article_id', $data['articleId'])->select();
//查询建议转投详情
diff --git a/application/api/controller/Cronmonitor.php b/application/api/controller/Cronmonitor.php
index 2ed6ece..80cba2b 100644
--- a/application/api/controller/Cronmonitor.php
+++ b/application/api/controller/Cronmonitor.php
@@ -76,6 +76,7 @@ class Cronmonitor extends Controller
$aParam['date'] = $sDate;
$aResult = object_to_array(json_decode(myPost($sUrl, $aParam)));
$aContent = empty($aResult['data']) ? [] : $aResult['data'];
+
if(empty($aContent)){
$this->showMessage($aResult['msg'] ?? '接口异常',2);
exit;
@@ -91,23 +92,20 @@ class Cronmonitor extends Controller
foreach ($aArticleCite as $key => $value) {
$aCite[$value['article_id']][] = $value;
}
+
//获取数据-文章通讯作者数据
$aArticleAuthor = empty($aContent['article_author']) ? [] : $aContent['article_author'];
if(empty($aArticleAuthor)){
$this->showMessage('未查询到引用文章通讯作者数据:'.$sDate,2);
exit;
}
+ $aArticleId = array_unique(array_column($aArticleAuthor, 'article_id'));
//获取数据-文章数据
$aArticle = empty($aContent['article']) ? [] : $aContent['article'];
//期刊数据
$aJournal = empty($aContent['journal']) ? [] : $aContent['journal'];
- //查询发送人信息
- $aEmail = array_column($aArticleAuthor, 'email');
- $aWhere = ['email' => ['in',$aEmail]];
- $aUser = Db::name('user')->where($aWhere)->column('email,realname,localname');
-
//查询邮件发送日志
$aArticleCiteId = array_column($aArticleCite, 'article_cite_id');
$aWhere = ['article_cite_id' => ['in',$aArticleCiteId],'is_success' => 1];
@@ -123,28 +121,32 @@ class Cronmonitor extends Controller
$aEmailCite= $this->aEmailConfig['cite'];
//邮件发送日志记录数组
$aEmailLog = [];
+ $aSendEmail = [];//['2101' => ['mohammadalipour_z@yahoo.com']];
foreach ($aArticleAuthor as $key => $value) {
- if(empty($value['email'])){//邮箱为空
+
+ //作者邮箱-发送信息
+ $email = empty($value['email']) ? '' : $value['email'];
+ if(empty($email)){
continue;
}
+
+ //获取引用文章信息
$aArticleCite = empty($aCite[$value['article_id']]) ? [] : $aCite[$value['article_id']];
if(empty($aArticleCite)){
$this->showMessage('未查询到文章引用信息为空,文章ID:'.$value['article_id']."\n\n",2);
continue;
}
- //数据组装-接收邮箱
- // $email = '1172937051@qq.com';//$value['email'];
- $email = $value['email'];
+
+ //判断同一个邮箱是否重复发送
+ if(!empty($aSendEmail[$value['article_id']]) && in_array($email, $aSendEmail[$value['article_id']])){
+ continue;
+ }
//用户信息
- $aUserInfo = empty($aUser[$value['email']]) ? [] : $aUser[$value['email']];
- $realname = empty($aUserInfo['realname']) ? '' : $aUserInfo['realname'];
- $localname = empty($aUserInfo['localname']) ? '' : $aUserInfo['localname'];
- $realname = empty($realname) ? $localname : $realname;
- $realname = empty($value['author_name']) ? $realname : $value['author_name'];
-
+ $realname = empty($value['author_name']) ? $email : $value['author_name'];
//邮件日志
$aEmailLogInfo = empty($aLog[$email]) ? [] : $aLog[$email];
+
foreach ($aArticleCite as $val) {
if(in_array($val['article_cite_id'], $aEmailLogInfo)){
$this->showMessage('文章标题为:'.$val['article_name'].'邮箱账号为:'.$email."已发送过邮件\n\n",2);
@@ -194,13 +196,14 @@ class Cronmonitor extends Controller
$aResult = sendEmail($email,$title,$from_name,$content,$memail,$mpassword);
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
$iIsSuccess = 2;
- $sMsg = empty($aResult['data']) ? '失败' : $aResult['data'];
+ $sMsg = empty($aResult['msg']) ? '未知' : $aResult['msg'];
if($iStatus == 1){
$iIsSuccess = 1;
$sMsg = '成功';
}
$this->showMessage('给邮箱:'.$email.'发送邮件-'.$sMsg."\n\n",2);
$aEmailLog[] = ['article_id' => $val['article_id'],'article_cite_id' => $val['article_cite_id'],'email' => $email,'content' => $content,'create_tiem' => time(),'is_success' => $iIsSuccess,'journal_id' => $val['journal_id'],'journal_issn' => $aJournalInfo['issn'],'msg' => $sMsg];
+ $aSendEmail[$value['article_id']][] = $email;
}
}
diff --git a/application/api/controller/Finalreview.php b/application/api/controller/Finalreview.php
index 3f100d6..ff7c965 100644
--- a/application/api/controller/Finalreview.php
+++ b/application/api/controller/Finalreview.php
@@ -1040,7 +1040,7 @@ class Finalreview extends Base
}
/**
- * @title 获取文章的终审意见
+ * @title 获取文章的审稿意见
* @param article_id
*/
public function getArticleFinalReview($aParam = []){
@@ -1052,18 +1052,81 @@ class Finalreview extends Base
if(empty($iArticleId)){
return json_encode(['status' => 2,'msg' => 'Please select a article']);
}
- //查询审稿记录
+ //查询文章审稿记录
+ $aWhere = ['article_id' => $iArticleId,'state' => ['between',[1,3]]];
+ $aArticleReviewer = Db::name('article_reviewer')->field('art_rev_id,state,ctime')->where($aWhere)->select();
+ if(!empty($aArticleReviewer)){
+ $aArtRevId = array_column($aArticleReviewer, 'art_rev_id');
+ $aWhere = ['art_rev_id' => ['in',$aArtRevId],'state' => 0];
+ //查询初审问卷
+ $aQuestion = Db::name('article_reviewer_question')->field('art_rev_id,ctime,score,rated')->where($aWhere)->order('ctime asc')->select();
+ $aQuestion = empty($aQuestion) ? [] : array_column($aQuestion, null,'art_rev_id');
+
+ //查询复审
+ $aReviewerRepeatLists = [];
+ $aWhere = ['art_rev_id' => ['in',$aArtRevId],'recommend' => ['between',[1,3]]];
+ $aReviewerRepeat = Db::name('article_reviewer_repeat')->field('art_rev_rep_id,art_rev_id,recommend,ctime,stime')->where($aWhere)->select();
+ if(!empty($aReviewerRepeat)){
+ foreach ($aReviewerRepeat as $key => $value) {
+ $aReviewerRepeatLists[$value['art_rev_id']][] = $value;
+ }
+ }
+ foreach ($aArticleReviewer as $key => $value) {
+ $aQuestionData = empty($aQuestion[$value['art_rev_id']]) ? [] : $aQuestion[$value['art_rev_id']];
+ $value['ctime'] = empty($aQuestionData['ctime']) ? $value['ctime'] : $aQuestionData['ctime'];
+ $value['score'] = empty($aQuestionData['score']) ? 0 : $aQuestionData['score'];
+ $value['repeat'] = empty($aReviewerRepeatLists[$value['art_rev_id']]) ? [] : $aReviewerRepeatLists[$value['art_rev_id']];
+ $value['rated'] = empty($aQuestionData['rated']) ? 0 : $aQuestionData['rated'];
+ $aArticleReviewer[$key] = $value;
+ }
+ }
+ //查询终审-审稿记录
$aWhere = ['article_id' => $iArticleId,'state' => ['in',[1,2,3]]];
$aReviewerFinal = Db::name('article_reviewer_final')->field('id,state,suggest_for_editor,suggest_for_author,update_time,reviewer_id,is_anonymous')->where($aWhere)->select();
if(!empty($aReviewerFinal)){
//查询作者信息
- $aUserId = array_unique(array_column($aReviewerFinal, 'user_id'));
+ $aUserId = array_unique(array_column($aReviewerFinal, 'reviewer_id'));
$aWhere = ['user_id' => ['in',$aUserId],'state' => 0];
$aUser = Db::name('user')->where($aWhere)->column('user_id,realname');
foreach ($aReviewerFinal as $key => $value) {
$aReviewerFinal[$key]['realname'] = empty($aUser[$value['reviewer_id']]) ? '' : $aUser[$value['reviewer_id']];
}
}
+ $aData = ['review' => $aArticleReviewer,'final_review' => $aReviewerFinal];
+ return json_encode(['status' => 1,'msg' => 'success','data' => $aData]);
+ }
+
+ /**
+ * @title 查询终审状态
+ * @param record_id 记录ID
+ * @param state 状态
+ */
+ public function getById(){
+ //获取参数
+ $aParam = $this->request->post();
+ //主键ID
+ $iId = empty($aParam['record_id']) ? 0 : $aParam['record_id'];
+ if(empty($iId)){
+ return json_encode(['status' => 2,'msg' => 'Please select the review record']);
+ }
+ //参数验证-审稿人ID
+ $iReviewerId = empty($aParam['reviewer_id']) ? 0 : $aParam['reviewer_id'];
+ if(empty($iReviewerId)){
+ return json_encode(['status' => 2,'msg' => 'Please select a reviewer']);
+ }
+ //稿件状态
+ //判断审稿人是否是编委/主编/副主编
+ $aWhere = ['user_id' => $iReviewerId,'state' => 0];
+ $aBoard = Db::name('board_to_journal')->where($aWhere)->column('journal_id');
+ if(empty($aBoard)){
+ return json_encode(['status' => 2,'msg' => 'The reviewer role does not meet the review requirements']);
+ }
+ //查询审稿记录
+ $aWhere = ['reviewer_id' => $iReviewerId,'id' => $iId];
+ $aReviewerFinal = Db::name('article_reviewer_final')->field('id,article_id,state,reviewer_id')->where($aWhere)->find();
+ if(empty($aReviewerFinal)){
+ return json_encode(['status' => 3,'msg' => 'Review record does not exist or review has been completed']);
+ }
return json_encode(['status' => 1,'msg' => 'success','data' => $aReviewerFinal]);
}
}
diff --git a/application/api/controller/Production.php b/application/api/controller/Production.php
index d3a6490..4974567 100644
--- a/application/api/controller/Production.php
+++ b/application/api/controller/Production.php
@@ -1606,6 +1606,23 @@ class Production extends Base
return jsonError($rule->getError());
}
$old_article_author_info = $this->production_article_author_obj->where('p_article_author_id', $data['p_article_author_id'])->find();
+
+ //判断邮箱是否重复 chengxiaoling 20250926 start
+ if(empty($old_article_author_info)){
+ return jsonError('Author information does not exist');
+ }
+ $iPArticleId = empty($old_article_author_info['p_article_id']) ? 0 : $old_article_author_info['p_article_id'];
+ $sEmail = empty($data['email']) ? '' : $data['email'];
+ $iAuthorId = empty($old_article_author_info['p_article_author_id']) ? 0 : $old_article_author_info['p_article_author_id'];
+ if(!empty($sEmail) && !empty($iPArticleId)){
+ $aWhere = ['p_article_id' => $iPArticleId,'email' => $sEmail,'state' => 0,'p_article_author_id' => ['<>',$iAuthorId]];
+ $aAuthor = $this->production_article_author_obj->field('p_article_author_id')->where($aWhere)->find();
+ if(!empty($aAuthor)){
+ return jsonError("Email has been bound by another author");
+ }
+ }
+ //判断邮箱是否重复 chengxiaoling 20250926 end
+
$article_info = $this->article_obj->where('article_id', $old_article_author_info['article_id'])->find();
$updata['author_name'] = $article_info['journal_id'] == 21 ? trim($data['last_name']) . trim($data['first_name']) : trim($data['first_name']) . ' ' . trim($data['last_name']);
$updata['first_name'] = trim($data['first_name']);
@@ -1695,6 +1712,19 @@ class Production extends Base
$p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find();
$article_info = $this->article_obj->where('article_id', $p_info['article_id'])->find();
+
+ //判断邮箱是否重复 chengxiaoling 20250926 start
+ $iPArticleId = empty($data['p_article_id']) ? 0 : $data['p_article_id'];
+ $sEmail = empty($data['email']) ? '' : $data['email'];
+ if(!empty($sEmail) && !empty($iPArticleId)){
+ $aWhere = ['p_article_id' => $iPArticleId,'email' => $sEmail,'state' => 0];
+ $aAuthor = $this->production_article_author_obj->field('p_article_author_id')->where($aWhere)->find();
+ if(!empty($aAuthor)){
+ return jsonError("Email has been bound by another author");
+ }
+ }
+ //判断邮箱是否重复 chengxiaoling 20250926 end
+
$insert['p_article_id'] = $data['p_article_id'];
$insert['article_id'] = $p_info['article_id'];
$insert['author_name'] = $article_info['journal_id'] == 21 ? trim($data['last_name']) . trim($data['first_name']) : trim($data['first_name']) . ' ' . trim($data['last_name']);
diff --git a/application/api/controller/Proofread.php b/application/api/controller/Proofread.php
new file mode 100644
index 0000000..7d55dcd
--- /dev/null
+++ b/application/api/controller/Proofread.php
@@ -0,0 +1,503 @@
+request->post() : $aParam;
+ $iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
+ if(empty($iArticleId)){
+ return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
+ }
+ //行号
+ $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id'];
+ //查询文章
+ $aWhere = ['article_id' => $iArticleId];
+ $oArticle = new Article;
+ $aArticle = json_decode($oArticle->get($aWhere),true);
+ $aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
+ if(empty($aArticle)){
+ return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ));
+ }
+ if($aArticle['state'] != 6){
+ return json_encode(array('status' => 4,'msg' => 'The article has not entered the proofreading stage'));
+ }
+
+ //查询是否进行过校对
+ $aProofReadWhere = ['article_id' => $iArticleId,'state' => 2];
+ if(!empty($iAmId)){
+ $aProofReadWhere['am_id'] = $iAmId;
+ }
+ $iCount = Db::name('article_proofread')->where($aProofReadWhere)->count();
+ if(!empty($iCount)){
+ return json_encode(array('status' => 5,'msg' => 'The article or paragraph has been proofread'));
+ }
+
+ //查询文章内容
+ $aWhere['type'] = 0;
+ $aWhere['content'] = ['<>',''];
+ $aWhere['state'] = 0;
+ if(!empty($iAmId)){
+ $aWhere['am_id'] = $iAmId;
+ }
+ $aArticleMain = Db::table('t_article_main')->field('am_id,content,type,is_h1,is_h2,is_h3,ami_id,amt_id')->where($aWhere)->select();
+ if(empty($aArticleMain)){
+ return json_encode(array('status' => 5,'msg' => 'The content of the article is empty'));
+ }
+
+ //实例化公共方法
+ $oHelperFunction = new \app\common\HelperFunction;
+ $oProofReadService = new \app\common\ProofReadService;
+ //数据处理
+ $aH = $aTable = [];
+ foreach ($aArticleMain as $key => $value) {
+ if(empty($oHelperFunction->filterAllTags($value['content']))){
+ continue;
+ }
+ $aResult = $oProofReadService->proofread($value['content']);
+ if(empty($aResult)){
+ continue;
+ }
+ $aResult['am_id'] = $value['am_id'];
+ $aError[] = $aResult;
+ }
+ if(empty($aError)){
+ return json_encode(array('status' => 1,'msg' => 'No errors found'));
+ }
+ //数据处理
+ foreach ($aError as $key => $value) {
+ if(empty($value['errors'])){
+ continue;
+ }
+ foreach ($value['errors'] as $k => $val) {
+ $val['am_id'] = $value['am_id'];
+ $val['article_id'] = $iArticleId;
+ $val['proof_before'] = empty($value['proof_before']) ? '' : $value['proof_before'];
+ $val['proof_after'] = empty($value['proof_after']) ? '' : $value['proof_after'];
+ $aData[] = $val;
+ }
+ }
+ if(empty($aData)){
+ return json_encode(array('status' => 1,'msg' => 'Data processing failed'));
+ }
+ //插入
+ $result = Db::name('article_proofread')->insertAll($aData);
+ if(!$result){
+ return json_encode(array('status' => 6,'msg' => 'No errors found'));
+ }
+
+ //查询参考文献
+ $aWhere = ['state' => ['in',[0,2]],'article_id' => $iArticleId];
+ return json_encode(['status' => 1,'msg' => 'success']);
+ }
+ /**
+ * @title 获取每行校对记录
+ * @param article_id 文章ID
+ * @param am_id 行号
+ * @param state 状态1已执行2未执行3删除
+ */
+ public function get($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 a article']);
+ }
+ //行号
+ $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id'];
+
+ //查询文章
+ $aWhere = ['article_id' => $iArticleId];
+ $aArticle = Db::name('article')->field('journal_id,state')->where($aWhere)->find();
+ if(empty($aArticle)){
+ return json_encode(['status' => 3,'msg' => 'The query article does not exist']);
+ }
+ if($aArticle['state'] < 5 || $aArticle['state'] == 8){
+ return json_encode(array('status' => 4,'msg' => 'The article has not entered the proofreading stage'));
+ }
+
+ //查询文章内容
+ $aWhere['type'] = 0;
+ $aWhere['content'] = ['<>',''];
+ $aWhere['state'] = 0;
+ if(!empty($iAmId)){
+ $aWhere['am_id'] = $iAmId;
+ }
+ $aArticleMain = Db::name('article_main')->field('am_id,content')->where($aWhere)->select();
+ if(empty($aArticleMain)){
+ return json_encode(array('status' => 5,'msg' => 'The content of the article is empty'));
+ }
+
+ //查询校对内容
+ $aAmId = array_column($aArticleMain, 'am_id');
+ $aWhere = ['am_id' => ['in',$aAmId]];
+ $iState = empty($aParam['state']) ? 0 : $aParam['state'];
+ if(!empty($iState)){
+ $aWhere['state'] = ['in',$iState];
+ }
+ $aProofRead = Db::name('article_proofread')->field('id,am_id,verbatim_texts,revised_content,explanation,state')->where($aWhere)->select();
+ if(empty($aProofRead)){
+ return json_encode(array('status' => 1,'msg' => 'Proofreading record is empty'));
+ }
+ //数据处理
+ $aData = [];
+ $aArticleMain = array_column($aArticleMain, 'content','am_id');
+ foreach ($aProofRead as $key => $value) {
+ $aData[$value['am_id']][] = $value;
+ }
+
+ // 存储每个文章的最新处理内容
+ // 样式定义:标红+下划线
+ // 定义标红+下划线样式
+ // $style = 'color: red; text-decoration: underline;';
+
+ // // 存储最终处理后的文章内容
+ // $aFinalContent = [];
+
+ // // 外层循环:遍历每个文章的错误分组($key为am_id)
+ // foreach ($aData as $amId => $errors) {
+ // // 获取原始文章内容(若不存在则跳过)
+ // $sContent = empty($aArticleMain[$amId]) ? '' : $aArticleMain[$amId];
+ // if (empty($sContent)) {
+ // continue;
+ // }
+
+ // // 初始化当前内容为原始内容,后续替换将基于此更新
+ // $currentContent = $sContent;
+
+ // // 内层循环:处理当前文章的每条错误记录
+ // foreach ($errors as $val) {
+ // // 只处理状态为2的错误
+ // if ($val['state'] != 2) {
+ // continue;
+ // }
+
+ // // 获取错误内容(待标红的文本)
+ // $verbatim_texts = trim($val['verbatim_texts'] ?? '');
+ // if (empty($verbatim_texts)) {
+ // continue; // 空错误内容跳过
+ // }
+
+ // // 构建带样式的替换内容(用span标签包裹,添加CSS样式)
+ // $revised_content = '' . htmlspecialchars($verbatim_texts, ENT_QUOTES, 'UTF-8') . '';
+
+ // // 定位错误内容在当前内容中的位置(支持多字节字符,如中文)
+ // $startPos = mb_strpos($currentContent, $verbatim_texts, 0, 'UTF-8');
+ // if ($startPos === false) {
+ // continue; // 未找到错误内容,跳过
+ // }
+
+ // // 计算错误内容的字节长度(用于替换)
+ // $byteLength = strlen($verbatim_texts);
+ // // 转换字符起始位置为字节位置(适配substr_replace的字节处理)
+ // $byteStart = 0;
+ // for ($i = 0; $i < $startPos; $i++) {
+ // $byteStart += strlen(mb_substr($currentContent, $i, 1, 'UTF-8'));
+ // }
+
+ // // 执行替换:用带样式的内容替换原始错误内容
+ // $currentContent = substr_replace($currentContent, $revised_content, $byteStart, $byteLength);
+ // }
+
+ // // 保存当前文章处理后的最终内容
+ // $aFinalContent[$amId] = $currentContent;
+ // }
+ return json_encode(['status' => 1,'msg' => 'success','data' => ['record' => $aData]]);//,'record_style' => $aFinalContent
+ }
+
+ /**
+ * @title 更新状态
+ * @param article_id 文章ID
+ * @param am_id 行号
+ * @param record_id 记录ID
+ * @param state 1已执行2未执行3撤销
+ */
+ public function change(){
+ //获取参数
+ $aParam = $this->request->post();
+ //参数验证-文章ID
+ $iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
+ if(empty($iArticleId)){
+ return json_encode(['status' => 2,'msg' => 'Please select a article']);
+ }
+ //参数验证-行号ID
+ $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id'];
+ if(empty($iAmId)){
+ return json_encode(['status' => 2,'msg' => 'Please select the proofreading content']);
+ }
+ //主键ID
+ $iId = empty($aParam['record_id']) ? 0 : $aParam['record_id'];
+ if(empty($iId)){
+ return json_encode(['status' => 2,'msg' => 'Please select the review record']);
+ }
+ //状态
+ $iState = empty($aParam['state']) ? 0 : intval($aParam['state']);
+ if(!in_array($iState, [1,2,3])){
+ return json_encode(['status' => 2,'msg' => 'Illegal review status']);
+ }
+
+ //修改内容
+ $sContent = empty($aParam['content']) ? '' : $aParam['content'];
+ if(in_array($iState, [1,2]) && empty($sContent)){
+ return json_encode(['status' => 2,'msg' => 'The operation content cannot be empty']);
+ }
+
+ //判断校对记录
+ $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'id' => $iId];
+ $aProofRead = Db::name('article_proofread')->where($aWhere)->find();
+
+ if(empty($aProofRead)){
+ return json_encode(['status' => 3,'msg' => 'Proofreading record is empty']);
+ }
+ if($aProofRead['state'] == 3){
+ return json_encode(['status' => 4,'msg' => 'Record deleted']);
+ }
+
+ //状态一致
+ if($iState == $aProofRead['state']){
+ return json_encode(['status' => 5,'msg' => 'Consistent status without modification']);
+ }
+
+ //判断记录是否执行
+ if($iState == 3 && $aProofRead['state'] == 1){
+ return json_encode(['status' => 6,'msg' => 'This record has been executed and cannot be deleted']);
+ }
+ $sData = $sUpdateContent = '';
+ if($iState == 1){ //执行替换操作
+ $aProofRead['content'] = $sContent;
+ $aResult = $this->replaceError($aProofRead);
+ $iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
+ if($iStatus != 1){
+ return json_encode($aResult);
+ }
+ //获取内容
+ $sUpdateContent = empty($aResult['data']) ? '' : $aResult['data'];
+ if(empty($sUpdateContent)){
+ return json_encode(['status' => 5,'msg' => 'Content processing failed']);
+ }
+ // $aDealData = json_decode($this->get(['am_id' => $iAmId,'article_id' => $iArticleId]),true);
+ // $aDealData = empty($aDealData['data']) ? [] : $aDealData['data'];
+ // $sData = empty($aDealData['record_style']) ? '' : $aDealData['record_style'];
+ $sData = $sUpdateContent;
+ }
+ if($iState == 2){ //执行替换操作
+ $aProofRead['content'] = $sContent;
+ $aResult = $this->removeReplaceError($aProofRead);
+ $iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
+ if($iStatus != 1){
+ return json_encode($aResult);
+ }
+ //获取内容
+ $sUpdateContent = empty($aResult['data']) ? '' : $aResult['data'];
+ if(empty($sUpdateContent)){
+ return json_encode(['status' => 5,'msg' => 'Content processing failed']);
+ }
+ // $aDealData = json_decode($this->get(['am_id' => $iAmId,'article_id' => $iArticleId]),true);
+ // $aDealData = empty($aDealData['data']) ? [] : $aDealData['data'];
+ // $sData = empty($aDealData['record_style']) ? '' : $aDealData['record_style'];
+ $sData = $sUpdateContent;
+ }
+ Db::startTrans();
+ //更新原始内容
+ if(!empty($sUpdateContent)){
+ $aWhere = ['am_id' => $iAmId,'state' => 0,'type' => 0];
+ $aUpdate = ['content' => $sUpdateContent];
+ $result_main = Db::name('article_main')->where($aWhere)->limit(1)->update($aUpdate);
+ }
+ //判断更新参数
+ $aUpdate = ['state' => $iState,'update_time' => time()];
+ //数据库更新
+ $aWhere = ['id' => $iId];
+ $result_proofread= Db::name('article_proofread')->where($aWhere)->limit(1)->update($aUpdate);
+ if(!$result_proofread || !$result_main){
+ return json_encode(['status' => 7,'msg' => "Update failed"]);
+ }
+ Db::commit();
+ //返回结果
+ return json_encode(['status' => 1,'msg' => "Update successful",'data' => $sData]);
+ }
+
+ /**
+ * 替换错误
+ * @param string $errorId 错误ID
+ * @return bool 替换是否成功
+ */
+ private function replaceError($aParam = [])
+ {
+ if(empty($aParam)){
+ return ['status' => 2,'msg' => 'The content is empty'];
+ }
+ //原始内容
+ $sContent = empty($aParam['content']) ? '' : $aParam['content'];
+ //错误内容
+ $verbatim_texts = empty($aParam['verbatim_texts']) ? '' : $aParam['verbatim_texts'];
+ //正确内容
+ $revised_content = empty($aParam['revised_content']) ? 0 : $aParam['revised_content'];
+
+ $iLength = strlen($verbatim_texts);
+ //内容替换
+ $sContent = $this->replaceByLengthAndKeyword($sContent,$iLength,$verbatim_texts,$revised_content);
+
+ return ['status' => 1,'msg' => 'success','data' => $sContent];
+ }
+
+ /**
+ * 撤回替换错误
+ * @param string $errorId 错误ID
+ * @return bool 替换是否成功
+ */
+ private function removeReplaceError($aParam = [])
+ {
+ if(empty($aParam)){
+ return ['status' => 2,'msg' => 'The content is empty'];
+ }
+ //原始内容
+ $sContent = empty($aParam['content']) ? '' : $aParam['content'];
+ //错误内容
+ $verbatim_texts = empty($aParam['verbatim_texts']) ? '' : $aParam['verbatim_texts'];
+ //正确内容
+ $revised_content = empty($aParam['revised_content']) ? '' : $aParam['revised_content'];
+
+ $iLength = strlen($revised_content);
+ //内容替换
+ $sContent = $this->replaceByLengthAndKeyword($sContent,$iLength,$revised_content,$verbatim_texts);
+
+ return ['status' => 1,'msg' => 'success','data' => $sContent];
+ }
+ /**
+ * 按长度和内容特征快速定位并替换字符串
+ * @param string $str 原始字符串
+ * @param int $targetLength 目标子串长度(字节数,多字节字符需注意)
+ * @param string $keyword 筛选关键词(目标子串需包含此关键词)
+ * @param string $replace 替换内容
+ * @param string $encoding 字符编码(默认UTF-8,处理多字节字符)
+ * @return string 替换后的字符串
+ */
+ private function replaceByLengthAndKeyword($str, $targetLength, $keyword, $replace, $encoding = 'UTF-8') {
+ // 边界校验:避免无效参数导致错误
+ if (empty($str) || $targetLength <= 0 || empty($keyword)) {
+ return '';
+ }
+ $strLength = strlen($str);
+ if ($targetLength > $strLength) {
+ return ''; // 目标长度超过原始字符串,无需处理
+ }
+
+ $result = $str;
+ $targets = []; // 存储目标子串的起始位置(字节索引)
+
+ // 遍历字符串,提取符合长度且包含关键词的子串位置(一次遍历完成筛选,减少内存占用)
+ for ($i = 0; $i <= $strLength - $targetLength; $i++) {
+ // 截取目标长度的子串
+ $substr = substr($result, $i, $targetLength);
+ // 检查子串是否包含关键词(多字节安全)
+ if (mb_strpos($substr, $keyword, 0, $encoding) !== false) {
+ $targets[] = $i; // 只存起始位置,减少内存占用
+ }
+ }
+
+ // 若没有匹配目标,直接返回原始字符串
+ if (empty($targets)) {
+ return '';
+ }
+
+ // 从后往前替换(避免前面替换导致后面位置偏移)
+ // 倒序遍历数组,无需额外排序,效率更高
+ for ($k = count($targets) - 1; $k >= 0; $k--) {
+ $start = $targets[$k];
+ // 二次校验:替换前确认子串仍符合条件(防止重复替换或中间修改导致的偏差)
+ $currentSubstr = substr($result, $start, $targetLength);
+ if (mb_strpos($currentSubstr, $keyword, 0, $encoding) !== false) {
+ $result = substr_replace($result, $replace, $start, $targetLength);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @title 更新内容
+ * @param article_id 文章ID
+ * @param am_id 行号
+ * @param record_id 记录ID
+ * @param revised_content 修改内容
+ * @param is_update_all 是否更新所有1是2否
+ */
+ public function modify(){
+ //获取参数
+ $aParam = $this->request->post();
+ //参数验证-文章ID
+ $iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
+ if(empty($iArticleId)){
+ return json_encode(['status' => 2,'msg' => 'Please select a article']);
+ }
+ //参数验证-行号ID
+ $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id'];
+ if(empty($iAmId)){
+ return json_encode(['status' => 2,'msg' => 'Please select the proofreading content']);
+ }
+ //主键ID
+ $iId = empty($aParam['record_id']) ? 0 : $aParam['record_id'];
+ if(empty($iId)){
+ return json_encode(['status' => 2,'msg' => 'Please select the review record']);
+ }
+ //修改后的内容
+ $sRevisedContent = empty($aParam['revised_content']) ? '' : $aParam['revised_content'];
+ if(empty($sRevisedContent)){
+ return json_encode(['status' => 2,'msg' => 'Please enter the modification content']);
+ }
+ //解释说明
+ $sExplanation = empty($aParam['explanation']) ? '' : $aParam['explanation'];
+ //是否更新所有1是2否
+ $iIsUpdateAll = empty($aParam['is_update_all']) ? 2 : $aParam['is_update_all'];
+
+ //查询内容是否存在
+ $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'id' => $iId];
+ $aProofRead = Db::name('article_proofread')->field('verbatim_texts,revised_content,explanation,state')->where($aWhere)->find();
+ if(empty($aProofRead)){
+ return json_encode(['status' => 3,'msg' => 'Proofreading record is empty']);
+ }
+ if($aProofRead['state'] == 3){
+ return json_encode(['status' => 4,'msg' => 'Record deleted']);
+ }
+ if($aProofRead['state'] == 1){
+ return json_encode(['status' => 5,'msg' => 'Record executed']);
+ }
+ //判断更新参数
+ $aUpdate = ['revised_content' => $sRevisedContent,'update_time' => time()];
+ if(!empty($sExplanation)){
+ $aUpdate['explanation'] = $sExplanation;
+ }
+ //数据库更新
+ $aWhere = ['id' => $iId];
+ if($iIsUpdateAll == 1){
+ if(empty($aProofRead['verbatim_texts']) || empty($aProofRead['revised_content'])){
+ return json_encode(['status' => 6,'msg' => 'AI proofreading content is empty']);
+ }
+ $aWhere = ['verbatim_texts' => $aProofRead['verbatim_texts'],'revised_content' => $aProofRead['revised_content'],'article_id' => $iArticleId,'state' => 2];
+ }
+ $result = Db::name('article_proofread')->where($aWhere)->update($aUpdate);
+ if(!$result){
+ return json_encode(['status' => 7,'msg' => "Update failed"]);
+ }
+ //返回结果
+ return json_encode(['status' => 1,'msg' => "Update successful"]);
+ }
+}
diff --git a/application/api/controller/Publish.php b/application/api/controller/Publish.php
index f27bd03..002085a 100644
--- a/application/api/controller/Publish.php
+++ b/application/api/controller/Publish.php
@@ -421,6 +421,13 @@ class Publish extends Base
$pra['journal_stage_id'] = $data['journal_stage_id'];
$res = object_to_array(json_decode(myPost($url, $pra)));
$res1 = object_to_array(json_decode(myPost($url1, $pra)));
+
+ //同步分期下的文章PDF文件到ftp.portico.org chengxiaoling 20250925 start
+ if(!empty($data['journal_stage_id'])){
+ $sQueueId = \think\Queue::push('app\api\job\SyncArticleData@fire', ['journal_stage_id' => $data['journal_stage_id']], 'SyncArticleData');
+ }
+ //同步分期下的文章PDF文件到ftp.portico.org chengxiaoling 20250925 end
+
return jsonSuccess([]);
}
diff --git a/application/api/controller/Supplementary.php b/application/api/controller/Supplementary.php
index 0b55701..068fe0e 100644
--- a/application/api/controller/Supplementary.php
+++ b/application/api/controller/Supplementary.php
@@ -31,28 +31,40 @@ class Supplementary extends Base
if(empty($sIssn)){
return json_encode(['status' => 2,'msg' => 'Please select an journal']);
}
-
+ if(is_string($sIssn)){
+ $sIssn = explode(',', $sIssn);
+ }
//根据期刊issn查询期刊ID
- $aWhere = ['state' => 0,'issn' => $sIssn];
- $aJournal = Db::name('journal')->field('journal_id')->where($aWhere)->find();
+ $aWhere = ['state' => 0,'issn' => ['in',$sIssn]];
+ $aJournal = Db::name('journal')->where($aWhere)->column('journal_id,issn');
if(empty($aJournal)){
return json_encode(['status' => 3,'msg' => 'No journal information found']);
}
//查询期刊编辑信息
- $aWhere = ['state' => 0,'journal_id' => $aJournal['journal_id']];
+ $aWhere = ['state' => 0,'journal_id' => ['in',array_keys($aJournal)]];
if(isset($aParam['type'])){//编辑类型
$aWhere['type'] = $aParam['type'];
}
- $aJournalBoard = Db::name('board_to_journal')->where($aWhere)->column('user_id');
+ $aJournalBoard = Db::name('board_to_journal')->field('journal_id,user_id')->where($aWhere)->select();
if(empty($aJournalBoard)){
return json_encode(['status' => 4,'msg' => 'No editorial information was found for the journal']);
}
//查询编辑详情
- $aWhere = ['state' => 0,'user_id' => ['in',$aJournalBoard]];
- $aUser = Db::name('user')->field('user_id,realname')->where($aWhere)->select();
- return json_encode(['status' => 1,'msg' => 'success','data' => $aUser]);
+ $aUserId = array_column($aJournalBoard, 'user_id');
+ $aWhere = ['state' => 0,'user_id' => ['in',$aUserId]];
+ $aUser = Db::name('user')->where($aWhere)->column('user_id,realname');
+ $aUserData = [];
+ foreach ($aJournalBoard as $key => $value) {
+ $sIssn = empty($aJournal[$value['journal_id']]) ? '' : $aJournal[$value['journal_id']];
+ if(empty($sIssn)){
+ continue;
+ }
+ $sRealName = empty($aUser[$value['user_id']]) ? '' : $aUser[$value['user_id']];
+ $aUserData[$sIssn][] = $sRealName;
+ }
+ return json_encode(['status' => 1,'msg' => 'success','data' => $aUserData]);
}
}
diff --git a/application/api/controller/Syncdata.php b/application/api/controller/Syncdata.php
new file mode 100644
index 0000000..eeec63a
--- /dev/null
+++ b/application/api/controller/Syncdata.php
@@ -0,0 +1,128 @@
+request->post();
+
+ //期刊ID
+ $iJournalId = empty($aParam['journal_id']) ? 0 : $aParam['journal_id'];
+ if(empty($iJournalId)){
+ return json_encode(['code' => 2, 'msg' => 'Please select a journal']);
+ }
+ //获取期刊下的子刊
+ $sUrl = $this->sJournalUrl."api/Syncdata/getJournalStage";
+ $aResult = object_to_array(json_decode(myPost1($sUrl,$aParam),true));
+ $iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
+
+ $sMsg = empty($aResult['msg']) ? 'Illegal operation-getJournalStage' : $aResult['msg'];
+ if($iStatus != 1){
+ return json_encode(['code' => 3, 'msg' => $sMsg]);
+ }
+ //获取期刊下的子刊
+ $aJournalStage = empty($aResult['data']) ? [] : $aResult['data'];
+ if(empty($aJournalStage)){
+ return json_encode(['code' => 4, 'msg' => 'Journal data is empty']);
+ }
+
+ //数据处理
+ foreach ($aJournalStage as $key => $value) {
+ // $aArticle = json_decode($this->getJournalStageArticle(['journal_stage_id' => $value['journal_stage_id']]),true);
+ // var_dump($aArticle);exit;
+ //写入查询期刊文章队列
+ $sQueue = Queue::push('app\api\job\SyncArticleData@fire', ['journal_stage_id' => $value['journal_stage_id']], 'SyncArticleData');
+ }
+ return json_encode(['code' => 1, 'msg' => 'Synchronization queue addition completed','data' => $sQueue]);
+ }
+ /**
+ * @title 获取期刊下的文章
+ * @param journal_id 期刊ID
+ * @param journal_stage_id 子刊ID
+ */
+ public function getJournalStageArticle($aParam = []){
+
+ //获取数据
+ $aParam = empty($aParam) ? $this->request->post() : $aParam;
+
+ //期刊ID
+ $iJournalStageId = empty($aParam['journal_stage_id']) ? 0 : $aParam['journal_stage_id'];
+ if(empty($iJournalStageId)){
+ return json_encode(['code' => 2, 'msg' => 'Please select a sub issue under the journal']);
+ }
+ //获取期刊下的子刊
+ $sUrl = $this->sJournalUrl."api/Syncdata/getJournalStageArticle";
+ $aResult = object_to_array(json_decode(myPost1($sUrl,$aParam),true));
+ $iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
+ $sMsg = empty($aResult['msg']) ? 'Illegal operation-getJournalStageArticle' : $aResult['msg'];
+ if($iStatus != 1){
+ return json_encode(['code' => 3, 'msg' => $sMsg]);
+ }
+ //获取文章
+ $aArticle = empty($aResult['data']) ? [] : $aResult['data'];
+ if(empty($aArticle)){
+ return json_encode(['code' => 4, 'msg' => 'Article data is empty']);
+ }
+
+ //写入上传文章队列
+ $sQueue = Queue::push('app\api\job\SyncArticleUpload@fire', $aArticle, 'SyncArticleUpload');
+ // $aResult = json_decode($this->uploadArticle($aArticle),true);
+ return json_encode(['code' => 1, 'msg' => 'Joined the upload file queue','data' => $sQueue]);
+ }
+ /**
+ * @title 同步文章数据到服务器
+ * @param file 文章数据
+ * @param journal_stage_id 子刊ID
+ */
+ public function uploadArticle($aParam = []){
+
+ //获取数据
+ $aParam = empty($aParam) ? $this->request->post() : $aParam;
+
+ //期刊ID
+ $iJournalStageId = empty($aParam['journal_stage_id']) ? 0 : $aParam['journal_stage_id'];
+ if(empty($iJournalStageId)){
+ return json_encode(['code' => 2, 'msg' => 'Please select a sub issue under the journal']);
+ }
+ //文章数据
+ $aArticle = empty($aParam['article']) ? [] : $aParam['article'];
+ if(empty($aArticle)){
+ return json_encode(['code' => 2, 'msg' => 'Article data is empty']);
+ }
+ //获取期刊下的子刊
+ $sUrl = $this->sJournalUrl."api/Syncdata/uploadArticle";
+ $aResult = object_to_array(json_decode(myPost1($sUrl,$aParam),true));
+ $iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
+ $sMsg = empty($aResult['msg']) ? 'Illegal operation-uploadArticle' : $aResult['msg'];
+ if($iStatus != 1){
+ return json_encode(['code' => 3, 'msg' => $sMsg]);
+ }
+ $aResult = empty($aResult['data']) ? [] : $aResult['data'];
+ return json_encode(['code' => 1, 'msg' => $sMsg,'data' => $aResult]);
+ }
+}
diff --git a/application/api/job/ArticleProofRead.php b/application/api/job/ArticleProofRead.php
new file mode 100644
index 0000000..0781508
--- /dev/null
+++ b/application/api/job/ArticleProofRead.php
@@ -0,0 +1,78 @@
+oQueueJob = new QueueJob;
+ $this->QueueRedis = QueueRedis::getInstance();
+ }
+
+ public function fire(Job $job, $data)
+ {
+ //任务开始判断
+ $this->oQueueJob->init($job);
+
+ // 获取 Redis 任务的原始数据
+ $rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
+ $jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
+ $jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
+
+ $this->oQueueJob->log("-----------队列任务开始-----------");
+ $this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
+
+ // 获取文章ID
+ $iArticleId = empty($data['article_id']) ? 0 : $data['article_id'];
+ if (empty($iArticleId)) {
+ $this->oQueueJob->log("无效的article_id,删除任务");
+ $job->delete();
+ return;
+ }
+ try {
+
+ // 生成Redis键并尝试获取锁
+ $sClassName = get_class($this);
+ $sRedisKey = "queue_job:{$sClassName}:{$iArticleId}";
+ $sRedisValue = uniqid() . '_' . getmypid();
+ if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
+ return; // 未获取到锁,已处理
+ }
+
+ //生成内容
+ $oProofRead = new Proofread;
+ $response = $oProofRead->proofRead($data);
+ // 验证API响应
+ if (empty($response)) {
+ throw new \RuntimeException("OpenAI API返回空结果");
+ }
+ // 检查JSON解析错误
+ $aResult = json_decode($response, true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
+ }
+ $sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
+ //更新完成标识
+ $this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
+ $job->delete();
+ $this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
+
+ } catch (\RuntimeException $e) {
+ $this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } catch (\LogicException $e) {
+ $this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } catch (\Exception $e) {
+ $this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } finally {
+ $this->oQueueJob->finnal();
+ }
+ }
+}
\ No newline at end of file
diff --git a/application/api/job/SendRelatedArticleEmail.php b/application/api/job/SendRelatedArticleEmail.php
index 975688a..1e029c1 100644
--- a/application/api/job/SendRelatedArticleEmail.php
+++ b/application/api/job/SendRelatedArticleEmail.php
@@ -70,7 +70,7 @@ class SendRelatedArticleEmail
// 执行核心任务
//查询是否发送过邮件
$oJournalArticle = new JournalArticle;
- $aLog = json_decode($oJournalArticle::getLog(['article_id' => $iArticleId,'article_author_id' => $article_author_id,'related_article_id' => $related_article_id,'is_success' => 1]),true);
+ $aLog = json_decode($oJournalArticle::getLog(['article_id' => $iArticleId,'email' => $email,'related_article_id' => $related_article_id,'is_success' => 1]),true);
$sMsg = '邮件已发送';
if(empty($aLog['data'])){
$aResult = sendEmail($email,$title,$from_name,$content,$memail,$mpassword);
diff --git a/application/api/job/SyncArticleData.php b/application/api/job/SyncArticleData.php
new file mode 100644
index 0000000..41cf313
--- /dev/null
+++ b/application/api/job/SyncArticleData.php
@@ -0,0 +1,78 @@
+oQueueJob = new QueueJob;
+ $this->QueueRedis = QueueRedis::getInstance();
+ }
+
+ public function fire(Job $job, $data)
+ {
+ //任务开始判断
+ $this->oQueueJob->init($job);
+
+ // 获取 Redis 任务的原始数据
+ $rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
+ $jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
+ $jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
+
+ $this->oQueueJob->log("-----------队列任务开始-----------");
+ $this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
+
+ // 获取文章ID
+ $iJournalStageId = empty($data['journal_stage_id']) ? 0 : $data['journal_stage_id'];
+ if (empty($iJournalStageId)) {
+ $this->oQueueJob->log("无效的journal_stage_id,删除任务");
+ $job->delete();
+ return;
+ }
+ try {
+
+ // 生成Redis键并尝试获取锁
+ $sClassName = get_class($this);
+ $sRedisKey = "queue_job:{$sClassName}:{$iJournalStageId}";
+ $sRedisValue = uniqid() . '_' . getmypid();
+ if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
+ return; // 未获取到锁,已处理
+ }
+
+ //生成内容
+ $oAireview = new Syncdata;
+ $response = $oAireview->getJournalStageArticle($data);
+ // 验证API响应
+ if (empty($response)) {
+ throw new \RuntimeException("OpenAI API返回空结果");
+ }
+ // 检查JSON解析错误
+ $aResult = json_decode($response, true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
+ }
+ $sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
+ //更新完成标识
+ $this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
+ $job->delete();
+ $this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
+
+ } catch (\RuntimeException $e) {
+ $this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } catch (\LogicException $e) {
+ $this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } catch (\Exception $e) {
+ $this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } finally {
+ $this->oQueueJob->finnal();
+ }
+ }
+}
\ No newline at end of file
diff --git a/application/api/job/SyncArticleUpload.php b/application/api/job/SyncArticleUpload.php
new file mode 100644
index 0000000..d6c4b8a
--- /dev/null
+++ b/application/api/job/SyncArticleUpload.php
@@ -0,0 +1,79 @@
+oQueueJob = new QueueJob;
+ $this->QueueRedis = QueueRedis::getInstance();
+ }
+
+ public function fire(Job $job, $data)
+ {
+ //任务开始判断
+ $this->oQueueJob->init($job);
+
+ // 获取 Redis 任务的原始数据
+ $rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
+ $jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
+ $jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
+
+ $this->oQueueJob->log("-----------队列任务开始-----------");
+ $this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
+
+ // 获取文章ID
+ $iJournalStageId = empty($data['journal_stage_id']) ? 0 : $data['journal_stage_id'];
+ if (empty($iJournalStageId)) {
+ $this->oQueueJob->log("无效的journal_stage_id,删除任务");
+ $job->delete();
+ return;
+ }
+ try {
+
+ // 生成Redis键并尝试获取锁
+ $sClassName = get_class($this);
+ $sRedisKey = "queue_job:{$sClassName}:{$iJournalStageId}";
+ $sRedisValue = uniqid() . '_' . getmypid();
+ if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
+ return; // 未获取到锁,已处理
+ }
+
+ //生成内容
+ $oAireview = new Syncdata;
+ $response = $oAireview->uploadArticle($data);
+ // 验证API响应
+ if (empty($response)) {
+ throw new \RuntimeException("OpenAI API返回空结果");
+ }
+ // 检查JSON解析错误
+ $aResult = json_decode($response, true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
+ }
+ $sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
+ $sData = empty($aResult['data']) ? '' : json_encode($aResult['data']);
+ //更新完成标识
+ $this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
+ $job->delete();
+ $this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg} | 数据:{$sData}");
+
+ } catch (\RuntimeException $e) {
+ $this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } catch (\LogicException $e) {
+ $this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } catch (\Exception $e) {
+ $this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
+ } finally {
+ $this->oQueueJob->finnal();
+ }
+ }
+}
\ No newline at end of file
diff --git a/application/common/Article.php b/application/common/Article.php
index bf7c741..f731f6e 100644
--- a/application/common/Article.php
+++ b/application/common/Article.php
@@ -84,7 +84,7 @@ class Article
}
$iAiArticleId = $aAiArticle['ai_article_id'];
//必填参数验证
- $aFields = ['article_id','article_type','media_type','journal_id','journal_issn','title_english','title_chinese','covered','research_method','digest','research_background','overview','summary','conclusion','is_generate'];
+ $aFields = ['article_id','article_type','media_type','journal_id','journal_issn','title_english','covered','title_chinese','digest','research_background','discussion','research_method','conclusion','overview','summary','is_generate'];
$sFiled = '';
$aUpdateParam = [];
diff --git a/application/common/JournalArticle.php b/application/common/JournalArticle.php
index 469dc35..cd4e75f 100644
--- a/application/common/JournalArticle.php
+++ b/application/common/JournalArticle.php
@@ -7,7 +7,7 @@ class JournalArticle
{
//官网接口地址
- protected static $sApiUrl = 'http://journalapi.tmrjournals.com/public/index.php/';//'http://zmzm.journal.dev.com/';
+ protected static $sApiUrl = 'http://journalapi.tmrjournals.com/public/index.php/';//'http://zmzm.journal.dev.com/';//
//期刊官网
protected static $sJournalUsx = 'https://www.tmrjournals.com/';
@@ -85,19 +85,20 @@ class JournalArticle
if(empty($aJournal)){
return json_encode(['status' => 5,'msg' => 'The journal to which the article belongs does not exist']);
}
- //文章作者
+
+ //获取数据-文章通讯作者数据
$aAuthor = empty($aData['author']) ? [] : $aData['author'];
if(empty($aAuthor)){
- return json_encode(['status' => 6,'msg' => 'No author information found for the article']);
+ return json_encode(['status' => 5,'msg' => '未查询到引用文章作者数据']);
}
//查询邮件发送日志
$aWhere = ['article_id' => $iArticleId,'is_success' => 1];
- $aEmailLog = Db::name('email_related_article')->field('related_article_id,article_author_id')->where($aWhere)->select();
+ $aEmailLog = Db::name('email_related_article')->field('related_article_id,email')->where($aWhere)->select();
$aLog = [];
if(!empty($aEmailLog)){
foreach ($aEmailLog as $key => $value) {
- $aLog[$value['related_article_id']][] = $value['article_author_id'];
+ $aLog[$value['related_article_id']][] = $value['email'];
}
}
@@ -106,18 +107,26 @@ class JournalArticle
//数据处理
$aEmailLog = [];
$sErrorMsg = '';
- foreach ($aAuthor as $key => $value) {
+ $aSendEmail = [];//['2101' => ['mohammadalipour_z@yahoo.com']];
+ foreach ($aAuthor as $key => $value) {
+ if(empty($value['is_report']) || (!empty($value['is_report']) && $value['is_report'] != 1)){
+ continue;
+ }
//作者邮箱-发送信息
- $email = empty($value['email']) ? '' : $value['email'];
+ $email = empty($value['email']) ? '' : $value['email'];//'tmr@tmrjournals.com';//'1172937051@qq.com';//
if(empty($email)){
continue;
}
- $email = $value['email'];//'tmr@tmrjournals.com';//'1172937051@qq.com';//
+
+ //判断同一个邮箱是否重复发送
+ if(!empty($aSendEmail[$value['article_id']]) && in_array($email, $aSendEmail[$value['article_id']])){
+ continue;
+ }
+
//判断是否发送过邮件
- //邮件日志
- $aEmailLogInfo = empty($aLog[$value['article_id']]) ? [] : $aLog[$value['article_id']];
- if(in_array($value['article_author_id'], $aEmailLogInfo)){
+ $aEmailLogInfo = empty($aLog[$value['article_id']]) ? [] : $aLog[$value['article_id']];//邮件日志
+ if(in_array($value['email'], $aEmailLogInfo)){
continue;
}
@@ -186,9 +195,12 @@ class JournalArticle
$iIsSuccess = 1;
$sMsg = '成功';
}
- $aEmaiParam = ['article_id' => $iArticleId,'article_author_id' =>$value['article_author_id'],'related_article_id' => $value['article_id'],'email' => $email,'content' => $content,'create_time' => time(),'journal_id' => $aJournalInfo['journal_id'],'journal_issn' => $aJournalInfo['issn'],'email' => $email,'title' => $title,'from_name' => $from_name,'content' => $content,'memail' => $memail,'mpassword' => $mpassword];
+ $aEmailParam = ['article_id' => $iArticleId,'article_author_id' =>$value['article_author_id'],'related_article_id' => $value['article_id'],'email' => $email,'content' => $content,'create_time' => time(),'journal_id' => $aJournalInfo['journal_id'],'journal_issn' => $aJournalInfo['issn'],'title' => $title,'from_name' => $from_name,'memail' => $memail,'mpassword' => $mpassword];
+
+ //邮件发送记录
+ $aSendEmail[$value['article_id']][] = $email;
//调用邮件发送队列
- Queue::push('app\api\job\SendRelatedArticleEmail@fire', $aEmaiParam, 'SendRelatedArticleEmail');
+ Queue::push('app\api\job\SendRelatedArticleEmail@fire', $aEmailParam, 'SendRelatedArticleEmail');
}
return json_encode(['status' => 1,'msg' => 'Added to email sending queue']);
}
@@ -221,9 +233,8 @@ class JournalArticle
* @return void
*/
static function getLog($aParam = []) {
-
//查询条件判断
- if(empty($aParam['article_id']) || empty($aParam['article_author_id']) || empty($aParam['related_article_id'])){
+ if(empty($aParam['article_id']) || empty($aParam['email']) || empty($aParam['related_article_id'])){
return json_encode(['status' => 2,'msg' => 'Missing parameter']);
}
diff --git a/application/common/OpenAi.php b/application/common/OpenAi.php
index d2e3f07..258ac87 100644
--- a/application/common/OpenAi.php
+++ b/application/common/OpenAi.php
@@ -103,7 +103,7 @@ class OpenAi
'contradiction_explanation' => "解释说明",
],
'fund_number' => [
- 'fund_number' => "1.[内容是否有基金号]2.[解释说明][返回格式字符串]"
+ 'fund_number' => "1.[内容是否有基金号]2.[列出基金号]3.[解释说明][返回格式字符串]"
],
'attribute' => [
'attribute_assessment' => "内容是否有科学性和创新性[包括但不限于科学性(结论是否科学、参考文献是否新颖等);创新性(结论与当前研究水平相比是否有明显突破、参考文献的时间)][返回是/否]",
diff --git a/application/common/ProofReadService.php b/application/common/ProofReadService.php
new file mode 100644
index 0000000..2a21ac3
--- /dev/null
+++ b/application/common/ProofReadService.php
@@ -0,0 +1,1236 @@
+errors = [];
+ $this->excludedFormats = [];
+ $correctedContent = $content;
+
+ //时间单位缩写校对
+ $correctedContent = $this->checkTimeUnitAbbreviations($correctedContent);
+ //横线/运算符校对
+ $correctedContent = $this->checkTextFormat($correctedContent);
+ //数字格式校对
+ $correctedContent = $this->checkNumberFormat($correctedContent);
+ //毫升单位校对
+ $correctedContent = $this->checkMlUnit($correctedContent);
+ //显著性P斜体校对
+ $correctedContent = $this->checkPSignificance($correctedContent);
+ //No. 123456的写法统一
+ $correctedContent = $this->checkNoFormatUniformity($correctedContent);
+ //图表标题一律使用全称Figure 1, Table 1.不能写成Fig. 1, Tab 1.
+ $correctedContent = $this->checkFigureTableTitle($correctedContent);
+ //检测参考文献是否能打开
+ // $correctedContent = $this->checkDoi($correctedContent);
+ //判断是否为空错误信息
+ if(empty($this->errors)){
+ return [];
+ }
+ return [
+ 'proof_before' => $content,
+ 'proof_after' => $correctedContent,
+ 'errors' => $this->errors
+ ];
+ }
+
+ /**
+ * 横线/运算符校对/数字和单位(高可用版)
+ */
+ private function checkTextFormat($content) {
+ // 初始化错误数组
+ $errors = [];
+ $defaultReturn = $content;
+ $originalContent = $content; // 保存完整原始内容
+ $searchOffsetForExclude = 0; // 【新增】仅用于「特殊内容过滤」的偏移量
+ $searchOffsetForCore = 0; // 【新增】仅用于「核心规则处理」的偏移量
+
+ // 验证数据
+ if (!is_string($content) || trim($content) === '') {
+ $this->handleErrors($errors);
+ return $defaultReturn;
+ }
+
+ $corrected = $content;
+ $excludeMarkers = []; // 存储 URL/DOI + /