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,158 @@
const database = require('../../config/database');
const Admin = require('../../models/admin');
class AdminService {
/**
* 获取管理员列表
* @param {Object} filters - 筛选条件
* @returns {Promise<Object>} 管理员列表和分页信息
*/
async getAdminList(filters = {}) {
try {
const { page = 1, pageSize = 10, username, role, status } = filters;
const offset = (parseInt(page) - 1) * parseInt(pageSize);
// 构建查询条件
let whereClause = 'WHERE 1=1';
const params = [];
if (username) {
whereClause += ' AND username LIKE ?';
params.push(`%${username}%`);
}
if (role) {
whereClause += ' AND role = ?';
params.push(role);
}
if (status !== undefined) {
whereClause += ' AND status = ?';
params.push(status);
}
// 查询总数
const countSql = `SELECT COUNT(*) as total FROM admins ${whereClause}`;
const [countResult] = await database.query(countSql, params);
const total = countResult.total;
// 查询数据
const sql = `
SELECT id, username, email, nickname, avatar, role, status, last_login, created_at, updated_at
FROM admins
${whereClause}
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`;
params.push(parseInt(pageSize), offset);
const admins = await database.query(sql, params);
return {
admins,
pagination: {
page: parseInt(page),
pageSize: parseInt(pageSize),
total,
totalPages: Math.ceil(total / parseInt(pageSize))
}
};
} catch (error) {
console.error('获取管理员列表失败:', error);
throw new Error('获取管理员列表失败');
}
}
/**
* 创建管理员
* @param {Object} adminData - 管理员数据
* @returns {Promise<Object>} 创建的管理员
*/
async createAdmin(adminData) {
try {
// 检查用户名是否已存在
const existingAdmin = await this.getAdminByUsername(adminData.username);
if (existingAdmin) {
throw new Error('用户名已存在');
}
// 创建管理员
const admin = await Admin.create(adminData);
return admin.toSafeObject();
} catch (error) {
console.error('创建管理员失败:', error);
throw error;
}
}
/**
* 根据用户名获取管理员
* @param {string} username - 用户名
* @returns {Promise<Object|null>} 管理员信息
*/
async getAdminByUsername(username) {
try {
return await Admin.findByUsername(username);
} catch (error) {
console.error('获取管理员失败:', error);
throw new Error('获取管理员失败');
}
}
/**
* 根据ID获取管理员
* @param {number} id - 管理员ID
* @returns {Promise<Object|null>} 管理员信息
*/
async getAdminById(id) {
try {
return await Admin.findById(id);
} catch (error) {
console.error('获取管理员失败:', error);
throw new Error('获取管理员失败');
}
}
/**
* 更新管理员信息
* @param {number} id - 管理员ID
* @param {Object} updateData - 更新数据
* @returns {Promise<Object>} 更新后的管理员信息
*/
async updateAdmin(id, updateData) {
try {
const admin = await Admin.findById(id);
if (!admin) {
throw new Error('管理员不存在');
}
await admin.update(updateData);
return admin.toSafeObject();
} catch (error) {
console.error('更新管理员失败:', error);
throw error;
}
}
/**
* 删除管理员
* @param {number} id - 管理员ID
* @returns {Promise<boolean>} 是否删除成功
*/
async deleteAdmin(id) {
try {
const admin = await Admin.findById(id);
if (!admin) {
throw new Error('管理员不存在');
}
await admin.delete();
return true;
} catch (error) {
console.error('删除管理员失败:', error);
throw error;
}
}
}
module.exports = new AdminService();

View File

@@ -0,0 +1,262 @@
const { query } = require('../../config/database');
const { AppError } = require('../../utils/errors');
class AnimalService {
// 获取动物列表
static async getAnimals(searchParams) {
try {
const { merchantId, species, status, page = 1, pageSize = 10 } = searchParams;
const offset = (page - 1) * pageSize;
let sql = `
SELECT a.*, m.business_name as merchant_name, m.merchant_type, u.nickname as username, u.nickname as real_name
FROM animals a
INNER JOIN merchants m ON a.merchant_id = m.id
INNER JOIN users u ON m.user_id = u.id
WHERE 1=1
`;
const params = [];
if (merchantId) {
sql += ' AND a.merchant_id = ?';
params.push(merchantId);
}
if (species) {
sql += ' AND a.species = ?';
params.push(species);
}
if (status) {
sql += ' AND a.status = ?';
params.push(status);
}
// 获取总数
const countSql = `SELECT COUNT(*) as total FROM (${sql}) as count_query`;
const countResult = await query(countSql, params);
const total = countResult[0].total;
// 添加分页和排序
sql += ' ORDER BY a.created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const animals = await query(sql, params);
return {
animals,
pagination: {
page,
pageSize,
total,
totalPages: Math.ceil(total / pageSize)
}
};
} catch (error) {
throw error;
}
}
// 获取单个动物详情
static async getAnimalById(animalId) {
try {
const sql = `
SELECT a.*, m.business_name as merchant_name, m.merchant_type, m.contact_person as contact_info, u.nickname as username, u.nickname as real_name, u.avatar
FROM animals a
INNER JOIN merchants m ON a.merchant_id = m.id
INNER JOIN users u ON m.user_id = u.id
WHERE a.id = ?
`;
const params = [animalId];
const result = await query(sql, params);
if (result.length === 0) {
throw new AppError('动物不存在', 404);
}
return result[0];
} catch (error) {
throw error;
}
}
// 创建动物
static async createAnimal(animalData) {
try {
const sql = `
INSERT INTO animals (
merchant_id, name, species, breed, birth_date, personality, farm_location, price, status
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
const params = [
animalData.merchant_id,
animalData.name,
animalData.species,
animalData.breed,
animalData.birth_date,
animalData.personality,
animalData.farm_location,
animalData.price,
animalData.status || 'available'
];
const result = await query(sql, params);
const animalId = result.insertId;
return await this.getAnimalById(animalId);
} catch (error) {
throw error;
}
}
// 更新动物信息
static async updateAnimal(animalId, updateData) {
try {
// 构建动态更新语句
const fields = [];
const params = [];
Object.keys(updateData).forEach(key => {
// 只允许更新特定字段
const allowedFields = ['name', 'species', 'breed', 'birth_date', 'personality', 'farm_location', 'price', 'status'];
if (allowedFields.includes(key)) {
fields.push(`${key} = ?`);
params.push(updateData[key]);
}
});
if (fields.length === 0) {
throw new AppError('没有提供可更新的字段', 400);
}
params.push(animalId); // 为WHERE条件添加ID
const sql = `UPDATE animals SET ${fields.join(', ')} WHERE id = ?`;
await query(sql, params);
return await this.getAnimalById(animalId);
} catch (error) {
throw error;
}
}
// 删除动物
static async deleteAnimal(animalId) {
try {
const sql = 'DELETE FROM animals WHERE id = ?';
const params = [animalId];
await query(sql, params);
} catch (error) {
throw error;
}
}
// 获取动物统计信息
static async getAnimalStatistics() {
try {
// 获取动物总数
const totalSql = 'SELECT COUNT(*) as total FROM animals';
const [totalResult] = await query(totalSql);
const totalAnimals = totalResult.total;
// 按物种统计
const speciesSql = `
SELECT species, COUNT(*) as count
FROM animals
GROUP BY species
ORDER BY count DESC
`;
const speciesStats = await query(speciesSql);
// 按状态统计
const statusSql = `
SELECT status, COUNT(*) as count
FROM animals
GROUP BY status
`;
const statusStats = await query(statusSql);
// 按商家统计前5名
const merchantSql = `
SELECT m.business_name as merchant_name, COUNT(a.id) as animal_count
FROM merchants m
LEFT JOIN animals a ON m.id = a.merchant_id
GROUP BY m.id, m.business_name
ORDER BY animal_count DESC
LIMIT 5
`;
const merchantStats = await query(merchantSql);
return {
total: totalAnimals,
bySpecies: speciesStats,
byStatus: statusStats,
topMerchants: merchantStats
};
} catch (error) {
throw error;
}
}
// 搜索动物
static async searchAnimals(searchParams) {
try {
const { keyword, species, minPrice, maxPrice, page = 1, pageSize = 10 } = searchParams;
const offset = (page - 1) * pageSize;
let sql = `
SELECT a.*, m.business_name as merchant_name, m.merchant_type, u.nickname as username, u.nickname as real_name
FROM animals a
INNER JOIN merchants m ON a.merchant_id = m.id
INNER JOIN users u ON m.user_id = u.id
WHERE a.status = 'available'
`;
const params = [];
if (keyword) {
sql += ' AND (a.name LIKE ? OR a.personality LIKE ? OR a.species LIKE ?)';
params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`);
}
if (species) {
sql += ' AND a.species = ?';
params.push(species);
}
if (minPrice !== null) {
sql += ' AND a.price >= ?';
params.push(minPrice);
}
if (maxPrice !== null) {
sql += ' AND a.price <= ?';
params.push(maxPrice);
}
// 获取总数
const countSql = `SELECT COUNT(*) as total FROM (${sql}) as count_query`;
const countResult = await query(countSql, params);
const total = countResult[0].total;
// 添加分页和排序
sql += ' ORDER BY a.created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const animals = await query(sql, params);
return {
animals,
pagination: {
page,
pageSize,
total,
totalPages: Math.ceil(total / pageSize)
}
};
} catch (error) {
throw error;
}
}
}
module.exports = AnimalService;

View File

@@ -0,0 +1,368 @@
const database = require('../../config/database');
class OrderService {
/**
* 创建订单
* @param {Object} orderData - 订单数据
* @param {number} userId - 用户ID
* @returns {Promise<Object>} 创建的订单
*/
async createOrder(orderData, userId) {
try {
const {
animal_id,
merchant_id,
total_amount,
payment_method,
shipping_address,
contact_info
} = orderData;
const query = `
INSERT INTO orders (
user_id, animal_id, merchant_id, total_amount,
payment_method, shipping_address, contact_info, status
) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')
`;
const params = [
userId, animal_id, merchant_id, total_amount,
payment_method, shipping_address, contact_info
];
const result = await database.query(query, params);
// 获取创建的订单详情
const order = await this.getOrderById(result.insertId);
return order;
} catch (error) {
console.error('创建订单失败:', error);
throw new Error('创建订单失败');
}
}
/**
* 根据ID获取订单
* @param {number} orderId - 订单ID
* @returns {Promise<Object>} 订单信息
*/
async getOrderById(orderId) {
try {
const query = `
SELECT
o.*,
a.name as animal_name,
a.species as animal_species,
a.price as animal_price,
u.username as user_name,
m.business_name as merchant_name
FROM orders o
LEFT JOIN animals a ON o.animal_id = a.id
LEFT JOIN users u ON o.user_id = u.id
LEFT JOIN merchants m ON o.merchant_id = m.id
WHERE o.id = ? AND o.is_deleted = 0
`;
const [order] = await database.query(query, [orderId]);
if (!order) {
throw new Error('订单不存在');
}
return order;
} catch (error) {
console.error('获取订单失败:', error);
throw error;
}
}
/**
* 获取用户订单列表
* @param {number} userId - 用户ID
* @param {Object} filters - 筛选条件
* @returns {Promise<Array>} 订单列表
*/
async getUserOrders(userId, filters = {}) {
try {
const { page = 1, pageSize = 10, status } = filters;
const offset = (page - 1) * pageSize;
let query = `
SELECT
o.*,
a.name as animal_name,
a.species as animal_species,
a.price as animal_price,
m.business_name as merchant_name
FROM orders o
LEFT JOIN animals a ON o.animal_id = a.id
LEFT JOIN merchants m ON o.merchant_id = m.id
WHERE o.user_id = ? AND o.is_deleted = 0
`;
let countQuery = `
SELECT COUNT(*) as total
FROM orders o
WHERE o.user_id = ? AND o.is_deleted = 0
`;
const params = [userId];
const countParams = [userId];
if (status) {
query += ' AND o.status = ?';
countQuery += ' AND o.status = ?';
params.push(status);
countParams.push(status);
}
query += ' ORDER BY o.created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const [orders] = await database.query(query, params);
const [totalResult] = await database.query(countQuery, countParams);
return {
orders,
pagination: {
page: parseInt(page),
pageSize: parseInt(pageSize),
total: totalResult.total,
totalPages: Math.ceil(totalResult.total / pageSize)
}
};
} catch (error) {
console.error('获取用户订单失败:', error);
throw new Error('获取用户订单失败');
}
}
/**
* 获取商家订单列表
* @param {number} merchantId - 商家ID
* @param {Object} filters - 筛选条件
* @returns {Promise<Array>} 订单列表
*/
async getMerchantOrders(merchantId, filters = {}) {
try {
const { page = 1, pageSize = 10, status } = filters;
const offset = (page - 1) * pageSize;
let query = `
SELECT
o.*,
a.name as animal_name,
a.species as animal_species,
a.price as animal_price,
u.username as user_name
FROM orders o
LEFT JOIN animals a ON o.animal_id = a.id
LEFT JOIN users u ON o.user_id = u.id
WHERE o.merchant_id = ? AND o.is_deleted = 0
`;
let countQuery = `
SELECT COUNT(*) as total
FROM orders o
WHERE o.merchant_id = ? AND o.is_deleted = 0
`;
const params = [merchantId];
const countParams = [merchantId];
if (status) {
query += ' AND o.status = ?';
countQuery += ' AND o.status = ?';
params.push(status);
countParams.push(status);
}
query += ' ORDER BY o.created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const [orders] = await database.query(query, params);
const [totalResult] = await database.query(countQuery, countParams);
return {
orders,
pagination: {
page: parseInt(page),
pageSize: parseInt(pageSize),
total: totalResult.total,
totalPages: Math.ceil(totalResult.total / pageSize)
}
};
} catch (error) {
console.error('获取商家订单失败:', error);
throw new Error('获取商家订单失败');
}
}
/**
* 更新订单状态
* @param {number} orderId - 订单ID
* @param {string} status - 新状态
* @param {number} userId - 操作人ID
* @returns {Promise<Object>} 更新后的订单
*/
async updateOrderStatus(orderId, status, userId) {
try {
const validStatuses = ['pending', 'confirmed', 'shipped', 'delivered', 'cancelled'];
if (!validStatuses.includes(status)) {
throw new Error('无效的订单状态');
}
const query = `
UPDATE orders
SET status = ?, updated_by = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ? AND is_deleted = 0
`;
const result = await database.query(query, [status, userId, orderId]);
if (result.affectedRows === 0) {
throw new Error('订单不存在或已被删除');
}
return await this.getOrderById(orderId);
} catch (error) {
console.error('更新订单状态失败:', error);
throw error;
}
}
/**
* 删除订单(软删除)
* @param {number} orderId - 订单ID
* @param {number} userId - 用户ID
* @returns {Promise<boolean>} 是否删除成功
*/
async deleteOrder(orderId, userId) {
try {
const query = `
UPDATE orders
SET is_deleted = 1, deleted_by = ?, deleted_at = CURRENT_TIMESTAMP
WHERE id = ? AND is_deleted = 0
`;
const result = await database.query(query, [userId, orderId]);
return result.affectedRows > 0;
} catch (error) {
console.error('删除订单失败:', error);
throw new Error('删除订单失败');
}
}
/**
* 获取订单统计信息
* @param {number} merchantId - 商家ID
* @returns {Promise<Object>} 统计信息
*/
async getOrderStats(merchantId) {
try {
const query = `
SELECT
COUNT(*) as total_orders,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_orders,
SUM(CASE WHEN status = 'confirmed' THEN 1 ELSE 0 END) as confirmed_orders,
SUM(CASE WHEN status = 'shipped' THEN 1 ELSE 0 END) as shipped_orders,
SUM(CASE WHEN status = 'delivered' THEN 1 ELSE 0 END) as delivered_orders,
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) as cancelled_orders,
SUM(total_amount) as total_revenue
FROM orders
WHERE merchant_id = ? AND is_deleted = 0
`;
const [stats] = await database.query(query, [merchantId]);
return stats;
} catch (error) {
console.error('获取订单统计失败:', error);
throw new Error('获取订单统计失败');
}
}
/**
* 获取所有订单(管理员)
* @param {Object} filters - 筛选条件
* @returns {Promise<Array>} 订单列表
*/
async getAllOrders(filters = {}) {
try {
const {
page = 1,
pageSize = 10,
status,
merchantId,
userId
} = filters;
const offset = (page - 1) * pageSize;
let query = `
SELECT
o.*,
a.name as animal_name,
a.species as animal_species,
u.username as user_name,
m.business_name as merchant_name
FROM orders o
LEFT JOIN animals a ON o.animal_id = a.id
LEFT JOIN users u ON o.user_id = u.id
LEFT JOIN merchants m ON o.merchant_id = m.id
WHERE o.is_deleted = 0
`;
let countQuery = `
SELECT COUNT(*) as total
FROM orders o
WHERE o.is_deleted = 0
`;
const params = [];
const countParams = [];
if (status) {
query += ' AND o.status = ?';
countQuery += ' AND o.status = ?';
params.push(status);
countParams.push(status);
}
if (merchantId) {
query += ' AND o.merchant_id = ?';
countQuery += ' AND o.merchant_id = ?';
params.push(merchantId);
countParams.push(merchantId);
}
if (userId) {
query += ' AND o.user_id = ?';
countQuery += ' AND o.user_id = ?';
params.push(userId);
countParams.push(userId);
}
query += ' ORDER BY o.created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const [orders] = await database.query(query, params);
const [totalResult] = await database.query(countQuery, countParams);
return {
orders,
pagination: {
page: parseInt(page),
pageSize: parseInt(pageSize),
total: totalResult.total,
totalPages: Math.ceil(totalResult.total / pageSize)
}
};
} catch (error) {
console.error('获取所有订单失败:', error);
throw new Error('获取所有订单失败');
}
}
}
module.exports = new OrderService();

View File

@@ -0,0 +1,206 @@
const { query } = require('../../config/database');
const { AppError } = require('../../utils/errors');
class TravelService {
// 获取旅行计划列表
static async getTravelPlans(searchParams) {
try {
const { userId, page = 1, pageSize = 10, status } = searchParams;
const offset = (page - 1) * pageSize;
let sql = `
SELECT tp.*, u.username, u.real_name, u.avatar_url
FROM travel_plans tp
INNER JOIN users u ON tp.user_id = u.id
WHERE 1=1
`;
const params = [];
if (userId) {
sql += ' AND tp.user_id = ?';
params.push(userId);
}
if (status) {
sql += ' AND tp.status = ?';
params.push(status);
}
// 获取总数
const countSql = `SELECT COUNT(*) as total FROM (${sql}) as count_query`;
const countResult = await query(countSql, params);
const total = countResult[0].total;
// 添加分页和排序
sql += ' ORDER BY tp.created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const plans = await query(sql, params);
return {
plans: plans.map(plan => this.sanitizePlan(plan)),
pagination: {
page: parseInt(page),
pageSize: parseInt(pageSize),
total: parseInt(total),
totalPages: Math.ceil(total / pageSize)
}
};
} catch (error) {
throw error;
}
}
// 获取单个旅行计划详情
static async getTravelPlanById(planId) {
try {
const sql = `
SELECT tp.*, u.username, u.real_name, u.avatar_url
FROM travel_plans tp
INNER JOIN users u ON tp.user_id = u.id
WHERE tp.id = ?
`;
const plans = await query(sql, [planId]);
if (plans.length === 0) {
throw new AppError('旅行计划不存在', 404);
}
return this.sanitizePlan(plans[0]);
} catch (error) {
throw error;
}
}
// 创建旅行计划
static async createTravelPlan(userId, planData) {
try {
const {
destination,
start_date,
end_date,
budget,
companions,
transportation,
accommodation,
activities,
notes
} = planData;
const sql = `
INSERT INTO travel_plans (
user_id, destination, start_date, end_date, budget, companions,
transportation, accommodation, activities, notes, status, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'planning', NOW(), NOW())
`;
const params = [
userId,
destination,
start_date,
end_date,
budget,
companions,
transportation,
accommodation,
activities,
notes
];
const result = await query(sql, params);
return result.insertId;
} catch (error) {
throw error;
}
}
// 更新旅行计划
static async updateTravelPlan(planId, userId, updateData) {
try {
const allowedFields = [
'destination', 'start_date', 'end_date', 'budget', 'companions',
'transportation', 'accommodation', 'activities', 'notes', 'status'
];
const setClauses = [];
const params = [];
for (const [key, value] of Object.entries(updateData)) {
if (allowedFields.includes(key) && value !== undefined) {
setClauses.push(`${key} = ?`);
params.push(value);
}
}
if (setClauses.length === 0) {
throw new AppError('没有有效的更新字段', 400);
}
setClauses.push('updated_at = NOW()');
params.push(planId, userId);
const sql = `
UPDATE travel_plans
SET ${setClauses.join(', ')}
WHERE id = ? AND user_id = ?
`;
const result = await query(sql, params);
if (result.affectedRows === 0) {
throw new AppError('旅行计划不存在或没有权限修改', 404);
}
return await this.getTravelPlanById(planId);
} catch (error) {
throw error;
}
}
// 删除旅行计划
static async deleteTravelPlan(planId, userId) {
try {
const sql = 'DELETE FROM travel_plans WHERE id = ? AND user_id = ?';
const result = await query(sql, [planId, userId]);
if (result.affectedRows === 0) {
throw new AppError('旅行计划不存在或没有权限删除', 404);
}
return true;
} catch (error) {
throw error;
}
}
// 获取用户旅行统计
static async getUserTravelStats(userId) {
try {
const sql = `
SELECT
COUNT(*) as total_plans,
COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed_plans,
COUNT(CASE WHEN status = 'planning' THEN 1 END) as planning_plans,
COUNT(CASE WHEN status = 'cancelled' THEN 1 END) as cancelled_plans,
SUM(budget) as total_budget
FROM travel_plans
WHERE user_id = ?
`;
const stats = await query(sql, [userId]);
return stats[0];
} catch (error) {
throw error;
}
}
// 安全返回旅行计划信息
static sanitizePlan(plan) {
if (!plan) return null;
const sanitized = { ...plan };
// 移除敏感信息或格式化数据
return sanitized;
}
}
module.exports = TravelService;

View File

@@ -0,0 +1,165 @@
const UserMySQL = require('../../models/UserMySQL');
const { AppError } = require('../../utils/errors');
class UserService {
// 获取用户详情
static async getUserProfile(userId) {
try {
const user = await UserMySQL.findById(userId);
if (!user) {
throw new AppError('用户不存在', 404);
}
return UserMySQL.sanitize(user);
} catch (error) {
throw error;
}
}
// 更新用户信息
static async updateUserProfile(userId, updateData) {
try {
const allowedFields = ['nickname', 'avatar', 'gender', 'birthday', 'phone', 'email'];
const filteredUpdates = {};
// 过滤允许更新的字段
Object.keys(updateData).forEach(key => {
if (allowedFields.includes(key) && updateData[key] !== undefined) {
filteredUpdates[key] = updateData[key];
}
});
if (Object.keys(filteredUpdates).length === 0) {
throw new AppError('没有有效的更新字段', 400);
}
// 检查邮箱是否已被其他用户使用
if (filteredUpdates.email) {
const emailExists = await UserMySQL.isEmailExists(filteredUpdates.email, userId);
if (emailExists) {
throw new AppError('邮箱已被其他用户使用', 400);
}
}
// 检查手机号是否已被其他用户使用
if (filteredUpdates.phone) {
const phoneExists = await UserMySQL.isPhoneExists(filteredUpdates.phone, userId);
if (phoneExists) {
throw new AppError('手机号已被其他用户使用', 400);
}
}
const success = await UserMySQL.update(userId, filteredUpdates);
if (!success) {
throw new AppError('更新用户信息失败', 500);
}
// 返回更新后的用户信息
return await this.getUserProfile(userId);
} catch (error) {
throw error;
}
}
// 搜索用户(管理员功能)
static async searchUsers(searchParams) {
try {
const { keyword, userType, page = 1, pageSize = 10 } = searchParams;
const offset = (page - 1) * pageSize;
let sql = `
SELECT id, username, user_type, real_name, avatar_url, email, phone,
created_at, updated_at, status
FROM users
WHERE 1=1
`;
const params = [];
if (keyword) {
sql += ` AND (
username LIKE ? OR
real_name LIKE ? OR
email LIKE ? OR
phone LIKE ?
)`;
const likeKeyword = `%${keyword}%`;
params.push(likeKeyword, likeKeyword, likeKeyword, likeKeyword);
}
if (userType) {
sql += ' AND user_type = ?';
params.push(userType);
}
// 获取总数
const countSql = `SELECT COUNT(*) as total FROM (${sql}) as count_query`;
const countResult = await UserMySQL.query(countSql, params);
const total = countResult[0].total;
// 添加分页和排序
sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
params.push(pageSize, offset);
const users = await UserMySQL.query(sql, params);
return {
users: users.map(user => UserMySQL.sanitize(user)),
pagination: {
page: parseInt(page),
pageSize: parseInt(pageSize),
total: parseInt(total),
totalPages: Math.ceil(total / pageSize)
}
};
} catch (error) {
throw error;
}
}
// 获取用户统计信息(管理员功能)
static async getUserStatistics() {
try {
const sql = `
SELECT
COUNT(*) as total_users,
COUNT(CASE WHEN user_type = 'farmer' THEN 1 END) as farmers,
COUNT(CASE WHEN user_type = 'merchant' THEN 1 END) as merchants,
COUNT(CASE WHEN user_type = 'admin' THEN 1 END) as admins,
COUNT(CASE WHEN status = 'active' THEN 1 END) as active_users,
COUNT(CASE WHEN status = 'inactive' THEN 1 END) as inactive_users,
DATE(created_at) as date
FROM users
GROUP BY DATE(created_at)
ORDER BY date DESC
LIMIT 30
`;
const stats = await UserMySQL.query(sql);
return stats;
} catch (error) {
throw error;
}
}
// 批量操作用户状态(管理员功能)
static async batchUpdateUserStatus(userIds, status) {
try {
if (!['active', 'inactive'].includes(status)) {
throw new AppError('无效的状态值', 400);
}
if (!userIds || userIds.length === 0) {
throw new AppError('请选择要操作的用户', 400);
}
const placeholders = userIds.map(() => '?').join(',');
const sql = `UPDATE users SET status = ?, updated_at = NOW() WHERE id IN (${placeholders})`;
const result = await UserMySQL.query(sql, [status, ...userIds]);
return result.affectedRows;
} catch (error) {
throw error;
}
}
}
module.exports = UserService;