|
|
|
|
@ -0,0 +1,68 @@
|
|
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* Preview: php scripts/news-review.php
|
|
|
|
|
* Apply: php scripts/news-review.php --apply
|
|
|
|
|
* Uses saved category settings; changes only review_status and appends audit logs.
|
|
|
|
|
*/
|
|
|
|
|
if (PHP_SAPI !== 'cli') {
|
|
|
|
|
http_response_code(403);
|
|
|
|
|
exit('CLI only');
|
|
|
|
|
}
|
|
|
|
|
require dirname(__DIR__).'/vendor/autoload.php';
|
|
|
|
|
$app = require dirname(__DIR__).'/bootstrap/app.php';
|
|
|
|
|
$app->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);
|
|
|
|
|
}
|