import { state } from '../../core/state'; import { SoftwareAsset } from '../../core/excelHandler'; import { openModal } from './BaseModal'; import { openSwUserModal } from './SWUserModal'; import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema'; import { createIcons, History, Plus, X, Save, Edit2, RotateCcw } from 'lucide'; import { CORP_LIST } from './SharedData'; import { generateOptionsHTML, setFieldValue, getFieldValue, setEditLock, createModalFrameHTML, autoFillForm, autoExtractForm } from './ModalUtils'; let currentSwAsset: SoftwareAsset | null = null; let isEditMode = false; /** * 소프트웨어 필드 매핑 (통합 스키마 기반) * 소프트웨어는 자산번호를 사용하지 않으므로 제거함 */ const SW_FIELD_MAP: Record = { '법인': ASSET_SCHEMA.CORP.key, '제품명': ASSET_SCHEMA.PRODUCT.key, '수량': ASSET_SCHEMA.QTY.key, '금액': ASSET_SCHEMA.PRICE.key, '구매일': ASSET_SCHEMA.PURCHASE_YM.key, '시작일': '시작일', '납품업체': ASSET_SCHEMA.VENDOR.key, '비고': ASSET_SCHEMA.REMARKS.key, '플랫폼명': ASSET_SCHEMA.PLATFORM.key, '부서': '부서', '계정명': ASSET_SCHEMA.ACCOUNT.key, '결제수단': ASSET_SCHEMA.PAY_METHOD.key, '연결카드번호': ASSET_SCHEMA.CARD_NUM.key, '결제일': ASSET_SCHEMA.PAY_DAY.key, '당월청구액': ASSET_SCHEMA.BILLING.key, '라이선스유형': ASSET_SCHEMA.LICENSE_TYPE.key, '만료일': ASSET_SCHEMA.EXPIRY.key, '라이선스키': ASSET_SCHEMA.LICENSE_KEY.key }; const SW_FORM_HTML = `
기본 정보 (Identity)
라이선스 및 계약 정보
관리 및 비고

사용자 할당 현황

`; function renderSwHistory(swId: string) { const container = document.getElementById('sw-history-list'); if (!container) return; const logs = (state.masterData.logs || []).filter(l => l.assetId === swId).sort((a,b) => new Date(b.date).getTime() - new Date(a.date).getTime()); if (logs.length === 0) { container.innerHTML = '
수정 이력이 없습니다.
'; return; } container.innerHTML = logs.map(l => `
${l.date}
${l.user}
${l.details.replace(/\n/g, '
')}
`).join(''); } function renderUserSummary(swId: string) { const container = document.getElementById('sw-assigned-users-summary'); if (!container) return; const userMapping = state.masterData.swUsers.find(u => u.sw_id === swId); if (!userMapping || !userMapping.userData || userMapping.userData.length === 0) { container.innerHTML = '
할당된 사용자가 없습니다.
'; return; } container.innerHTML = userMapping.userData.map(u => `
${u[3] || '이름없음'}${u[1] || '부서없음'}
`).join(''); } function applySwTypeUI(type: string) { const cloudFields = document.querySelectorAll('.cloud-only'); const swFields = document.querySelectorAll('.sw-standard-field'); const userSection = document.getElementById('sw-user-section'); const keyGroup = document.getElementById('sw-license-key-group'); const typeGroup = document.getElementById('sw-license-type-group'); const expiryGroup = document.getElementById('sw-expiry-group'); const startGroup = document.getElementById('sw-start-group'); if (type === '클라우드') { cloudFields.forEach(el => (el as HTMLElement).style.display = 'flex'); swFields.forEach(el => (el as HTMLElement).style.display = 'none'); if (userSection) userSection.style.display = 'none'; } else { cloudFields.forEach(el => (el as HTMLElement).style.display = 'none'); swFields.forEach(el => (el as HTMLElement).style.display = 'flex'); if (userSection) userSection.style.display = 'block'; if (type === '구독SW') { if (keyGroup) keyGroup.style.display = 'none'; if (typeGroup) typeGroup.style.display = 'flex'; if (expiryGroup) expiryGroup.style.display = 'flex'; if (startGroup) startGroup.style.display = 'flex'; } else if (type === '영구SW') { if (keyGroup) keyGroup.style.display = 'flex'; if (typeGroup) typeGroup.style.display = 'none'; if (expiryGroup) expiryGroup.style.display = 'none'; if (startGroup) startGroup.style.display = 'flex'; } } } export function openSwModal(asset: SoftwareAsset, mode: 'view' | 'add' = 'view') { currentSwAsset = asset; const modal = document.getElementById('sw-asset-modal')!; setEditLock('sw-asset-form', mode, { saveBtnId: 'btn-save-sw-asset', revertBtnId: 'btn-revert-sw-edit', addLogBtnId: 'btn-add-sw-log' }); isEditMode = (mode === 'add'); autoFillForm('sw', asset, SW_FIELD_MAP); applySwTypeUI(asset.type); renderUserSummary(asset.id); renderSwHistory(asset.id); modal.classList.remove('hidden'); createIcons({ icons: { X, History, Plus } }); } export function initSwModal(onSave: () => void, closeModalsCb: () => void) { if (!document.getElementById('sw-asset-modal')) { const html = createModalFrameHTML('sw', '소프트웨어 상세 정보', SW_FORM_HTML, { historyTitle: '업데이트 내역', addLogBtnId: 'btn-add-sw-log' }); document.body.insertAdjacentHTML('beforeend', html); const logModalHTML = ` `; document.body.insertAdjacentHTML('beforeend', logModalHTML); } const form = document.getElementById('sw-asset-form') as HTMLFormElement; const saveBtn = document.getElementById('btn-save-sw-asset')!; const revertBtn = document.getElementById('btn-revert-sw-edit')!; const deleteBtn = document.getElementById('btn-delete-sw-asset')!; const userAssignBtn = document.getElementById('btn-open-sw-user')!; const userUpdateBtn = document.getElementById('btn-open-sw-update')!; const logAddBtn = document.getElementById('btn-add-sw-log')!; const logModal = document.getElementById('sw-log-modal')!; const typeSelect = document.getElementById('sw-asset-type') as HTMLSelectElement; typeSelect?.addEventListener('change', () => { applySwTypeUI(typeSelect.value); }); const closeModalAction = () => { closeModalsCb(); isEditMode = false; }; document.getElementById('btn-close-sw-modal')?.addEventListener('click', closeModalAction); document.getElementById('btn-cancel-sw-modal')?.addEventListener('click', closeModalAction); revertBtn.addEventListener('click', () => { setEditLock('sw-asset-form', 'view', { saveBtnId: 'btn-save-sw-asset', revertBtnId: 'btn-revert-sw-edit', addLogBtnId: 'btn-add-sw-log' }); isEditMode = false; if (currentSwAsset) openSwModal(currentSwAsset, 'view'); }); // 날짜 필드는 type="date"로 변경되어 별도 제한 로직 불필요 saveBtn.addEventListener('click', () => { if (!currentSwAsset) return; if (!isEditMode) { setEditLock('sw-asset-form', 'edit', { saveBtnId: 'btn-save-sw-asset', revertBtnId: 'btn-revert-sw-edit', addLogBtnId: 'btn-add-hw-log' }); isEditMode = true; return; } const extracted = autoExtractForm('sw', SW_FIELD_MAP); const updated = { ...currentSwAsset, ...extracted, 수량: parseInt(extracted[ASSET_SCHEMA.QTY.key] || '0') }; const type = getFieldValue('sw-asset-type') || currentSwAsset.type; updated.type = type; // 데이터 저장 로직 (state 업데이트) const oldType = currentSwAsset.type; const newType = updated.type; // 유형이 변경된 경우 기존 리스트에서 삭제 if (oldType !== newType) { if (oldType === '구독SW') state.masterData.subSw = state.masterData.subSw.filter(a => a.id !== updated.id); else if (oldType === '영구SW') state.masterData.permSw = state.masterData.permSw.filter(a => a.id !== updated.id); else if (oldType === '클라우드') state.masterData.cloud = state.masterData.cloud.filter(a => a.id !== updated.id); } let targetList: SoftwareAsset[] = []; if (newType === '구독SW') targetList = state.masterData.subSw; else if (newType === '영구SW') targetList = state.masterData.permSw; else targetList = (state.masterData as any).cloud || []; const idx = targetList.findIndex(a => a.id === updated.id); if (idx > -1) targetList[idx] = updated; else targetList.push(updated); onSave(); setEditLock('sw-asset-form', 'view', { saveBtnId: 'btn-save-sw-asset', revertBtnId: 'btn-revert-sw-edit', addLogBtnId: 'btn-add-sw-log' }); isEditMode = false; }); deleteBtn.addEventListener('click', () => { if (currentSwAsset && confirm(UI_TEXT.MESSAGES.CONFIRM_DELETE)) { const type = currentSwAsset.type; if (type === '구독SW') state.masterData.subSw = state.masterData.subSw.filter(a => a.id !== currentSwAsset!.id); else if (type === '영구SW') state.masterData.permSw = state.masterData.permSw.filter(a => a.id !== currentSwAsset!.id); onSave(); closeModalAction(); } }); userUpdateBtn.addEventListener('click', () => { if (currentSwAsset) openSwUserModal(currentSwAsset); }); logAddBtn.addEventListener('click', () => { logModal.classList.remove('hidden'); (document.getElementById('new-log-date') as HTMLInputElement).value = new Date().toISOString().split('T')[0]; (document.getElementById('new-log-details') as HTMLTextAreaElement).value = ''; }); document.getElementById('btn-close-sw-log')?.addEventListener('click', () => logModal.classList.add('hidden')); document.getElementById('btn-cancel-sw-log')?.addEventListener('click', () => logModal.classList.add('hidden')); document.getElementById('btn-confirm-sw-log')?.addEventListener('click', () => { if (!currentSwAsset) return; const date = (document.getElementById('new-log-date') as HTMLInputElement).value; const details = (document.getElementById('new-log-details') as HTMLTextAreaElement).value; if (!date || !details) return; state.masterData.logs = state.masterData.logs || []; state.masterData.logs.push({ id: Math.random().toString(36).substring(2, 9), assetId: currentSwAsset.id, date, user: '담당자', details }); logModal.classList.add('hidden'); renderSwHistory(currentSwAsset.id); }); }