import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import * as bcrypt from 'bcrypt'; import * as jwt from 'jsonwebtoken'; import { ConfigService } from '@nestjs/config'; import { AdminORM } from '../infrastructure/database/entities/admin.orm'; import { v4 as uuidv4 } from 'uuid'; /** * 管理员角色 */ export enum AdminRole { SUPER_ADMIN = 'SUPER_ADMIN', ADMIN = 'ADMIN', OPERATOR = 'OPERATOR', VIEWER = 'VIEWER', } /** * 角色权限映射 */ const ROLE_PERMISSIONS: Record = { [AdminRole.SUPER_ADMIN]: ['*'], [AdminRole.ADMIN]: [ 'knowledge:*', 'experience:*', 'user:read', 'conversation:read', 'statistics:*', 'admin:read', ], [AdminRole.OPERATOR]: [ 'knowledge:read', 'knowledge:create', 'knowledge:update', 'experience:read', 'experience:approve', 'user:read', 'conversation:read', 'statistics:read', ], [AdminRole.VIEWER]: [ 'knowledge:read', 'experience:read', 'user:read', 'conversation:read', 'statistics:read', ], }; /** * 登录结果 */ export interface LoginResult { admin: { id: string; username: string; name: string; role: string; permissions: string[]; }; token: string; expiresIn: number; } /** * 管理员服务 */ @Injectable() export class AdminService { private readonly jwtSecret: string; private readonly jwtExpiresIn: number = 24 * 60 * 60; // 24小时 constructor( @InjectRepository(AdminORM) private adminRepo: Repository, private configService: ConfigService, ) { this.jwtSecret = this.configService.get('JWT_SECRET') || 'iconsulting-secret-key'; } /** * 管理员登录 */ async login(username: string, password: string, ip?: string): Promise { const admin = await this.adminRepo.findOne({ where: { username } }); if (!admin || !admin.isActive) { throw new Error('用户名或密码错误'); } const isPasswordValid = await bcrypt.compare(password, admin.passwordHash); if (!isPasswordValid) { throw new Error('用户名或密码错误'); } // 更新登录信息 admin.lastLoginAt = new Date(); admin.lastLoginIp = ip; await this.adminRepo.save(admin); // 生成Token const token = jwt.sign( { sub: admin.id, username: admin.username, role: admin.role, }, this.jwtSecret, { expiresIn: this.jwtExpiresIn }, ); // 获取权限 const permissions = this.getPermissions(admin.role as AdminRole, admin.permissions); return { admin: { id: admin.id, username: admin.username, name: admin.name, role: admin.role, permissions, }, token, expiresIn: this.jwtExpiresIn, }; } /** * 验证Token */ async verifyToken(token: string): Promise<{ valid: boolean; admin?: { id: string; username: string; role: string; permissions: string[]; }; }> { try { const decoded = jwt.verify(token, this.jwtSecret) as { sub: string; username: string; role: string; }; const admin = await this.adminRepo.findOne({ where: { id: decoded.sub } }); if (!admin || !admin.isActive) { return { valid: false }; } const permissions = this.getPermissions(admin.role as AdminRole, admin.permissions); return { valid: true, admin: { id: admin.id, username: admin.username, role: admin.role, permissions, }, }; } catch { return { valid: false }; } } /** * 创建管理员 */ async createAdmin(params: { username: string; password: string; name: string; email?: string; phone?: string; role: AdminRole; }): Promise { // 检查用户名是否存在 const existing = await this.adminRepo.findOne({ where: { username: params.username }, }); if (existing) { throw new Error('用户名已存在'); } // 加密密码 const passwordHash = await bcrypt.hash(params.password, 10); const admin = this.adminRepo.create({ id: uuidv4(), username: params.username, passwordHash, name: params.name, email: params.email, phone: params.phone, role: params.role, permissions: ROLE_PERMISSIONS[params.role], isActive: true, }); await this.adminRepo.save(admin); return admin; } /** * 获取管理员列表 */ async listAdmins(options?: { role?: AdminRole; isActive?: boolean; page?: number; pageSize?: number; }): Promise<{ items: AdminORM[]; total: number; }> { const page = options?.page || 1; const pageSize = options?.pageSize || 20; const query = this.adminRepo.createQueryBuilder('admin'); if (options?.role) { query.andWhere('admin.role = :role', { role: options.role }); } if (options?.isActive !== undefined) { query.andWhere('admin.isActive = :active', { active: options.isActive }); } query.orderBy('admin.createdAt', 'DESC'); const [items, total] = await query .skip((page - 1) * pageSize) .take(pageSize) .getManyAndCount(); return { items, total }; } /** * 更新管理员 */ async updateAdmin( adminId: string, params: { name?: string; email?: string; phone?: string; role?: AdminRole; isActive?: boolean; }, ): Promise { const admin = await this.adminRepo.findOne({ where: { id: adminId } }); if (!admin) { throw new Error('管理员不存在'); } if (params.name) admin.name = params.name; if (params.email !== undefined) admin.email = params.email; if (params.phone !== undefined) admin.phone = params.phone; if (params.role) { admin.role = params.role; admin.permissions = ROLE_PERMISSIONS[params.role]; } if (params.isActive !== undefined) admin.isActive = params.isActive; await this.adminRepo.save(admin); return admin; } /** * 修改密码 */ async changePassword( adminId: string, oldPassword: string, newPassword: string, ): Promise { const admin = await this.adminRepo.findOne({ where: { id: adminId } }); if (!admin) { throw new Error('管理员不存在'); } const isOldPasswordValid = await bcrypt.compare(oldPassword, admin.passwordHash); if (!isOldPasswordValid) { throw new Error('原密码错误'); } admin.passwordHash = await bcrypt.hash(newPassword, 10); await this.adminRepo.save(admin); } /** * 重置密码(超管功能) */ async resetPassword(adminId: string, newPassword: string): Promise { const admin = await this.adminRepo.findOne({ where: { id: adminId } }); if (!admin) { throw new Error('管理员不存在'); } admin.passwordHash = await bcrypt.hash(newPassword, 10); await this.adminRepo.save(admin); } /** * 检查权限 */ hasPermission(adminPermissions: string[], requiredPermission: string): boolean { // 超管拥有所有权限 if (adminPermissions.includes('*')) { return true; } // 完全匹配 if (adminPermissions.includes(requiredPermission)) { return true; } // 通配符匹配 (如 knowledge:* 匹配 knowledge:read) const [resource, action] = requiredPermission.split(':'); if (adminPermissions.includes(`${resource}:*`)) { return true; } return false; } /** * 获取管理员权限列表 */ private getPermissions(role: AdminRole, customPermissions?: string[]): string[] { const rolePermissions = ROLE_PERMISSIONS[role] || []; if (customPermissions && customPermissions.length > 0) { return [...new Set([...rolePermissions, ...customPermissions])]; } return rolePermissions; } }