初始化:职引项目 v1.0

This commit is contained in:
yuzhiran
2026-06-08 16:28:00 +08:00
commit 511f60d0db
111 changed files with 27295 additions and 0 deletions
@@ -0,0 +1,133 @@
import { Controller, Get, Post, Body, Query, HttpException, HttpStatus, UseGuards } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'
import { Public } from '../../common/decorators/public.decorator'
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'
import { CurrentUser } from '../../common/decorators/current-user.decorator'
import { User, UserDocument } from '../user/user.schema'
import { Interview, InterviewDocument } from '../interview/interview.schema'
@Controller('admin')
export class AdminController {
constructor(
@InjectModel(User.name) private userModel: Model<UserDocument>,
@InjectModel(Interview.name) private interviewModel: Model<InterviewDocument>,
) {}
@Get('check')
@UseGuards(JwtAuthGuard)
async checkAdmin(@CurrentUser('userId') userId: string) {
const user = await this.userModel.findById(userId).select('role').exec()
return { isAdmin: user?.role === 'admin' }
}
@Public()
@Post('verify')
async verify(@Body('adminId') adminId: string) {
const user = await this.userModel.findById(adminId).exec()
if (!user || user.role !== 'admin') {
throw new HttpException('无权限访问', HttpStatus.FORBIDDEN)
}
return { ok: true, nickname: user.nickname || '管理员' }
}
@Public()
@Get('overview')
async overview() {
const [userCount, interviewCount, todayUsers, todayInterviews] = await Promise.all([
this.userModel.countDocuments().exec(),
this.interviewModel.countDocuments().exec(),
this.userModel.countDocuments({ createdAt: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) } }).exec(),
this.interviewModel.countDocuments({ createdAt: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) } }).exec(),
])
return { userCount, interviewCount, todayUsers, todayInterviews }
}
@Public()
@Get('users')
async getUsers(@Query('keyword') keyword: string, @Query('page') page = '1', @Query('limit') limit = '20') {
const filter: any = {}
if (keyword) filter.$or = [
{ phone: { $regex: keyword, $options: 'i' } },
{ nickname: { $regex: keyword, $options: 'i' } },
]
const skip = (Math.max(1, +page) - 1) * +limit
const [users, total] = await Promise.all([
this.userModel.find(filter).sort({ createdAt: -1 }).skip(skip).limit(+limit).select('-password').lean().exec(),
this.userModel.countDocuments(filter).exec(),
])
return { users, total, page: +page }
}
@Public()
@Get('interviews')
async getInterviews(@Query('page') page = '1', @Query('limit') limit = '20') {
const skip = (Math.max(1, +page) - 1) * +limit
const [interviews, total] = await Promise.all([
this.interviewModel.find().sort({ createdAt: -1 }).skip(skip).limit(+limit).populate('userId', 'phone nickname').lean().exec(),
this.interviewModel.countDocuments().exec(),
])
return { interviews, total, page: +page }
}
@UseGuards(JwtAuthGuard)
@Post('set-vip')
async setVip(@Body('userId') targetUserId: string, @CurrentUser('userId') adminUserId: string) {
const admin = await this.userModel.findById(adminUserId).exec()
if (admin?.role !== 'admin') throw new HttpException('无权限', HttpStatus.FORBIDDEN)
const user = await this.userModel.findById(targetUserId).exec()
if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)
const expireAt = new Date()
expireAt.setDate(expireAt.getDate() + 30)
user.plan = 'vip'
user.vipExpireAt = expireAt
user.remaining = 999
await user.save()
return { success: true, plan: 'vip', expireAt }
}
@UseGuards(JwtAuthGuard)
@Get('admins')
async getAdmins(@CurrentUser('userId') adminUserId: string) {
const admin = await this.userModel.findById(adminUserId).exec()
if (admin?.role !== 'admin') throw new HttpException('无权限', HttpStatus.FORBIDDEN)
const admins = await this.userModel.find({ role: 'admin' }).select('phone nickname email createdAt isSystemAdmin').lean().exec()
return { admins }
}
@UseGuards(JwtAuthGuard)
@Post('set-admin')
async setAdmin(@Body('userId') targetUserId: string, @CurrentUser('userId') adminUserId: string) {
const admin = await this.userModel.findById(adminUserId).exec()
if (admin?.role !== 'admin') throw new HttpException('无权限', HttpStatus.FORBIDDEN)
const user = await this.userModel.findById(targetUserId).exec()
if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)
if (user.role === 'admin') throw new HttpException('该用户已是管理员', HttpStatus.BAD_REQUEST)
user.role = 'admin'
await user.save()
return { success: true, message: '已设为管理员' }
}
@UseGuards(JwtAuthGuard)
@Get('config')
async getConfig(@CurrentUser('userId') adminUserId: string) {
const admin = await this.userModel.findById(adminUserId).exec()
if (admin?.role !== 'admin') throw new HttpException('无权限', HttpStatus.FORBIDDEN)
return {
interview: {
maxRoundsFree: 5,
maxRoundsVip: 10,
dailyFreeLimit: 3,
},
diagnosis: {
dailyFreeLimit: 2,
},
optimize: {
dailyFreeLimit: 2,
},
price: {
monthly: 2900, // 分
},
}
}
}
+14
View File
@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common'
import { MongooseModule } from '@nestjs/mongoose'
import { AdminController } from './admin.controller'
import { User, UserSchema } from '../user/user.schema'
import { Interview, InterviewSchema } from '../interview/interview.schema'
@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
MongooseModule.forFeature([{ name: Interview.name, schema: InterviewSchema }]),
],
controllers: [AdminController],
})
export class AdminModule {}