query('search', ''); $query = PmisManual::tenant($this->tenantId()) ->with('author:id,name') ->withCount('attachments') ->orderByDesc('id'); if ($search) { $query->where(function ($q) use ($search) { $q->where('title', 'like', "%{$search}%") ->orWhere('tags', 'like', "%{$search}%"); }); } $manuals = $query->get()->map(fn ($m) => [ 'id' => $m->id, 'title' => $m->title, 'author' => $m->author?->name ?? '관리자', 'createdAt' => $m->created_at->format('Y-m-d'), 'views' => $m->views, 'hasAttachment' => $m->attachments_count > 0, ]); return response()->json(['manuals' => $manuals]); } public function show(int $id): JsonResponse { $manual = PmisManual::tenant($this->tenantId()) ->with(['author:id,name', 'attachments']) ->findOrFail($id); $manual->increment('views'); return response()->json([ 'manual' => [ 'id' => $manual->id, 'title' => $manual->title, 'content' => $manual->content, 'tags' => $manual->tags, 'author' => $manual->author?->name ?? '관리자', 'createdAt' => $manual->created_at->format('Y-m-d'), 'views' => $manual->views, 'attachments' => $manual->attachments->map(fn ($a) => [ 'id' => $a->id, 'fileName' => $a->original_name, 'size' => PmisManualAttachment::formatSize($a->file_size), 'downloadUrl' => "/juil/construction-pmis/api/manuals/attachments/{$a->id}/download", ]), ], ]); } public function store(Request $request): JsonResponse { $user = auth()->user(); if (! $user->isAdmin()) { return response()->json(['message' => '권한이 없습니다.'], 403); } $request->validate([ 'title' => 'required|string|max:300', 'content' => 'nullable|string', 'tags' => 'nullable|string|max:500', 'files' => 'nullable|array', 'files.*' => 'file|max:51200', ]); $manual = PmisManual::create([ 'tenant_id' => $this->tenantId(), 'title' => $request->title, 'content' => $request->content ?? '', 'tags' => $request->tags ?? '', 'author_id' => $user->id, ]); if ($request->hasFile('files')) { foreach ($request->file('files') as $file) { $path = $file->store('pmis/manuals', 'public'); $manual->attachments()->create([ 'original_name' => $file->getClientOriginalName(), 'file_path' => $path, 'file_size' => $file->getSize(), ]); } } return response()->json(['manual' => $manual->load('attachments'), 'message' => '등록되었습니다.'], 201); } public function update(Request $request, int $id): JsonResponse { $user = auth()->user(); if (! $user->isAdmin()) { return response()->json(['message' => '권한이 없습니다.'], 403); } $manual = PmisManual::tenant($this->tenantId())->findOrFail($id); $request->validate([ 'title' => 'required|string|max:300', 'content' => 'nullable|string', 'tags' => 'nullable|string|max:500', 'files' => 'nullable|array', 'files.*' => 'file|max:51200', ]); $manual->update([ 'title' => $request->title, 'content' => $request->content ?? '', 'tags' => $request->tags ?? '', ]); if ($request->hasFile('files')) { foreach ($request->file('files') as $file) { $path = $file->store('pmis/manuals', 'public'); $manual->attachments()->create([ 'original_name' => $file->getClientOriginalName(), 'file_path' => $path, 'file_size' => $file->getSize(), ]); } } return response()->json(['manual' => $manual->load('attachments'), 'message' => '수정되었습니다.']); } public function destroy(int $id): JsonResponse { $user = auth()->user(); if (! $user->isAdmin()) { return response()->json(['message' => '권한이 없습니다.'], 403); } $manual = PmisManual::tenant($this->tenantId())->findOrFail($id); foreach ($manual->attachments as $att) { Storage::disk('public')->delete($att->file_path); } $manual->delete(); return response()->json(['message' => '삭제되었습니다.']); } public function attachmentDownload(int $id) { $att = PmisManualAttachment::findOrFail($id); $fullPath = Storage::disk('public')->path($att->file_path); return response()->download($fullPath, $att->original_name); } public function attachmentDestroy(int $id): JsonResponse { $user = auth()->user(); if (! $user->isAdmin()) { return response()->json(['message' => '권한이 없습니다.'], 403); } $att = PmisManualAttachment::findOrFail($id); Storage::disk('public')->delete($att->file_path); $att->delete(); return response()->json(['message' => '삭제되었습니다.']); } }