321 lines
7.7 KiB
JavaScript
321 lines
7.7 KiB
JavaScript
|
|
const express = require('express');
|
|||
|
|
const { auth } = require('../middleware/auth');
|
|||
|
|
const { validateQuery, validate } = require('../middleware/validation');
|
|||
|
|
const { logger } = require('../config/logger');
|
|||
|
|
const { HTTP_STATUS } = require('../config/constants');
|
|||
|
|
const { getDB } = require('../database');
|
|||
|
|
const Joi = require('joi');
|
|||
|
|
|
|||
|
|
const router = express.Router();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 系统设置验证规则
|
|||
|
|
*/
|
|||
|
|
const systemSchemas = {
|
|||
|
|
// 更新系统设置
|
|||
|
|
updateSettings: Joi.object({
|
|||
|
|
basic: Joi.object({
|
|||
|
|
siteName: Joi.string().max(100).allow(''),
|
|||
|
|
siteDescription: Joi.string().max(500).allow(''),
|
|||
|
|
siteKeywords: Joi.string().max(200).allow(''),
|
|||
|
|
siteLogo: Joi.string().allow(''),
|
|||
|
|
siteFavicon: Joi.string().allow(''),
|
|||
|
|
|
|||
|
|
icp: Joi.string().max(100).allow('')
|
|||
|
|
}).optional(),
|
|||
|
|
features: Joi.object({
|
|||
|
|
allowRegister: Joi.boolean(),
|
|||
|
|
allowTransfer: Joi.boolean(),
|
|||
|
|
allowExchange: Joi.boolean(),
|
|||
|
|
allowReview: Joi.boolean(),
|
|||
|
|
allowComment: Joi.boolean()
|
|||
|
|
}).optional(),
|
|||
|
|
|
|||
|
|
security: Joi.object({
|
|||
|
|
maxLoginAttempts: Joi.number().integer().min(1).max(100),
|
|||
|
|
lockoutDuration: Joi.number().integer().min(1).max(86400),
|
|||
|
|
ipWhitelist: Joi.string().allow('')
|
|||
|
|
}).optional()
|
|||
|
|
})
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取系统设置 (公开接口,不需要认证)
|
|||
|
|
* GET /api/system/settings
|
|||
|
|
*/
|
|||
|
|
router.get('/settings', async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
|
|||
|
|
const db = getDB();
|
|||
|
|
|
|||
|
|
// 获取系统设置
|
|||
|
|
const [settings] = await db.execute(
|
|||
|
|
'SELECT setting_key, setting_value FROM system_settings'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 组织设置数据
|
|||
|
|
const settingsData = {
|
|||
|
|
basic: {
|
|||
|
|
siteName: '',
|
|||
|
|
siteDescription: '',
|
|||
|
|
siteKeywords: '',
|
|||
|
|
siteLogo: '',
|
|||
|
|
siteFavicon: '',
|
|||
|
|
|
|||
|
|
icp: ''
|
|||
|
|
},
|
|||
|
|
features: {
|
|||
|
|
allowRegister: true,
|
|||
|
|
allowTransfer: true,
|
|||
|
|
allowExchange: true,
|
|||
|
|
allowReview: true,
|
|||
|
|
allowComment: true
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
security: {
|
|||
|
|
maxLoginAttempts: 5,
|
|||
|
|
lockoutDuration: 300,
|
|||
|
|
ipWhitelist: ''
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 填充数据库中的设置
|
|||
|
|
settings.forEach(setting => {
|
|||
|
|
const keys = setting.setting_key.split('.');
|
|||
|
|
if (keys.length === 2 && settingsData[keys[0]]) {
|
|||
|
|
try {
|
|||
|
|
// 尝试解析JSON值,如果失败则使用原始值
|
|||
|
|
settingsData[keys[0]][keys[1]] = JSON.parse(setting.setting_value);
|
|||
|
|
} catch {
|
|||
|
|
settingsData[keys[0]][keys[1]] = setting.setting_value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
logger.info('System settings retrieved', {
|
|||
|
|
settingsCount: settings.length
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
success: true,
|
|||
|
|
data: settingsData
|
|||
|
|
});
|
|||
|
|
} catch (error) {
|
|||
|
|
next(error);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 更新系统设置
|
|||
|
|
* PUT /api/system/settings
|
|||
|
|
*/
|
|||
|
|
router.put('/settings',
|
|||
|
|
auth,
|
|||
|
|
validate(systemSchemas.updateSettings),
|
|||
|
|
async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
// 检查管理员权限
|
|||
|
|
if (req.user.role !== 'admin') {
|
|||
|
|
return res.status(HTTP_STATUS.FORBIDDEN).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const db = getDB();
|
|||
|
|
const settings = req.body;
|
|||
|
|
|
|||
|
|
// 开始事务
|
|||
|
|
await db.beginTransaction();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 更新设置
|
|||
|
|
for (const [category, categorySettings] of Object.entries(settings)) {
|
|||
|
|
for (const [key, value] of Object.entries(categorySettings)) {
|
|||
|
|
const settingKey = `${category}.${key}`;
|
|||
|
|
const settingValue = JSON.stringify(value);
|
|||
|
|
|
|||
|
|
await db.execute(
|
|||
|
|
`INSERT INTO system_settings (setting_key, setting_value, updated_at)
|
|||
|
|
VALUES (?, ?, NOW())
|
|||
|
|
ON DUPLICATE KEY UPDATE
|
|||
|
|
setting_value = VALUES(setting_value),
|
|||
|
|
updated_at = VALUES(updated_at)`,
|
|||
|
|
[settingKey, settingValue]
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
await db.commit();
|
|||
|
|
|
|||
|
|
logger.info('System settings updated', {
|
|||
|
|
userId: req.user.id,
|
|||
|
|
categories: Object.keys(settings)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
success: true,
|
|||
|
|
message: '系统设置更新成功'
|
|||
|
|
});
|
|||
|
|
} catch (error) {
|
|||
|
|
await db.rollback();
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
next(error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取系统信息
|
|||
|
|
* GET /api/system/info
|
|||
|
|
*/
|
|||
|
|
router.get('/info', auth, async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
// 检查管理员权限
|
|||
|
|
if (req.user.role !== 'admin') {
|
|||
|
|
return res.status(HTTP_STATUS.FORBIDDEN).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const systemInfo = {
|
|||
|
|
version: '1.0.0',
|
|||
|
|
nodeVersion: process.version,
|
|||
|
|
platform: process.platform,
|
|||
|
|
uptime: process.uptime(),
|
|||
|
|
memoryUsage: process.memoryUsage(),
|
|||
|
|
timestamp: new Date().toISOString()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
success: true,
|
|||
|
|
data: systemInfo
|
|||
|
|
});
|
|||
|
|
} catch (error) {
|
|||
|
|
next(error);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取维护模式状态(公开接口)
|
|||
|
|
* GET /api/system/maintenance-status
|
|||
|
|
*/
|
|||
|
|
router.get('/maintenance-status', async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
const db = getDB();
|
|||
|
|
|
|||
|
|
// 从系统设置表获取维护模式状态
|
|||
|
|
const [rows] = await db.execute(
|
|||
|
|
'SELECT setting_value FROM system_settings WHERE setting_key = ?',
|
|||
|
|
['maintenance_mode']
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const maintenanceMode = rows.length > 0 ? rows[0].setting_value === 'true' : false;
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
success: true,
|
|||
|
|
data: {
|
|||
|
|
maintenance_mode: maintenanceMode
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取维护模式状态失败:', error);
|
|||
|
|
next(error);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取维护模式状态(管理员接口)
|
|||
|
|
* GET /api/system/admin/maintenance-status
|
|||
|
|
*/
|
|||
|
|
router.get('/admin/maintenance-status', auth, async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
// 检查管理员权限
|
|||
|
|
if (req.user.role !== 'admin') {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
error: {
|
|||
|
|
code: 'FORBIDDEN',
|
|||
|
|
message: '权限不足'
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const db = getDB();
|
|||
|
|
|
|||
|
|
// 从系统设置表获取维护模式状态
|
|||
|
|
const [rows] = await db.execute(
|
|||
|
|
'SELECT setting_value FROM system_settings WHERE setting_key = ?',
|
|||
|
|
['maintenance_mode']
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const maintenanceMode = rows.length > 0 ? rows[0].setting_value === 'true' : false;
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
success: true,
|
|||
|
|
data: {
|
|||
|
|
maintenance_mode: maintenanceMode
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取维护模式状态失败:', error);
|
|||
|
|
next(error);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 切换维护模式
|
|||
|
|
* POST /api/system/toggle-maintenance
|
|||
|
|
*/
|
|||
|
|
router.post('/toggle-maintenance', auth, async (req, res, next) => {
|
|||
|
|
try {
|
|||
|
|
// 检查管理员权限
|
|||
|
|
if (req.user.role !== 'admin') {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
error: {
|
|||
|
|
code: 'FORBIDDEN',
|
|||
|
|
message: '权限不足'
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const { maintenance_mode } = req.body;
|
|||
|
|
const db = getDB();
|
|||
|
|
|
|||
|
|
// 更新或插入维护模式设置
|
|||
|
|
await db.execute(
|
|||
|
|
`INSERT INTO system_settings (setting_key, setting_value, updated_at)
|
|||
|
|
VALUES ('maintenance_mode', ?, NOW())
|
|||
|
|
ON DUPLICATE KEY UPDATE
|
|||
|
|
setting_value = VALUES(setting_value),
|
|||
|
|
updated_at = NOW()`,
|
|||
|
|
[maintenance_mode ? 'true' : 'false']
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
logger.info('Maintenance mode toggled', {
|
|||
|
|
userId: req.user.id,
|
|||
|
|
username: req.user.username,
|
|||
|
|
maintenanceMode: maintenance_mode
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
success: true,
|
|||
|
|
data: {
|
|||
|
|
maintenance_mode: maintenance_mode
|
|||
|
|
},
|
|||
|
|
message: maintenance_mode ? '维护模式已开启' : '维护模式已关闭'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('切换维护模式失败:', error);
|
|||
|
|
next(error);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
module.exports = router;
|