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.

146 lines
4.6 KiB

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Paper;
use App\Models\ResearchDirection;
use App\Support\ApiResponse;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PaperController extends Controller
{
use ApiResponse;
public function index(Request $request): JsonResponse
{
$query = Paper::query()->withCount('teachers');
if ($kw = $request->query('keyword')) {
$query->where(function ($q) use ($kw) {
$q->where('title', 'like', "%{$kw}%")
->orWhere('authors', 'like', "%{$kw}%")
->orWhere('school_name', 'like', "%{$kw}%")
->orWhere('summary', 'like', "%{$kw}%");
});
}
if ($request->filled('school_name')) {
$query->where('school_name', $request->query('school_name'));
}
if ($request->filled('university_id')) {
$query->where('university_id', (int) $request->query('university_id'));
}
if ($request->filled('research_direction_id')) {
$dirId = (int) $request->query('research_direction_id');
$query->whereHas('teachers.researchDirections', fn ($q) => $q->where('research_directions.id', $dirId));
} elseif ($request->filled('research_direction')) {
$dir = $request->query('research_direction');
$query->whereHas('teachers.researchDirections', fn ($q) => $q->where('research_directions.name', 'like', "%{$dir}%"));
}
if ($request->query('link_status') === 'linked') {
$query->has('teachers');
} elseif ($request->query('link_status') === 'unlinked') {
$query->doesntHave('teachers');
}
if ($request->filled('source')) {
$query->where('source', $request->query('source'));
}
if ($request->filled('crawl_job_id')) {
$query->where('crawl_job_id', (int) $request->query('crawl_job_id'));
}
$paginator = $query
->orderByDesc('published_at')
->orderByDesc('id')
->paginate((int) $request->query('page_size', 20))
->withQueryString();
$paginator->getCollection()->transform(fn (Paper $p) => $this->serializeList($p));
return $this->paginated($paginator);
}
public function filterOptions(): JsonResponse
{
$schools = Paper::query()
->whereNotNull('school_name')
->distinct()
->orderBy('school_name')
->pluck('school_name')
->filter()
->values();
$directions = ResearchDirection::query()
->where('status', 1)
->whereHas('teachers')
->orderBy('sort')
->orderBy('name')
->pluck('name')
->values();
return $this->ok([
'school_names' => $schools,
'research_directions' => $directions,
]);
}
public function show(int $paper): JsonResponse
{
$model = Paper::query()->with(['teachers.university'])->findOrFail($paper);
return $this->ok($this->serializeDetail($model));
}
public function destroy(int $paper): JsonResponse
{
$model = Paper::query()->findOrFail($paper);
$model->teachers()->detach();
$model->delete();
return $this->ok(null, '已删除');
}
/**
* @return array<string, mixed>
*/
protected function serializeList(Paper $p): array
{
$isNew = $p->source === 'crawl'
&& $p->created_at
&& $p->created_at->gte(Carbon::now()->subDay());
return [
'id' => $p->id,
'title' => $p->title,
'authors' => $p->authors,
'school_name' => $p->school_name,
'published_at' => $p->published_at?->format('Y-m'),
'imported_at' => $p->created_at?->format('Y-m-d'),
'url' => $p->url,
'summary' => $p->summary,
'source' => $p->source,
'is_new' => $isNew,
'teachers_count' => (int) ($p->teachers_count ?? 0),
'is_linked' => (int) ($p->teachers_count ?? 0) > 0,
];
}
/**
* @return array<string, mixed>
*/
protected function serializeDetail(Paper $p): array
{
$row = $this->serializeList($p);
$row['published_at'] = $p->published_at?->toDateString();
$row['teachers'] = $p->teachers->map(fn ($t) => [
'id' => $t->id,
'name' => $t->name,
'university_name' => $t->university?->name,
])->values();
return $row;
}
}