Files
wzdj/lib/utils/account-evaluation.ts
v0 e267fa09f6 feat: enhance live room and planet matchmaking features
Add fan group entry on live room; update planet matching with 4 type buttons.

Co-authored-by: undefined <undefined+undefined@users.noreply.github.com>
2025-12-01 10:46:13 +00:00

134 lines
4.1 KiB
TypeScript

import { GAME_DATA } from "@/lib/data/game-data"
export type EvaluationInput = {
gameName: string
serverType: string // "热门服" | "普通服" | "鬼服"
currentLevel: number
maxLevel: number
rankName: string
// Assets
assetCounts: {
legendary: number // 传说级
epic: number // 史诗级
rare: number // 优质级
common: number // 普通级
}
// Bonus
registrationMonths: number
rechargeAmount6Months: number
mallConsumption?: number // Added mall consumption parameter
// Risk
isRealNameVerified: boolean
isRealNameOwner: boolean
hasBanRecord: boolean
}
export type EvaluationResult = {
totalScore: number
valuation: number // Preliminary valuation
loanAmount: number // Loan amount
details: {
baseScore: number
assetScore: number
bonusScore: number
riskCoefficient: number
consumptionMultiplier: number // Added consumption multiplier to result
}
}
export function evaluateAccount(input: EvaluationInput): EvaluationResult {
const gameConfig = GAME_DATA.games[input.gameName] || { score: 20, ranks: {} }
// 1. Base Value Score (Max 50)
// Game Score (Max 30)
const gameScore = gameConfig.score
// Server Score (Max 10)
const serverScore = GAME_DATA.server_scores[input.serverType] || 8
// Level Score (Max 10)
// Score = (Current / Max) * 10
const levelRatio = Math.min(input.currentLevel / (input.maxLevel || 100), 1)
const levelScore = Number.parseFloat((levelRatio * 10).toFixed(1))
const baseScore = gameScore + serverScore + levelScore
// 2. Core Asset Score (Max 30)
// Asset Score = Sum(Count * Weight)
// Cap count at 20 to avoid outliers as per requirements
const getAssetScore = (count: number, weight: number) => Math.min(count, 20) * weight
const assetBaseScore =
getAssetScore(input.assetCounts.legendary, GAME_DATA.asset_weights["传说级"]) +
getAssetScore(input.assetCounts.epic, GAME_DATA.asset_weights["史诗级"]) +
getAssetScore(input.assetCounts.rare, GAME_DATA.asset_weights["优质级"]) +
getAssetScore(input.assetCounts.common, GAME_DATA.asset_weights["普通级"])
// Rank Bonus
const rankBonus = gameConfig.ranks ? gameConfig.ranks[input.rankName] || 0 : 0
const coreAssetScore = Math.min(assetBaseScore + rankBonus, 30)
// 3. Bonus Score (Max 20)
let timeScore = 0
if (input.registrationMonths >= 25) timeScore = 10
else if (input.registrationMonths >= 13) timeScore = 8
else if (input.registrationMonths >= 7) timeScore = 5
else timeScore = 3
// Recharge Amount (Max 10)
// Score = min(Amount * 0.001, 10)
const rechargeScore = Math.min(input.rechargeAmount6Months * 0.001, 10)
const bonusScore = timeScore + rechargeScore
// 4. Risk Correction Coefficient
let riskKey = "未实名"
if (input.isRealNameVerified) {
if (input.isRealNameOwner) {
riskKey = input.hasBanRecord ? "本人_有封号" : "本人_无封号"
} else {
riskKey = input.hasBanRecord ? "非本人_有封号" : "非本人_无封号"
}
}
const riskCoefficient = GAME_DATA.correction_coeffs[riskKey] || 0.7
let consumptionMultiplier = 1.0
const consumption = input.mallConsumption || 0
if (consumption >= 2000) {
consumptionMultiplier = GAME_DATA.consumption_weights.level4
} else if (consumption >= 500) {
consumptionMultiplier = GAME_DATA.consumption_weights.level3
} else if (consumption >= 100) {
consumptionMultiplier = GAME_DATA.consumption_weights.level2
} else {
consumptionMultiplier = 1.0
}
// Final Calculation
const totalScore = Number.parseFloat(((baseScore + coreAssetScore + bonusScore) * riskCoefficient).toFixed(2))
const valuation = Math.floor(totalScore * GAME_DATA.base_multiple)
let loanAmount = Math.floor(valuation * 0.6 * consumptionMultiplier)
if (loanAmount < 500) {
loanAmount = 0
}
return {
totalScore,
valuation,
loanAmount,
details: {
baseScore: Number.parseFloat(baseScore.toFixed(1)),
assetScore: Number.parseFloat(coreAssetScore.toFixed(1)),
bonusScore: Number.parseFloat(bonusScore.toFixed(1)),
riskCoefficient,
consumptionMultiplier, // Return multiplier for UI display
},
}
}