Files
2025-09-04 10:49:10 +08:00

230 lines
8.0 KiB
JavaScript

const Joi = require('joi');
const { AppError } = require('./errorHandler');
const { ERROR_CODES, HTTP_STATUS } = require('../config/constants');
// 验证中间件工厂函数
const validate = (schema) => {
return (req, res, next) => {
const { error } = schema.validate(req.body, { abortEarly: false });
if (error) {
const errorMessage = error.details.map(detail => detail.message).join(', ');
return next(new AppError(errorMessage, HTTP_STATUS.BAD_REQUEST, ERROR_CODES.VALIDATION_ERROR));
}
next();
};
};
// 查询参数验证中间件
const validateQuery = (schema) => {
return (req, res, next) => {
const { error } = schema.validate(req.query, { abortEarly: false });
if (error) {
const errorMessage = error.details.map(detail => detail.message).join(', ');
return next(new AppError(errorMessage, HTTP_STATUS.BAD_REQUEST, ERROR_CODES.VALIDATION_ERROR));
}
next();
};
};
// 路径参数验证中间件
const validateParams = (schema) => {
return (req, res, next) => {
const { error } = schema.validate(req.params, { abortEarly: false });
if (error) {
const errorMessage = error.details.map(detail => detail.message).join(', ');
return next(new AppError(errorMessage, HTTP_STATUS.BAD_REQUEST, ERROR_CODES.VALIDATION_ERROR));
}
next();
};
};
// 通用验证规则
const commonSchemas = {
// ID验证
id: Joi.number().integer().positive().required().messages({
'number.base': 'ID必须是数字',
'number.integer': 'ID必须是整数',
'number.positive': 'ID必须是正数',
'any.required': 'ID是必需的'
}),
// 分页验证
pagination: Joi.object({
page: Joi.number().integer().min(1).default(1).messages({
'number.base': '页码必须是数字',
'number.integer': '页码必须是整数',
'number.min': '页码必须大于0'
}),
limit: Joi.number().integer().min(1).max(100).default(10).messages({
'number.base': '每页数量必须是数字',
'number.integer': '每页数量必须是整数',
'number.min': '每页数量必须大于0',
'number.max': '每页数量不能超过100'
})
})
};
// 用户相关验证规则
const userSchemas = {
// 用户注册
register: Joi.object({
username: Joi.string().alphanum().min(3).max(30).required().messages({
'string.base': '用户名必须是字符串',
'string.alphanum': '用户名只能包含字母和数字',
'string.min': '用户名至少3个字符',
'string.max': '用户名最多30个字符',
'any.required': '用户名是必需的'
}),
password: Joi.string().min(6).max(128).required().messages({
'string.base': '密码必须是字符串',
'string.min': '密码至少6个字符',
'string.max': '密码最多128个字符',
'any.required': '密码是必需的'
}),
phone: Joi.string().pattern(/^1[3-9]\d{9}$/).required().messages({
'string.pattern.base': '手机号格式不正确',
'any.required': '手机号是必需的'
}),
// 可选字段,注册时不需要填写
real_name: Joi.string().max(50).allow('').optional().messages({
'string.max': '真实姓名最多50个字符'
}),
role: Joi.string().valid('admin', 'user').default('user').messages({
'any.only': '角色只能是admin或user'
})
}),
// 用户登录
login: Joi.object({
username: Joi.string().required().messages({
'any.required': '用户名是必需的'
}),
password: Joi.string().required().messages({
'any.required': '密码是必需的'
})
})
};
// 转账相关验证规则
const transferSchemas = {
// 转账查询参数
query: Joi.object({
page: Joi.number().integer().min(1).default(1).messages({
'number.base': '页码必须是数字',
'number.integer': '页码必须是整数',
'number.min': '页码必须大于0'
}),
limit: Joi.number().integer().min(1).max(100).default(10).messages({
'number.base': '每页数量必须是数字',
'number.integer': '每页数量必须是整数',
'number.min': '每页数量必须大于0',
'number.max': '每页数量不能超过100'
}),
status: Joi.string().valid('pending', 'confirmed', 'rejected', 'cancelled').allow('').messages({
'any.only': '状态值无效'
}),
type: Joi.string().valid('user_to_user', 'system_to_user', 'user_to_system').allow('').messages({
'any.only': '转账类型无效'
}),
search: Joi.string().allow('').max(100).messages({
'string.max': '搜索关键词最多100个字符'
}),
transfer_type: Joi.string().valid('user_to_user', 'system_to_user', 'user_to_system').allow('').messages({
'any.only': '转账类型无效'
}),
start_date: Joi.date().iso().allow('').messages({
'date.format': '开始日期格式不正确'
}),
end_date: Joi.date().iso().allow('').messages({
'date.format': '结束日期格式不正确'
}),
sort: Joi.string().valid('id', 'amount', 'created_at', 'updated_at', 'status').allow('').messages({
'any.only': '排序字段无效,只支持: id, amount, created_at, updated_at, status'
}),
order: Joi.string().valid('asc', 'desc').allow('').messages({
'any.only': '排序方向无效,只支持: asc, desc'
}),
// 优先显示待处理转账参数
show_pending: Joi.alternatives().try(
Joi.boolean(),
Joi.string().valid('true', 'false', '')
).allow('').messages({
'alternatives.match': 'show_pending参数只能是布尔值或字符串true/false'
})
}),
// 创建转账
create: Joi.object({
to_user_id: Joi.number().integer().positive().required().messages({
'number.base': '收款用户ID必须是数字',
'number.integer': '收款用户ID必须是整数',
'number.positive': '收款用户ID必须是正数',
'any.required': '收款用户ID是必需的'
}),
amount: Joi.number().positive().precision(2).required().messages({
'number.base': '金额必须是数字',
'number.positive': '金额必须是正数',
'any.required': '金额是必需的'
}),
transfer_type: Joi.string().valid('user_to_user', 'system_to_user', 'user_to_system').required().messages({
'any.only': '转账类型无效',
'any.required': '转账类型是必需的'
}),
description: Joi.string().max(500).allow('').messages({
'string.max': '描述最多500个字符'
}),
voucher_url: Joi.string().uri().allow('').messages({
'string.uri': '凭证URL格式不正确'
})
}),
// 确认转账
confirm: Joi.object({
transfer_id: Joi.number().integer().positive().required().messages({
'number.base': '转账ID必须是数字',
'number.integer': '转账ID必须是整数',
'number.positive': '转账ID必须是正数',
'any.required': '转账ID是必需的'
}),
note: Joi.string().max(500).allow('').messages({
'string.max': '备注最多500个字符'
})
}),
// 拒绝转账
reject: Joi.object({
transfer_id: Joi.number().integer().positive().required().messages({
'number.base': '转账ID必须是数字',
'number.integer': '转账ID必须是整数',
'number.positive': '转账ID必须是正数',
'any.required': '转账ID是必需的'
}),
note: Joi.string().max(500).allow('').messages({
'string.max': '备注最多500个字符'
})
})
};
// 系统设置相关验证规则
const systemSchemas = {
updateSettings: Joi.object({
site_name: Joi.string().max(100).optional(),
site_description: Joi.string().max(500).optional(),
contact_phone: Joi.string().max(20).optional(),
maintenance_mode: Joi.boolean().optional(),
max_transfer_amount: Joi.number().positive().optional(),
min_transfer_amount: Joi.number().positive().optional(),
transfer_fee_rate: Joi.number().min(0).max(1).optional()
})
};
// 导出所有验证规则
module.exports = {
validate,
validateQuery,
validateParams,
commonSchemas,
userSchemas,
transferSchemas,
systemSchemas
};