From 978c81ea1017fb09388c18431d95e24ecdfadd28 Mon Sep 17 00:00:00 2001 From: wangjinlei <751475802@qq.com> Date: Tue, 23 Jun 2026 09:55:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/api/controller/EmailClient.php | 15 +++++--- application/api/controller/Journal.php | 18 +++++++++ application/common/CrossrefService.php | 43 +++++++++++++++++++++- application/common/PubmedService.php | 24 +++++++++++- 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/application/api/controller/EmailClient.php b/application/api/controller/EmailClient.php index e9a4af92..5d379ad6 100644 --- a/application/api/controller/EmailClient.php +++ b/application/api/controller/EmailClient.php @@ -1385,7 +1385,7 @@ class EmailClient extends Base $factoryId = intval($this->request->param('promotion_factory_id', 0)); $sendDate = trim($this->request->param('send_date', date('Y-m-d', strtotime('+1 day')))); $taskName = trim($this->request->param('task_name', '')); - $noRepeatDays = intval($this->request->param('no_repeat_days', 30)); + $noRepeatDays = intval($this->request->param('no_repeat_days', 15)); $minInterval = intval($this->request->param('min_interval', 30)); $maxInterval = intval($this->request->param('max_interval', 60)); $maxBounceRate = intval($this->request->param('max_bounce_rate', 5)); @@ -2624,8 +2624,8 @@ class EmailClient extends Base $expertType = intval($factory['expert_type']); $dailyLimit = max(1, intval($factory['send_count'])); - // 默认频次:expert=30天,内部=60天 - $noRepeatDaysDefault = $expertType === 5 ? 30 : 60; + // 默认频次:expert=15天,内部=20天 + $noRepeatDaysDefault = $expertType === 5 ? 15 : 20; $noRepeatDays = intval($this->request->param('no_repeat_days', $noRepeatDaysDefault)); if ($expertType === 5) { @@ -2734,7 +2734,7 @@ class EmailClient extends Base $query = Db::name('expert')->alias('e') ->join('t_expert_field ef', 'e.expert_id = ef.expert_id', 'inner') - ->where('e.state', 0) +// ->where('e.state', 0) ->where('e.unsubscribed', 0) ->where('ef.state', 0); @@ -2776,11 +2776,16 @@ class EmailClient extends Base $query->where('e.country_id', 'in', $countryIds); } - return $query + $res1 = $query ->field('e.*') ->group('e.expert_id') ->limit($limit) ->select(); + + +// echo $query->getLastSql(); + + return $res1; } /** diff --git a/application/api/controller/Journal.php b/application/api/controller/Journal.php index f785b0bd..e7f5f7fd 100644 --- a/application/api/controller/Journal.php +++ b/application/api/controller/Journal.php @@ -126,6 +126,24 @@ class Journal extends Base { return jsonSuccess($program); } + public function citeMate(){ + $data = $this->request->post(); + $rule = new Validate([ + "journal_id"=>"require", + "year"=>"require" + ]); + if(!$rule->check($data)){ + return jsonError($rule->getError()); + } + $journal_info = $this->journal_obj->where("journal_id",$data['journal_id'])->find(); + $url = "http://journalapi.tmrjournals.com/public/index.php/api/Main/citeMate"; + $program['journal_issn'] = $journal_info['issn']; + $program['year'] = $data['year']; + $res = object_to_array(json_decode(myPost($url,$program))); + + return json($res); + } + public function delJournalStage(){ $data = $this->request->post(); $rule = new Validate([ diff --git a/application/common/CrossrefService.php b/application/common/CrossrefService.php index ca8c5483..e5babfb9 100644 --- a/application/common/CrossrefService.php +++ b/application/common/CrossrefService.php @@ -16,6 +16,10 @@ class CrossrefService private $timeout = 15; // 请求超时(秒) private $maxRetry = 2; // 单个DOI最大重试次数 private $crossrefUrl = "https://api.crossref.org/works/"; // 接口地址 + private $pubmedAbbr = true; // CrossRef 无期刊缩写时,是否回退到 PubMed/NLM 规范缩写 + + /** @var PubmedService|null 懒加载 */ + private $pubmedService = null; public function __construct($config = []) { @@ -24,6 +28,7 @@ class CrossrefService if (isset($config['timeout'])) $this->timeout = intval($config['timeout']); if (isset($config['maxRetry'])) $this->maxRetry = intval($config['maxRetry']); if (isset($config['crossrefUrl'])) $this->crossrefUrl = (string)$config['crossrefUrl']; + if (isset($config['pubmed_abbr'])) $this->pubmedAbbr = (bool)$config['pubmed_abbr']; } } @@ -191,7 +196,15 @@ class CrossrefService $title = $this->getTitle($msg); $publisher = $this->getPublisher($msg); - $joura = !empty($publisher['title']) ? $publisher['title'] : ($publisher['short_title'] ?? ''); + $validDoi = $this->filterValidDoi($doi); + // 期刊缩写优先级:CrossRef short-container-title → PubMed/NLM 规范缩写 → CrossRef 全称 + $shortTitle = trim((string)($publisher['short_title'] ?? '')); + $fullTitle = trim((string)($publisher['title'] ?? '')); + $joura = $shortTitle; + if ($joura === '') { + $pubmedAbbr = $this->lookupPubmedJournalAbbr($validDoi); + $joura = $pubmedAbbr !== '' ? $pubmedAbbr : $fullTitle; + } $authors = $this->getAuthors($msg); $dateno = $this->getVolumeIssuePages($msg); $retractInfo = $this->checkRetracted($msg); @@ -280,6 +293,34 @@ class CrossrefService ]; } + /** + * 用 PubMed/NLM 反查期刊规范缩写(CrossRef 无缩写时的兜底)。 + * 任何异常都吞掉并返回空串,保证不影响主流程。 + * + * @param string $doi 已规整的裸 DOI + * @return string 缩写或空串 + */ + private function lookupPubmedJournalAbbr($doi) + { + $doi = trim((string)$doi); + if (!$this->pubmedAbbr || $doi === '') { + return ''; + } + + try { + if ($this->pubmedService === null) { + $this->pubmedService = new PubmedService([ + 'email' => $this->mailto, + 'timeout' => $this->timeout, + ]); + } + $abbr = $this->pubmedService->journalAbbrByDoi($doi); + return is_string($abbr) ? trim($abbr) : ''; + } catch (\Throwable $e) { + return ''; + } + } + /** * 提取作者列表 */ diff --git a/application/common/PubmedService.php b/application/common/PubmedService.php index ad17e2da..ba5865ee 100644 --- a/application/common/PubmedService.php +++ b/application/common/PubmedService.php @@ -60,7 +60,8 @@ class PubmedService $pmid = trim($pmid); if ($pmid === '') return null; - $cacheKey = 'pmid_' . $pmid; + // v2:解析结果新增 journal_iso_abbr / journal_medline_ta,换 key 避免命中旧缓存 + $cacheKey = 'pmid_v2_' . $pmid; $cached = $this->cacheGet($cacheKey, 30 * 86400); if (is_array($cached)) return $cached; @@ -96,6 +97,22 @@ class PubmedService return $info; } + /** + * DOI -> 期刊规范缩写(NLM/ISO 形式,如 "J Clin Oncol") + * 优先 ISOAbbreviation,回退 MedlineTA;查不到返回 null。 + */ + public function journalAbbrByDoi(string $doi): ?string + { + $info = $this->fetchByDoi($doi); + if (!is_array($info)) return null; + + $abbr = trim((string)($info['journal_iso_abbr'] ?? '')); + if ($abbr === '') { + $abbr = trim((string)($info['journal_medline_ta'] ?? '')); + } + return $abbr !== '' ? $abbr : null; + } + // ----------------- Internals ----------------- private function esearch(string $term): ?string @@ -162,6 +179,9 @@ class PubmedService $pubTypes = array_values(array_unique($pubTypes)); $journal = $this->xpText($xp, '//PubmedArticle//Journal//Title'); + // 期刊规范缩写:ISOAbbreviation(Journal 下)与 MedlineTA(MedlineJournalInfo 下) + $journalIsoAbbr = $this->xpText($xp, '//PubmedArticle//Journal//ISOAbbreviation'); + $journalMedlineTa = $this->xpText($xp, '//PubmedArticle//MedlineJournalInfo//MedlineTA'); $year = ''; $year = $this->xpText($xp, '//PubmedArticle//JournalIssue//PubDate//Year'); @@ -182,6 +202,8 @@ class PubmedService 'mesh_terms' => $mesh, 'publication_types' => $pubTypes, 'journal' => $journal, + 'journal_iso_abbr' => $journalIsoAbbr, + 'journal_medline_ta' => $journalMedlineTa, 'year' => $year, ]; }