244 lines
7.7 KiB
JavaScript
244 lines
7.7 KiB
JavaScript
import express from 'express';
|
|
import cors from 'cors';
|
|
import mysql from 'mysql2/promise';
|
|
import dotenv from 'dotenv';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
dotenv.config();
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const app = express();
|
|
app.use(cors());
|
|
app.use(express.json({ limit: '50mb' }));
|
|
|
|
// MySQL Connection Pool
|
|
const pool = mysql.createPool({
|
|
host: process.env.DB_HOST || 'localhost',
|
|
user: process.env.DB_USER || 'itam_user',
|
|
password: process.env.DB_PASSWORD || 'itam_pw',
|
|
database: process.env.DB_NAME || 'itam_db',
|
|
waitForConnections: true,
|
|
connectionLimit: 10,
|
|
queueLimit: 0
|
|
});
|
|
|
|
// Helper for DB updates
|
|
async function ensureTables() {
|
|
try {
|
|
// Cloud_Assets Table
|
|
await pool.query(`
|
|
CREATE TABLE IF NOT EXISTS cloud_assets (
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
platform_name VARCHAR(100),
|
|
corp VARCHAR(50),
|
|
dept VARCHAR(100),
|
|
purpose VARCHAR(255),
|
|
account_name VARCHAR(100),
|
|
payment_method VARCHAR(50),
|
|
payment_date VARCHAR(50),
|
|
card_number VARCHAR(50),
|
|
monthly_fee VARCHAR(50),
|
|
note TEXT
|
|
)
|
|
`);
|
|
|
|
// Logs Table
|
|
await pool.query(`
|
|
CREATE TABLE IF NOT EXISTS asset_logs (
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
asset_id VARCHAR(50),
|
|
date VARCHAR(20),
|
|
details TEXT,
|
|
user VARCHAR(50),
|
|
INDEX(asset_id)
|
|
)
|
|
`);
|
|
console.log('✅ Cloud & Logs tables ensured.');
|
|
} catch (err) {
|
|
console.error('❌ Error ensuring tables:', err);
|
|
}
|
|
}
|
|
|
|
ensureTables();
|
|
|
|
// --- API Endpoints ---
|
|
|
|
// Get Master Data (Multi-tab)
|
|
app.get('/api/master-data', async (req, res) => {
|
|
try {
|
|
const [pc] = await pool.query('SELECT * FROM pc_assets');
|
|
const [server] = await pool.query('SELECT * FROM server_assets');
|
|
const [storage] = await pool.query('SELECT * FROM storage_assets');
|
|
const [equip] = await pool.query('SELECT * FROM equip_assets');
|
|
const [mobile] = await pool.query('SELECT * FROM mobile_assets');
|
|
const [subSw] = await pool.query('SELECT * FROM sw_sub_assets');
|
|
const [permSw] = await pool.query('SELECT * FROM sw_perm_assets');
|
|
const [cloud] = await pool.query('SELECT * FROM cloud_assets');
|
|
const [swUsers] = await pool.query('SELECT * FROM sw_users');
|
|
const [logs] = await pool.query('SELECT * FROM asset_logs ORDER BY date DESC');
|
|
|
|
res.json({
|
|
pc, server, storage, equip, mobile,
|
|
subSw, permSw, cloud,
|
|
swUsers,
|
|
logs
|
|
});
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Save Hardware Asset (PC, Server, Storage, etc.)
|
|
app.post('/api/hardware/save', async (req, res) => {
|
|
const asset = req.body;
|
|
const type = asset.type;
|
|
let table = '';
|
|
|
|
if (type === '개인PC' || type === 'PC') table = 'pc_assets';
|
|
else if (type === '서버') table = 'server_assets';
|
|
else if (type === '스토리지') table = 'storage_assets';
|
|
else if (type === '모바일' || type === '모바일기기') table = 'mobile_assets';
|
|
else table = 'equip_assets';
|
|
|
|
try {
|
|
// Check if exists
|
|
const [rows] = await pool.query(`SELECT id FROM ${table} WHERE id = ?`, [asset.id]);
|
|
|
|
const data = { ...asset };
|
|
delete data.id;
|
|
delete data.type;
|
|
|
|
if (rows.length > 0) {
|
|
await pool.query(`UPDATE ${table} SET ? WHERE id = ?`, [data, asset.id]);
|
|
} else {
|
|
await pool.query(`INSERT INTO ${table} SET ?`, [{ id: asset.id, ...data }]);
|
|
}
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Save Software Asset
|
|
app.post('/api/software/save', async (req, res) => {
|
|
const asset = req.body;
|
|
const table = asset.type === '구독SW' ? 'sw_sub_assets' : (asset.type === '영구SW' ? 'sw_perm_assets' : 'cloud_assets');
|
|
|
|
try {
|
|
const [rows] = await pool.query(`SELECT id FROM ${table} WHERE id = ?`, [asset.id]);
|
|
const data = { ...asset };
|
|
delete data.id;
|
|
delete data.type;
|
|
|
|
if (rows.length > 0) {
|
|
await pool.query(`UPDATE ${table} SET ? WHERE id = ?`, [data, asset.id]);
|
|
} else {
|
|
await pool.query(`INSERT INTO ${table} SET ?`, [{ id: asset.id, ...data }]);
|
|
}
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Delete Asset
|
|
app.delete('/api/asset/:type/:id', async (req, res) => {
|
|
const { type, id } = req.params;
|
|
let table = '';
|
|
|
|
if (type === '개인PC' || type === 'PC') table = 'pc_assets';
|
|
else if (type === '서버') table = 'server_assets';
|
|
else if (type === '스토리지') table = 'storage_assets';
|
|
else if (type === '모바일' || type === '모바일기기') table = 'mobile_assets';
|
|
else if (type === '전산비품' || type === '기타자산') table = 'equip_assets';
|
|
else if (type === '구독SW') table = 'sw_sub_assets';
|
|
else if (type === '영구SW') table = 'sw_perm_assets';
|
|
else if (type === '클라우드') table = 'cloud_assets';
|
|
|
|
try {
|
|
await pool.query(`DELETE FROM ${table} WHERE id = ?`, [id]);
|
|
// Also delete logs and users if needed
|
|
if (table.includes('sw')) await pool.query('DELETE FROM sw_users WHERE sw_id = ?', [id]);
|
|
await pool.query('DELETE FROM asset_logs WHERE asset_id = ?', [id]);
|
|
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
// Log Save
|
|
app.post('/api/logs/save', async (req, res) => {
|
|
const log = req.body;
|
|
try {
|
|
const [rows] = await pool.query('SELECT id FROM asset_logs WHERE id = ?', [log.id]);
|
|
if (rows.length > 0) {
|
|
await pool.query('UPDATE asset_logs SET ? WHERE id = ?', [log, log.id]);
|
|
} else {
|
|
await pool.query('INSERT INTO asset_logs SET ?', [log]);
|
|
}
|
|
res.json({ success: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// SW User Save
|
|
app.post('/api/sw-users/save', async (req, res) => {
|
|
const user = req.body;
|
|
try {
|
|
const [rows] = await pool.query('SELECT id FROM sw_users WHERE id = ?', [user.id]);
|
|
if (rows.length > 0) {
|
|
await pool.query('UPDATE sw_users SET ? WHERE id = ?', [user, user.id]);
|
|
} else {
|
|
await pool.query('INSERT INTO sw_users SET ?', [user]);
|
|
}
|
|
res.json({ success: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
app.post('/api/sw-users/batch', async (req, res) => {
|
|
const { swId, users } = req.body;
|
|
try {
|
|
await pool.query('DELETE FROM sw_users WHERE sw_id = ?', [swId]);
|
|
for (const u of users) {
|
|
await pool.query('INSERT INTO sw_users SET ?', { ...u, sw_id: swId });
|
|
}
|
|
res.json({ success: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// 자산번호 생성 API
|
|
app.get('/api/generate-asset-code', async (req, res) => {
|
|
const { prefix } = req.query;
|
|
if (!prefix) return res.status(400).json({ error: 'Prefix is required' });
|
|
|
|
try {
|
|
const tables = [
|
|
'pc_assets', 'server_assets', 'storage_assets', 'equip_assets', 'mobile_assets',
|
|
'sw_sub_assets', 'sw_perm_assets'
|
|
];
|
|
let maxNum = 0;
|
|
|
|
for (const table of tables) {
|
|
const [rows] = await pool.query(`SELECT asset_code FROM ${table} WHERE asset_code LIKE ?`, [`${prefix}%`]);
|
|
rows.forEach(r => {
|
|
const numPart = r.asset_code.replace(prefix, '');
|
|
const num = parseInt(numPart);
|
|
if (!isNaN(num) && num > maxNum) maxNum = num;
|
|
});
|
|
}
|
|
|
|
const nextCode = `${prefix}${(maxNum + 1).toString().padStart(3, '0')}`;
|
|
res.json({ nextCode });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
app.listen(PORT, () => {
|
|
console.log(`🚀 ITAM Dedicated API Server running on http://localhost:${PORT}`);
|
|
});
|