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.

151 lines
5.0 KiB

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\StudyTour;
use App\Support\SecurePrivateImportUpload;
use App\Support\StudyTourDeclarationExporter;
use App\Support\StudyTourDeclarationParser;
use App\Support\StudyTourPayload;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\HeaderUtils;
class StudyTourController extends Controller
{
public function index(Request $request): JsonResponse
{
$q = StudyTour::query()->orderBy('sort')->orderByDesc('id');
StudyTourPayload::applyListFilters($q, $request);
return response()->json($q->get());
}
public function store(Request $request): JsonResponse
{
$this->ensureSuperAdmin($request);
$data = $request->validate(StudyTourPayload::validationRules(true));
$data = StudyTourPayload::normalizeIncoming($data);
$row = StudyTour::create($data + [
'tags' => $data['tags'] ?? [],
'venue_ids' => $data['venue_ids'] ?? [],
'venue_items' => $data['venue_items'] ?? [],
'seasons' => $data['seasons'] ?? [],
'suitable_audience' => $data['suitable_audience'] ?? null,
'route_plans' => $data['route_plans'] ?? [],
'courses' => $data['courses'] ?? [],
'gallery_media' => $data['gallery_media'] ?? [],
'sort' => $data['sort'] ?? 0,
'is_on_shelf' => $data['is_on_shelf'] ?? true,
]);
return response()->json($row, 201);
}
public function update(Request $request, StudyTour $studyTour): JsonResponse
{
$this->ensureSuperAdmin($request);
$data = $request->validate(StudyTourPayload::validationRules(false));
$data = StudyTourPayload::normalizeIncoming($data);
$studyTour->fill($data)->save();
return response()->json($studyTour->fresh());
}
public function destroy(Request $request, StudyTour $studyTour): JsonResponse
{
$this->ensureSuperAdmin($request);
$studyTour->delete();
return response()->json(['message' => '删除成功']);
}
public function export(Request $request): BinaryFileResponse|JsonResponse
{
$this->ensureSuperAdmin($request);
$data = $request->validate([
'ids' => ['required', 'array', 'min:1', 'max:'.StudyTourDeclarationExporter::MAX_BATCH],
'ids.*' => ['integer', 'min:1'],
]);
$ids = array_values(array_unique(array_map('intval', $data['ids'])));
$order = array_flip($ids);
$tours = StudyTour::query()
->whereIn('id', $ids)
->get()
->sortBy(fn (StudyTour $row) => $order[$row->id] ?? 9999)
->values();
if ($tours->isEmpty()) {
return response()->json(['message' => '未找到可导出的线路'], 422);
}
try {
$download = StudyTourDeclarationExporter::writeDownload($tours);
} catch (\Throwable $e) {
return response()->json(['message' => '导出失败:'.$e->getMessage()], 422);
}
$ascii = str_ends_with(strtolower($download['filename']), '.zip')
? 'study-tours.zip'
: 'study-tour.docx';
$response = response()->download(
$download['path'],
$ascii,
['Content-Type' => $download['mime']]
)->deleteFileAfterSend(true);
$response->headers->set(
'Content-Disposition',
HeaderUtils::makeDisposition(
HeaderUtils::DISPOSITION_ATTACHMENT,
$download['filename'],
$ascii
)
);
return $response;
}
public function parseDoc(Request $request): JsonResponse
{
$request->validate([
'file' => ['required', 'file', 'max:10240'],
]);
$uploaded = $request->file('file');
if ($uploaded === null) {
return response()->json(['message' => '请上传申报表文件'], 422);
}
$path = null;
try {
$path = SecurePrivateImportUpload::storeTemporary(
$uploaded,
'tmp/declaration-import',
['doc', 'docx'],
10240
);
$extension = strtolower((string) pathinfo($path, PATHINFO_EXTENSION));
$result = StudyTourDeclarationParser::parseFile($path, $extension);
} catch (\Illuminate\Validation\ValidationException $e) {
throw $e;
} catch (\Throwable $e) {
return response()->json(['message' => '申报表解析失败:'.$e->getMessage()], 422);
} finally {
if (is_string($path) && is_file($path)) {
@unlink($path);
}
}
return response()->json($result);
}
private function ensureSuperAdmin(Request $request): void
{
abort_unless($request->user()?->isSuperAdmin(), 403, '仅超级管理员可操作');
}
}