'use client' import { useEffect, useRef, useState, useCallback } from 'react' const TOWER_META = [ { type: 'outsource', name: '外包程序员', cost: 30, desc: '近战 8伤', color: '#94A3B8', img: '/game-assets/tower-outsource.png', tip: '廉价但30%丢空,5%自伤' }, { type: 'intern', name: '00后实习生', cost: 50, desc: '近战 15伤', color: '#22C55E', img: '/game-assets/tower-intern.png', tip: '整顿职场:5%概率秒杀' }, { type: 'hrbp', name: 'HRBP', cost: 80, desc: '辅助+20%攻速', color: '#EC4899', img: '/game-assets/tower-hrbp.png', tip: '打鸡血:周围塔攻速+20%' }, { type: 'ops', name: '运营专员', cost: 90, desc: '溅射 18伤', color: '#8B5CF6', img: '/game-assets/tower-ops.png', tip: '增长黑客:20%双倍HC' }, { type: 'ppt', name: 'PPT大师', cost: 100, desc: 'AOE减速', color: '#F59E0B', img: '/game-assets/tower-ppt.png', tip: '黑话领域:减速40%' }, { type: 'senior', name: 'P6资深开发', cost: 120, desc: '远程 30伤', color: '#3B82F6', img: '/game-assets/tower-senior.png', tip: '代码屎山:附带持续伤害' }, { type: 'pm', name: '产品经理', cost: 160, desc: '需求变更', color: '#06B6D4', img: '/game-assets/tower-pm.png', tip: '需求变更:每4次把怪打回去' }, ] as const type TowerType = 'outsource' | 'intern' | 'hrbp' | 'ops' | 'ppt' | 'senior' | 'pm' type EffectType = 'attack_boost' | 'speed_boost' | 'money_rain' | 'rage_mode' | 'backfire' interface PuaResult { score: number title: string desc: string effect: EffectType cost?: number // 实际扣除的 HC(前端填写) } const EFFECT_META: Record = { attack_boost: { label: '攻击力提升', color: '#22C55E', icon: '⚔️' }, speed_boost: { label: '攻速暴增', color: '#FBBF24', icon: '⚡' }, money_rain: { label: 'HC暴击', color: '#A78BFA', icon: '💰' }, rage_mode: { label: '全场狂暴', color: '#FF4E00', icon: '🔥' }, backfire: { label: '废话翻车', color: '#6B7280', icon: '💀' }, } const PUA_PLACEHOLDERS = [ '今天是本季度最关键的一天,大家冲!', '不拼搏,对不起父母的养育之恩...', '996是福报,感恩公司给的机会', '我们要有狼性精神,卷赢对手!', '大家加油,相信自己!', ] // ── 费用计算:基于当前HC的15%,最低20,最高200,取整到10的倍数 ──────────── function calcPuaCost(hc: number): number { const raw = Math.ceil(hc * 0.15) const rounded = Math.ceil(raw / 10) * 10 // 向上取到整十 return Math.max(20, Math.min(200, rounded)) } // ── PUA 输入面板 ───────────────────────────────────────────────────────────── function PuaPanel({ gameReady, hc, waveStarted }: { gameReady: boolean; hc: number; waveStarted: boolean }) { const [text, setText] = useState('') const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [history, setHistory] = useState([]) const [insufficient, setInsufficient] = useState(false) const textareaRef = useRef(null) const placeholder = useRef(PUA_PLACEHOLDERS[Math.floor(Math.random() * PUA_PLACEHOLDERS.length)]).current const cost = calcPuaCost(hc) const canAfford = hc >= cost const handleSubmit = useCallback(async () => { if (!text.trim() || loading || !gameReady || !waveStarted) return // 先从游戏扣除 HC(扣不到则拒绝) const spendHC: ((n: number) => boolean) | undefined = typeof window !== 'undefined' ? (window as any).__gameSpendHC : undefined const currentHC: number = typeof window !== 'undefined' ? ((window as any).__gameGetHC?.() ?? hc) : hc const actualCost = calcPuaCost(currentHC) if (!spendHC?.(actualCost)) { setInsufficient(true) setTimeout(() => setInsufficient(false), 2000) return } setLoading(true) setResult(null) setInsufficient(false) try { const res = await fetch('/api/pua-score', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text.trim() }), }) const data: PuaResult & { cost?: number } = await res.json() data.cost = actualCost setResult(data) setHistory(prev => [data, ...prev].slice(0, 5)) // 通知游戏场景应用 buff if (typeof window !== 'undefined') { ;(window as any).__gamePuaBuff?.(data.effect, data.score, data.title) } } catch { setResult({ score: 1, title: '网络故障', desc: 'AI开小差了', effect: 'backfire' }) } finally { setLoading(false) } }, [text, loading, gameReady, hc, waveStarted]) const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleSubmit() } } const scoreColor = (s: number) => s >= 9 ? '#FF4E00' : s >= 7 ? '#FBBF24' : s >= 4 ? '#22C55E' : '#6B7280' return (
{/* 标题 */}
PUA 激励台
{!waveStarted ? '⚠ 召唤第一波后才能激励' : '输入打鸡血的话,AI判断鸡血值'}
{/* 费用提示 */}
激励费用
-{cost} HC {!canAfford && ( 余额不足 )}
{/* HC 不足闪烁提示 */} {insufficient && (
HC 不足!先去打怪赚钱!
)} {/* 输入框 */}