230 lines
8.0 KiB
JavaScript
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
|
|
}; |