refactor: integrate software assets into unified schema and optimize backend API
This commit is contained in:
@@ -48,7 +48,7 @@ export const state: AppState = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 전용 API 엔드포인트들로부터 데이터 로드
|
||||
* 전용 API 엔드포인트들로부터 데이터 로드 (Modernized Paths)
|
||||
*/
|
||||
export async function loadMasterDataFromDB() {
|
||||
try {
|
||||
@@ -58,12 +58,12 @@ export async function loadMasterDataFromDB() {
|
||||
{ key: 'storage', url: `http://${location.hostname}:3000/api/storage` },
|
||||
{ key: 'equip', url: `http://${location.hostname}:3000/api/equip` },
|
||||
{ key: 'mobile', url: `http://${location.hostname}:3000/api/mobile` },
|
||||
{ key: 'subSw', url: `http://${location.hostname}:3000/api/sw/sub` },
|
||||
{ key: 'permSw', url: `http://${location.hostname}:3000/api/sw/perm` },
|
||||
{ key: 'cloud', url: `http://${location.hostname}:3000/api/cloud` },
|
||||
{ key: 'domain', url: `http://${location.hostname}:3000/api/ops/domain` },
|
||||
{ key: 'swUsers', url: `http://${location.hostname}:3000/api/sw-users` },
|
||||
{ key: 'logs', url: `http://${location.hostname}:3000/api/logs` }
|
||||
{ key: 'subSw', url: `http://${location.hostname}:3000/api/asset/software/subscription` },
|
||||
{ key: 'permSw', url: `http://${location.hostname}:3000/api/asset/software/perpetual` },
|
||||
{ key: 'cloud', url: `http://${location.hostname}:3000/api/asset/cloud` },
|
||||
{ key: 'domain', url: `http://${location.hostname}:3000/api/asset/domain` },
|
||||
{ key: 'swUsers', url: `http://${location.hostname}:3000/api/asset/software/assignment` },
|
||||
{ key: 'logs', url: `http://${location.hostname}:3000/api/asset/history` }
|
||||
];
|
||||
|
||||
const results = await Promise.all(endpoints.map(e => fetch(e.url)));
|
||||
@@ -79,13 +79,15 @@ export async function loadMasterDataFromDB() {
|
||||
if (results[i].ok) {
|
||||
const data = await results[i].json();
|
||||
const key = endpoints[i].key;
|
||||
console.log(`📡 Loaded ${key}: ${Array.isArray(data) ? data.length : 'not an array'} items`);
|
||||
|
||||
if (['pc', 'server', 'storage', 'equip', 'mobile'].includes(key)) {
|
||||
// 하드웨어 데이터는 자동 재분류 로직 통과
|
||||
(data as HardwareAsset[]).forEach(asset => saveHardwareAsset(asset));
|
||||
(Array.isArray(data) ? data : []).forEach(asset => saveHardwareAsset(asset));
|
||||
} else {
|
||||
(state.masterData as any)[key] = data || [];
|
||||
(state.masterData as any)[key] = Array.isArray(data) ? data : [];
|
||||
}
|
||||
} else {
|
||||
console.error(`❌ Failed to load ${endpoints[i].key}: ${results[i].status} ${results[i].statusText}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,25 +196,37 @@ export function deleteHardwareAsset(assetId: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 소프트웨어 자산 저장 (API 연동)
|
||||
* 소프트웨어 자산 저장 (API 연동 - 개선된 일괄 저장 경로)
|
||||
*/
|
||||
export async function saveSoftwareAsset(asset: SoftwareAsset) {
|
||||
try {
|
||||
const response = await fetch(`http://${location.hostname}:3000/api/software/save`, {
|
||||
const type = asset.type;
|
||||
let url = '';
|
||||
let categoryKey: keyof MasterAssetData = 'subSw';
|
||||
|
||||
if (type === '구독SW') {
|
||||
url = `http://${location.hostname}:3000/api/asset/software/subscription/batch`;
|
||||
categoryKey = 'subSw';
|
||||
} else if (type === '영구SW') {
|
||||
url = `http://${location.hostname}:3000/api/asset/software/perpetual/batch`;
|
||||
categoryKey = 'permSw';
|
||||
} else {
|
||||
url = `http://${location.hostname}:3000/api/asset/cloud/batch`;
|
||||
categoryKey = 'cloud';
|
||||
}
|
||||
|
||||
const arr = state.masterData[categoryKey] as SoftwareAsset[];
|
||||
const idx = arr.findIndex(a => a.id === asset.id);
|
||||
if (idx > -1) arr[idx] = asset;
|
||||
else arr.push(asset);
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(asset)
|
||||
body: JSON.stringify(arr)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// 로컬 상태 업데이트
|
||||
const key = asset.type === '구독SW' ? 'subSw' : (asset.type === '영구SW' ? 'permSw' : 'cloud');
|
||||
const arr = state.masterData[key] as SoftwareAsset[];
|
||||
const idx = arr.findIndex(a => a.id === asset.id);
|
||||
if (idx > -1) arr[idx] = asset;
|
||||
else arr.push(asset);
|
||||
|
||||
// 통합 sw 배열 동기화
|
||||
state.masterData.sw = [...state.masterData.subSw, ...state.masterData.permSw, ...state.masterData.cloud];
|
||||
return true;
|
||||
}
|
||||
@@ -223,21 +237,24 @@ export async function saveSoftwareAsset(asset: SoftwareAsset) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 소프트웨어 자산 삭제 (API 연동)
|
||||
* 소프트웨어 자산 삭제 (API 연동 - 개선된 일괄 저장 경로)
|
||||
*/
|
||||
export async function deleteSoftwareAsset(type: string, id: string) {
|
||||
try {
|
||||
const response = await fetch(`http://${location.hostname}:3000/api/asset/${type}/${id}`, {
|
||||
method: 'DELETE'
|
||||
const key = type === '구독SW' ? 'subSw' : (type === '영구SW' ? 'permSw' : 'cloud');
|
||||
const path = type === '구독SW' ? 'subscription' : (type === '영구SW' ? 'perpetual' : 'cloud');
|
||||
|
||||
const arr = state.masterData[key] as SoftwareAsset[];
|
||||
const filtered = arr.filter(a => a.id !== id);
|
||||
|
||||
const response = await fetch(`http://${location.hostname}:3000/api/asset/software/${path}/batch`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(filtered)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const key = type === '구독SW' ? 'subSw' : (type === '영구SW' ? 'permSw' : 'cloud');
|
||||
const arr = state.masterData[key] as SoftwareAsset[];
|
||||
const idx = arr.findIndex(a => a.id === id);
|
||||
if (idx > -1) arr.splice(idx, 1);
|
||||
|
||||
// 통합 sw 배열 동기화
|
||||
(state.masterData as any)[key] = filtered;
|
||||
state.masterData.sw = [...state.masterData.subSw, ...state.masterData.permSw, ...state.masterData.cloud];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,13 @@ export function formatInline(value: any): string {
|
||||
* 날짜 문자열 포맷팅 (YYYY.MM.DD -> YYYY-MM-DD)
|
||||
*/
|
||||
export function normalizeDate(dateStr: string): string {
|
||||
return (dateStr || '').replace(/\./g, '-').trim();
|
||||
if (!dateStr) return '';
|
||||
let str = String(dateStr).replace(/\./g, '-').trim();
|
||||
// YYYYMM 형식 처리 (6자리 숫자)
|
||||
if (/^\d{6}$/.test(str)) {
|
||||
return `${str.substring(0, 4)}-${str.substring(4, 6)}`;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user