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
6.0 KiB

4 days ago
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Venue;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class VenueController extends Controller
{
public function store(Request $request): JsonResponse
{
abort_unless($request->user()?->isSuperAdmin(), 403, '仅超级管理员可操作');
$data = $request->validate([
'name' => ['required', 'string', 'max:120'],
'venue_type' => ['nullable', 'string', 'max:80'],
3 days ago
'venue_types' => ['nullable', 'array'],
'venue_types.*' => ['string', 'max:80'],
4 days ago
'unit_name' => ['nullable', 'string', 'max:120'],
'district' => ['nullable', 'string', 'max:80'],
'ticket_type' => ['nullable', 'string', 'max:80'],
3 days ago
'appointment_type' => ['nullable', 'string', 'max:40'],
4 days ago
'open_time' => ['nullable', 'string', 'max:120'],
'reservation_notice' => ['nullable', 'string'],
'study_courses' => ['nullable', 'string'],
'address' => ['nullable', 'string', 'max:255'],
3 days ago
'contact_phone' => ['nullable', 'string', 'max:20'],
4 days ago
'lat' => ['nullable', 'numeric'],
'lng' => ['nullable', 'numeric'],
'cover_image' => ['nullable', 'string', 'max:255'],
'gallery_media' => ['nullable', 'array'],
'gallery_media.*.type' => ['required_with:gallery_media', 'in:image,video'],
'gallery_media.*.url' => ['required_with:gallery_media', 'string', 'max:255'],
'detail_html' => ['nullable', 'string'],
'live_people_count' => ['nullable', 'integer', 'min:0'],
'sort' => ['nullable', 'integer', 'min:0'],
'is_active' => ['boolean'],
]);
$venue = Venue::create($data + ['is_active' => $data['is_active'] ?? true]);
return response()->json($venue, 201);
}
public function index(Request $request): JsonResponse
{
$user = $request->user();
$keyword = trim((string) $request->string('keyword'));
$district = trim((string) $request->string('district'));
$venueType = trim((string) $request->string('venue_type'));
$ticketType = trim((string) $request->string('ticket_type'));
$isActive = $request->input('is_active');
// 必须用关联本身的查询,勿用 getQuery()->get(),否则会绕过 BelongsToMany::get()
// 的 select `venues.*`,在 join user_venue 时 `id` 可能被 pivot 表的 id 覆盖(列表 id 比库大 1
if ($user->isSuperAdmin()) {
$query = Venue::query();
} else {
$query = $user->venues();
}
if ($keyword !== '') {
$query->where(function ($q) use ($keyword) {
$q->where('name', 'like', '%' . $keyword . '%')
->orWhere('address', 'like', '%' . $keyword . '%')
->orWhere('unit_name', 'like', '%' . $keyword . '%')
->orWhere('open_time', 'like', '%' . $keyword . '%')
->orWhere('reservation_notice', 'like', '%' . $keyword . '%')
->orWhere('study_courses', 'like', '%' . $keyword . '%');
});
}
if ($district !== '') {
$query->where('district', $district);
}
if ($venueType !== '') {
3 days ago
$query->where(function ($q) use ($venueType) {
$q->where('venue_type', $venueType)
->orWhereJsonContains('venue_types', $venueType);
});
4 days ago
}
if ($ticketType !== '') {
$query->where('ticket_type', $ticketType);
}
if ($isActive !== null && $isActive !== '') {
$query->where('is_active', (int) $isActive === 1);
}
$venues = $query->orderBy('venues.sort')->orderByDesc('venues.id')->get();
return response()->json($venues);
}
public function update(Request $request, int $id): JsonResponse
{
$venue = Venue::query()->findOrFail($id);
$this->ensureVenuePermission($request, $venue->id);
$data = $request->validate([
'name' => ['sometimes', 'string', 'max:120'],
'venue_type' => ['nullable', 'string', 'max:80'],
3 days ago
'venue_types' => ['nullable', 'array'],
'venue_types.*' => ['string', 'max:80'],
4 days ago
'unit_name' => ['nullable', 'string', 'max:120'],
'district' => ['nullable', 'string', 'max:80'],
'ticket_type' => ['nullable', 'string', 'max:80'],
3 days ago
'appointment_type' => ['nullable', 'string', 'max:40'],
4 days ago
'open_time' => ['nullable', 'string', 'max:120'],
'reservation_notice' => ['nullable', 'string'],
'study_courses' => ['nullable', 'string'],
'address' => ['nullable', 'string', 'max:255'],
3 days ago
'contact_phone' => ['nullable', 'string', 'max:20'],
4 days ago
'lat' => ['nullable', 'numeric'],
'lng' => ['nullable', 'numeric'],
'cover_image' => ['nullable', 'string', 'max:255'],
'gallery_media' => ['nullable', 'array'],
'gallery_media.*.type' => ['required_with:gallery_media', 'in:image,video'],
'gallery_media.*.url' => ['required_with:gallery_media', 'string', 'max:255'],
'detail_html' => ['nullable', 'string'],
'live_people_count' => ['nullable', 'integer', 'min:0'],
'sort' => ['nullable', 'integer', 'min:0'],
'is_active' => ['boolean'],
]);
if (!$request->user()?->isSuperAdmin()) {
unset($data['sort']);
}
$venue->fill($data)->save();
return response()->json($venue);
}
private function ensureVenuePermission(Request $request, int $venueId): void
{
$user = $request->user();
if ($user->isSuperAdmin()) {
return;
}
$allowed = $user->venues()->where('venues.id', $venueId)->exists();
abort_unless($allowed, 403, '仅可操作已绑定场馆');
}
}