252 lines
7.0 KiB
TypeScript
252 lines
7.0 KiB
TypeScript
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<FileUploadResponse> => {
|
|
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<void> => {
|
|
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<void> => {
|
|
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}`;
|
|
};
|