2026-01-23 08:55:16 +08:00
|
|
|
const { sequelize } = require('../db');
|
|
|
|
|
const NetworkCard = require('../models/NetworkCard');
|
|
|
|
|
const DevicePort = require('../models/DevicePort');
|
|
|
|
|
const Device = require('../models/Device');
|
|
|
|
|
|
|
|
|
|
async function migrate() {
|
|
|
|
|
console.log('========================================');
|
|
|
|
|
console.log(' IDC管理系统 - 数据库迁移脚本 v2.0 ');
|
|
|
|
|
console.log('========================================');
|
|
|
|
|
console.log('');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
try {
|
|
|
|
|
console.log('🔍 检测数据库类型...');
|
|
|
|
|
const dbType = sequelize.getDialect();
|
|
|
|
|
console.log(` 数据库类型: ${dbType}`);
|
|
|
|
|
console.log('');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log('📋 开始迁移...');
|
|
|
|
|
console.log(' 1. 创建 network_cards 表');
|
|
|
|
|
console.log(' 2. 为 device_ports 添加 nic_id 字段');
|
|
|
|
|
console.log(' 3. 创建相关索引');
|
|
|
|
|
console.log('');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
if (dbType === 'sqlite') {
|
|
|
|
|
await migrateSQLite();
|
|
|
|
|
} else if (dbType === 'mysql') {
|
|
|
|
|
await migrateMySQL();
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`⚠️ 不支持的数据库类型: ${dbType}`);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log('');
|
|
|
|
|
console.log('✅ 迁移完成!');
|
|
|
|
|
console.log('');
|
|
|
|
|
console.log('📊 验证迁移结果...');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
|
|
|
|
const [tables] = await sequelize.query(
|
|
|
|
|
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
|
|
|
|
);
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(` 数据库表: ${tables.map(t => t.name).join(', ')}`);
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
const portCount = await DevicePort.count();
|
|
|
|
|
const cardCount = await NetworkCard.count();
|
|
|
|
|
console.log(` device_ports: ${portCount} 条记录`);
|
|
|
|
|
console.log(` network_cards: ${cardCount} 条记录`);
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log('');
|
|
|
|
|
console.log('========================================');
|
|
|
|
|
console.log(' 迁移成功完成!🎉');
|
|
|
|
|
console.log('========================================');
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('');
|
|
|
|
|
console.error('❌ 迁移失败:', error.message);
|
|
|
|
|
console.error('');
|
|
|
|
|
console.error('错误详情:', error.stack);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
} finally {
|
|
|
|
|
await sequelize.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function migrateSQLite() {
|
|
|
|
|
console.log('');
|
|
|
|
|
console.log('🔄 执行 SQLite 迁移...');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
await sequelize.query('PRAGMA foreign_keys = OFF');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
try {
|
|
|
|
|
console.log(' → 删除旧的 device_ports 表...');
|
|
|
|
|
await sequelize.query('DROP TABLE IF EXISTS `device_ports`');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 删除旧的 network_cards 表...');
|
|
|
|
|
await sequelize.query('DROP TABLE IF EXISTS `network_cards`');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 同步 DevicePort 模型...');
|
|
|
|
|
await DevicePort.sync({ force: false });
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 同步 NetworkCard 模型...');
|
|
|
|
|
await NetworkCard.sync({ force: false });
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 同步 Device 模型(确保外键关系)...');
|
|
|
|
|
await Device.sync({ force: false });
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 重新同步 DevicePort 模型(含外键)...');
|
|
|
|
|
await DevicePort.sync({ force: true });
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 重新同步 NetworkCard 模型...');
|
|
|
|
|
await NetworkCard.sync({ force: false });
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
await sequelize.query('PRAGMA foreign_keys = ON');
|
|
|
|
|
} catch (error) {
|
|
|
|
|
await sequelize.query('PRAGMA foreign_keys = ON');
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function migrateMySQL() {
|
|
|
|
|
console.log('');
|
|
|
|
|
console.log('🔄 执行 MySQL 迁移...');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
const tableName = 'network_cards';
|
|
|
|
|
console.log(` → 创建表: ${tableName}`);
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
const createTableSQL = `
|
|
|
|
|
CREATE TABLE IF NOT EXISTS \`${tableName}\` (
|
|
|
|
|
\`nic_id\` VARCHAR(255) NOT NULL PRIMARY KEY,
|
|
|
|
|
\`device_id\` VARCHAR(255) NOT NULL,
|
|
|
|
|
\`name\` VARCHAR(255) NOT NULL,
|
|
|
|
|
\`description\` TEXT,
|
|
|
|
|
\`slot_number\` INT,
|
|
|
|
|
\`port_count\` INT DEFAULT 0,
|
|
|
|
|
\`model\` VARCHAR(255),
|
|
|
|
|
\`manufacturer\` VARCHAR(255),
|
|
|
|
|
\`status\` ENUM('normal', 'warning', 'fault', 'offline') DEFAULT 'normal',
|
|
|
|
|
\`created_at\` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
\`updated_at\` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
INDEX \`idx_device_id\` (\`device_id\`),
|
|
|
|
|
INDEX \`idx_slot_number\` (\`slot_number\`),
|
|
|
|
|
UNIQUE INDEX \`idx_device_name\` (\`device_id\`, \`name\`)
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
|
`;
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
await sequelize.query(createTableSQL);
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 检查 nic_id 字段是否存在...');
|
2026-03-27 19:12:16 +08:00
|
|
|
const [columns] = await sequelize.query("SHOW COLUMNS FROM `device_ports` LIKE 'nic_id'", {
|
|
|
|
|
type: sequelize.QueryTypes.SELECT,
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
if (columns.length === 0) {
|
|
|
|
|
console.log(' → 添加 nic_id 字段...');
|
|
|
|
|
await sequelize.query(
|
|
|
|
|
'ALTER TABLE `device_ports` ADD COLUMN `nic_id` VARCHAR(255) NULL AFTER `device_id`'
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(' → nic_id 字段已存在,跳过');
|
|
|
|
|
}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 创建 nic_id 索引...');
|
|
|
|
|
try {
|
|
|
|
|
await sequelize.query('CREATE INDEX `idx_port_nic_id` ON `device_ports`(`nic_id`)');
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error.message.includes('Duplicate key name')) {
|
|
|
|
|
console.log(' → 索引已存在,跳过');
|
|
|
|
|
} else {
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 同步模型以确保关系正确...');
|
|
|
|
|
await NetworkCard.sync({ force: false });
|
|
|
|
|
await DevicePort.sync({ force: false });
|
2026-03-27 19:12:16 +08:00
|
|
|
|
2026-01-23 08:55:16 +08:00
|
|
|
console.log(' → 添加外键约束...');
|
|
|
|
|
try {
|
|
|
|
|
await sequelize.query(
|
|
|
|
|
'ALTER TABLE `device_ports` ADD CONSTRAINT `fk_port_nic` FOREIGN KEY (`nic_id`) REFERENCES `network_cards`(`nic_id`)'
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error.message.includes('Duplicate key name') || error.message.includes('already exists')) {
|
|
|
|
|
console.log(' → 外键约束已存在,跳过');
|
|
|
|
|
} else {
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
migrate();
|