fix(remote-backup): 移除调试日志并改进协议类型验证

refactor(migrations): 添加设备字段options配置迁移
This commit is contained in:
zhang1106
2026-03-23 11:09:36 +08:00
parent 66807b1660
commit f51c39284b
3 changed files with 81 additions and 36 deletions
+4 -13
View File
@@ -802,7 +802,6 @@ router.delete('/remote/targets/:id', (req, res) => {
router.post('/remote/test', async (req, res) => {
try {
const config = req.body;
console.log(`[RemoteBackup] 收到连接测试请求:`, JSON.stringify(config));
if (!config.host || !config.port || !config.username) {
return res.status(400).json({
@@ -812,21 +811,13 @@ router.post('/remote/test', async (req, res) => {
}
if (!config.protocol) {
const port = parseInt(config.port);
if (port === 22 || port === 2222) {
config.protocol = 'sftp';
} else if (port === 445 || port === 139 || port === 443) {
config.protocol = 'smb';
} else if (port === 80 || port === 443 || config.url) {
config.protocol = 'webdav';
} else {
config.protocol = 'ftp';
}
console.log(`[RemoteBackup] 推断协议类型: ${config.protocol} (基于端口 ${config.port})`);
return res.status(400).json({
success: false,
message: '请提供协议类型(protocol',
});
}
const result = await testRemoteConnection(config);
console.log(`[RemoteBackup] 连接测试结果:`, JSON.stringify(result));
if (result.success) {
res.json({
+77 -22
View File
@@ -94,6 +94,11 @@ const migrations = [
name: '设备字段系统标记',
description: '为 deviceFields 表添加 isSystem 字段,标记系统字段不可删除',
migrate: migrateDeviceFieldsIsSystem
},
{
name: '设备字段Options配置',
description: '确保 deviceFields 表的 type 和 status 字段有正确的 options 配置',
migrate: migrateDeviceFieldsOptions
}
];
@@ -149,7 +154,7 @@ async function runMigrations() {
async function getTableColumns(tableName) {
const dialect = sequelize.getDialect();
if (dialect === 'sqlite') {
const tableInfo = await sequelize.query(
`PRAGMA table_info(${tableName})`,
@@ -167,7 +172,7 @@ async function getTableColumns(tableName) {
async function tableExists(tableName) {
const dialect = sequelize.getDialect();
if (dialect === 'sqlite') {
const tables = await sequelize.query(
"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
@@ -185,10 +190,10 @@ async function tableExists(tableName) {
async function addColumnIfNotExists(tableName, columnName, columnDef) {
const columns = await getTableColumns(tableName);
if (!columns.includes(columnName)) {
const dialect = sequelize.getDialect();
const sql = dialect === 'sqlite'
const sql = dialect === 'sqlite'
? `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnDef}`
: `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnDef}`;
await sequelize.query(sql);
@@ -276,7 +281,7 @@ async function migrateConsumableLogDecouple() {
async function removeConsumableLogFK() {
const dialect = sequelize.getDialect();
if (dialect === 'sqlite') {
const fks = await sequelize.query(
`PRAGMA foreign_key_list(consumable_logs);`,
@@ -411,7 +416,7 @@ async function migrateConsumableLogArchive() {
async function migrateSnList() {
const tables = ['consumables', 'consumable_records', 'consumable_logs'];
for (const table of tables) {
if (await tableExists(table)) {
const columnDef = dbDialect === 'sqlite' ? "TEXT DEFAULT '[]'" : "JSON";
@@ -429,7 +434,7 @@ async function migrateDeviceModelField() {
}
const dialect = sequelize.getDialect();
if (dialect === 'mysql') {
await sequelize.query(
'ALTER TABLE devices MODIFY COLUMN model VARCHAR(255) NULL'
@@ -441,7 +446,7 @@ async function migrateDeviceModelField() {
console.log(' model_old 字段已存在,跳过迁移');
return;
}
await sequelize.query('ALTER TABLE devices RENAME COLUMN model TO model_old');
await sequelize.query('ALTER TABLE devices ADD COLUMN model VARCHAR(255)');
await sequelize.query('UPDATE devices SET model = model_old');
@@ -452,14 +457,14 @@ async function migrateDeviceModelField() {
async function migrateDeviceFieldsConfig() {
const DeviceField = require('../models/DeviceField');
const updates = [
{ fieldName: 'model', required: false },
{ fieldName: 'powerConsumption', required: true },
{ fieldName: 'purchaseDate', required: false },
{ fieldName: 'warrantyExpiry', required: false },
];
for (const update of updates) {
const field = await DeviceField.findOne({ where: { fieldName: update.fieldName } });
if (field && field.required !== update.required) {
@@ -475,7 +480,7 @@ async function migrateDeviceFieldsConfig() {
async function migrateDeviceFieldsNullable() {
const dialect = sequelize.getDialect();
if (dialect === 'mysql') {
const alterCommands = [
"ALTER TABLE devices MODIFY COLUMN name VARCHAR(255) NULL",
@@ -488,7 +493,7 @@ async function migrateDeviceFieldsNullable() {
"ALTER TABLE devices MODIFY COLUMN powerConsumption FLOAT NULL",
"ALTER TABLE devices MODIFY COLUMN customFields JSON NULL"
];
for (const sql of alterCommands) {
try {
await sequelize.query(sql);
@@ -499,21 +504,21 @@ async function migrateDeviceFieldsNullable() {
}
}
console.log(' devices 表字段已改为可空');
} else if (dialect === 'sqlite') {
const columns = await getTableColumns('devices');
const hasNullableFlag = columns.includes('_nullable_migration_done');
if (hasNullableFlag) {
console.log(' 已完成可空迁移,跳过');
return;
}
await sequelize.query('PRAGMA foreign_keys = OFF');
try {
await sequelize.query('DROP TABLE IF EXISTS devices_new');
await sequelize.query(`
CREATE TABLE devices_new (
deviceId VARCHAR(255) PRIMARY KEY NOT NULL UNIQUE,
@@ -536,28 +541,28 @@ async function migrateDeviceFieldsNullable() {
_nullable_migration_done INTEGER DEFAULT 1
)
`);
await sequelize.query(`
INSERT INTO devices_new (
deviceId, name, type, model, serialNumber, rackId, position, height,
powerConsumption, status, purchaseDate, warrantyExpiry, ipAddress,
description, customFields, createdAt, updatedAt
)
SELECT
SELECT
deviceId, name, type, model, serialNumber, rackId, position, height,
powerConsumption, status, purchaseDate, warrantyExpiry, ipAddress,
description, customFields, createdAt, updatedAt
FROM devices
`);
await sequelize.query('DROP TABLE devices');
await sequelize.query('ALTER TABLE devices_new RENAME TO devices');
await sequelize.query('CREATE INDEX IF NOT EXISTS idx_devices_status ON devices(status)');
await sequelize.query('CREATE INDEX IF NOT EXISTS idx_devices_type ON devices(type)');
await sequelize.query('CREATE INDEX IF NOT EXISTS idx_devices_rackId ON devices(rackId)');
await sequelize.query('CREATE INDEX IF NOT EXISTS idx_devices_name ON devices(name)');
console.log(' devices 表字段已改为可空');
} finally {
await sequelize.query('PRAGMA foreign_keys = ON');
@@ -632,6 +637,56 @@ async function migrateDeviceFieldsIsSystem() {
console.log(' 设备字段系统标记迁移完成');
}
async function migrateDeviceFieldsOptions() {
const DeviceField = require('../models/DeviceField');
if (!(await tableExists('deviceFields'))) {
console.log(' deviceFields 表不存在,跳过');
return;
}
const deviceTypeOptions = [
{ value: 'server', label: '服务器' },
{ value: 'switch', label: '交换机' },
{ value: 'router', label: '路由器' },
{ value: 'storage', label: '存储设备' },
{ value: 'other', label: '其他设备' }
];
const statusOptions = [
{ value: 'running', label: '运行中' },
{ value: 'maintenance', label: '维护中' },
{ value: 'offline', label: '离线' },
{ value: 'fault', label: '故障' }
];
const typeField = await DeviceField.findOne({ where: { fieldName: 'type' } });
if (typeField) {
if (!typeField.options || typeField.options.length === 0) {
await typeField.update({ options: deviceTypeOptions });
console.log(' 已更新 type 字段的 options');
} else {
console.log(' type 字段 options 已存在,跳过');
}
} else {
console.log(' type 字段不存在,跳过');
}
const statusField = await DeviceField.findOne({ where: { fieldName: 'status' } });
if (statusField) {
if (!statusField.options || statusField.options.length === 0) {
await statusField.update({ options: statusOptions });
console.log(' 已更新 status 字段的 options');
} else {
console.log(' status 字段 options 已存在,跳过');
}
} else {
console.log(' status 字段不存在,跳过');
}
console.log(' 设备字段 Options 配置迁移完成');
}
async function migrateIdleDeviceAndBusiness() {
const queryInterface = sequelize.getQueryInterface();
const dialect = sequelize.getDialect();
@@ -296,7 +296,6 @@ const RemoteBackupSettings = () => {
await form.validateFields();
const values = form.getFieldsValue(true);
console.log('[TestConnection] getFieldsValue(true):', JSON.stringify(values));
const response = await api.post('/backup/remote/test', values);
if (response?.success) {