const { useState, useEffect } = React; function CommonCode() { // 상태 관리 const [currentData, setCurrentData] = useState([]); const [groupData, setGroupData] = useState([]); const [selectedGroupCode, setSelectedGroupCode] = useState(null); const [selectedGroupName, setSelectedGroupName] = useState(''); const [isLoading, setIsLoading] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [deleteTargetIdx, setDeleteTargetIdx] = useState(null); const [editData, setEditData] = useState({ idx: '', grp: '', code: '', svalue: '', ivalue: '', fvalue: '', svalue2: '', memo: '' }); const [isEditMode, setIsEditMode] = useState(false); // 컴포넌트 마운트 시 초기 데이터 로드 useEffect(() => { loadGroups(); }, []); // 코드그룹 목록 로드 const loadGroups = async () => { setIsLoading(true); try { const response = await fetch('/Common/GetGroups'); const data = await response.json(); setGroupData(data || []); } catch (error) { console.error('그룹 데이터 로드 중 오류 발생:', error); showNotification('그룹 데이터 로드 중 오류가 발생했습니다.', 'error'); } finally { setIsLoading(false); } }; // 그룹 선택 처리 const selectGroup = async (code, name) => { setSelectedGroupCode(code); setSelectedGroupName(name); await loadDataByGroup(code); }; // 특정 그룹의 데이터 로드 const loadDataByGroup = async (grp) => { setIsLoading(true); try { let url = '/Common/GetList'; if (grp) { url += '?grp=' + encodeURIComponent(grp); } const response = await fetch(url); const data = await response.json(); setCurrentData(data || []); } catch (error) { console.error('데이터 로드 중 오류 발생:', error); showNotification('데이터 로드 중 오류가 발생했습니다.', 'error'); } finally { setIsLoading(false); } }; // 추가 모달 표시 const showAddModal = () => { if (!selectedGroupCode) { showNotification('먼저 코드그룹을 선택하세요.', 'warning'); return; } setIsEditMode(false); setEditData({ idx: '', grp: selectedGroupCode, code: '', svalue: '', ivalue: '', fvalue: '', svalue2: '', memo: '' }); setShowEditModal(true); }; // 편집 모달 표시 const editItem = (idx) => { const item = currentData.find(x => x.idx === idx); if (!item) return; setIsEditMode(true); setEditData({ idx: item.idx, grp: item.grp || '', code: item.code || '', svalue: item.svalue || '', ivalue: item.ivalue || '', fvalue: item.fvalue || '', svalue2: item.svalue2 || '', memo: item.memo || '' }); setShowEditModal(true); }; // 데이터 저장 const saveData = async () => { const form = document.getElementById('editForm'); if (!form.checkValidity()) { form.reportValidity(); return; } const data = { idx: parseInt(editData.idx) || 0, grp: editData.grp, code: editData.code, svalue: editData.svalue, ivalue: parseInt(editData.ivalue) || 0, fvalue: parseFloat(editData.fvalue) || 0.0, svalue2: editData.svalue2, memo: editData.memo }; setIsLoading(true); try { const response = await fetch('/Common/Save', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); const result = await response.json(); if (result.Success) { showNotification(result.Message, 'success'); setShowEditModal(false); if (selectedGroupCode) { await loadDataByGroup(selectedGroupCode); } } else { showNotification(result.Message, 'error'); } } catch (error) { console.error('저장 중 오류 발생:', error); showNotification('저장 중 오류가 발생했습니다.', 'error'); } finally { setIsLoading(false); } }; // 삭제 확인 const confirmDelete = async () => { if (!deleteTargetIdx) return; setIsLoading(true); try { const response = await fetch('/Common/Delete', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ idx: deleteTargetIdx }) }); const data = await response.json(); if (data.Success) { showNotification(data.Message, 'success'); setShowDeleteModal(false); setDeleteTargetIdx(null); if (selectedGroupCode) { await loadDataByGroup(selectedGroupCode); } } else { showNotification(data.Message, 'error'); } } catch (error) { console.error('삭제 중 오류 발생:', error); showNotification('삭제 중 오류가 발생했습니다.', 'error'); } finally { setIsLoading(false); } }; // 삭제 요청 const deleteCurrentItem = () => { if (!editData.idx) { showNotification('삭제할 항목이 없습니다.', 'warning'); return; } setDeleteTargetIdx(parseInt(editData.idx)); setShowEditModal(false); setShowDeleteModal(true); }; // 알림 표시 함수 const showNotification = (message, type = 'info') => { const colors = { info: 'bg-blue-500/90 backdrop-blur-sm', success: 'bg-green-500/90 backdrop-blur-sm', warning: 'bg-yellow-500/90 backdrop-blur-sm', error: 'bg-red-500/90 backdrop-blur-sm' }; const icons = { info: ( ), success: ( ), warning: ( ), error: ( ) }; // React에서는 실제 DOM 조작 대신 Toast 라이브러리나 상태로 관리하는 것이 좋습니다 // 여기서는 기존 방식을 유지하되 React 컴포넌트 스타일로 구현 const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`; notification.innerHTML = `
${type === 'info' ? '' : ''} ${type === 'success' ? '' : ''} ${type === 'warning' ? '' : ''} ${type === 'error' ? '' : ''} ${message}
`; notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; document.body.appendChild(notification); setTimeout(() => { notification.style.transform = 'translateX(0)'; notification.style.opacity = '1'; }, 10); setTimeout(() => { notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; setTimeout(() => notification.remove(), 300); }, 3000); }; // 키보드 이벤트 핸들러 useEffect(() => { const handleKeyDown = (e) => { if (e.key === 'Escape') { setShowEditModal(false); setShowDeleteModal(false); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, []); // 입력 필드 변경 핸들러 const handleInputChange = (field, value) => { setEditData(prev => ({ ...prev, [field]: value })); }; return (
{/* 2열 구조 메인 컨테이너 */}
{/* 좌측: 코드그룹 리스트 */}

코드그룹 목록

{groupData.length === 0 ? (
그룹 데이터가 없습니다.
) : ( groupData.map(group => (
selectGroup(group.code, group.memo)} >
{group.code}
{group.memo}
)) )}
{/* 우측: 상세 데이터 */}
{/* 상단 헤더 */}

{selectedGroupCode ? `${selectedGroupCode} - ${selectedGroupName}` : '코드그룹을 선택하세요'}

{currentData.length}

{/* 데이터 테이블 */}
{currentData.length === 0 ? ( ) : ( currentData.map(item => ( editItem(item.idx)} > )) )}
코드 비고 값(문자열) 값(숫자) 값(실수) 값2
{selectedGroupCode ? '데이터가 없습니다.' : '좌측에서 코드그룹을 선택하세요'}
{item.code || '-'} {item.memo || '-'} {item.svalue || '-'} {item.ivalue || '0'} {item.fvalue || '0.0'} {item.svalue2 || '-'}
{/* 로딩 인디케이터 */} {isLoading && (
데이터 로딩 중...
)} {/* 추가/편집 모달 */} {showEditModal && (
{/* 모달 헤더 */}

{isEditMode ? '공용코드 편집' : '공용코드 추가'}

{/* 모달 내용 */}
handleInputChange('code', e.target.value)} required className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="코드를 입력하세요" />
handleInputChange('svalue', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="문자열 값" />
handleInputChange('ivalue', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="숫자 값" />
handleInputChange('fvalue', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="실수 값" />
handleInputChange('svalue2', e.target.value)} className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" placeholder="추가 문자열 값" />
{/* 모달 푸터 */}
)} {/* 삭제 확인 모달 */} {showDeleteModal && (

삭제 확인

이 작업은 되돌릴 수 없습니다.

선택한 공용코드를 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.

)}
); }