// Player auth modal component const { useState, useEffect } = React; function PlayerAuthModal({ isOpen, onClose, onLoginSuccess, currentPlayer, onLogout, viewOtherPlayer, lang }) { const str = window.UI_STRINGS[lang] || window.UI_STRINGS.zh; const [mode, setMode] = useState('login'); const [isEdit, setIsEdit] = useState(false); const [qq, setQq] = useState(''); const [gameId, setGameId] = useState(''); const [password, setPassword] = useState(''); const [confirmPw, setConfirmPw] = useState(''); const [externalContact, setExternalContact] = useState(''); const [userRegionMode, setUserRegionMode] = useState('cn'); const [error, setError] = useState(''); const [success, setSuccess] = useState(''); const [loading, setLoading] = useState(false); const [showIdConfirm, setShowIdConfirm] = useState(false); const isViewOther = !!viewOtherPlayer; const targetPlayer = isViewOther ? viewOtherPlayer : currentPlayer; useEffect(() => { if (isOpen) { setError(''); setSuccess(''); setIsEdit(false); setShowIdConfirm(false); setUserRegionMode('cn'); setExternalContact(''); if (targetPlayer) { setMode('profile'); setQq(targetPlayer.qq || ''); setGameId(targetPlayer.gameId || ''); setExternalContact(targetPlayer.contactExternal || ''); } else { setMode('login'); setQq(''); setGameId(''); setPassword(''); setConfirmPw(''); } } }, [isOpen, targetPlayer]); if (!isOpen) return null; const handleLogin = async (e) => { e.preventDefault(); setError(''); setSuccess(''); setLoading(true); const data = await window.api.playerLogin(qq, password); setLoading(false); if (data.success) { localStorage.setItem('player_token', data.token); onLoginSuccess(data.player); onClose(); } else { setError(data.error || '登录失败'); } }; const onClickRegisterCheck = (e) => { e.preventDefault(); setError(''); if (!/^\d{6,12}$/.test(gameId)) { return setError('游戏ID只能填写6‑12位纯数字!'); } if (password !== confirmPw) { return setError('两次输入的密码不一致'); } if (userRegionMode === 'cn') { if (!qq) return setError('国内模式请填写QQ号'); } else { if (!externalContact) return setError('海外模式请填写Discord纯数字ID或者联系邮箱'); } setShowIdConfirm(true); }; const doRealRegister = async () => { setShowIdConfirm(false); setLoading(true); const registerPayload = { qq: userRegionMode === 'cn' ? qq : '', contactExternal: userRegionMode === 'intl' ? externalContact : '', gameId: gameId, password: password, regionMode: userRegionMode }; const data = await window.api.playerRegister(registerPayload); setLoading(false); if (data.success) { if (data.needConfirmation) { setSuccess(data.message || '注册成功!请检查邮箱确认。'); // 不清除表单,让用户看到自己填的内容 } else { localStorage.setItem('player_token', data.token); onLoginSuccess(data.player); onClose(); } } else { setError(data.error || '注册失败'); } }; const handleUpdateProfile = async (e) => { e.preventDefault(); setError(''); setSuccess(''); setLoading(true); const payload = {}; if (password) { if (!confirmPw) return setError('请填写原密码'); payload.current_password = confirmPw; payload.new_password = password; } const data = await window.api.playerUpdate(payload); setLoading(false); if (data.success) { setSuccess('密码修改成功!'); onLoginSuccess(data.player); setPassword(''); setConfirmPw(''); setIsEdit(false); } else { setError(data.error || '修改失败'); } }; const handleLogout = () => { localStorage.removeItem('player_token'); onLogout(); onClose(); }; // ===== 样式对象(与之前一致)===== const modalStyle = { position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center', backdropFilter: 'blur(2px)', }; const boxStyle = { background: 'linear-gradient(180deg, var(--bg-1), var(--bg-2))', border: '1px solid var(--border-0)', borderRadius: 6, padding: 28, width: 420, maxWidth: '90vw', boxShadow: '0 20px 60px rgba(0,0,0,0.5), 0 0 40px rgba(196,90,58,0.08)', }; const confirmOverlayStyle = { position: 'fixed', inset: 0, zIndex: 2000, background: 'rgba(0,0,0,0.7)', display: 'flex', alignItems: 'center', justifyContent: 'center' }; const confirmBoxStyle = { background: 'var(--bg-1)', border: '1px solid var(--border-0)', borderRadius: 6, padding: 22, width: 340, maxWidth: '90vw' }; const btnPrimary = { width: '100%', padding: '10px 0', background: 'linear-gradient(135deg, var(--accent-rust), var(--accent-rust-dim))', border: '1px solid var(--accent-rust)', borderRadius: 3, color: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 500, boxShadow: '0 2px 6px rgba(196,90,58,0.3)', fontFamily: 'var(--sans)', marginTop: 6, opacity: loading ? 0.6 : 1, }; const btnSecondary = { padding: '6px 0', background: 'transparent', border: 'none', color: 'var(--accent-mustard)', cursor: 'pointer', fontSize: 12, fontFamily: 'var(--sans)', }; const btnRow = { display: 'flex', gap: 10, marginTop: 16 }; const inputSt = { width: '100%', height: 38, padding: '0 10px', background: 'var(--bg-0)', border: '1px solid var(--border-1)', borderRadius: 3, color: 'var(--text-0)', fontSize: 13, fontFamily: 'var(--sans)', outline: 'none', }; const inputDisabled = { ...inputSt, opacity: 0.5, cursor: "not-allowed" }; const labelSt = { display: 'block', color: 'var(--text-2)', fontSize: 11, marginBottom: 5, letterSpacing: 0.5, }; const radioWrap = { display: "flex", gap: "16px", margin: "6px 0 12px 0" }; return (