import { vars } from './variable.js'; // 파일 사이즈 변환 export function formatBytes(bytes) { const abs = Math.abs(bytes); let size, unit; if (abs < 1024) { size = addCommasToNumber(bytes); unit = ' Bytes'; } else if (abs < 1048576) { size = addCommasToNumber((bytes / 1024).toFixed(2)); unit = ' KB'; } else if (abs < 1073741824) { size = addCommasToNumber((bytes / 1048576).toFixed(2)); unit = ' MB'; } else if (abs < 1099511627776) { size = addCommasToNumber((bytes / 1073741824).toFixed(2)); unit = ' GB'; } else { size = addCommasToNumber((bytes / 1099511627776).toFixed(2)); unit = ' TB'; } if (size != 0) { let decimalPointNum = size.split('.')[1]; if (decimalPointNum) { // 소수점 아래 숫자가 00인 경우 if (decimalPointNum == '00') size = size.split('.')[0]; // 소수점 아래 두번째 숫자가 0인 경우 else if (decimalPointNum[1] == '0') size = `${size.split('.')[0]}.${decimalPointNum[0]}`; } } return size + unit; } // 1000 단위 콤마 추가 // export function addCommasToNumber(num) { // return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); // } export function addCommasToNumber(num) { const isNegative = Number(num) < 0; const parts = Math.abs(Number(num)).toString().split('.'); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); const formatted = parts.join('.'); return isNegative ? `-${formatted}` : formatted; } export function getDepth(path) { path = path.startsWith('/') ? path.slice(1) : path; let pathSplit = path.split('/'); let result = pathSplit.length; return result; } export function updatePartialPath(sourcePath, targetPath) { let sourcePathSplit = sourcePath.split('/'); let targetPathSplit = targetPath.split('/'); for (let i = 0; i < sourcePathSplit.length; i++) { targetPathSplit[i] = sourcePathSplit[i]; } return targetPathSplit.join('/'); } // 파일명, 확장자 분리 export function splitBaseAndExt(target, isLowerExt) { let targetSplit = target.split('.'); let ext = targetSplit.pop(); if (isLowerExt) ext = ext.toLowerCase(); let base = targetSplit.join('.'); return { ext: ext, base: base } } // 선택한 대상이 포함된 상위 폴더 경로 추출 export function splitTopPathAndTargetName(resourcePath) { let resourcePathSplit = resourcePath.split('/'); let targetName = resourcePathSplit.pop(); let topPath = resourcePathSplit.join('/'); if (!topPath || topPath == '' || topPath == null) topPath = '/'; return { targetName: targetName, topPath: topPath }; } export function extractPathByLength(target, count) { if (!Array.isArray(target)) { target = target.split('/'); } const parts = target.filter(Boolean).slice(0, count); return '/' + parts.join('/'); } // 특수문자를 체크하는 정규표현식 export function hasSpecialChar(target) { // const pattern = /[\/\\;:?`'"<>|#%&*]/; const pattern = /[\/\\:*?'"`<>|#]/; return pattern.test(target); } // 동일한 폴더명/파일명 존재 여부 확인 export function existEqualName(type, comparisonPath, targetName) { let result; if (comparisonPath != '' && comparisonPath != undefined) { result = getTypeDataFromFolderData(type, comparisonPath)[targetName]; } else { // result = vars.currentTreeObject[type][targetName]; result = vars.allTreeObject[type][targetName]; } // 헤더 버튼 이름 변경 시 페이지 버튼과 이름 같은 경우 변경 불가 let pageBtnNameArr = ['과업개요', '공문']; if (comparisonPath == '/' && result == undefined) result = pageBtnNameArr.includes(targetName); return result; // folderData에서 타입(폴더/파일)과 경로를 사용해서 해당 경로의 타입별 데이터 가져오기 function getTypeDataFromFolderData(type, path) { let data; if (type == 'folder') data = vars.allTreeObject[type]; if (type == 'file') data = vars.currentTreeObject[type]; let pathSplit = path.split('/'); pathSplit.shift(); // if (pathSplit[0] == '') return data; for (let i = 0; i < pathSplit.length; i++) { if (data[pathSplit[i]]) { if (type == 'folder') data = data[pathSplit[i]]['child'][type]; if (type == 'file') data = data; } else { data = data; } } return data; } } export function getNextFileName(nameArr, newName) { const dotIdx = newName.lastIndexOf('.'); const base = dotIdx !== -1 ? newName.slice(0, dotIdx) : newName; const ext = dotIdx !== -1 ? newName.slice(dotIdx) : ''; const set = new Set(nameArr); let maxNum = 0; const regex = new RegExp(`^${escapeRegExp(base)}(?: \\((\\d+)\\))?${escapeRegExp(ext)}$`); for (const name of set) { const match = name.match(regex); if (match) { const num = match[1] ? parseInt(match[1], 10) : 0; if (num > maxNum) maxNum = num; } } if (maxNum === 0 && !set.has(newName)) return newName; return `${base} (${maxNum + 1})${ext}`; function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } } export function getDataFromTreeObject(path, type, data) { let parentData; if (!data) data = vars.allTreeObject; let pathSplit = path.split('/'); pathSplit.shift(); for (let i = 0; i < pathSplit.length; i++) { if (i != pathSplit.length - 1) { if (data['folder'][pathSplit[i]]) { data = data['folder'][pathSplit[i]]['child']; } } else { if (type == 'folder') { parentData = data; data = data['folder'][pathSplit[i]]; } if (type == 'file') { if (data['file'][pathSplit[i]]) { parentData = data; data = data['file'][pathSplit[i]]; } } } } return { parentData: parentData, data: data }; } export function getCurrentTreeObject(path) { let data = vars.allTreeObject; let pathSplit = path.split('/'); pathSplit.shift(); for (let i = 0; i < pathSplit.length; i++) { if (i != pathSplit.length - 1) { if (data['folder'][pathSplit[i]]) { data = data['folder'][pathSplit[i]]['child']; } } else { if (data['folder'][pathSplit[i]]) data = data['folder'][pathSplit[i]]['child']; } } return data; } export function targetFocus(target, behavior = 'smooth') { target.scrollIntoView({ behavior: behavior, // 부드럽게 block: 'center', // 화면 중앙에 위치하도록 (start, end, nearest 도 가능) inline: 'center' }); target.focus(); } export function pxToRem(px) { let remPx = parseFloat(getComputedStyle(document.documentElement).fontSize); return px / remPx; } export function buildResourcePathFromSegments(rows) { if (!Array.isArray(rows)) rows = [rows]; let result = []; rows.map(row => { let resourcePath = '/'; let maxDepth = 8; let arr = []; for (let i = 0; i < maxDepth; i++) { let num = i+1; let segment = row[`path${num}`]; if (segment) arr.push(segment); } if (arr.length != 0) resourcePath += arr.join('/'); result.push(resourcePath); }) return result; } export function headerBtnForceClick(headerBtn) { headerBtn.click(); } export function treeBtnForceClick(treeBtn) { treeBtn.click(); } export function closeInitProgress() { document.querySelector('.init-progress').style.display = 'none'; } export async function getMyDownloadList(){ let res = await axios.get(`${vars.path_name}/getMyDownloadList`, {params : {user_id : JSON.parse(vars.userInfoString).user_id}}); // console.log(res.data); if(res.data.length > 0){ if(document.querySelector('.download-btn .download-reddot')){ document.querySelector('.download-btn .download-reddot').style.display = 'block'; } }else{ if(document.querySelector('.download-btn .download-reddot')){ document.querySelector('.download-btn .download-reddot').style.display = 'none'; } } let ul = document.querySelector('.download-modal__body_list'); ul.innerHTML = ''; for(let i = 0; i < res.data.length; i++){ let li = document.createElement('li'); li.classList.add('download-modal__body_list_item'); let expireDate = new Date(res.data[i].expire_date); let now = new Date(); let yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000); let state = (expireDate < yesterday)? `/`: (!res.data[i].made)?`준비중`:`/` let expire =(state == '준비중')?state :(expireDate < yesterday)? '만료됨': formatDateTime(expireDate); li.innerHTML = ` /

${res.data[i].name}

${res.data[i].project_nm}${res.data[i].path}

${expire}
${state}
`; ul.appendChild(li); li.querySelector('.downloadFolder__btn__icon')?.addEventListener('click', () => { window.location.href = res.data[i].url; }) } function formatDateTime(date) { const padZero = (num) => String(num).padStart(2, '0'); const year = date.getFullYear(); const month = padZero(date.getMonth() + 1); // getMonth()는 0부터 시작하므로 +1 const day = padZero(date.getDate()); const hours = padZero(date.getHours()); const minutes = padZero(date.getMinutes()); return `${year}-${month}-${day} ${hours}:${minutes}`; } } export async function openNewWindowViewer() { let isRecycleBinModal = document.querySelector('.recycle-bin-modal').style.display == 'flex'; let lastListItem = (isRecycleBinModal) ? vars.lastListItem_bin : vars.lastListItem; let resourcePath = lastListItem.dataset.resourcePath; let dataId = lastListItem.dataset.id; let isLowerExt = true, ext = splitBaseAndExt(resourcePath, isLowerExt).ext; let thumbnail_key = getDataFromTreeObject(resourcePath, 'file', vars.currentTreeObject).data?.thumbnailKey; //Presigned URL let PresignedUrl = undefined; let getDataInfoParams = { userInfoString: vars.userInfoString, storageType: vars.storageType, dataIdArr: [dataId], isRemoved: isRecycleBinModal, debug: "'우측 미리보기 새 창으로 열기 버튼 클릭 이벤트'에서 실행" } let getDataInfoRes = await axios.post(`${vars.path_name}/getDataInfo`, { params: getDataInfoParams } ); if (getDataInfoRes.data.message == 'getDataInfo_success') { let result = getDataInfoRes.data.result; let directViewExtArr = ['xls', 'xlsx', 'xlsm', 'docx', 'hwp', 'hwpx']; let objectKey = directViewExtArr.includes(ext) ? result.object_key : result.popup_key; if(objectKey == undefined || objectKey == `` || objectKey == null){ return; } let generateDownloadUrlParams = { objectKey: objectKey, resourcePath: resourcePath } let generateDownloadUrlRes = await axios.post(`${vars.path_name}/generateDownloadUrl`, generateDownloadUrlParams); if (generateDownloadUrlRes.data.message == 'generateDownloadUrl_success') { PresignedUrl = generateDownloadUrlRes.data.url; } } //Presigned URL end thumbnail_key = encodeURIComponent(thumbnail_key); resourcePath = encodeURIComponent(resourcePath); let fullPath = encodeURIComponent(PresignedUrl); // 뷰어 기본 width값은 현재 화면 width값의 절반 let denominator = 2; // url 뷰어는 현재 화면 width값과 동일하게 설정 if (ext == 'url') denominator = 1; let width = screen.width / denominator; let height = screen.height; let left = screen.width * 2 + 10; let open_ext = `pdf`; switch(ext){ case 'pdf' : case 'doc' : case 'ppt' : case 'pptx': case 'dwg' : case 'dxf' : case 'grm' : open_ext = 'pdf'; break; case 'hwp' : case 'hwpx' : open_ext = ext; break; case 'xls' : case 'xlsx' : case 'xlsm' : open_ext = ext; break; case 'docx' : open_ext = ext; break; case 'gsim' : open_ext = 'gsim'; break case 'ifc' : open_ext = 'ifc'; break case 'png' : case 'jpg' : case 'jpeg' : case 'webp' : case 'gif' : open_ext = 'png'; break case 'mp4' : case 'mov' : case 'webm' : open_ext = 'mp4'; break case 'log' : case 'txt' : case 'md' : open_ext = 'txt'; break case 'url' : open_ext = 'url'; break; case 'zip' : open_ext = 'zip'; break case 'glb': case 'gltf': case 'obj': case 'stl': case 'fbx': case '3dm': open_ext = 'glb'; break; case 'html': open_ext = 'html'; break; } //presigned url은 ext를 읽을수 없엉... const jsonData = JSON.stringify({$ext : open_ext}); const encodedData = btoa(jsonData); // 3d모델뷰어 썸네일 생성을 위해 dataId, path_name 추가 // let popup = window.open(`/popup?path=${fullPath}&data=${encodedData}`, '', `width=${width}, height=${height}, left=${left},`); let popup = window.open(`/popup?thumbnail_key=${thumbnail_key}&path_name=${vars.path_name}&resourcePath=${resourcePath}&dataId=${dataId}&path=${fullPath}&data=${encodedData}`, '', `width=${width}, height=${height}, left=${left},`); } export function initFileAreaUI(fileAreaMode) { let listContainer = document.querySelector('.archive-main .archive-main-center .list-container'); let isRecycleBinModal = document.querySelector('.recycle-bin-modal').style.display == 'flex'; if (isRecycleBinModal) listContainer = document.querySelector('.recycle-bin-modal .recycle-bin-wrap .list-container'); let listHeader = listContainer.querySelector('.list-header'); let listBody = listContainer.querySelector('.list-body'); let listBodyItemWrap = listBody.querySelector('.list-item-wrap'); let mapContainer = listBody.querySelector('.map-container'); let archiveMainRight = document.querySelector('.archive-main-right'); let viewerHeader = archiveMainRight.querySelector('.viewer-header'); if (fileAreaMode == 'map') { listHeader.style.display = 'none'; listBody.style.height = '100%'; listBody.style.overflowY = 'hidden'; listBodyItemWrap.style.display = 'none'; if (mapContainer) mapContainer.style.display = 'flex'; archiveMainRight.style.minWidth = '36rem'; archiveMainRight.style.maxWidth = '36rem'; archiveMainRight.style.height = 'calc(100% - 2.75rem)'; archiveMainRight.style.position = 'absolute'; archiveMainRight.style.right = '0.625rem'; archiveMainRight.style.top = '0.5rem'; archiveMainRight.style.background = '#fffa'; archiveMainRight.style.backdropFilter = 'blur(0.2rem)'; archiveMainRight.style.webkitBackdropFilter = 'blur(0.2rem)'; archiveMainRight.style.borderRadius = '0.25rem'; archiveMainRight.style.boxShadow = '#ccc 0 0 0rem 0.0625rem, #0c0c0db3 0rem 0.5rem 1rem -0.25rem'; viewerHeader.style.borderRadius = '0.25rem 0.25rem 0 0'; } else { listHeader.style.display = 'flex'; listBody.style.height = 'calc(100% - 2.25rem)'; listBody.style.overflowY = 'scroll'; listBodyItemWrap.style.display = 'flex'; if (mapContainer) mapContainer.style.display = 'none'; archiveMainRight.style.minWidth = '41rem'; archiveMainRight.style.maxWidth = '41rem'; archiveMainRight.style.height = '100%'; archiveMainRight.style.position = 'relative'; archiveMainRight.style.right = 'unset'; archiveMainRight.style.top = 'unset'; archiveMainRight.style.background = '#fff'; archiveMainRight.style.backdropFilter = 'none'; archiveMainRight.style.webkitBackdropFilter = 'none'; archiveMainRight.style.borderRadius = 'unset'; archiveMainRight.style.boxShadow = 'none'; viewerHeader.style.borderRadius = 'unset'; } } export function syncGroupStyle() { let listContainer = document.querySelector('.archive-main .archive-main-center .list-container'); let isRecycleBinModal = document.querySelector('.recycle-bin-modal').style.display == 'flex'; if (isRecycleBinModal) listContainer = document.querySelector('.recycle-bin-modal .recycle-bin-wrap .list-container'); listContainer.querySelectorAll('.main-list-item').forEach(item => { if (listContainer.querySelectorAll(`.list-item.selected[data-main-file-name="${item.dataset.mainFileName}"]`).length > 0) { listContainer.querySelectorAll(`.list-item[data-main-file-name="${item.dataset.mainFileName}"]`).forEach(item => { item.classList.add('group-style'); item.classList.remove('non-selected'); }) } else { listContainer.querySelectorAll(`.list-item[data-main-file-name="${item.dataset.mainFileName}"]`).forEach(item => { item.classList.remove('group-style'); }) } }) }