yingsa/server/src/controllers/adminController.js

502 lines
14 KiB
JavaScript

const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { User, Store, SystemUser, LadderUser, Match, PointOrder, StoreStaff } = require('../models');
const { success, error, getPagination, pageResult } = require('../utils/helper');
const { Op } = require('sequelize');
class AdminController {
// 后台登录
async login(req, res) {
try {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json(error('请输入用户名和密码', 400));
}
const admin = await SystemUser.findOne({
where: { username },
include: [{ model: Store, as: 'store' }]
});
if (!admin) {
return res.status(401).json(error('用户名或密码错误', 401));
}
const isValid = await admin.validatePassword(password);
if (!isValid) {
return res.status(401).json(error('用户名或密码错误', 401));
}
if (admin.status !== 1) {
return res.status(403).json(error('账号已被禁用', 403));
}
// 更新最后登录时间
await admin.update({ last_login_at: new Date() });
// 生成token
const token = jwt.sign(
{ adminId: admin.id },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
);
res.json(success({
token,
userInfo: {
id: admin.id,
username: admin.username,
realName: admin.real_name,
role: admin.role,
storeId: admin.store_id,
storeName: admin.store?.name,
avatar: admin.avatar
}
}, '登录成功'));
} catch (err) {
console.error('登录失败:', err);
res.status(500).json(error('登录失败'));
}
}
// 仪表盘数据
async getDashboard(req, res) {
try {
const admin = req.admin;
const storeWhere = admin.role === 'super_admin' ? {} : { store_id: admin.store_id };
// 统计数据
const [userCount, storeCount, ladderUserCount, matchCount, pendingOrderCount] = await Promise.all([
User.count({ where: { status: 1 } }),
Store.count({ where: { status: 1 } }),
LadderUser.count({ where: { status: 1, ...storeWhere } }),
Match.count({ where: storeWhere }),
PointOrder.count({ where: { status: 0, ...storeWhere } })
]);
// 近7天比赛数据
const last7Days = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
const recentMatches = await Match.count({
where: {
...storeWhere,
created_at: { [Op.gte]: last7Days }
}
});
res.json(success({
stats: {
userCount,
storeCount: admin.role === 'super_admin' ? storeCount : 1,
ladderUserCount,
matchCount,
pendingOrderCount,
recentMatches
}
}));
} catch (err) {
console.error('获取仪表盘数据失败:', err);
res.status(500).json(error('获取失败'));
}
}
// === 用户管理 ===
async getUsers(req, res) {
try {
const { page = 1, pageSize = 20, keyword, status } = req.query;
const { limit, offset } = getPagination(page, pageSize);
const where = {};
if (keyword) {
where[Op.or] = [
{ nickname: { [Op.like]: `%${keyword}%` } },
{ phone: { [Op.like]: `%${keyword}%` } },
{ member_code: { [Op.like]: `%${keyword}%` } }
];
}
if (status !== undefined && status !== '') {
where.status = parseInt(status);
}
const { rows, count } = await User.findAndCountAll({
where,
order: [['created_at', 'DESC']],
limit,
offset
});
res.json(pageResult(rows.map(user => ({
id: user.id,
nickname: user.nickname,
phone: user.phone,
avatar: user.avatar,
gender: user.gender,
memberCode: user.member_code,
totalPoints: user.total_points,
status: user.status,
createdAt: user.created_at
})), count, page, pageSize));
} catch (err) {
console.error('获取用户列表失败:', err);
res.status(500).json(error('获取失败'));
}
}
// 搜索用户(用于积分操作,不需要超级管理员权限)
async searchUsers(req, res) {
try {
const { keyword, pageSize = 10 } = req.query;
if (!keyword || keyword.trim().length < 2) {
return res.json(success([]));
}
const where = {
status: 1 // 只搜索正常状态的用户
};
where[Op.or] = [
{ nickname: { [Op.like]: `%${keyword.trim()}%` } },
{ phone: { [Op.like]: `%${keyword.trim()}%` } },
{ member_code: { [Op.like]: `%${keyword.trim()}%` } }
];
const users = await User.findAll({
where,
limit: parseInt(pageSize) || 10,
order: [['created_at', 'DESC']],
attributes: ['id', 'nickname', 'phone', 'avatar', 'member_code']
});
res.json(success(users.map(user => ({
id: user.id,
nickname: user.nickname,
phone: user.phone,
avatar: user.avatar,
memberCode: user.member_code
}))));
} catch (err) {
console.error('搜索用户失败:', err);
res.status(500).json(error('搜索失败'));
}
}
async getUserDetail(req, res) {
try {
const { id } = req.params;
const user = await User.findByPk(id, {
include: [{
model: LadderUser,
as: 'ladderUsers',
include: [{ model: Store, as: 'store' }]
}]
});
if (!user) {
return res.status(404).json(error('用户不存在', 404));
}
res.json(success({
id: user.id,
nickname: user.nickname,
phone: user.phone,
avatar: user.avatar,
gender: user.gender,
memberCode: user.member_code,
totalPoints: user.total_points,
status: user.status,
createdAt: user.created_at,
ladderUsers: user.ladderUsers.map(lu => ({
id: lu.id,
storeId: lu.store_id,
storeName: lu.store?.name,
realName: lu.real_name,
level: lu.level,
powerScore: lu.power_score,
matchCount: lu.match_count
}))
}));
} catch (err) {
console.error('获取用户详情失败:', err);
res.status(500).json(error('获取失败'));
}
}
async updateUserStatus(req, res) {
try {
const { id } = req.params;
const { status } = req.body;
const user = await User.findByPk(id);
if (!user) {
return res.status(404).json(error('用户不存在', 404));
}
await user.update({ status });
res.json(success(null, '更新成功'));
} catch (err) {
console.error('更新用户状态失败:', err);
res.status(500).json(error('更新失败'));
}
}
// === 门店管理 ===
async getStores(req, res) {
try {
const { page = 1, pageSize = 20, keyword, status } = req.query;
const { limit, offset } = getPagination(page, pageSize);
const where = {};
if (keyword) {
where.name = { [Op.like]: `%${keyword}%` };
}
if (status !== undefined && status !== '') {
where.status = parseInt(status);
}
const { rows, count } = await Store.findAndCountAll({
where,
order: [['created_at', 'DESC']],
limit,
offset
});
res.json(pageResult(rows, count, page, pageSize));
} catch (err) {
console.error('获取门店列表失败:', err);
res.status(500).json(error('获取失败'));
}
}
async createStore(req, res) {
try {
const data = req.body;
const store = await Store.create(data);
res.json(success({ id: store.id }, '创建成功'));
} catch (err) {
console.error('创建门店失败:', err);
res.status(500).json(error('创建失败'));
}
}
async updateStore(req, res) {
try {
const { id } = req.params;
const data = req.body;
const store = await Store.findByPk(id);
if (!store) {
return res.status(404).json(error('门店不存在', 404));
}
await store.update(data);
res.json(success(null, '更新成功'));
} catch (err) {
console.error('更新门店失败:', err);
res.status(500).json(error('更新失败'));
}
}
async deleteStore(req, res) {
try {
const { id } = req.params;
const store = await Store.findByPk(id);
if (!store) {
return res.status(404).json(error('门店不存在', 404));
}
// 检查是否有关联数据
const ladderCount = await LadderUser.count({ where: { store_id: id } });
if (ladderCount > 0) {
return res.status(400).json(error('该门店下有天梯用户,无法删除', 400));
}
await store.destroy();
res.json(success(null, '删除成功'));
} catch (err) {
console.error('删除门店失败:', err);
res.status(500).json(error('删除失败'));
}
}
// === 系统用户管理 ===
async getSystemUsers(req, res) {
try {
const { page = 1, pageSize = 20, keyword, role } = req.query;
const { limit, offset } = getPagination(page, pageSize);
const where = {};
if (keyword) {
where[Op.or] = [
{ username: { [Op.like]: `%${keyword}%` } },
{ real_name: { [Op.like]: `%${keyword}%` } }
];
}
if (role) {
where.role = role;
}
const { rows, count } = await SystemUser.findAndCountAll({
where,
include: [{ model: Store, as: 'store', attributes: ['id', 'name'] }],
attributes: { exclude: ['password'] },
order: [['created_at', 'DESC']],
limit,
offset
});
res.json(pageResult(rows.map(user => ({
id: user.id,
username: user.username,
realName: user.real_name,
phone: user.phone,
role: user.role,
storeId: user.store_id,
storeName: user.store?.name,
status: user.status,
lastLoginAt: user.last_login_at,
createdAt: user.created_at
})), count, page, pageSize));
} catch (err) {
console.error('获取系统用户列表失败:', err);
res.status(500).json(error('获取失败'));
}
}
async createSystemUser(req, res) {
try {
const { username, password, real_name, phone, role, store_id } = req.body;
if (!username || !password) {
return res.status(400).json(error('用户名和密码不能为空', 400));
}
// 检查用户名是否已存在
const existing = await SystemUser.findOne({ where: { username } });
if (existing) {
return res.status(400).json(error('用户名已存在', 400));
}
const user = await SystemUser.create({
username,
password,
real_name,
phone,
role: role || 'staff',
store_id: role === 'staff' ? store_id : null,
status: 1
});
res.json(success({ id: user.id }, '创建成功'));
} catch (err) {
console.error('创建系统用户失败:', err);
res.status(500).json(error('创建失败'));
}
}
async updateSystemUser(req, res) {
try {
const { id } = req.params;
const { real_name, phone, role, store_id, status, password } = req.body;
const user = await SystemUser.findByPk(id);
if (!user) {
return res.status(404).json(error('用户不存在', 404));
}
const updateData = { real_name, phone, role, status };
if (role === 'staff') {
updateData.store_id = store_id;
} else {
updateData.store_id = null;
}
if (password) {
updateData.password = password;
}
await user.update(updateData);
res.json(success(null, '更新成功'));
} catch (err) {
console.error('更新系统用户失败:', err);
res.status(500).json(error('更新失败'));
}
}
async deleteSystemUser(req, res) {
try {
const { id } = req.params;
if (req.admin.id === parseInt(id)) {
return res.status(400).json(error('不能删除自己', 400));
}
const user = await SystemUser.findByPk(id);
if (!user) {
return res.status(404).json(error('用户不存在', 404));
}
await user.destroy();
res.json(success(null, '删除成功'));
} catch (err) {
console.error('删除系统用户失败:', err);
res.status(500).json(error('删除失败'));
}
}
// === 个人信息 ===
async getProfile(req, res) {
try {
const admin = req.admin;
res.json(success({
id: admin.id,
username: admin.username,
realName: admin.real_name,
phone: admin.phone,
role: admin.role,
storeId: admin.store_id,
storeName: admin.store?.name,
avatar: admin.avatar
}));
} catch (err) {
console.error('获取个人信息失败:', err);
res.status(500).json(error('获取失败'));
}
}
async updateProfile(req, res) {
try {
const { real_name, phone, avatar } = req.body;
await req.admin.update({ real_name, phone, avatar });
res.json(success(null, '更新成功'));
} catch (err) {
console.error('更新个人信息失败:', err);
res.status(500).json(error('更新失败'));
}
}
async updatePassword(req, res) {
try {
const { old_password, new_password } = req.body;
if (!old_password || !new_password) {
return res.status(400).json(error('请输入旧密码和新密码', 400));
}
const isValid = await req.admin.validatePassword(old_password);
if (!isValid) {
return res.status(400).json(error('旧密码错误', 400));
}
await req.admin.update({ password: new_password });
res.json(success(null, '密码修改成功'));
} catch (err) {
console.error('修改密码失败:', err);
res.status(500).json(error('修改失败'));
}
}
}
module.exports = new AdminController();