merge: main 브랜치의 최신 변경 사항 병합 및 충돌 해결

This commit is contained in:
2026-04-17 15:37:57 +09:00
50 changed files with 8265 additions and 1187 deletions

View File

@@ -5,7 +5,7 @@ import { realServerData } from './realServerData';
// --- State Definitions ---
export interface AppState {
masterData: MasterAssetData;
activeCategory: 'hw' | 'sw';
activeCategory: 'hw' | 'sw' | 'ops';
activeSubTab: string;
activeCharts: any[];
}
@@ -14,7 +14,9 @@ const dummy = generateDummyData();
// 서버 데이터만 실제 데이터로 교체
const mergedHw: HardwareAsset[] = [
...dummy.hw.filter(a => a.type !== '서버'),
...realServerData.map(s => ({
...realServerData.map((serverData: any) => {
const s = serverData;
return {
id: s.id || Math.random().toString(36).substring(2, 9),
type: '서버',
법인: s.법인,
@@ -47,21 +49,55 @@ const mergedHw: HardwareAsset[] = [
서버PW: s.서버PW || '',
모니터링: s.모니터링 || '',
비고: s.비고 || ''
}))
}})
];
// --- Initial State ---
export const state: AppState = {
masterData: {
...dummy,
hw: mergedHw,
logs: [] // MasterAssetData 인터페이스에 맞게 추가
hw: mergedHw, // 기본적으로 하드코딩된 데이터를 가지고 시작
logs: []
},
activeCategory: 'hw',
activeSubTab: '대시보드',
activeCharts: []
};
/**
* DB에서 데이터 로드
*/
export async function loadMasterDataFromDB() {
try {
const [hwRes, swRes, swUserRes] = await Promise.all([
fetch('http://localhost:3000/api/hw'),
fetch('http://localhost:3000/api/sw'),
fetch('http://localhost:3000/api/sw-users')
]);
if (hwRes.ok) {
const hwData = await hwRes.json();
if (hwData && hwData.length > 0) state.masterData.hw = hwData;
}
if (swRes.ok) {
const swData = await swRes.json();
if (swData && swData.length > 0) state.masterData.sw = swData;
}
if (swUserRes.ok) {
const swUserData = await swUserRes.json();
if (swUserData && swUserData.length > 0) state.masterData.swUsers = swUserData;
}
console.log('✅ DB 데이터 로드 완료');
return true;
} catch (err) {
console.warn('⚠️ 백엔드 서버 연결 실패. 로컬 데이터를 유지합니다.');
}
return false;
}
// --- State Helpers ---
export function updateState(newState: Partial<AppState>) {
Object.assign(state, newState);

56
src/core/utils.ts Normal file
View File

@@ -0,0 +1,56 @@
/**
* 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, bgColor: string): string {
return `<span style="background:${bgColor}; color:white; font-size:10px; padding:1px 4px; border-radius:3px; font-weight:700; margin-right:4px; display:inline-block; line-height:1.2;">${text}</span>`;
}
/**
* 텍스트 내 줄바꿈을 구분자(/)로 변경하여 한 줄로 표시
*/
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();
}
/**
* 고유 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');
}