refactor: 统一代码风格并迁移至 ESLint 新配置

style(backend): 格式化模型文件代码
style(frontend): 调整组件代码格式
chore: 删除旧 ESLint 配置并添加新配置
refactor(backend): 重构模型定义语法
style: 统一箭头函数和对象属性简写
This commit is contained in:
zhang1106
2026-03-27 19:12:16 +08:00
parent 6a8d4144ff
commit 63f0cb570e
166 changed files with 15483 additions and 11170 deletions
+276 -109
View File
@@ -10,33 +10,194 @@ const { FRONTEND } = require('../config');
const initDefaultSettings = async () => {
const defaultSettings = [
// 全局配置
{ settingKey: 'site_name', settingValue: JSON.stringify('机柜管理系统'), settingType: 'string', category: 'general', description: '网站名称', isEditable: true },
{ settingKey: 'site_logo', settingValue: JSON.stringify(''), settingType: 'string', category: 'general', description: '网站Logo URL', isEditable: true },
{ settingKey: 'timezone', settingValue: JSON.stringify('Asia/Shanghai'), settingType: 'string', category: 'general', description: '时区设置', isEditable: true },
{ settingKey: 'date_format', settingValue: JSON.stringify('YYYY-MM-DD'), settingType: 'string', category: 'general', description: '日期格式', isEditable: true },
{ settingKey: 'session_timeout', settingValue: JSON.stringify(30), settingType: 'number', category: 'general', description: '登录有效期(分钟)', isEditable: true },
{ settingKey: 'idle_timeout', settingValue: JSON.stringify(30), settingType: 'number', category: 'general', description: '用户空闲超时时间(分钟)', isEditable: true },
{ settingKey: 'idle_warning_time', settingValue: JSON.stringify(60), settingType: 'number', category: 'general', description: '空闲超时前警告时间(秒)', isEditable: false },
{ settingKey: 'max_login_attempts', settingValue: JSON.stringify(5), settingType: 'number', category: 'general', description: '最大登录尝试次数', isEditable: true },
{ settingKey: 'maintenance_mode', settingValue: JSON.stringify(false), settingType: 'boolean', category: 'general', description: '维护模式', isEditable: true },
{
settingKey: 'site_name',
settingValue: JSON.stringify('机柜管理系统'),
settingType: 'string',
category: 'general',
description: '网站名称',
isEditable: true,
},
{
settingKey: 'site_logo',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'general',
description: '网站Logo URL',
isEditable: true,
},
{
settingKey: 'timezone',
settingValue: JSON.stringify('Asia/Shanghai'),
settingType: 'string',
category: 'general',
description: '时区设置',
isEditable: true,
},
{
settingKey: 'date_format',
settingValue: JSON.stringify('YYYY-MM-DD'),
settingType: 'string',
category: 'general',
description: '日期格式',
isEditable: true,
},
{
settingKey: 'session_timeout',
settingValue: JSON.stringify(30),
settingType: 'number',
category: 'general',
description: '登录有效期(分钟)',
isEditable: true,
},
{
settingKey: 'idle_timeout',
settingValue: JSON.stringify(30),
settingType: 'number',
category: 'general',
description: '用户空闲超时时间(分钟)',
isEditable: true,
},
{
settingKey: 'idle_warning_time',
settingValue: JSON.stringify(60),
settingType: 'number',
category: 'general',
description: '空闲超时前警告时间(秒)',
isEditable: false,
},
{
settingKey: 'max_login_attempts',
settingValue: JSON.stringify(5),
settingType: 'number',
category: 'general',
description: '最大登录尝试次数',
isEditable: true,
},
{
settingKey: 'maintenance_mode',
settingValue: JSON.stringify(false),
settingType: 'boolean',
category: 'general',
description: '维护模式',
isEditable: true,
},
// 外观设置
{ settingKey: 'primary_color', settingValue: JSON.stringify('#667eea'), settingType: 'string', category: 'appearance', description: '主题主色调', isEditable: true },
{ settingKey: 'secondary_color', settingValue: JSON.stringify('#764ba2'), settingType: 'string', category: 'appearance', description: '主题辅助色调', isEditable: true },
{ settingKey: 'compact_mode', settingValue: JSON.stringify(false), settingType: 'boolean', category: 'appearance', description: '紧凑模式', isEditable: true },
{ settingKey: 'sidebar_collapsed', settingValue: JSON.stringify(false), settingType: 'boolean', category: 'appearance', description: '侧边栏默认折叠', isEditable: true },
{ settingKey: 'table_row_height', settingValue: JSON.stringify('default'), settingType: 'string', category: 'appearance', description: '表格行高: small/default/middle/large', isEditable: true },
{ settingKey: 'animation_enabled', settingValue: JSON.stringify(true), settingType: 'boolean', category: 'appearance', description: '启用动画效果', isEditable: true },
{
settingKey: 'primary_color',
settingValue: JSON.stringify('#667eea'),
settingType: 'string',
category: 'appearance',
description: '主题主色调',
isEditable: true,
},
{
settingKey: 'secondary_color',
settingValue: JSON.stringify('#764ba2'),
settingType: 'string',
category: 'appearance',
description: '主题辅助色调',
isEditable: true,
},
{
settingKey: 'compact_mode',
settingValue: JSON.stringify(false),
settingType: 'boolean',
category: 'appearance',
description: '紧凑模式',
isEditable: true,
},
{
settingKey: 'sidebar_collapsed',
settingValue: JSON.stringify(false),
settingType: 'boolean',
category: 'appearance',
description: '侧边栏默认折叠',
isEditable: true,
},
{
settingKey: 'table_row_height',
settingValue: JSON.stringify('default'),
settingType: 'string',
category: 'appearance',
description: '表格行高: small/default/middle/large',
isEditable: true,
},
{
settingKey: 'animation_enabled',
settingValue: JSON.stringify(true),
settingType: 'boolean',
category: 'appearance',
description: '启用动画效果',
isEditable: true,
},
// 关于页面
{ settingKey: 'app_version', settingValue: JSON.stringify('1.0.0'), settingType: 'string', category: 'about', description: '应用版本', isEditable: false },
{ settingKey: 'company_name', settingValue: JSON.stringify(''), settingType: 'string', category: 'about', description: '公司/组织名称', isEditable: true },
{ settingKey: 'contact_email', settingValue: JSON.stringify(''), settingType: 'string', category: 'about', description: '联系邮箱', isEditable: true },
{ settingKey: 'contact_phone', settingValue: JSON.stringify(''), settingType: 'string', category: 'about', description: '联系电话', isEditable: true },
{ settingKey: 'company_address', settingValue: JSON.stringify(''), settingType: 'string', category: 'about', description: '公司地址', isEditable: true },
{ settingKey: 'system_description', settingValue: JSON.stringify('机柜管理系统 - 专业的数据中心设备管理解决方案'), settingType: 'string', category: 'about', description: '系统描述', isEditable: true },
{ settingKey: 'privacy_policy', settingValue: JSON.stringify(''), settingType: 'string', category: 'about', description: '隐私政策URL', isEditable: true },
{ settingKey: 'terms_of_service', settingValue: JSON.stringify(''), settingType: 'string', category: 'about', description: '服务条款URL', isEditable: true },
{
settingKey: 'app_version',
settingValue: JSON.stringify('1.0.0'),
settingType: 'string',
category: 'about',
description: '应用版本',
isEditable: false,
},
{
settingKey: 'company_name',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'about',
description: '公司/组织名称',
isEditable: true,
},
{
settingKey: 'contact_email',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'about',
description: '联系邮箱',
isEditable: true,
},
{
settingKey: 'contact_phone',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'about',
description: '联系电话',
isEditable: true,
},
{
settingKey: 'company_address',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'about',
description: '公司地址',
isEditable: true,
},
{
settingKey: 'system_description',
settingValue: JSON.stringify('机柜管理系统 - 专业的数据中心设备管理解决方案'),
settingType: 'string',
category: 'about',
description: '系统描述',
isEditable: true,
},
{
settingKey: 'privacy_policy',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'about',
description: '隐私政策URL',
isEditable: true,
},
{
settingKey: 'terms_of_service',
settingValue: JSON.stringify(''),
settingType: 'string',
category: 'about',
description: '服务条款URL',
isEditable: true,
},
];
let createdCount = 0;
@@ -60,7 +221,9 @@ const initDefaultSettings = async () => {
}
}
console.log(`系统设置初始化结果: 创建 ${createdCount} 个, 更新 ${updatedCount} 个, 失败 ${errorCount}`);
console.log(
`系统设置初始化结果: 创建 ${createdCount} 个, 更新 ${updatedCount} 个, 失败 ${errorCount}`
);
return { createdCount, updatedCount, errorCount };
};
@@ -75,12 +238,15 @@ router.get('/', async (req, res) => {
if (category) {
where.category = category;
}
const settings = await SystemSetting.findAll({
where,
order: [['category', 'ASC'], ['settingKey', 'ASC']]
order: [
['category', 'ASC'],
['settingKey', 'ASC'],
],
});
// 格式化返回数据
const formattedSettings = {};
settings.forEach(setting => {
@@ -90,10 +256,10 @@ router.get('/', async (req, res) => {
category: setting.category,
description: setting.description,
isEditable: setting.isEditable,
updatedAt: setting.updatedAt
updatedAt: setting.updatedAt,
};
});
res.json(formattedSettings);
} catch (error) {
res.status(500).json({ error: error.message });
@@ -116,7 +282,7 @@ router.get('/idle-timeout', async (req, res) => {
timeout: timeout * 60 * 1000, // 转换为毫秒
warningTime: fixedWarningTime * 1000, // 固定10秒(转换为毫秒)
timeoutMinutes: timeout,
warningTimeSeconds: fixedWarningTime
warningTimeSeconds: fixedWarningTime,
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -128,11 +294,11 @@ router.get('/:key', async (req, res) => {
try {
const { key } = req.params;
const setting = await SystemSetting.findByPk(key);
if (!setting) {
return res.status(404).json({ error: '设置不存在' });
}
res.json({
key: setting.settingKey,
value: JSON.parse(setting.settingValue),
@@ -140,7 +306,7 @@ router.get('/:key', async (req, res) => {
category: setting.category,
description: setting.description,
isEditable: setting.isEditable,
updatedAt: setting.updatedAt
updatedAt: setting.updatedAt,
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -152,17 +318,17 @@ router.put('/:key', async (req, res) => {
try {
const { key } = req.params;
const { value } = req.body;
const setting = await SystemSetting.findByPk(key);
if (!setting) {
return res.status(404).json({ error: '设置不存在' });
}
if (!setting.isEditable) {
return res.status(403).json({ error: '该设置不可编辑' });
}
// 验证值类型
let parsedValue = value;
if (setting.settingType === 'number') {
@@ -173,18 +339,18 @@ router.put('/:key', async (req, res) => {
} else if (setting.settingType === 'boolean') {
parsedValue = Boolean(value);
}
await setting.update({
settingValue: JSON.stringify(parsedValue)
settingValue: JSON.stringify(parsedValue),
});
res.json({
message: '设置更新成功',
setting: {
key: setting.settingKey,
value: parsedValue,
updatedAt: setting.updatedAt
}
updatedAt: setting.updatedAt,
},
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -195,28 +361,28 @@ router.put('/:key', async (req, res) => {
router.put('/', async (req, res) => {
try {
const { settings } = req.body;
if (!settings || typeof settings !== 'object') {
return res.status(400).json({ error: '请提供有效的设置对象' });
}
const updatedSettings = [];
const errors = [];
for (const [key, value] of Object.entries(settings)) {
try {
const setting = await SystemSetting.findByPk(key);
if (!setting) {
errors.push({ key, error: '设置不存在' });
continue;
}
if (!setting.isEditable) {
errors.push({ key, error: '该设置不可编辑' });
continue;
}
let parsedValue = value;
if (setting.settingType === 'number') {
parsedValue = Number(value);
@@ -227,21 +393,21 @@ router.put('/', async (req, res) => {
} else if (setting.settingType === 'boolean') {
parsedValue = Boolean(value);
}
await setting.update({
settingValue: JSON.stringify(parsedValue)
settingValue: JSON.stringify(parsedValue),
});
updatedSettings.push({ key, value: parsedValue });
} catch (error) {
errors.push({ key, error: error.message });
}
}
res.json({
message: `成功更新 ${updatedSettings.length} 个设置`,
updatedSettings,
errors: errors.length > 0 ? errors : undefined
errors: errors.length > 0 ? errors : undefined,
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -253,11 +419,11 @@ router.post('/reset/:key', async (req, res) => {
try {
const { key } = req.params;
const setting = await SystemSetting.findByPk(key);
if (!setting) {
return res.status(404).json({ error: '设置不存在' });
}
const defaultValues = {
site_name: '机柜管理系统',
site_logo: '',
@@ -281,22 +447,22 @@ router.post('/reset/:key', async (req, res) => {
company_address: '',
system_description: '机柜管理系统 - 专业的数据中心设备管理解决方案',
privacy_policy: '',
terms_of_service: ''
terms_of_service: '',
};
const defaultValue = defaultValues[key];
if (defaultValue === undefined) {
return res.status(400).json({ error: '该设置没有默认值' });
}
await setting.update({
settingValue: JSON.stringify(defaultValue)
settingValue: JSON.stringify(defaultValue),
});
res.json({
message: '设置已重置为默认值',
key,
value: defaultValue
value: defaultValue,
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -309,7 +475,7 @@ router.post('/backup', async (req, res) => {
// 获取系统设置中的备份路径
const backupPathSetting = await SystemSetting.findByPk('backup_path');
const backupPath = backupPathSetting ? JSON.parse(backupPathSetting.settingValue) : './backups';
// 解析备份目录路径
let backupDir;
if (backupPath.startsWith('/') || backupPath.match(/^[A-Za-z]:\//)) {
@@ -319,22 +485,22 @@ router.post('/backup', async (req, res) => {
// 相对路径,基于项目根目录
backupDir = path.join(__dirname, '../', backupPath);
}
// 确保备份目录存在
if (!fs.existsSync(backupDir)) {
fs.mkdirSync(backupDir, { recursive: true });
}
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupFile = path.join(backupDir, `backup_${timestamp}.json`);
// 获取所有数据库数据
const Device = require('../models/Device');
const Rack = require('../models/Rack');
const Room = require('../models/Room');
const Consumable = require('../models/Consumable');
const User = require('../models/User');
const backupData = {
timestamp: new Date().toISOString(),
version: '1.0.0',
@@ -344,38 +510,38 @@ router.post('/backup', async (req, res) => {
rooms: await Room.findAll({ raw: true }),
consumables: await Consumable.findAll({ raw: true }),
// 不包含敏感用户信息
users: await User.findAll({
users: await User.findAll({
attributes: ['userId', 'username', 'role', 'createdAt', 'updatedAt'],
raw: true
})
}
raw: true,
}),
},
};
// 写入备份文件
fs.writeFileSync(backupFile, JSON.stringify(backupData, null, 2));
// 更新最后备份时间
const lastBackupSetting = await SystemSetting.findByPk('last_backup_time');
if (lastBackupSetting) {
await lastBackupSetting.update({
settingValue: JSON.stringify(new Date().toISOString())
settingValue: JSON.stringify(new Date().toISOString()),
});
}
// 统计备份文件数量
const backupFiles = fs.readdirSync(backupDir).filter(f => f.startsWith('backup_'));
const countSetting = await SystemSetting.findByPk('backup_count');
if (countSetting) {
await countSetting.update({
settingValue: JSON.stringify(backupFiles.length)
settingValue: JSON.stringify(backupFiles.length),
});
}
res.json({
message: '备份成功',
backupFile: `${backupPath}/backup_${timestamp}.json`,
fileSize: fs.statSync(backupFile).size,
backupCount: backupFiles.length
backupCount: backupFiles.length,
});
} catch (error) {
console.error('备份失败:', error);
@@ -387,7 +553,7 @@ router.post('/backup', async (req, res) => {
const getBackupDir = async () => {
const backupPathSetting = await SystemSetting.findByPk('backup_path');
const backupPath = backupPathSetting ? JSON.parse(backupPathSetting.settingValue) : './backups';
let backupDir;
if (backupPath.startsWith('/') || backupPath.match(/^[A-Za-z]:\//)) {
// 绝对路径
@@ -396,7 +562,7 @@ const getBackupDir = async () => {
// 相对路径,基于项目根目录
backupDir = path.join(__dirname, '../', backupPath);
}
return backupDir;
};
@@ -404,12 +570,13 @@ const getBackupDir = async () => {
router.get('/backup/list', async (req, res) => {
try {
const backupDir = await getBackupDir();
if (!fs.existsSync(backupDir)) {
return res.json({ backups: [] });
}
const files = fs.readdirSync(backupDir)
const files = fs
.readdirSync(backupDir)
.filter(f => f.startsWith('backup_') && f.endsWith('.json'))
.map(f => {
const filePath = path.join(backupDir, f);
@@ -419,11 +586,11 @@ router.get('/backup/list', async (req, res) => {
path: `${path.basename(backupDir)}/${f}`,
size: stats.size,
createdAt: stats.birthtime,
modifiedAt: stats.mtime
modifiedAt: stats.mtime,
};
})
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
res.json({ backups: files });
} catch (error) {
res.status(500).json({ error: error.message });
@@ -434,50 +601,50 @@ router.get('/backup/list', async (req, res) => {
router.post('/backup/restore', async (req, res) => {
try {
const { filename } = req.body;
if (!filename) {
return res.status(400).json({ error: '请提供备份文件名' });
}
const backupDir = await getBackupDir();
const backupFile = path.join(backupDir, filename);
if (!fs.existsSync(backupFile)) {
return res.status(404).json({ error: '备份文件不存在' });
}
const backupData = JSON.parse(fs.readFileSync(backupFile, 'utf8'));
// 恢复数据
const { Device, Rack, Room, Consumable, User } = require('../models');
if (backupData.data.devices) {
for (const device of backupData.data.devices) {
await Device.upsert(device);
}
}
if (backupData.data.racks) {
for (const rack of backupData.data.racks) {
await Rack.upsert(rack);
}
}
if (backupData.data.rooms) {
for (const room of backupData.data.rooms) {
await Room.upsert(room);
}
}
if (backupData.data.consumables) {
for (const consumable of backupData.data.consumables) {
await Consumable.upsert(consumable);
}
}
res.json({
message: '恢复成功',
restoredAt: new Date().toISOString()
restoredAt: new Date().toISOString(),
});
} catch (error) {
console.error('恢复备份失败:', error);
@@ -491,13 +658,13 @@ router.delete('/backup/:filename', async (req, res) => {
const { filename } = req.params;
const backupDir = await getBackupDir();
const backupFile = path.join(backupDir, filename);
if (!fs.existsSync(backupFile)) {
return res.status(404).json({ error: '备份文件不存在' });
}
fs.unlinkSync(backupFile);
res.json({ message: '删除成功', filename });
} catch (error) {
res.status(500).json({ error: error.message });
@@ -510,11 +677,11 @@ router.get('/backup/download/:filename', async (req, res) => {
const { filename } = req.params;
const backupDir = await getBackupDir();
const backupFile = path.join(backupDir, filename);
if (!fs.existsSync(backupFile)) {
return res.status(404).json({ error: '备份文件不存在' });
}
res.download(backupFile, filename);
} catch (error) {
res.status(500).json({ error: error.message });
@@ -528,14 +695,14 @@ router.get('/system/info', async (req, res) => {
const Rack = require('../models/Rack');
const Room = require('../models/Room');
const User = require('../models/User');
const [deviceCount, rackCount, roomCount, userCount] = await Promise.all([
Device.count(),
Rack.count(),
Room.count(),
User.count()
User.count(),
]);
res.json({
system: {
name: '机柜管理系统',
@@ -545,15 +712,15 @@ router.get('/system/info', async (req, res) => {
platform: process.platform,
arch: process.arch,
memoryUsage: process.memoryUsage(),
pid: process.pid
pid: process.pid,
},
statistics: {
devices: deviceCount,
racks: rackCount,
rooms: roomCount,
users: userCount
users: userCount,
},
timestamp: new Date().toISOString()
timestamp: new Date().toISOString(),
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -590,7 +757,7 @@ router.post('/frontend/port/sync', async (req, res) => {
message: '前端端口配置已同步',
port,
configPath: '.frontend-port',
notice: '配置已更新,请重启前端服务以应用新端口'
notice: '配置已更新,请重启前端服务以应用新端口',
});
} catch (error) {
res.status(500).json({ error: error.message });
@@ -614,8 +781,8 @@ router.post('/frontend/restart', async (req, res) => {
after: {
pid: result.pid,
port: result.port,
url: `http://localhost:${result.port}`
}
url: `http://localhost:${result.port}`,
},
});
} catch (error) {
res.status(500).json({ error: error.message });