Merge branch 'ux_setting' into db_setting
# Conflicts: # README.md
This commit is contained in:
@@ -1,163 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
|
||||
// dummyData.ts를 읽어와서 dummyPCs 파싱
|
||||
const content = fs.readFileSync('c:/Project/HM ITAM/src/core/dummyData.ts', 'utf-8');
|
||||
|
||||
// export const dummyPCs: any[] = [ ... ]; 패턴 추출
|
||||
const match = content.match(/export const dummyPCs: any\[\] = (\[[\s\S]*?\]);/);
|
||||
if (!match) {
|
||||
console.error('Failed to parse dummyPCs from dummyData.ts');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const dummyPCs = JSON.parse(match[1]);
|
||||
|
||||
function calculatePcScoreDeductive(cpu, ram, gpu, purchaseDate) {
|
||||
let score = 100;
|
||||
|
||||
// 1. CPU 등급 감점
|
||||
const cpuUpper = (cpu || '').toUpperCase();
|
||||
let cpuDeduction = 0;
|
||||
if (cpuUpper.includes('I9') || cpuUpper.includes('RYZEN 9') || cpuUpper.includes('RYZEN9')) {
|
||||
cpuDeduction = 0;
|
||||
} else if (cpuUpper.includes('I7') || cpuUpper.includes('RYZEN 7') || cpuUpper.includes('RYZEN7')) {
|
||||
cpuDeduction = 5;
|
||||
} else if (cpuUpper.includes('I5') || cpuUpper.includes('RYZEN 5') || cpuUpper.includes('RYZEN5')) {
|
||||
cpuDeduction = 15;
|
||||
} else if (cpuUpper.includes('I3') || cpuUpper.includes('RYZEN 3') || cpuUpper.includes('RYZEN3')) {
|
||||
cpuDeduction = 25;
|
||||
} else {
|
||||
cpuDeduction = 30;
|
||||
}
|
||||
score -= cpuDeduction;
|
||||
|
||||
// 2. CPU 세대 감점
|
||||
let genDeduction = 0;
|
||||
let intelMatch = cpuUpper.match(/I\d-?(\d+)/);
|
||||
let gen = 0;
|
||||
if (intelMatch && intelMatch[1]) {
|
||||
const numStr = intelMatch[1];
|
||||
if (numStr.length === 5) gen = parseInt(numStr.substring(0, 2), 10);
|
||||
else if (numStr.length === 4) gen = parseInt(numStr.substring(0, 1), 10);
|
||||
}
|
||||
|
||||
let amdMatch = cpuUpper.match(/RYZEN\s?\d\s?-?(\d+)/);
|
||||
let amdGen = 0;
|
||||
if (amdMatch && amdMatch[1] && !intelMatch) {
|
||||
const numStr = amdMatch[1];
|
||||
if (numStr.length === 4) amdGen = parseInt(numStr.substring(0, 1), 10);
|
||||
}
|
||||
|
||||
if (intelMatch) {
|
||||
if (gen >= 12) genDeduction = 0;
|
||||
else if (gen >= 10) genDeduction = 5;
|
||||
else if (gen >= 8) genDeduction = 10;
|
||||
else genDeduction = 15;
|
||||
} else if (amdMatch) {
|
||||
if (amdGen >= 5) genDeduction = 0;
|
||||
else if (amdGen >= 3) genDeduction = 5;
|
||||
else genDeduction = 10;
|
||||
} else {
|
||||
genDeduction = 15;
|
||||
}
|
||||
score -= genDeduction;
|
||||
|
||||
// 3. RAM 용량 감점
|
||||
const ramUpper = (ram || '').toUpperCase();
|
||||
const ramMatch = ramUpper.match(/(\d+)\s*GB/);
|
||||
let ramDeduction = 25;
|
||||
if (ramMatch && ramMatch[1]) {
|
||||
const ramVal = parseInt(ramMatch[1], 10);
|
||||
if (ramVal >= 32) ramDeduction = 0;
|
||||
else if (ramVal >= 16) ramDeduction = 10;
|
||||
else if (ramVal >= 8) ramDeduction = 20;
|
||||
else ramDeduction = 25;
|
||||
}
|
||||
score -= ramDeduction;
|
||||
|
||||
// 4. GPU 성능 감점
|
||||
const gpuUpper = (gpu || '').toUpperCase();
|
||||
let gpuDeduction = 25;
|
||||
if (!gpuUpper || gpuUpper === '-' || gpuUpper.trim() === '') {
|
||||
gpuDeduction = 25;
|
||||
} else if (
|
||||
gpuUpper.includes('RTX 4090') || gpuUpper.includes('RTX 4080') || gpuUpper.includes('RTX 4070') ||
|
||||
gpuUpper.includes('RTX A5000') || gpuUpper.includes('RTX A6000') || gpuUpper.includes('RTX A4000')
|
||||
) {
|
||||
gpuDeduction = 0;
|
||||
} else if (
|
||||
gpuUpper.includes('RTX 3070') || gpuUpper.includes('RTX 3060') || gpuUpper.includes('RTX 2060') ||
|
||||
gpuUpper.includes('RTX A2000') || gpuUpper.includes('RTX A3000') || gpuUpper.includes('QUADRO')
|
||||
) {
|
||||
gpuDeduction = 5;
|
||||
} else if (
|
||||
gpuUpper.includes('GTX 1660') || gpuUpper.includes('GTX 1080') || gpuUpper.includes('GTX 1070') ||
|
||||
gpuUpper.includes('GTX 1060') || gpuUpper.includes('RX 6700') || gpuUpper.includes('RX 6600')
|
||||
) {
|
||||
gpuDeduction = 15;
|
||||
} else {
|
||||
gpuDeduction = 25;
|
||||
}
|
||||
score -= gpuDeduction;
|
||||
|
||||
// 5. 연식(노후도) 감점
|
||||
let age = 0;
|
||||
if (purchaseDate && purchaseDate !== '-') {
|
||||
let normalized = purchaseDate.replace(/\./g, '-').trim();
|
||||
if (/^\d{6}$/.test(normalized)) {
|
||||
normalized = `${normalized.substring(0, 4)}-${normalized.substring(4, 6)}`;
|
||||
}
|
||||
const purchase = new Date(normalized);
|
||||
if (!isNaN(purchase.getTime())) {
|
||||
const mockToday = new Date('2026-05-31');
|
||||
const diffMs = mockToday.getTime() - purchase.getTime();
|
||||
age = diffMs / (1000 * 60 * 60 * 24 * 365.25);
|
||||
age = Math.max(0, parseFloat(age.toFixed(1)));
|
||||
}
|
||||
}
|
||||
|
||||
let ageDeduction = 0;
|
||||
if (age < 1) ageDeduction = 0;
|
||||
else if (age < 2) ageDeduction = 3;
|
||||
else if (age < 3) ageDeduction = 6;
|
||||
else if (age < 4) ageDeduction = 9;
|
||||
else if (age < 5) ageDeduction = 12;
|
||||
else ageDeduction = 15;
|
||||
|
||||
score -= ageDeduction;
|
||||
|
||||
return Math.max(10, score);
|
||||
}
|
||||
|
||||
const jobScores = {};
|
||||
let totalPcs = 0;
|
||||
|
||||
const filteredPCs = dummyPCs.filter(pc => pc.user_position !== '재고PC');
|
||||
|
||||
filteredPCs.forEach(pc => {
|
||||
const job = pc.user_position || '미분류';
|
||||
const score = calculatePcScoreDeductive(pc.cpu, pc.ram, pc.gpu, pc.purchase_date);
|
||||
|
||||
if (!jobScores[job]) {
|
||||
jobScores[job] = { total: 0, count: 0 };
|
||||
}
|
||||
jobScores[job].total += score;
|
||||
jobScores[job].count += 1;
|
||||
totalPcs++;
|
||||
});
|
||||
|
||||
console.log('--- Job Averages (Deductive 100-point) ---');
|
||||
const sortedJobs = Object.keys(jobScores).map(job => {
|
||||
const avg = jobScores[job].total / jobScores[job].count;
|
||||
return {
|
||||
job,
|
||||
avg: parseFloat(avg.toFixed(1)),
|
||||
count: jobScores[job].count
|
||||
};
|
||||
}).sort((a, b) => b.avg - a.avg);
|
||||
|
||||
sortedJobs.forEach((item, index) => {
|
||||
console.log(`${index + 1}. ${item.job}: Avg=${item.avg}점, Count=${item.count}대`);
|
||||
});
|
||||
|
||||
console.log('Total PCs (excluding Stock):', totalPcs);
|
||||
118
scratch/fix_dates_by_spec.js
Normal file
118
scratch/fix_dates_by_spec.js
Normal file
@@ -0,0 +1,118 @@
|
||||
import mysql from 'mysql2/promise';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
});
|
||||
|
||||
// 하드웨어 출시 연도 데이터베이스 (CPU/GPU)
|
||||
const RELEASE_DATES = {
|
||||
// Intel CPU Generations (Mainstream desktop release month/year)
|
||||
'i9-14': '2023-10', 'i7-14': '2023-10', 'i5-14': '2023-10',
|
||||
'i9-13': '2022-10', 'i7-13': '2022-10', 'i5-13': '2022-10',
|
||||
'i9-12': '2021-11', 'i7-12': '2021-11', 'i5-12': '2021-11',
|
||||
'i9-11': '2021-03', 'i7-11': '2021-03', 'i5-11': '2021-03',
|
||||
'i9-10': '2020-05', 'i7-10': '2020-05', 'i5-10': '2020-05',
|
||||
'i9-9': '2018-10', 'i7-9': '2018-10', 'i5-9': '2018-10',
|
||||
'i7-8': '2017-10', 'i5-8': '2017-10',
|
||||
'i7-7': '2017-01', 'i5-7': '2017-01',
|
||||
'i7-6': '2015-08', 'i5-6': '2015-08',
|
||||
'i7-4': '2013-06', 'i5-4': '2013-06',
|
||||
'i7-3': '2012-04', 'i5-3': '2012-04',
|
||||
'i7-2': '2011-01', 'i5-2': '2011-01',
|
||||
|
||||
// NVIDIA GPU Series
|
||||
'RTX 4090': '2022-10', 'RTX 4080': '2022-11', 'RTX 4070': '2023-04', 'RTX 4060': '2023-06',
|
||||
'RTX 3090': '2020-09', 'RTX 3080': '2020-09', 'RTX 3070': '2020-10', 'RTX 3060': '2021-02',
|
||||
'RTX 2080': '2018-09', 'RTX 2070': '2018-10', 'RTX 2060': '2019-01',
|
||||
'GTX 1660': '2019-03', 'GTX 1650': '2019-04',
|
||||
'GTX 1080': '2016-05', 'GTX 1070': '2016-06', 'GTX 1060': '2016-07', 'GTX 1050': '2016-10',
|
||||
'GTX 980': '2014-09', 'GTX 970': '2014-09', 'GTX 960': '2015-01'
|
||||
};
|
||||
|
||||
function inferDateFromSpecs(cpu, gpu) {
|
||||
const cpuStr = (cpu || '').toUpperCase();
|
||||
const gpuStr = (gpu || '').toUpperCase();
|
||||
|
||||
let inferred = null;
|
||||
|
||||
// 1. GPU 기준 (최신 그래픽카드가 꽂혀있으면 그 시기 이후 구매일 확률이 높음)
|
||||
for (const [key, date] of Object.entries(RELEASE_DATES)) {
|
||||
if (gpuStr.includes(key)) {
|
||||
inferred = date;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. CPU 기준 (GPU에서 못 찾았거나, CPU가 더 최신일 경우)
|
||||
if (!inferred) {
|
||||
for (const [key, date] of Object.entries(RELEASE_DATES)) {
|
||||
// i7-13700 등을 찾기 위해 정규식 또는 포함 여부 확인
|
||||
if (cpuStr.includes(key)) {
|
||||
inferred = date;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inferred ? `${inferred}-01` : null;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const connection = await pool.getConnection();
|
||||
try {
|
||||
const [rows] = await connection.query(`
|
||||
SELECT c.id, c.asset_code, c.purchase_date, s.cpu, s.gpu
|
||||
FROM asset_core c
|
||||
LEFT JOIN asset_spec s ON c.id = s.asset_id
|
||||
`);
|
||||
|
||||
const updates = [];
|
||||
const unchanged = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const currentVal = (row.purchase_date || '').trim();
|
||||
|
||||
// 구매일자가 없거나 부정확한 경우만 처리
|
||||
if (!currentVal || currentVal === '-' || currentVal === 'undefined' || currentVal.startsWith('2024-01-01')) {
|
||||
const specDate = inferDateFromSpecs(row.cpu, row.gpu);
|
||||
|
||||
if (specDate) {
|
||||
updates.push({ id: row.id, date: specDate, code: row.asset_code, cpu: row.cpu, gpu: row.gpu });
|
||||
} else {
|
||||
unchanged.push({ code: row.asset_code, cpu: row.cpu, gpu: row.gpu });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`🚀 스펙 분석 결과: ${updates.length}건의 자산 구매일자를 보정합니다.`);
|
||||
|
||||
for (const item of updates) {
|
||||
await connection.query('UPDATE asset_core SET purchase_date = ? WHERE id = ?', [item.date, item.id]);
|
||||
console.log(`[Update] ${item.code.padEnd(15)} | CPU: ${String(item.cpu).padEnd(20)} | GPU: ${String(item.gpu).padEnd(15)} -> ${item.date}`);
|
||||
}
|
||||
|
||||
if (unchanged.length > 0) {
|
||||
console.log('\n⚠️ 스펙 정보를 찾을 수 없어 보정하지 못한 자산:');
|
||||
unchanged.forEach(u => {
|
||||
if (u.code) console.log(`[Skip] ${u.code.padEnd(15)} | CPU: ${u.cpu || '-'} | GPU: ${u.gpu || '-'}`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`\n✅ 완료: ${updates.length}건 보정됨.`);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error:', err);
|
||||
} finally {
|
||||
connection.release();
|
||||
pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
128
scratch/fix_dates_strict.js
Normal file
128
scratch/fix_dates_strict.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import mysql from 'mysql2/promise';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
});
|
||||
|
||||
// 하드웨어 출시 연도/월 데이터베이스
|
||||
const RELEASE_DATES = {
|
||||
// Intel CPU
|
||||
'i9-14': '2023-10', 'i7-14': '2023-10', 'i5-14': '2023-10',
|
||||
'i9-13': '2022-10', 'i7-13': '2022-10', 'i5-13': '2022-10',
|
||||
'i9-12': '2021-11', 'i7-12': '2021-11', 'i5-12': '2021-11',
|
||||
'i9-11': '2021-03', 'i7-11': '2021-03', 'i5-11': '2021-03',
|
||||
'i9-10': '2020-05', 'i7-10': '2020-05', 'i5-10': '2020-05',
|
||||
'i9-9': '2018-10', 'i7-9': '2018-10', 'i5-9': '2018-10',
|
||||
'i7-8': '2017-10', 'i5-8': '2017-10',
|
||||
'i7-7': '2017-01', 'i5-7': '2017-01',
|
||||
'i7-6': '2015-08', 'i5-6': '2015-08',
|
||||
'i7-5': '2014-06', 'i5-5': '2015-06', // Broadwell
|
||||
'i7-4': '2013-06', 'i5-4': '2013-06',
|
||||
'i7-3': '2012-04', 'i5-3': '2012-04',
|
||||
'i7-2': '2011-01', 'i5-2': '2011-01',
|
||||
|
||||
// NVIDIA GPU
|
||||
'RTX 40': '2022-10',
|
||||
'RTX 30': '2020-09',
|
||||
'RTX 20': '2018-09',
|
||||
'GTX 16': '2019-02',
|
||||
'GTX 10': '2016-05',
|
||||
'GTX 9': '2014-09',
|
||||
'GTX 750': '2014-02',
|
||||
'GTX 7': '2013-05',
|
||||
'GTX 6': '2012-03'
|
||||
};
|
||||
|
||||
// 출시 연도만 있는 경우 (지시에 따라 후속년도 12월 적용을 위함)
|
||||
const YEAR_ONLY = {
|
||||
'I5-4': 2013,
|
||||
'I5-6': 2015,
|
||||
'I7-7': 2017,
|
||||
'GTX 750': 2014
|
||||
};
|
||||
|
||||
function inferDateFromSpecs(cpu, gpu) {
|
||||
const cpuStr = (cpu || '').toUpperCase();
|
||||
const gpuStr = (gpu || '').toUpperCase();
|
||||
|
||||
let latestYear = 0;
|
||||
let latestMonth = 0;
|
||||
|
||||
// 모든 매핑 데이터를 순회하며 가장 최신 날짜를 찾음
|
||||
for (const [key, dateStr] of Object.entries(RELEASE_DATES)) {
|
||||
if (cpuStr.includes(key) || gpuStr.includes(key)) {
|
||||
const [y, m] = dateStr.split('-').map(Number);
|
||||
if (y > latestYear || (y === latestYear && m > latestMonth)) {
|
||||
latestYear = y;
|
||||
latestMonth = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 매칭된 정보가 있는 경우
|
||||
if (latestYear > 0) {
|
||||
// 월 정보가 명확히 매핑된 경우 (RELEASE_DATES 사용)
|
||||
// 하지만 지시사항에 따라 "월을 못찾으면 12월" & "후속년도" 규칙 적용 여부 판단
|
||||
// RELEASE_DATES는 월이 이미 있으므로 그대로 사용하되,
|
||||
// 만약 YEAR_ONLY에만 걸리는 경우를 위해 로직 보강
|
||||
return `${latestYear}-${String(latestMonth).padStart(2, '0')}-01`;
|
||||
}
|
||||
|
||||
// 연도만 매칭되는 경우 (지시사항: 후속년도 12월)
|
||||
for (const [key, year] of Object.entries(YEAR_ONLY)) {
|
||||
if (cpuStr.includes(key) || gpuStr.includes(key)) {
|
||||
return `${year + 1}-12-01`;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const connection = await pool.getConnection();
|
||||
try {
|
||||
const [rows] = await connection.query(`
|
||||
SELECT c.id, c.asset_code, c.purchase_date, s.cpu, s.gpu
|
||||
FROM asset_core c
|
||||
LEFT JOIN asset_spec s ON c.id = s.asset_id
|
||||
`);
|
||||
|
||||
const updates = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const currentVal = (row.purchase_date || '').trim();
|
||||
|
||||
// 구매일자가 없거나 '-', 'undefined'인 경우 + 혹은 아직 보정이 필요한 자산
|
||||
if (!currentVal || currentVal === '-' || currentVal === 'undefined' || currentVal.startsWith('0000') || currentVal === '2024-01-01') {
|
||||
const specDate = inferDateFromSpecs(row.cpu, row.gpu);
|
||||
if (specDate) {
|
||||
updates.push({ id: row.id, date: specDate, code: row.asset_code, cpu: row.cpu, gpu: row.gpu });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`🚀 지시사항 반영: ${updates.length}건의 자산을 보정합니다. (후속년도/12월 규칙 적용)`);
|
||||
|
||||
for (const item of updates) {
|
||||
await connection.query('UPDATE asset_core SET purchase_date = ? WHERE id = ?', [item.date, item.id]);
|
||||
console.log(`[Update] ${item.code.padEnd(15)} | CPU: ${String(item.cpu).padEnd(20)} | GPU: ${String(item.gpu).padEnd(15)} -> ${item.date}`);
|
||||
}
|
||||
|
||||
console.log(`\n✅ 완료: ${updates.length}건 보정됨.`);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error:', err);
|
||||
} finally {
|
||||
connection.release();
|
||||
pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
88
scratch/fix_purchase_dates.js
Normal file
88
scratch/fix_purchase_dates.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import mysql from 'mysql2/promise';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
});
|
||||
|
||||
async function run() {
|
||||
const connection = await pool.getConnection();
|
||||
try {
|
||||
// 먼저 잘못 들어간 0000-00-01 등 복구
|
||||
console.log('잘못된 형식(0000-00-01 등)을 초기화합니다...');
|
||||
await connection.query("UPDATE asset_core SET purchase_date = '-' WHERE purchase_date LIKE '0000%' OR purchase_date = '2020-01-01'");
|
||||
|
||||
const [rows] = await connection.query('SELECT id, asset_code, purchase_date, category FROM asset_core');
|
||||
|
||||
const updates = [];
|
||||
const missing = [];
|
||||
|
||||
for (const row of rows) {
|
||||
const code = (row.asset_code || '').trim();
|
||||
const currentVal = (row.purchase_date || '').trim();
|
||||
|
||||
// 구매일자가 없거나 '-', 'undefined' 인 경우 대상
|
||||
if (!currentVal || currentVal === '-' || currentVal === 'undefined') {
|
||||
let inferredDate = null;
|
||||
|
||||
// 1. PREFIX-YYYYMM-NNNN 형식 (예: PC-202406-0001)
|
||||
const match6 = code.match(/[A-Z]+-(\d{4})(0[1-9]|1[0-2])-\d+/);
|
||||
if (match6) {
|
||||
inferredDate = `${match6[1]}-${match6[2]}-01`;
|
||||
} else {
|
||||
// 2. PREFIX-YYYYNN 형식 (예: PC-202423) -> 연도만 있고 뒤에 순번 2자리
|
||||
const matchYearSeq = code.match(/[A-Z]+-(20\d{2})(\d{2})$/);
|
||||
if (matchYearSeq) {
|
||||
inferredDate = `${matchYearSeq[1]}-01-01`; // 월을 모르므로 1월로 통일
|
||||
} else {
|
||||
// 3. PREFIX-YYNNN 형식 (예: PC-24001)
|
||||
const matchShort = code.match(/[A-Z]+-(1\d|2\d)(\d{3})/);
|
||||
if (matchShort) {
|
||||
inferredDate = `20${matchShort[1]}-01-01`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0000 등의 잘못된 매칭 방지
|
||||
if (inferredDate && !inferredDate.startsWith('0000')) {
|
||||
updates.push({ id: row.id, date: inferredDate, code: code });
|
||||
} else {
|
||||
missing.push({ id: row.id, code: code, category: row.category });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`총 ${updates.length}건의 자산을 업데이트합니다.`);
|
||||
for (const item of updates) {
|
||||
await connection.query('UPDATE asset_core SET purchase_date = ? WHERE id = ?', [item.date, item.id]);
|
||||
console.log(`[Update] ${item.code} -> ${item.date}`);
|
||||
}
|
||||
|
||||
console.log('\n--- 구매일자를 추정할 수 없는 자산 목록 ---');
|
||||
if (missing.length === 0) {
|
||||
console.log('없음');
|
||||
} else {
|
||||
// 중복 제거 및 정렬하여 보고
|
||||
const uniqueMissing = missing.filter(m => m.code !== '');
|
||||
uniqueMissing.forEach(m => {
|
||||
console.log(`[Missing] 코드: ${m.code.padEnd(20)} | 카테고리: ${m.category}`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`\n완료: ${updates.length}건 업데이트됨, ${missing.length}건 미결정.`);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error:', err);
|
||||
} finally {
|
||||
connection.release();
|
||||
pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -1,30 +0,0 @@
|
||||
import pkg from 'xlsx';
|
||||
const { readFile, utils } = pkg;
|
||||
|
||||
try {
|
||||
const workbook = readFile('c:/Project/HM ITAM/SampleData_PC.xlsx');
|
||||
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
const rawRows = utils.sheet_to_json(sheet, { header: 1 });
|
||||
|
||||
const corps = new Set();
|
||||
|
||||
// 첫 번째 행(헤더) 제외하고 C열(인덱스 2) 데이터 추출
|
||||
rawRows.slice(1).forEach(row => {
|
||||
if (row[2] !== undefined && row[2] !== null) {
|
||||
corps.add(String(row[2]).trim());
|
||||
}
|
||||
});
|
||||
|
||||
const jobs = new Map();
|
||||
rawRows.slice(1).forEach(row => {
|
||||
const job = String(row[3] || '').trim();
|
||||
jobs.set(job, (jobs.get(job) || 0) + 1);
|
||||
});
|
||||
|
||||
console.log('--- Unique Jobs in D column ---');
|
||||
Array.from(jobs.entries()).forEach(([key, val]) => {
|
||||
console.log(`${key}: ${val}대`);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import pkg from 'xlsx';
|
||||
const { readFile, utils } = pkg;
|
||||
|
||||
try {
|
||||
const workbook = readFile('c:/Project/HM ITAM/SampleData_SVR.xlsx');
|
||||
|
||||
for (const sheetName of workbook.SheetNames) {
|
||||
console.log(`\n================= Sheet: ${sheetName} =================`);
|
||||
const sheet = workbook.Sheets[sheetName];
|
||||
const rawRows = utils.sheet_to_json(sheet, { header: 1 });
|
||||
const validRows = rawRows.filter(row => {
|
||||
return row.some(val => val !== undefined && val !== null && String(val).trim() !== '');
|
||||
});
|
||||
|
||||
const header = validRows[0];
|
||||
const assetNameIdx = header.indexOf('자산명');
|
||||
const typeIdx = header.indexOf('유형');
|
||||
const detailIdx = header.indexOf('상세');
|
||||
const teamIdx = header.indexOf('팀명');
|
||||
|
||||
validRows.slice(1).forEach((row, idx) => {
|
||||
console.log(`[${idx + 1}] 팀명: ${row[teamIdx]} | 자산명: ${row[assetNameIdx]} | 유형: ${row[typeIdx]} | 상세: ${row[detailIdx]}`);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
import pkg from 'xlsx';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const { readFile, utils } = pkg;
|
||||
|
||||
// 임시 ID 생성 및 도우미 함수
|
||||
const randomId = () => Math.random().toString(36).substring(2, 9);
|
||||
const CORPS = ['한맥', '삼안', '장헌', '장헌산업', 'PTC', '바론', '한라'];
|
||||
|
||||
function cleanValue(val) {
|
||||
if (val === undefined || val === null) return '-';
|
||||
const str = String(val).trim();
|
||||
return str === '' ? '-' : str;
|
||||
}
|
||||
|
||||
try {
|
||||
const workbook = readFile('c:/Project/HM ITAM/SampleData_PC.xlsx');
|
||||
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
|
||||
// header: 1로 읽어 2차원 배열을 획득
|
||||
const rawRows = utils.sheet_to_json(sheet, { header: 1 });
|
||||
|
||||
// 첫 번째 행은 헤더이므로 제외
|
||||
const dataRows = rawRows.slice(1);
|
||||
|
||||
const parsedPCs = [];
|
||||
let pcIndex = 0;
|
||||
let designKihuckCount = 0;
|
||||
|
||||
for (const row of dataRows) {
|
||||
// 빈 행 건너뛰기 (성명, 부서, 팀명 모두 비어있으면 데이터가 없는 행으로 판단)
|
||||
if (!row[0] && !row[1] && !row[2] && !row[3] && !row[4]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const deptRaw = cleanValue(row[0]);
|
||||
const teamRaw = cleanValue(row[1]);
|
||||
const corpRaw = cleanValue(row[2]); // C열: 소속 (NEW)
|
||||
const jobRaw = cleanValue(row[3]); // D열: 직무 (밀림)
|
||||
const nameRaw = cleanValue(row[4]); // E열: 성명 (밀림)
|
||||
|
||||
// 특정 사용자 제외 필터
|
||||
if (nameRaw === '한치영' || nameRaw === '공용') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const posRaw = cleanValue(row[5]); // F열: 직급 (밀림)
|
||||
const mainboardRaw = cleanValue(row[6]); // G열: 메인보드 (밀림)
|
||||
const cpuRaw = cleanValue(row[7]); // H열: CPU (밀림)
|
||||
const cpuYearRaw = row[8]; // I열: CPU 출시연도 (밀림)
|
||||
const gpuRaw = cleanValue(row[9]); // J열: GPU (밀림)
|
||||
const gpuYearRaw = row[10]; // K열: GPU 출시연도 (밀림)
|
||||
const ramRaw = cleanValue(row[11]); // L열: RAM (밀림)
|
||||
const ssd1Raw = cleanValue(row[12]);// M열: SDD1 (밀림)
|
||||
const ssd2Raw = cleanValue(row[13]);// N열: SDD2 (밀림)
|
||||
const hdd1Raw = cleanValue(row[14]);// O열: HDD1 (밀림)
|
||||
const hdd2Raw = cleanValue(row[15]);// P열: HDD2 (밀림)
|
||||
const hdd3Raw = cleanValue(row[16]);// Q열: HDD3 (밀림)
|
||||
const hdd4Raw = cleanValue(row[17]);// R열: HDD4 (밀림)
|
||||
|
||||
// W열(22번째 인덱스) -> 구매일자
|
||||
const dateRaw = cleanValue(row[22]);
|
||||
// X열(23번째 인덱스) -> 비고
|
||||
const memoRaw = cleanValue(row[23]);
|
||||
|
||||
// 1. 법인 매핑 (엑셀 C열의 실제 소속 우선 사용, 없을 시 순환 지정)
|
||||
const purchase_corp = corpRaw !== '-' ? corpRaw : CORPS[pcIndex % CORPS.length];
|
||||
|
||||
// 2. 재고PC 판단 및 상태 설정
|
||||
const isStock = teamRaw === '재고PC';
|
||||
const hw_status = isStock ? '창고보관' : '운영중';
|
||||
|
||||
// 3. 성명 정제
|
||||
let user_current = nameRaw;
|
||||
if (isStock) {
|
||||
// 재고PC인 경우 직무 컬럼(row[3])에 성명이 들어가 있음
|
||||
user_current = jobRaw !== '-' ? jobRaw : '재고장비';
|
||||
}
|
||||
|
||||
// 4. 직무 정제
|
||||
let user_position = jobRaw;
|
||||
if (isStock) {
|
||||
user_position = '재고PC';
|
||||
} else if (user_position === '-' || user_position === 'undefined' || !user_position || ['안용주', '김민수', '심영표', '이수창A', '조병철', '윤진호', '김대영', '박정웅', '김유식'].includes(user_position)) {
|
||||
// 직무가 유효하지 않거나 이름인 경우 정제
|
||||
if (nameRaw === '장종찬' || posRaw === '사장') {
|
||||
user_position = '기획자';
|
||||
} else if (nameRaw === '노트북' || nameRaw === '공용') {
|
||||
user_position = '기획자';
|
||||
} else {
|
||||
// 팀명/부서 기준 매핑
|
||||
const combined = (deptRaw + ' ' + teamRaw).toUpperCase();
|
||||
if (combined.includes('개발') || combined.includes('SOLUTION') || combined.includes('WEB') || combined.includes('ERP')) {
|
||||
user_position = '개발자';
|
||||
} else if (combined.includes('BIM') || combined.includes('구조') || combined.includes('설계') || combined.includes('터널') || combined.includes('상하수도') || combined.includes('수자원') || combined.includes('건설') || combined.includes('CM')) {
|
||||
user_position = '엔지니어';
|
||||
} else if (combined.includes('디자인') || combined.includes('GRAPHICS')) {
|
||||
user_position = '디자이너';
|
||||
} else {
|
||||
user_position = '기획자';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 만약 직무가 'BIM모델러' 인 경우, 그대로 유지
|
||||
if (jobRaw === 'BIM모델러') {
|
||||
user_position = 'BIM모델러';
|
||||
}
|
||||
|
||||
// 개발자/디자이너 세부 직무 분리 로직 적용
|
||||
if (user_position === '개발자') {
|
||||
const nameUpper = nameRaw.trim();
|
||||
const teamUpper = teamRaw.toUpperCase();
|
||||
|
||||
if (nameUpper === '조찬영' || nameUpper === '김용연') {
|
||||
user_position = 'AI 개발자';
|
||||
} else if (
|
||||
teamUpper.includes('그래픽스') ||
|
||||
teamUpper.includes('MODELER') ||
|
||||
teamUpper.includes('HMEG') ||
|
||||
teamUpper.includes('EG-BIM') ||
|
||||
teamUpper.includes('GSIM') ||
|
||||
teamUpper.includes('STRANA')
|
||||
) {
|
||||
user_position = '3D 개발자';
|
||||
} else if (
|
||||
teamUpper.includes('WEB') ||
|
||||
teamUpper.includes('솔루션개발') ||
|
||||
teamUpper.includes('ERP') ||
|
||||
teamUpper.includes('전산')
|
||||
) {
|
||||
user_position = '웹 개발자';
|
||||
} else {
|
||||
user_position = '프로그램 개발자';
|
||||
}
|
||||
} else if (user_position === '디자이너') {
|
||||
const teamUpper = teamRaw.toUpperCase();
|
||||
if (teamUpper.includes('디자인셀')) {
|
||||
user_position = 'UXUI 디자이너';
|
||||
} else if (teamUpper.includes('디자인기획')) {
|
||||
// 디자인기획팀 소속 중 약 40%는 3D 디자이너, 60%는 편집 디자이너
|
||||
if (designKihuckCount % 10 < 4) {
|
||||
user_position = '3D 디자이너';
|
||||
} else {
|
||||
user_position = '편집 디자이너';
|
||||
}
|
||||
designKihuckCount++;
|
||||
} else {
|
||||
user_position = '편집 디자이너';
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 구매일자 포맷 가공 (YYYY-MM)
|
||||
let purchase_date = '2022-01'; // 기본값
|
||||
if (dateRaw !== '-') {
|
||||
if (dateRaw.length === 6 && !isNaN(dateRaw)) {
|
||||
purchase_date = `${dateRaw.substring(0, 4)}-${dateRaw.substring(4, 6)}`;
|
||||
} else if (dateRaw.length === 4 && !isNaN(dateRaw)) {
|
||||
purchase_date = `${dateRaw}-01`;
|
||||
} else {
|
||||
purchase_date = dateRaw;
|
||||
}
|
||||
} else if (cpuYearRaw && !isNaN(cpuYearRaw)) {
|
||||
purchase_date = `${cpuYearRaw}-01`;
|
||||
}
|
||||
|
||||
// 6. 도입 금액(purchase_amount) 책정
|
||||
let purchase_amount = '1500000';
|
||||
const cpuUpper = cpuRaw.toUpperCase();
|
||||
const gpuUpper = gpuRaw.toUpperCase();
|
||||
|
||||
if (cpuUpper.includes('I9') || cpuUpper.includes('RYZEN 9') || cpuUpper.includes('RYZEN9') || gpuUpper.includes('4080') || gpuUpper.includes('4090')) {
|
||||
purchase_amount = '3500000';
|
||||
} else if (cpuUpper.includes('I7') || cpuUpper.includes('RYZEN 7') || cpuUpper.includes('RYZEN7') || gpuUpper.includes('3070') || gpuUpper.includes('4070') || gpuUpper.includes('A2000')) {
|
||||
purchase_amount = '2200000';
|
||||
} else if (cpuUpper.includes('I5') || cpuUpper.includes('RYZEN 5') || cpuUpper.includes('RYZEN5') || gpuUpper.includes('3060') || gpuUpper.includes('2060')) {
|
||||
purchase_amount = '1500000';
|
||||
} else if (cpuYearRaw && parseInt(cpuYearRaw) < 2020) {
|
||||
purchase_amount = '800000';
|
||||
} else {
|
||||
purchase_amount = '950000';
|
||||
}
|
||||
|
||||
// 7. MAC 주소 생성 (16진수 포맷)
|
||||
const mac_address = `00:1A:2B:3C:4D:${pcIndex.toString(16).toUpperCase().padStart(2, '0')}`;
|
||||
|
||||
parsedPCs.push({
|
||||
id: randomId(),
|
||||
asset_type: '개인PC',
|
||||
purchase_corp,
|
||||
asset_code: 'PC-24' + String(pcIndex).padStart(3, '0'),
|
||||
purchase_date,
|
||||
user_current,
|
||||
user_position,
|
||||
current_dept: teamRaw !== '-' ? teamRaw : deptRaw,
|
||||
previous_dept: pcIndex % 8 === 0 ? '기획팀' : '-',
|
||||
location: '서울본사 7층',
|
||||
manager_primary: '김IT',
|
||||
manager_secondary: '이IT',
|
||||
model_name: mainboardRaw !== '-' ? mainboardRaw : '사내 표준 데스크톱',
|
||||
os: 'Windows 11 Pro',
|
||||
cpu: cpuRaw,
|
||||
gpu: gpuRaw,
|
||||
ram: ramRaw,
|
||||
ssd_1: ssd1Raw,
|
||||
ssd_2: ssd2Raw,
|
||||
ssd_3: '-',
|
||||
hdd_1: hdd1Raw,
|
||||
hdd_2: hdd2Raw,
|
||||
hdd_3: hdd3Raw,
|
||||
hdd_4: hdd4Raw,
|
||||
mainboard: mainboardRaw,
|
||||
ip_address: '192.168.0.' + (10 + (pcIndex % 240)),
|
||||
purchase_amount,
|
||||
purchase_vendor: 'LG전자/삼성전자/HP',
|
||||
approval_document: '2024_상반기_PC구매_' + pcIndex,
|
||||
memo: memoRaw !== '-' ? memoRaw : (isStock ? '재고 보유 분' : '임직원 지급용'),
|
||||
asset_name: `개인PC ${pcIndex + 1}`,
|
||||
mac_address,
|
||||
hw_status
|
||||
});
|
||||
|
||||
pcIndex++;
|
||||
}
|
||||
|
||||
console.log(`Successfully parsed ${parsedPCs.length} PCs from excel file.`);
|
||||
|
||||
// dummyData.ts 의 나머지 데이터(dummyServers 등)를 포함하여 전체 파일을 새로 씁니다.
|
||||
const newDummyDataFileContent = `import { HardwareAsset, SoftwareAsset, SWUser, HardwareLog } from './excelHandler';
|
||||
|
||||
// 유틸리티: 랜덤 문자열
|
||||
const randomId = () => Math.random().toString(36).substring(2, 9);
|
||||
|
||||
// 유틸리티: 랜덤 년월 (YYYY-MM) (최근 10년)
|
||||
const randomPurchaseYM = () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const year = currentYear - Math.floor(Math.random() * 10);
|
||||
const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0');
|
||||
return \`\${year}-\${month}\`;
|
||||
};
|
||||
|
||||
// 유틸리티: 랜덤 YYYY-MM-DD
|
||||
const randomDateStr = (maxYearsAgo = 10) => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const year = currentYear - Math.floor(Math.random() * maxYearsAgo);
|
||||
const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0');
|
||||
const day = String(Math.floor(Math.random() * 28) + 1).padStart(2, '0');
|
||||
return \`\${year}-\${month}-\${day}\`;
|
||||
};
|
||||
|
||||
const CORPS = ['한맥', '삼안', '장헌', '장헌산업', 'PTC', '바론', '한라'];
|
||||
const getRandomCorp = () => CORPS[Math.floor(Math.random() * CORPS.length)];
|
||||
|
||||
// ────────────────────────────────────────────────────────
|
||||
// 1. SampleData_PC.xlsx 에서 파싱된 PC 데이터 주입
|
||||
// ────────────────────────────────────────────────────────
|
||||
export const dummyPCs: any[] = ${JSON.stringify(parsedPCs, null, 2)};
|
||||
|
||||
// ────────────────────────────────────────────────────────
|
||||
// 2. 기타 자산 더미 데이터 (서버, 스토리지, 소프트웨어 등)
|
||||
// ────────────────────────────────────────────────────────
|
||||
|
||||
export const dummyServers: any[] = Array.from({ length: 15 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '서버',
|
||||
type2: i % 2 === 0 ? '물리' : '가상',
|
||||
purchase_corp: getRandomCorp(),
|
||||
asset_code: \`SRV-24\${String(i).padStart(3, '0')}\`,
|
||||
purchase_date: randomPurchaseYM(),
|
||||
asset_purpose: i % 2 === 0 ? '운영 웹 서버' : '사내망 DB 서버',
|
||||
current_dept: '인프라팀',
|
||||
previous_dept: '-',
|
||||
location: 'IDC 센터 1-A',
|
||||
manager_primary: '박서버',
|
||||
manager_secondary: '최백업',
|
||||
ip_address: \`10.0.0.\${10 + i}\`,
|
||||
ip_address_2: \`192.168.100.\${10 + i}\`,
|
||||
remote_tool: 'RDP / SSH',
|
||||
remote_id: \`admin_\${i}\`,
|
||||
remote_pw: '********',
|
||||
model_name: 'Dell PowerEdge R750',
|
||||
os: 'Ubuntu 22.04 LTS',
|
||||
cpu: 'Intel Xeon Gold 6330',
|
||||
ram: '128GB',
|
||||
gpu: i % 3 === 0 ? 'NVIDIA A100' : '-',
|
||||
ssd_1: '1TB NVMe',
|
||||
ssd_2: '1TB NVMe',
|
||||
hdd_1: '4TB HDD',
|
||||
monitoring: 'Zabbix Agent',
|
||||
purchase_amount: '8500000',
|
||||
purchase_vendor: '델테크놀로지스',
|
||||
approval_document: \`2024_IDC_확장품의_\sign\${i}\`,
|
||||
memo: '서버 랙 3번 위치',
|
||||
asset_name: \`운영 서버 \${i+1}\`,
|
||||
mac_address: \`00:1A:2B:3C:4E:\${String(i).padStart(2, '0')}\`,
|
||||
hw_status: '운영중'
|
||||
}));
|
||||
|
||||
export const dummyStorages: any[] = Array.from({ length: 8 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '스토리지',
|
||||
purchase_corp: getRandomCorp(),
|
||||
asset_code: \`STR-24\${String(i).padStart(3, '0')}\`,
|
||||
asset_name: \`공용 스토리지 \${i+1}\`,
|
||||
location: 'IDC 센터 1-A',
|
||||
model_name: 'Synology RS4021xs+',
|
||||
volume: '100TB',
|
||||
manager_primary: '박서버',
|
||||
manager_secondary: '최백업',
|
||||
ip_address: \`10.0.0.\${50 + i}\`,
|
||||
mac_address: \`00:1A:2B:3C:4F:\${String(i).padStart(2, '0')}\`,
|
||||
purchase_date: randomPurchaseYM(),
|
||||
purchase_amount: '12000000',
|
||||
purchase_vendor: '시놀로지코리아',
|
||||
approval_document: \`2024_스토리지구매_\${i}\`,
|
||||
memo: '부서별 백업본 저장용',
|
||||
os: 'Synology DSM',
|
||||
asset_purpose: '데이터 백업',
|
||||
hw_status: '운영중'
|
||||
}));
|
||||
|
||||
export const dummyEquips: any[] = Array.from({ length: 12 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '전산비품',
|
||||
purchase_corp: getRandomCorp(),
|
||||
asset_code: \`EQ-24\${String(i).padStart(3, '0')}\`,
|
||||
asset_name: \`네트워크 스위치 \${i+1}\`,
|
||||
location: '전산실 랙 1',
|
||||
manager_primary: '네트워크담당자',
|
||||
ip_address: \`192.168.10.\${200 + i}\`,
|
||||
mac_address: \`00:1A:2B:3C:51:\${String(i).padStart(2, '0')}\`,
|
||||
os: 'Cisco IOS',
|
||||
purchase_date: randomPurchaseYM(),
|
||||
purchase_amount: '150000',
|
||||
purchase_vendor: '다나와',
|
||||
approval_document: \`2024_비품구매_\${i}\`,
|
||||
memo: '사내망 확장용',
|
||||
asset_purpose: '네트워크 분배'
|
||||
}));
|
||||
|
||||
export const dummyMobiles: any[] = Array.from({ length: 15 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '모바일기기',
|
||||
purchase_corp: getRandomCorp(),
|
||||
asset_code: \`MOB-24\${String(i).padStart(3, '0')}\`,
|
||||
asset_name: \`테스트용 단말기 \${i+1}\`,
|
||||
location: '개발2팀',
|
||||
manager_primary: '테스터',
|
||||
os: i % 2 === 0 ? 'Android 14' : 'iOS 17',
|
||||
purchase_date: randomPurchaseYM(),
|
||||
purchase_amount: '900000',
|
||||
purchase_vendor: '삼성전자/애플',
|
||||
approval_document: \`2024_모바일구매_\${i}\`,
|
||||
memo: '앱 호환성 테스트 전용',
|
||||
asset_purpose: 'QA 테스트',
|
||||
ip_address: \`192.168.1.\${10 + i}\`,
|
||||
mac_address: \`00:1A:2B:3C:50:\${String(i).padStart(2, '0')}\`
|
||||
}));
|
||||
|
||||
export const dummySubSw: any[] = Array.from({ length: 10 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_type: '구독SW',
|
||||
sw_field: '업무용/협업',
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '전사',
|
||||
product_name: \`Microsoft 365 E\${3 + (i%2)}\`,
|
||||
purchase_date: randomDateStr(3),
|
||||
start_date: randomDateStr(1),
|
||||
expired_date: randomDateStr(0),
|
||||
purchase_amount: '150000',
|
||||
asset_count: 50 + i * 5,
|
||||
email_account: \`admin\${i}@hmcorp.com\`,
|
||||
purchase_vendor: '소프트웨어인라이프',
|
||||
memo: '연간 계약 갱신 필요'
|
||||
}));
|
||||
|
||||
export const dummyPermSw: any[] = Array.from({ length: 5 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_type: '영구SW',
|
||||
sw_field: '디자인/설계',
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '디자인팀',
|
||||
product_name: \`AutoCAD 202\${i%4}\`,
|
||||
purchase_date: randomDateStr(5),
|
||||
start_date: randomDateStr(5),
|
||||
expired_date: '2099-12-31',
|
||||
purchase_amount: '3000000',
|
||||
asset_count: 2,
|
||||
email_account: \`design\${i}@hmcorp.com\`,
|
||||
purchase_vendor: '오토데스크 파트너',
|
||||
memo: 'USB 동글키 보관중'
|
||||
}));
|
||||
|
||||
export const dummyCloud: any[] = Array.from({ length: 5 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_type: '클라우드',
|
||||
asset_mfr: i % 2 === 0 ? 'AWS' : 'GCP',
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '개발팀',
|
||||
product_name: \`컴퓨팅 인스턴스 Type \${i}\`,
|
||||
email_account: \`awsadmin\${i}@hmcorp.com\`,
|
||||
purchase_method: '법인카드(신한 1234)',
|
||||
purchase_amount: \`\${500000 + i * 100000}\`,
|
||||
asset_count: 1,
|
||||
purchase_vendor: 'AWS/GCP',
|
||||
memo: '환율 변동에 따라 매월 상이함'
|
||||
}));
|
||||
|
||||
export const dummyDomain: any[] = Array.from({ length: 5 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '도메인',
|
||||
purchase_corp: getRandomCorp(),
|
||||
product_name: \`사내 운영 서비스 \${i+1}\`,
|
||||
domain_address: \`service\${i+1}.hmcorp.com\`,
|
||||
start_date: randomDateStr(4),
|
||||
expired_date: randomDateStr(0),
|
||||
purchase_amount: '22000',
|
||||
manager_primary: '인프라팀장',
|
||||
manager_secondary: '인프라담당자',
|
||||
memo: '가비아 자동갱신 설정 완료'
|
||||
}));
|
||||
|
||||
export const dummySwUsers: any[] = Array.from({ length: 15 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_id: dummySubSw[0]?.id || randomId(),
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '경영지원팀',
|
||||
user_current: \`홍길동\${i}\`,
|
||||
memo: \`SW신청서_2400\${i}\`
|
||||
}));
|
||||
|
||||
export const dummyLogs: any[] = Array.from({ length: 10 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
assetId: dummyPCs[0]?.id || randomId(),
|
||||
date: randomDateStr(1),
|
||||
details: i % 2 === 0 ? '메모리 추가 증설 (16GB -> 32GB)' : '디스플레이 파손 수리',
|
||||
user: 'IT지원팀',
|
||||
cost: i % 2 === 0 ? 80000 : 150000,
|
||||
}));
|
||||
`;
|
||||
|
||||
fs.writeFileSync('c:/Project/HM ITAM/src/core/dummyData.ts', newDummyDataFileContent, 'utf-8');
|
||||
console.log('✅ dummyData.ts file updated successfully.');
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to update dummy data:', e);
|
||||
}
|
||||
@@ -1,442 +0,0 @@
|
||||
import pkg from 'xlsx';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const { readFile, utils } = pkg;
|
||||
|
||||
const randomId = () => Math.random().toString(36).substring(2, 9);
|
||||
const CORPS = ['한맥', '삼안', '장헌', '장헌산업', 'PTC', '바론', '한라'];
|
||||
|
||||
function cleanValue(val) {
|
||||
if (val === undefined || val === null) return '-';
|
||||
const str = String(val).trim();
|
||||
return str === '' ? '-' : str;
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 기존 dummyPCs 로딩
|
||||
const dummyDataPath = 'c:/Project/HM ITAM/src/core/dummyData.ts';
|
||||
const content = fs.readFileSync(dummyDataPath, 'utf-8');
|
||||
const matchPCs = content.match(/export const dummyPCs: any\[\] = (\[[\s\S]*?\]);/);
|
||||
if (!matchPCs) {
|
||||
console.error('Failed to parse dummyPCs from dummyData.ts');
|
||||
process.exit(1);
|
||||
}
|
||||
const dummyPCs = JSON.parse(matchPCs[1]);
|
||||
console.log(`Loaded ${dummyPCs.length} existing PCs from dummyData.ts`);
|
||||
|
||||
// 2. SampleData_SVR.xlsx 파싱
|
||||
const workbook = readFile('c:/Project/HM ITAM/SampleData_SVR.xlsx');
|
||||
|
||||
const parsedServers = [];
|
||||
const parsedStorages = [];
|
||||
const parsedEquips = [];
|
||||
|
||||
let serverIndex = 0;
|
||||
let storageIndex = 0;
|
||||
let equipIndex = 0;
|
||||
|
||||
// ----------------- 시트 1: 합본데이터(공용PC) -----------------
|
||||
const sheetPC = workbook.Sheets['합본데이터(공용PC)'];
|
||||
const rawPC = utils.sheet_to_json(sheetPC, { header: 1 });
|
||||
const rowsPC = rawPC.slice(1).filter(row => row.some(val => val !== undefined && val !== null && String(val).trim() !== ''));
|
||||
|
||||
for (const row of rowsPC) {
|
||||
const teamRaw = cleanValue(row[0]);
|
||||
const svrNoRaw = cleanValue(row[1]);
|
||||
const assetNameRaw = cleanValue(row[2]);
|
||||
const typeRaw = cleanValue(row[3]);
|
||||
const detailRaw = cleanValue(row[4]);
|
||||
const locRaw = cleanValue(row[5]);
|
||||
const mgr1Raw = cleanValue(row[6]);
|
||||
const mgr2Raw = cleanValue(row[7]);
|
||||
const osRaw = cleanValue(row[8]);
|
||||
const osVerRaw = cleanValue(row[9]);
|
||||
const osBuildRaw = cleanValue(row[10]);
|
||||
const modelRaw = cleanValue(row[11]);
|
||||
const mainboardRaw = cleanValue(row[12]);
|
||||
const cpuRaw = cleanValue(row[13]);
|
||||
const ramRaw = cleanValue(row[14]);
|
||||
const gpuRaw = cleanValue(row[15]);
|
||||
const ssd1Raw = cleanValue(row[16]);
|
||||
const ssd2Raw = cleanValue(row[17]);
|
||||
const hdd1Raw = cleanValue(row[18]);
|
||||
const hdd2Raw = cleanValue(row[19]);
|
||||
const hdd3Raw = cleanValue(row[20]);
|
||||
const hdd4Raw = cleanValue(row[21]);
|
||||
|
||||
const ipAddress = '172.16.10.' + (50 + (serverIndex % 150));
|
||||
const randomCorp = CORPS[serverIndex % CORPS.length];
|
||||
|
||||
// 서비스 분류 판단
|
||||
let service_type = '내부서비스';
|
||||
const detailUpper = detailRaw.toUpperCase();
|
||||
const assetUpper = assetNameRaw.toUpperCase();
|
||||
const teamUpper = teamRaw.toUpperCase();
|
||||
|
||||
if (teamUpper.includes('회의실') || assetUpper.includes('회의실') || assetUpper.includes('사이니지')) {
|
||||
service_type = '회의용/공용';
|
||||
} else if (
|
||||
detailUpper.includes('SAAS') || detailUpper.includes('웹서비스') ||
|
||||
detailUpper.includes('운영') || detailUpper.includes('WAS') ||
|
||||
detailUpper.includes('MYSTATION') || detailUpper.includes('CLOUD') ||
|
||||
detailUpper.includes('홈페이지') || detailUpper.includes('WEB') ||
|
||||
detailUpper.includes('외주') || assetUpper.includes('CLOUD') ||
|
||||
assetUpper.includes('웹서비스') || assetUpper.includes('운영')
|
||||
) {
|
||||
service_type = '외부서비스';
|
||||
}
|
||||
|
||||
// 방치 의심 판단
|
||||
const is_inactive = (
|
||||
detailUpper.includes('원격 및 로컬접근 불가') ||
|
||||
detailUpper.includes('철수예정') ||
|
||||
detailUpper.includes('미사용') ||
|
||||
detailUpper.includes('구형 OS')
|
||||
);
|
||||
|
||||
// 실시간 리소스 및 네트워크 가상 데이터 생성
|
||||
let cpu_usage = 0;
|
||||
let ram_usage = 0;
|
||||
let network_traffic = '0 GB';
|
||||
|
||||
if (is_inactive) {
|
||||
cpu_usage = 0;
|
||||
ram_usage = 0;
|
||||
network_traffic = '0 GB (N/A)';
|
||||
} else if (service_type === '회의용/공용') {
|
||||
cpu_usage = Math.floor(Math.random() * 10) + 2; // 2%~12%
|
||||
ram_usage = Math.floor(Math.random() * 15) + 5; // 5%~20%
|
||||
network_traffic = (Math.random() * 1.5 + 0.1).toFixed(1) + ' GB';
|
||||
} else if (service_type === '외부서비스') {
|
||||
// 일부 저사양 운영/SaaS 서버는 병목 현상을 시뮬레이션하기 위해 과부하 부여
|
||||
const isUnderSpec = !gpuRaw.toUpperCase().includes('RTX 30') && !gpuRaw.toUpperCase().includes('RTX 40') && (cpuRaw.toUpperCase().includes('I5') || ramRaw.toUpperCase().includes('16GB') || cpuRaw === '-');
|
||||
if (isUnderSpec) {
|
||||
cpu_usage = Math.floor(Math.random() * 15) + 81; // 81%~95% (과부하)
|
||||
ram_usage = Math.floor(Math.random() * 10) + 86; // 86%~95%
|
||||
} else {
|
||||
cpu_usage = Math.floor(Math.random() * 30) + 40; // 40%~70%
|
||||
ram_usage = Math.floor(Math.random() * 20) + 60; // 60%~80%
|
||||
}
|
||||
network_traffic = (Math.random() * 1500 + 300).toFixed(0) + ' GB';
|
||||
} else { // 내부서비스
|
||||
// Abaqus 해석용이나 Pix4D 등 고부하 내부 인프라도 부하율 높게 부여
|
||||
const isHighLoad = detailUpper.includes('ABAQUS') || detailUpper.includes('PIX4D') || detailUpper.includes('영상 렌더링') || detailUpper.includes('TERRA');
|
||||
if (isHighLoad) {
|
||||
cpu_usage = Math.floor(Math.random() * 20) + 70; // 70%~90%
|
||||
ram_usage = Math.floor(Math.random() * 20) + 75; // 75%~95%
|
||||
} else {
|
||||
cpu_usage = Math.floor(Math.random() * 35) + 15; // 15%~50%
|
||||
ram_usage = Math.floor(Math.random() * 30) + 20; // 20%~50%
|
||||
}
|
||||
network_traffic = (Math.random() * 300 + 10).toFixed(0) + ' GB';
|
||||
}
|
||||
|
||||
const assetItem = {
|
||||
id: randomId(),
|
||||
asset_type: typeRaw !== '-' ? typeRaw : '공용PC',
|
||||
purchase_corp: randomCorp,
|
||||
asset_code: 'SVR-24' + String(serverIndex).padStart(3, '0'),
|
||||
purchase_date: '2023-03',
|
||||
asset_purpose: detailRaw,
|
||||
current_dept: teamRaw,
|
||||
previous_dept: '-',
|
||||
location: locRaw,
|
||||
manager_primary: mgr1Raw,
|
||||
manager_secondary: mgr2Raw,
|
||||
ip_address: ipAddress,
|
||||
remote_tool: 'RDP / VNC',
|
||||
model_name: modelRaw !== '-' ? modelRaw : (mainboardRaw !== '-' ? mainboardRaw : '사내 표준 공용PC'),
|
||||
os: osRaw !== '-' ? `${osRaw} (${osVerRaw})` : 'Windows 10',
|
||||
cpu: cpuRaw,
|
||||
ram: ramRaw,
|
||||
gpu: gpuRaw,
|
||||
ssd_1: ssd1Raw,
|
||||
ssd_2: ssd2Raw,
|
||||
hdd_1: hdd1Raw,
|
||||
hdd_2: hdd2Raw,
|
||||
hdd_3: hdd3Raw,
|
||||
hdd_4: hdd4Raw,
|
||||
monitoring: service_type === '외부서비스' ? '대상' : '비대상',
|
||||
purchase_amount: gpuRaw.toUpperCase().includes('RTX 4080') || gpuRaw.toUpperCase().includes('RTX 3090') ? '3500000' : '1500000',
|
||||
purchase_vendor: '다나와',
|
||||
approval_document: '2023_공용PC_도입_' + serverIndex,
|
||||
memo: is_inactive ? '방치 의심 장비 (회수 필요)' : '정상 운영 장비',
|
||||
asset_name: assetNameRaw,
|
||||
mac_address: `00:1A:2B:3C:5E:${serverIndex.toString(16).toUpperCase().padStart(2, '0')}`,
|
||||
hw_status: is_inactive ? '수리/대기' : '운영중',
|
||||
service_type: service_type,
|
||||
is_inactive: is_inactive,
|
||||
cpu_usage: cpu_usage,
|
||||
ram_usage: ram_usage,
|
||||
network_traffic: network_traffic
|
||||
};
|
||||
|
||||
// 스토리지로 보낼 자산들 (유형이 NAS/DAS이거나 자산명에 NAS가 들어가면)
|
||||
if (typeRaw.toUpperCase().includes('NAS') || typeRaw.toUpperCase().includes('DAS') || assetUpper.includes('NAS') || assetUpper.includes('DAS')) {
|
||||
assetItem.asset_code = 'STO-24' + String(storageIndex).padStart(3, '0');
|
||||
assetItem.volume = hdd1Raw !== '-' ? hdd1Raw : '10TB';
|
||||
parsedStorages.push(assetItem);
|
||||
storageIndex++;
|
||||
} else {
|
||||
parsedServers.push(assetItem);
|
||||
serverIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------- 시트 2: 합본데이터(NAS) -----------------
|
||||
const sheetNAS = workbook.Sheets['합본데이터(NAS)'];
|
||||
const rawNAS = utils.sheet_to_json(sheetNAS, { header: 1 });
|
||||
const rowsNAS = rawNAS.slice(1).filter(row => row.some(val => val !== undefined && val !== null && String(val).trim() !== ''));
|
||||
|
||||
for (const row of rowsNAS) {
|
||||
const teamRaw = cleanValue(row[0]);
|
||||
const svrNoRaw = cleanValue(row[1]);
|
||||
const assetNameRaw = cleanValue(row[2]);
|
||||
const typeRaw = cleanValue(row[3]);
|
||||
const detailRaw = cleanValue(row[4]);
|
||||
const locRaw = cleanValue(row[5]);
|
||||
const mgr1Raw = cleanValue(row[6]);
|
||||
const mgr2Raw = cleanValue(row[7]);
|
||||
const toolRaw = cleanValue(row[8]);
|
||||
const ipRaw = cleanValue(row[9]);
|
||||
const ip2Raw = cleanValue(row[10]);
|
||||
const idRaw = cleanValue(row[11]);
|
||||
const pwRaw = cleanValue(row[12]);
|
||||
const osRaw = cleanValue(row[15]);
|
||||
const osVerRaw = cleanValue(row[16]);
|
||||
const osBuildRaw = cleanValue(row[17]);
|
||||
const modelRaw = cleanValue(row[18]);
|
||||
const cpuRaw = cleanValue(row[19]);
|
||||
const ramRaw = cleanValue(row[20]);
|
||||
const gpuRaw = cleanValue(row[21]);
|
||||
const ssd1Raw = cleanValue(row[22]);
|
||||
const ssd2Raw = cleanValue(row[23]);
|
||||
const hdd1Raw = cleanValue(row[24]);
|
||||
const hdd2Raw = cleanValue(row[25]);
|
||||
const hdd3Raw = cleanValue(row[26]);
|
||||
const hdd4Raw = cleanValue(row[27]);
|
||||
|
||||
const randomCorp = CORPS[storageIndex % CORPS.length];
|
||||
|
||||
// NAS는 기본적으로 내부 백업/공유용 인프라
|
||||
const service_type = '내부서비스';
|
||||
const is_inactive = false;
|
||||
|
||||
// NAS 실시간 리소스 가상 데이터
|
||||
const cpu_usage = Math.floor(Math.random() * 25) + 15; // 15%~40%
|
||||
const ram_usage = Math.floor(Math.random() * 35) + 30; // 30%~65%
|
||||
const network_traffic = (Math.random() * 600 + 50).toFixed(0) + ' GB';
|
||||
|
||||
const assetItem = {
|
||||
id: randomId(),
|
||||
asset_type: typeRaw !== '-' ? typeRaw : '공용 NAS',
|
||||
purchase_corp: randomCorp,
|
||||
asset_code: 'STO-24' + String(storageIndex).padStart(3, '0'),
|
||||
purchase_date: '2022-08',
|
||||
asset_purpose: detailRaw,
|
||||
current_dept: teamRaw !== '-' ? teamRaw : '디자인팀',
|
||||
previous_dept: '-',
|
||||
location: locRaw,
|
||||
manager_primary: mgr1Raw,
|
||||
manager_secondary: mgr2Raw,
|
||||
ip_address: ipRaw !== '-' ? ipRaw : '172.16.42.' + (100 + storageIndex),
|
||||
remote_tool: toolRaw !== '-' ? toolRaw : 'Web GUI',
|
||||
model_name: modelRaw !== '-' ? modelRaw : 'Synology 공용 NAS',
|
||||
os: osRaw !== '-' ? `${osRaw} ${osVerRaw}` : 'DSM 7.x',
|
||||
cpu: cpuRaw,
|
||||
ram: ramRaw,
|
||||
gpu: gpuRaw,
|
||||
ssd_1: ssd1Raw,
|
||||
ssd_2: ssd2Raw,
|
||||
hdd_1: hdd1Raw,
|
||||
hdd_2: hdd2Raw,
|
||||
hdd_3: hdd3Raw,
|
||||
hdd_4: hdd4Raw,
|
||||
monitoring: '비대상',
|
||||
purchase_amount: '4500000',
|
||||
purchase_vendor: '시놀로지 총판',
|
||||
approval_document: '2022_스토리지_도입_' + storageIndex,
|
||||
memo: '스토리지 서버 공유 자산',
|
||||
asset_name: assetNameRaw,
|
||||
mac_address: `00:1A:2B:3C:5F:${storageIndex.toString(16).toUpperCase().padStart(2, '0')}`,
|
||||
hw_status: '운영중',
|
||||
service_type: service_type,
|
||||
is_inactive: is_inactive,
|
||||
volume: hdd1Raw !== '-' ? hdd1Raw : '24TB',
|
||||
cpu_usage: cpu_usage,
|
||||
ram_usage: ram_usage,
|
||||
network_traffic: network_traffic
|
||||
};
|
||||
|
||||
parsedStorages.push(assetItem);
|
||||
storageIndex++;
|
||||
}
|
||||
|
||||
console.log(`Parsed Servers: ${parsedServers.length} units`);
|
||||
console.log(`Parsed Storages: ${parsedStorages.length} units`);
|
||||
|
||||
// 3. 파일 다시 쓰기
|
||||
const newDummyDataFileContent = `import { HardwareAsset, SoftwareAsset, SWUser, HardwareLog } from './excelHandler';
|
||||
|
||||
// 유틸리티: 랜덤 문자열
|
||||
const randomId = () => Math.random().toString(36).substring(2, 9);
|
||||
|
||||
// 유틸리티: 랜덤 년월 (YYYY-MM) (최근 10년)
|
||||
const randomPurchaseYM = () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const year = currentYear - Math.floor(Math.random() * 10);
|
||||
const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0');
|
||||
return \`\${year}-\${month}\`;
|
||||
};
|
||||
|
||||
// 유틸리티: 랜덤 YYYY-MM-DD
|
||||
const randomDateStr = (maxYearsAgo = 10) => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const year = currentYear - Math.floor(Math.random() * maxYearsAgo);
|
||||
const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0');
|
||||
const day = String(Math.floor(Math.random() * 28) + 1).padStart(2, '0');
|
||||
return \`\${year}-\${month}-\${day}\`;
|
||||
};
|
||||
|
||||
const CORPS = ['한맥', '삼안', '장헌', '장헌산업', 'PTC', '바론', '한라'];
|
||||
const getRandomCorp = () => CORPS[Math.floor(Math.random() * CORPS.length)];
|
||||
|
||||
// ────────────────────────────────────────────────────────
|
||||
// 1. SampleData_PC.xlsx 에서 파싱된 PC 데이터 주입
|
||||
// ────────────────────────────────────────────────────────
|
||||
export const dummyPCs: any[] = ${JSON.stringify(dummyPCs, null, 2)};
|
||||
|
||||
// ────────────────────────────────────────────────────────
|
||||
// 2. 기타 자산 더미 데이터 (서버, 스토리지, 소프트웨어 등 - 엑셀 파싱 연동)
|
||||
// ────────────────────────────────────────────────────────
|
||||
|
||||
export const dummyServers: any[] = ${JSON.stringify(parsedServers, null, 2)};
|
||||
|
||||
export const dummyStorages: any[] = ${JSON.stringify(parsedStorages, null, 2)};
|
||||
|
||||
export const dummyEquips: any[] = Array.from({ length: 12 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '전산비품',
|
||||
purchase_corp: getRandomCorp(),
|
||||
asset_code: \`EQ-24\${String(i).padStart(3, '0')}\`,
|
||||
asset_name: \`네트워크 스위치 \${i+1}\`,
|
||||
location: '전산실 랙 1',
|
||||
manager_primary: '네트워크담당자',
|
||||
ip_address: \`192.168.10.\${200 + i}\`,
|
||||
mac_address: \`00:1A:2B:3C:51:\${String(i).padStart(2, '0')}\`,
|
||||
os: 'Cisco IOS',
|
||||
purchase_date: randomPurchaseYM(),
|
||||
purchase_amount: '150000',
|
||||
purchase_vendor: '다나와',
|
||||
approval_document: \`2024_비품구매_\${i}\`,
|
||||
memo: '사내망 확장용',
|
||||
asset_purpose: '네트워크 분배'
|
||||
}));
|
||||
|
||||
export const dummyMobiles: any[] = Array.from({ length: 15 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '모바일기기',
|
||||
purchase_corp: getRandomCorp(),
|
||||
asset_code: \`MOB-24\${String(i).padStart(3, '0')}\`,
|
||||
asset_name: \`테스트용 단말기 \${i+1}\`,
|
||||
location: '개발2팀',
|
||||
manager_primary: '테스터',
|
||||
os: i % 2 === 0 ? 'Android 14' : 'iOS 17',
|
||||
purchase_date: randomPurchaseYM(),
|
||||
purchase_amount: '900000',
|
||||
purchase_vendor: '삼성전자/애플',
|
||||
approval_document: \`2024_모바일구매_\${i}\`,
|
||||
memo: '앱 호환성 테스트 전용',
|
||||
asset_purpose: 'QA 테스트',
|
||||
ip_address: \`192.168.1.\${10 + i}\`,
|
||||
mac_address: \`00:1A:2B:3C:50:\${String(i).padStart(2, '0')}\`
|
||||
}));
|
||||
|
||||
export const dummySubSw: any[] = Array.from({ length: 10 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_type: '구독SW',
|
||||
sw_field: '업무용/협업',
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '전사',
|
||||
product_name: \`Microsoft 365 E\${3 + (i%2)}\`,
|
||||
purchase_date: randomDateStr(3),
|
||||
start_date: randomDateStr(1),
|
||||
expired_date: randomDateStr(0),
|
||||
purchase_amount: '150000',
|
||||
asset_count: 50 + i * 5,
|
||||
email_account: \`admin\${i}@hmcorp.com\`,
|
||||
purchase_vendor: '소프트웨어인라이프',
|
||||
memo: '연간 계약 갱신 필요'
|
||||
}));
|
||||
|
||||
export const dummyPermSw: any[] = Array.from({ length: 5 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_type: '영구SW',
|
||||
sw_field: '디자인/설계',
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '디자인팀',
|
||||
product_name: \`AutoCAD 202\${i%4}\`,
|
||||
purchase_date: randomDateStr(5),
|
||||
start_date: randomDateStr(5),
|
||||
expired_date: '2099-12-31',
|
||||
purchase_amount: '3000000',
|
||||
asset_count: 2,
|
||||
email_account: \`design\${i}@hmcorp.com\`,
|
||||
purchase_vendor: '오토데스크 파트너',
|
||||
memo: 'USB 동글키 보관중'
|
||||
}));
|
||||
|
||||
export const dummyCloud: any[] = Array.from({ length: 5 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_type: '클라우드',
|
||||
asset_mfr: i % 2 === 0 ? 'AWS' : 'GCP',
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '개발팀',
|
||||
product_name: \`컴퓨팅 인스턴스 Type \${i}\`,
|
||||
email_account: \`awsadmin\${i}@hmcorp.com\`,
|
||||
purchase_method: '법인카드(신한 1234)',
|
||||
purchase_amount: \`\${500000 + i * 100000}\`,
|
||||
asset_count: 1,
|
||||
purchase_vendor: 'AWS/GCP',
|
||||
memo: '환율 변동에 따라 매월 상이함'
|
||||
}));
|
||||
|
||||
export const dummyDomain: any[] = Array.from({ length: 5 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
asset_type: '도메인',
|
||||
purchase_corp: getRandomCorp(),
|
||||
product_name: \`사내 운영 서비스 \${i+1}\`,
|
||||
domain_address: \`service\${i+1}.hmcorp.com\`,
|
||||
start_date: randomDateStr(4),
|
||||
expired_date: randomDateStr(0),
|
||||
purchase_amount: '22000',
|
||||
manager_primary: '인프라팀장',
|
||||
manager_secondary: '인프라담당자',
|
||||
memo: '가비아 자동갱신 설정 완료'
|
||||
}));
|
||||
|
||||
export const dummySwUsers: any[] = Array.from({ length: 15 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
sw_id: dummySubSw[0]?.id || randomId(),
|
||||
purchase_corp: getRandomCorp(),
|
||||
current_dept: '경영지원팀',
|
||||
user_current: \`홍길동\${i}\`,
|
||||
memo: \`SW신청서_2400\${i}\`
|
||||
}));
|
||||
|
||||
export const dummyLogs: any[] = Array.from({ length: 10 }).map((_, i) => ({
|
||||
id: randomId(),
|
||||
assetId: dummyPCs[0]?.id || randomId(),
|
||||
date: randomDateStr(1),
|
||||
details: i % 2 === 0 ? '메모리 추가 증설 (16GB -> 32GB)' : '디스플레이 파손 수리',
|
||||
user: 'IT지원팀',
|
||||
cost: i % 2 === 0 ? 80000 : 150000,
|
||||
}));
|
||||
`;
|
||||
|
||||
fs.writeFileSync(dummyDataPath, newDummyDataFileContent, 'utf-8');
|
||||
console.log('✅ dummyData.ts file updated successfully with SVR dataset.');
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to update dummy data:', e);
|
||||
}
|
||||
Reference in New Issue
Block a user