feat: latest code update
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get, Post, Body, Query, HttpException, HttpStatus, UseGuards } from '@nestjs/common'
|
||||
import { Controller, Get, Post, Body, Query, Param, HttpException, HttpStatus, UseGuards } from '@nestjs/common'
|
||||
import { InjectModel } from '@nestjs/mongoose'
|
||||
import { Model } from 'mongoose'
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'
|
||||
@@ -226,7 +226,7 @@ export class AdminController {
|
||||
}
|
||||
|
||||
@Get('user/:id')
|
||||
async getUserDetail(@Query('id') id: string) {
|
||||
async getUserDetail(@Param('id') id: string) {
|
||||
const user = await this.userModel.findById(id).select('-password -openid').lean().exec()
|
||||
if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)
|
||||
const [interviews, resumes] = await Promise.all([
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Controller, Post, Get, Body, Param, UseGuards, Logger } from '@nestjs/c
|
||||
import { InjectModel } from '@nestjs/mongoose'
|
||||
import { Model } from 'mongoose'
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'
|
||||
import { Public } from '../../common/decorators/public.decorator'
|
||||
import { CurrentUser } from '../../common/decorators/current-user.decorator'
|
||||
import { AiService } from '../ai/ai.service'
|
||||
import { Contribution, ContributionDocument } from '../schemas/contribution.schema'
|
||||
@@ -186,4 +187,19 @@ export class ContributionController {
|
||||
.select('company position rounds experience createdAt')
|
||||
.exec()
|
||||
}
|
||||
|
||||
@Public()
|
||||
@Get('companies/hot')
|
||||
async getHotCompanies() {
|
||||
const banks = await this.companyBankModel.aggregate([
|
||||
{ $group: { _id: '$company', positionCount: { $sum: 1 }, totalContributions: { $sum: '$contributionCount' } } },
|
||||
{ $sort: { totalContributions: -1, positionCount: -1 } },
|
||||
{ $project: { _id: 0, name: '$_id', positionCount: 1 } },
|
||||
]).exec()
|
||||
|
||||
if (banks.length > 0) return banks
|
||||
|
||||
const DEFAULT_COMPANIES = ['腾讯', '字节跳动', '阿里巴巴', '美团', '百度', '京东', '网易', '小红书']
|
||||
return DEFAULT_COMPANIES.map((name, i) => ({ name, positionCount: 0, sort: i }))
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ const DEFAULT_PRICING: PricingConfig = {
|
||||
resumeOptimize: { freeLimit: 3, pricePerOptimize: 300, creditsPerPurchase: 1 },
|
||||
resumeDownload: { pricePerDownload: 200, creditsPerPurchase: 1 },
|
||||
plans: {
|
||||
growth: { price: 1990, durationDays: 30, credits: { interview: 999, resumeOptimize: 20, resumeDownload: 10 }, features: [] },
|
||||
sprint: { price: 4990, durationDays: 30, credits: { interview: 999, resumeOptimize: 50, resumeDownload: 30 }, features: [] },
|
||||
growth: { price: 1990, durationDays: 30, credits: { interview: 999, resumeOptimize: 20, resumeDownload: 10 }, features: ['免费版全部权益', 'AI 数字人面试无限次', '详细面试报告(四维评分)', '进步轨迹雷达图 + 打卡', '每日一题推送', '参考回答思路', '公司真题库', '简历优化 20 次/月', '简历下载 10 次/月'] },
|
||||
sprint: { price: 4990, durationDays: 30, credits: { interview: 999, resumeOptimize: 50, resumeDownload: 30 }, features: ['成长版全部权益', 'AI 语音分析(语气词/语速检测)', '技能缺口分析报告', '学习路径推荐', '真人导师 1v1 点评(每月 1 次)', '简历精修(每月 1 次)', '内推优先', '简历优化 50 次/月', '简历下载 30 次/月'] },
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -47,15 +47,6 @@ export class QuotaService {
|
||||
if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)
|
||||
if (user.plan !== 'free') return
|
||||
|
||||
// Backward compat: migrate remaining → freeOptimizeUsed
|
||||
if ((user.freeOptimizeUsed ?? 0) <= 0 && (user.remaining ?? 0) > 0 && (user.resumeOptimizeCredits ?? 0) <= 0) {
|
||||
const migrateCount = Math.min(user.remaining, FREE_OPTIMIZE_LIMIT)
|
||||
await this.userModel.findByIdAndUpdate(userId, {
|
||||
$set: { freeOptimizeUsed: migrateCount, remaining: Math.max(0, user.remaining - migrateCount) },
|
||||
}).exec()
|
||||
this.logger.log(`Migrated remaining=${user.remaining} → freeOptimizeUsed=${migrateCount} for user ${userId}`)
|
||||
}
|
||||
|
||||
// Try paid credits first
|
||||
const paid = await this.userModel.findOneAndUpdate(
|
||||
{ _id: userId, resumeOptimizeCredits: { $gt: 0 } },
|
||||
@@ -63,6 +54,13 @@ export class QuotaService {
|
||||
).exec()
|
||||
if (paid) return
|
||||
|
||||
// Try old remaining credits (backward compat)
|
||||
const oldRemaining = await this.userModel.findOneAndUpdate(
|
||||
{ _id: userId, remaining: { $gt: 0 } },
|
||||
{ $inc: { remaining: -1 } },
|
||||
).exec()
|
||||
if (oldRemaining) return
|
||||
|
||||
// Then free limit
|
||||
const freeResult = await this.userModel.findOneAndUpdate(
|
||||
{ _id: userId, freeOptimizeUsed: { $lt: FREE_OPTIMIZE_LIMIT } },
|
||||
|
||||
Reference in New Issue
Block a user