Merge remote-tracking branch 'remotes/origin/checkrefer'

This commit is contained in:
wyn
2026-05-26 18:06:25 +08:00
8 changed files with 4429 additions and 0 deletions

View File

@@ -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());
}
}

View File

@@ -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([]);
}

View File

@@ -1308,4 +1308,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 = totalprogress_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;
}
}