Files
ai-web/app/Http/Controllers/Admin/ArticleController.php

120 lines
3.9 KiB
PHP
Raw Permalink Normal View History

2026-02-11 17:28:36 +08:00
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin;
use App\Enums\EntityStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\ArticleRequest;
use App\Models\Article;
use App\Models\Category;
use App\Models\Source;
use App\Services\ChangeLogService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class ArticleController extends Controller
{
public function __construct(private readonly ChangeLogService $changeLogService)
{
}
public function index(Request $request): View
{
$items = Article::query()
->with(['category', 'source'])
->when($request->filled('q'), function ($query) use ($request): void {
$query->whereFullText(['title', 'excerpt', 'body'], (string) $request->string('q'));
})
->latest('updated_at')
->paginate(20)
->withQueryString();
return view('admin.articles.index', [
'items' => $items,
'filters' => $request->only(['q']),
]);
}
public function create(): View
{
return view('admin.articles.form', [
'item' => new Article(),
'categories' => Category::query()->where('type', 'news')->orderBy('name')->get(),
'sources' => Source::query()->where('is_whitelisted', true)->orderBy('name')->get(),
'statusOptions' => EntityStatus::cases(),
'submitRoute' => route('admin.articles.store'),
'method' => 'POST',
]);
}
public function store(ArticleRequest $request): RedirectResponse
{
$item = Article::query()->create($this->normalizePayload($request->validated()));
$this->changeLogService->log('created', $item);
return redirect()->route('admin.articles.edit', $item)->with('status', '资讯已创建');
}
public function edit(Article $article): View
{
return view('admin.articles.form', [
'item' => $article,
'categories' => Category::query()->where('type', 'news')->orderBy('name')->get(),
'sources' => Source::query()->where('is_whitelisted', true)->orderBy('name')->get(),
'statusOptions' => EntityStatus::cases(),
'submitRoute' => route('admin.articles.update', $article),
'method' => 'PUT',
]);
}
public function update(ArticleRequest $request, Article $article): RedirectResponse
{
$before = $article->getAttributes();
$article->fill($this->normalizePayload($request->validated()));
$article->save();
$this->changeLogService->log('updated', $article, $before);
return redirect()->route('admin.articles.edit', $article)->with('status', '资讯已更新');
}
public function publish(Article $article): RedirectResponse
{
$before = $article->getAttributes();
$article->status = EntityStatus::Published;
$article->published_at = $article->published_at ?? now();
$article->save();
$this->changeLogService->log('published', $article, $before);
return redirect()->route('admin.articles.edit', $article)->with('status', '资讯已发布');
}
public function markStale(Article $article): RedirectResponse
{
$before = $article->getAttributes();
$article->is_stale = true;
$article->status = EntityStatus::Stale;
$article->save();
$this->changeLogService->log('marked_stale', $article, $before);
return redirect()->route('admin.articles.edit', $article)->with('status', '资讯已标记失效');
}
private function normalizePayload(array $data): array
{
$data['is_stale'] = (bool) ($data['is_stale'] ?? false);
if (($data['status'] ?? null) === EntityStatus::Published->value && empty($data['published_at'])) {
$data['published_at'] = now();
}
return $data;
}
}