style, utils 수정

This commit is contained in:
2025-06-12 14:16:46 +09:00
parent 38fa323db6
commit 93a7c087e1
2 changed files with 151 additions and 1 deletions

View File

@@ -679,6 +679,12 @@ export const SearchItem = styled.div`
}
`;
export const DownloadContainer = styled.div`
display: flex;
align-items: center;
gap: 10px;
`;
export const SearchRow = styled.div`
display: flex;
flex-wrap: wrap;
@@ -689,4 +695,43 @@ export const SearchRow = styled.div`
padding-top: 15px;
margin-top: 15px;
}
`;
export const TabScroll = styled.div`
width: 100%;
overflow: auto;
`;
export const TabItem = styled(Link)`
display: inline-flex;
width: 120px;
height: 30px;
justify-content: center;
align-items: center;
background: #f9f9f9;
border-left: 1px solid #d9d9d9;
&:hover {
background: #888;
color: #fff;
}
${props =>
props.$state === 'active' &&
`
background: #888;
color: #fff;`}
`;
export const TabWrapper = styled.ul`
display: flex;
li:first-child {
${TabItem} {
border-left: 0;
}
}
`;
export const CircularProgressWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
`;

View File

@@ -86,4 +86,109 @@ export const getFieldLabel = (key, value) => {
}
return key;
};
};
export const numberFormatter = {
formatCurrency: (number, decimals = 2) => {
if (number === null || number === undefined) return '0';
try {
const num = typeof number === 'string' ? parseFloat(number) : number;
if (isNaN(num)) return '0';
// 정수인지 확인
const isInteger = Number.isInteger(num);
// 작은 수이거나 소수점이 있는 경우
if ((Math.abs(num) < 1 && num !== 0) || !isInteger) {
return num.toFixed(decimals);
}
// 정수인 경우
return new Intl.NumberFormat('ko-KR', {
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(num);
} catch (e) {
console.error('Currency formatting error:', e);
return '0';
}
}
};
/**
* API 응답으로부터 파일 다운로드를 처리하는 함수
* @param {Object} response - API 응답 객체
* @param {Object} response.data - 응답 데이터
* @param {Object} response.headers - 응답 헤더
* @param {Object} options - 추가 옵션
* @param {string} options.defaultFileName - 기본 파일명 (기본값: 'download')
* @returns {void}
* @throws {Error} 데이터가 없거나 파일 형식이 잘못된 경우
*/
export const responseFileDownload = (response, options = {}) => {
const { defaultFileName = 'download' } = options;
if (!response.data) {
console.log(response);
throw new Error('No data received');
}
const contentType = response.headers['content-type'] || response.headers['Content-Type'];
const contentDisposition = response.headers['content-disposition'] || response.headers['Content-Disposition'];
// Excel이나 ZIP 파일 형식 검증
if (!contentType.includes('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') &&
!contentType.includes('application/zip')) {
console.log(response);
throw new Error(`잘못된 파일 형식입니다. Content-Type: ${contentType}`);
}
let fileName = defaultFileName;
let fileExtension = '.xlsx';
let mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
// ZIP 파일 처리
if (contentType && contentType.includes('application/zip')) {
fileExtension = '.zip';
mimeType = 'application/zip';
fileName = `${defaultFileName}_multiple_files`;
}
// Content-Disposition에서 파일명 추출
if (contentDisposition) {
const fileNameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
if (fileNameMatch && fileNameMatch[1]) {
fileName = decodeURIComponent(fileNameMatch[1].replace(/['"]/g, ''));
}
} else {
fileName = fileName + fileExtension;
}
const blob = new Blob([response.data], { type: mimeType });
// 파일 유효성 검사
if (blob.size === 0) {
throw new Error('다운로드된 파일이 비어있습니다.');
}
if (blob.size < 1024) {
throw new Error('파일 크기가 너무 작습니다. 올바른 Excel 파일이 아닐 수 있습니다.');
}
// 파일 다운로드 실행
const href = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = href;
link.download = fileName;
link.style.display = 'none';
link.rel = 'noopener noreferrer';
document.body.appendChild(link);
link.click();
// 정리
link.remove();
window.URL.revokeObjectURL(href);
};