feat: 添加用户管理页

This commit is contained in:
Stev_Wang
2026-01-03 19:25:56 +08:00
parent cb5088115a
commit a950d1d526
12 changed files with 491 additions and 7 deletions

View File

@@ -0,0 +1,52 @@
import { Controller, Get, Post, Put, Delete, Body, Param, HttpCode, HttpStatus, UseGuards } from '@nestjs/common';
import { AdminUsersService } from './admin-users.service';
import { AdminRole } from '../entities/admin-user.entity';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
@Controller('admin/admin-users')
@UseGuards(JwtAuthGuard)
export class AdminUsersController {
constructor(private adminUsersService: AdminUsersService) {}
@Get()
@HttpCode(HttpStatus.OK)
async findAll() {
return this.adminUsersService.findAll();
}
@Get(':id')
@HttpCode(HttpStatus.OK)
async findOne(@Param('id') id: string) {
return this.adminUsersService.findOne(Number(id));
}
@Post()
@HttpCode(HttpStatus.CREATED)
async create(@Body() createAdminUserDto: {
username: string;
password: string;
role: AdminRole;
}) {
return this.adminUsersService.create(createAdminUserDto);
}
@Put(':id')
@HttpCode(HttpStatus.OK)
async update(
@Param('id') id: string,
@Body() updateAdminUserDto: {
username?: string;
password?: string;
role?: AdminRole;
},
) {
return this.adminUsersService.update(Number(id), updateAdminUserDto);
}
@Delete(':id')
@HttpCode(HttpStatus.OK)
async remove(@Param('id') id: string) {
await this.adminUsersService.remove(Number(id));
return { message: '删除成功' };
}
}

View File

@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AdminUsersController } from './admin-users.controller';
import { AdminUsersService } from './admin-users.service';
import { AdminUser } from '../entities/admin-user.entity';
import { AuthModule } from '../auth/auth.module';
@Module({
imports: [TypeOrmModule.forFeature([AdminUser]), AuthModule],
controllers: [AdminUsersController],
providers: [AdminUsersService],
exports: [AdminUsersService],
})
export class AdminUsersModule {}

View File

@@ -0,0 +1,75 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AdminUser, AdminRole } from '../entities/admin-user.entity';
import * as bcrypt from 'bcrypt';
@Injectable()
export class AdminUsersService {
constructor(
@InjectRepository(AdminUser)
private adminUserRepository: Repository<AdminUser>,
) {}
async findAll(): Promise<AdminUser[]> {
return this.adminUserRepository.find({
select: ['id', 'username', 'role', 'createdAt', 'updatedAt'],
order: { createdAt: 'DESC' },
});
}
async findOne(id: number): Promise<AdminUser | null> {
return this.adminUserRepository.findOne({
where: { id },
select: ['id', 'username', 'role', 'createdAt', 'updatedAt'],
});
}
async findByUsername(username: string): Promise<AdminUser | null> {
return this.adminUserRepository.findOne({
where: { username },
});
}
async create(createAdminUserDto: {
username: string;
password: string;
role: AdminRole;
}): Promise<AdminUser> {
const hashedPassword = await bcrypt.hash(createAdminUserDto.password, 10);
const adminUser = this.adminUserRepository.create({
username: createAdminUserDto.username,
passwordHash: hashedPassword,
role: createAdminUserDto.role,
});
return this.adminUserRepository.save(adminUser);
}
async update(id: number, updateAdminUserDto: {
username?: string;
password?: string;
role?: AdminRole;
}): Promise<AdminUser | null> {
const adminUser = await this.findOne(id);
if (!adminUser) {
return null;
}
if (updateAdminUserDto.username) {
adminUser.username = updateAdminUserDto.username;
}
if (updateAdminUserDto.password) {
adminUser.passwordHash = await bcrypt.hash(updateAdminUserDto.password, 10);
}
if (updateAdminUserDto.role) {
adminUser.role = updateAdminUserDto.role;
}
return this.adminUserRepository.save(adminUser);
}
async remove(id: number): Promise<boolean> {
const result = await this.adminUserRepository.delete(id);
return (result.affected ?? 0) > 0;
}
}

View File

@@ -5,6 +5,7 @@ import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { PlayerModule } from './player/player.module';
import { AdminUsersModule } from './admin-users/admin-users.module';
@Module({
imports: [
@@ -26,6 +27,7 @@ import { PlayerModule } from './player/player.module';
}),
AuthModule,
PlayerModule,
AdminUsersModule,
],
controllers: [AppController],
providers: [AppService],

View File

@@ -17,6 +17,6 @@ import { AdminUser } from '../entities/admin-user.entity';
],
controllers: [AuthController],
providers: [AuthService],
exports: [AuthService],
exports: [AuthService, JwtModule],
})
export class AuthModule {}

View File

@@ -0,0 +1,30 @@
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const authHeader = request.headers.authorization;
if (!authHeader) {
throw new UnauthorizedException('未提供认证令牌');
}
const [type, token] = authHeader.split(' ');
if (type !== 'Bearer' || !token) {
throw new UnauthorizedException('无效的认证令牌格式');
}
try {
const payload = await this.jwtService.verifyAsync(token);
request.user = payload;
return true;
} catch (error) {
throw new UnauthorizedException('无效的认证令牌');
}
}
}