1
This commit is contained in:
@@ -1131,6 +1131,9 @@ class Preaccept extends Base
|
|||||||
return jsonError($rule->getError());
|
return jsonError($rule->getError());
|
||||||
}
|
}
|
||||||
$am_info = $this->article_main_obj->where("am_id",$data['am_id'])->find();
|
$am_info = $this->article_main_obj->where("am_id",$data['am_id'])->find();
|
||||||
|
$old_content = $am_info['content'];
|
||||||
|
$new_raw_content = isset($data['content']) ? (string)$data['content'] : '';
|
||||||
|
|
||||||
$insert['article_id'] = $am_info['article_id'];
|
$insert['article_id'] = $am_info['article_id'];
|
||||||
$insert['am_id'] = $data['am_id'];
|
$insert['am_id'] = $data['am_id'];
|
||||||
$insert['type'] = 0;
|
$insert['type'] = 0;
|
||||||
@@ -1140,11 +1143,21 @@ class Preaccept extends Base
|
|||||||
$insert['ctime'] = time();
|
$insert['ctime'] = time();
|
||||||
$this->article_main_log_obj->insert($insert);
|
$this->article_main_log_obj->insert($insert);
|
||||||
|
|
||||||
|
// 判断是否存在“引用删除”(新 content 相对旧 content 缺少 <mycite>)
|
||||||
|
$hasCitationDeletion = $this->hasMyciteDeletion($old_content, $new_raw_content);
|
||||||
|
|
||||||
|
$update['content'] = $this->formatMain($new_raw_content);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$update['content'] = $this->formatMain($data['content']);
|
|
||||||
$update['state'] = 0;
|
$update['state'] = 0;
|
||||||
$this->article_main_obj->where("am_id",$data['am_id'])->update($update);
|
$this->article_main_obj->where("am_id",$data['am_id'])->update($update);
|
||||||
|
|
||||||
|
// 若检测到引用删除,则进行全文扫描并标记未被引用条目的 is_used=0(含 table 内容)
|
||||||
|
if ($hasCitationDeletion) {
|
||||||
|
// $this->markUnusedReferencesForArticle(intval($am_info['article_id']));
|
||||||
|
}
|
||||||
// return jsonSuccess([]);
|
// return jsonSuccess([]);
|
||||||
//返回更新数据 20260119 start
|
//返回更新数据 20260119 start
|
||||||
$update = empty($update) ? [] : array_merge($update,['am_id' => empty($data['am_id']) ? 0 : $data['am_id']]);
|
$update = empty($update) ? [] : array_merge($update,['am_id' => empty($data['am_id']) ? 0 : $data['am_id']]);
|
||||||
@@ -1155,6 +1168,121 @@ class Preaccept extends Base
|
|||||||
//返回更新数据 20260119 end
|
//返回更新数据 20260119 end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否发生 <mycite> 删除(new 相对 old 少了任意引用 id)
|
||||||
|
*/
|
||||||
|
private function hasMyciteDeletion(string $oldContent, string $newContent): bool
|
||||||
|
{
|
||||||
|
$oldIds = $this->extractMyciteIds($oldContent);
|
||||||
|
if (empty($oldIds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$newIds = $this->extractMyciteIds($newContent);
|
||||||
|
|
||||||
|
// old 有引用,new 为空 => 删除
|
||||||
|
if (empty($newIds)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$oldSet = array_fill_keys($oldIds, 1);
|
||||||
|
$newSet = array_fill_keys($newIds, 1);
|
||||||
|
foreach ($oldSet as $id => $_) {
|
||||||
|
if (!isset($newSet[$id])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文本/HTML 中提取 <mycite data-id="1,2,3"> 的 id 列表
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
private function extractMyciteIds(string $text): array
|
||||||
|
{
|
||||||
|
if ($text === '') return [];
|
||||||
|
$ids = [];
|
||||||
|
if (preg_match_all('/<\s*mycite\b[^>]*\bdata-id\s*=\s*(["\'])(.*?)\1[^>]*>/iu', $text, $m)) {
|
||||||
|
foreach ($m[2] as $raw) {
|
||||||
|
$raw = trim((string)$raw);
|
||||||
|
if ($raw === '') continue;
|
||||||
|
$parts = preg_split('/\s*,\s*/', $raw);
|
||||||
|
foreach ($parts as $p) {
|
||||||
|
$p = trim((string)$p);
|
||||||
|
if ($p === '') continue;
|
||||||
|
$v = intval($p);
|
||||||
|
if ($v > 0) $ids[] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ids = array_values(array_unique($ids));
|
||||||
|
sort($ids);
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全文扫描(正文 + table),将 production_article_refer 未被引用的条目标记 is_used=0
|
||||||
|
* - 被引用的条目 is_used=1
|
||||||
|
*
|
||||||
|
* 注意:依赖 production_article_refer 表存在 is_used 字段(int/tinyint)
|
||||||
|
*/
|
||||||
|
private function markUnusedReferencesForArticle(int $articleId)
|
||||||
|
{
|
||||||
|
if ($articleId <= 0) return;
|
||||||
|
|
||||||
|
$production = Db::name('production_article')
|
||||||
|
->where('article_id', $articleId)
|
||||||
|
->where('state', 0)
|
||||||
|
->field('p_article_id')
|
||||||
|
->find();
|
||||||
|
$pArticleId = intval($production['p_article_id'] ?? 0);
|
||||||
|
if ($pArticleId <= 0) return;
|
||||||
|
|
||||||
|
// 1) 收集已使用的 p_refer_id
|
||||||
|
$usedIds = [];
|
||||||
|
|
||||||
|
$mains = Db::name('article_main')
|
||||||
|
->where('article_id', $articleId)
|
||||||
|
->whereIn('state', [0, 2])
|
||||||
|
->field('content')
|
||||||
|
->select();
|
||||||
|
foreach ($mains as $row) {
|
||||||
|
$usedIds = array_merge($usedIds, $this->extractMyciteIds((string)($row['content'] ?? '')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$tables = Db::name('article_main_table')
|
||||||
|
->where('article_id', $articleId)
|
||||||
|
->where('state', 0)
|
||||||
|
->field('table_data,html_data,title,note')
|
||||||
|
->select();
|
||||||
|
foreach ($tables as $row) {
|
||||||
|
$usedIds = array_merge($usedIds, $this->extractMyciteIds((string)($row['table_data'] ?? '')));
|
||||||
|
$usedIds = array_merge($usedIds, $this->extractMyciteIds((string)($row['html_data'] ?? '')));
|
||||||
|
$usedIds = array_merge($usedIds, $this->extractMyciteIds((string)($row['title'] ?? '')));
|
||||||
|
$usedIds = array_merge($usedIds, $this->extractMyciteIds((string)($row['note'] ?? '')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$usedIds = array_values(array_unique($usedIds));
|
||||||
|
|
||||||
|
// 2) 标记:先全置 0,再把用到的置 1
|
||||||
|
try {
|
||||||
|
Db::name('production_article_refer')
|
||||||
|
->where('p_article_id', $pArticleId)
|
||||||
|
->where('state', 0)
|
||||||
|
->update(['is_used' => 0, 'update_time' => time()]);
|
||||||
|
|
||||||
|
if (!empty($usedIds)) {
|
||||||
|
Db::name('production_article_refer')
|
||||||
|
->where('p_article_id', $pArticleId)
|
||||||
|
->where('state', 0)
|
||||||
|
->whereIn('p_refer_id', $usedIds)
|
||||||
|
->update(['is_used' => 1, 'update_time' => time()]);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// 工具方法:不影响主流程,忽略异常(可按需改为记录日志)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getArticleMainsRecycle(){
|
public function getArticleMainsRecycle(){
|
||||||
$data = $this->request->post();
|
$data = $this->request->post();
|
||||||
$rule = new Validate([
|
$rule = new Validate([
|
||||||
|
|||||||
@@ -526,31 +526,40 @@ class References extends Base
|
|||||||
* - type (可选):默认 0(仅文本 main),传空则处理所有 type
|
* - type (可选):默认 0(仅文本 main),传空则处理所有 type
|
||||||
* - dry_run (可选):1=只预览不落库
|
* - dry_run (可选):1=只预览不落库
|
||||||
*/
|
*/
|
||||||
public function convertArticleMainCitationsToMycite($aParam = [])
|
public function convertArticleMainCitationsToMycite()
|
||||||
{
|
{
|
||||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
// $aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||||
$pArticleId = intval($aParam['p_article_id'] ?? 0);
|
// $pArticleId = intval($aParam['p_article_id'] ?? 0);
|
||||||
if ($pArticleId <= 0) {
|
// if ($pArticleId <= 0) {
|
||||||
return jsonError('p_article_id is required');
|
// return jsonError('p_article_id is required');
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// // 通过 production_article -> article_id,确保是当前系统存在的文章
|
||||||
|
// $aArticle = $this->getArticle(['p_article_id' => $pArticleId]);
|
||||||
|
// $iStatus = empty($aArticle['status']) ? 0 : $aArticle['status'];
|
||||||
|
// if ($iStatus != 1) {
|
||||||
|
// return json_encode($aArticle);
|
||||||
|
// }
|
||||||
|
// $aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
||||||
|
// $articleId = intval($aArticle['article_id'] ?? 0);
|
||||||
|
// if ($articleId <= 0) {
|
||||||
|
// return jsonError('Article not found');
|
||||||
|
// }
|
||||||
|
|
||||||
// 通过 production_article -> article_id,确保是当前系统存在的文章
|
$aParam = $this->request->post();
|
||||||
$aArticle = $this->getArticle(['p_article_id' => $pArticleId]);
|
$rule = new Validate([
|
||||||
$iStatus = empty($aArticle['status']) ? 0 : $aArticle['status'];
|
"article_id"=>"require"
|
||||||
if ($iStatus != 1) {
|
]);
|
||||||
return json_encode($aArticle);
|
if(!$rule->check($aParam)){
|
||||||
|
return jsonError($rule->getError());
|
||||||
}
|
}
|
||||||
$aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
|
||||||
$articleId = intval($aArticle['article_id'] ?? 0);
|
|
||||||
if ($articleId <= 0) {
|
|
||||||
return jsonError('Article not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
$dryRun = intval($aParam['dry_run'] ?? 0) === 1;
|
$dryRun = intval($aParam['dry_run'] ?? 0) === 1;
|
||||||
$type = isset($aParam['type']) ? $aParam['type'] : 0;
|
$type = $aParam['type'] ?? 0;
|
||||||
|
|
||||||
|
$p_info = $this->production_article_obj->where('article_id', $aParam['article_id'])->where('state', 0)->find();
|
||||||
|
$pArticleId = $p_info['p_article_id'];
|
||||||
$query = Db::name('article_main')
|
$query = Db::name('article_main')
|
||||||
->where('article_id', $articleId)
|
->where('article_id', $aParam['article_id'])
|
||||||
->whereIn('state', [0, 2])
|
->whereIn('state', [0, 2])
|
||||||
->order('sort asc');
|
->order('sort asc');
|
||||||
if ($type !== '' && $type !== null) {
|
if ($type !== '' && $type !== null) {
|
||||||
@@ -593,8 +602,7 @@ class References extends Base
|
|||||||
->where('am_id', $amId)
|
->where('am_id', $amId)
|
||||||
->limit(1)
|
->limit(1)
|
||||||
->update([
|
->update([
|
||||||
'content' => $new,
|
'content' => $new
|
||||||
'update_time' => time(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -610,7 +618,7 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
return jsonSuccess([
|
return jsonSuccess([
|
||||||
'article_id' => $articleId,
|
'article_id' => $aParam['article_id'],
|
||||||
'p_article_id' => $pArticleId,
|
'p_article_id' => $pArticleId,
|
||||||
'dry_run' => $dryRun ? 1 : 0,
|
'dry_run' => $dryRun ? 1 : 0,
|
||||||
'total' => count($mains),
|
'total' => count($mains),
|
||||||
@@ -619,6 +627,97 @@ class References extends Base
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新 production_article_refer
|
||||||
|
*
|
||||||
|
* 参数:
|
||||||
|
* - list(必填):数组,每项至少含 p_refer_id,其余为可更新字段
|
||||||
|
* - p_article_id(可选):若传则校验每条记录均属该生产文章,防止误改
|
||||||
|
*
|
||||||
|
* 可更新字段(白名单):author,title,joura,dateno,doilink,doi,refer_doi,refer_content,refer_frag,
|
||||||
|
* refer_type,isbn,index,is_change,is_ai_check,cs,is_ja,article_id
|
||||||
|
*/
|
||||||
|
public function batchUpdateRefer($aParam = [])
|
||||||
|
{
|
||||||
|
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||||
|
$list = isset($aParam['list']) ? $aParam['list'] : (isset($aParam['refer_list']) ? $aParam['refer_list'] : null);
|
||||||
|
if (is_string($list)) {
|
||||||
|
$list = json_decode($list, true);
|
||||||
|
}
|
||||||
|
if (!is_array($list) || $list === []) {
|
||||||
|
return jsonError('list is required and must be a non-empty array');
|
||||||
|
}
|
||||||
|
|
||||||
|
$pArticleIdCheck = isset($aParam['p_article_id']) ? intval($aParam['p_article_id']) : 0;
|
||||||
|
|
||||||
|
$allowed = [
|
||||||
|
'author', 'title', 'joura', 'dateno', 'doilink', 'doi', 'refer_doi',
|
||||||
|
'refer_content', 'refer_frag', 'refer_type', 'isbn', 'index',
|
||||||
|
'is_change', 'is_ai_check', 'cs', 'is_ja', 'article_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
$ok = 0;
|
||||||
|
$failed = [];
|
||||||
|
|
||||||
|
Db::startTrans();
|
||||||
|
try {
|
||||||
|
foreach ($list as $idx => $row) {
|
||||||
|
if (!is_array($row)) {
|
||||||
|
$failed[] = ['index' => $idx, 'msg' => 'item must be object'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$pReferId = intval(isset($row['p_refer_id']) ? $row['p_refer_id'] : 0);
|
||||||
|
if ($pReferId <= 0) {
|
||||||
|
$failed[] = ['index' => $idx, 'msg' => 'p_refer_id is required'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$where = ['p_refer_id' => $pReferId, 'state' => 0];
|
||||||
|
$exist = Db::name('production_article_refer')->where($where)->find();
|
||||||
|
if (empty($exist)) {
|
||||||
|
$failed[] = ['p_refer_id' => $pReferId, 'msg' => 'reference not found or state!=0'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($pArticleIdCheck > 0 && intval($exist['p_article_id']) !== $pArticleIdCheck) {
|
||||||
|
$failed[] = ['p_refer_id' => $pReferId, 'msg' => 'p_article_id mismatch'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$update = [];
|
||||||
|
foreach ($allowed as $field) {
|
||||||
|
if (array_key_exists($field, $row)) {
|
||||||
|
$update[$field] = $row[$field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($update === []) {
|
||||||
|
$failed[] = ['p_refer_id' => $pReferId, 'msg' => 'no updatable fields'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$update['update_time'] = time();
|
||||||
|
if (!isset($update['is_change'])) {
|
||||||
|
$update['is_change'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Db::name('production_article_refer')->where($where)->limit(1)->update($update);
|
||||||
|
if ($result === false) {
|
||||||
|
$failed[] = ['p_refer_id' => $pReferId, 'msg' => 'update failed'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ok++;
|
||||||
|
}
|
||||||
|
Db::commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Db::rollback();
|
||||||
|
return jsonError('batch update failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonSuccess([
|
||||||
|
'updated' => $ok,
|
||||||
|
'failed' => $failed,
|
||||||
|
'total' => count($list),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改参考文献的信息
|
* 修改参考文献的信息
|
||||||
* @param p_refer_id 主键ID
|
* @param p_refer_id 主键ID
|
||||||
|
|||||||
Reference in New Issue
Block a user