参考文献本地大模型校对
This commit is contained in:
@@ -10,7 +10,6 @@ use PhpOffice\PhpWord\IOFactory;
|
||||
use app\common\OpenAi;
|
||||
use app\common\CrossrefService;
|
||||
use app\common\PubmedService;
|
||||
use app\common\ReferenceCheckService;
|
||||
|
||||
/**
|
||||
* @title 文章接口
|
||||
@@ -6392,430 +6391,4 @@ class Article extends Base
|
||||
Db::commit();
|
||||
return json_encode(['status' => 1,'msg' => 'success']);
|
||||
}
|
||||
/**
|
||||
* 调试:预览 article_main 中提取的 blue 引用(不入队)
|
||||
* POST: article_id
|
||||
*/
|
||||
public function citationReview()
|
||||
{
|
||||
$articleId = 7821;//intval($this->request->post('article_id', 0));
|
||||
if ($articleId <= 0) {
|
||||
return jsonError('article_id is required');
|
||||
}
|
||||
|
||||
$svc = new ReferenceCheckService();
|
||||
$mains = Db::name('article_main')
|
||||
->field('am_id,content')
|
||||
->where('article_id', $articleId)
|
||||
->where('am_id', 127448)
|
||||
//->whereIn('state', [0, 2])
|
||||
->order('sort asc')
|
||||
->select();
|
||||
|
||||
$preview = [];
|
||||
foreach ($mains as $item) {
|
||||
$preview[] = [
|
||||
'am_id' => $item['am_id'],
|
||||
'citations' => $svc->extractReferences((string)$item['content']),
|
||||
];
|
||||
break;
|
||||
}
|
||||
return jsonSuccess(['article_id' => $articleId, 'sections' => $preview]);
|
||||
}
|
||||
/**
|
||||
* 提取文献引用
|
||||
*
|
||||
* @param string $content 原始内容
|
||||
* @return array
|
||||
*/
|
||||
function extractReferences($content)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
// 匹配 <blue>[57]</blue>、<blue>[74-79]</blue>、<blue>[72, 45]</blue>
|
||||
preg_match_all(
|
||||
'/<blue>\[([\d,\-\s]+)\]<\/blue>/',
|
||||
$content,
|
||||
$matches,
|
||||
PREG_OFFSET_CAPTURE
|
||||
);
|
||||
|
||||
if (empty($matches[0])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($matches[0] as $index => $match) {
|
||||
|
||||
// 完整标签
|
||||
$fullTag = $match[0];
|
||||
|
||||
// 标签开始位置
|
||||
$tagStart = $match[1];
|
||||
|
||||
// 标签结束位置
|
||||
$tagEnd = $tagStart + strlen($fullTag);
|
||||
|
||||
// 文献号原始字符串
|
||||
$rawRef = trim($matches[1][$index][0]);
|
||||
|
||||
// 展开文献号
|
||||
$referenceNumbers = $this->expandReferenceNumbers($rawRef);
|
||||
|
||||
/**
|
||||
* 获取原文内容
|
||||
* 这里按句号切分:
|
||||
* 找当前引用所在句子的开始和结束位置
|
||||
*/
|
||||
$sentenceStart = $this->findSentenceStart($content, $tagStart);
|
||||
$sentenceEnd = $this->findSentenceEnd($content, $tagEnd);
|
||||
|
||||
$originalText = mb_substr(
|
||||
$content,
|
||||
$sentenceStart,
|
||||
$sentenceEnd - $sentenceStart
|
||||
);
|
||||
|
||||
// 去掉 blue 标签
|
||||
$originalText = preg_replace(
|
||||
'/<blue>\[[\d,\-\s]+\]<\/blue>/',
|
||||
'',
|
||||
$originalText
|
||||
);
|
||||
|
||||
$originalText = trim($originalText);
|
||||
|
||||
$result[] = [
|
||||
'reference_raw' => $rawRef,
|
||||
'reference_numbers' => $referenceNumbers,
|
||||
'original_text' => $originalText,
|
||||
|
||||
// blue标签在整段中的位置
|
||||
'reference_start' => $tagStart,
|
||||
'reference_end' => $tagEnd,
|
||||
|
||||
// 原文位置
|
||||
'text_start' => $sentenceStart,
|
||||
'text_end' => $sentenceEnd,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开文献号
|
||||
* 11-15 => [11,12,13,14,15]
|
||||
* 72,45 => [72,45]
|
||||
* 74-79,81 => [74,75,76,77,78,79,81]
|
||||
*/
|
||||
function expandReferenceNumbers($refStr)
|
||||
{
|
||||
$numbers = [];
|
||||
|
||||
$parts = explode(',', $refStr);
|
||||
|
||||
foreach ($parts as $part) {
|
||||
|
||||
$part = trim($part);
|
||||
|
||||
// 范围
|
||||
if (strpos($part, '-') !== false) {
|
||||
|
||||
list($start, $end) = explode('-', $part);
|
||||
|
||||
$start = intval(trim($start));
|
||||
$end = intval(trim($end));
|
||||
|
||||
if ($start <= $end) {
|
||||
$numbers = array_merge(
|
||||
$numbers,
|
||||
range($start, $end)
|
||||
);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// 单个数字
|
||||
if (is_numeric($part)) {
|
||||
$numbers[] = intval($part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($numbers));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找句子开始位置
|
||||
*/
|
||||
function findSentenceStart($content, $position)
|
||||
{
|
||||
$delimiters = ['.', '。', '!', '?', "\n"];
|
||||
|
||||
$start = 0;
|
||||
|
||||
foreach ($delimiters as $delimiter) {
|
||||
|
||||
$pos = strrpos(
|
||||
substr($content, 0, $position),
|
||||
$delimiter
|
||||
);
|
||||
|
||||
if ($pos !== false) {
|
||||
$start = max($start, $pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $start;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找句子结束位置
|
||||
*/
|
||||
function findSentenceEnd($content, $position)
|
||||
{
|
||||
$length = strlen($content);
|
||||
|
||||
$endPositions = [];
|
||||
|
||||
foreach (['.', '。', '!', '?', "\n"] as $delimiter) {
|
||||
|
||||
$pos = strpos($content, $delimiter, $position);
|
||||
|
||||
if ($pos !== false) {
|
||||
$endPositions[] = $pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return empty($endPositions)
|
||||
? $length
|
||||
: min($endPositions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 引用相关性:提交单条到队列(异步调用 promotion 同款本地大模型)
|
||||
* POST: content_a(必填), content_b(可选), article_id, reference_no(n=index+1), am_id
|
||||
*/
|
||||
public function referenceCheckEnqueue()
|
||||
{
|
||||
$data = $this->request->post();
|
||||
$contentA = trim((string)(isset($data['content_a']) ? $data['content_a'] : ''));
|
||||
$contentB = trim((string)(isset($data['content_b']) ? $data['content_b'] : ''));
|
||||
$articleId = intval(isset($data['article_id']) ? $data['article_id'] : 0);
|
||||
$referenceNo = intval(isset($data['reference_no']) ? $data['reference_no'] : 0);
|
||||
|
||||
if ($contentA === '') {
|
||||
return jsonError('content_a is required');
|
||||
}
|
||||
|
||||
try {
|
||||
$svc = new ReferenceCheckService();
|
||||
$extra = [
|
||||
'reference_no' => $referenceNo,
|
||||
'article_id' => $articleId,
|
||||
'am_id' => intval(isset($data['am_id']) ? $data['am_id'] : 0),
|
||||
];
|
||||
|
||||
if ($contentB === '' && $articleId > 0 && $referenceNo > 0) {
|
||||
$prod = Db::name('production_article')
|
||||
->where('article_id', $articleId)
|
||||
->where('state', 0)
|
||||
->find();
|
||||
if ($prod) {
|
||||
$referMap = $svc->loadReferMapByPArticleId(intval($prod['p_article_id']));
|
||||
$referIndex = $referenceNo - 1;
|
||||
if (isset($referMap[$referIndex])) {
|
||||
$refer = $referMap[$referIndex];
|
||||
$contentB = $svc->formatReferForLlm($refer);
|
||||
$extra['p_article_id'] = intval($prod['p_article_id']);
|
||||
$extra['p_refer_id'] = intval($refer['p_refer_id']);
|
||||
$extra['refer_index'] = $referIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = $svc->enqueue($contentA, $contentB, $extra);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
public function checkOne(){
|
||||
$articleId = intval($this->request->param('article_id', 7414));
|
||||
$svc = new ReferenceCheckService();
|
||||
return jsonSuccess($svc->enqueueSecondPassByArticle($articleId));
|
||||
}
|
||||
public function referenceCheckEnqueueArticleMain(){
|
||||
$amId = 127448;
|
||||
$svc = new ReferenceCheckService();
|
||||
$main = Db::name('article_main')
|
||||
->field('am_id,content,article_id')
|
||||
->where('am_id', $amId)
|
||||
->whereIn('state', [0, 2])
|
||||
->find();
|
||||
$result = $svc->enqueueByArticleMain($main);
|
||||
return jsonSuccess($result);
|
||||
}
|
||||
public function referenceCheckEnqueueArticle(){
|
||||
$data = $this->request->get();
|
||||
$articleId = intval(isset($data['article_id']) ? $data['article_id'] : 0);
|
||||
var_dump($articleId);
|
||||
if ($articleId <= 0) {
|
||||
return jsonError('article_id is required');
|
||||
}
|
||||
try {
|
||||
$svc = new ReferenceCheckService();
|
||||
$result = $svc->enqueueByArticle($articleId);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 按文章批量入队:从 article_main 提取 blue 引用与文献号
|
||||
* POST: article_id, clear_previous=1(默认清空该文旧明细后重检)
|
||||
*/
|
||||
public function referenceCheckEnqueueArticle2()
|
||||
{
|
||||
$data = $this->request->post();
|
||||
$articleId = intval(isset($data['article_id']) ? $data['article_id'] : 0);
|
||||
if ($articleId <= 0) {
|
||||
return jsonError('article_id is required');
|
||||
}
|
||||
|
||||
try {
|
||||
$svc = new ReferenceCheckService();
|
||||
$clear = !isset($data['clear_previous']) || intval($data['clear_previous']) === 1;
|
||||
$result = $svc->enqueueByArticle($articleId, $clear);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单条引用相关性检测结果
|
||||
* GET/POST: check_id
|
||||
*/
|
||||
public function referenceCheckResult()
|
||||
{
|
||||
$checkId = intval($this->request->param('check_id', 0));
|
||||
if ($checkId <= 0) {
|
||||
return jsonError('check_id is required');
|
||||
}
|
||||
|
||||
$row = (new ReferenceCheckService())->getResult($checkId);
|
||||
if (!$row) {
|
||||
return jsonError('result not found');
|
||||
}
|
||||
|
||||
return jsonSuccess($this->formatReferenceCheckRow($row));
|
||||
}
|
||||
|
||||
/**
|
||||
* 稿件预览:带不合理引用标记的 content(序号 + 引用句)
|
||||
* GET/POST: article_id, am_id(可选,只预览某一节)
|
||||
*/
|
||||
public function referenceCheckPreview()
|
||||
{
|
||||
$articleId = intval($this->request->param('article_id', 0));
|
||||
if ($articleId <= 0) {
|
||||
return jsonError('article_id is required');
|
||||
}
|
||||
$amId = intval($this->request->param('am_id', 0));
|
||||
|
||||
try {
|
||||
$data = (new ReferenceCheckService())->buildArticlePreview($articleId, $amId);
|
||||
$data['markup_hint'] = [
|
||||
'ref_no' => '.ref-no-error — 不合理的文献序号(如 70-73 中单独的 70)',
|
||||
'ref_cite' => '.ref-cite-tag.ref-cite-error — 含不合理序号的 blue 引用块',
|
||||
'ref_context'=> '.ref-context-error — 不合理的引用句/上下文',
|
||||
];
|
||||
$data['preview_css'] = '.ref-no-error{color:#c00;font-weight:bold;border-bottom:2px wavy #c00}'
|
||||
. '.ref-cite-tag.ref-cite-error{background:#ffecec}'
|
||||
. '.ref-context-error{background:#fff3cd;outline:1px dashed #e6a700}';
|
||||
return jsonSuccess($data);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文章列出引用校对结果([70-73] 为 4 条,reference_no 分别为 70,71,72,73)
|
||||
* GET/POST: article_id, status(可选), only_mismatch=1 仅不合理
|
||||
*/
|
||||
public function referenceCheckList()
|
||||
{
|
||||
$articleId = intval($this->request->param('article_id', 0));
|
||||
if ($articleId <= 0) {
|
||||
return jsonError('article_id is required');
|
||||
}
|
||||
|
||||
$status = $this->request->param('status', '');
|
||||
$statusFilter = ($status === '' || $status === null) ? -1 : intval($status);
|
||||
$onlyMismatch = intval($this->request->param('only_mismatch', 0)) === 1;
|
||||
$rows = (new ReferenceCheckService())->listByArticle($articleId, $statusFilter, $onlyMismatch);
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$list[] = $this->formatReferenceCheckRow($row);
|
||||
}
|
||||
|
||||
$mains = Db::name('article_main')
|
||||
->field('am_id,ref_check_status,sort')
|
||||
->where('article_id', $articleId)
|
||||
->whereIn('state', [0, 2])
|
||||
->order('sort asc')
|
||||
->select();
|
||||
$sections = [];
|
||||
foreach ($mains as $m) {
|
||||
$st = intval(isset($m['ref_check_status']) ? $m['ref_check_status'] : 0);
|
||||
$sections[] = [
|
||||
'am_id' => intval($m['am_id']),
|
||||
'ref_check_status' => $st,
|
||||
'ref_check_pass' => $st === ReferenceCheckService::AM_STATUS_PASS,
|
||||
'ref_check_label' => ReferenceCheckService::amStatusLabel($st),
|
||||
];
|
||||
}
|
||||
|
||||
return jsonSuccess([
|
||||
'article_id' => $articleId,
|
||||
'total' => count($list),
|
||||
'list' => $list,
|
||||
'sections' => $sections,
|
||||
]);
|
||||
}
|
||||
|
||||
private function formatReferenceCheckRow($row)
|
||||
{
|
||||
$statusMap = array(0 => 'pending', 1 => 'done', 2 => 'failed');
|
||||
$amId = intval(isset($row['am_id']) ? $row['am_id'] : 0);
|
||||
$citeStart = intval(isset($row['cite_tag_start']) ? $row['cite_tag_start'] : 0);
|
||||
$rowStatus = intval($row['status']);
|
||||
return array(
|
||||
'check_id' => intval(isset($row['id']) ? $row['id'] : (isset($row['check_id']) ? $row['check_id'] : 0)),
|
||||
'article_id' => intval(isset($row['article_id']) ? $row['article_id'] : 0),
|
||||
'am_id' => $amId,
|
||||
'cite_group_key' => $amId . '_' . $citeStart,
|
||||
'p_refer_id' => intval(isset($row['p_refer_id']) ? $row['p_refer_id'] : 0),
|
||||
'refer_index' => intval(isset($row['refer_index']) ? $row['refer_index'] : 0),
|
||||
'reference_no' => intval(isset($row['reference_no']) ? $row['reference_no'] : 0),
|
||||
'reference_raw' => isset($row['reference_raw']) ? $row['reference_raw'] : '',
|
||||
'cite_tag_start' => $citeStart,
|
||||
'cite_tag_end' => intval(isset($row['cite_tag_end']) ? $row['cite_tag_end'] : 0),
|
||||
'text_start' => intval(isset($row['text_start']) ? $row['text_start'] : 0),
|
||||
'text_end' => intval(isset($row['text_end']) ? $row['text_end'] : 0),
|
||||
'status' => isset($statusMap[$rowStatus]) ? $statusMap[$rowStatus] : 'unknown',
|
||||
'is_match' => intval($row['is_match']),
|
||||
'can_support' => intval(isset($row['can_support']) ? $row['can_support'] : $row['is_match']),
|
||||
'is_reasonable' => intval(isset($row['can_support']) ? $row['can_support'] : $row['is_match']) === 1,
|
||||
'confidence' => floatval($row['confidence']),
|
||||
'reason' => isset($row['reason']) ? $row['reason'] : '',
|
||||
'error_msg' => isset($row['error_msg']) ? $row['error_msg'] : '',
|
||||
'content_a' => isset($row['content_a']) ? $row['content_a'] : '',
|
||||
'content_b' => isset($row['content_b']) ? $row['content_b'] : '',
|
||||
'updated_at' => isset($row['updated_at']) ? $row['updated_at'] : '',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -271,6 +271,14 @@ class Base extends Controller
|
||||
}
|
||||
$this->production_article_refer_obj->where('p_article_id', $refer_info['p_article_id'])->where('index', ">", $refer_info['index'])->where('state', 0)->setDec('index');
|
||||
$this->production_article_refer_obj->where('p_refer_id', $p_refer_id)->update(['state' => 1]);
|
||||
|
||||
// 文献集合已变更,原校对结果的 reference_no 已全部错位,整篇标记为未校对
|
||||
try {
|
||||
(new \app\common\ReferenceCheckService())
|
||||
->clearArticleChecksByPArticleId(intval($refer_info['p_article_id']));
|
||||
} catch (\Exception $e) {
|
||||
\think\Log::error('delOneRefer clearArticleChecksByPArticleId p_refer_id=' . $p_refer_id . ' ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use think\Env;
|
||||
use think\Queue;
|
||||
use think\Validate;
|
||||
use app\common\CrossrefService;
|
||||
use app\common\ReferenceCheckService;
|
||||
|
||||
class Preaccept extends Base
|
||||
{
|
||||
@@ -15,6 +16,26 @@ class Preaccept extends Base
|
||||
parent::__construct($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增/修改导致文献集合改变后,清空整篇校对明细,使文章状态回到"未校对"。
|
||||
* 失败仅记日志,不阻塞主流程。
|
||||
*/
|
||||
private function resetArticleChecksOnReferChange($pArticleId, $sourceTag = '')
|
||||
{
|
||||
$pArticleId = intval($pArticleId);
|
||||
if ($pArticleId <= 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
(new ReferenceCheckService())->clearArticleChecksByPArticleId($pArticleId);
|
||||
} catch (\Exception $e) {
|
||||
\think\Log::error(
|
||||
'resetArticleChecksOnReferChange[' . $sourceTag . '] p_article_id='
|
||||
. $pArticleId . ' ' . $e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**获取文章参考文献列表
|
||||
* @return \think\response\Json
|
||||
@@ -92,6 +113,7 @@ class Preaccept extends Base
|
||||
return jsonError($rule->getError());
|
||||
}
|
||||
$this->production_article_refer_obj->where('p_article_id',$data['p_article_id'])->update(["state"=>1]);
|
||||
$this->resetArticleChecksOnReferChange(intval($data['p_article_id']), 'discardRefersByParticleid');
|
||||
return jsonSuccess([]);
|
||||
}
|
||||
|
||||
@@ -142,6 +164,7 @@ class Preaccept extends Base
|
||||
}
|
||||
$adId= $this->production_article_refer_obj->insertGetId($insert);
|
||||
$this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where("p_refer_id", "<>", $adId)->where("index", ">", $pre_refer['index'])->where('state', 0)->setInc('index');
|
||||
$this->resetArticleChecksOnReferChange(intval($p_info['p_article_id']), 'addRefer');
|
||||
return jsonSuccess([]);
|
||||
|
||||
|
||||
@@ -198,6 +221,7 @@ class Preaccept extends Base
|
||||
}
|
||||
$adId= $this->production_article_refer_obj->insertGetId($insert);
|
||||
$this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where("p_refer_id", "<>", $adId)->where("index", ">", $pre_refer['index'])->where('state', 0)->setInc('index');
|
||||
$this->resetArticleChecksOnReferChange(intval($p_info['p_article_id']), 'addReferByParticleid');
|
||||
return jsonSuccess([]);
|
||||
}
|
||||
|
||||
@@ -233,6 +257,7 @@ class Preaccept extends Base
|
||||
$insert['cs'] = 1;
|
||||
$adId = $this->production_article_refer_obj->insertGetId($insert);
|
||||
$this->production_article_refer_obj->where('p_article_id', $p_info['p_article_id'])->where("p_refer_id", "<>", $adId)->where("index", ">", $pre_refer['index'])->where('state', 0)->setInc('index');
|
||||
$this->resetArticleChecksOnReferChange(intval($p_info['p_article_id']), 'addReferNotdoi');
|
||||
return jsonSuccess([]);
|
||||
}
|
||||
|
||||
@@ -462,6 +487,17 @@ class Preaccept extends Base
|
||||
// }
|
||||
// $this->production_article_refer_obj->where('p_refer_id', $data['p_refer_id'])->update(['refer_doi' => $data['doi']]);
|
||||
// my_doiToFrag2($this->production_article_refer_obj->where('p_refer_id', $data['p_refer_id'])->find());
|
||||
|
||||
//文献内容更新成功后异步重检该文献对应的全部校对明细(失败不阻塞主流程)
|
||||
try {
|
||||
(new ReferenceCheckService())->enqueueRecheckByPReferId(
|
||||
intval($data['p_refer_id']),
|
||||
intval($old_refer_info['p_article_id'])
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
\think\Log::error('editRefer enqueueRecheckByPReferId p_refer_id=' . $data['p_refer_id'] . ' ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return jsonSuccess([]);
|
||||
}
|
||||
|
||||
@@ -1453,6 +1489,7 @@ class Preaccept extends Base
|
||||
return jsonError($rule->getError());
|
||||
}
|
||||
$refer_info = $this->production_article_refer_obj->where('p_refer_id', $data['p_refer_id'])->find();
|
||||
$sibling_p_refer_id = 0;
|
||||
if ($data['act'] == "up") {
|
||||
$up_info = $this->production_article_refer_obj->where('p_article_id', $refer_info['p_article_id'])->where('index', $refer_info['index'] - 1)->where('state', 0)->find();
|
||||
if (!$up_info) {
|
||||
@@ -1460,6 +1497,7 @@ class Preaccept extends Base
|
||||
}
|
||||
$this->production_article_refer_obj->where('p_refer_id', $up_info['p_refer_id'])->setInc("index");
|
||||
$this->production_article_refer_obj->where('p_refer_id', $refer_info['p_refer_id'])->setDec("index");
|
||||
$sibling_p_refer_id = intval($up_info['p_refer_id']);
|
||||
} else {
|
||||
$down_info = $this->production_article_refer_obj->where('p_article_id', $refer_info['p_article_id'])->where('index', $refer_info['index'] + 1)->where('state', 0)->find();
|
||||
if (!$down_info) {
|
||||
@@ -1467,7 +1505,19 @@ class Preaccept extends Base
|
||||
}
|
||||
$this->production_article_refer_obj->where('p_refer_id', $refer_info['p_refer_id'])->setInc("index");
|
||||
$this->production_article_refer_obj->where('p_refer_id', $down_info['p_refer_id'])->setDec("index");
|
||||
$sibling_p_refer_id = intval($down_info['p_refer_id']);
|
||||
}
|
||||
|
||||
// 仅同步本次交换的两条 p_refer_id 对应的校对明细 reference_no / refer_index
|
||||
try {
|
||||
(new ReferenceCheckService())->syncReferenceNoByPReferIds(
|
||||
[intval($refer_info['p_refer_id']), $sibling_p_refer_id],
|
||||
intval($refer_info['p_article_id'])
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
\think\Log::error('sortRefer syncReferenceNoByPReferIds: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return jsonSuccess([]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1307,4 +1307,231 @@ class References extends Base
|
||||
}
|
||||
return json_encode(['status' => 8,'msg' => 'fail']);
|
||||
}
|
||||
/**
|
||||
* 参考文献第一次校对
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function allReferenceCheckAI(){
|
||||
//获取参数
|
||||
$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' ));
|
||||
}
|
||||
//查询文章(p_article_id 与 article_id 都要带,下游服务方法两者都用)
|
||||
$aWhere = ['p_article_id' => $iPArticleId,'state' => ['in',[0,2]]];
|
||||
$aProductionArticle = Db::name('production_article')->field('p_article_id,article_id')->where($aWhere)->find();
|
||||
if(empty($aProductionArticle)){
|
||||
return json_encode(array('status' => 3,'msg' => 'No articles found' ));
|
||||
}
|
||||
if($this->checkReferStatus($iPArticleId)==0){
|
||||
return jsonError('请修正完文献内容再进行校对。');
|
||||
}
|
||||
//已存在校对记录则禁止重复执行第一次校对,提示走重置接口
|
||||
$iExisting = Db::name('article_reference_check_result')
|
||||
->where('p_article_id', $iPArticleId)
|
||||
->count();
|
||||
if(intval($iExisting) > 0){
|
||||
return jsonError('该文章已存在校对记录,请使用"重置校对"接口重新校对。');
|
||||
}
|
||||
try {
|
||||
$svc = new ReferenceCheckService();
|
||||
$result = $svc->enqueueByPArticle($aProductionArticle);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 文献校对重置:删除该文章已有的全部校对明细,并重新入队整篇校对
|
||||
* POST/GET: article_id(必填)
|
||||
* @url /api/Article/referenceCheckReset
|
||||
*/
|
||||
public function referenceCheckResetAI()
|
||||
{
|
||||
//获取参数
|
||||
$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' ));
|
||||
}
|
||||
//查询文章(p_article_id 与 article_id 都要带,下游服务方法两者都用)
|
||||
$aWhere = ['p_article_id' => $iPArticleId,'state' => ['in',[0,2]]];
|
||||
$aProductionArticle = Db::name('production_article')->field('p_article_id,article_id')->where($aWhere)->find();
|
||||
if(empty($aProductionArticle)){
|
||||
return json_encode(array('status' => 3,'msg' => 'No articles found' ));
|
||||
}
|
||||
if($this->checkReferStatus($iPArticleId)==0){
|
||||
return jsonError('请修正完文献内容再进行校对。');
|
||||
}
|
||||
$iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(array('status' => 4,'msg' => 'Unbound article' ));
|
||||
}
|
||||
try {
|
||||
$result = (new ReferenceCheckService())->resetAndRecheckByArticle($aProductionArticle);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空某篇文章下的全部参考文献校对记录(不重新入队)
|
||||
*
|
||||
* 与 referenceCheckResetAI 的区别:reset 是「清空 + 重新校对」,
|
||||
* 这里只做「清空」一步,校对状态回到未校对,等待用户手动再触发。
|
||||
*
|
||||
* POST/GET: p_article_id(必填)
|
||||
*/
|
||||
public function referenceCheckClearAI()
|
||||
{
|
||||
$aParam = $this->request->post();
|
||||
if (empty($aParam)) {
|
||||
$aParam = $this->request->param();
|
||||
}
|
||||
|
||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||
if ($iPArticleId <= 0) {
|
||||
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
||||
}
|
||||
|
||||
// 校验文章存在(与其它校对接口口径一致:state in [0,2])
|
||||
$aProductionArticle = Db::name('production_article')
|
||||
->field('p_article_id,article_id')
|
||||
->where(['p_article_id' => $iPArticleId, 'state' => ['in', [0, 2]]])
|
||||
->find();
|
||||
if (empty($aProductionArticle)) {
|
||||
return json_encode(array('status' => 3, 'msg' => 'No articles found'));
|
||||
}
|
||||
|
||||
try {
|
||||
$deleted = (new ReferenceCheckService())->clearArticleChecksByPArticleId($iPArticleId);
|
||||
return jsonSuccess([
|
||||
'p_article_id' => $iPArticleId,
|
||||
'deleted' => intval($deleted),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 p_article_id 查整篇引用校对进度(按 reference_no 分组聚合)
|
||||
*
|
||||
* POST/GET: p_article_id(必填)
|
||||
*
|
||||
* 返回 list 中每项含:reference_no、p_refer_id、status(数值)、
|
||||
* total、pending、done、failed、pass、is_pass、last_updated_at、records
|
||||
*
|
||||
* status 数值含义:
|
||||
* 0 = 待校验 1 = 校对中 2 = 校对完成 3 = 校对失败
|
||||
*/
|
||||
public function referenceCheckProgressAI()
|
||||
{
|
||||
$aParam = $this->request->post();
|
||||
if (empty($aParam)) {
|
||||
$aParam = $this->request->param();
|
||||
}
|
||||
|
||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||
if ($iPArticleId <= 0) {
|
||||
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
||||
}
|
||||
try {
|
||||
$result = (new ReferenceCheckService())->getProgressByPArticleId($iPArticleId);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 p_article_id 查整篇文章引用校对总状态(用于前端按钮分流)
|
||||
*
|
||||
* POST/GET: p_article_id(必填)
|
||||
*
|
||||
* 计数维度是「参考文献」(按 reference_no 分组),不是单条校对明细行。
|
||||
* 例:50 条参考文献、底层 111 条校对明细时,total = 50。
|
||||
*
|
||||
* 返回 status 数值含义(整篇):
|
||||
* 0 = 未校对(一条记录都没有)
|
||||
* 1 = 校对中(至少 1 条参考文献仍有未跑完的明细)
|
||||
* 2 = 校对完成(所有参考文献全部明细已结束)
|
||||
*
|
||||
* 返回字段:p_article_id、status、total、pending、done、failed、progress_percent
|
||||
* total —— 参考文献条数
|
||||
* pending —— 该条参考文献仍有未跑完明细的数量(含"部分跑完")
|
||||
* done —— 该条参考文献所有明细都 status=1 的数量
|
||||
* failed —— 该条参考文献全部跑完且至少 1 条 status=2 的数量
|
||||
* pending + done + failed = total;progress_percent = (done+failed)/total
|
||||
*
|
||||
* 分组明细请走 referenceCheckProgressAI。
|
||||
*/
|
||||
public function referenceCheckArticleStatusAI()
|
||||
{
|
||||
$aParam = $this->request->post();
|
||||
if (empty($aParam)) {
|
||||
$aParam = $this->request->param();
|
||||
}
|
||||
|
||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||
if ($iPArticleId <= 0) {
|
||||
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
||||
}
|
||||
|
||||
try {
|
||||
$result = (new ReferenceCheckService())->getArticleProgressStatusByPArticleId($iPArticleId);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 p_refer_id 查单条参考文献的校对明细
|
||||
*
|
||||
* POST/GET: p_refer_id(必填)
|
||||
*
|
||||
* 返回 list 中每项含:am_id、confidence、reason、is_match、is_pass
|
||||
* 同时附带上下文:p_refer_id、p_article_id、reference_no、total
|
||||
*/
|
||||
public function referenceCheckDetailsAI()
|
||||
{
|
||||
$aParam = $this->request->post();
|
||||
if (empty($aParam)) {
|
||||
$aParam = $this->request->param();
|
||||
}
|
||||
|
||||
$iPReferId = empty($aParam['p_refer_id']) ? 0 : intval($aParam['p_refer_id']);
|
||||
if ($iPReferId <= 0) {
|
||||
return json_encode(array('status' => 2, 'msg' => 'Please select a reference'));
|
||||
}
|
||||
|
||||
try {
|
||||
$result = (new ReferenceCheckService())->getCheckDetailsByPReferId($iPReferId);
|
||||
return jsonSuccess($result);
|
||||
} catch (\Exception $e) {
|
||||
return jsonError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function checkReferStatus($p_article_id){
|
||||
$list = $this->production_article_refer_obj->where('p_article_id', $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;
|
||||
}
|
||||
}
|
||||
return $frag;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user