'0082AA', 't' => 'D25A5A', 'r' => 'D25A5A', ]; public function __construct(\think\Request $request = null) { parent::__construct($request); } /** * 添加生产实例 */ public function addProduction() { $data = $this->request->post(); $rule = new Validate([ 'article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } // $data['article_id'] = 1144; $check = $this->production_article_obj->where('article_id', $data['article_id'])->where('state', 0)->find(); if ($check) { return jsonError('Instance already exists'); } $article_info = $this->article_obj->where('article_id', $data['article_id'])->find(); // $files = $this->article_file_obj // ->where('article_id', $article_info['article_id']) // ->where('type_name', 'manuscirpt') // ->order('ctime desc') // ->limit(1) // ->select(); // if (count($files) == 0) { // return jsonError('No Manuscript'); // } // $url = $this->ts_base_url . "api/typeset/webReaddoc"; // $program['fileRoute'] = "https://submission.tmrjournals.com/public/" . $files[0]['file_url']; // $res = object_to_array(json_decode(myPost($url, $program))); // $file_runs = $res['data']; // return jsonSuccess($file_runs); //整理信息 // $frag = []; // $aa = []; // $frag['title'] = $article_info['title']; // $start_refer = false; // foreach ($file_runs as $k => $v) { // if ($start_refer && $v != '') { // if (strlen($v) > 500) { // $start_refer = false; // $frag['main'][] = $v; // continue; // } // $frag['references'][] = $v; // continue; // } // $g_val = trim(preg_replace('/\<.*?\>/', '', $v)); // $aa[] = $g_val; // // if ((strpos(strtolower(trim($g_val)), "keyword") == 0 || strpos(strtolower(trim($g_val)), "keyword") == 1) && !isset($frag['keywords'])) { // $frag['keywords'] = $v; // continue; // } // if (strtolower($g_val) == 'reference:' || strtolower($g_val) == 'references:' || strtolower($g_val) == 'references' || strtolower($g_val) == 'reference') { // $start_refer = true; // continue; // } // $frag['main'][] = $v; // } // if (!isset($frag['main'])) { // return jsonError("manuscript file error!"); // } $insert['main'] = '';//isset($frag['main']) ? json_encode($frag['main']) : ''; $insert['article_id'] = $data['article_id']; $insert['journal_id'] = $article_info['journal_id']; $insert['ctime'] = time(); $p_article_id = $this->production_article_obj->insertGetId($insert); //将主体内容写入数据库 // foreach ($frag['main'] as $v) { // $ca['p_article_id'] = $p_article_id; // $ca['content'] = $v; // $ca['content_g'] = ''; // $ca['ctime'] = time(); // $this->production_article_main_obj->insert($ca); // } return jsonSuccess([]); } public function getWebMains() { $data = $this->request->post(); $rule = new Validate([ "article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/getArticleMainsForSubmission"; $pro['article_id'] = $data['article_id']; $res = object_to_array(json_decode(myPost($url, $pro))); $re['mains'] = $res['data']['mains']; $re['article'] = $res['data']['article']; return jsonSuccess($re); } public function addWebMain() { $data = $this->request->post(); $rule = new Validate([ "article_id" => 'require', "pre_id" => "require", "type" => "require", "content" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/addArticleMainAddForSubmission"; $res = object_to_array(json_decode(myPost($url, $data))); return jsonSuccess([]); } public function addWebMains() { $data = $this->request->post(); $rule = new Validate([ "article_id" => 'require', "pre_id" => "require", "contents" => "require|array" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/addArticleMainsAddForSubmission"; $program['article_id'] = $data['article_id']; $program['pre_id'] = $data['pre_id']; $program['contents'] = json_encode($data['contents']); $res = object_to_array(json_decode(myPost($url, $program))); return jsonSuccess($res); } /**添加主题内容的空白行 * @return void */ public function addWebMainEmpty() { $data = $this->request->post(); $rule = new Validate([ "article_id" => "require", "pre_id" => "require", ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/addArticleMainAddEmptyForSubmission"; $res = object_to_array(json_decode(myPost($url, $data))); return jsonSuccess([]); } /**清空web的主体内容 * @return void */ public function clearWebMains() { $data = $this->request->post(); $rule = new Validate([ "article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/clearArticleMainForSubmission"; $res = object_to_array(json_decode(myPost($url, $data))); return jsonSuccess([]); } public function delWebMain() { $data = $this->request->post(); $rule = new Validate([ "article_main_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/delArticleMainForSubmission"; $res = object_to_array(json_decode(myPost($url, $data))); return jsonSuccess([]); } public function delWebMains() { $data = $this->request->post(); $rule = new Validate([ "ids" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $program['ids'] = json_encode($data['ids']); $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/delArticleMainsForSubmission"; $res = object_to_array(json_decode(myPost($url, $program))); return jsonSuccess([]); } public function editWebMain() { $data = $this->request->post(); $rule = new Validate([ "article_main_id" => "require", "type" => "require", "content" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/editArticleMainForSubmission"; $res = object_to_array(json_decode(myPost($url, $data))); return jsonSuccess([]); } /** * 获取全部生成实例的main内容 * @return \think\response\Json|void * @author wangjinlei */ public function getProductionMains() { // die("stop service!"); $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); $frag = getArticleMains($p_info['article_id']); // $frag = $this->getProductionMainImgs($data['p_article_id']); // if (count($frag) == 0) { // return jsonError("create error"); // } $re['mains'] = $frag; $re['production'] = $p_info; return jsonSuccess($re); } /** * @return void */ public function getProductionMainsByDoi() { die("stop service"); // $data = $this->request->post(); // $rule = new Validate([ // 'doi' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $a = explode('/', $data['doi']); // $pro_info = $this->production_article_obj->where('doi', $a[1])->where('state', 2)->find(); // if (!$pro_info) { // return jsonError("production error"); // } // // if (isset($data['file']) && $data['file'] != "") { // $frag = $this->getProductionMainImgsByNew($pro_info['p_article_id'], $data['file']); // } else { // $frag = $this->getProductionMainImgs($pro_info['p_article_id']); // } // if (count($frag) == 0) { // return jsonError("create error"); // } // $re['mains'] = $frag; // $re['production'] = $pro_info; // return jsonSuccess($re); } /** * 删除main内容的某一行 * @return void * */ // public function delProductionMain() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_main_id' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $this->production_article_main_obj->where('p_main_id', $data['p_main_id'])->update(['state' => 1]); // return jsonSuccess([]); // } /**添加主体文章图片 * @return void */ // public function addProductionMainImg() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_article_id' => 'require', // "pre_type" => "require", // "body" => "require", // "content" => "require", // "width" => "require", // "note" => "require" // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $insert['p_article_id'] = $data['p_article_id']; // if ($data['pre_type'] == "main") { // $insert['p_main_id'] = $data['body']; // } else { // $insert['pre_id'] = $data['body']; // } // $insert['content'] = $data['content']; // $insert['width'] = $data['width']; // $insert['title'] = $data['title']; // $insert['note'] = $data['note']; // $this->production_article_main_img_obj->insert($insert); // return jsonSuccess([]); // } /**删除mainimg * @return void */ // public function delProductionMainImg() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_main_img_id' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $p_img_info = $this->production_article_main_img_obj->where('p_main_img_id', $data['p_main_img_id'])->find(); // $next_info = $this->production_article_main_img_obj->where('pre_id', $p_img_info['p_main_img_id'])->find(); // if ($next_info) { // if ($p_img_info['p_main_id'] == 0) { // $this->production_article_main_img_obj->where('p_main_img_id', $next_info['p_main_img_id'])->update(['pre_id' => $p_img_info['pre_id']]); // } else { // $this->production_article_main_img_obj->where('p_main_img_id', $next_info['p_main_img_id'])->update(['p_main_id' => $p_img_info['p_main_id']]); // } // } // $this->production_article_main_img_obj->where('p_main_img_id', $data['p_main_img_id'])->update(['state' => 1]); // return jsonSuccess([]); // } /**编辑mainimg * @return void */ // public function editProductionMainImg() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_main_img_id' => 'require', // "width" => "require", // "content" => "require", // "note" => "require" // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $update['width'] = $data['width']; // $update['content'] = $data['content']; // $update['title'] = $data['title']; // $update['note'] = $data['note']; // $this->production_article_main_img_obj->where('p_main_img_id', $data['p_main_img_id'])->update($update); // return jsonSuccess([]); // } /** * 编辑main内容 * @return \think\response\Json|void * */ // public function editProductionMain() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_main_id' => 'require', // 'content' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $update['content'] = trim($data['content']); // $this->production_article_main_obj->where('p_main_id', $data['p_main_id'])->update($update); // return jsonSuccess([]); // } public function pushMainToWeb() { $data = $this->request->post(); $rule = new Validate([ 'article_id' => "require", "p_article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $url = "http://journalapi.tmrjournals.com/public/index.php/master/Article/addArticleMainForSubmission"; $pro['article_id'] = $data['article_id']; $pro['p_article_id'] = $data['p_article_id']; $res = object_to_array(json_decode(myPost($url, $pro))); // if($res['code']==1){ // return jsonError("Repeated submission"); // } return jsonSuccess([]); } /**main内容gpt程序校对 * @return void * */ // public function mainGptcheck() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_main_id' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $main_info = $this->production_article_main_obj->where('p_main_id', $data['p_main_id'])->find(); // if (mb_strlen($main_info['content']) < 20) { // return trim($main_info['content']); // } // $res = object_to_array(json_decode(pushGpt('请将以下内容按照医学期刊的标准校对,不要改变原意,主要是对格式和拼写的校对,将这四个标签保留,将校对好的内容返回 :' . trim($main_info['content'])))); // $r = $res['choices'][0]['message']['content']; // $re['content'] = $r; // return jsonSuccess($re); // } public function getPublicMains() { } /** * 删除生产实例 */ public function delProduction() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update(['state' => 1]); return jsonSuccess([]); } /** * 编辑生产实例 */ public function editProduction() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number', 'journal_stage_id' => 'require', 'title' => 'require', 'type' => 'require', 'acknowledgment' => 'require', 'keywords' => 'require', 'author_contribution' => 'require', 'abbr' => 'require', 'abstract' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); $journal_info = $this->journal_obj->where('journal_id', $p_info['journal_id'])->find(); $update['title'] = trim($data['title']); $update['journal_stage_id'] = $data['journal_stage_id']; $update['type'] = trim($data['type']); $update['icon'] = isset($data['icon']) ? trim($data['icon']) : ''; $update['tradition_tag'] = isset($data['tradition_tag']) ? trim($data['tradition_tag']) : ''; $update['tradition'] = isset($data['tradition']) ? trim($data['tradition']) : ''; $update['author_contribution'] = trim($data['author_contribution']); $update['mhoo'] = isset($data['mhoo']) ? trim($data['mhoo']) : ''; $update['ltai'] = isset($data['ltai']) ? trim($data['ltai']) : ''; // $update['abstract'] = trim($data['abstract']); $update['keywords'] = trim($data['keywords']); $update['abbreviation'] = isset($data['abbreviation']) ? trim($data['abbreviation']) : ''; $update['acknowledgment'] = trim($data['acknowledgment']); $update['executive_editor'] = isset($data['executive_editor']) ? trim($data['executive_editor']) : ''; $update['abbr'] = trim($data['abbr']); // $update['pub_date'] = trim($data['pub_date']); $update['npp'] = isset($data['npp']) ? $data['npp'] : ''; //生成doi号 // $doi = ''; // if ($p_info['doi'] == '') { // $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Journal/getStageDetail'; // $cs['journal_stage_id'] = $data['journal_stage_id']; // $list = object_to_array(json_decode(myPost($url, $cs))); // $re = $list['data']['stage']; // $doi = $this->createdoi($re['stage_year'], $re['stage_vol'], $journal_info['abbr']); // }else{ // $doi = $p_info['doi']; // } // $update['doi'] = $doi; $update['abstract'] = isset($data['abstract']) ? trim($data['abstract']) : ''; $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($update); return jsonSuccess($update); } /** * 获取文章排版结果列表 */ public function getArticleFrags() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $list = $this->production_article_frag_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); $re['frags'] = $list; return jsonSuccess($re); } // /** // * 编辑文章主要内容 // */ // public function editMainContent() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_article_id' => 'require|number', // 'main' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $update['main'] = $data['main']; // $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($update); // return jsonSuccess([]); // } private function createdoi($year, $vol, $abbr) { $frag = ''; $doi = $abbr . $year . $vol . rand(1000, 9999); $frag = $doi; $check = $this->production_article_obj->where('doi', $doi)->find(); if ($check) { $frag = $this->createdoi($year, $vol, $abbr); } return $frag; } /** * 获取引用文献列表 */ public function getReferList() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $this->refuseReferIndex($data['p_article_id']); $dois = $this->production_article_refer_obj->where("p_article_id", $data['p_article_id'])->where("refer_doi", "<>", "")->where("state", 0)->group("refer_doi")->having("count(*)>1")->column("refer_doi"); $list = $this->production_article_refer_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->order("index")->select(); $aRepeat = []; foreach ($list as $k => $v) { if (in_array($v['refer_doi'], $dois)) { $list[$k]['is_repeat'] = 1; $aRepeat[$v['refer_doi']][] = $v['index']; } else { $list[$k]['is_repeat'] = 0; } if(strpos($v['refer_content'],'retraction')!==false||strpos($v['refer_content'],'retracted')!==false){ $list[$k]['retract'] = 1; }else{ $list[$k]['retract'] = 0; } } $re['refers'] = $list; $re['repeat'] = empty($aRepeat) ? [] : $aRepeat; return jsonSuccess($re); } /** * 修改参考文献的最终结果 */ public function editReferFrag() { $data = $this->request->post(); $rule = new Validate([ 'p_refer_id' => 'require', 'refer_frag' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $updata['refer_frag'] = trim($data['refer_frag']); $updata['cs'] = 1; $this->production_article_refer_obj->where('p_refer_id', $data['p_refer_id'])->update($updata); return jsonSuccess([]); } /** * 获取生产实例列表 */ public function getProductionList() { $data = $this->request->post(); $rule = new Validate([ 'editor_id' => 'require|number', 'journal_id' => 'require', 'pageIndex' => 'require', 'pageSize' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $journalids = []; if ($data['journal_id'] == 0) { $journalids = $this->journal_obj->where('editor_id', $data['editor_id'])->column('journal_id'); } else { $journalids[] = $data['journal_id']; } $limit_start = ($data['pageIndex'] - 1) * $data['pageSize']; $list = $this->production_article_obj ->field('t_production_article.*,t_article.accept_sn') ->join('t_article', 't_article.article_id = t_production_article.article_id', 'left') ->where('t_production_article.journal_id', 'in', $journalids) ->where('t_production_article.state', 0) ->limit($limit_start, $data['pageSize']) ->select(); $count = $this->production_article_obj->where('journal_id', 'in', $journalids)->where('state', 0)->count(); $re['productions'] = $list; $re['count'] = $count; return jsonSuccess($re); } /** * 编辑文章信息在排版之后 */ public function editArticleLast() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number', // 'abstract' => 'require', 'doi' => 'require', 'pub_date' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } if (isset($data['abstract'])) { $updata['abstract'] = trim($data['abstract']); } $updata['doi'] = $data['doi']; $updata['pub_date'] = $data['pub_date']; $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($updata); return jsonSuccess([]); } /** * 推送文章到官网系统 */ public function pushArticleToSystem() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); if ($p_info['topics'] == "" || $p_info['related'] == "") { return jsonError("Topic and related articles cannot be empty"); } if ($p_info['state'] != 0) { return jsonError("Non repeatable submission"); } if ($p_info['proof_state'] != 2) { return jsonError('Warning: It is a violation to publish your article online without completing PROOF. The ONLINE step will only continue if you have completed the PROOF step.'); } //参考文献重复的不能提交 // $this->production_article_refer_obj->where("p_article_id",$data['p_article_id'])->where("state",0)->group("refer_doi")-> $article_info = $this->article_obj->where('article_id', $p_info['article_id'])->find(); $journal_info = $this->journal_obj->where('journal_id', $article_info['journal_id'])->find(); $authors = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); $report_authors = []; foreach ($authors as $k => $v) { $cache = $this->production_article_author_to_organ_obj ->field('t_production_article_organ.organ_name') ->join('t_production_article_organ', 't_production_article_organ.p_article_organ_id = t_production_article_author_to_organ.p_article_organ_id', 'left') ->where('t_production_article_author_to_organ.p_article_author_id', $v['p_article_author_id']) ->where('t_production_article_author_to_organ.state', 0) ->select(); $authors[$k]['organs'] = $cache; if ($v['is_report'] == 1) { $c_user = $this->user_obj->where('email', $v['email'])->find(); $cac['user_id'] = $c_user['user_id']; $report_authors[] = $cac; } } $organs = $this->production_article_organ_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); //check信息是否完整 if (count($authors) == 0 || $p_info['journal_stage_id'] == '' || $p_info['doi'] == '' || $p_info['abstract'] == '' || $p_info['npp'] == '') { return jsonError('Incomplete information'); } //发送推送请求 // $url = "http://www.journal.com/master/Article/addArticleForSubmission"; $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Article/addArticleForSubmission'; $pra = []; $pra['p_article_id'] = $data['p_article_id']; $pra['title'] = $p_info['title']; $pra['journal_stage_id'] = $p_info['journal_stage_id']; $pra['issn'] = $journal_info['issn']; $pra['ltai'] = $p_info['ltai']; $pra['type'] = $p_info['type']; $pra['doi'] = $p_info['doi']; $pra['tradition_tag'] = $p_info['tradition_tag']; $pra['tradition'] = $p_info['tradition']; $pra['mhoo'] = $p_info['mhoo']; $pra['abstract'] = $p_info['abstract']; $pra['pub_date'] = $p_info['pub_date']; $pra['abbr'] = $p_info['abbr']; $pra['icon'] = $p_info['icon']; $pra['lx_online'] = $journal_info['cycle'] == 0 ? 0 : 1; $pra['related'] = $p_info['related']; $pra['topics'] = $p_info['topics']; if ($p_info['file_sub'] != '') { $pra['file_sub'] = $p_info['file_sub']; } if ($p_info['file_sub2'] != '') { $pra['file_sub2'] = $p_info['file_sub2']; } if($p_info['file_sub_table'] != ''){ $pra['file_sub_table'] = $p_info['file_sub_table']; } if ($p_info['file_cdf'] != '') { $pra['file_cdf'] = $p_info['file_cdf']; } if ($p_info['endnote'] != '') { $pra['endnote'] = $p_info['endnote']; } if ($p_info['bibtex'] != '') { $pra['bibtex'] = $p_info['bibtex']; } if ($p_info['file_original'] != '') { $pra['file_original'] = $p_info['file_original']; } $pra['file_pdf'] = $p_info['file_pdf']; $pra['keywords'] = $p_info['keywords']; $pra['npp'] = $p_info['npp']; $pra['authors'] = json_encode($authors); $pra['organs'] = json_encode($organs); $res = object_to_array(json_decode(myPost($url, $pra))); if ($res['code'] == 0) { $r_update['state'] = 2; $r_update['w_article_id'] = isset($res['data']['article_id']) ? $res['data']['article_id'] : 0; $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($r_update); foreach ($report_authors as $v) { $iua['user_id'] = $v['user_id']; $iua['w_article_id'] = $res['data']['article_id']; $iua['w_article_doi'] = '10.53388/' . $p_info['doi']; $iua['journal_title'] = $journal_info['title']; $this->user_author_obj->insert($iua); } //推送到生成AI内容队列 chengxiaoling start 20250530 if (!empty($p_info['type']) && in_array($p_info['type'], ['Article', 'Review', 'Mini Review'])) { $iArticleId = empty($r_update['w_article_id']) ? 0 : $r_update['w_article_id']; if (!empty($iArticleId)) { Queue::push('app\api\job\ArticleAiCreateContent@fire', ['article_id' => $iArticleId], 'ArticleAiCreateContent'); } } //推送到生成AI内容队列 chengxiaoling end 20250530 //推送到关联文章发送邮件提醒队列【立即发送提醒邮件给关联文章的作者及文章作者】 chengxiaoling start 20250609 if (!empty($p_info['related'])) { $iArticleId = empty($r_update['w_article_id']) ? 0 : $r_update['w_article_id']; if (!empty($iArticleId)) { Queue::push('app\api\job\RelatedArticle@fire', ['article_id' => $iArticleId], 'RelatedArticle'); } } //推送到关联文章发送邮件提醒队列【立即发送提醒邮件给关联文章的作者及文章作者】 chengxiaoling end 20250609 return jsonSuccess([]); } else { return jsonError('system error:' . $res['msg']); } } public function getPdfByHtml() { $data = $this->request->post(); $html = $data['html']; $path = ROOT_PATH . 'public' . DS . 'testpdf' . DS; $intFontSize = 10.5; // $defaultConfig = (new Mpdf\Config\ConfigVariables())->getDefaults(); $defaultConfig = (new ConfigVariables())->getDefaults(); $fontDirs = $defaultConfig['fontDir']; // $defaultFontConfig = (new Mpdf\Config\FontVariables())->getDefaults(); $defaultFontConfig = (new FontVariables())->getDefaults(); $fontData = $defaultFontConfig['fontdata']; $mpdf = new \Mpdf\Mpdf([ 'mode' => 'utf-8', 'format' => 'A4', 'default_font_size' => $intFontSize, 'useSubstitutions' => true, //中文支持关键 'useAdobeCJK' => true, 'margin_left' => 0, 'margin_right' => 0, 'margin_top' => 0, 'margin_bottom' => 0, 'margin_header' => 0, 'margin_footer' => 0, 'fontDir' => array_merge($fontDirs, [ __DIR__ . '/custom/font/directory', ]), 'fontdata' => $fontData + [ '宋体' => [ 'R' => 'Sun-ExtA.ttf', 'I' => 'Sun-ExtB.ttf', ] ], 'default_font' => '宋体' //CSS中写的汉字宋体就这么写要是别的自定义的就写自己的 自定义字体关键 ]); $strContent = $html; $mpdf->WriteHTML($strContent); $strFileName_New = time() . rand(100, 999) . '.pdf'; $mpdf->Output($path . $strFileName_New, 'f'); return jsonSuccess(['url' => $strFileName_New]); } public function creatpdf() { $path = ROOT_PATH . 'public' . DS . 'testpdf' . DS; $mpdf = new Mpdf(['mode' => 'utf-8', 'format' => 'A4']); $mpdf->SetDisplayMode('fullpage'); $mpdf->autoScriptToLang = true; $mpdf->autoLangToFont = true; $fileUrl = $path . '1234.pdf'; $mpdf->WriteHTML(file_get_contents($path . 'meaut1.html')); $mpdf->Output($fileUrl, "D"); } public function creatpdf1() { $path = ROOT_PATH . 'public' . DS . 'testpdf' . DS; $intFontSize = 10.5; // $defaultConfig = (new Mpdf\Config\ConfigVariables())->getDefaults(); $defaultConfig = (new ConfigVariables())->getDefaults(); $fontDirs = $defaultConfig['fontDir']; // $defaultFontConfig = (new Mpdf\Config\FontVariables())->getDefaults(); $defaultFontConfig = (new FontVariables())->getDefaults(); $fontData = $defaultFontConfig['fontdata']; $mpdf = new \Mpdf\Mpdf([ 'mode' => 'utf-8', 'format' => 'A4', 'default_font_size' => $intFontSize, 'useSubstitutions' => true, //中文支持关键 'useAdobeCJK' => true, 'margin_left' => 0, 'margin_right' => 0, 'margin_top' => 0, 'margin_bottom' => 0, 'margin_header' => 0, 'margin_footer' => 0, 'fontDir' => array_merge($fontDirs, [ __DIR__ . '/custom/font/directory', ]), 'fontdata' => $fontData + [ '宋体' => [ 'R' => 'Sun-ExtA.ttf', 'I' => 'Sun-ExtB.ttf', ] ], 'default_font' => '宋体' //CSS中写的汉字宋体就这么写要是别的自定义的就写自己的 自定义字体关键 ]); //自定义标签样式设置也可以直接修改DefaultCss.php中的默认设置 // $mpdf->defaultCSS["BODY"]['FONT-SIZE'] = '10.5pt'; // $mpdf->defaultCSS["BODY"]['LINE-HEIGHT'] = '1.6em'; // $mpdf->defaultCSS["P"]['MARGIN'] = '0 0'; // $mpdf->defaultCSS["P"]['PADDING'] = '0'; // $mpdf->defaultCSS["H1"]['FONT-SIZE'] = '16pt'; // $mpdf->defaultCSS["H1"]['MARGIN'] = '0 0'; // $mpdf->defaultCSS["H2"]['FONT-SIZE'] = '10.5pt'; // $mpdf->defaultCSS["H2"]['MARGIN'] = '0em 0'; // $mpdf->defaultCSS["H4"]['FONT-SIZE'] = '14pt'; // $mpdf->defaultCSS["H4"]['MARGIN'] = '0 0'; // $mpdf->defaultCSS["H5"]['FONT-SIZE'] = '10.5pt'; // $mpdf->defaultCSS["H5"]['FONT-WEIGHT'] = 'normal'; // $mpdf->defaultCSS["H5"]['MARGIN'] = '-3.4em 0 0 0'; // $mpdf->defaultCSS['SPAN'] = [ // 'PADDINT-LEFT' => '14px', // 'PADDINT-RIGHT' => '14px', // 'PADDINT-TOP' => '0px', // 'PADDINT-BOTTOM' => '0px' // ]; $strContent = file_get_contents($path . 'meaut33.html'); $mpdf->WriteHTML($strContent); $strFileName_New = $path . time() . rand(100, 999) . '.pdf'; $mpdf->Output($strFileName_New, true); //第二个参数true是直接下载 不设置默认仅保存 } // public function bekjournal($str) // { // preg_match("/[0-9]{4}/", $str, $math); // $year = $math[0]; // $frag[0] = trim(substr($str, 0, stripos($str, $year))); // $frag[1] = substr($str, stripos($str, $year)); // return $frag; // } public function prgeAuthor($author) { $a = explode(',', $author); if (count($a) < 7) { return $author . '.'; } else { return trim($a[0]) . ', ' . trim($a[1]) . ', ' . trim($a[2]) . ', et al.'; } } // public function testTypeSetting(){ // $data['p_article_id'] = 7; // $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(); // $journal_info = $this->journal_obj->where('journal_id', $p_info['journal_id'])->find(); // $editor_info = $this->user_obj->where('user_id', $journal_info['editor_id'])->find(); // $typesetInfo = []; // $typesetInfo['info_title'] = $p_info['title']; // $typesetInfo['info_type'] = $p_info['type']; // $typesetInfo['doi'] = $p_info['doi']; // $typesetInfo['topic'] = ''; // $typesetInfo['mainText'] = $p_info['main']; // $au_res = $this->authorFormate($data['p_article_id']); // $typesetInfo['author'] = $au_res['author']; // $typesetInfo['authorAddress'] = $au_res['address']; // $typesetInfo['authorContribution'] = $p_info['author_contribution']; // //查询通讯作者 // $corr_authors = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('is_report', 1)->where('state', 0)->select(); // $corrauthor = ''; // $corremail = ''; // foreach ($corr_authors as $v) { // $corrauthor .= trim($v['first_name']) . ' ' . trim($v['last_name']) . '. '; // $corremail .= $v['email'] . '. '; // } // $typesetInfo['authorCorresponding'] = substr(trim($corrauthor), 0, -1); // $typesetInfo['authorCorrespondingEmail'] = substr(trim($corremail), 0, -1); // $typesetInfo['traditon'] = $p_info['tradition']; // $typesetInfo['journal'] = $journal_info['title']; // $typesetInfo['jabbr'] = $journal_info['jabbr']; // //查询分期 // $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Journal/getStageDetail'; // $cs['journal_stage_id'] = $p_info['journal_stage_id']; // $list = object_to_array(json_decode(myPost($url, $cs))); // $stage_re = $list['data']['stage']; // $typesetInfo['stage'] = $stage_re['stage_year'] . ';' . $stage_re['stage_vol'] . '(' . $stage_re['stage_no'] . '):' . $p_info['npp']; //2022;6(1):17 // $typesetInfo['little_author'] = $p_info['abbr']; // $typesetInfo['website'] = $journal_info['website']; // $typesetInfo['acknowledgment'] = $p_info['acknowledgment']; // $typesetInfo['received_date'] = date("d F Y", $article_info['ctime']);; // $typesetInfo['accepted_date'] = date("d F Y", $article_info['rtime']); // $typesetInfo['online_date'] = $p_info['pub_date']; //这里可能会有问题 // $typesetInfo['abbreviation'] = $p_info['abbreviation']; // $typesetInfo['abstractText'] = $p_info['abstract']; // $typesetInfo['keywords'] = $p_info['keywords']; // $typesetInfo['userAccount'] = $editor_info['nickname']; // //获取文件 // // $files = $this->article_file_obj // // ->where('article_id', $article_info['article_id']) // // ->where('type_name', 'manuscirpt') // // ->order('ctime desc') // // ->limit(1) // // ->select(); // // if (count($files) == 0) { // // return jsonError('No Manuscript'); // // } // // $typesetInfo['filename'] = "http://api.tmrjournals.com/public/" . $files[0]['file_url']; // $rs = $this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where('state', 0)->select(); // // $refers = []; // // foreach ($rs as $v) { // // $refers[] = $v['refer_frag']; // // } // $typesetInfo['refers'] = json_encode($rs); // $url = "http://localhost:8081/typeset/webtest"; // $res = object_to_array(json_decode(myPost1($url, $typesetInfo))); // dump($res); // } /** * 排版主方法入口 */ public function doTypeSetting() { $data = $this->request->post(); // 验证规则 $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $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(); $journal_info = $this->journal_obj->where('journal_id', $p_info['journal_id'])->find(); $editor_info = $this->user_obj->where('user_id', $journal_info['editor_id'])->find(); $typesetInfo = []; $typesetInfo['info_title'] = $p_info['title']; $typesetInfo['info_type'] = $p_info['type']; $typesetInfo['doi'] = $p_info['doi']; $typesetInfo['topic'] = ''; $typesetInfo['mainText'] = $p_info['main']; $au_res = $this->authorFormate($data['p_article_id']); $typesetInfo['author'] = $au_res['author']; $typesetInfo['authorAddress'] = $au_res['address']; $typesetInfo['authorContribution'] = $p_info['author_contribution']; //查询通讯作者 $corr_authors = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('is_report', 1)->where('state', 0)->select(); $corrauthor = ''; $corremail = ''; foreach ($corr_authors as $v) { $corrauthor .= trim($v['first_name']) . ' ' . trim($v['last_name']) . '. '; $corremail .= $v['email'] . '. '; } $typesetInfo['authorCorresponding'] = substr(trim($corrauthor), 0, -1); $typesetInfo['authorCorrespondingEmail'] = substr(trim($corremail), 0, -1); $typesetInfo['traditon'] = $p_info['tradition']; $typesetInfo['journal'] = $journal_info['title']; $typesetInfo['jabbr'] = $journal_info['jabbr']; //查询分期 $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Journal/getStageDetail'; $cs['journal_stage_id'] = $p_info['journal_stage_id']; $list = object_to_array(json_decode(myPost($url, $cs))); $stage_re = $list['data']['stage']; $typesetInfo['stage'] = $stage_re['stage_year'] . ';' . $stage_re['stage_vol'] . '(' . $stage_re['stage_no'] . '):' . $p_info['npp']; //2022;6(1):17 $typesetInfo['little_author'] = $p_info['abbr']; $typesetInfo['website'] = $journal_info['website']; $typesetInfo['acknowledgment'] = $p_info['acknowledgment']; $typesetInfo['received_date'] = date("d F Y", $article_info['ctime']);; $typesetInfo['accepted_date'] = date("d F Y", $article_info['rtime']); $typesetInfo['online_date'] = $p_info['pub_date']; //这里可能会有问题 $typesetInfo['abbreviation'] = $p_info['abbreviation']; $typesetInfo['abstractText'] = $p_info['abstract']; $typesetInfo['keywords'] = $p_info['keywords']; $typesetInfo['userAccount'] = $editor_info['nickname']; //获取文件 $files = $this->article_file_obj ->where('article_id', $article_info['article_id']) ->where('type_name', 'manuscirpt') ->order('ctime desc') ->limit(1) ->select(); if (count($files) == 0) { return jsonError('No Manuscript'); } $typesetInfo['filename'] = "http://api.tmrjournals.com/public/" . $files[0]['file_url']; $rs = $this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where('state', 0)->order("index")->select(); // $refers = []; // foreach ($rs as $v) { // $refers[] = $v['refer_frag']; // } // $typesetInfo['refers'] = json_encode($refers); $typesetInfo['refers'] = json_encode($rs); $url = $this->ts_base_url . "api/typeset/webGetDocx"; // $url = "http://localhost:8081/typeset/webGetDocx"; $res = object_to_array(json_decode(myPost1($url, $typesetInfo))); if (!isset($res['data']['file']) || $res['data']['file'] == '') { return jsonError('create error'); } $file_res = date('Ymd') . DS . $res['data']['file']; $tf_insert['p_article_id'] = $p_info['p_article_id']; $tf_insert['url'] = $file_res; $tf_insert['ctime'] = time(); $this->production_article_frag_obj->insert($tf_insert); return jsonSuccess([]); } public function getTopicsByIssn() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("p_article_id", $data['p_article_id'])->find(); $journal_info = $this->journal_obj->where("journal_id", $p_info['journal_id'])->find(); $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Article/getTopicByIssn'; $pra = []; $pra['issn'] = $journal_info['issn']; $res = object_to_array(json_decode(myPost($url, $pra))); $re['now'] = $p_info['topics'] == "" ? [] : json_decode($p_info['topics']); $re['list'] = $res['data']['list']; return jsonSuccess($re); } public function getProductRelatedList() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("p_article_id", $data['p_article_id'])->find(); if ($p_info['related'] == "") { return jsonSuccess(['list' => null]); } $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Article/getArticlesForSubmission'; $pra = []; $pra['ids'] = $p_info['related']; $res = object_to_array(json_decode(myPost($url, $pra))); $re['list'] = $res['data']['list']; return jsonSuccess($re); } public function addProductRelated() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require", "article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("p_article_id", $data['p_article_id'])->find(); if ($p_info['related'] == "") { $list[] = $data['article_id']; } else { if (array_search($data['article_id'], json_decode($p_info['related'])) !== false) { return jsonSuccess([]); } $list = json_decode($p_info['related']); $list[] = $data['article_id']; sort($list); } $l = self::repalecArray($list); $this->production_article_obj->where("p_article_id", $data['p_article_id'])->update(['related' => count($l) > 0 ? json_encode($l) : '']); return jsonSuccess($list); } private function repalecArray($list) { $frag = []; foreach ($list as $v) { $frag[] = $v; } return $frag; } public function delProductRelated() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require", "article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("p_article_id", $data['p_article_id'])->find(); $list = json_decode($p_info['related']); $key = array_search($data['article_id'], $list); if ($key !== false) { unset($list[$key]); } $this->production_article_obj->where("p_article_id", $data['p_article_id'])->update(['related' => json_encode(self::repalecArray($list))]); return jsonSuccess(['list' => $list]); } // public function editProductTopics(){ // $data = $this->request->post(); // $rule = new Validate([ // "p_article_id"=>"require", // "list"=>"require" // ]); // if(!$rule->check($data)){ // return jsonError($rule->getError()); // } // $this->production_article_obj->where("p_article_id",$data['p_article_id'])->update(['topics'=>json_encode($data['list'])]); // return jsonSuccess([]); // } public function addProductTopic() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require", "journal_topic_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("p_article_id", $data['p_article_id'])->find(); if ($p_info['topics'] == "") { $list[] = $data['journal_topic_id']; } else { if (array_search($data['journal_topic_id'], json_decode($p_info['topics'])) !== false) { return jsonSuccess([]); } $list = json_decode($p_info['topics']); $list[] = $data['journal_topic_id']; sort($list); } $this->production_article_obj->where("p_article_id", $data['p_article_id'])->update(['topics' => json_encode(self::repalecArray($list))]); return jsonSuccess(['list' => $list]); } public function delProductTopic() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require", "journal_topic_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("p_article_id", $data['p_article_id'])->find(); $list = json_decode($p_info['topics']); $key = array_search($data['journal_topic_id'], $list); if ($key !== false) { unset($list[$key]); } $l = self::repalecArray($list); $this->production_article_obj->where("p_article_id", $data['p_article_id'])->update(['topics' => count($l) > 0 ? json_encode($l) : '']); return jsonSuccess(['list' => $list]); } public function editProductRelated() { $data = $this->request->post(); $rule = new Validate([ "p_article_id" => "require", "list" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $this->production_article_obj->where("p_article_id", $data['p_article_id'])->update(['related' => json_encode($data['list'])]); return jsonSuccess([]); } private function abstractChange($str) { $html = preg_replace('/(.*?)<\/strong>/', '{b}$2{/b}', $str); $html = strip_tags($html); $html = str_replace("{b}", "", $html); $html = str_replace("{/b}", "", $html); return $html; } public function doTypeSettingNew() { $data = $this->request->post(); $rule = new Validate([ "article_id" => "require" ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where("article_id", $data['article_id'])->whereIn("state", [0, 2])->find(); if (!$p_info) { return jsonError("error"); } $article_info = $this->article_obj->where('article_id', $p_info['article_id'])->find(); $journal_info = $this->journal_obj->where('journal_id', $p_info['journal_id'])->find(); $editor_info = $this->user_obj->where('user_id', $journal_info['editor_id'])->find(); $typesetInfo = []; $typesetInfo['info_title'] = $p_info['title']; $typesetInfo['info_type'] = $p_info['type']; $typesetInfo['doi'] = $p_info['doi']; $typesetInfo['topic'] = ''; // $typesetInfo['mainText'] = $p_info['main']; $au_res = $this->authorFormate($p_info['p_article_id']); $typesetInfo['author'] = $au_res['author']; $typesetInfo['authorAddress'] = $au_res['address']; $typesetInfo['authorAddressList'] = $au_res['addressList1']; $typesetInfo['authorContribution'] = $p_info['author_contribution']; //查询通讯作者 $corr_authors = $this->production_article_author_obj->where('p_article_id', $p_info['p_article_id'])->where('is_report', 1)->where('state', 0)->select(); $corrauthor = ''; $corremail = ''; foreach ($corr_authors as $v) { $corrauthor .= trim($v['first_name']) . ' ' . trim($v['last_name']) . '. '; $corremail .= $v['email'] . '. '; } $typesetInfo['authorCorresponding'] = substr(trim($corrauthor), 0, -1); $typesetInfo['authorCorrespondingEmail'] = substr(trim($corremail), 0, -1); $typesetInfo['traditon'] = $p_info['tradition']; $typesetInfo['journal'] = $journal_info['title']; $typesetInfo['jabbr'] = $journal_info['jabbr']; //查询分期 $url = 'http://journalapi.tmrjournals.com/public/index.php/master/Journal/getStageDetail'; $cs['journal_stage_id'] = $p_info['journal_stage_id']; $list = object_to_array(json_decode(myPost($url, $cs))); $stage_re = $list['data']['stage']; $typesetInfo['stage'] = $stage_re['stage_year'] . ';' . $stage_re['stage_vol'] . '(' . $stage_re['stage_no'] . '):' . $p_info['npp']; //2022;6(1):17 $typesetInfo['little_author'] = $p_info['abbr']; $typesetInfo['website'] = $journal_info['website']; $typesetInfo['acknowledgment'] = $p_info['acknowledgment']; // $received_info = $this->article_msg_obj->where("article_id",$p_info['article_id'])->where("state_from",4)->where("state_to",1)->find(); $received_data = $article_info['received_time'] > 0 ? $article_info['received_time'] : $article_info['ctime']; $typesetInfo['received_date'] = date("d F Y", $received_data); $super_num = $this->article_author_obj->where("article_id", $p_info['article_id'])->where("state", 0)->where("is_super", 1)->count(); $typesetInfo['has_more'] = $super_num > 1; $typesetInfo['accepted_date'] = date("d F Y", $article_info['rtime']); $typesetInfo['online_date'] = $p_info['pub_date']; //这里可能会有问题 $typesetInfo['abbreviation'] = $p_info['abbreviation']; $typesetInfo['abstractText'] = $this->abstractChange($p_info['abstract']); $typesetInfo['keywords'] = $p_info['keywords']; $typesetInfo['userAccount'] = $editor_info['nickname']; $files = $this->article_file_obj ->where('article_id', $article_info['article_id']) ->where('type_name', 'manuscirpt') ->order('ctime desc') ->limit(1) ->select(); if (count($files) == 0) { return jsonError('No Manuscript'); } $typesetInfo['filename'] = "http://api.tmrjournals.com/public/" . $files[0]['file_url']; $rs = $this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where('state', 0)->order("index")->select(); $typesetInfo['refers'] = json_encode($rs); $main_list = $this->article_main_obj->where("article_id", $data['article_id'])->whereIn("state", [0, 2])->order("sort")->select(); $start = 0; foreach ($main_list as $k => $v) { $cas = strip_tags($v['content']); if (strtolower(substr($cas, 0, 8)) === "keywords") { $start = $k; break; } } $mainList = []; $images = []; $tables = []; $nbsp = false; foreach ($main_list as $k => $item) { if ($start >= $k) { continue; } $main_string = ""; if ($item['type'] == 1) { continue; $info = $this->article_main_image_obj->where("ami_id", $item['ami_id'])->find(); $arr['image'] = $info['url']; $arr['title'] = "" . $info['title'] . ""; $arr['note'] = $info['note']; $images[$info['ami_id']] = $arr; $main_string = ""; } else if ($item['type'] == 2) { continue; $info = $this->article_main_table_obj->where("amt_id", $item['amt_id'])->find(); $arr_table['title'] = "" . strip_tags($info['title']) . ""; $arr_table['table_data'] = $info['table_data']; $arr_table['note'] = $info['note']; $tables[$info['amt_id']] = $arr_table; $main_string = ""; } else { if ($item['is_h1'] == 1) { // $main_string = "".$item['content'].""; $main_string = "" . strip_tags($item['content']) . ""; $nbsp = true; } else if ($item['is_h2'] == 1 || $item['is_h3'] == 1) { $main_string = "" . $item['content'] . ""; $nbsp = false; } else { $main_string = $nbsp ? "" . $item['content'] : $item['content']; $nbsp = false; } } $mainList[] = $main_string; } $typesetInfo['mainText'] = json_encode($mainList); // $typesetInfo['images'] = $images==[]?null:$images; // $typesetInfo['tables'] = $tables==[]?null:$tables; $as = $this->user_obj->field("t_user.*,t_article_reviewer_question.is_anonymous") ->join("t_article_reviewer", "t_article_reviewer.reviewer_id=t_user.user_id", "left") ->join("t_article_reviewer_question", "t_article_reviewer_question.art_rev_id=t_article_reviewer.art_rev_id", "left") ->where("t_article_reviewer.article_id", $article_info['article_id']) ->whereIn("t_article_reviewer.state", [1, 2, 3]) ->select(); $as_str = ""; $has_yc = false; foreach ($as as $v) { if ($v['is_anonymous'] == 1) { $has_yc = true; } else { $as_str .= $v["realname"] . ", "; } } $aca = trim(trim($as_str), ","); // return jsonSuccess(["ddd"=>$has_yc?$aca." and other anonymous reviewers":$aca]); if ($as_str == "") { $author_str = "all anonymous reviewers"; } else { $author_str = $has_yc ? $aca . " and other anonymous reviewers" : $aca; } $typesetInfo['author_str'] = $author_str; $typesetInfo['images'] = null; $typesetInfo['tables'] = null; $url = $this->ts_base_url . "api/typeset/createDocx"; // $url = "http://192.168.110.110:8081/typeset/createDocx"; // $url = "http://192.168.110.110:8081/typeset/testqt"; $res = object_to_array(json_decode(myPost1($url, $typesetInfo))); if (!isset($res['data']['file']) || $res['data']['file'] == '') { return jsonError('create error'); } $file_res = date('Ymd') . DS . $res['data']['file']; $tf_insert['p_article_id'] = $p_info['p_article_id']; $tf_insert['url'] = $file_res; $tf_insert['ctime'] = time(); $this->production_article_frag_obj->insert($tf_insert); return jsonSuccess($res); } public function readTest() { $url = "http://192.168.110.110:8081/typeset/readdoc"; $typesetInfo['filename'] = "11.docx"; $res = object_to_array(json_decode(myPost($url, $typesetInfo))); return jsonSuccess($res); } /** * 获取生产实例详情 */ public function getProductionDetail() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); proofState($p_info['article_id']); $list = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); foreach ($list as $k => $v) { $list[$k]['organs'] = $this->production_article_author_to_organ_obj ->field("t_production_article_organ.*") ->join("t_production_article_organ", 't_production_article_organ.p_article_organ_id = t_production_article_author_to_organ.p_article_organ_id', 'left') ->where('t_production_article_author_to_organ.p_article_author_id', $v['p_article_author_id']) ->where('t_production_article_author_to_organ.state', 0) ->select(); } $re['production'] = $p_info; $re['author'] = $list; return jsonSuccess($re); } public function getProductionPreview() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $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(); $journal_info = $this->journal_obj->where('journal_id', $article_info['journal_id'])->find(); // $list = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); $re['production'] = $p_info; $re['author'] = $this->authorFormate($data['p_article_id']); $re['journal'] = $journal_info; return jsonSuccess($re); } /** * 获取生产实例详情通过文章id */ public function getProductionDetailByArticleid() { $data = $this->request->post(); $rule = new Validate([ 'article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('article_id', $data['article_id'])->where('state', 0)->find(); $article_info = $this->article_obj->where('article_id', $p_info['article_id'])->find(); $journal_info = $this->journal_obj->where('journal_id', $article_info['journal_id'])->find(); $re['production'] = $p_info; $re['article'] = $article_info; $re['journal'] = $journal_info; return jsonSuccess($re); } /** * 添加作者机构 */ public function addAuthorOrgan() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number', 'organ_name' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); $insert['p_article_id'] = $data['p_article_id']; $insert['article_id'] = $p_info['article_id']; $insert['organ_name'] = trim($data['organ_name']); $this->production_article_organ_obj->insert($insert); return jsonSuccess([]); } /** * 删除作者机构 */ public function delAuthorOrgan() { $data = $this->request->post(); $rule = new Validate([ 'p_article_organ_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $this->production_article_organ_obj->where('p_article_organ_id', $data['p_article_organ_id'])->update(['state' => 1]); $this->production_article_author_to_organ_obj->where('p_article_organ_id', $data['p_article_organ_id'])->update(['state' => 1]); return jsonSuccess([]); } /** * 编辑作者信息 */ public function editAuthor() { $data = $this->request->post(); $rule = new Validate([ 'p_article_author_id' => 'require', 'first_name' => 'require', 'last_name' => 'require', 'author_country' => 'require', 'is_first' => 'require', 'is_report' => 'require', 'organs' => 'require' ]); if (!$rule->check($data)) { 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']); $updata['last_name'] = trim($data['last_name']); $updata['orcid'] = isset($data['orcid']) ? $data['orcid'] : ''; $updata['author_country'] = $data['author_country']; $updata['is_first'] = $data['is_first']; $updata['is_report'] = $data['is_report']; $updata['email'] = isset($data['email']) ? trim($data['email']) : ''; $this->production_article_author_obj->where('p_article_author_id', $data['p_article_author_id'])->update($updata); if (is_array($data['organs'])) { $has_ids = []; foreach ($data['organs'] as $v) { $cache_one = $this->production_article_author_to_organ_obj ->where('p_article_author_id', $data['p_article_author_id']) ->where('p_article_organ_id', $v) ->where('state', 0) ->find(); if ($cache_one == null) { $insert['p_article_id'] = $old_article_author_info['p_article_id']; $insert['p_article_author_id'] = $data['p_article_author_id']; $insert['p_article_organ_id'] = $v; $this->production_article_author_to_organ_obj->insert($insert); } $has_ids[] = intval($v); } $this->production_article_author_to_organ_obj->where('p_article_author_id', $data['p_article_author_id'])->where('state', 0)->where('p_article_organ_id', 'not in', $has_ids)->update(['state' => 1]); } else { $this->production_article_author_to_organ_obj->where('p_article_author_id', $data['p_article_author_id'])->where('state', 0)->update(['state' => 1]); } return jsonSuccess([]); } /** * 编辑作者机构信息 */ public function editAuthorOrgan() { $data = $this->request->post(); $rule = new Validate([ 'p_article_organ_id' => 'require|number', 'organ_name' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $this->production_article_organ_obj->where('p_article_organ_id', $data['p_article_organ_id'])->update(['organ_name' => $data['organ_name']]); return jsonSuccess([]); } /** * 获取机构列表 */ public function getOrganList() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $list = $this->production_article_organ_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); $re['organs'] = $list; return jsonSuccess($re); } /** * 添加作者 */ public function addAuthor() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number', 'first_name' => 'require', 'last_name' => 'require', 'author_country' => 'require', 'is_first' => 'require', 'is_report' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $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']); $insert['first_name'] = trim($data['first_name']); $insert['last_name'] = trim($data['last_name']); $insert['orcid'] = isset($data['orcid']) ? $data['orcid'] : ''; $insert['author_country'] = $data['author_country']; $insert['is_first'] = $data['is_first']; $insert['is_report'] = $data['is_report']; $insert['email'] = isset($data['email']) ? trim($data['email']) : ''; Db::startTrans(); $pa_id = $this->production_article_author_obj->insertGetId($insert); $or_res = true; if (isset($data['organs']) && is_array($data['organs'])) { foreach ($data['organs'] as $v) { $cache_ins['p_article_id'] = $data['p_article_id']; $cache_ins['p_article_author_id'] = $pa_id; $cache_ins['p_article_organ_id'] = $v; $or_res = $this->production_article_author_to_organ_obj->insert($cache_ins) ? true : false; } } if ($pa_id && $or_res) { Db::commit(); return jsonSuccess([]); } else { Db::rollback(); return jsonError("system error"); } } /** * gpt校对main内容 */ // public function freshMain() // { // $data = $this->request->post(); // $rule = new Validate([ // 'p_article_id' => 'require' // ]); // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // $list = $this->production_article_main_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); // foreach ($list as $v) { // if ($v['content'] == '' || strlen($v['content']) < 60) { // $this->production_article_main_obj->where('p_main_id', $v['p_main_id'])->update(['content_g' => $v['content']]); // } else { // Queue::push('app\api\job\gpt@fresh', $v, 'gpt'); // } // } // // return jsonSuccess([]); // } /** * 更新引用条目 */ public function freshRefers() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require', 'refers' => 'require|array' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); //清空之前的引用条目 $this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->update(['state' => 1]); foreach ($data['refers'] as $k => $v) { $cache_insert['p_article_id'] = $p_info['p_article_id']; $cache_insert['refer_content'] = $v; $cache_insert['index'] = $k; $cache_insert['ctime'] = time(); $this->production_article_refer_obj->insert($cache_insert); } $this->referToDoi($data['p_article_id']); $this->doiTofrag($data['p_article_id']); return jsonSuccess([]); } /** * 合并到上个文献中 */ public function referHB() { $data = $this->request->post(); $rule = new Validate([ 'p_refer_id' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $refer_info = $this->production_article_refer_obj->where('p_refer_id', $data['p_refer_id'])->find(); $refer_rev_res = $this->production_article_refer_obj ->where('p_article_id', $refer_info['p_article_id']) ->where('state', 0) ->where('p_refer_id', '<', $refer_info['p_refer_id']) ->order('p_refer_id desc') ->limit(1)->select(); $refer_rev_info = $refer_rev_res[0]; $updata['refer_frag'] = $refer_rev_info['refer_frag'] . $refer_info['refer_frag']; $updata['cs'] = 0; $this->production_article_refer_obj->where('p_refer_id', $refer_rev_info['p_refer_id'])->update($updata); $this->production_article_refer_obj->where('p_refer_id', $refer_info['p_refer_id'])->update(['state' => 1]); return jsonSuccess([]); } /** * 参考文献识别doi */ public function referToDoi($p_article_id) { $p_info = $this->production_article_obj->where('p_article_id', $p_article_id)->find(); $refers = $this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where('state', 0)->select(); foreach ($refers as $v) { //处理doi if (strripos($v['refer_content'], 'doi:') == false && strripos($v['refer_content'], 'doi.org/') == false) { continue; } $doi = ''; if (strripos($v['refer_content'], 'doi.org/') != false) { $cache_arr = explode(' ', trim(substr($v['refer_content'], strripos($v['refer_content'], 'doi.org/') + 8))); if (substr($cache_arr[0], -1) == '.') { $doi = substr($cache_arr[0], 0, -1); } else { $doi = $cache_arr[0]; } } else { $cache_arr = explode(' ', trim(substr($v['refer_content'], strripos($v['refer_content'], 'doi:') + 4))); if (substr($cache_arr[0], -1) == '.') { $doi = substr($cache_arr[0], 0, -1); } else { $doi = $cache_arr[0]; } } $this->production_article_refer_obj->where('p_refer_id', $v['p_refer_id'])->update(['refer_doi' => $doi]); } return jsonSuccess([]); } public function doiTofrag($p_article_id) { $p_info = $this->production_article_obj->where('p_article_id', $p_article_id)->find(); $refers = $this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where('state', 0)->select(); foreach ($refers as $v) { if ($v['refer_doi'] == '') { $this->production_article_refer_obj->where('p_refer_id', $v['p_refer_id'])->update(['refer_frag' => $v['refer_content']]); } else { //修改队列兼容对接OPENAI接口 chengxiaoling 20251128 start // Queue::push('app\api\job\ts@fire1', $v, 'ts'); Queue::push('app\api\job\ArticleReferDetailQueue@fire', $v, 'ArticleReferDetailQueue'); //修改队列兼容对接OPENAI接口 chengxiaoling 20251128 end } } return jsonSuccess([]); } /** * 验证参考文献是否全部通过 */ public function checkRefer() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $list = $this->production_article_refer_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); if (!$list) { return jsonError('references error'); } $frag = 1; foreach ($list as $v) { if ($v['cs'] == 0) { $frag = 0; break; } } if ($frag == 0) { return jsonError('references check error'); } else { return jsonSuccess([]); } } /** * 生成 BibTeX 内容 * @param array $references 参考文献数据 * @param int $p_article_id 文章ID * @return string BibTeX 内容 */ private function generateBibContent($p_article_id, $references) { $content = "% BibTeX file generated for article ID: {$p_article_id}\n"; $content .= "% Generated on " . date('Y-m-d H:i:s') . "\n\n"; foreach ($references as $ref) { $entry = $this->generateBibEntry($ref); if ($entry) { $content .= $entry . "\n\n"; } } return $content; } public function creatLatex(){ $data = $this->request->post(); $rule = new Validate([ "article_id"=>"require" ]); if(!$rule->check($data)){ return jsonError($rule->getError()); } //查询基础信息 $article_production_info = $this->production_article_obj->where("article_id",$data['article_id'])->find(); $references = $this->production_article_refer_obj ->where('p_article_id', $article_production_info['p_article_id']) ->where('state', 0) ->order('index ASC') ->select(); if($article_production_info==null){ return jsonError("No production information found"); } //创建基础目录,加载必要文件 $outputPath = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $data['article_id']; if (!$outputPath) { mkdir($outputPath, 0755, true); } //生成tex文件 //处理头部信息 //处理正文内容信息 $article_main_list = $this->article_main_obj->where("article_id",$data['article_id'])->where("state",0)->order("sort asc")->select(); $fragContentList = []; foreach ($article_main_list as $article_main_info){ if($article_main_info['type']==0){//普通内容 //替换其他标签 $updatedContent = $this->convertToLatex($article_main_info['content'],$references); //做内容替换 $article_main_info['content'] = $updatedContent; $fragContentList[] = $article_main_info; }elseif ($article_main_info['type']==1){//处理图片 $fragContentList[] = $this->figerConvertLatex($article_main_info['ami_id']); }else{//处理表格 $fragContentList[] = $this->tableCovertLatex($article_main_info['amt_id'],$references); } } //实际生成tex $tex_file = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $data['article_id'] . DS . 'article_' . $data['article_id'] . '.tex'; $tex_content_last = ""; foreach ($fragContentList as $val){ $tex_content_last .= $val."/n"; } file_put_contents($tex_file, $tex_content_last); //生成bib文件 $file = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $data['article_id'] . DS . 'references_' . $data['article_id'] . '.bib'; $bibContent = $this->generateBibContent($article_production_info['p_article_id'],$references); file_put_contents($file, $bibContent); // //生成pdf文件 // $pdfFile = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $data['article_id'] . DS . 'article_' . $data['article_id'] . '.pdf'; // $command = "cd {$outputPath} && pdflatex -interaction=nonstopmode article_" . $data['article_id'] . ".tex"; // exec($command, $output, $returnCode); // if ($returnCode !== 0) { // return jsonError("Failed to generate PDF"); // } //存储pdf文件 return jsonSuccess(['file'=>$tex_file]); } // public function figerConvertLatex($ami_id){ // $ami_info = $this->article_main_image_obj->where("ami_id",$ami_id)->find(); // explode("/",$ami_info['url']); // //拷贝图片到目标目录 // $filePath = ROOT_PATH . 'public' . DS . 'uploads' . DS . 'articleImage' . DS . $ami_info['url'] ; // $nowFile = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_'.$ami_info['article_id'] . DS . $ami_info['article_id'] . DS . $ami_info['file_name']; // // // // } public function myFigerTest(){ echo $this->figerConvertLatex(4172); } public function figerConvertLatex($ami_id){ $ami_info = $this->article_main_image_obj->where("ami_id",$ami_id)->find(); $urlParts = explode("/",$ami_info['url']); $fileName = $urlParts[count($urlParts) - 1]; // 创建目标目录 $targetDir = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $ami_info['article_id']; if (!file_exists($targetDir)) { mkdir($targetDir, 0755, true); } // 拷贝图片到目标目录 $filePath = ROOT_PATH . 'public' . DS . 'articleImage' . DS . $ami_info['url']; $targetFilePath = $targetDir . DS . $fileName; if (file_exists($filePath)) { copy($filePath, $targetFilePath); } // 检测图片尺寸 $imageInfo = getimagesize($targetFilePath); $imageWidth = $imageInfo[0]; // 图片宽度 $imageHeight = $imageInfo[1]; // 图片高度 // 定义宽度阈值(例如:宽度大于600像素则使用两栏) $wideImageThreshold = 600; $isWideImage = $imageWidth > $wideImageThreshold; // 生成LaTeX图片代码 if ($isWideImage) { $latexLines[] = "\\begin{figure*}[htbp!]"; // 使用figure*环境实现两栏 $latexLines[] = " \\centering"; $latexLines[] = " \\includegraphics[width=0.9\\textwidth]{" . $fileName . "}"; // 使用全宽度 } else { $latexLines[] = "\\begin{figure}[H]"; $latexLines[] = " \\centering"; $latexLines[] = " \\includegraphics[width=0.9\\textwidth]{" . $fileName . "}"; } //添加图片的label $latexLines[] = " \\label{fig:" . $ami_id . "}"; if(!empty($ami_info['title'])&&!empty($ami_info['note'])){ $escapedTitle = '{\fontspec{Calibri}\footnotesize\bfseries\color{figerTitleColor} '.$this->convertToLatex(preg_replace('/^Figure\s+\d+\s*/i', '', $ami_info['title']),[]).'}\\\\'; $escapedTitle .= '{\vspace{0.5em}\raggedright\small {'.$this->convertToLatex($ami_info['note'],[]).'}}'; $latexLines[] = " \\caption{" . $escapedTitle . "}"; } if (!empty($ami_info['title'])) { $escapedTitle = $this->convertToLatex(preg_replace('/^Figure\s+\d+\s*/i', '', $ami_info['title']),[]); $latexLines[] = " \\caption{" . $escapedTitle . "}"; } // // if (!empty($ami_info['note'])) { // $escapedNote = $this->escapeLatexSpecialChars(strip_tags($ami_info['note'])); // $latexLines[] = " \\label{fig:" . $ami_info['ami_id'] . "}"; // $latexLines[] = " \\footnotesize{" . $escapedNote . "}"; // } $latexLines[] = "\\end{figure" . ($isWideImage ? "*" : "") . "}"; return implode("\n", $latexLines); } public function figerConvertLatex11($ami_id){ $ami_info = $this->article_main_image_obj->where("ami_id",$ami_id)->find(); $urlParts = explode("/",$ami_info['url']); $fileName = $urlParts[count($urlParts) - 1]; // 创建目标目录 $targetDir = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $ami_info['article_id'] ; if (!file_exists($targetDir)) { mkdir($targetDir, 0755, true); } // 拷贝图片到目标目录 $filePath = ROOT_PATH . 'public' . DS . 'uploads' . DS . 'articleImage' . DS . $ami_info['url']; $targetFilePath = $targetDir . DS . $fileName; if (file_exists($filePath)) { copy($filePath, $targetFilePath); } // 生成LaTeX图片代码 $latexCode[] = "\\begin{figure}[H]"; $latexCode[] = " \\centering"; $latexCode[]= " \\includegraphics[width=0.8\\textwidth]{" . $fileName . "}"; if (!empty($ami_info['title'])) { $escapedTitle = $this->escapeLatexSpecialChars($ami_info['title']); $latexCode[] = " \\caption{" . $escapedTitle . "}"; } if (!empty($ami_info['note'])) { $escapedNote = $this->escapeLatexSpecialChars($ami_info['note']); $latexCode[] = " \\label{fig:" . $ami_info['ami_id'] . "}"; $latexCode[] = " \\footnotesize{" . $escapedNote . "}"; } $latexCode[] = "\\end{figure}"; return implode("\n", $latexCode); } public function mytestconver(){ $data = $this->request->post(); $rule = new Validate([ "id"=>"require" ]); if(!$rule->check($data)){ return jsonError($rule->getError()); } $info = $this->article_main_obj->where("am_id",$data['id'])->find(); if(isset($data["code"])){ $content = $data['code']; }else{ $content = $info['content']; } $production_info = $this->production_article_obj->where("article_id",$info['article_id'])->find(); $refers = $this->production_article_refer_obj->where("p_article_id",$production_info['p_article_id'])->where('state',0)->order("index")->select(); $res = $this->convertToLatex($content,$refers); echo $res; // return jsonSuccess([$res]); } public function convertToLatex($content,$references,$check_refer = true) { // 空内容直接返回 if (empty(trim($content))) { return ''; } //单行处理公式内容 $pattern = '/^]*?\s+data-latex="([^"]*)"[^>]*?>.*?<\/wmath>$/'; if(preg_match($pattern, $content) === 1){ $pattern1 = '/]*?\s+data-latex="([^"]*)">/'; if (preg_match($pattern1, $content, $matches)) { $latexContent = $matches[1]; // 将 $$ 转换为 $,因为equation环境不需要$$ $latexContent = str_replace('$$', '', $latexContent); return "\\begin{equation}\n\t{$latexContent}\n\\end{equation}"; } return $content; } $refArray = []; foreach ($references as $ref) { $refArray[$ref['index'] + 1] = $ref; } $content = str_replace("–","-",$content); // 步骤1:忽略并移除、和标签 $content = $this->removeIgnoredTags($content); // 步骤2:解析剩余标签并生成LaTeX内容 $latexContent = $this->textRenderCreate($content,$refArray,$check_refer); // $latexContent = $this->convertReferencesToLatex($content, $refArray); return $latexContent; } /** * 移除需要忽略的标签:、、 * @param string $content 原始内容 * @return string 处理后的内容 */ private function removeIgnoredTags($content) { $content = html_entity_decode($content, ENT_QUOTES, 'UTF-8'); // 移除和(不区分大小写,处理可能的空格) $content = preg_replace('/<\/?tr\s*>/i', '', $content); // 移除 $content = str_replace('', '', $content); return $content; } /** * 对应Java的textRenderCreate方法,解析文本和标签 * @param string $content 待解析的内容 * @return string 解析后的LaTeX内容 */ private function textRenderCreate($content,$references,$check_refer) { $latex = ''; while (!empty($content)) { $nextTag = $this->determineNextTag($content); if ($nextTag === 'no') { // 无标签,转义特殊字符后直接拼接 $latex .= $this->escapeLatexSpecialChars($content); $content = ''; }else { $tagOpen = "<{$nextTag}>"; $tagClose = ""; $beginTag = strpos($content, $tagOpen); // 标签前的文本 if ($beginTag > 0) { $latex .= $this->escapeLatexSpecialChars(substr($content, 0, $beginTag)); } // 找到标签的最后闭合位置(处理嵌套) $endTag = $this->getLastTabIndex($content, $nextTag); if ($endTag === false) { // 无闭合标签,保留原内容(异常情况处理) $latex .= $this->escapeLatexSpecialChars(substr($content, $beginTag)); $content = ''; continue; } // 截取标签包裹的内容(包含标签) $tagWrappedContent = substr( $content, $beginTag, $endTag - $beginTag + strlen($tagClose) ); //这里处理引用 if ($check_refer&&preg_match('/(?:)?\[(\d+(?:[-,]\d+)*)\](?:<\/blue>)?/', $tagWrappedContent, $matches)) { // 去除匹配中的 $cleanedMatch = str_replace(['', ''], '', $matches[0]); // 提取引用编号部分(去掉方括号) $referencePart = trim($cleanedMatch, '[]'); // 分割逗号分隔的不同引用项 $parts = explode(',', $referencePart); $latexRefs = []; foreach ($parts as $part) { // 判断是否是范围形式如 3-5 if (strpos($part, '-') !== false) { list($start, $end) = explode('-', $part); $start = intval($start); $end = intval($end); // 展开范围并逐个查找 ref_id for ($i = $start; $i <= $end; $i++) { $arrayIndex = $i; if (isset($references[$arrayIndex]) && !empty($references[$arrayIndex]['p_refer_id'])) { $latexRefs[] = 'ref_' . $references[$arrayIndex]['p_refer_id']; } else { $latexRefs[] = $i; } } } else { // 单个引用编号处理 $index = intval($part); $arrayIndex = $index; if (isset($references[$arrayIndex]) && !empty($references[$arrayIndex]['p_refer_id'])) { $latexRefs[] = 'ref_' . $references[$arrayIndex]['p_refer_id']; } else { $latexRefs[] = $index; } } } $latex .= '\parencite{' . implode(',', $latexRefs) . '}'; }else{ // 解析标签内容并应用样式 $style = []; $tagContentList = []; $this->getTextRenderData($tagWrappedContent, $nextTag, $style, $tagContentList); // 拼接解析后的标签内容 $latex .= implode('', $tagContentList); } // 剩余内容 $content = substr($content, $endTag + strlen($tagClose)); } } return $latex; } /** * 对应Java的getLastTabIndex方法,找到标签的最后闭合位置(处理嵌套) * @param string $content 内容 * @param string $tag 标签名 * @return int|false 闭合标签的起始位置 */ private function getLastTabIndex($content, $tag) { $tagOpen = "<{$tag}>"; $tagClose = ""; $beginTag = strpos($content, $tagOpen); if ($beginTag === false) { return false; } // 先找第一个闭合标签 $endTagCa = strpos($content, $tagClose, $beginTag); if ($endTagCa === false) { return false; } // 统计当前标签内的开放标签数量 $caNowStr = substr($content, $beginTag, $endTagCa - $beginTag + strlen($tagClose)); $caCount = preg_match_all("/<{$tag}>/", $caNowStr, $matches); if ($caCount === 1) { return $endTagCa; } else { // 递归查找匹配的闭合标签数量 $reallyNum = 0; while ($reallyNum !== $caCount) { $numIndex = $this->getNumIndex($content, $tag, $caCount); if ($numIndex === false) { break; } $substring = substr($content, $beginTag, $numIndex - $beginTag + strlen($tagClose)); $ccaCount = preg_match_all("/<{$tag}>/", $substring, $matches); if ($ccaCount !== $caCount) { $caCount = $ccaCount; } else { $reallyNum = $ccaCount; } } return $this->getNumIndex($content, $tag, $reallyNum); } } /** * 对应Java的getNumIndex方法,找到第num个闭合标签的位置 * @param string $content 内容 * @param string $tag 标签名 * @param int $num 第几个闭合标签 * @return int|false 标签位置 */ private function getNumIndex($content, $tag, $num) { $tagClose = ""; $count = 0; $index = -1; while (($index = strpos($content, $tagClose, $index + 1)) !== false) { $count++; if ($count === $num) { return $index; } } return false; } /** * 对应Java的getTextRenderData方法,递归解析标签内容并应用样式 * @param string $now 标签包裹的内容(如xxx) * @param string $tag 标签名 * @param array $style 样式数组(引用传递,深拷贝处理嵌套) * @param array $textRenderData 输出的LaTeX内容列表 */ private function getTextRenderData($now, $tag, &$style, &$textRenderData) { if($tag === 'wmath'){ $pattern = '/data-latex="(.*?)"/'; if (preg_match($pattern,$now, $matches1)) { $latexContent = $matches1[1]; // 将 $$ 转换为 $ $latexContent = str_replace('$$', '$', $latexContent); $styledContent = $this->applyStyleToContent($latexContent, $style); $textRenderData[] = $styledContent; } }elseif ($tag === 'myfigure'){//对图片的正文处理 $pattern = '/data-id=["\'](\d+)["\']/'; if (preg_match($pattern, $now, $matches)) { $figureId = $matches[1]; //处理查找到id之后的逻辑 $textRenderData[] = "\\ref{fig:".$figureId."}"; } }elseif ($tag === 'mytable'){//对表格的正文处理 $pattern = '/data-id=["\'](\d+)["\']/'; if (preg_match($pattern, $now, $matches)) { $tableId = $matches[1]; $cache_table = $this->article_main_table_obj->where("amt_id",$tableId)->find(); if(!$cache_table){ return ; } $cache_list = $this->article_main_obj ->join("t_article_main_table","t_article_main_table.amt_id=t_article_main.amt_id","left") ->where("t_article_main.article_id",$cache_table['article_id']) ->where("t_article_main.type",2) ->where("CHAR_LENGTH(t_article_main_table.table_data)",">",6000) ->order("t_article_main.sort")->select(); $key_num = 0; foreach ($cache_list as $cache_key =>$cache_list_item){ if($cache_list_item['amt_id']==$tableId){ $key_num = $cache_key+1; } } if(strlen($cache_table['table_data'])>6000){ $textRenderData[] = "\\textcolor[HTML]{".$this->colorMap['blue']."}{Supplementary Table ".$key_num."}}"; }else{ $textRenderData[] = "\\ref{tab:".$tableId."}"; } } }else{ // 应用当前标签的样式 $this->addStyle($style, $tag); // 提取标签内的内容(去掉前后标签) $tagOpen = "<{$tag}>"; $tagClose = ""; $content = substr($now, strlen($tagOpen), strlen($now) - strlen($tagOpen) - strlen($tagClose)); while (!empty($content)) { $nextTag = $this->determineNextTag($content); if ($nextTag === 'no') { // 无子标签,应用样式并添加内容 $styledContent = $this->applyStyleToContent($this->escapeLatexSpecialChars($content), $style); $textRenderData[] = $styledContent; $content = ''; } else { $subTagOpen = "<{$nextTag}>"; $subBeginTag = strpos($content, $subTagOpen); // 子标签前的内容 if ($subBeginTag > 0) { $prefixContent = $this->escapeLatexSpecialChars(substr($content, 0, $subBeginTag)); $styledPrefix = $this->applyStyleToContent($prefixContent, $style); $textRenderData[] = $styledPrefix; } // 找到子标签的最后闭合位置 $subEndTag = $this->getLastTabIndex($content, $nextTag); if ($subEndTag === false) { // 无闭合标签,保留原内容 $textRenderData[] = $this->escapeLatexSpecialChars(substr($content, $subBeginTag)); $content = ''; continue; } // 子标签包裹的内容 $subNow = substr( $content, $subBeginTag, $subEndTag - $subBeginTag + strlen("") ); // 深拷贝样式(避免父级样式被修改) $newStyle = $this->deepCopy($style); // 递归解析子标签 $this->getTextRenderData($subNow, $nextTag, $newStyle, $textRenderData); // 剩余内容 $content = substr($content, $subEndTag + strlen("")); } } } } /** * 对应Java的deepCopy方法,深拷贝样式数组 * @param array $original 原始样式 * @return array 拷贝后的样式 */ private function deepCopy($original) { // 由于样式是简单数组,直接使用数组拷贝即可 return $original; } /** * 对应Java的determineNextTag方法,确定下一个匹配的标签 * @param string $content 待检查的内容 * @return string 标签名或'no' */ private function determineNextTag($content) { $tagPattern = '/<(' . implode('|', $this->supportedTags) . ')>/i'; if (preg_match($tagPattern, $content, $matches)) { return $matches[1]; } return 'no'; } /** * 对应Java的addStyle方法,根据标签设置样式 * @param array $style 样式数组(引用传递) * @param string $tag 标签名 */ private function addStyle(&$style, $tag) { switch ($tag) { case 'sup': $style['vertAlign'] = 'superscript'; break; case 'sub': $style['vertAlign'] = 'subscript'; break; case 'blue': $style['color'] = $this->colorMap['blue']; break; case 'b': $style['bold'] = true; break; case 'i': $style['italic'] = true; break; case 't': $style['color'] = $this->colorMap['t']; break; case 'r': $style['color'] = $this->colorMap['r']; break; // tr标签已被移除,无需处理 } } /** * 将样式应用到内容上,生成对应的LaTeX命令 * @param string $content LaTeX内容 * @param array $style 样式数组 * @return string 应用样式后的LaTeX内容 */ private function applyStyleToContent($content, $style) { if (empty($style)) { return $content; } // 处理加粗 if (isset($style['bold']) && $style['bold']) { $content = "\\textbf{{$content}}"; } // 处理斜体 if (isset($style['italic']) && $style['italic']) { $content = "\\textit{{$content}}"; } // 处理颜色(LaTeX需要xcolor包,支持HTML十六进制颜色) if (isset($style['color'])) { $color = $style['color']; $content = "\\textcolor[HTML]{{$color}}{{$content}}"; } // 处理上标 if (isset($style['vertAlign']) && $style['vertAlign'] === 'superscript') { // LaTeX上标需要考虑嵌套,用{}包裹内容 $content = '$^{{'.$content.'}}$'; } // 处理下标 if (isset($style['vertAlign']) && $style['vertAlign'] === 'subscript') { $content = '$_{{'.$content.'}}$'; } return $content; } /** * 转义LaTeX特殊字符,避免编译错误 * @param string $text 原始文本 * @return string 转义后的文本 */ private function escapeLatexSpecialChars($text) { $specialChars = [ '\\' => '\\textbackslash', '{' => '\\{', '}' => '\\}', '$' => '\\$', '%' => '\\%', '#' => '\\#', '&' => '\\&', '_' => '\\_', '^' => '\\textasciicircum', '~' => '\\textasciitilde', ]; return strtr($text, $specialChars); } /** * 生成单个 BibTeX 条目 * @param array $ref 参考文献数据 * @return string|null BibTeX 条目或 null */ private function generateBibEntry($ref) { // 使用 DOI 或索引作为 citation key $citationKey = 'ref_' . $ref['p_refer_id']; // 如果有解析后的作者和标题信息,优先使用 // if (!empty($ref['author']) && !empty($ref['title'])) { if ($ref['refer_type'] == "journal") { return $this->generateFromParsedData($ref, $citationKey); } elseif ($ref['refer_type'] == "book"){ } else { return $this->generateOtherMsic($ref, $citationKey); } } private function generateOtherBook($ref, $citationKey){ $entry = "@book{{$citationKey},\n"; // 添加基本字段 if (!empty($ref['author'])) { $entry .= " author={" . $this->escapeBibTeX($this->formatBibTeXAuthors($ref['author'])) . "},\n"; } if (!empty($ref['title'])) { $entry .= " title={" . $this->escapeBibTeX($ref['title']) . "},\n"; } if (!empty($ref['publisher'])) { $entry .= " publisher={" . $this->escapeBibTeX($ref['dateno']) . "},\n"; } // 移除最后一个逗号并关闭条目 $entry = rtrim($entry, ",\n") . "\n}"; return $entry; } private function generateOtherMsic($ref, $citationKey){ $entry = "@misc{{$citationKey},\n"; if (!empty($ref['title'])) { $entry .= " title={" . $this->escapeBibTeX($ref['title']) . "},\n"; }else{ $entry .= " title={" . $this->escapeBibTeX($ref['refer_frag']) . "},\n"; } // 移除最后一个逗号并关闭条目 $entry = rtrim($entry, ",\n") . "\n}"; return $entry; } private function parsePublicationInfo($referenceText) { $result = [ 'year' => '', 'volume' => '', 'number' => '', 'pages' => '' ]; // 匹配模式:year;volume(number):pages $pattern = '/(\d{4})\s*;\s*(\d+)(?:\(([^)]+)\))?(?:\s*:\s*([a-zA-Z0-9\u2013\u2014\-]+(?:\s*[\u2013\u2014\-]\s*[a-zA-Z0-9]+)?))?/'; if (preg_match($pattern, $referenceText, $matches)) { $result['year'] = isset($matches[1]) ? $matches[1] : ''; $result['volume'] = isset($matches[2]) ? $matches[2] : ''; // 期号可能是可选的 if (isset($matches[3]) && $matches[3] !== '') { $result['number'] = $matches[3]; } // 页码也是可选的 if (isset($matches[4]) && $matches[4] !== '') { $result['pages'] = $matches[4]; } } else { // 如果标准模式不匹配,尝试更宽松的匹配方式 $result = self::parseLooseFormat($referenceText); } return $result; } private function parseLooseFormat($referenceText) { $result = [ 'year' => '', 'volume' => '', 'number' => '', 'pages' => '' ]; // 提取年份(4位数字) if (preg_match('/\b(\d{4})\b/', $referenceText, $yearMatches)) { $result['year'] = $yearMatches[1]; } // 提取卷号和期号(格式如 54(4) 或 54 (4)) if (preg_match('/(\d+)\s*\(?(\d*)\)?\s*:?\s*([a-zA-Z0-9\-]*)/', $referenceText, $volMatches)) { if (isset($volMatches[1])) { $result['volume'] = $volMatches[1]; } if (isset($volMatches[2]) && $volMatches[2] !== '') { $result['number'] = $volMatches[2]; } if (isset($volMatches[3]) && $volMatches[3] !== '') { $result['pages'] = $volMatches[3]; } } return $result; } /** * 从解析后的数据生成 BibTeX 条目 * @param array $ref 参考文献数据 * @param string $citationKey citation key * @return string BibTeX 条目 */ private function generateFromParsedData($ref, $citationKey) { $entry = "@article{{$citationKey},\n"; // 添加已解析的字段 if (!empty($ref['author'])) { $entry .= " author={" . $this->escapeBibTeX($this->formatBibTeXAuthors($ref['author'])) . "},\n"; } if (!empty($ref['title'])) { $entry .= " title={" . $this->escapeBibTeX($ref['title']) . "},\n"; } if (!empty($ref['joura'])) { $entry .= " journal={" . $this->escapeBibTeX($ref['joura']) . "},\n"; } // 解析并添加出版信息 if (!empty($ref['dateno'])) { $pubInfo = $this->parsePublicationInfo($ref['dateno']); if (!empty($pubInfo['year'])) { $entry .= " year={" . $this->escapeBibTeX($pubInfo['year']) . "},\n"; } if (!empty($pubInfo['volume'])) { $entry .= " volume={" . $this->escapeBibTeX($pubInfo['volume']) . "},\n"; } if (!empty($pubInfo['number'])) { $entry .= " number={" . $this->escapeBibTeX($pubInfo['number']) . "},\n"; } if (!empty($pubInfo['pages'])) { $entry .= " pages={" . $this->escapeBibTeX($pubInfo['pages']) . "},\n"; } } if (!empty($ref['refer_doi'])) { $entry .= " doi={" . $this->escapeBibTeX($ref['refer_doi']) . "},\n"; } // 移除最后一个逗号并关闭条目 $entry = rtrim($entry, ",\n") . "\n}"; return $entry; } /** * 将文章正文中的引用标记转换为LaTeX格式 * @param string $content 文章正文内容 * @param array $references 引用数组,键为索引(int-1),值为引用对象 * @return string 转换后的内容 */ // private function convertReferencesToLatex($content, $references) // { // // 匹配 [1] 或 [1,2] 或 [1,2,3] 等格式 // return preg_replace_callback('/\[(\d+(?:,\d+)*)\]/', function ($matches) use ($references) { // $indices = explode(',', $matches[1]); // $latexRefs = []; // // foreach ($indices as $index) { // // 数据库索引从1开始,数组索引从0开始,所以需要减1 // $arrayIndex = $index - 1; // // if (isset($references[$arrayIndex]) && !empty($references[$arrayIndex]['p_refer_id'])) { // $latexRefs[] = 'ref_' . $references[$arrayIndex]['p_refer_id']; // } else { // // 如果找不到对应引用,保持原来的数字格式 // $latexRefs[] = $index; // } // } // // return '\parencite{' . implode(',', $latexRefs) . '}'; // }, $content); // } private function convertReferencesToLatex($content, $references) { // 匹配 [1], [1,2], [2-4], [1,3-6] 等格式,并处理相邻的 标签 return preg_replace_callback( '/(?:)?\[(\d+(?:[-,]\d+)*)\](?:<\/blue>)?/', function ($matches) use ($references) { // 去除匹配中的 $cleanedMatch = str_replace(['', ''], '', $matches[0]); // 提取引用编号部分(去掉方括号) $referencePart = trim($cleanedMatch, '[]'); // 分割逗号分隔的不同引用项 $parts = explode(',', $referencePart); $latexRefs = []; foreach ($parts as $part) { // 判断是否是范围形式如 3-5 if (strpos($part, '-') !== false) { list($start, $end) = explode('-', $part); $start = intval($start); $end = intval($end); // 展开范围并逐个查找 ref_id for ($i = $start; $i <= $end; $i++) { $arrayIndex = $i; if (isset($references[$arrayIndex]) && !empty($references[$arrayIndex]['p_refer_id'])) { $latexRefs[] = 'ref_' . $references[$arrayIndex]['p_refer_id']; } else { $latexRefs[] = $i; } } } else { // 单个引用编号处理 $index = intval($part); $arrayIndex = $index; if (isset($references[$arrayIndex]) && !empty($references[$arrayIndex]['p_refer_id'])) { $latexRefs[] = 'ref_' . $references[$arrayIndex]['p_refer_id']; } else { $latexRefs[] = $index; } } } return '\parencite{' . implode(',', $latexRefs) . '}'; }, $content ); } /** * 处理文章正文中的引用标记 * @param int $p_article_id 文章ID * @return void */ // public function processArticleReferences() // { // $data = $this->request->post(); // $rule = new Validate([ // 'article_id' => 'require|number' // ]); // // if (!$rule->check($data)) { // return jsonError($rule->getError()); // } // // // 获取文章信息 // $particle = $this->production_article_obj->where('article_id', $data['article_id'])->find(); // if (!$particle) { // return jsonError('文章不存在'); // } // // // 获取该文章的所有引用 // $references = $this->production_article_refer_obj // ->where('p_article_id', $particle['p_article_id']) // ->where('state', 0) // ->order('index ASC') // ->select(); // // // $refArray = []; // foreach ($references as $ref) { // $refArray[$ref['index'] + 1] = $ref; // } // // // $mainContents = $this->article_main_obj->where("article_id", $data['article_id'])->where("type", 0)->where("state", 0)->order("sort asc")->select(); // // // $frag = []; // // 处理每个正文段落 // foreach ($mainContents as $main) { // $updatedContent = $this->convertReferencesToLatex($main['content'], $refArray); // $frag[] = $updatedContent; // // 更新处理后的内容 // } // // return jsonSuccess($frag); // } /** * 格式化作者信息为BibTeX格式 * @param string $authors 作者字符串,如 "Li Y, Yang C, Zhao H, Qu S, Li X, Li Y" * @return string 格式化后的作者字符串,如 "Li, Y. and Yang, C. and Zhao, H. and Qu, S. and Li, X. and Li, Y." */ private function formatBibTeXAuthors($authors) { $authors = rtrim($authors, ". \t\n\r\0\x0B"); // 如果包含"et al",则原样保留 // if (stripos($authors, 'et al') !== false) { // return $authors; // } // 按逗号分割各个作者 $authorArray = array_map('trim', explode(', ', $authors)); $formattedAuthors = []; foreach ($authorArray as $author) { $author = trim($author); if (empty($author)) { continue; } // 按空格分割作者的各部分 $authorParts = explode(' ', $author); if (count($authorParts) >= 2) { // 最后一个是姓氏,前面的是名字首字母 $lastName = array_pop($authorParts); $firstName = implode(' ', $authorParts); $formattedAuthors[] = $lastName . ", " . $firstName; // $firstNameInitials = implode('. ', $authorParts) . '.'; // $formattedAuthors[] = $lastName . ', ' . $firstNameInitials; } else { // 如果只有一个部分,当作姓氏处理 $formattedAuthors[] = $author; } } // 用 " and " 连接所有作者 return implode(' and ', $formattedAuthors); } /** * 从原始内容生成 BibTeX 条目(简单处理) * @param array $ref 参考文献数据 * @param string $citationKey citation key * @return string BibTeX 条目 */ private function generateFromRawContent($ref, $citationKey) { $entry = "@misc{{$citationKey},\n"; // 将整个参考文献内容作为 note 字段 if (!empty($ref['refer_content'])) { $entry .= " note={" . $this->escapeBibTeX($ref['refer_content']) . "},\n"; } if (!empty($ref['refer_doi'])) { $entry .= " doi={" . $this->escapeBibTeX($ref['refer_doi']) . "},\n"; } // 移除最后一个逗号并关闭条目 $entry = rtrim($entry, ",\n") . "\n}"; return $entry; } /** * 转义 BibTeX 特殊字符 * @param string $text 文本内容 * @return string 转义后的内容 */ private function escapeBibTeX($text) { // 转义大括号 $text = str_replace(['{', '}'], ['\\{', '\\}'], $text); // 转义反斜杠 $text = str_replace('\\', '\\\\', $text); return $text; } /** * 生成 BibTeX 文件 */ public function generateBibtex() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } try { // 创建数据库连接 $db = Db::connect(); $generator = new ReferenceBibGenerator($db); // 生成 BibTeX 文件 $filePath = $generator->generateBibFile($data['p_article_id']); // 返回相对路径供前端使用 $relativePath = str_replace(ROOT_PATH . 'public' . DS, '', $filePath); return jsonSuccess([ 'file_path' => $relativePath, 'full_path' => $filePath ]); } catch (Exception $e) { return jsonError('生成 BibTeX 文件失败: ' . $e->getMessage()); } } public function getFragBF() { $data = $this->request->post(); // 验证规则 $rule = new Validate([ 'p_article_id' => 'require|number' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $list = $this->production_article_refer_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); $z = count($list); $m = 0; foreach ($list as $v) { if ($v['refer_frag'] != '' || $v['author'] != '') { $m++; } } if ($z == 0) { return jsonError('system error!'); } $f = intval($m * 100 / $z); $re['bf'] = $f; return jsonSuccess($re); } /** * 删除作者 */ public function delAuthor() { $data = $this->request->post(); $rule = new Validate([ 'p_article_author_id' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $this->production_article_author_obj->where('p_article_author_id', $data['p_article_author_id'])->update(['state' => 1]); return jsonSuccess([]); } /** * 获取作者列表 */ public function getAuthorlist() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $list = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); foreach ($list as $k => $v) { $list[$k]['organs'] = $this->production_article_author_to_organ_obj ->field("t_production_article_organ.*") ->join("t_production_article_organ", 't_production_article_organ.p_article_organ_id = t_production_article_author_to_organ.p_article_organ_id', 'left') ->where('t_production_article_author_to_organ.p_article_author_id', $v['p_article_author_id']) ->where('t_production_article_author_to_organ.state', 0) ->select(); } $re['authors'] = $list; return jsonSuccess($re); } /** * 更改附加文件 */ public function editArticleFile() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require', 'filetype' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } if ($data['filetype'] == 'PDF') { $updata['file_pdf'] = $data['fileURL']; } elseif ($data['filetype'] == 'HTML') { $updata['file_html'] = $data['fileURL']; } elseif ($data['filetype'] == 'SUB') { $updata['file_sub'] = $data['fileURL']; } elseif ($data['filetype'] == 'SUB2') { $updata['file_sub2'] = $data['fileURL']; } elseif ($data['filetype'] == 'endNote') { $updata['endnote'] = $data['fileURL']; } elseif ($data['filetype'] == 'bibTex') { $updata['bibtex'] = $data['fileURL']; } elseif ($data['filetype'] == 'CDF') { $updata['file_cdf'] = $data['fileURL']; } elseif ($data['filetype'] == 'Original') { $updata['file_original'] = $data['fileURL']; } $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($updata); return jsonSuccess([]); } /** * 上传文章图片文件 */ public function up_articlepic_file() { $file = request()->file('articleicon'); if ($file) { $info = $file->move(ROOT_PATH . 'public' . DS . 'articleicon'); if ($info) { return json(['code' => 0, 'upurl' => str_replace("\\", "/", $info->getSaveName())]); } else { return json(['code' => 1, 'msg' => $file->getError()]); } } } /** * 开始proof */ public function pushProof() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $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(); $journal_info = $this->journal_obj->where('journal_id', $article_info['journal_id'])->find(); $user_info = $this->user_obj->where('user_id', $article_info['user_id'])->find(); $this->pdfAddProof($p_info['article_id']); if ($p_info['file_pdf'] == '') { return jsonError('To the editor: PROOF is the final form before the article goes online. The PROOF link step not be opened if you have not completed the previous steps.'); } //发送邮件 $tt = "Dear Author,

"; $tt .= "Please confirm proof of your manuscript on the submission website within 48 hours. (https://submission.tmrjournals.com)

"; // $tt .= "Click here to confirm the proof.
"; $tt .= "Click here to view and confirm the proof.

"; $tt .= "If your response is not received, we will regard the author's consent to the version if the time exceeds.

"; $tt .= "If you have any questions, please feel free to contact us.
"; $tt .= "Note: Double-check the authors' information carefully to ensure they are correct."; // $maidata['email'] = '751475802@qq.com'; $maidata['email'] = $user_info['email']; $maidata['title'] = "PROOF|" . $journal_info['title']; $maidata['content'] = $tt; $maidata['tmail'] = $journal_info['email']; $maidata['tpassword'] = $journal_info['epassword']; if ($p_info['file_sub'] != '') { $file = []; $file[] = ROOT_PATH . 'public' . DS . 'proofPDF' . DS . $p_info['article_id'] . '.pdf'; if (substr($p_info['file_sub'], strripos($p_info['file_sub'], '.') + 1) == 'pdf') { $file[] = ROOT_PATH . 'public' . DS . 'proofPDF' . DS . $p_info['article_id'] . 'SUB.pdf'; } else { $file[] = ROOT_PATH . 'public' . DS . 'articleSUB' . DS . $p_info['file_sub']; } } else { $file = ROOT_PATH . 'public' . DS . 'proofPDF' . DS . $p_info['article_id'] . '.pdf'; } sendEmail($maidata['email'], $maidata['title'], $journal_info['title'], $maidata['content'], $maidata['tmail'], $maidata['tpassword'], $file); //更改数据库 $updata['proof_state'] = 1; $updata['proof_stime'] = time(); $updata['proof_etime'] = strtotime("+2 day"); $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($updata); return jsonSuccess([]); } /** * 自动执行 */ public function proofState() { $this->production_article_obj->where('proof_state', 1)->where('proof_etime', '<', time())->update(['proof_state' => 2]); } /** * 作者反馈proof */ public function editProof() { $data = $this->request->post(); $rule = new Validate([ 'article_id' => 'require', 'code' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $updata = []; $updata['proof_rtime'] = time(); if ($data['code'] == 0) { //同意 $updata['proof_state'] = 2; } else { //拒绝 if (trim($data['content']) == '') { return jsonError('Content is required'); } $updata['proof_state'] = 2; $updata['proof_content'] = trim($data['content']); } $this->production_article_obj->where('article_id', $data['article_id'])->where('state', 0)->update($updata); return jsonSuccess([]); } /** * 同意proof通过邮件链接 */ public function editProofFromEmail($articleId) { $this->production_article_obj->where('article_id', $articleId)->where('state', 0)->update(['proof_state' => 2, 'proof_rtime' => time()]); echo 'Commit Succeeded'; } public function myproofAdd() { $article_id = $this->request->post("article_id"); self::pdfAddProof($article_id); } /** * @title 文章文件上传 * * @param name:name type:string require:1 desc:文件域名称(articleSUB/articleSUB2/bibTex/endNote/articleCDF/articleOriginal) * @param name:type type:string require:1 desc:pathinfo(articleSUB/articleSUB2/bibTex/endNote/articleCDF/articleOriginal) * * @return upurl:图片地址 */ public function up_article_file($type) { $file = request()->file($type); if ($file) { $info = $file->move(ROOT_PATH . 'public' . DS . $type); if ($info) { return json(['code' => 0, 'msg' => 'success', 'upurl' => str_replace("\\", "/", $info->getSaveName())]); } else { return json(['code' => 1, 'msg' => $file->getError()]); } } } public function mytestlongtable(){ $data = $this->request->post(); $rule = new Validate([ "table_id"=>"require" ]); if(!$rule->check($data)){ return jsonError($rule->getError()); } $res = $this->longTablePdfCreate([$data['table_id'], $data['table_id']+1]); return json($res); } public function longTablePdfCreate(array $table_ids) { // 获取表格数据 $table_info_f = $this->article_main_table_obj->where("amt_id", $table_ids[0])->find(); if (!$table_info_f) { return jsonError("Table not found"); } $article_id = $table_info_f['article_id']; $production_info = $this->production_article_obj->where("article_id", $article_id)->find(); if (!$production_info) { return jsonError("Production not found"); } $references = $this->production_article_refer_obj->where("p_article_id", $production_info['p_article_id'])->select(); // 解析表格数据 // $tableData = json_decode($table_info['table_data'], true); // if (!$tableData) { // return jsonError("Invalid table data"); // } // $latex = []; $tex_content = "\\documentclass[8pt]{article}\n"; $tex_content .= "\\usepackage[UTF8]{ctex} % 设置字体\n"; $tex_content .= "\\usepackage{tabularray} % longtblr核心宏包\n"; $tex_content .= "\\usepackage{xcolor} % 颜色支持\n\n"; $tex_content .= "\\usepackage{geometry} \n"; $tex_content .= "\\usepackage{textcomp} \n"; $tex_content .= "\\usepackage[english]{babel} \n"; $tex_content .= "\\geometry{ a4paper, % A4纸张 left=1.5cm, % 左页边距 right=1.5cm, % 右页边距 top=2cm, % 上页边距 bottom=2cm, % 下页边距 }"; $tex_content .= "\\linespread{1.05}"; $tex_content .= "\\definecolor{tablegray}{RGB}{250,231,232}\n\n"; $tex_content .= "\\begin{document}\n\n"; foreach ($table_ids as $value){ $latex = []; $table_info = $this->article_main_table_obj->where("amt_id", $value)->find(); $tableData = json_decode($table_info['table_data'], true); if (!$tableData) { continue; } $maxColCount = 0; $str_list = []; foreach ($tableData as $row) { $colCount = 0; foreach ($row as $cell) { $colCount += $cell['colspan']; // 跨列会占用多个列位置 if($cell['colspan']==1){ $colIndex = $colCount; // 当前列的索引 // 计算当前单元格的字符数 $cellTextLength = strlen(strip_tags($cell['text'])); // 或者使用 mb_strlen($cell['text'], 'UTF-8') 来处理多字节字符 if(isset($str_list[$colIndex])){ $str_list[$colIndex] = max($cellTextLength, $str_list[$colIndex]); } else { $str_list[$colIndex] = $cellTextLength; } } } if ($colCount > $maxColCount) { $maxColCount = $colCount; } } // 根据 $str_list 计算列宽比例(比例范围:0.2-1) $columnSpec = ''; if (!empty($str_list)) { // 找到最大字符数,用于比例计算 $maxTextLength = max($str_list); if ($maxTextLength > 0) { // 为每一列计算相对宽度(比例范围:0.2-1) for ($i = 1; $i <= $maxColCount; $i++) { if (isset($str_list[$i]) && $str_list[$i] > 0) { // 计算当前列的相对比例(0-1之间) $relativeRatio = round($str_list[$i] / $maxTextLength, 1); // 将比例调整到0.2-1范围内 $adjustedRatio = max(0.3, min(1, $relativeRatio)); // 转换为整数(乘以10便于处理小数) // $widthValue = round($adjustedRatio * 10); $columnSpec .= "X[$adjustedRatio] "; } else { // 如果某列没有数据,给一个默认最小宽度(对应0.2比例) $columnSpec .= "X[0.3] "; // 0.2 * 10 = 2 } } } else { // 如果没有有效数据,使用平均分配 $columnSpec = str_repeat('X[1] ', $maxColCount); } } else { // 如果 $str_list 为空,使用平均分配 $columnSpec = str_repeat('X[1] ', $maxColCount); } // 整理title信息 $title = strip_tags($table_info['title']); $label = "tab-".$table_info['amt_id']; // 开始构建LaTeX代码 // $latex = []; // 遍历表格数据,生成每一行 $table = []; foreach ($tableData as $rowIndex => $row) { $table[$rowIndex] = []; $currentCol = 0; // 记录当前处理到的列位置 // 处理当前行的每个单元格 foreach ($row as $cell) { while (isset($table[$rowIndex][$currentCol])){ $currentCol += 1; } // 处理单元格文本:移除HTML标签,替换为LaTeX粗体 $text = $this->convertToLatex($cell['text'], $references,false); // 处理合并单元格:跨列(colspan)和跨行(rowspan) $colspan = $cell['colspan'] ?? 1; $rowspan = $cell['rowspan'] ?? 1; $cellContent = $text; // 处理跨列(使用tabularray的c选项,跨多列) if ($colspan > 1 && $rowspan > 1) { // 跨行跨列 $cellContent = "\\SetCell[c={$colspan},r={$rowspan}]{l,bg=white} {$cellContent}"; $table[$rowIndex][$currentCol] = $cellContent; for($n_c=1;$n_c<$colspan;$n_c++){ $table[$rowIndex][$currentCol+$n_c] = ""; } for ($a_r=1;$a_r<$rowspan;$a_r++){ for ($a_c=0;$a_c<$colspan;$a_c++){ $table[$rowIndex+$a_r][$currentCol+$a_c] = ""; } } } elseif ($colspan > 1) { // 仅跨列 $cellContent = "\\SetCell[c={$colspan}]{l,bg=white} {$cellContent}"; $table[$rowIndex][$currentCol] = $cellContent; for($n_c=1;$n_c<$colspan;$n_c++){ $table[$rowIndex][$currentCol+$n_c] = ""; } } elseif ($rowspan > 1) { // 仅跨行 $cellContent = "\\SetCell[r={$rowspan}]{l,bg=white} {$cellContent}"; $table[$rowIndex][$currentCol] = $cellContent; for ($a_r=1;$a_r<$rowspan;$a_r++){ $table[$rowIndex+$a_r][$currentCol] = ""; } }else{ $table[$rowIndex][$currentCol] = $cellContent; } // 如果是跨列单元格,跳过后续的colspan-1个位置 $currentCol += $colspan; } } foreach ($table as $row){ $rowContent = implode(' & ', $row) . " \\\\"; $latex[] = " {$rowContent}"; } $tex_content .= "\t\\begin{longtblr}[\n"; $tex_content .= "\t\tcaption = {" . $title . "},\n"; $tex_content .= "\t\tlabel = {" . $label . "},\n"; $tex_content .= "\t\t]{\n"; $tex_content .= "\t\t\t% 你指定的列格式:自定义宽度比例 + 左对齐 + 防止文字溢出\n"; $tex_content .= "\t\t\tcolspec={" . $columnSpec . "},\n"; $tex_content .= "\t\t\twidth = \\textwidth, % 表格宽度占满行宽(配合X列生效)\n"; $tex_content .= "\t\t\trowhead = 1, % 表头跨页重复\n"; $tex_content .= "\t\t\t% 三线表核心配置\n"; $tex_content .= "\t\t\thline{1} = {1pt}, % 顶线(粗)\n"; $tex_content .= "\t\t\thline{2} = {0.5pt}, % 表头分隔线(细)\n"; $tex_content .= "\t\t\thline{Z} = {1pt}, % 底线(粗)\n"; $tex_content .= "\t\t\t% 隔行变色 + 样式优化\n"; $tex_content .= "\t\t\trow{1} = {bg=gray!30, font=\\bfseries, abovesep=5pt, belowsep=5pt}, % 表头样式\n"; $tex_content .= "\t\t\trow{even} = {bg=tablegray}, % 偶数行浅灰\n"; $tex_content .= "\t\t\trow{odd} = {bg=white}, % 奇数行白色\n"; $tex_content .= "\t\t\trowsep = 4pt, % 行间距\n"; $tex_content .= "\t\t}\n"; $tex_content .= "\t\t% 表头\n"; $tex_content .= implode("\n", $latex); $tex_content .= "\n\t\\end{longtblr}\n\n"; } $tex_content .= "\\end{document}"; // echo $tex_content; // 创建输出目录 $outputPath = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_'.$article_id; if (!file_exists($outputPath)) { mkdir($outputPath, 0755, true); } // 生成tex文件 $tex_file = $outputPath . DS . 'table.tex'; file_put_contents($tex_file, $tex_content); $pdfFilePath = $outputPath . DS . 'table.pdf'; $success = $this->generatePdfFromTex($tex_file, $pdfFilePath); // if($success){ // $this->production_article_obj->where("p_article_id",$production_info['p_article_id'])->update(['file_sub_table'=>'tex_'.$article_id.DS."table.pdf"]); // } // $frag['success'] = $success; // $frag['file'] = $pdfFilePath; // return $frag; $iStatus = empty($success['status']) ? 0 : $success['status']; if($iStatus != 1){ return json_encode($success); } if($iStatus == 1){ $this->production_article_obj->where("p_article_id",$production_info['p_article_id'])->update(['file_sub_table'=>'tex_'.$article_id.DS."table.pdf"]); } $frag['success'] = $success; $frag['file'] = $pdfFilePath; // return $frag; return json_encode(['status' => 1,'msg' => 'Table generated successfully']); // if ($success) { // return jsonSuccess([ // 'pdf_file' => $pdfFilePath, // 'message' => 'PDF生成成功' // ]); // } else { // return jsonError('PDF生成失败'); // } // return $tex_file; // 返回文件路径 // return jsonSuccess([ // 'file' => $tex_file, // 'url' => '/public/latex/table_tex/table_' . $table_id . '.tex' // ]); } /** * 根据tex文件生成对应的pdf文件 * @param string $texFilePath .tex文件路径 * @param string $pdfFilePath 输出PDF文件路径 * @return bool 是否生成成功 */ public function generatePdfFromTex($texFilePath, $pdfFilePath) { try { // 检查.tex文件是否存在 if (!file_exists($texFilePath)) { // throw new Exception("LaTeX文件不存在: " . $texFilePath); return ['status' => 2,'msg' => "LaTeX文件不存在: " . $texFilePath]; } // 确保输出目录存在 $pdfDir = dirname($pdfFilePath); if (!is_dir($pdfDir)) { mkdir($pdfDir, 0755, true); } // 方法1: 使用pdflatex命令(推荐) // $command = "{$sLatexDir}pdflatex -include-directory=" . dirname($texFilePath) . // " -output-directory=" . $pdfDir . " " . escapeshellarg($texFilePath); // $command = "pdflatex -output-directory=" . $pdfDir . " " . escapeshellarg($texFilePath); $sLatexDir = '/usr/bin/';//latex执行目录 $command = sprintf( '%slualatex -interaction=nonstopmode -output-directory=%s %s 2>&1', rtrim($sLatexDir, '/') . '/', // /usr/bin/lualatex escapeshellarg($pdfDir), // 转义输出目录(含空格/特殊字符) escapeshellarg($texFilePath) // 转义tex文件路径 ); $output = []; $returnVar = 0; exec($command, $output, $returnVar); // 检查命令执行结果 if ($returnVar !== 0) { // error_log("LaTeX to PDF conversion failed: " . implode("\n", $output)); // return false; return ['status' => 3,'msg' => "LaTeX to PDF conversion failed: " . implode("\n", $output)]; } // 检查PDF文件是否生成成功 if (!file_exists($pdfFilePath)) { // error_log("PDF文件未生成: " . $pdfFilePath); // return false; return ['status' => 3,'msg' => "PDF文件未生成: " . $pdfFilePath]; } // return true; return ['status' => 1,'msg' => "PDF文件生成成功: " . $pdfFilePath]; } catch (Exception $e) { // error_log("生成PDF失败: " . $e->getMessage()); // return false; return ['status' => 3,'msg' => "PDF文件未生成: " . $pdfFilePath]; } } private function escapeLatexSpecialCharsArr($text) { if (is_null($text) || $text === '') { return ''; } $text = strval($text); // 转义LaTeX特殊字符 $search = ['\\', '&', '%', '$', '#', '_', '{', '}', '~', '^']; $replace = ['\\textbackslash{}', '\\&', '\\%', '\\$', '\\#', '\\_', '\\{', '\\}', '\\textasciitilde{}', '\\textasciicircum{}']; $text = str_replace($search, $replace, $text); // 处理换行符 $text = str_replace(["\r\n", "\r", "\n"], ' ', $text); return $text; } public function myTableTest(){ $references = $this->production_article_refer_obj->where("p_article_id",3328)->where("state",0)->order("index asc")->select(); $res = $this->tableCovertLatex(1047,$references); echo $res; } public function tableCovertLatex($amt_id, $references,$aTableInfo = []) { if(empty($aTableInfo)){ $table_info = $this->article_main_table_obj->where('amt_id', $amt_id)->find(); }else{ $table_info = $aTableInfo; } $tableData = json_decode($table_info['table_data'], true); // 检查JSON解码是否成功 if (json_last_error() !== JSON_ERROR_NONE || !is_array($tableData) || empty($tableData)) { return "JSON error"; } if(strlen($table_info['table_data'])>6000){ return "long table"; } // 获取表格最大列数(遍历所有行,找到列数最大值,处理合并后列数变化的情况) $maxColCount = 0; $str_list = []; foreach ($tableData as $row) { $colCount = 0; foreach ($row as $cell) { $colCount += $cell['colspan']; // 跨列会占用多个列位置 if($cell['colspan']==1){ $colIndex = $colCount; // 当前列的索引 // 计算当前单元格的字符数 $cellTextLength = strlen(strip_tags($cell['text'])); // 或者使用 mb_strlen($cell['text'], 'UTF-8') 来处理多字节字符 if(isset($str_list[$colIndex])){ $str_list[$colIndex] = max($cellTextLength, $str_list[$colIndex]); } else { $str_list[$colIndex] = $cellTextLength; } } } if ($colCount > $maxColCount) { $maxColCount = $colCount; } } // 根据 $str_list 计算列宽比例(比例范围:0.2-1) $columnSpec = ''; if (!empty($str_list)) { // 找到最大字符数,用于比例计算 $maxTextLength = max($str_list); if ($maxTextLength > 0) { // 为每一列计算相对宽度(比例范围:0.2-1) for ($i = 1; $i <= $maxColCount; $i++) { if (isset($str_list[$i]) && $str_list[$i] > 0) { // 计算当前列的相对比例(0-1之间) $relativeRatio = round($str_list[$i] / $maxTextLength, 1); // 将比例调整到0.2-1范围内 $adjustedRatio = max(0.3, min(1, $relativeRatio)); // 转换为整数(乘以10便于处理小数) // $widthValue = round($adjustedRatio * 10); $columnSpec .= "X[$adjustedRatio] "; } else { // 如果某列没有数据,给一个默认最小宽度(对应0.2比例) $columnSpec .= "X[0.3] "; // 0.2 * 10 = 2 } } } else { // 如果没有有效数据,使用平均分配 $columnSpec = str_repeat('X[1] ', $maxColCount); } } else { // 如果 $str_list 为空,使用平均分配 $columnSpec = str_repeat('X[1] ', $maxColCount); } // 计算列宽比例(简单平均分配,可根据需要调整) // $columnSpec = str_repeat('X[1] ', $maxColCount); $columnSpec = rtrim($columnSpec); // 整理title信息 $title = strip_tags($table_info['title']); $label = "tab:".$table_info['amt_id']; $notes = $this->escapeLatexSpecialChars(trim(strip_tags($table_info['note']),"*. \t\n\r\0\x0B")); //确定是单栏还是双栏的表格 $oneRowString = 0; foreach ($str_list as $v){ $oneRowString += $v; } $table_ss = $oneRowString < 50 ? "tmrtable" : "tmrtable*"; // 开始构建LaTeX代码 $latex = []; $latex[] = "\\begin{".$table_ss."}{".$this->convertToLatex($title,$references)."}{".$label."}{".$columnSpec."}{1}{".$notes."}"; // 遍历表格数据,生成每一行 $table = []; foreach ($tableData as $rowIndex => $row) { // $cells = []; $table[$rowIndex] = []; $currentCol = 0; // 记录当前处理到的列位置 //调整$currentCol // while (isset($table[$rowIndex][$currentCol])){ // $currentCol += 1; // } // 处理当前行的每个单元格 foreach ($row as $cell) { while (isset($table[$rowIndex][$currentCol])){ $currentCol += 1; } // 处理单元格文本:移除HTML标签,替换为LaTeX粗体 $text = $this->convertToLatex($cell['text'], $references); // 处理合并单元格:跨列(colspan)和跨行(rowspan) $colspan = $cell['colspan'] ?? 1; $rowspan = $cell['rowspan'] ?? 1; $cellContent = $text; // 处理跨列(使用tabularray的c选项,跨多列) if ($colspan > 1 && $rowspan > 1) { // 跨行跨列 $cellContent = "\\SetCell[c={$colspan},r={$rowspan}]{l,bg=white} {$cellContent}"; $table[$rowIndex][$currentCol] = $cellContent; for($n_c=1;$n_c<$colspan;$n_c++){ $table[$rowIndex][$currentCol+$n_c] = ""; } for ($a_r=1;$a_r<$rowspan;$a_r++){ for ($a_c=0;$a_c<$colspan;$a_c++){ $table[$rowIndex+$a_r][$currentCol+$a_c] = ""; } } } elseif ($colspan > 1) { // 仅跨列 $cellContent = "\\SetCell[c={$colspan}]{l,bg=white} {$cellContent}"; $table[$rowIndex][$currentCol] = $cellContent; for($n_c=1;$n_c<$colspan;$n_c++){ $table[$rowIndex][$currentCol+$n_c] = ""; } } elseif ($rowspan > 1) { // 仅跨行 $cellContent = "\\SetCell[r={$rowspan}]{l,bg=white} {$cellContent}"; $table[$rowIndex][$currentCol] = $cellContent; for ($a_r=1;$a_r<$rowspan;$a_r++){ $table[$rowIndex+$a_r][$currentCol] = ""; } }else{ $table[$rowIndex][$currentCol] = $cellContent; } // $cells[] = $cellContent; // 如果是跨列单元格,跳过后续的colspan-1个位置 $currentCol += $colspan; } // 拼接单元格,行尾用\\ // $rowContent = implode(' & ', $cells) . " \\\\"; // $latex[] = " {$rowContent}"; } foreach ($table as $row){ $rowContent = implode(' & ', $row) . " \\\\"; $latex[] = " {$rowContent}"; } $latex[] = "\\end{".$table_ss."}"; // 拼接所有行,返回LaTeX代码 return implode("\n", $latex); } function extractPureTitle(string $title): string { // 正则表达式说明: // ^Table\s+ :匹配以Table开头(不区分大小写),后跟一个或多个空格 // [\d.]+ :匹配一个或多个数字或小数点(支持1、1.2、2.3.4等编号) // \s* :匹配零个或多个空格(处理编号后的空格) // i :不区分大小写匹配 $pattern = '/^Table\s+[\d.]+\s*/i'; // 替换匹配的前缀为空字符串 $pureTitle = preg_replace($pattern, '', $title); // 去除首尾多余的空格(处理边界情况) return trim($pureTitle); } /**解决附加内容的表格内容 * @return void */ private function tableForComp($table_data,$references){ // 解码表格数据 $tableData = json_decode($table_data, true); if (!$tableData || !isset($tableData['rows']) || !is_array($tableData['rows'])) { return ''; } $latexLines = []; // 开始longtblr环境 $latexLines[] = "\\begin{longtblr}["; // 设置表格基本属性 $columns = count($tableData['rows'][0] ?? []); $colSpec = str_repeat('X[c]', $columns); // 默认居中列 $latexLines[] = " colspec={{$colSpec}},"; $latexLines[] = " width=\\textwidth,"; $latexLines[] = " hlines,"; $latexLines[] = " vlines,"; $latexLines[] = " rowhead=1,"; // 如果第一行是表头 $latexLines[] = "]"; // 处理表格行 foreach ($tableData['rows'] as $rowIndex => $row) { $rowCells = []; foreach ($row as $cell) { // 转换单元格内容中的特殊标签 $convertedCell = $this->convertToLatex($cell, $references); $rowCells[] = $convertedCell; } $latexLines[] = " " . implode(" & ", $rowCells) . " \\\\"; } $latexLines[] = "\\end{longtblr}"; return implode("\n", $latexLines); } private function authorFormate($p_article_id) { // $authors = $this->article_author_obj->where('article_id', $article_id)->where('state', 0)->select(); $p_info = $this->production_article_obj->where('p_article_id', $p_article_id)->find(); $article_info = $this->article_obj->where('article_id', $p_info['article_id'])->find(); $authors = $this->production_article_author_obj->where('p_article_id', $p_article_id)->where('state', 0)->select(); //组装地址数组 $address = []; // foreach ($authors as $v) { // $cac = $this->production_article_author_to_organ_obj // ->field('t_production_article_organ.*') // ->join('t_production_article_organ', 't_production_article_organ.p_article_organ_id = t_production_article_author_to_organ.p_article_organ_id', 'left') // ->where('t_production_article_author_to_organ.p_article_author_id', $v['p_article_author_id']) // ->where('t_production_article_author_to_organ.state', 0) // ->select(); // foreach ($cac as $val) { // if (!in_array($val['organ_name'], $address)) { // $address[] = $val['organ_name']; // } // } // } $os = $this->production_article_author_to_organ_obj->where('p_article_id', $p_article_id)->where('state', 0)->column('p_article_organ_id'); $ors = $this->production_article_organ_obj->where('p_article_organ_id', 'in', $os)->select(); foreach ($ors as $v) { $address[] = $v['organ_name']; } $first_num = 0; //第一作者的总数 foreach ($authors as $v) { if ($v['is_first'] == 1) { $first_num++; } } //构建数组字符串 $author = ''; foreach ($authors as $v) { $cache_str = $article_info['journal_id'] == 21 ? trim($v['last_name']) . trim($v['first_name']) . "" : trim($v['first_name']) . ' ' . trim($v['last_name']) . ''; $cac = $this->production_article_author_to_organ_obj ->field('t_production_article_organ.*') ->join('t_production_article_organ', 't_production_article_organ.p_article_organ_id = t_production_article_author_to_organ.p_article_organ_id', 'left') ->where('t_production_article_author_to_organ.p_article_author_id', $v['p_article_author_id']) ->where('t_production_article_author_to_organ.state', 0) ->order('t_production_article_author_to_organ.p_article_organ_id') ->select(); foreach ($cac as $val) { $cache_str .= (intval(search_array_val($address, $val['organ_name'])) + 1) . ", "; } $cache_str = trim($cache_str); $cache_str = substr($cache_str, 0, -1); if ($first_num > 1 && $v['is_first'] == 1) { $cache_str .= '#'; } if ($v['is_report'] == 1) { $cache_str .= '*'; } $cache_str .= ''; $author .= $cache_str; } //组装address $address_str = ''; $address1 = []; foreach ($address as $k => $v) { $address_str .= ($k + 1) . ' ' . $v . ' '; $address1[] = [ "k" => $k + 1, "content" => $v ]; } $frag['author'] = $author; $frag['address'] = $address_str; $frag['addressList'] = $address; $frag['addressList1'] = $address1; return $frag; } /** * 更改文章pdf文件 */ public function updateArticlePDF() { $data = $this->request->post(); $rule = new Validate([ 'p_article_id' => 'require', 'pdf' => 'require' ]); if (!$rule->check($data)) { return jsonError($rule->getError()); } $update['file_pdf'] = $data['pdf']; $this->production_article_obj->where('p_article_id', $data['p_article_id'])->update($update); return jsonSuccess([]); } /** * 上传pdf文件 */ public function up_pdf_file() { $file = request()->file('pdf'); if ($file) { $info = $file->move(ROOT_PATH . 'public' . DS . 'pdf'); if ($info) { return json(['code' => 0, 'upurl' => str_replace("\\", "/", $info->getSaveName())]); } else { return json(['code' => 1, 'msg' => $file->getError()]); } } } /**上传最终版文章word文件 * @return \think\response\Json|void */ public function up_last_artFile() { $file = request()->file('completedManuscirpt'); if ($file) { $info = $file->move(ROOT_PATH . 'public' . DS . 'completedManuscirpt'); if ($info) { return json(['code' => 0, 'upurl' => str_replace("\\", "/", $info->getSaveName())]); } else { return json(['code' => 1, 'msg' => $file->getError()]); } } } /** * 上传pdf文件 */ public function up_mainimg_file() { $file = request()->file('mainimg'); if ($file) { $info = $file->move(ROOT_PATH . 'public' . DS . 'mainimg'); if ($info) { return json(['code' => 0, 'upurl' => str_replace("\\", "/", $info->getSaveName())]); } else { return json(['code' => 1, 'msg' => $file->getError()]); } } } /** * 生成初稿 * @param article_id 文章ID */ public function createArticlePdf($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' => ['in',[0,2]]]; $aProductionArticle = Db::name('production_article')->where($aWhere)->find(); if(empty($aProductionArticle)){ return json_encode(array('status' => 3,'msg' => 'No articles found' )); } //关联文章ID $iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id']; if(empty($iArticleId)){ return json_encode(array('status' => 4,'msg' => 'Unbound article' )); } //调用生成Tex队列 Queue::push('app\api\job\ArticleCreateTex@fire', ['p_article_id' => $iPArticleId], 'ArticleCreateTex'); return json_encode(array('status' => 1,'msg' => 'PDF generation in progress, please wait')); } /** * 生成初稿-参考文献 * @param p_article_id 生产环境文章信息 */ private function creatReferences($aParam = []){ $aParam = empty($aParam) ? $this->request->post() : $aParam; //必填值验证 $iPArticleId = empty($aParam['p_article_id']) ? '' : $aParam['p_article_id']; if(empty($iPArticleId)){ return json_encode(array('status' => 2,'msg' => 'Please select an article' )); } //查询参考文献 $aWhere = ['p_article_id' => $iPArticleId,'state' => 0]; $aReferences = Db::name('production_article_refer')->where($aWhere)->order('index asc')->select(); if(empty($aReferences)){ return json_encode(array('status' => 3,'msg' => 'No reference information found' )); } //参考文献处理 $sContent = "% BibTeX file generated for article ID: {$iPArticleId}\n"; $sContent .= "% Generated on " . date('Y-m-d H:i:s') . "\n\n"; $sReferences = ''; $aReferencesLists = []; foreach ($aReferences as $value) { $aReferencesLists[$value['index'] + 1] = $value; $sReferencesInfo = $this->generateBibEntry($value); if(empty($sReferencesInfo)){ continue; } $sReferences .= $sReferencesInfo . "\n\n"; } if(empty($sReferences)){ return json_encode(array('status' => 4,'msg' => 'No reference information found' )); } $sContent .= $sReferences; return ['status' => 1,'msg' => 'success','data' => ['references' => $sContent,'references_list' => $aReferencesLists]]; } /** * 生成初稿-处理正文内容表格/图片相关联 * @param p_article_id 生产环境文章信息 */ public function dealMainFigureOrTable($aParam = []){ //获取参数 $aParam = empty($aParam) ? $this->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' )); } //查询内容 $aWhere = ['article_id' => $iArticleId,'type' => 0,'state' => 0,'is_h1' => ['<>',1],'is_h2' => ['<>',1],'is_h3' => ['<>',1]]; $aTextMain = Db::name('article_main')->field('am_id,content')->where($aWhere)->order('sort asc')->select(); if(empty($aTextMain)){ return json_encode(array('status' => 3,'msg' => 'The content is empty' )); } //查询图片信息 $aWhere = ['article_id' => $iArticleId,'state' => 0]; $aImageMain = Db::name('article_main_image')->where($aWhere)->order('ami_id asc')->column('ami_id'); //查询表格信息 $aWhere = ['article_id' => $iArticleId,'state' => 0]; $aTableMain = Db::name('article_main_table')->where($aWhere)->order('amt_id asc')->column('amt_id'); //数据处理 $aUpdate = []; $oFigureTagProcessor = new \app\common\FigureTagProcessor; $oTableTagProcessor = new \app\common\TableTagProcessor; foreach ($aTextMain as $key => $value) { $sContent = empty($value['content']) ? '' : trim($value['content']); if(empty($sContent)){ continue; } //处理图片 $aFigureContent = $oFigureTagProcessor->dealFigureStr($sContent,$aImageMain); $iStatus = empty($aFigureContent['status']) ? 0 : $aFigureContent['status']; $sData = empty($aFigureContent['data']) ? '' : $aFigureContent['data']; // var_dump($aFigureContent); if($iStatus != 1){ $sData = $sContent; }else{ $aUpdate[$value['am_id']] = ['am_id' => $value['am_id'],'content' => $sData]; } //处理表格 $aTableContent = $oTableTagProcessor->dealTableStr($sData,$aTableMain); $iStatus = empty($aTableContent['status']) ? 0 : $aTableContent['status']; $sData = empty($aTableContent['data']) ? $sContent : $aTableContent['data']; if($iStatus != 1){ continue; } $aUpdate[$value['am_id']] = ['am_id' => $value['am_id'],'content' => $sData]; } //批量更新入库 if(empty($aUpdate)){ return json_encode(array('status' => 3,'msg' => 'No table or image data to be processed was found' )); } $oArticleMain = new \app\common\ArticleMain(); $result = $oArticleMain->saveAll($aUpdate); if ($result === false) { return json_encode(array('status' => 4,'msg' => 'Operation failed'.json_encode($aUpdate))); } return json_encode(array('status' => 1,'msg' => 'success')); } /** * 生成latex .tex文件 * @param article_id 文章ID */ public function execCreateTex($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' => ['in',[0,2]]]; $aProductionArticle = Db::name('production_article')->where($aWhere)->find(); if(empty($aProductionArticle)){ return json_encode(array('status' => 3,'msg' => 'No articles found' )); } //关联文章ID $iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id']; if(empty($iArticleId)){ return json_encode(array('status' => 4,'msg' => 'Unbound article' )); } //内容 $oLatexContent = new \app\common\LatexContent; //内容生成 //获取第一页内容 $aResult = $oLatexContent->buildFirst($aProductionArticle); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; $sMsg = empty($aResult['msg']) ? 'Content generation failed-First' : $aResult['msg']; $sFirstTemplateInfo = empty($aResult['data']) ? '' : $aResult['data']; if($iStatus != 1){ return json_encode(array('status' => 5,'msg' => $sMsg)); } if(empty($sFirstTemplateInfo)){ return json_encode(array('status' => 6,'msg' => 'Article content retrieval failed')); } //获取参考文献 $aResult = $this->creatReferences($aProductionArticle); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; $sMsg = empty($aResult['msg']) ? 'Content generation failed-Reference' : $aResult['msg']; $aResult = empty($aResult['data']) ? [] : $aResult['data']; $sReferences = empty($aResult['references']) ? '' : $aResult['references'];//参考文献内容 $aReferencesLists = empty($aResult['references_list']) ? [] : $aResult['references_list'];//参考文献数组 if($iStatus != 1){ return json_encode(array('status' => 8,'msg' => $sMsg)); } if(empty($sReferences)){ return json_encode(array('status' => 9,'msg' => 'Article content retrieval failed')); } //生成主内容 $aResult = $oLatexContent->buildMain(['production_article' => $aProductionArticle,'references' => $aReferencesLists]); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; $sMsg = empty($aResult['msg']) ? 'Content generation failed-Main' : $aResult['msg']; $sMainTemplateInfo = empty($aResult['data']) ? '' : $aResult['data']; if($iStatus != 1){ return json_encode(array('status' => 6,'msg' => $sMsg)); } if(empty($sMainTemplateInfo)){ return json_encode(array('status' => 7,'msg' => 'Article content retrieval failed')); } //创建基础目录 $sDir = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $iArticleId; if (!is_dir($sDir)) { mkdir($sDir, 0755, true); } //生成Reference文件 $sFileUrl = $sDir. DS . 'references_' . $iArticleId . '.bib'; file_put_contents($sFileUrl, $sReferences); if(!file_exists($sFileUrl)){ return json_encode(array('status' => 10,'msg' => 'Reference file generation failed')); } //生成运行文件.tex $sTexName = 'article_' . $iArticleId; $sTexFileUrl = $sDir. DS . $sTexName .'.tex'; $sTemplateInfo = $sFirstTemplateInfo."\n".$sMainTemplateInfo; file_put_contents($sTexFileUrl, $sTemplateInfo); if(!file_exists($sTexFileUrl)){ return json_encode(array('status' => 11,'msg' => 'tex file generation failed')); } //调用生成PDF队列 $queue = Queue::push('app\api\job\ArticleCreatePdf@fire', ['p_article_id' => $iPArticleId], 'ArticleCreatePdf'); //生成长表格PDF $aLongTableId = empty($aResult['long_table_id']) ? [] : $aResult['long_table_id']; if(!empty($aLongTableId)){ //调用生成长表格队列 $longtablequeue = Queue::push('app\api\job\ArticleCreateLongTable@fire', ['p_article_id' => $iPArticleId,'long_table_id' => $aLongTableId], 'ArticleCreateLongTable'); } return json_encode(array('status' => 1,'msg' => 'tex file generated successfully')); } /** * 命令行生成PDF * @param article_id 文章ID */ public function execCreatePdf($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' => ['in',[0,2]]]; $aProductionArticle = Db::name('production_article')->field('article_id,pdf_id')->where($aWhere)->find(); if(empty($aProductionArticle)){ return json_encode(array('status' => 3,'msg' => 'No articles found' )); } $iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id']; if(empty($iArticleId)){ return json_encode(array('status' => 4,'msg' => 'Unbound article' )); } //日志查询 if(!empty($aProductionArticle['pdf_id'])){ $aWhere = ['article_id' => $iArticleId,'p_article_id' => $iPArticleId,'pdf_id' => $aProductionArticle['pdf_id']]; $aPdf = Db::name('production_article_pdf')->field('url')->where($aWhere)->find(); $sPdfUrl = empty($aPdf['url']) ? '' : trim(basename($aPdf['url']),'.pdf'); } //验证参考文献Reference文件是否存在 $sDir = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_' . $iArticleId; $sFileUrl = $sDir. DS . 'references_' . $iArticleId . '.bib'; if(!file_exists($sFileUrl)){ return json_encode(array('status' => 4,'msg' => 'Reference file generation failed')); } //验证生成运行文件.tex是否存在 $sTexName = 'article_' . $iArticleId; $sTexFileUrl = $sDir. DS . $sTexName .'.tex'; if(!file_exists($sTexFileUrl)){ return json_encode(array('status' => 5,'msg' => 'Latex.tex file not generated')); } //命令行生成PDF $aOutput = []; $iReturnCode = 0; $sLatexDir = '/usr/bin/';//'/usr/bin/';//latex执行目录 $sPdfName = $sTexName.'_'.uniqid();//PDF文件名 //切换目录 chdir($sDir); //清理所有编译缓存文件 if(!empty($sPdfUrl)){ $delFiles = [ "{$sPdfUrl}.aux", "{$sPdfUrl}.bbl", "{$sPdfUrl}.blg", "{$sPdfUrl}.bcf", "{$sPdfUrl}.run.xml", "{$sPdfUrl}.log", "{$sPdfUrl}.out", "{$sPdfUrl}.toc" ]; foreach ($delFiles as $file) { if(!file_exists($file)){ continue; } unlink($file); } } $sPdfFilePath = $sDir. DS . $sPdfName.'.pdf'; // 编译命令 $command = "{$sLatexDir}xelatex -interaction=nonstopmode -jobname={$sPdfName} -file-line-error {$sTexName}.tex 2>&1 ; "; //生成参考文献 $command .= "{$sLatexDir}biber --debug --logfile={$sDir}/biber_error.log --input-directory={$sDir} --output-directory={$sDir} {$sPdfName} 2>&1 ; "; $command .= "{$sLatexDir}xelatex -interaction=nonstopmode -jobname={$sPdfName} -file-line-error {$sTexName}.tex 2>&1 ; "; $command .= "{$sLatexDir}xelatex -interaction=nonstopmode -jobname={$sPdfName} -file-line-error {$sTexName}.tex 2>&1"; //执行命令并获取结果 exec($command, $aOutput, $iReturnCode); $sOutput = implode("\n", $aOutput); //验证是否生成 if (!in_array($iReturnCode,[0,1])) { return json_encode(array('status' => 6,'msg' => 'PDF generation failed:'.$iReturnCode)); } if(!file_exists($sPdfFilePath)){ return json_encode(array('status' => 7,'msg' => 'PDF generation failed')); } //写入日志 Db::startTrans(); $sUrl = str_replace(ROOT_PATH . 'public' , '', $sPdfFilePath); $aInsert = ['article_id' => $iArticleId,'p_article_id' => $iPArticleId,'url' => trim($sUrl,'/'),'create_time' => time()]; $iId = Db::name('production_article_pdf')->insertGetId($aInsert); if(empty($iId)){ return json_encode(['status' => 8,'msg' => 'Log insertion failed']); } //更新生产表关联ID $aUpdate = ['pdf_id' => $iId]; $aWhere = ['p_article_id' => $iPArticleId]; $update_result = DB::name('production_article')->where($aWhere)->limit(1)->update($aUpdate); if($update_result === false){ return json_encode(['status' => 9,'msg' => 'Log insertion failed']); } Db::commit(); return json_encode(array('status' => 1,'msg' => 'PDF generated successfully')); } /** * 获取排版生成PDF历史版本 * @param p_article_id 文章ID */ public function getProductionArticlePdf($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' => ['in',[0,2]]]; $aProductionArticle = Db::name('production_article')->field('article_id,pdf_id')->where($aWhere)->find(); if(empty($aProductionArticle)){ return json_encode(array('status' => 3,'msg' => 'No articles found' )); } $iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id']; if(empty($iArticleId)){ return json_encode(array('status' => 4,'msg' => 'Unbound article' )); } //日志查询 $aWhere = ['article_id' => $iArticleId,'p_article_id' => $iPArticleId,'state' => 2]; $aPdf = Db::name('production_article_pdf')->field('pdf_id,url,create_time')->where($aWhere)->select(); return json_encode(array('status' => 1,'msg' => 'success','data' => $aPdf)); } /** * 获取生产文章信息 * @param p_article_id 文章ID */ public function getProductionArticle($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' => ['in',[0,2]]]; $aProductionArticle = Db::name('production_article')->field('pdf_id,file_sub_table')->where($aWhere)->find(); return json_encode(array('status' => 1,'msg' => 'success','data' => $aPdf)); } }