style, utils 수정
This commit is contained in:
@@ -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;
|
||||
`;
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user