import { vars } from '../archive/variable.js'; import { docVars } from './docVariable.js'; import { checkProjectInactive } from '../main.js'; import { getAiUsed, syncDocInfo, getDocDataBySelected, getGroupCompanyData, uploadDocFile, upsertDocData } from './docDataManager.js'; import { initCustomSelectBoxes, renderDocViewer, itemBoxSelected } from './docPageRenderer.js'; let fileArr = []; let originCompanyList = []; let timeoutId; function debounce(func, delay) { return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(this, args); }, delay); }; } /*****************************************************************************************************************************/ /**************************************************************************************************************** AI 선택 모달 */ /*****************************************************************************************************************************/ let aiChoiceConfirmCallback = null; export async function openDocAiChoiceModal(onConfirm) { if (checkProjectInactive()) return; // 체크 초기화 // const radioButtons = document.querySelectorAll('input[name="aiChoice"]'); // radioButtons.forEach(radio => { // radio.checked = false; // }); aiChoiceConfirmCallback = onConfirm; // 콜백 저장 const modalBackground = document.querySelector('.official-doc-modal-background'); const modalContainer = document.querySelector('.official-doc-modal.official-doc-ai-choice-modal'); modalBackground.style.display = 'flex'; modalContainer.style.display = 'flex'; } function clickDocAiChoiceModalConfirm() { if (checkProjectInactive()) return; const confirmBtn = document.querySelector('.official-doc-modal.official-doc-ai-choice-modal .official-doc-positive-btn'); confirmBtn.addEventListener('click', async () => { const selectedRadio = document.querySelector('input[name="aiChoice"]:checked'); if (!selectedRadio) { alert('사용할 AI를 선택해주세요.'); return; } const selectedValue = selectedRadio?.value; // 모달 닫기 document.querySelector('.official-doc-modal-background').style.display = 'none'; document.querySelector('.official-doc-modal.official-doc-ai-choice-modal').style.display = 'none'; // 저장된 콜백 실행 if (aiChoiceConfirmCallback) { aiChoiceConfirmCallback(selectedValue); aiChoiceConfirmCallback = null; // 재사용 대비 초기화 } }); } clickDocAiChoiceModalConfirm(); function clickDocAiChoiceModalCancel() { if (checkProjectInactive()) return; const modalBackground = document.querySelector('.official-doc-modal-background'); const modal = document.querySelector('.official-doc-modal.official-doc-ai-choice-modal'); const cancelBtn = document.querySelector('.official-doc-modal.official-doc-ai-choice-modal .official-doc-negative-btn'); if (!cancelBtn || !modal) return; cancelBtn.addEventListener('click', () => { modalBackground.style.display = 'none'; modal.style.display = 'none'; }); } clickDocAiChoiceModalCancel(); /*****************************************************************************************************************************/ /************************************************************************************** 추가모달 수정모달 사용자입력모달 업서트모달 */ /*****************************************************************************************************************************/ export async function openDocUpsertModal(data, droppedFiles, fileName, mode = 'add') { const modalBackground = document.querySelector('.official-doc-modal-background'); const modalContainer = document.querySelector('.official-doc-modal.official-doc-upsert-modal'); modalBackground.style.display = 'flex'; modalContainer.style.display = 'flex'; modalContainer.dataset.originFileName = mode === 'edit' ? data?.file_path?.split('/')?.pop() || '' : fileName || ''; modalContainer.dataset.mode = mode; /***** 업서트모달 헤더 */ const realFileName = mode === 'edit' ? data?.file_path?.split('/')?.pop() || '수정' : fileName || '추가'; createDocModalHeader(realFileName); /***** 업서트모달 바디 */ await createDocModalBody(modalContainer, data, mode, droppedFiles); /***** 업서트모달 프리뷰 */ handleDocModalPreview(modalContainer, data, mode, droppedFiles); // 모달 백그라운드 누르면 모달 초기화 + flex none 되기 // modalBackground.addEventListener('pointerdown', () => { // modalContainer.style.display = 'none'; // modalHeader.innerHTML = ''; // modalBody.innerHTML = ''; // docModalPreview.innerHTML = ''; // modalBackground.style.display = 'none'; // droppedFiles = []; // }); } // 업서트모달 헤더 만들기 function createDocModalHeader(realFileName) { const modalHeader = document.querySelector('.official-doc-modal.official-doc-upsert-modal .official-doc-modal-header'); const icon = document.createElement('img'); icon.classList.add('icon'); icon.src = '/main/img/officialDoc/Ficon-pdf.svg'; icon.alt = 'Ficon-pdf'; const title = document.createElement('h3'); title.classList.add('text-green'); title.textContent = realFileName; modalHeader.appendChild(icon); modalHeader.appendChild(title); return modalHeader; } // 업서트모달 바디 const createDocModalBody = async(modalContainer, data, mode, droppedFiles) => { const modalBody = modalContainer.querySelector('.official-doc-modal-body'); modalBody.innerHTML = ''; // 기존 내용 초기화 // 추가모드일 때만 필요한 파일과 아이디 if (mode === 'add' || mode === 'input') { fileArr = droppedFiles; docVars.currentGroupId = await getDocSeq(); } // 입력 필드 만들기 const inputFields = getInputFields(data, mode); inputFields.forEach(({ label, type = 'text', name, value, placeholder, attrs = {}, extra = null }) => { const input = createInputField(type, name, value, placeholder, attrs); modalBody.appendChild(type === 'hidden' ? input : createInputWrap(label, input, extra)); }); // 수신처에 따른 수/발신 영역 자동으로 채우기 populateCompanySelectOption(modalBody); // 공문종류 셀렉트박스 옵션 채우기 populateCategorySelectOption(modalBody); // addSelectOptionListener(modalBody); // 수정모드에서 구분(발주처/외) 채우기 if (mode === 'edit') populateCompanyType(); }; // 업서트모달 바디 : 입력필드 function getInputFields(data, mode) { const safeData = typeof data === 'object' && data !== null ? data : {}; return [ { label: 'group_id', type: 'hidden', name: 'group_id', value: `${docVars.currentGroupId}` }, { label: '수신처 *', type: 'text', name: 'recipient_org', value: safeData.수신처 ?? '', attrs: { readonly: true, id: 'recipient_org' }, extra: createDocCustomSelectbox('recipient', safeData.수신처약자 ?? '수신처'), placeholder: '오른쪽 셀렉트박스에서 회사를 선택해주세요.' ?? '', }, { label: '수신자', type: 'text', name: 'recipient_name', value: safeData.수신자 ?? '' }, { label: '수신자 약자 *', type: 'text', name: 'recipient_name_abbr', value: safeData.수신자약자 ?? '' }, { label: '발신처 *', type: 'text', name: 'sender_org', value: safeData.발신처 ?? '', attrs: { readonly: true, id: 'sender_org' }, extra: createDocCustomSelectbox('sender', safeData.발신처약자 ?? '발신처'), placeholder: '오른쪽 셀렉트박스에서 회사를 선택해주세요.' ?? '', }, { label: '발신자', type: 'text', name: 'sender_name', value: safeData.발신자 ?? '' }, { label: '발신자 약자 *', type: 'text', name: 'sender_name_abbr', value: safeData.발신자약자 ?? '' }, { label: '수신 / 발신', type: 'text', name: 'doc_direction', value: safeData.doc_direction ?? '', attrs: { readonly: true, id: 'doc-direction' }, placeholder: '수신처를 선택하시면 자동으로 입력됩니다.' ?? '', }, { label: '구분(발주처/외)', type: 'text', name: 'company_type', value: '', attrs: { readonly: true, id: 'company-type' }, placeholder: '수신처를 선택하시면 자동으로 입력됩니다.' ?? '', }, { label: '공문번호 *', type: 'text', name: 'doc_number', value: safeData.공문번호 ?? '' }, { label: '유형', type: 'text', name: 'doc_type', value: safeData.공문유형 ?? '' }, { label: '종류 *', type: 'text', name: 'category', value: safeData.공문종류 ?? '', attrs: { readonly: true, id: 'doc-category' }, extra: createDocCustomSelectbox('category', safeData.공문종류 ?? ''), }, { label: '제목 *', type: 'text', name: 'doc_title', value: safeData.공문제목 ?? '' }, { label: '제목요약 *', type: 'text', name: 'doc_title_summary', value: safeData.공문제목요약 ?? '' }, { label: '연관공문', type: 'text', name: 'doc_related_docs', value: safeData.공문간연계 ?? '' }, { label: '사내담당', type: 'text', name: 'doc_manager', value: safeData.doc_manager ?? '' }, { label: '공문일자 *', type: 'date', name: 'doc_date', value: safeData.공문일자 ?? '' }, { label: '내용요약', type: 'textarea', name: 'doc_content_summary', value: safeData.공문내용요약 ?? '' }, { label: '특이사항', type: 'textarea', name: 'doc_memo', value: safeData.doc_memo ?? '' }, { label: '첨부문서수', type: 'text', name: 'attachment_count', value: safeData.첨부문서수 ?? '' }, { label: '첨부문서제목', type: 'hidden', name: 'attachment_title', value: safeData.첨부문서제목 ?? '' }, ]; } // 업서트모달 바디 : 입력필드 wrapper 만들기 const createInputWrap = (labelText, inputElement, extraElement = null) => { const wrap = document.createElement('div'); wrap.className = 'official-doc-type-wrap'; const label = document.createElement('p'); // 필수입력 * 빨간색으로 표시 if (labelText.includes('*')) { const parts = labelText.split('*'); label.innerHTML = `${parts[0]}*`; } else { label.textContent = labelText; } wrap.appendChild(label); if (labelText != '종류') wrap.appendChild(inputElement); if (extraElement) wrap.appendChild(extraElement); return wrap; }; // 업서트모달 바디 : 입력필드 만들기 const createInputField = (type, name, value, placeholder, attrs = {}) => { let inputElement; if (type === 'textarea') { inputElement = document.createElement('textarea'); } else { inputElement = document.createElement('input'); inputElement.type = type; } inputElement.name = name; inputElement.value = value; if (placeholder !== undefined) inputElement.placeholder = placeholder; Object.entries(attrs).forEach(([key, val]) => inputElement.setAttribute(key, val)); return inputElement; }; // 업서트모달 바디 : 입력필드 셀렉트박스 만들기 function createDocCustomSelectbox(id, selectedText) { const wrap = document.createElement('div'); wrap.classList.add('doc-modal-custom-select-wrap'); wrap.id = `doc-modal-select-${id}`; const select = document.createElement('div'); select.classList.add('doc-modal-custom-select'); select.id = `doc-modal-custom-select-${id}`; select.setAttribute('tabindex', '0'); const div1 = document.createElement('div'); div1.className = 'doc-modal-custom-select-div'; const span = document.createElement('span'); span.className = 'selected'; if (id === 'category') { if (['행정/일반', '기술/성과물', '회의/기타'].includes(selectedText)) { span.textContent = selectedText; } else { span.textContent = '종류를 선택해주세요.'; } } else { span.textContent = selectedText; } div1.appendChild(span); select.appendChild(div1); const div2 = document.createElement('div'); div2.className = 'doc-select-icon-wrap'; const img = document.createElement('img'); img.className = 'doc-select-icon'; img.src = '/main/img/officialDoc/icon-down-sign-aaa.svg'; img.alt = 'icon-down-sign-aaa'; div2.appendChild(img); select.appendChild(div2); const optionsDiv = document.createElement('div'); optionsDiv.className = 'options'; select.appendChild(optionsDiv); wrap.appendChild(select); return wrap; } // 업서트모달 바디 : 입력필드 수신처, 발신처에 따른 수/발신 값 자동으로 채우기 function populateCompanySelectOption(modalBody) { const recipientWrapper = document.querySelector('#doc-modal-select-recipient'); // 수신처 const senderWrapper = document.querySelector('#doc-modal-select-sender'); // 발신처 const directioninput = document.querySelector('#doc-direction'); // 수/발신 const rolePairMap = { 기준: '상대기관', 상대기관: '기준', 발주처: '수신처', 수신처: '발주처', }; // 옵션 생성 함수 const createOption = (wrapper, role, type, name, id) => { const option = document.createElement('div'); option.classList.add('option'); option.textContent = `${name} (${type}, ${role})`; option.dataset.companyRole = role; option.dataset.companyType = type; option.dataset.companyId = id; option.dataset.companyName = name; option.addEventListener('click', () => { wrapper.querySelector('.selected').textContent = name; if (wrapper.id === 'doc-modal-select-recipient') { const recipientRole = role; const companyType = type; const counterpartRole = rolePairMap[recipientRole]; directioninput.value = recipientRole === '기준' || recipientRole === '발주처' ? '수신' : '발신'; document.querySelector('#recipient_org').value = name; document.querySelector('#company-type').value = companyType; const senderOptionsWrapper = senderWrapper.querySelector('.options'); senderOptionsWrapper.innerHTML = ''; const counterpartList = docVars.groupCompanyData[companyType][counterpartRole] || []; counterpartList.forEach(({ name: counterName, id: counterId }, idx) => { const counterOption = document.createElement('div'); counterOption.classList.add('option'); counterOption.textContent = counterName; counterOption.dataset.companyRole = counterpartRole; counterOption.dataset.companyType = companyType; counterOption.dataset.companyId = counterId; counterOption.addEventListener('click', () => { senderWrapper.querySelector('.selected').textContent = counterName; document.querySelector('#sender_org').value = counterName; }); senderOptionsWrapper.appendChild(counterOption); if (idx === 0) { senderWrapper.querySelector('.selected').textContent = counterName; document.querySelector('#sender_org').value = counterName; } }); } if (wrapper.id === 'doc-modal-select-sender') { document.querySelector('#sender_org').value = name; } }); wrapper.querySelector('.options').appendChild(option); }; // 수/발신 박스에 옵션 각각 생성 for (const type in docVars.groupCompanyData) { const roleGroups = docVars.groupCompanyData[type]; for (const role in roleGroups) { const companies = roleGroups[role]; companies.forEach(({ name, id }) => { createOption(recipientWrapper, role, type, name, id); createOption(senderWrapper, role, type, name, id); }); } } } function addSelectOptionListener(modalBody) { if (!modalBody.dataset.listenerAttached) { modalBody.addEventListener('click', (e) => { const select = e.target.closest('.doc-modal-custom-select'); const option = e.target.closest('.option'); if (option && select) { e.stopPropagation(); const selected = select.querySelector('.selected'); selected.innerText = option.innerText.trim(); select.classList.remove('open'); } else if (select) { e.stopPropagation(); document.querySelectorAll('.doc-modal-custom-select').forEach((s) => { if (s !== select) s.classList.remove('open'); }); select.classList.toggle('open'); } else { document.querySelectorAll('.doc-modal-custom-select').forEach((s) => s.classList.remove('open')); } const selectWrapper = e.target.closest('.doc-modal-custom-select-wrap'); const selectedText = option?.innerText; if (selectWrapper && selectWrapper.id === 'doc-modal-select-recipient' && option) { const selectedName = option.dataset.companyName; const selectedType = option.dataset.companyType; let direction = ''; let companyType = ''; for (const type in docVars.groupCompanyData) { const base = docVars.groupCompanyData[type]['기준'] || []; const target = docVars.groupCompanyData[type]['상대기관'] || []; const buyer = docVars.groupCompanyData[type]['발주처'] || []; const receiver = docVars.groupCompanyData[type]['수신처'] || []; const isInBaseOrBuyer = base.some((item) => item.name === selectedName && type === selectedType) || buyer.some((item) => item.name === selectedName && type === selectedType); const isInTargetOrReceiver = target.some((item) => item.name === selectedName && type === selectedType) || receiver.some((item) => item.name === selectedName && type === selectedType); if (isInBaseOrBuyer) { direction = '수신'; companyType = type; break; } else if (isInTargetOrReceiver) { direction = '발신'; companyType = type; break; } } document.querySelector('#doc-direction').value = direction; document.querySelector('#company-type').value = companyType; document.querySelector('#recipient_org').value = selectedName; } if (selectWrapper && selectWrapper.id === 'doc-modal-select-sender' && option) { document.querySelector('#sender_org').value = selectedText; } }); // 중복 리스너 방지 modalBody.dataset.listenerAttached = 'true'; } } // 업서트모달 바디 : 수정모드에서 구분(발주처/외) 채우기 const populateCompanyType = () => { const selectedText = document.querySelector('.official-doc-modal-body .doc-modal-custom-select-wrap .doc-modal-custom-select-div .selected').innerHTML; // 선택한 값 const options = document.querySelectorAll('.official-doc-modal-body .doc-modal-custom-select-wrap .options .option'); // 모든 옵션 options.forEach(option => { let pureCompanyName = getPureCompanyName(option.textContent) if (pureCompanyName.trim() === selectedText.trim()) { // selectedText와 옵션의 텍스트가 일치하는지 // 일치하는 옵션을 찾았으면 그 옵션의 data-company-type을 입력 필드에 채워줌 const companyType = option.dataset.companyType; // data-company-type 값 가져오기 const companyTypeInput = document.querySelector('#company-type'); // 입력 필드 companyTypeInput.value = companyType; } }); }; // 업서트모달 바디 : 종류 셀렉트박스 옵션 function populateCategorySelectOption(modalBody) { const categoryWrapper = document.querySelector('#doc-modal-custom-select-category'); const optionsWrapper = categoryWrapper.querySelector('.options'); const categoryInput = document.querySelector('.official-doc-modal .official-doc-modal-block .official-doc-modal-body .official-doc-type-wrap #doc-category'); const validOptions = ['행정/일반', '기술/성과물', '회의/기타']; const createOption = (wrapper) => { const options = validOptions; options.forEach(optionText => { const optionDiv = document.createElement('div'); optionDiv.className = 'option'; optionDiv.textContent = optionText; optionDiv.addEventListener('click', () => { if (validOptions.includes(optionText)) { categoryWrapper.querySelector('.selected').textContent = optionText; categoryInput.value = optionText; } categoryWrapper.classList.remove('open'); }); wrapper.appendChild(optionDiv); }); }; createOption(optionsWrapper); } // 업서트모달 프리뷰 만들기 async function handleDocModalPreview(modalContainer, data, mode, droppedFiles) { const docModalPreview = modalContainer.querySelector('.official-doc-modal-preview'); docModalPreview.innerHTML = ''; docModalPreview.style.display = 'flex'; if (mode === 'edit') { // 수정모드 let PresignedUrl = undefined; const resourcePath = data.file_path; await syncDocInfo(['official', 'attach', null]); let objectKey = docVars.allDocData?.find((doc) => doc.doc_id === data.공문아이디)?.preview_key; let generateDownloadUrlParams = { objectKey: objectKey, resourcePath: resourcePath, }; let generateDownloadUrlRes = await axios.post(`${docVars.path_name}/generateDownloadDocUrl`, generateDownloadUrlParams); if (generateDownloadUrlRes.data.message == 'generateDownloadDocUrl_success') { PresignedUrl = generateDownloadUrlRes.data.url; } if (PresignedUrl) { const response = await fetch(PresignedUrl); const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); const iframe = document.createElement('iframe'); iframe.src = `/libs/pdfViewer/web/viewer.html`; iframe.addEventListener('load', () => { const app = iframe.contentWindow.PDFViewerApplication; app.pdfCursorTools._handTool.activate(); app.open({ url: blobUrl }); app.appConfig.mainContainer.classList.add('scrollbar'); app.appConfig.mainContainer.style.marginLeft = '4px'; }); docModalPreview.appendChild(iframe); } } else if (mode === 'add' || mode === 'input') { // 추가모드 const file = droppedFiles[0]; const fileURL = URL.createObjectURL(file); const iframe = document.createElement('iframe'); iframe.src = `/libs/pdfViewer/web/viewer.html`; iframe.addEventListener('load', () => { const app = iframe.contentWindow.PDFViewerApplication; app.pdfCursorTools._handTool.activate(); app.open({ url: fileURL }); }); docModalPreview.appendChild(iframe); } } // 업서트모달 취소버튼 function clickDocUpsertModalCancel() { if (checkProjectInactive()) return; const modalBackground = document.querySelector('.official-doc-modal-background'); const modal = document.querySelector('.official-doc-modal.official-doc-upsert-modal'); const modalHeader = modal?.querySelector('.official-doc-modal-header'); const modalBody = modal?.querySelector('.official-doc-modal-body'); const docModalPreview = modal?.querySelector('.official-doc-modal-preview'); const cancelBtn = document.querySelector('.official-doc-modal.official-doc-upsert-modal .official-doc-modal-block .official-doc-modal-footer .official-doc-negative-btn'); if (!cancelBtn || !modal) return; cancelBtn.addEventListener('click', () => { modalBackground.style.display = 'none'; modal.style.display = 'none'; modal.dataset.originFileName = ''; modal.dataset.mode = ''; modalHeader.innerHTML = ''; modalBody.innerHTML = ''; docModalPreview.innerHTML = ''; }); } clickDocUpsertModalCancel(); // 업서트모달 필수입력 유효성 검사 function validateDocModalInput(modalContainer) { const inputWraps = modalContainer.querySelectorAll('.official-doc-type-wrap'); let isValid = true; inputWraps.forEach((wrap) => { const label = wrap.querySelector('p'); const input = wrap.querySelector('input, textarea'); // label에 *이 있으면 필수입력 if (label && label.innerText.includes('*')) { const value = input?.value.trim(); if (!value) { isValid = false; } } }); return isValid; } // 업서트모달 확인버튼 const confirmBtn = document.querySelector('.official-doc-upsert-modal .official-doc-modal-block .official-doc-modal-footer .official-doc-positive-btn'); const clickDocUpsertModalConfirm = debounce(async() => { if (checkProjectInactive()) return; // 필수입력 유효성 검사 const modalContainer = document.querySelector('.official-doc-modal.official-doc-upsert-modal'); const isValid = validateDocModalInput(modalContainer); if (!isValid) { alert('필수 항목을 모두 입력해주세요.'); return; } // textarea 엔터 제거 const rawSummary = document.querySelector('textarea[name="doc_content_summary"]').value.trim(); const cleanSummary = rawSummary.replace(/\r?\n/g, ' '); const rawMemo = document.querySelector('textarea[name="doc_memo"]').value.trim(); const cleanMemo = rawMemo.replace(/\r?\n/g, ' '); // 회사명에서 괄호 뒤에 글자 빼기 > (발주처, 기준) const recipientOrgFullText = document.querySelector('#doc-modal-select-recipient .selected').innerText; const senderOrgFullText = document.querySelector('#doc-modal-select-sender .selected').innerText; const categoryText = document.querySelector('#doc-modal-custom-select-category .selected').innerText; const mode = modalContainer.dataset.mode; const existingFileName = modalContainer.dataset.originFileName || ''; const droppedFile = fileArr?.[0]; const fileName = droppedFile ? droppedFile.name : existingFileName; const formData = { group_id: document.querySelector('input[name="group_id"]').value.trim(), recipient_org: document.querySelector('input[name="recipient_org"]').value.trim(), recipient_org_abbr: getPureCompanyName(recipientOrgFullText), recipient_name: document.querySelector('input[name="recipient_name"]').value.trim(), recipient_name_abbr: document.querySelector('input[name="recipient_name_abbr"]').value.trim(), sender_org: document.querySelector('input[name="sender_org"]').value.trim(), sender_org_abbr: getPureCompanyName(senderOrgFullText), sender_name: document.querySelector('input[name="sender_name"]').value.trim(), sender_name_abbr: document.querySelector('input[name="sender_name_abbr"]').value.trim(), doc_direction: document.querySelector('input[name="doc_direction"]').value.trim(), doc_number: document.querySelector('input[name="doc_number"]').value.trim(), doc_type: document.querySelector('input[name="doc_type"]').value.trim(), doc_category: categoryText, doc_title: document.querySelector('input[name="doc_title"]').value.trim(), doc_title_summary: document.querySelector('input[name="doc_title_summary"]').value.trim(), doc_related_docs: document.querySelector('input[name="doc_related_docs"]').value.trim(), doc_date: document.querySelector('input[name="doc_date"]').value.trim(), doc_content_summary: cleanSummary, attachment_title: document.querySelector('input[name="attachment_title"]').value.trim(), attachment_count: document.querySelector('input[name="attachment_count"]').value.trim(), doc_manager: document.querySelector('input[name="doc_manager"]').value.trim(), doc_memo: cleanMemo, doc_label: 'official', file_name: fileName, is_aiused: getAiUsed(), }; // 수신/발신 선택 확인 const recipientInnerText = document.querySelector('#doc-modal-select-recipient .selected').innerText; const senderInnerText = document.querySelector('#doc-modal-select-sender .selected').innerText; if (recipientInnerText === '수신처' || senderInnerText === '발신처') { alert('수신처 또는 발신처를 선택해주세요.'); return; } try { if (mode === 'add' || mode === 'input') { const uploadResult = await uploadDocFile(fileArr, 'modal_add'); if (!uploadResult.success) { alert('파일 업로드에 실패했습니다.'); return; } formData.file_name = fileName; formData.userInfoString = vars.userInfoString; formData.uploadParams = uploadResult.uploadParams; formData.uploadSuccessFileArr = uploadResult.uploadSuccessFileArr; formData.uploadFailedFileArr = uploadResult.uploadFailedFileArr; // 메타데이터 DB에 저장 await upsertDocData(formData, 'modal_add'); } else { // 수정 모드일 경우 DB에 내용만 업데이트 await upsertDocData(formData, 'modal_edit'); } // 모달 닫기 및 초기화 document.querySelector('.official-doc-modal-background').style.display = 'none'; const modal = document.querySelector('.official-doc-modal.official-doc-upsert-modal'); modal.style.display = 'none'; modal.querySelector('.official-doc-modal-header').innerHTML = ''; modal.querySelector('.official-doc-modal-body').innerHTML = ''; alert('저장이 완료되었습니다.'); await syncDocInfo(['official', 'attach', null]); await getDocDataBySelected(); let docId = docVars.selectedDoc?.doc_id; let newLi = document.querySelector(`li[data-doc-id="${docId}"]`); if (newLi) { itemBoxSelected(newLi); // await renderDocViewer(newLi.dataset.resourcePath, newLi.dataset.docId); if (mode === 'edit') { await renderDocViewer(newLi.dataset.resourcePath, newLi.dataset.docId); } } } catch (err) { console.error('❌ 저장 중 오류 발생:', err); alert('저장 중 오류가 발생했습니다.'); } }, 500); confirmBtn.addEventListener('click', clickDocUpsertModalConfirm); // 마지막 시퀀스 가져오기 // 공문 아이디 저장용 async function getDocSeq() { try { const res = await axios.get(`${docVars.path_name}/getDocSeq`); let currNum = parseInt(res.data.data); return currNum; } catch (error) { console.error('getDocSeq error', error); } } /******************************************************************************************************************************/ /***************************************************************************************************************** 세팅모달 설정모달 */ /******************************************************************************************************************************/ async function openDocSettingModal() { if (checkProjectInactive()) return; const settingBtn = document.querySelector('.official-doc-setting-button'); const settingModalContainer = document.querySelector('.official-doc-modal.official-doc-setting-modal'); const modalBackground = document.querySelector('.official-doc-modal-background'); const orderBaseContainer = document.querySelector('.order-base'); const orderTargetContainer = document.querySelector('.order-target'); const otherOrderBaseContainer = document.querySelector('.other-order-base'); const otherOrderTargetContainer = document.querySelector('.other-order-target'); // input 템플릿 함수 const getInputHTML = (name, companyId = '') => `