Files
frontend/packages/common/business_components/src/ui/map/lib/util.js
T
2025-04-24 10:26:49 +09:00

597 lines
17 KiB
JavaScript

//공통
export const util = {
getOneToArrayByObjectKey: function (arr, key, value) {
let result = {};
arr.forEach(item => {
if (item[key] === value) {
result = item;
}
});
return result;
},
groupByProperty: (arr, prop, parentProp, group) => {
const tree = [];
const mappedArr = {};
let arrElem;
let mappedElem;
// 먼저 배열의 노드를 개체에 매핑하고 -> 해시 테이블을 생성
for (let i = 0; i < arr.length; i++) {
arrElem = arr[i];
if (group && arrElem.mnuGroup !== group) continue;
mappedArr[arrElem[prop]] = arrElem;
mappedArr[arrElem[prop]].children = [];
}
for (const mnuCd in mappedArr) {
if (mappedArr.hasOwnProperty(mnuCd)) {
mappedElem = mappedArr[mnuCd];
// 요소가 루트 수준에 없으면 자식의 부모 배열에 추가.
if (mappedElem[parentProp] && mappedArr[mappedElem[parentProp]]?.children) {
mappedArr[mappedElem[parentProp]].children.push(mappedElem);
}
// 요소가 루트 수준에 있는 경우 첫 번째 수준 요소 배열에 추가
else {
tree.push(mappedElem);
}
}
}
return tree;
},
getLowestChildren: function (obj) {
if (!obj.children || obj.children.length === 0) {
return obj;
} else {
return this.getLowestChildren(obj.children[0]);
}
},
hasClass: (e, clazz) => {
return e.target.classList.contains(clazz);
},
isNull: function (str) {
if (typeof str === 'undefined' || str === null || str === 'null' || str === '' || str === 'undefined') {
return true;
}
return false;
},
nvl: function (str, returnVal) {
if (this.isNull(str)) {
return returnVal;
}
return str;
},
isNumeric: function (str) {
const pattern = /\d/;
return pattern.test(str);
},
isAlpha: function (str) {
const pattern = /[a-zA-Z]/;
return pattern.test(str);
},
isAlphaNumeric: function (str) {
const pattern = /^[a-zA-Z0-9]+$/;
return pattern.test(str);
},
isSpecialChar: function (str) {
const pattern = /[~!@#$%^&*()_+|<>?:{}]/;
return pattern.test(str);
},
isKoreanAplhaNumeric: function (str) {
const pattern = /^[ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-zA-Z0-9]+$/;
return pattern.test(str);
},
isValidPassword: function (str) {
const pattern = /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*(),.?":{}|<>])[a-zA-Z0-9!@#$%^&*(),.?":{}|<>]{8,20}$/;
return pattern.test(str);
},
isValidExt: function (fileName, allowedExtensions) {
const fileExtension = fileName.split('.').pop().toLowerCase();
return allowedExtensions.includes(fileExtension);
},
isValidAllDate: function (dateString) {
const formats = ['YYYY', 'YYYYMM', 'YYYYMMDD'];
for (let format of formats) {
if (moment(dateString, format, true).isValid()) {
return true;
}
}
return false;
},
isEmptyObject: function (param) {
return Object.keys(param).length === 0 && param.constructor === Object;
},
castArrayObjectToList: function (array, key) {
var newArray = [];
for (var i = 0; i < array.length; i++) {
newArray.push(array[i][key]);
}
return newArray;
},
arraysMatch: function (arr1, arr2) {
// 길이가 같은지 확인
if (arr1.length !== arr2.length) return false;
// 각 요소가 일치하는지 확인
return arr1.every((element, index) => element === arr2[index]);
},
//상위뎁스 객체들 조회
findObjectByKeyAndValue: function ({ array, find: { key: findKey, value: findValue }, result: { key: resultKey }, parents = [] }) {
for (let i = 0; i < array.length; i++) {
let obj = array[i];
let siblings = [...array];
//siblings.splice(i, 1); // 현재 메뉴를 제거하여 형제 메뉴들만 남김
let currentParents = [...parents, { [resultKey]: obj, siblings: siblings }];
if (obj[findKey] === findValue) {
let formattedResult = currentParents.reduce((acc, cur, idx) => {
acc[`${resultKey}${idx + 1}`] = { active: cur[resultKey], list: cur.siblings };
return acc;
}, {});
return formattedResult;
}
if (obj.children) {
let result = this.findObjectByKeyAndValue({ array: obj.children, find: { key: findKey, value: findValue }, result: { key: resultKey }, parents: currentParents });
if (result !== null) {
return result;
}
}
}
return null;
},
autoComma(val, returnVal) {
if (!val && val !== 0) return returnVal ? returnVal : '';
// 문자열로 변환하고, 숫자와 소수점만을 허용
val = String(val).replace(/[^0-9.-]/g, '');
// 소수점을 기준으로 숫자를 분리
let [integerPart, decimalPart] = val.split('.');
// 정수 부분에 대해 쉼표 추가
integerPart = integerPart.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
// 소수점 이하 숫자가 있다면 다시 합치기
return decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
},
removeComma: function (str) {
str = String(str);
return str.replace(/[^\d]+/g, '');
},
removeSpaceAndTrim: function (str) {
if (str) {
str = String(str);
return str.replace(/\s/g, '');
} else {
return str;
}
},
isNotWhiteSpace: function (str) {
const hasWhitespace = /\s/.test(str);
return !hasWhitespace;
},
//숫자만 남기고 모두 제거해서 반환
retainOnlyNumbers: function (str) {
str = String(str);
return str.replace(/\D+/g, '');
},
proxyToObject: function (proxy) {
return JSON.parse(JSON.stringify(Object.assign({}, proxy)));
},
dateFormatter: function ({ input, isHan = false }) {
const value = this.retainOnlyNumbers(input);
if (value.length === 6) {
const date = moment(value, 'YYYYMM');
return date.format(isHan ? 'YYYY년 MM월' : 'YYYY-MM');
} else if (value.length === 8) {
const date = moment(value, 'YYYYMMDD');
return date.format(isHan ? 'YYYY년 MM월 DD일' : 'YYYY-MM-DD');
} else if (value.length === 14) {
const date = moment(value, 'YYYYMMDDHHmmss');
return date.format(isHan ? 'YYYY년 MM월 DD일 HH시 mm분 ss초' : 'YYYY-MM-DD HH:MM:SS');
} else {
return input;
}
},
generateYearArray: function (num) {
const currentYear = moment().year();
if (num <= 1 || isNaN(num)) {
return [(currentYear - 2).toString(), (currentYear - 1).toString(), currentYear.toString()];
}
const years = [];
for (let i = num - 1; i >= 0; i--) {
years.push((currentYear - i).toString());
}
return years;
},
getFileId: function () {
let timeStamp = moment().format('YYYYMMDDHHmmssSSS'); // YYYYMMDDHHmmssSSS 형태로 타임스탬프를 생성
return 'CFM_' + timeStamp.slice(-12); // slice(-12)는 문자열의 끝에서 12자리를 추출합니다.
},
lpad: function (number, pad, length) {
let str = number.toString();
while (str.length < length) {
str = pad + str;
}
return str;
},
convertKeysToCamelCase: function (obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
return Object.keys(obj).reduce((acc, key) => {
const camelCaseKey = key.replace(/([-_]\w)/g, match => match.replace(/[-_]/, '').toUpperCase());
acc[camelCaseKey] = typeof obj[key] === 'object' ? this.convertKeysToCamelCase(obj[key]) : obj[key];
return acc;
}, {});
},
blobUrlToBlob: async blobUrl => {
try {
const response = await fetch(blobUrl);
return await response.blob();
} catch (error) {
console.error(error);
return new Blob();
}
},
hexToRgba: hex => {
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
return `rgba(${r}, ${g}, ${b} , 0.5)`;
},
rgbaToHex: rgba => {
/*rgba값을 가져와서 rgb 로 추출 후 hex 값 반환 */
if (!rgba) return false;
const rgbArray = rgba.match(/\d+/g).slice(0, 3).map(Number);
return `#${((1 << 24) | (rgbArray[0] << 16) | (rgbArray[1] << 8) | rgbArray[2]).toString(16).slice(1).toUpperCase()}`;
},
rgbAddOpacity: (rgb, opacity) => {
const rgbValues = rgb.match(/\d+/g); // rgb 값을 배열로 추출
const colorWithOpacity = `rgba(${rgbValues[0]}, ${rgbValues[1]}, ${rgbValues[2]}, ${opacity})`; // rgba로 변환
return colorWithOpacity;
},
generateMonthArray: (pSmonth, pEmonth) => {
let startYear = Math.floor(pSmonth / 100);
let startMonth = pSmonth % 100;
let endYear = Math.floor(pEmonth / 100);
let endMonth = pEmonth % 100;
let months = [];
for (let year = startYear; year <= endYear; year++) {
let monthStart = year === startYear ? startMonth : 1;
let monthEnd = year === endYear ? endMonth : 12;
for (let month = monthStart; month <= monthEnd; month++) {
let monthString = month < 10 ? `0${month}` : `${month}`;
months.push(`${year}${monthString}`);
}
}
return months;
},
findDuplicatesForArr: (arr, key) => {
const map = new Map();
const duplicates = [];
arr.forEach(item => {
const keyValue = item[key];
if (map.has(keyValue)) {
if (!duplicates.includes(keyValue)) {
duplicates.push(keyValue);
}
} else {
map.set(keyValue, true);
}
});
return duplicates;
},
createHtmlFromJson: (html, data) => {
if (!html || util.isEmptyObject(html)) return null;
const { classNm, headerKey, rows } = JSON.parse(html);
if (!rows) return null;
const tableRows = rows
.map(row => {
const value = data?.[row.key] ?? null;
let displayValue;
if (typeof value === 'number') {
displayValue = util.autoComma(value, 0);
} else if (typeof value === 'string') {
displayValue = util.nvl(value, '-');
} else {
displayValue = '-';
}
return `
<tr>
<th>${row.th}</th>
<td>${displayValue}</td>
</tr>
`;
})
.join('');
return `
<div class="${classNm}">
<table>
<tr>
<th colspan="2" style="position: relative; text-align: center; background-color: #DEEAF3;">
${data?.[headerKey] ?? '-'}
</th>
</tr>
${tableRows}
</table>
</div>
`;
},
};
/**
*
* 다이렉트로 import하여 사용하기 위해 export로 수정중
*
* */
//객체 배열에서 특정 key의 value인 것을 추출
export const getArrayByObjectKey = function (arr, key, value) {
return arr.filter(item => item[key] === value);
};
//소수점 1자리를 기준으로 점을 언더스코어로 변경
export const numberDotToUnderscore = function (num) {
if (Number.isInteger(num)) {
return num.toString();
} else {
return num.toFixed(1).replace('.', '_');
}
};
export const stripHTML = function (htmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
return doc.body.textContent || '';
};
//URL에서 매개변수 추출
export function getParameterByName(name, url = window.location.search) {
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
export function dateFormatForDB({ date: isoString, format = 'YYYY-MM-DD HH:MI:SS' }) {
if (!isoString) return '';
let date = new Date(isoString);
let year = date.getFullYear();
let month = (date.getMonth() + 1).toString().padStart(2, '0');
let day = date.getDate().toString().padStart(2, '0');
let hours = date.getHours().toString().padStart(2, '0');
let minutes = date.getMinutes().toString().padStart(2, '0');
let seconds = date.getSeconds().toString().padStart(2, '0');
return (
format
//
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('MI', minutes)
.replace('SS', seconds)
);
}
//blob 다운로드
//blob 다운로드
export function downloadFromBlob(res, data) {
const url = URL.createObjectURL(new Blob([res.data], { type: res.data.type }));
const link = document.createElement('a');
const contentDisposition = res.headers?.['content-disposition']; // 파일 이름
let fileName = data?.fileName || 'export'; //기본 파일 이름
if (contentDisposition) {
const [fileNameMatch] = contentDisposition.split(';').filter(str => str.includes('filename'));
if (fileNameMatch) {
[, fileName] = fileNameMatch.split('=');
// 파일명이 "UTF-8''" 등으로 인코딩되어 있을 수 있으니 decodeURIComponent 추가
fileName = decodeURIComponent(fileName);
}
}
link.href = url;
// 브라우저 인코딩 관련 이슈 방지를 위해 파일명에 대한 추가 decodeURI 처리
link.download = decodeURIComponent(fileName).replace(/"/g, '').trim();
link.style.display = 'none';
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);
}
export function downloadBlobAsFile(blob, filename = 'export') {
// 브라우저에 따라 인코딩 처리 햔재는 파이어폭스만
const url = URL.createObjectURL(blob);
const encodedFilename = encodeURIComponent(filename);
const downloadLink = document.createElement('a');
downloadLink.href = url;
downloadLink.download = decodeURIComponent(encodedFilename);
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
URL.revokeObjectURL(url);
}
export function viewFile(res, data) {
// Blob URL 생성
const url = URL.createObjectURL(new Blob([res.data], { type: res.data.type }));
let fileType = null;
let fileName = data?.fileName || 'export'; // 기본 파일 이름
// PDF 및 이미지 타입의 MIME 타입 확인
if (res.data.type === 'application/pdf') {
fileType = 'pdf';
} else if (res.data.type.startsWith('image/')) {
fileType = 'img';
} else if (res.data.type === 'application/octet-stream') {
// Content-Disposition 헤더에서 파일 이름 추출
const contentDisposition = res.headers?.['content-disposition'];
if (contentDisposition) {
const fileNameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
if (fileNameMatch && fileNameMatch[1]) {
fileName = fileNameMatch[1].replace(/['"]/g, ''); // 파일 이름 추출
fileName = decodeURIComponent(fileName); // URL 인코딩된 파일 이름을 디코딩
}
}
// 파일 확장자 추출
const fileExtension = fileName.split('.').pop().toLowerCase();
// 확장자를 통해 파일 타입 결정
if (fileExtension === 'pdf') {
fileType = 'pdf';
} else if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'].includes(fileExtension)) {
fileType = 'img';
} else {
console.error('지원하지 않는 파일 형식입니다.');
}
}
// URL과 파일 타입 반환
return { url, fileType, fileName };
}
export function getToday() {
return getDate('today');
}
export function getDate(type, diff) {
const date = new Date();
switch (type) {
case 'year':
date.setFullYear(date.getFullYear() + diff);
break;
case 'month':
date.setMonth(date.getMonth() + diff);
break;
case 'day':
date.setDate(date.getDate() + diff);
break;
case 'today':
date.setDate(date.getDate());
break;
default:
console.log('잘못된 타입입니다. 올바른 타입: 년, 월, 일');
return;
}
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}${month}${day}`;
}
//promise 처리
export const byPromise = function (actions) {
return actions.reduce((promise, action) => {
return promise.then(async () => {
if (typeof action === 'function') {
return await action();
} else {
return await action;
}
});
}, Promise.resolve());
};
export const getMessage = (msgGroup, msgKey, innerText, fix) => {
let resultString = GLOBAL.MESSAGE[msgGroup][msgKey];
const prefix = fix?.prefix || '';
const suffix = fix?.suffix || '';
if (innerText) {
for (const [key, value] of Object.entries(innerText)) {
const regex = new RegExp(`\\$\{${key}\}`, 'g');
resultString = resultString.replace(regex, value);
}
}
if (resultString) resultString = resultString.replace(/\\n/g, '\n');
return resultString ? `${prefix}${resultString}${suffix}` : '안내 메시지 로딩 오류 - 관리자에게 문의하세요.';
};
// global.js의 message를 읽어오는 alert
export const gAlert = (msgGroup, msgKey, innerText, fix) => {
alert(getMessage(msgGroup, msgKey, innerText, fix));
};
// message를 confirm
export const gConfirm = (msgGroup, msgKey, innerText, fix) => {
return window.confirm(getMessage(msgGroup, msgKey, innerText, fix));
};
// message를 함수 리턴
export const gMessage = getMessage;
// message를 save후 응답까지 처리
export const gSaveCommonConfirm = async ({ message, api = async () => {}, param = {}, success, fail, prefix }) => {
try {
if (!gConfirm('CONFIRM', `${message}_QUEST`, null, { prefix })) return;
const result = await api(param, { isAlert: false });
if (result?.code !== 200) return;
const rep = message === 'UPLOAD' ? result.data.data : result.data;
if (rep > 0) {
gAlert('INFO', `${message}_COMPLETE`);
await success?.();
} else {
gAlert('ERROR', `${message}_FAIL`);
await fail?.();
}
} catch (error) {
console.error('오류 발생:', error); // 시큐어코딩 관련 수정 : 오류 정보를 로그로 출력
}
};
export const nullToValue = (text, { value = '-', prefix = '', suffix = '' } = {}) => {
if (!text || text === value) {
return value;
}
return `${prefix}${text}${suffix}`;
};
export const filterArrayOfObjectsByKeys = (arrayOfObjects, keys) => {
return arrayOfObjects.map(obj => {
return keys.reduce((filteredObj, key) => {
if (obj.hasOwnProperty(key)) {
filteredObj[key] = obj[key];
}
return filteredObj;
}, {});
});
};
export const isMobile = () => {
const width = window.innerWidth > 0 ? window.innerWidth : window.screen.width;
return width < GLOBAL.MOBILE_SIZE;
};