refactor: 重写系统设置模块,新增维护模式与登录策略功能
- 移除大量无实际效果的冗余配置项 - 新增维护模式拦截逻辑,支持管理员豁免 - 重构登录失败次数限制,从配置动态读取阈值 - 新增站点Logo支持与配置管理 - 优化用户管理页面数据拉取逻辑 - 新增端口批量创建范围模式功能 - 更新依赖包版本与缓存策略
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const User = require('../models/User');
|
||||
const UserRole = require('../models/UserRole');
|
||||
const Role = require('../models/Role');
|
||||
const SystemSetting = require('../models/SystemSetting');
|
||||
const logger = require('../utils/logger').module('AuthMiddleware');
|
||||
|
||||
// 维护模式缓存,避免每次请求都查数据库
|
||||
let maintenanceModeCache = { value: false, updatedAt: 0 };
|
||||
const MAINTENANCE_CACHE_TTL = 30000; // 30秒缓存
|
||||
|
||||
function getJwtSecret() {
|
||||
const envSecret = process.env.JWT_SECRET;
|
||||
|
||||
@@ -169,6 +176,41 @@ const authMiddleware = async (req, res, next) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 维护模式检查:普通用户无法访问,管理员不受影响
|
||||
const now = Date.now();
|
||||
if (now - maintenanceModeCache.updatedAt > MAINTENANCE_CACHE_TTL) {
|
||||
try {
|
||||
const maintenanceSetting = await SystemSetting.findByPk('maintenance_mode');
|
||||
maintenanceModeCache = {
|
||||
value: maintenanceSetting ? JSON.parse(maintenanceSetting.settingValue) : false,
|
||||
updatedAt: now,
|
||||
};
|
||||
} catch (err) {
|
||||
logger.warn('读取维护模式设置失败', { error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
if (maintenanceModeCache.value) {
|
||||
// 查询用户角色,判断是否为管理员
|
||||
const userRole = await UserRole.findOne({
|
||||
where: { UserId: user.userId },
|
||||
include: [{ model: Role }],
|
||||
});
|
||||
const isAdmin = userRole && userRole.Role && userRole.Role.roleCode === 'admin';
|
||||
|
||||
if (!isAdmin) {
|
||||
logger.info('维护模式:拒绝普通用户访问', {
|
||||
userId: user.userId,
|
||||
username: user.username,
|
||||
});
|
||||
return res.status(503).json({
|
||||
success: false,
|
||||
code: 'MAINTENANCE_MODE',
|
||||
message: '系统维护中,请稍后再试',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
req.user = decoded;
|
||||
req.userModel = user;
|
||||
next();
|
||||
@@ -229,6 +271,11 @@ const optionalAuth = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 清除维护模式缓存,在设置更新时调用 */
|
||||
const clearMaintenanceCache = () => {
|
||||
maintenanceModeCache = { value: false, updatedAt: 0 };
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
generateToken,
|
||||
verifyToken,
|
||||
@@ -236,4 +283,5 @@ module.exports = {
|
||||
optionalAuth,
|
||||
JWT_SECRET,
|
||||
TOKEN_EXPIRY,
|
||||
clearMaintenanceCache,
|
||||
};
|
||||
|
||||
@@ -53,6 +53,7 @@ const User = sequelize.define(
|
||||
loginCount: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
comment: '连续登录失败次数,登录成功后重置',
|
||||
},
|
||||
lockedUntil: {
|
||||
type: DataTypes.DATE,
|
||||
|
||||
Generated
+61
-5
@@ -8,6 +8,7 @@
|
||||
"name": "idc-backend",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"all": "^0.0.0",
|
||||
"axios": "^1.13.6",
|
||||
"basic-ftp": "^5.0.3",
|
||||
"bcryptjs": "^3.0.3",
|
||||
@@ -44,7 +45,7 @@
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.0",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^3.0.1",
|
||||
"nodemon": "^3.1.14",
|
||||
"prettier": "^3.8.1",
|
||||
"supertest": "^7.1.4"
|
||||
}
|
||||
@@ -142,6 +143,7 @@
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1669,6 +1671,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
|
||||
"integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -1735,6 +1738,7 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -1843,6 +1847,12 @@
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/all": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/all/-/all-0.0.0.tgz",
|
||||
"integrity": "sha512-0oKlfNVv2d+d7c1gwjGspzgbwot47PGQ4b3v1ccx4mR8l9P/Y6E6Dr/yE8lNT63EcAKEbHo6UG3odDpC/NQcKw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ansi-escapes": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
||||
@@ -2462,6 +2472,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
@@ -3778,6 +3789,7 @@
|
||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -3838,6 +3850,7 @@
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
@@ -4232,6 +4245,7 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
|
||||
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -7519,16 +7533,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.11",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz",
|
||||
"integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==",
|
||||
"version": "3.1.14",
|
||||
"resolved": "https://registry.npmmirror.com/nodemon/-/nodemon-3.1.14.tgz",
|
||||
"integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"minimatch": "^10.2.1",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
@@ -7547,6 +7561,29 @@
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/balanced-match": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/brace-expansion": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
@@ -7565,6 +7602,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/minimatch": {
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz",
|
||||
"integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^5.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -8117,6 +8170,7 @@
|
||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -10319,6 +10373,7 @@
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz",
|
||||
"integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@dabh/diagnostics": "^2.0.8",
|
||||
@@ -10567,6 +10622,7 @@
|
||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"test:operation-logs": "jest tests/operationLog.model.test.js tests/operationLogger.test.js tests/operationLogs.api.test.js --runInBand"
|
||||
},
|
||||
"dependencies": {
|
||||
"all": "^0.0.0",
|
||||
"axios": "^1.13.6",
|
||||
"basic-ftp": "^5.0.3",
|
||||
"bcryptjs": "^3.0.3",
|
||||
@@ -54,7 +55,7 @@
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.0",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^3.0.1",
|
||||
"nodemon": "^3.1.14",
|
||||
"prettier": "^3.8.1",
|
||||
"supertest": "^7.1.4"
|
||||
}
|
||||
|
||||
+38
-6
@@ -7,12 +7,11 @@ const UserRole = require('../models/UserRole');
|
||||
const { generateToken, authMiddleware } = require('../middleware/auth');
|
||||
const {
|
||||
SALT_ROUNDS,
|
||||
MAX_LOGIN_ATTEMPTS,
|
||||
LOCK_TIME,
|
||||
PASSWORD_MIN_LENGTH,
|
||||
USERNAME_MIN_LENGTH,
|
||||
USERNAME_MAX_LENGTH,
|
||||
} = require('../config');
|
||||
const SystemSetting = require('../models/SystemSetting');
|
||||
const { generateId } = require('../utils/idGenerator');
|
||||
|
||||
const router = express.Router();
|
||||
@@ -146,6 +145,38 @@ router.post('/login', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 检查维护模式:非管理员无法登录
|
||||
const maintenanceSetting = await SystemSetting.findByPk('maintenance_mode');
|
||||
const isMaintenanceMode = maintenanceSetting
|
||||
? JSON.parse(maintenanceSetting.settingValue)
|
||||
: false;
|
||||
|
||||
if (isMaintenanceMode) {
|
||||
// 先查找用户,判断是否为管理员
|
||||
const checkUser = await User.findOne({ where: { username } });
|
||||
if (checkUser) {
|
||||
const userRole = await UserRole.findOne({
|
||||
where: { UserId: checkUser.userId },
|
||||
include: [{ model: Role }],
|
||||
});
|
||||
const isAdmin = userRole && userRole.Role && userRole.Role.roleCode === 'admin';
|
||||
if (!isAdmin) {
|
||||
return res.status(503).json({
|
||||
success: false,
|
||||
code: 'MAINTENANCE_MODE',
|
||||
message: '系统维护中,暂时无法登录,请联系管理员',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从系统设置读取最大登录尝试次数
|
||||
const maxAttemptsSetting = await SystemSetting.findByPk('max_login_attempts');
|
||||
const maxLoginAttempts = maxAttemptsSetting
|
||||
? JSON.parse(maxAttemptsSetting.settingValue)
|
||||
: 5;
|
||||
const lockTimeMs = 30 * 60 * 1000; // 锁定30分钟
|
||||
|
||||
const user = await User.findOne({ where: { username } });
|
||||
if (!user) {
|
||||
return res.status(401).json({
|
||||
@@ -163,6 +194,7 @@ router.post('/login', async (req, res) => {
|
||||
message: `账户已被锁定,请在 ${remainingMinutes} 分钟后重试`,
|
||||
});
|
||||
}
|
||||
// 锁定时间已过,自动解锁
|
||||
user.status = 'active';
|
||||
user.loginCount = 0;
|
||||
user.lockedUntil = null;
|
||||
@@ -187,18 +219,18 @@ router.post('/login', async (req, res) => {
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
if (!isPasswordValid) {
|
||||
user.loginCount = (user.loginCount || 0) + 1;
|
||||
if (user.loginCount >= MAX_LOGIN_ATTEMPTS) {
|
||||
if (user.loginCount >= maxLoginAttempts) {
|
||||
user.status = 'locked';
|
||||
user.lockedUntil = new Date(Date.now() + LOCK_TIME);
|
||||
user.lockedUntil = new Date(Date.now() + lockTimeMs);
|
||||
}
|
||||
await user.save();
|
||||
|
||||
const remainingAttempts = MAX_LOGIN_ATTEMPTS - user.loginCount;
|
||||
const remainingAttempts = maxLoginAttempts - user.loginCount;
|
||||
let message = '用户名或密码错误';
|
||||
if (remainingAttempts > 0) {
|
||||
message += `,剩余 ${remainingAttempts} 次尝试机会`;
|
||||
} else {
|
||||
message = `账户已被锁定,请在 3 分钟后重试`;
|
||||
message = `账户已被锁定,请在 30 分钟后重试`;
|
||||
}
|
||||
|
||||
return res.status(401).json({
|
||||
|
||||
@@ -4,7 +4,7 @@ const router = express.Router();
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Op } = require('sequelize');
|
||||
const { authMiddleware } = require('../middleware/auth');
|
||||
const { authMiddleware, clearMaintenanceCache } = require('../middleware/auth');
|
||||
|
||||
// 读取 package.json 获取版本号
|
||||
const packageJsonPath = path.join(__dirname, '../../package.json');
|
||||
@@ -28,7 +28,7 @@ const { FRONTEND } = require('../config');
|
||||
// 初始化默认系统设置
|
||||
const initDefaultSettings = async () => {
|
||||
const defaultSettings = [
|
||||
// 全局配置
|
||||
// 基本设置 - 站点信息
|
||||
{
|
||||
settingKey: 'site_name',
|
||||
settingValue: JSON.stringify('机柜管理系统'),
|
||||
@@ -45,30 +45,8 @@ const initDefaultSettings = async () => {
|
||||
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),
|
||||
@@ -77,14 +55,6 @@ const initDefaultSettings = async () => {
|
||||
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),
|
||||
@@ -119,38 +89,6 @@ const initDefaultSettings = async () => {
|
||||
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,
|
||||
},
|
||||
|
||||
// 关于页面
|
||||
{
|
||||
@@ -201,22 +139,6 @@ const initDefaultSettings = async () => {
|
||||
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;
|
||||
@@ -361,6 +283,11 @@ router.put('/:key', async (req, res) => {
|
||||
settingValue: JSON.stringify(parsedValue),
|
||||
});
|
||||
|
||||
// 如果更新了维护模式设置,清除缓存
|
||||
if (key === 'maintenance_mode') {
|
||||
clearMaintenanceCache();
|
||||
}
|
||||
|
||||
res.json({
|
||||
message: '设置更新成功',
|
||||
setting: {
|
||||
@@ -426,6 +353,11 @@ router.put('/', async (req, res) => {
|
||||
updatedSettings,
|
||||
errors: errors.length > 0 ? errors : undefined,
|
||||
});
|
||||
|
||||
// 如果更新了维护模式设置,清除缓存
|
||||
if ('maintenance_mode' in settings) {
|
||||
clearMaintenanceCache();
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
@@ -444,27 +376,16 @@ router.post('/reset/:key', async (req, res) => {
|
||||
const defaultValues = {
|
||||
site_name: '机柜管理系统',
|
||||
site_logo: '',
|
||||
timezone: 'Asia/Shanghai',
|
||||
date_format: 'YYYY-MM-DD',
|
||||
session_timeout: 30,
|
||||
idle_timeout: 30,
|
||||
idle_warning_time: 60,
|
||||
max_login_attempts: 5,
|
||||
maintenance_mode: false,
|
||||
frontend_port: FRONTEND.DEFAULT_PORT,
|
||||
primary_color: '#667eea',
|
||||
secondary_color: '#764ba2',
|
||||
compact_mode: false,
|
||||
sidebar_collapsed: false,
|
||||
table_row_height: 'default',
|
||||
animation_enabled: true,
|
||||
company_name: '',
|
||||
contact_email: '',
|
||||
contact_phone: '',
|
||||
company_address: '',
|
||||
system_description: '机柜管理系统 - 专业的数据中心设备管理解决方案',
|
||||
privacy_policy: '',
|
||||
terms_of_service: '',
|
||||
};
|
||||
|
||||
const defaultValue = defaultValues[key];
|
||||
@@ -476,6 +397,11 @@ router.post('/reset/:key', async (req, res) => {
|
||||
settingValue: JSON.stringify(defaultValue),
|
||||
});
|
||||
|
||||
// 如果重置了维护模式设置,清除缓存
|
||||
if (key === 'maintenance_mode') {
|
||||
clearMaintenanceCache();
|
||||
}
|
||||
|
||||
res.json({
|
||||
message: '设置已重置为默认值',
|
||||
key,
|
||||
|
||||
Reference in New Issue
Block a user