You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.5 KiB
170 lines
4.5 KiB
<?php
|
|
|
|
namespace App\Support\News;
|
|
|
|
use App\Models\CrawlAddress;
|
|
use App\Models\DictItem;
|
|
use App\Models\DictType;
|
|
use App\Models\News;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class UniversityNewsCategory
|
|
{
|
|
public const LABEL = '高校要闻';
|
|
|
|
public const VALUE = 'university_news';
|
|
|
|
/**
|
|
* 合并重复的「高校要闻」字典项,保留已有数据引用最多的那条(通常即爬虫沿用的原始分类)。
|
|
*/
|
|
public static function consolidateDuplicates(): ?int
|
|
{
|
|
$typeId = DictType::query()->where('code', 'news_category')->where('status', 1)->value('id');
|
|
if (! $typeId) {
|
|
return null;
|
|
}
|
|
|
|
$items = DictItem::query()
|
|
->where('dict_type_id', $typeId)
|
|
->where(function ($q) {
|
|
$q->where('value', self::VALUE)
|
|
->orWhere('label', self::LABEL);
|
|
})
|
|
->orderBy('id')
|
|
->get();
|
|
|
|
if ($items->isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
if ($items->count() === 1) {
|
|
$item = $items->first();
|
|
$item->fill(['label' => self::LABEL, 'value' => self::VALUE, 'status' => 1]);
|
|
$item->save();
|
|
|
|
return (int) $item->id;
|
|
}
|
|
|
|
$keeper = $items->sort(function (DictItem $a, DictItem $b) {
|
|
$countA = self::referenceCount((int) $a->id);
|
|
$countB = self::referenceCount((int) $b->id);
|
|
if ($countA !== $countB) {
|
|
return $countB <=> $countA;
|
|
}
|
|
|
|
return $a->id <=> $b->id;
|
|
})->first();
|
|
|
|
if (! $keeper) {
|
|
return null;
|
|
}
|
|
|
|
return DB::transaction(function () use ($items, $keeper) {
|
|
$keeperId = (int) $keeper->id;
|
|
|
|
foreach ($items as $item) {
|
|
if ((int) $item->id === $keeperId) {
|
|
continue;
|
|
}
|
|
|
|
News::query()
|
|
->where('category_dict_item_id', $item->id)
|
|
->update(['category_dict_item_id' => $keeperId]);
|
|
|
|
CrawlAddress::query()
|
|
->where('category_dict_item_id', $item->id)
|
|
->update(['category_dict_item_id' => $keeperId]);
|
|
|
|
$item->delete();
|
|
}
|
|
|
|
$keeper->fill([
|
|
'label' => self::LABEL,
|
|
'value' => self::VALUE,
|
|
'status' => 1,
|
|
]);
|
|
$keeper->save();
|
|
|
|
return $keeperId;
|
|
});
|
|
}
|
|
|
|
public static function canonicalId(): ?int
|
|
{
|
|
$typeId = DictType::query()->where('code', 'news_category')->where('status', 1)->value('id');
|
|
if (! $typeId) {
|
|
return null;
|
|
}
|
|
|
|
$item = DictItem::query()
|
|
->where('dict_type_id', $typeId)
|
|
->where('status', 1)
|
|
->where('value', self::VALUE)
|
|
->orderBy('id')
|
|
->first();
|
|
|
|
if ($item) {
|
|
return (int) $item->id;
|
|
}
|
|
|
|
$item = DictItem::query()
|
|
->where('dict_type_id', $typeId)
|
|
->where('status', 1)
|
|
->where('label', self::LABEL)
|
|
->orderBy('id')
|
|
->first();
|
|
|
|
return $item ? (int) $item->id : null;
|
|
}
|
|
|
|
/**
|
|
* @return list<int>
|
|
*/
|
|
public static function categoryIds(): array
|
|
{
|
|
$id = self::canonicalId();
|
|
|
|
return $id ? [$id] : [];
|
|
}
|
|
|
|
public static function applyUniversityNewsOnly(Builder $query): Builder
|
|
{
|
|
$id = self::canonicalId();
|
|
|
|
return $query->where('category_dict_item_id', $id ?? -1);
|
|
}
|
|
|
|
public static function applyExcludeUniversityNews(Builder $query): Builder
|
|
{
|
|
$id = self::canonicalId();
|
|
if (! $id) {
|
|
return $query;
|
|
}
|
|
|
|
return $query->where(function ($q) use ($id) {
|
|
$q->whereNull('category_dict_item_id')
|
|
->orWhere('category_dict_item_id', '!=', $id);
|
|
});
|
|
}
|
|
|
|
public static function isUniversityNewsCategory(?DictItem $item): bool
|
|
{
|
|
if (! $item) {
|
|
return false;
|
|
}
|
|
|
|
$canonicalId = self::canonicalId();
|
|
|
|
return $canonicalId
|
|
? (int) $item->id === $canonicalId
|
|
: ($item->value === self::VALUE || $item->label === self::LABEL);
|
|
}
|
|
|
|
protected static function referenceCount(int $dictItemId): int
|
|
{
|
|
return News::query()->where('category_dict_item_id', $dictItemId)->count()
|
|
+ CrawlAddress::query()->where('category_dict_item_id', $dictItemId)->count();
|
|
}
|
|
}
|