import { Controller, Get, Post, Delete, Body, Param, Query, UseGuards } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { PrismaService } from '../../infrastructure/database/prisma.service'; import { enrichWithNames } from '../../common/helpers/name-resolver'; import { AdminAuthGuard } from '../../common/guards/admin-auth.guard'; import { AdminRolesGuard } from '../../common/guards/admin-roles.guard'; import { AdminRoles } from '../../common/decorators/admin-roles.decorator'; import type { AdminRole } from '../../common/types/admin-role.enum'; @ApiTags('admin-users') @Controller('admin-api/users') @UseGuards(AdminAuthGuard, AdminRolesGuard) @ApiBearerAuth() export class AdminUsersMgmtController { constructor(private readonly prisma: PrismaService) {} // ── User List ── @Get() @AdminRoles('ADMIN' as AdminRole) @ApiOperation({ summary: 'C 端用户列表' }) async listUsers(@Query('search') search?: string, @Query('page') page?: string, @Query('limit') limit?: string) { const take = Math.min(Number(limit) || 20, 100); const skip = (Math.max(Number(page) || 1, 1) - 1) * take; const where: any = { deletedAt: null }; if (search) where.OR = [{ email: { contains: search } }, { nickname: { contains: search } }]; const [items, total] = await Promise.all([ this.prisma.user.findMany({ where, orderBy: { createdAt: 'desc' }, take, skip, select: { id: true, email: true, nickname: true, role: true, status: true, lastLoginAt: true, createdAt: true } }), this.prisma.user.count({ where }), ]); const enriched = await enrichWithNames(this.prisma, items); return { items: enriched, total }; } // ── Membership ── @Get('memberships') @AdminRoles('ADMIN' as AdminRole) @ApiOperation({ summary: '用户会员列表' }) async memberships(@Query('userId') userId?: string) { return this.prisma.userMembership.findMany({ where: userId ? { userId } : undefined, include: { plan: true }, orderBy: { createdAt: 'desc' }, take: 100, }); } @Post('memberships') @AdminRoles('SUPER_ADMIN' as AdminRole) @ApiOperation({ summary: '手动分配会员' }) async addMembership(@Body() d: { userId: string; planId: string; expiresAt?: string }) { return this.prisma.userMembership.create({ data: { userId: d.userId, planId: d.planId, expiresAt: d.expiresAt ? new Date(d.expiresAt) : null }, }); } // ── Deletion Requests ── @Get('deletion-requests') @AdminRoles('ADMIN' as AdminRole) @ApiOperation({ summary: '注销申请列表' }) async deletionRequests(@Query('status') status?: string) { return this.prisma.accountDeletionRequest.findMany({ where: status ? { status } : undefined, orderBy: { createdAt: 'desc' }, take: 100, }); } @Post('deletion-requests/:id/approve') @AdminRoles('SUPER_ADMIN' as AdminRole) @ApiOperation({ summary: '批准注销(立即执行)' }) async approveDeletion(@Param('id') id: string) { return this.prisma.accountDeletionRequest.update({ where: { id }, data: { status: 'completed', reviewedAt: new Date(), completedAt: new Date() }, }); } @Post('deletion-requests/:id/reject') @AdminRoles('SUPER_ADMIN' as AdminRole) @ApiOperation({ summary: '驳回注销' }) async rejectDeletion(@Param('id') id: string) { return this.prisma.accountDeletionRequest.update({ where: { id }, data: { status: 'cancelled', reviewedAt: new Date(), cancelledAt: new Date() }, }); } // ── Devices ── @Get(':userId/devices') @AdminRoles('ADMIN' as AdminRole) @ApiOperation({ summary: '查看用户设备' }) async userDevices(@Param('userId') userId: string) { return this.prisma.userDevice.findMany({ where: { userId }, orderBy: { lastSeenAt: 'desc' } }); } }