ui, 파일업로드 관련 손보기

This commit is contained in:
leeheejin
2025-09-29 17:21:47 +09:00
parent bff7416cd1
commit a5bf6601a0
18 changed files with 858 additions and 308 deletions

View File

@@ -131,15 +131,90 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
}
}, [component.id]); // component.id가 변경될 때만 실행
// 🎯 화면설계 모드에서 실제 화면으로의 실시간 동기화 이벤트 리스너
useEffect(() => {
const handleDesignModeFileChange = (event: CustomEvent) => {
console.log("🎯🎯🎯 FileUploadComponent 화면설계 모드 파일 변경 이벤트 수신:", {
eventComponentId: event.detail.componentId,
currentComponentId: component.id,
isMatch: event.detail.componentId === component.id,
filesCount: event.detail.files?.length || 0,
action: event.detail.action,
source: event.detail.source,
eventDetail: event.detail
});
// 현재 컴포넌트와 일치하고 화면설계 모드에서 온 이벤트인 경우
if (event.detail.componentId === component.id && event.detail.source === 'designMode') {
console.log("✅✅✅ 화면설계 모드 → 실제 화면 파일 동기화 시작:", {
componentId: component.id,
filesCount: event.detail.files?.length || 0,
action: event.detail.action
});
// 파일 상태 업데이트
const newFiles = event.detail.files || [];
setUploadedFiles(newFiles);
// localStorage 백업 업데이트
try {
const backupKey = `fileUpload_${component.id}`;
localStorage.setItem(backupKey, JSON.stringify(newFiles));
console.log("💾 화면설계 모드 동기화 후 localStorage 백업 업데이트:", {
componentId: component.id,
fileCount: newFiles.length
});
} catch (e) {
console.warn("localStorage 백업 업데이트 실패:", e);
}
// 전역 상태 업데이트
if (typeof window !== 'undefined') {
(window as any).globalFileState = {
...(window as any).globalFileState,
[component.id]: newFiles
};
}
// onUpdate 콜백 호출 (부모 컴포넌트에 알림)
if (onUpdate) {
onUpdate({
uploadedFiles: newFiles,
lastFileUpdate: event.detail.timestamp
});
}
console.log("🎉🎉🎉 화면설계 모드 → 실제 화면 동기화 완료:", {
componentId: component.id,
finalFileCount: newFiles.length
});
}
};
if (typeof window !== 'undefined') {
window.addEventListener('globalFileStateChanged', handleDesignModeFileChange as EventListener);
return () => {
window.removeEventListener('globalFileStateChanged', handleDesignModeFileChange as EventListener);
};
}
}, [component.id, onUpdate]);
// 템플릿 파일과 데이터 파일을 조회하는 함수
const loadComponentFiles = useCallback(async () => {
if (!component?.id) return;
try {
const screenId = formData?.screenId || (typeof window !== 'undefined' && window.location.pathname.includes('/screens/')
let screenId = formData?.screenId || (typeof window !== 'undefined' && window.location.pathname.includes('/screens/')
? parseInt(window.location.pathname.split('/screens/')[1])
: null);
// 디자인 모드인 경우 기본 화면 ID 사용
if (!screenId && isDesignMode) {
screenId = 40; // 기본 화면 ID
console.log("📂 디자인 모드: 기본 화면 ID 사용 (40)");
}
if (!screenId) {
console.log("📂 화면 ID 없음, 기존 파일 로직 사용");
return false; // 기존 로직 사용
@@ -474,14 +549,18 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
}
const uploadData = {
tableName: tableName,
fieldName: columnName,
recordId: recordId || `temp_${component.id}`,
// 🎯 formData에서 백엔드 API 설정 가져오기
autoLink: formData?.autoLink || true,
linkedTable: formData?.linkedTable || tableName,
recordId: formData?.recordId || recordId || `temp_${component.id}`,
columnName: formData?.columnName || columnName,
isVirtualFileColumn: formData?.isVirtualFileColumn || true,
docType: component.fileConfig?.docType || 'DOCUMENT',
docTypeName: component.fileConfig?.docTypeName || '일반 문서',
// 호환성을 위한 기존 필드들
tableName: tableName,
fieldName: columnName,
targetObjid: targetObjid, // InteractiveDataTable 호환을 위한 targetObjid 추가
columnName: columnName, // 가상 파일 컬럼 지원
isVirtualFileColumn: true, // 가상 파일 컬럼으로 처리
};
console.log("📤 파일 업로드 시작:", {
@@ -715,7 +794,9 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
componentId: component.id,
files: updatedFiles,
fileCount: updatedFiles.length,
timestamp: Date.now()
timestamp: Date.now(),
source: 'realScreen', // 🎯 실제 화면에서 온 이벤트임을 표시
action: 'delete'
}
});
window.dispatchEvent(syncEvent);

View File

@@ -516,7 +516,7 @@ export const FileViewerModal: React.FC<FileViewerModalProps> = ({
return (
<Dialog open={isOpen} onOpenChange={() => {}}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto [&>button]:hidden">
<DialogHeader>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">