2025-12-20 09:37:43 +08:00
|
|
|
require('dotenv').config();
|
2026-03-20 17:15:14 +08:00
|
|
|
const path = require('path');
|
2026-03-13 15:13:58 +08:00
|
|
|
const { ensureJwtSecret } = require('./initConfig');
|
|
|
|
|
ensureJwtSecret();
|
|
|
|
|
|
2025-12-18 10:45:13 +08:00
|
|
|
const express = require('express');
|
|
|
|
|
const cors = require('cors');
|
2025-12-18 19:11:56 +08:00
|
|
|
const fileUpload = require('express-fileupload');
|
2025-12-18 10:45:13 +08:00
|
|
|
const { sequelize } = require('./db');
|
2026-03-06 14:39:52 +08:00
|
|
|
const { FILE_UPLOAD } = require('./config');
|
2025-12-18 10:45:13 +08:00
|
|
|
|
|
|
|
|
const app = express();
|
2025-12-20 08:20:51 +08:00
|
|
|
const PORT = process.env.PORT || 8000;
|
2025-12-18 10:45:13 +08:00
|
|
|
|
|
|
|
|
app.use(cors());
|
|
|
|
|
app.use(express.json());
|
2026-03-06 14:39:52 +08:00
|
|
|
app.use(fileUpload({ limits: { fileSize: FILE_UPLOAD.MAX_FILE_SIZE } }));
|
2025-12-18 19:11:56 +08:00
|
|
|
app.use('/temp', express.static('temp'));
|
2025-12-18 10:45:13 +08:00
|
|
|
|
2026-03-10 14:34:39 +08:00
|
|
|
async function syncDatabase() {
|
|
|
|
|
await sequelize.authenticate();
|
|
|
|
|
console.log('数据库连接成功');
|
2025-12-18 10:45:13 +08:00
|
|
|
|
2026-03-10 14:34:39 +08:00
|
|
|
await sequelize.sync({
|
|
|
|
|
force: false,
|
2026-03-27 19:12:16 +08:00
|
|
|
alter: false,
|
2026-03-10 14:34:39 +08:00
|
|
|
});
|
|
|
|
|
console.log('数据库表结构同步完成');
|
|
|
|
|
}
|
2026-02-11 10:21:32 +08:00
|
|
|
|
2026-03-10 14:34:39 +08:00
|
|
|
async function initDeviceFields() {
|
|
|
|
|
await require('./initDeviceFields')();
|
|
|
|
|
console.log('设备字段初始化完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function initTicketFields() {
|
|
|
|
|
await require('./initTicketFields')();
|
|
|
|
|
console.log('工单字段初始化完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function initTicketModels() {
|
|
|
|
|
await require('./models/ticketIndex').initializeModels();
|
|
|
|
|
console.log('工单模型关联初始化完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function syncSystemSettings() {
|
|
|
|
|
const SystemSetting = require('./models/SystemSetting');
|
|
|
|
|
await SystemSetting.sync();
|
|
|
|
|
console.log('系统设置模型同步完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function syncConsumableModels() {
|
|
|
|
|
const Consumable = require('./models/Consumable');
|
|
|
|
|
const ConsumableLog = require('./models/ConsumableLog');
|
|
|
|
|
const ConsumableCategory = require('./models/ConsumableCategory');
|
|
|
|
|
const ConsumableRecord = require('./models/ConsumableRecord');
|
|
|
|
|
const ConsumableLogArchive = require('./models/ConsumableLogArchive');
|
|
|
|
|
|
|
|
|
|
await Promise.all([
|
2026-03-13 22:11:34 +08:00
|
|
|
Consumable.sync(), // 暂时禁用 alter 模式
|
2026-03-10 14:34:39 +08:00
|
|
|
ConsumableLog.sync(),
|
|
|
|
|
ConsumableCategory.sync(),
|
|
|
|
|
ConsumableRecord.sync(),
|
2026-03-27 19:12:16 +08:00
|
|
|
ConsumableLogArchive.sync(),
|
2026-03-10 14:34:39 +08:00
|
|
|
]);
|
|
|
|
|
console.log('耗材模型同步完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function syncInventoryModels() {
|
|
|
|
|
const InventoryPlan = require('./models/InventoryPlan');
|
|
|
|
|
const InventoryTask = require('./models/InventoryTask');
|
|
|
|
|
const InventoryRecord = require('./models/InventoryRecord');
|
|
|
|
|
|
2026-03-27 19:12:16 +08:00
|
|
|
await Promise.all([InventoryPlan.sync(), InventoryTask.sync(), InventoryRecord.sync()]);
|
2026-03-10 14:34:39 +08:00
|
|
|
console.log('盘点模型同步完成');
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 17:07:20 +08:00
|
|
|
async function syncBackupLogModel() {
|
|
|
|
|
const BackupLog = require('./models/BackupLog');
|
|
|
|
|
await BackupLog.sync();
|
|
|
|
|
console.log('备份日志模型同步完成');
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:15:14 +08:00
|
|
|
async function syncOperationLogModel() {
|
|
|
|
|
const OperationLog = require('./models/OperationLog');
|
|
|
|
|
await OperationLog.sync();
|
|
|
|
|
console.log('操作日志模型同步完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function syncBusinessModels() {
|
|
|
|
|
const Business = require('./models/Business');
|
|
|
|
|
const DeviceBusiness = require('./models/DeviceBusiness');
|
|
|
|
|
const Warehouse = require('./models/Warehouse');
|
|
|
|
|
|
|
|
|
|
await Business.sync({ alter: true });
|
|
|
|
|
await DeviceBusiness.sync({ alter: true });
|
|
|
|
|
await Warehouse.sync({ alter: true });
|
|
|
|
|
console.log('业务/设备关联/库房模型同步完成');
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 14:34:39 +08:00
|
|
|
async function initDefaultSystemSettings() {
|
|
|
|
|
console.log('开始初始化系统设置默认值...');
|
|
|
|
|
const { initDefaultSettings } = require('./routes/systemSettings');
|
|
|
|
|
await initDefaultSettings();
|
|
|
|
|
console.log('系统设置初始化完成');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function initFaultCategories() {
|
|
|
|
|
console.log('开始初始化故障分类...');
|
|
|
|
|
const FaultCategory = require('./models/FaultCategory');
|
|
|
|
|
|
|
|
|
|
const defaultCategories = [
|
2026-03-27 19:12:16 +08:00
|
|
|
{
|
|
|
|
|
name: '系统故障',
|
|
|
|
|
description: '操作系统、应用程序等系统软件的故障问题',
|
|
|
|
|
priority: 1,
|
|
|
|
|
defaultPriority: 'high',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '硬件故障',
|
|
|
|
|
description: '物理设备、服务器、存储等硬件设备的故障问题',
|
|
|
|
|
priority: 2,
|
|
|
|
|
defaultPriority: 'high',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '网络故障',
|
|
|
|
|
description: '网络连接、交换机、路由器等网络相关故障',
|
|
|
|
|
priority: 3,
|
|
|
|
|
defaultPriority: 'high',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '软件故障',
|
|
|
|
|
description: '应用程序错误、软件兼容性等问题',
|
|
|
|
|
priority: 4,
|
|
|
|
|
defaultPriority: 'medium',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '安全事件',
|
|
|
|
|
description: '安全漏洞、入侵检测、权限异常等安全问题',
|
|
|
|
|
priority: 5,
|
|
|
|
|
defaultPriority: 'urgent',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '性能问题',
|
|
|
|
|
description: '系统响应慢、资源利用率高等性能问题',
|
|
|
|
|
priority: 6,
|
|
|
|
|
defaultPriority: 'medium',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '配置变更',
|
|
|
|
|
description: '系统配置、软件配置等变更需求',
|
|
|
|
|
priority: 7,
|
|
|
|
|
defaultPriority: 'low',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '例行维护',
|
|
|
|
|
description: '定期维护、巡检、更新等计划性工作',
|
|
|
|
|
priority: 8,
|
|
|
|
|
defaultPriority: 'low',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '数据问题',
|
|
|
|
|
description: '数据错误、数据丢失、数据同步等数据相关问题',
|
|
|
|
|
priority: 9,
|
|
|
|
|
defaultPriority: 'high',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '其他问题',
|
|
|
|
|
description: '无法归类的其他问题',
|
|
|
|
|
priority: 99,
|
|
|
|
|
defaultPriority: 'medium',
|
|
|
|
|
},
|
2026-03-10 14:34:39 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const cat of defaultCategories) {
|
|
|
|
|
const existing = await FaultCategory.findOne({ where: { name: cat.name } });
|
|
|
|
|
if (!existing) {
|
|
|
|
|
const categoryId = `CAT${Date.now().toString(36).toUpperCase()}${Math.random().toString(36).substr(2, 4).toUpperCase()}`;
|
|
|
|
|
await FaultCategory.create({
|
|
|
|
|
categoryId,
|
|
|
|
|
...cat,
|
|
|
|
|
expectedDuration: 120,
|
|
|
|
|
solutions: [],
|
|
|
|
|
isSystem: true,
|
2026-03-27 19:12:16 +08:00
|
|
|
isActive: true,
|
2026-03-10 14:34:39 +08:00
|
|
|
});
|
|
|
|
|
console.log(`创建故障分类: ${cat.name}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
console.log('故障分类初始化完成');
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-13 15:13:58 +08:00
|
|
|
async function initAutoBackupScheduler() {
|
|
|
|
|
const { initAutoBackup } = require('./utils/autoBackupScheduler');
|
|
|
|
|
const status = initAutoBackup();
|
|
|
|
|
if (status.enabled) {
|
|
|
|
|
console.log(`自动备份已启用,下次执行时间:${status.nextRun || '未知'}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 14:34:39 +08:00
|
|
|
async function initializeApp() {
|
|
|
|
|
try {
|
|
|
|
|
await syncDatabase();
|
|
|
|
|
await initDeviceFields();
|
|
|
|
|
await initTicketFields();
|
|
|
|
|
await initTicketModels();
|
|
|
|
|
await syncSystemSettings();
|
|
|
|
|
await syncConsumableModels();
|
|
|
|
|
await syncInventoryModels();
|
2026-03-16 17:07:20 +08:00
|
|
|
await syncBackupLogModel();
|
2026-03-20 17:15:14 +08:00
|
|
|
await syncOperationLogModel();
|
|
|
|
|
await syncBusinessModels();
|
2026-03-10 14:34:39 +08:00
|
|
|
await initDefaultSystemSettings();
|
|
|
|
|
await initFaultCategories();
|
2026-03-13 15:13:58 +08:00
|
|
|
await initAutoBackupScheduler();
|
2026-03-10 14:34:39 +08:00
|
|
|
|
|
|
|
|
console.log('所有初始化完成,服务器准备就绪');
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('初始化失败:', error);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:15:14 +08:00
|
|
|
const swaggerUi = require('swagger-ui-express');
|
|
|
|
|
const { specs, customCSS } = require('./swagger');
|
|
|
|
|
|
2026-03-10 14:34:39 +08:00
|
|
|
initializeApp();
|
2025-12-18 10:45:13 +08:00
|
|
|
|
|
|
|
|
const deviceRoutes = require('./routes/devices');
|
|
|
|
|
const rackRoutes = require('./routes/racks');
|
|
|
|
|
const roomRoutes = require('./routes/rooms');
|
|
|
|
|
const deviceFieldRoutes = require('./routes/deviceFields');
|
2025-12-20 17:43:50 +08:00
|
|
|
const backgroundRoutes = require('./routes/background');
|
2025-12-24 16:44:27 +08:00
|
|
|
const consumableRoutes = require('./routes/consumables');
|
|
|
|
|
const consumableRecordRoutes = require('./routes/consumableRecords');
|
|
|
|
|
const consumableCategoryRoutes = require('./routes/consumableCategories');
|
2025-12-25 10:48:35 +08:00
|
|
|
const authRoutes = require('./routes/auth');
|
|
|
|
|
const usersRoutes = require('./routes/users');
|
|
|
|
|
const rolesRoutes = require('./routes/roles');
|
2025-12-25 16:49:00 +08:00
|
|
|
const ticketRoutes = require('./routes/tickets');
|
|
|
|
|
const ticketCategoryRoutes = require('./routes/ticketCategories');
|
2025-12-29 08:40:08 +08:00
|
|
|
const ticketFieldRoutes = require('./routes/ticketFields');
|
2025-12-29 16:10:42 +08:00
|
|
|
const systemSettingsRoutes = require('./routes/systemSettings');
|
2026-01-23 08:55:16 +08:00
|
|
|
const cableRoutes = require('./routes/cables');
|
|
|
|
|
const devicePortRoutes = require('./routes/devicePorts');
|
2026-01-26 17:21:20 +08:00
|
|
|
const networkCardRoutes = require('./routes/networkCards');
|
2026-02-26 11:24:00 +08:00
|
|
|
const inventoryRoutes = require('./routes/inventory');
|
2026-03-13 15:13:58 +08:00
|
|
|
const backupRoutes = require('./routes/backup');
|
2026-03-15 12:19:13 +08:00
|
|
|
const statisticsRoutes = require('./routes/statistics');
|
2026-03-20 17:15:14 +08:00
|
|
|
const operationLogsRoutes = require('./routes/operationLogs');
|
|
|
|
|
const idleDeviceRoutes = require('./routes/idleDevices');
|
|
|
|
|
const warehouseRoutes = require('./routes/warehouses');
|
|
|
|
|
const dangerousOperationsRoutes = require('./routes/dangerousOperations');
|
2025-12-18 10:45:13 +08:00
|
|
|
|
|
|
|
|
app.use('/api/devices', deviceRoutes);
|
|
|
|
|
app.use('/api/racks', rackRoutes);
|
|
|
|
|
app.use('/api/rooms', roomRoutes);
|
|
|
|
|
app.use('/api/deviceFields', deviceFieldRoutes);
|
2025-12-20 17:43:50 +08:00
|
|
|
app.use('/api/background', backgroundRoutes);
|
2025-12-24 16:44:27 +08:00
|
|
|
app.use('/api/consumables', consumableRoutes);
|
|
|
|
|
app.use('/api/consumable-records', consumableRecordRoutes);
|
|
|
|
|
app.use('/api/consumable-categories', consumableCategoryRoutes);
|
2025-12-25 10:48:35 +08:00
|
|
|
app.use('/api/auth', authRoutes);
|
|
|
|
|
app.use('/api/users', usersRoutes);
|
|
|
|
|
app.use('/api/roles', rolesRoutes);
|
2025-12-25 16:49:00 +08:00
|
|
|
app.use('/api/tickets', ticketRoutes);
|
|
|
|
|
app.use('/api/ticket-categories', ticketCategoryRoutes);
|
2025-12-29 08:40:08 +08:00
|
|
|
app.use('/api/ticket-fields', ticketFieldRoutes);
|
2025-12-29 16:10:42 +08:00
|
|
|
app.use('/api/system-settings', systemSettingsRoutes);
|
2026-01-23 08:55:16 +08:00
|
|
|
app.use('/api/cables', cableRoutes);
|
|
|
|
|
app.use('/api/device-ports', devicePortRoutes);
|
2026-01-26 17:21:20 +08:00
|
|
|
app.use('/api/network-cards', networkCardRoutes);
|
2026-02-26 11:24:00 +08:00
|
|
|
app.use('/api/inventory', inventoryRoutes);
|
2026-03-13 15:13:58 +08:00
|
|
|
app.use('/api/backup', backupRoutes);
|
2026-03-15 12:19:13 +08:00
|
|
|
app.use('/api/statistics', statisticsRoutes);
|
2026-03-20 17:15:14 +08:00
|
|
|
app.use('/api/operation-logs', operationLogsRoutes);
|
|
|
|
|
app.use('/api/idle-devices', idleDeviceRoutes);
|
|
|
|
|
app.use('/api/warehouses', warehouseRoutes);
|
|
|
|
|
app.use('/api/dangerous-operations', dangerousOperationsRoutes);
|
2025-12-20 17:43:50 +08:00
|
|
|
|
|
|
|
|
app.use('/uploads', express.static('uploads'));
|
2025-12-18 10:45:13 +08:00
|
|
|
|
2026-03-27 19:12:16 +08:00
|
|
|
app.use(
|
|
|
|
|
'/api-docs',
|
|
|
|
|
swaggerUi.serve,
|
|
|
|
|
swaggerUi.setup(specs, {
|
|
|
|
|
customCss: customCSS,
|
|
|
|
|
customSiteTitle: 'IDC设备管理系统 API文档',
|
|
|
|
|
swaggerOptions: {
|
|
|
|
|
persistAuthorization: true,
|
|
|
|
|
displayRequestDuration: true,
|
|
|
|
|
docExpansion: 'none',
|
|
|
|
|
deepLinking: true,
|
|
|
|
|
defaultModelsExpandDepth: -1,
|
|
|
|
|
defaultModelExpandDepth: 2,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
2026-03-20 17:15:14 +08:00
|
|
|
|
|
|
|
|
app.get('/api-docs', (req, res) => {
|
|
|
|
|
res.sendFile(path.join(__dirname, 'swagger_index.html'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.get('/api-docs.json', (req, res) => {
|
|
|
|
|
res.json(specs);
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-12 11:19:56 +08:00
|
|
|
app.get('/api', (req, res) => {
|
|
|
|
|
res.json({
|
|
|
|
|
name: 'IDC设备管理系统 API',
|
|
|
|
|
version: '1.0.0',
|
|
|
|
|
description: '数据中心设备管理平台后端服务',
|
|
|
|
|
endpoints: {
|
|
|
|
|
auth: '/api/auth',
|
|
|
|
|
rooms: '/api/rooms',
|
|
|
|
|
racks: '/api/racks',
|
|
|
|
|
devices: '/api/devices',
|
|
|
|
|
deviceFields: '/api/deviceFields',
|
|
|
|
|
devicePorts: '/api/device-ports',
|
|
|
|
|
networkCards: '/api/network-cards',
|
|
|
|
|
cables: '/api/cables',
|
|
|
|
|
tickets: '/api/tickets',
|
|
|
|
|
ticketCategories: '/api/ticket-categories',
|
|
|
|
|
ticketFields: '/api/ticket-fields',
|
|
|
|
|
consumables: '/api/consumables',
|
|
|
|
|
consumableRecords: '/api/consumable-records',
|
|
|
|
|
consumableCategories: '/api/consumable-categories',
|
|
|
|
|
users: '/api/users',
|
|
|
|
|
roles: '/api/roles',
|
|
|
|
|
systemSettings: '/api/system-settings',
|
|
|
|
|
background: '/api/background',
|
2026-03-27 19:12:16 +08:00
|
|
|
inventory: '/api/inventory',
|
2026-03-12 11:19:56 +08:00
|
|
|
},
|
|
|
|
|
health: '/health',
|
2026-03-27 19:12:16 +08:00
|
|
|
documentation: '/docs/api/README.md',
|
2026-03-12 11:19:56 +08:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-20 17:15:14 +08:00
|
|
|
const { performHealthCheck } = require('./utils/healthCheck');
|
|
|
|
|
|
|
|
|
|
app.get('/health', async (req, res) => {
|
|
|
|
|
const health = await performHealthCheck();
|
|
|
|
|
const statusCode = health.status === 'error' ? 503 : health.status === 'warning' ? 200 : 200;
|
|
|
|
|
res.status(statusCode).json(health);
|
2025-12-18 10:45:13 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.listen(PORT, () => {
|
|
|
|
|
console.log(`服务器运行在 http://localhost:${PORT}`);
|
2026-03-10 14:34:39 +08:00
|
|
|
});
|