diff --git a/scripts/news-review.php b/scripts/news-review.php new file mode 100644 index 0000000..6d8de04 --- /dev/null +++ b/scripts/news-review.php @@ -0,0 +1,68 @@ +make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + +use Illuminate\Support\Facades\DB; + +$arguments = array_slice($argv, 1); +if (array_diff($arguments, ['--apply'])) { + fwrite(STDERR, "用法:php scripts/news-review.php [--apply]\n"); + exit(1); +} +$apply = in_array('--apply', $arguments, true); +try { + $result = DB::transaction(function () use ($apply) { + // Same lock as the collector: prevents collection starting during the update. + $control = DB::table('company_news_control')->where('id', 1)->lockForUpdate()->first(); + if (!$control) throw new RuntimeException('缺少采集控制记录,请先执行迁移'); + if ($control->active_batch_id) throw new RuntimeException('存在未完成的采集批次,请先完成该批次'); + $settings = DB::table('company_news_settings')->where('id', 1)->lockForUpdate()->first(); + $codes = json_decode($settings->retained_categories ?? '[]', true, 512, JSON_THROW_ON_ERROR); + if (!is_array($codes) || !$codes) throw new RuntimeException('尚未选择留存分类,请先保存分类设置'); + foreach ($codes as $code) { + if (!is_string($code)) throw new RuntimeException('分类代码格式异常,未执行更新'); + } + $counts = ['categories' => count(array_unique($codes)), 'total' => 0, 'retained' => 0, 'discarded' => 0, 'changed' => 0]; + $query = DB::table('company_news')->select('id', 'categories', 'review_status')->orderBy('id'); + if ($apply) $query->lockForUpdate(); + $query->chunkById(200, function ($rows) use ($codes, $apply, &$counts) { + foreach ($rows as $row) { + $categories = json_decode($row->categories ?? '[]', true, 512, JSON_THROW_ON_ERROR) ?? []; + if (!is_array($categories)) throw new RuntimeException('新闻 '.$row->id.' 分类格式异常,已取消本次操作'); + $status = array_intersect(array_column($categories, 'code'), $codes) ? 'retained' : 'discarded'; + $counts['total']++; + $counts[$status]++; + if ($row->review_status === $status) continue; + $counts['changed']++; + if (!$apply) continue; + DB::table('company_news')->where('id', $row->id)->update(['review_status' => $status]); + DB::table('company_news_logs')->insert([ + 'news_id' => $row->id, 'actor_id' => null, 'action' => 'review', + 'detail' => json_encode([ + 'source' => 'news-review.php:按保存的分类设置批量更新', + 'from' => $row->review_status, 'to' => $status, 'category_codes' => $codes, + ], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR), + 'created_at' => now(), + ]); + } + }); + return $counts; + }); + echo $apply ? "更新完成\n" : "仅预览,未修改任何新闻\n"; + echo "已选分类:{$result['categories']}\n新闻总数:{$result['total']}\n分类后已留存:{$result['retained']}\n分类后不留存:{$result['discarded']}\n"; + echo ($apply ? '实际修改:' : '预计修改:').$result['changed']."\n"; + if (!$apply) echo "确认后执行:php scripts/news-review.php --apply\n"; +} catch (Throwable $error) { + fwrite(STDERR, '执行失败:'.$error->getMessage()."\n"); + exit(1); +}