/** * ITAM 공통 유틸리티 함수 */ /** * 숫자에 천 단위 콤마 추가 (금액 표시용) */ export function formatPrice(value: string | number): string { if (value === undefined || value === null) return ''; const num = String(value).replace(/[^0-9]/g, ''); if (!num) return ''; return num.replace(/\B(?=(\d{3})+(?!\d))/g, ','); } /** * HTML 배지 생성 (정/부 담당자, 원격도구 등) */ export function createBadge(text: string, type: 'primary' | 'muted' | 'success' | 'danger' = 'primary'): string { return `${text}`; } /** * 텍스트 내 줄바꿈을 구분자(/)로 변경하여 한 줄로 표시 */ export function formatInline(value: any): string { return String(value || '').replace(/\n/g, ' / ').trim(); } /** * 날짜 문자열 포맷팅 (YYYY.MM.DD -> YYYY-MM-DD) */ export function normalizeDate(dateStr: string): string { return (dateStr || '').replace(/\./g, '-').trim(); } /** * 구매일로부터 현재까지의 경과 연수 계산 (소수점 첫째자리) */ export function calculateAssetAge(purchaseDate: string): number { const normalized = normalizeDate(purchaseDate); if (!normalized) return 0; const purchase = new Date(normalized); if (isNaN(purchase.getTime())) return 0; const diffMs = Date.now() - purchase.getTime(); const age = diffMs / (1000 * 60 * 60 * 24 * 365.25); return Math.max(0, parseFloat(age.toFixed(1))); } /** * 고유 ID 생성 (7자리 랜덤 문자열) */ export function generateId(): string { return Math.random().toString(36).substring(2, 9); } /** * 두 자산 객체 간의 변경 사항 감지 */ export function getAssetChanges(oldAsset: any, newAsset: any, fields: {key: string, label: string}[]): string { const changes: string[] = []; fields.forEach(field => { const oldVal = String(oldAsset[field.key] || '').trim(); const newVal = String(newAsset[field.key] || '').trim(); if (oldVal !== newVal) { changes.push(`${field.label}: ${oldVal || '없음'} → ${newVal || '없음'}`); } }); return changes.join('\n'); } /** * 자산 목록 정렬 (기본: 법인별 -> 자산번호 순) */ export function sortAssets(list: T[]): T[] { return [...list].sort((a: any, b: any) => { // 1순위: 법인 (가나다순) const corpA = String(a.법인 || a.corp || '').trim(); const corpB = String(b.법인 || b.corp || '').trim(); if (corpA < corpB) return -1; if (corpA > corpB) return 1; // 2순위: 자산번호/코드 (영문/숫자순) const codeA = String(a.자산코드 || a.자산번호 || a.id || '').trim(); const codeB = String(b.자산코드 || b.자산번호 || b.id || '').trim(); if (codeA < codeB) return -1; if (codeA > codeB) return 1; return 0; }); } /** * 동적 정렬 함수 * @param list 정렬할 목록 * @param key 정렬 기준 필드 * @param direction 정렬 방향 ('asc' | 'desc') */ export function dynamicSort(list: T[], key: string, direction: 'asc' | 'desc'): T[] { return [...list].sort((a: any, b: any) => { let valA = a[key]; let valB = b[key]; // 숫자인 경우 처리 if (typeof valA === 'number' && typeof valB === 'number') { return direction === 'asc' ? valA - valB : valB - valA; } // 금액 필드 (숫자형 문자열 포함) 처리 if (key === '금액' || key === 'price' || key === '수량' || key === 'qty') { const numA = typeof valA === 'number' ? valA : parseInt(String(valA || '0').replace(/[^0-9-]/g, ''), 10); const numB = typeof valB === 'number' ? valB : parseInt(String(valB || '0').replace(/[^0-9-]/g, ''), 10); return direction === 'asc' ? numA - numB : numB - numA; } // 문자열 정렬 (기본) valA = String(valA || '').toLowerCase(); valB = String(valB || '').toLowerCase(); if (valA < valB) return direction === 'asc' ? -1 : 1; if (valA > valB) return direction === 'asc' ? 1 : -1; return 0; }); }