import { apiClient } from "./client"; export interface FileInfo { id: string; name: string; size: number; type: string; extension: string; uploadedAt: string; lastModified: string; serverPath?: string; serverFilename?: string; } export interface FileUploadResponse { success: boolean; message: string; files: FileInfo[]; data?: FileInfo[]; } export interface FileDownloadParams { fileId: string; serverFilename: string; originalName: string; } /** * 파일 업로드 */ export const uploadFiles = async (params: { files: FileList | File[]; tableName?: string; fieldName?: string; recordId?: string; docType?: string; docTypeName?: string; targetObjid?: string; parentTargetObjid?: string; linkedTable?: string; linkedField?: string; autoLink?: boolean; columnName?: string; isVirtualFileColumn?: boolean; companyCode?: string; // 🔒 멀티테넌시: 회사 코드 }): Promise => { const formData = new FormData(); // 파일 추가 const fileArray = Array.isArray(params.files) ? params.files : Array.from(params.files); fileArray.forEach((file) => { formData.append("files", file); }); // 추가 파라미터들 추가 if (params.tableName) formData.append("tableName", params.tableName); if (params.fieldName) formData.append("fieldName", params.fieldName); if (params.recordId) formData.append("recordId", params.recordId); if (params.docType) formData.append("docType", params.docType); if (params.docTypeName) formData.append("docTypeName", params.docTypeName); if (params.targetObjid) formData.append("targetObjid", params.targetObjid); if (params.parentTargetObjid) formData.append("parentTargetObjid", params.parentTargetObjid); if (params.linkedTable) formData.append("linkedTable", params.linkedTable); if (params.linkedField) formData.append("linkedField", params.linkedField); if (params.autoLink !== undefined) formData.append("autoLink", params.autoLink.toString()); if (params.columnName) formData.append("columnName", params.columnName); if (params.isVirtualFileColumn !== undefined) formData.append("isVirtualFileColumn", params.isVirtualFileColumn.toString()); if (params.companyCode) formData.append("companyCode", params.companyCode); // 🔒 멀티테넌시 const response = await apiClient.post("/files/upload", formData, { headers: { "Content-Type": undefined, // axios가 자동으로 multipart/form-data를 설정하도록 }, }); return response.data; }; /** * 파일 다운로드 */ export const downloadFile = async (params: FileDownloadParams): Promise => { try { console.log("📥 downloadFile 호출:", params); const response = await apiClient.get(`/files/download/${params.fileId}`, { params: { serverFilename: params.serverFilename, originalName: params.originalName, }, responseType: "blob", // 파일 다운로드를 위해 blob 타입으로 설정 }); console.log("📥 다운로드 응답:", response); // Blob URL 생성 const blob = new Blob([response.data]); const url = window.URL.createObjectURL(blob); // 다운로드 링크 생성 및 클릭 const link = document.createElement("a"); link.href = url; link.download = params.originalName; document.body.appendChild(link); link.click(); // 정리 document.body.removeChild(link); window.URL.revokeObjectURL(url); } catch (error) { console.error("파일 다운로드 오류:", error); throw new Error("파일 다운로드에 실패했습니다."); } }; /** * 파일 삭제 */ export const deleteFile = async (fileId: string, serverFilename: string): Promise => { const response = await apiClient.delete(`/files/${fileId}`, { data: { serverFilename }, }); if (!response.data.success) { throw new Error(response.data.message || "파일 삭제에 실패했습니다."); } }; /** * 파일 정보 조회 */ export const getFileInfo = async (fileId: string, serverFilename: string) => { const response = await apiClient.get(`/files/info/${fileId}`, { params: { serverFilename }, }); return response.data; }; /** * 컴포넌트의 템플릿 파일과 데이터 파일을 모두 조회 */ export const getComponentFiles = async (params: { screenId: number; componentId: string; tableName?: string; recordId?: string; columnName?: string; }): Promise<{ success: boolean; templateFiles: FileInfo[]; dataFiles: FileInfo[]; totalFiles: FileInfo[]; }> => { const response = await apiClient.get('/files/component-files', { params, }); return response.data; }; /** * 파일 업로드 및 JSON 데이터 생성 * InteractiveScreenViewer에서 사용할 통합 함수 */ export const uploadFilesAndCreateData = async (files: FileList) => { try { // 1. 파일 업로드 const uploadResponse = await uploadFiles(files); if (!uploadResponse.success) { throw new Error(uploadResponse.message); } // 2. JSON 데이터 구조 생성 const fileData = { files: uploadResponse.files.map((file) => ({ id: file.id, name: file.name, size: file.size, type: file.type, extension: file.extension, uploadedAt: file.uploadedAt, lastModified: file.lastModified, serverFilename: file.serverFilename, // 다운로드에 필요 })), totalCount: uploadResponse.files.length, totalSize: uploadResponse.files.reduce((sum, file) => sum + file.size, 0), lastModified: new Date().toISOString(), }; return { success: true, data: fileData, message: uploadResponse.message, }; } catch (error) { console.error("파일 업로드 및 데이터 생성 오류:", error); throw error; } }; /** * 테이블 연결된 파일 조회 */ export const getLinkedFiles = async ( tableName: string, recordId: string, ): Promise<{ success: boolean; files: any[]; totalCount: number; targetObjid: string; }> => { try { console.log("📎 연결된 파일 조회:", { tableName, recordId }); const response = await apiClient.get(`/files/linked/${tableName}/${recordId}`); console.log("✅ 연결된 파일 조회 성공:", response.data); return response.data; } catch (error) { console.error("연결된 파일 조회 오류:", error); throw new Error("연결된 파일 조회에 실패했습니다."); } }; /** * 파일 미리보기 URL 생성 */ export const getFilePreviewUrl = (fileId: string): string => { const baseUrl = process.env.NEXT_PUBLIC_API_URL || "/api"; return `${baseUrl}/files/preview/${fileId}`; }; /** * 파일 다운로드 URL 생성 */ export const getFileDownloadUrl = (fileId: string): string => { const baseUrl = process.env.NEXT_PUBLIC_API_URL || "/api"; return `${baseUrl}/files/download/${fileId}`; }; /** * 직접 파일 경로 URL 생성 (정적 파일 서빙) */ export const getDirectFileUrl = (filePath: string): string => { const baseUrl = process.env.NEXT_PUBLIC_API_URL?.replace("/api", "") || ""; return `${baseUrl}${filePath}`; }; /** * 대표 파일 설정 */ export const setRepresentativeFile = async (objid: string): Promise<{ success: boolean; message: string; }> => { try { const response = await apiClient.put(`/files/representative/${objid}`); return response.data; } catch (error) { console.error("대표 파일 설정 오류:", error); throw new Error("대표 파일 설정에 실패했습니다."); } };