tenantId()) ->whereNull('parent_id') ->with('children.children.children') ->orderBy('sort_order') ->get(); return response()->json(['folders' => $folders]); } public function folderStore(Request $request): JsonResponse { $request->validate([ 'name' => 'required|string|max:200', 'parent_id' => 'nullable|integer', ]); $folder = PmisArchiveFolder::create([ 'tenant_id' => $this->tenantId(), 'parent_id' => $request->parent_id, 'name' => $request->name, 'sort_order' => PmisArchiveFolder::tenant($this->tenantId()) ->where('parent_id', $request->parent_id) ->count(), ]); return response()->json(['folder' => $folder], 201); } public function folderUpdate(Request $request, int $id): JsonResponse { $folder = PmisArchiveFolder::tenant($this->tenantId())->findOrFail($id); $request->validate(['name' => 'required|string|max:200']); $folder->update(['name' => $request->name]); return response()->json(['folder' => $folder]); } public function folderDestroy(int $id): JsonResponse { $folder = PmisArchiveFolder::tenant($this->tenantId())->findOrFail($id); $descendantIds = $folder->allDescendantIds(); PmisArchiveFile::tenant($this->tenantId()) ->whereIn('folder_id', $descendantIds) ->each(function ($file) { Storage::disk('public')->delete($file->file_path); $file->delete(); }); PmisArchiveFolder::tenant($this->tenantId()) ->whereIn('id', $descendantIds) ->delete(); return response()->json(['message' => '삭제되었습니다.']); } /* ─── 파일 목록 ─── */ public function fileList(Request $request): JsonResponse { $folderId = $request->query('folder_id'); $tab = $request->query('tab', '전체'); $search = $request->query('search', ''); $dateFrom = $request->query('date_from'); $dateTo = $request->query('date_to'); $includeSubfolder = $request->boolean('include_subfolder', true); $query = PmisArchiveFile::tenant($this->tenantId()); if ($folderId) { if ($includeSubfolder) { $folder = PmisArchiveFolder::tenant($this->tenantId())->find($folderId); if ($folder) { $folderIds = $folder->allDescendantIds(); $query->whereIn('folder_id', $folderIds); } } else { $query->where('folder_id', $folderId); } } if ($tab !== '전체') { $query->where('file_type', $tab); } if ($search) { $query->where(function ($q) use ($search) { $q->where('title', 'like', "%{$search}%") ->orWhere('original_name', 'like', "%{$search}%") ->orWhereHas('folder', fn ($fq) => $fq->where('name', 'like', "%{$search}%")); }); } if ($dateFrom) { $query->whereDate('created_at', '>=', $dateFrom); } if ($dateTo) { $query->whereDate('created_at', '<=', $dateTo); } $files = $query->orderByDesc('created_at')->get(); $result = $files->map(fn ($f) => [ 'id' => $f->id, 'title' => $f->title ?: $f->original_name, 'fileName' => $f->original_name, 'filePath' => Storage::disk('public')->url($f->file_path), 'fileType' => $f->file_type, 'siteName' => $f->site_name, 'size' => PmisArchiveFile::formatSize($f->file_size), 'sizeRaw' => $f->file_size, 'registrant' => $f->registeredByUser?->name ?? '-', 'registeredAt' => $f->created_at->format('Y-m-d'), 'folderId' => $f->folder_id, ]); return response()->json(['files' => $result]); } /* ─── 파일 업로드 ─── */ public function fileStore(Request $request): JsonResponse { $request->validate([ 'folder_id' => 'required|integer|exists:pmis_archive_folders,id', 'files' => 'required|array|min:1', 'files.*' => 'file|max:51200', 'title' => 'nullable|string|max:300', 'site_name' => 'nullable|string|max:200', ]); $user = auth()->user(); $uploaded = []; foreach ($request->file('files') as $file) { $ext = $file->getClientOriginalExtension(); $path = $file->store('pmis/archive', 'public'); $record = PmisArchiveFile::create([ 'tenant_id' => $this->tenantId(), 'folder_id' => $request->folder_id, 'title' => $request->title ?: '', 'original_name' => $file->getClientOriginalName(), 'file_path' => $path, 'file_type' => PmisArchiveFile::detectFileType($ext), 'file_size' => $file->getSize(), 'site_name' => $request->site_name ?: '', 'registered_by' => $user?->id, ]); $uploaded[] = $record; } return response()->json(['files' => $uploaded, 'message' => count($uploaded).'개 파일이 업로드되었습니다.'], 201); } /* ─── 파일 삭제 ─── */ public function fileDestroy(int $id): JsonResponse { $file = PmisArchiveFile::tenant($this->tenantId())->findOrFail($id); Storage::disk('public')->delete($file->file_path); $file->delete(); return response()->json(['message' => '삭제되었습니다.']); } /* ─── 파일 다운로드 ─── */ public function fileDownload(int $id) { $file = PmisArchiveFile::tenant($this->tenantId())->findOrFail($id); $fullPath = Storage::disk('public')->path($file->file_path); return response()->download($fullPath, $file->original_name); } }