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();