feat: 实现ID生成器并重构模型ID生成逻辑

refactor: 统一ID生成方式,使用新的idGenerator模块
refactor: 重构模型ID生成逻辑,允许空ID并在创建前自动生成
fix(roomSchema): 使机房ID字段变为可选并更新前端表单验证
style: 格式化代码并优化导入语句
test: 添加操作日志集成测试文件
docs: 添加错误处理模块文档
This commit is contained in:
zhang1106
2026-04-02 10:34:13 +08:00
parent ea67951dd4
commit 7f1df28858
28 changed files with 451 additions and 91 deletions
+137
View File
@@ -0,0 +1,137 @@
class AppError extends Error {
constructor(code, message, statusCode = 500, details = null) {
super(message);
this.code = code;
this.statusCode = statusCode;
this.details = details;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
const ERROR_CODES = {
BAD_REQUEST: 'BAD_REQUEST',
UNAUTHORIZED: 'UNAUTHORIZED',
FORBIDDEN: 'FORBIDDEN',
NOT_FOUND: 'NOT_FOUND',
CONFLICT: 'CONFLICT',
VALIDATION_ERROR: 'VALIDATION_ERROR',
INTERNAL_ERROR: 'INTERNAL_ERROR',
DATABASE_ERROR: 'DATABASE_ERROR',
NETWORK_ERROR: 'NETWORK_ERROR',
};
const STATUS_CODE_MAP = {
400: ERROR_CODES.BAD_REQUEST,
401: ERROR_CODES.UNAUTHORIZED,
403: ERROR_CODES.FORBIDDEN,
404: ERROR_CODES.NOT_FOUND,
409: ERROR_CODES.CONFLICT,
500: ERROR_CODES.INTERNAL_ERROR,
};
const FRIENDLY_MESSAGES = {
[ERROR_CODES.BAD_REQUEST]: '请求参数错误,请检查输入',
[ERROR_CODES.UNAUTHORIZED]: '未授权访问,请先登录',
[ERROR_CODES.FORBIDDEN]: '无权执行此操作',
[ERROR_CODES.NOT_FOUND]: '请求的资源不存在',
[ERROR_CODES.CONFLICT]: '数据冲突,请刷新后重试',
[ERROR_CODES.VALIDATION_ERROR]: '数据验证失败',
[ERROR_CODES.INTERNAL_ERROR]: '服务器内部错误,请稍后重试',
[ERROR_CODES.DATABASE_ERROR]: '数据库操作失败',
[ERROR_CODES.NETWORK_ERROR]: '网络连接错误',
};
function logError(error, req = null) {
const timestamp = new Date().toISOString();
const logData = {
timestamp,
message: error.message,
code: error.code,
statusCode: error.statusCode,
stack: error.stack,
details: error.details,
userAgent: req?.headers?.['user-agent'],
ip: req?.ip,
path: req?.path,
method: req?.method,
};
console.error('=== ERROR LOG ===');
console.error(JSON.stringify(logData, null, 2));
}
function buildErrorResponse(error) {
const code = error.code || STATUS_CODE_MAP[error.statusCode] || ERROR_CODES.INTERNAL_ERROR;
const message =
error.message || FRIENDLY_MESSAGES[code] || FRIENDLY_MESSAGES[ERROR_CODES.INTERNAL_ERROR];
const response = {
success: false,
error: {
code,
message,
},
};
if (error.details) {
response.error.details = error.details;
}
return response;
}
function createError(code, message, statusCode = 500, details = null) {
return new AppError(code, message, statusCode, details);
}
function sendErrorResponse(res, error, req = null) {
logError(error, req);
let statusCode = 500;
let appError = error;
if (!(error instanceof AppError)) {
if (error.name === 'SequelizeValidationError') {
statusCode = 400;
const details = error.errors.map(err => ({
field: err.path,
message: err.message,
}));
appError = createError(
ERROR_CODES.VALIDATION_ERROR,
FRIENDLY_MESSAGES[ERROR_CODES.VALIDATION_ERROR],
statusCode,
details
);
} else if (error.name === 'SequelizeUniqueConstraintError') {
statusCode = 409;
appError = createError(ERROR_CODES.CONFLICT, '数据已存在', statusCode);
} else {
statusCode = error.statusCode || 500;
appError = createError(
STATUS_CODE_MAP[statusCode] || ERROR_CODES.INTERNAL_ERROR,
FRIENDLY_MESSAGES[STATUS_CODE_MAP[statusCode] || ERROR_CODES.INTERNAL_ERROR],
statusCode,
process.env.NODE_ENV === 'development' ? error.stack : null
);
}
}
statusCode = appError.statusCode || statusCode;
res.status(statusCode).json(buildErrorResponse(appError));
}
function errorHandlerMiddleware(err, req, res, next) {
sendErrorResponse(res, err, req);
}
module.exports = {
AppError,
ERROR_CODES,
createError,
logError,
buildErrorResponse,
sendErrorResponse,
errorHandlerMiddleware,
};