데이터 테이블 첨부파일 연계
This commit is contained in:
@@ -8,7 +8,8 @@ import { useAuth } from "@/hooks/useAuth";
|
||||
|
||||
interface FileUploadProps {
|
||||
component: FileComponent;
|
||||
onUpdateComponent: (updates: Partial<FileComponent>) => void;
|
||||
onUpdateComponent?: (updates: Partial<FileComponent>) => void;
|
||||
onFileUpload?: (files: AttachedFileInfo[]) => void; // 파일 업로드 완료 콜백
|
||||
userInfo?: any; // 사용자 정보 (선택적)
|
||||
}
|
||||
|
||||
@@ -16,7 +17,7 @@ interface FileUploadProps {
|
||||
* 독립적인 File 컴포넌트
|
||||
* attach_file_info 테이블 기반 파일 관리
|
||||
*/
|
||||
export function FileUpload({ component, onUpdateComponent, userInfo }: FileUploadProps) {
|
||||
export function FileUpload({ component, onUpdateComponent, onFileUpload, userInfo }: FileUploadProps) {
|
||||
const [isDragOver, setIsDragOver] = useState(false);
|
||||
const [uploadQueue, setUploadQueue] = useState<File[]>([]);
|
||||
const [localUploadedFiles, setLocalUploadedFiles] = useState<AttachedFileInfo[]>(component.uploadedFiles || []);
|
||||
@@ -110,16 +111,43 @@ export function FileUpload({ component, onUpdateComponent, userInfo }: FileUploa
|
||||
// 파일 확장자 검증
|
||||
const isFileTypeAllowed = (file: File): boolean => {
|
||||
const fileName = file.name.toLowerCase();
|
||||
return fileConfig.accept.some((accept) => {
|
||||
if (accept.startsWith(".")) {
|
||||
return fileName.endsWith(accept);
|
||||
|
||||
console.log("🔍 파일 타입 검증:", {
|
||||
fileName: file.name,
|
||||
fileType: file.type,
|
||||
acceptRules: fileConfig.accept,
|
||||
});
|
||||
|
||||
const result = fileConfig.accept.some((accept) => {
|
||||
// 모든 파일 허용 (와일드카드)
|
||||
if (accept === "*/*" || accept === "*") {
|
||||
console.log("✅ 와일드카드 매칭:", accept);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 확장자 기반 검증 (.jpg, .png 등)
|
||||
if (accept.startsWith(".")) {
|
||||
const matches = fileName.endsWith(accept.toLowerCase());
|
||||
console.log(`${matches ? "✅" : "❌"} 확장자 검증:`, accept, "→", matches);
|
||||
return matches;
|
||||
}
|
||||
|
||||
// MIME 타입 기반 검증 (image/*, text/* 등)
|
||||
if (accept.includes("/*")) {
|
||||
const type = accept.split("/")[0];
|
||||
return file.type.startsWith(type);
|
||||
const matches = file.type.startsWith(type);
|
||||
console.log(`${matches ? "✅" : "❌"} MIME 타입 검증:`, accept, "→", matches);
|
||||
return matches;
|
||||
}
|
||||
return file.type === accept;
|
||||
|
||||
// 정확한 MIME 타입 매칭 (image/jpeg, application/pdf 등)
|
||||
const matches = file.type === accept;
|
||||
console.log(`${matches ? "✅" : "❌"} 정확한 MIME 매칭:`, accept, "→", matches);
|
||||
return matches;
|
||||
});
|
||||
|
||||
console.log(`🎯 최종 검증 결과:`, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
// 파일 선택 핸들러
|
||||
@@ -184,9 +212,18 @@ export function FileUpload({ component, onUpdateComponent, userInfo }: FileUploa
|
||||
setUploadQueue((prev) => [...prev, ...validFiles]);
|
||||
|
||||
if (fileConfig.autoUpload) {
|
||||
console.log("🚀 자동 업로드 시작");
|
||||
console.log("🚀 자동 업로드 시작:", {
|
||||
autoUpload: fileConfig.autoUpload,
|
||||
filesCount: validFiles.length,
|
||||
fileNames: validFiles.map((f) => f.name),
|
||||
});
|
||||
// 자동 업로드 실행
|
||||
validFiles.forEach(uploadFile);
|
||||
} else {
|
||||
console.log("⏸️ 자동 업로드 비활성화:", {
|
||||
autoUpload: fileConfig.autoUpload,
|
||||
filesCount: validFiles.length,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log("❌ 업로드할 유효한 파일이 없음");
|
||||
@@ -270,6 +307,45 @@ export function FileUpload({ component, onUpdateComponent, userInfo }: FileUploa
|
||||
formData.append("writer", "system");
|
||||
}
|
||||
|
||||
// 프론트엔드 파일 타입 설정을 백엔드로 전송
|
||||
if (fileConfig.accept && fileConfig.accept.length > 0) {
|
||||
const acceptString = fileConfig.accept.join(",");
|
||||
formData.append("accept", acceptString);
|
||||
console.log("✅ 허용 파일 타입 추가:", acceptString);
|
||||
}
|
||||
|
||||
// 자동 연결 정보 추가
|
||||
if (fileConfig.autoLink) {
|
||||
formData.append("autoLink", "true");
|
||||
console.log("✅ 자동 연결 활성화: true");
|
||||
|
||||
if (fileConfig.linkedTable) {
|
||||
formData.append("linkedTable", fileConfig.linkedTable);
|
||||
console.log("✅ 연결 테이블 추가:", fileConfig.linkedTable);
|
||||
}
|
||||
|
||||
if (fileConfig.linkedField) {
|
||||
formData.append("linkedField", fileConfig.linkedField);
|
||||
console.log("✅ 연결 필드 추가:", fileConfig.linkedField);
|
||||
}
|
||||
|
||||
if (fileConfig.recordId) {
|
||||
formData.append("recordId", fileConfig.recordId);
|
||||
console.log("✅ 레코드 ID 추가:", fileConfig.recordId);
|
||||
}
|
||||
|
||||
// 가상 파일 컬럼 정보 추가
|
||||
if (fileConfig.isVirtualFileColumn) {
|
||||
formData.append("isVirtualFileColumn", "true");
|
||||
console.log("✅ 가상 파일 컬럼 활성화: true");
|
||||
|
||||
if (fileConfig.columnName) {
|
||||
formData.append("columnName", fileConfig.columnName);
|
||||
console.log("✅ 컬럼명 추가:", fileConfig.columnName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FormData 내용 디버깅
|
||||
console.log("📋 FormData 내용 확인:");
|
||||
for (const [key, value] of formData.entries()) {
|
||||
@@ -357,9 +433,17 @@ export function FileUpload({ component, onUpdateComponent, userInfo }: FileUploa
|
||||
// 로컬 상태 업데이트
|
||||
setLocalUploadedFiles(updatedFiles);
|
||||
|
||||
onUpdateComponent({
|
||||
uploadedFiles: updatedFiles,
|
||||
});
|
||||
// 컴포넌트 업데이트 (옵셔널)
|
||||
if (onUpdateComponent) {
|
||||
onUpdateComponent({
|
||||
uploadedFiles: updatedFiles,
|
||||
});
|
||||
}
|
||||
|
||||
// 파일 업로드 완료 콜백 호출 (모달에서 사용)
|
||||
if (onFileUpload) {
|
||||
onFileUpload(updatedFiles);
|
||||
}
|
||||
|
||||
// 업로드 큐에서 제거
|
||||
setUploadQueue((prev) => prev.filter((f) => f !== file));
|
||||
|
||||
Reference in New Issue
Block a user