feat: registration gravity from DB config instead of hardcoded

- Add registrationGravity to pricing config (default 50, adjustable via admin)
- Inject PricingService into UserService, read config for all 4 registration paths
- Expose registrationGravity in /member/plans response for frontend
- Login page fetches dynamic value from API, replaces hardcoded '50'
- Update user.vue gravity card copy
This commit is contained in:
yuzhiran
2026-06-25 08:12:01 +08:00
parent 52e5350ba0
commit 2fddd39301
5 changed files with 38 additions and 6 deletions
@@ -53,6 +53,7 @@ export class MemberController {
}
return {
registrationGravity: pricing.registrationGravity,
interview: { dailyFreeLimit: FREE_DAILY_LIMIT, maxRoundsFree: 5, maxRoundsVip: 10 },
gravityRates: pricing.gravityRates,
products: {
@@ -10,6 +10,8 @@ export interface GravityRates {
}
interface PricingConfig {
/** 新用户注册赠送引力值 */
registrationGravity: number
interview: { pricePerSession: number; creditsPerPurchase: number }
resumeOptimize: { freeLimit: number; pricePerOptimize: number; creditsPerPurchase: number }
resumeDownload: { pricePerDownload: number; creditsPerPurchase: number }
@@ -21,6 +23,7 @@ interface PricingConfig {
}
const DEFAULT_PRICING: PricingConfig = {
registrationGravity: 50,
interview: { pricePerSession: 600, creditsPerPurchase: 1 },
resumeOptimize: { freeLimit: 3, pricePerOptimize: 400, creditsPerPurchase: 1 },
resumeDownload: { pricePerDownload: 200, creditsPerPurchase: 1 },
@@ -62,6 +65,7 @@ export class PricingService {
private mergeDefaults(value: any): PricingConfig {
return {
registrationGravity: value?.registrationGravity ?? DEFAULT_PRICING.registrationGravity,
interview: { ...DEFAULT_PRICING.interview, ...value?.interview },
resumeOptimize: { ...DEFAULT_PRICING.resumeOptimize, ...value?.resumeOptimize },
resumeDownload: { ...DEFAULT_PRICING.resumeDownload, ...value?.resumeDownload },
+6 -4
View File
@@ -5,6 +5,7 @@ import { Model } from 'mongoose'
import { JwtService } from '@nestjs/jwt'
import { User, UserDocument } from './user.schema'
import { EmailService } from '../email/email.service'
import { PricingService } from '../schemas/pricing.service'
/** 通过 IP 查询粗略地理位置(ip-api.com 免费接口) */
async function lookupIpLocation(ip: string): Promise<string> {
@@ -30,6 +31,7 @@ export class UserService {
@InjectModel(User.name) private userModel: Model<UserDocument>,
private jwtService: JwtService,
private emailService: EmailService,
private pricingService: PricingService,
) {}
async sendCode(phone: string) {
@@ -58,7 +60,7 @@ export class UserService {
let user = await this.userModel.findOne({ phone }).exec()
if (!user) {
user = await this.userModel.create({ phone, nickname: `用户${phone.slice(-4)}`, gravity: 5 })
user = await this.userModel.create({ phone, nickname: `用户${phone.slice(-4)}`, gravity: (await this.pricingService.getConfig()).registrationGravity })
}
await this.recordLogin(user._id.toString(), ip)
@@ -94,7 +96,7 @@ export class UserService {
let user = await this.userModel.findOne({ wxOpenid: openid }).exec()
if (!user) {
user = await this.userModel.create({ wxOpenid: openid, nickname: '微信用户', gravity: 5 })
user = await this.userModel.create({ wxOpenid: openid, nickname: '微信用户', gravity: (await this.pricingService.getConfig()).registrationGravity })
}
await this.recordLogin(user._id.toString(), ip)
@@ -170,7 +172,7 @@ export class UserService {
if (!user) {
isNew = true
const nick = email.split('@')[0]
user = await this.userModel.create({ email, nickname: nick, remaining: 0, gravity: 5 })
user = await this.userModel.create({ email, nickname: nick, remaining: 0, gravity: (await this.pricingService.getConfig()).registrationGravity })
}
await this.recordLogin(user._id.toString(), ip)
return { ...this.generateAuthResponse(user), isNew, hasPassword: !!user.password }
@@ -208,7 +210,7 @@ export class UserService {
}
const nick = email.split('@')[0]
const hashed = await bcrypt.hash(password, 10)
const user = await this.userModel.create({ email, nickname: nick, password: hashed, remaining: 0, gravity: 5 })
const user = await this.userModel.create({ email, nickname: nick, password: hashed, remaining: 0, gravity: (await this.pricingService.getConfig()).registrationGravity })
await this.recordLogin(user._id.toString(), ip)
return this.generateAuthResponse(user)
}