// ============================================================ // LoginPage — 登录/注册 Modal 弹层 // // 行为: // - 未登录时弹出,不可操作主页(Modal 遮罩) // - 可关闭(右上 X),关闭后主页可操作,但 API 401 时会再次弹出 // - 登录成功 → 关闭 Modal,更新全局登录态 // ============================================================ import { useState, useCallback } from 'react'; import { Modal, Tabs, Typography, App } from 'antd'; import { useAppContext } from '@/contexts/app-context.ts'; import { useTheme } from '@/hooks/use-theme.ts'; import { LoginForm } from './components/LoginForm'; import { RegisterForm } from './components/RegisterForm'; import { useAuthState, getStoredPassword } from './hooks/use-auth-state'; import {AuthAPI, LoginResponseBody} from '@/services/modules'; import { getDeviceId } from '@/utils/device'; import type { LoginFormValues, RegisterFormValues } from './types'; const { Text } = Typography; interface LoginPageProps { open: boolean; onClose: () => void; } export function LoginPage({ open, onClose }: LoginPageProps) { const { edition, login } = useAppContext(); const { isDark } = useTheme(); const { message } = App.useApp(); const isEnterprise = edition === 'enterprise'; const [activeTab, setActiveTab] = useState('login'); const [submitting, setSubmitting] = useState(false); const authState = useAuthState(); // ========== 登录 ========== const handleLogin = useCallback( async (values: LoginFormValues) => { setSubmitting(true); try { const auth:LoginResponseBody = await AuthAPI.login({ username: values.username, password: values.password, device_id: getDeviceId(), user_ip: '', }); // 记住偏好(密码 Base64 编码,自动登录靠 refresh_token) authState.saveAuth(values.username, values.password, values.remember, values.autoLogin); // 更新全局登录态(内部完成 setToken + emit LOGIN_SUCCESS) login(auth); message.success(`登录成功,欢迎 ${auth.display_name || auth.username}`); onClose(); } catch (err) { message.error((err as Error).message || '登录失败,请检查用户名和密码'); } finally { setSubmitting(false); } }, [authState, message, login, onClose], ); // ========== 注册 ========== const handleRegister = useCallback( async (values: RegisterFormValues) => { setSubmitting(true); try { await AuthAPI.register({ username: values.username, password: values.password, phone: values.phone, sms_code: values.sms_code, device_id: values.device_id || getDeviceId(), device_label: values.device_label || '', display_name: values.display_name || '', referral_code: values.referral_code || '', }); message.success('注册成功,请登录'); setActiveTab('login'); } catch (err) { message.error((err as Error).message || '注册失败'); } finally { setSubmitting(false); } }, [message], ); const handleSendSms = useCallback( async (phone: string) => { try { await AuthAPI.sendSms({ phone }); message.success('验证码已发送'); } catch (err) { message.error((err as Error).message || '验证码发送失败'); } }, [message], ); // ========== 渲染 ========== const loginTab = ( ); const registerTab = ( ); return ( {/* 标题 */}
船长 · HeiXiu {isEnterprise ? '企业版 — 员工账号登录' : '个人版'}
{/* 个人版 Tab | 企业版仅登录 */} {isEnterprise ? ( loginTab ) : ( )}
); }