refactor(backend): 重构动物相关 API 接口

- 更新了动物数据结构和相关类型定义
- 优化了动物列表、详情、创建、更新和删除接口
- 新增了更新动物状态接口
- 移除了与认领记录相关的接口
-调整了 API 响应结构
This commit is contained in:
ylweng
2025-08-31 00:45:46 +08:00
parent 0cad74b06f
commit 8e5295b572
111 changed files with 15290 additions and 1972 deletions

View File

@@ -0,0 +1,225 @@
// 管理员控制器
const Admin = require('../../models/admin');
const AdminService = require('../../services/admin');
const jwt = require('jsonwebtoken');
const { query } = require('../../config/database');
// 生成JWT token
const generateToken = (admin) => {
return jwt.sign(
{ id: admin.id, username: admin.username, role: admin.role },
process.env.JWT_SECRET || 'admin-secret-key',
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
);
};
// 管理员登录
exports.login = async (req, res, next) => {
try {
const { username, password } = req.body;
// 验证输入
if (!username || !password) {
return res.status(400).json({
success: false,
code: 400,
message: '用户名和密码不能为空'
});
}
// 查找管理员
const admin = await Admin.findByUsername(username);
if (!admin) {
return res.status(401).json({
success: false,
code: 401,
message: '用户名或密码错误'
});
}
// 验证密码
const isPasswordValid = await admin.verifyPassword(password);
if (!isPasswordValid) {
return res.status(401).json({
success: false,
code: 401,
message: '用户名或密码错误'
});
}
// 更新最后登录时间
await admin.updateLastLogin();
// 生成token
const token = generateToken(admin);
res.status(200).json({
success: true,
code: 200,
message: '登录成功',
data: {
admin: admin.toSafeObject(),
token
}
});
} catch (error) {
next(error);
}
};
// 获取当前管理员信息
exports.getProfile = async (req, res, next) => {
try {
const admin = await Admin.findById(req.admin.id);
if (!admin) {
return res.status(404).json({
success: false,
code: 404,
message: '管理员不存在'
});
}
res.status(200).json({
success: true,
code: 200,
message: '获取成功',
data: {
admin: admin.toSafeObject()
}
});
} catch (error) {
next(error);
}
};
// 获取管理员列表
exports.getList = async (req, res, next) => {
try {
const result = await AdminService.getAdminList(req.query);
res.status(200).json({
success: true,
code: 200,
message: '获取成功',
data: result
});
} catch (error) {
next(error);
}
};
// 创建管理员
exports.create = async (req, res, next) => {
try {
const { username, password, email, nickname, role } = req.body;
// 验证必填字段
if (!username || !password) {
return res.status(400).json({
success: false,
code: 400,
message: '用户名和密码不能为空'
});
}
// 创建管理员
const adminData = {
username,
password,
email: email || null,
nickname: nickname || null,
role: role || 'admin',
status: 1
};
const admin = await AdminService.createAdmin(adminData);
res.status(201).json({
success: true,
code: 201,
message: '创建成功',
data: {
admin
}
});
} catch (error) {
if (error.message === '用户名已存在') {
return res.status(409).json({
success: false,
code: 409,
message: '用户名已存在'
});
}
next(error);
}
};
// 更新管理员
exports.update = async (req, res, next) => {
try {
const { id } = req.params;
const updateData = req.body;
// 不能修改自己角色
if (req.admin.id == id && updateData.role) {
return res.status(400).json({
success: false,
code: 400,
message: '不能修改自己的角色'
});
}
const admin = await AdminService.updateAdmin(id, updateData);
res.status(200).json({
success: true,
code: 200,
message: '更新成功',
data: {
admin
}
});
} catch (error) {
if (error.message === '管理员不存在') {
return res.status(404).json({
success: false,
code: 404,
message: '管理员不存在'
});
}
next(error);
}
};
// 删除管理员
exports.delete = async (req, res, next) => {
try {
const { id } = req.params;
// 不能删除自己
if (req.admin.id == id) {
return res.status(400).json({
success: false,
code: 400,
message: '不能删除自己'
});
}
await AdminService.deleteAdmin(id);
res.status(200).json({
success: true,
code: 200,
message: '删除成功'
});
} catch (error) {
if (error.message === '管理员不存在') {
return res.status(404).json({
success: false,
code: 404,
message: '管理员不存在'
});
}
next(error);
}
};

View File

@@ -0,0 +1,166 @@
const AnimalService = require('../../services/animal');
const { success } = require('../../utils/response');
const { AppError } = require('../../utils/errors');
class AnimalController {
// 获取动物列表
static async getAnimals(req, res, next) {
try {
const { page, pageSize, species, status } = req.query;
const result = await AnimalService.getAnimals({
merchantId: req.userId,
page: parseInt(page) || 1,
pageSize: parseInt(pageSize) || 10,
species,
status
});
res.json(success(result));
} catch (error) {
next(error);
}
}
// 获取单个动物详情
static async getAnimal(req, res, next) {
try {
const { animalId } = req.params;
if (!animalId) {
throw new AppError('动物ID不能为空', 400);
}
const animal = await AnimalService.getAnimalById(animalId);
res.json(success({ animal }));
} catch (error) {
next(error);
}
}
// 创建动物
static async createAnimal(req, res, next) {
try {
const {
name,
species,
breed,
age,
gender,
price,
description,
images,
health_status,
vaccination_status
} = req.body;
// 验证必要字段
if (!name || !species || !price) {
throw new AppError('缺少必要字段: name, species, price', 400);
}
const animalData = {
merchant_id: req.userId,
name,
species,
breed: breed || null,
age: age || null,
gender: gender || null,
price: parseFloat(price),
description: description || null,
images: images || null,
health_status: health_status || null,
vaccination_status: vaccination_status || null,
status: 'available'
};
const animal = await AnimalService.createAnimal(animalData);
res.status(201).json(success({ animal }));
} catch (error) {
next(error);
}
}
// 更新动物信息
static async updateAnimal(req, res, next) {
try {
const { animalId } = req.params;
const updateData = req.body;
if (!animalId) {
throw new AppError('动物ID不能为空', 400);
}
const animal = await AnimalService.updateAnimal(animalId, updateData);
res.json(success({ animal }));
} catch (error) {
next(error);
}
}
// 删除动物
static async deleteAnimal(req, res, next) {
try {
const { animalId } = req.params;
if (!animalId) {
throw new AppError('动物ID不能为空', 400);
}
await AnimalService.deleteAnimal(animalId);
res.json(success({ message: '动物删除成功' }));
} catch (error) {
next(error);
}
}
// 获取动物统计信息
static async getAnimalStatistics(req, res, next) {
try {
const statistics = await AnimalService.getAnimalStatistics();
res.json(success({ statistics }));
} catch (error) {
next(error);
}
}
// 搜索动物
static async searchAnimals(req, res, next) {
try {
const { keyword, species, minPrice, maxPrice, page, pageSize } = req.query;
const result = await AnimalService.searchAnimals({
keyword,
species,
minPrice: minPrice ? parseFloat(minPrice) : null,
maxPrice: maxPrice ? parseFloat(maxPrice) : null,
page: parseInt(page) || 1,
pageSize: parseInt(pageSize) || 10
});
res.json(success(result));
} catch (error) {
next(error);
}
}
// 获取所有动物(管理员)
static async getAllAnimals(req, res, next) {
try {
const { page, pageSize, species, status } = req.query;
const result = await AnimalService.getAnimals({
page: parseInt(page) || 1,
pageSize: parseInt(pageSize) || 10,
species,
status
});
res.json(success(result));
} catch (error) {
next(error);
}
}
}
module.exports = AnimalController;

View File

@@ -39,8 +39,10 @@ const register = async (req, res, next) => {
// 创建新用户
const userId = await UserMySQL.create({
username,
password: hashedPassword,
nickname: nickname || username,
password_hash: hashedPassword,
user_type: 'farmer',
real_name: nickname || username,
avatar_url: '',
email,
phone
});
@@ -92,7 +94,7 @@ const login = async (req, res, next) => {
}
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password);
const isPasswordValid = await bcrypt.compare(password, user.password_hash);
if (!isPasswordValid) {
throw new AppError('密码错误', 401);
}
@@ -250,11 +252,66 @@ const wechatLogin = async (req, res, next) => {
}
};
// 管理员登录
const adminLogin = async (req, res, next) => {
try {
const { username, password } = req.body;
if (!username || !password) {
throw new AppError('用户名和密码不能为空', 400);
}
// 查找用户(支持用户名、邮箱、手机号登录)
let user = await UserMySQL.findByUsername(username);
if (!user) {
user = await UserMySQL.findByEmail(username);
}
if (!user) {
user = await UserMySQL.findByPhone(username);
}
if (!user) {
throw new AppError('用户不存在', 404);
}
// 检查用户状态
if (!UserMySQL.isActive(user)) {
throw new AppError('账户已被禁用', 403);
}
// 检查用户是否为管理员假设level >= 2为管理员
if (user.level < 2) {
throw new AppError('权限不足,需要管理员权限', 403);
}
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password_hash);
if (!isPasswordValid) {
throw new AppError('密码错误', 401);
}
// 生成token
const token = generateToken(user.id);
// 更新最后登录时间
await UserMySQL.updateLastLogin(user.id);
res.json(success({
user: UserMySQL.sanitize(user),
token,
message: '管理员登录成功'
}));
} catch (error) {
next(error);
}
};
module.exports = {
register,
login,
getCurrentUser,
updateProfile,
changePassword,
wechatLogin
wechatLogin,
adminLogin
};

View File

@@ -0,0 +1,402 @@
const OrderService = require('../../services/order');
/**
* 创建订单
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function createOrder(req, res, next) {
try {
const orderData = req.body;
const userId = req.user.id;
// 验证必要字段
if (!orderData.animal_id || !orderData.merchant_id || !orderData.total_amount) {
return res.status(400).json({
success: false,
message: '缺少必要字段: animal_id, merchant_id, total_amount'
});
}
const order = await OrderService.createOrder(orderData, userId);
res.status(201).json({
success: true,
data: {
order,
message: '订单创建成功'
}
});
} catch (error) {
console.error('创建订单控制器错误:', error);
next(error);
}
}
/**
* 获取订单详情
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function getOrder(req, res, next) {
try {
const { orderId } = req.params;
const userId = req.user.id;
const order = await OrderService.getOrderById(orderId);
// 检查权限:用户只能查看自己的订单,商家只能查看自己店铺的订单
if (req.user.role === 'user' && order.user_id !== userId) {
return res.status(403).json({
success: false,
message: '无权访问此订单'
});
}
if (req.user.role === 'merchant' && order.merchant_id !== req.user.merchant_id) {
return res.status(403).json({
success: false,
message: '无权访问此订单'
});
}
res.json({
success: true,
data: order
});
} catch (error) {
console.error('获取订单详情控制器错误:', error);
if (error.message === '订单不存在') {
return res.status(404).json({
success: false,
message: '订单不存在'
});
}
res.status(500).json({
success: false,
message: error.message || '获取订单详情失败'
});
}
}
/**
* 获取用户订单列表
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function getUserOrders(req, res, next) {
try {
const userId = req.user.id;
const filters = {
page: req.query.page,
limit: req.query.limit,
status: req.query.status
};
const result = await OrderService.getUserOrders(userId, filters);
res.json({
success: true,
data: result.orders,
pagination: result.pagination
});
} catch (error) {
console.error('获取用户订单列表控制器错误:', error);
res.status(500).json({
success: false,
message: error.message || '获取订单列表失败'
});
}
}
/**
* 获取商家订单列表
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function getMerchantOrders(req, res, next) {
try {
const merchantId = req.user.merchant_id;
const filters = {
page: req.query.page,
limit: req.query.limit,
status: req.query.status
};
const result = await OrderService.getMerchantOrders(merchantId, filters);
res.json({
success: true,
data: result.orders,
pagination: result.pagination
});
} catch (error) {
console.error('获取商家订单列表控制器错误:', error);
res.status(500).json({
success: false,
message: error.message || '获取订单列表失败'
});
}
}
/**
* 取消订单
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function cancelOrder(req, res, next) {
try {
const { orderId } = req.params;
const userId = req.user.id;
const order = await OrderService.cancelOrder(orderId, userId);
res.json({
success: true,
message: '订单取消成功',
data: order
});
} catch (error) {
console.error('取消订单控制器错误:', error);
if (error.message === '订单不存在') {
return res.status(404).json({
success: false,
message: '订单不存在'
});
}
if (error.message === '无权操作此订单') {
return res.status(403).json({
success: false,
message: '无权操作此订单'
});
}
if (error.message === '订单状态不允许取消') {
return res.status(400).json({
success: false,
message: '订单状态不允许取消'
});
}
res.status(500).json({
success: false,
message: error.message || '取消订单失败'
});
}
}
/**
* 支付订单
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function payOrder(req, res, next) {
try {
const { orderId } = req.params;
const userId = req.user.id;
const paymentData = req.body;
// 验证必要字段
if (!paymentData.payment_method) {
return res.status(400).json({
success: false,
message: '缺少必要字段: payment_method'
});
}
const order = await OrderService.payOrder(orderId, userId, paymentData);
res.json({
success: true,
message: '订单支付成功',
data: order
});
} catch (error) {
console.error('支付订单控制器错误:', error);
if (error.message === '订单不存在') {
return res.status(404).json({
success: false,
message: '订单不存在'
});
}
if (error.message === '无权操作此订单') {
return res.status(403).json({
success: false,
message: '无权操作此订单'
});
}
if (error.message === '订单状态不允许支付') {
return res.status(400).json({
success: false,
message: '订单状态不允许支付'
});
}
res.status(500).json({
success: false,
message: error.message || '支付订单失败'
});
}
}
/**
* 获取订单统计信息
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function getOrderStatistics(req, res, next) {
try {
const userId = req.user.id;
const statistics = await OrderService.getOrderStatistics(userId);
res.json({
success: true,
data: statistics
});
} catch (error) {
console.error('获取订单统计信息控制器错误:', error);
res.status(500).json({
success: false,
message: error.message || '获取统计信息失败'
});
}
}
/**
* 获取所有订单(管理员)
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function getAllOrders(req, res, next) {
try {
const filters = {
page: req.query.page,
limit: req.query.limit,
status: req.query.status
};
const result = await OrderService.getAllOrders(filters);
res.json({
success: true,
data: result.orders,
pagination: result.pagination
});
} catch (error) {
console.error('获取所有订单控制器错误:', error);
res.status(500).json({
success: false,
message: error.message || '获取所有订单失败'
});
}
}
/**
* 更新订单状态
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function updateOrderStatus(req, res, next) {
try {
const { orderId } = req.params;
const { status } = req.body;
const userId = req.user.id;
const order = await OrderService.updateOrderStatus(orderId, status, userId);
res.json({
success: true,
message: '订单状态更新成功',
data: order
});
} catch (error) {
console.error('更新订单状态控制器错误:', error);
if (error.message === '订单不存在') {
return res.status(404).json({
success: false,
message: '订单不存在'
});
}
if (error.message === '无权操作此订单') {
return res.status(403).json({
success: false,
message: '无权操作此订单'
});
}
res.status(500).json({
success: false,
message: error.message || '更新订单状态失败'
});
}
}
/**
* 删除订单
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function deleteOrder(req, res, next) {
try {
const { orderId } = req.params;
const userId = req.user.id;
await OrderService.deleteOrder(orderId, userId);
res.json({
success: true,
message: '订单删除成功'
});
} catch (error) {
console.error('删除订单控制器错误:', error);
if (error.message === '订单不存在') {
return res.status(404).json({
success: false,
message: '订单不存在'
});
}
if (error.message === '无权操作此订单') {
return res.status(403).json({
success: false,
message: '无权操作此订单'
});
}
res.status(500).json({
success: false,
message: error.message || '删除订单失败'
});
}
}
/**
* 获取商家统计信息
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
async function getMerchantStats(req, res, next) {
try {
const merchantId = req.user.merchant_id;
const stats = await OrderService.getMerchantStats(merchantId);
res.json({
success: true,
data: stats
});
} catch (error) {
console.error('获取商家统计信息控制器错误:', error);
res.status(500).json({
success: false,
message: error.message || '获取统计信息失败'
});
}
}
module.exports = {
createOrder,
getOrder,
getUserOrders,
getMerchantOrders,
cancelOrder,
payOrder,
getOrderStatistics,
getAllOrders,
updateOrderStatus,
deleteOrder,
getMerchantStats
};

View File

@@ -0,0 +1,152 @@
const TravelService = require('../../services/travel');
const { success } = require('../../utils/response');
const { AppError } = require('../../utils/errors');
class TravelController {
// 获取旅行计划列表
static async getTravelPlans(req, res, next) {
try {
const { page, pageSize, status } = req.query;
const result = await TravelService.getTravelPlans({
userId: req.userId,
page: parseInt(page) || 1,
pageSize: parseInt(pageSize) || 10,
status
});
res.json(success(result));
} catch (error) {
next(error);
}
}
// 获取单个旅行计划详情
static async getTravelPlan(req, res, next) {
try {
const { planId } = req.params;
if (!planId) {
throw new AppError('旅行计划ID不能为空', 400);
}
const plan = await TravelService.getTravelPlanById(planId);
res.json(success({ plan }));
} catch (error) {
next(error);
}
}
// 创建旅行计划
static async createTravelPlan(req, res, next) {
try {
const {
destination,
start_date,
end_date,
budget,
companions,
transportation,
accommodation,
activities,
notes
} = req.body;
if (!destination || !start_date || !end_date) {
throw new AppError('目的地、开始日期和结束日期不能为空', 400);
}
const planId = await TravelService.createTravelPlan(req.userId, {
destination,
start_date,
end_date,
budget,
companions,
transportation,
accommodation,
activities,
notes
});
const plan = await TravelService.getTravelPlanById(planId);
res.status(201).json(success({
plan,
message: '旅行计划创建成功'
}));
} catch (error) {
next(error);
}
}
// 更新旅行计划
static async updateTravelPlan(req, res, next) {
try {
const { planId } = req.params;
if (!planId) {
throw new AppError('旅行计划ID不能为空', 400);
}
const plan = await TravelService.updateTravelPlan(planId, req.userId, req.body);
res.json(success({
plan,
message: '旅行计划更新成功'
}));
} catch (error) {
next(error);
}
}
// 删除旅行计划
static async deleteTravelPlan(req, res, next) {
try {
const { planId } = req.params;
if (!planId) {
throw new AppError('旅行计划ID不能为空', 400);
}
await TravelService.deleteTravelPlan(planId, req.userId);
res.json(success({
message: '旅行计划删除成功',
planId: parseInt(planId)
}));
} catch (error) {
next(error);
}
}
// 获取用户旅行统计
static async getTravelStats(req, res, next) {
try {
const stats = await TravelService.getUserTravelStats(req.userId);
res.json(success({ stats }));
} catch (error) {
next(error);
}
}
// 获取所有旅行计划(管理员功能)
static async getAllTravelPlans(req, res, next) {
try {
const { page, pageSize, status, userId } = req.query;
const result = await TravelService.getTravelPlans({
userId,
page: parseInt(page) || 1,
pageSize: parseInt(pageSize) || 10,
status
});
res.json(success(result));
} catch (error) {
next(error);
}
}
}
module.exports = TravelController;

View File

@@ -0,0 +1,129 @@
const UserService = require('../../services/user');
const { success } = require('../../utils/response');
const { AppError } = require('../../utils/errors');
class UserController {
// 获取用户详情
static async getUserProfile(req, res, next) {
try {
const user = await UserService.getUserProfile(req.userId);
res.json(success({ user }));
} catch (error) {
next(error);
}
}
// 更新用户信息
static async updateProfile(req, res, next) {
try {
const user = await UserService.updateUserProfile(req.userId, req.body);
res.json(success({
user,
message: '个人信息更新成功'
}));
} catch (error) {
next(error);
}
}
// 搜索用户(管理员功能)
static async searchUsers(req, res, next) {
try {
const result = await UserService.searchUsers(req.query);
res.json(success(result));
} catch (error) {
next(error);
}
}
// 获取用户统计信息(管理员功能)
static async getUserStatistics(req, res, next) {
try {
const stats = await UserService.getUserStatistics();
res.json(success({ statistics: stats }));
} catch (error) {
next(error);
}
}
// 批量操作用户状态(管理员功能)
static async batchUpdateUserStatus(req, res, next) {
try {
const { userIds, status } = req.body;
if (!userIds || !Array.isArray(userIds) || userIds.length === 0) {
throw new AppError('请选择要操作的用户', 400);
}
if (!status || !['active', 'inactive'].includes(status)) {
throw new AppError('无效的状态值', 400);
}
const affectedRows = await UserService.batchUpdateUserStatus(userIds, status);
res.json(success({
message: `成功更新 ${affectedRows} 个用户状态`,
affectedRows
}));
} catch (error) {
next(error);
}
}
// 获取用户列表(管理员功能)
static async getUsers(req, res, next) {
try {
const { page = 1, pageSize = 10, userType, status } = req.query;
const result = await UserService.searchUsers({
page: parseInt(page),
pageSize: parseInt(pageSize),
userType,
status,
keyword: req.query.keyword
});
res.json(success(result));
} catch (error) {
next(error);
}
}
// 获取单个用户详情(管理员功能)
static async getUserById(req, res, next) {
try {
const { userId } = req.params;
if (!userId) {
throw new AppError('用户ID不能为空', 400);
}
const user = await UserService.getUserProfile(userId);
res.json(success({ user }));
} catch (error) {
next(error);
}
}
// 删除用户(管理员功能)
static async deleteUser(req, res, next) {
try {
const { userId } = req.params;
if (!userId) {
throw new AppError('用户ID不能为空', 400);
}
// 这里需要实现软删除逻辑
// 暂时先返回成功消息
res.json(success({
message: '用户删除成功',
userId
}));
} catch (error) {
next(error);
}
}
}
module.exports = UserController;