import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import { useUserStore } from '../store'; import { setWxerwma, wxId } from '@/wx/ws-login.ts'; import { checkCaptcha } from '@/wx/tencent-captcha.ts'; import { dynimicLoadTcapTcha } from '@/wx/load-js.ts'; import { message } from '@/modules/message'; import { useShallow } from 'zustand/react/shallow'; import { WeChatMpLogin } from './modules/WeChatMpLogin'; const WeChatLogin: React.FC = () => { const userStore = useUserStore( useShallow((state) => { return { config: state.config! }; }), ); useEffect(() => { setWxerwma({ ...userStore.config.wxLogin, }); }, []); return
; }; type VerificationCodeInputProps = { onGetCode: () => void; verificationCode: string; setVerificationCode: (value: string) => void; }; const VerificationCodeInput = forwardRef(({ onGetCode, verificationCode, setVerificationCode }: VerificationCodeInputProps, ref) => { // const [verificationCode, setVerificationCode] = useState('') const [isCounting, setIsCounting] = useState(false); const [countdown, setCountdown] = useState(60); useImperativeHandle(ref, () => ({ isCounting, setIsCounting, setCountdown, })); const handleGetCode = () => { if (!isCounting) { // setIsCounting(true) // setCountdown(60) onGetCode(); // 调用父组件传入的获取验证码逻辑 } }; useEffect(() => { let timer; if (isCounting) { timer = setInterval(() => { setCountdown((prev) => { if (prev <= 1) { setIsCounting(false); clearInterval(timer); return 60; } return prev - 1; }); }, 1000); } return () => clearInterval(timer); }, [isCounting]); return (
setVerificationCode(e.target.value)} />
); }); function PhoneNumberValidation({ phoneNumber, setPhoneNumber }) { // const [phoneNumber, setPhoneNumber] = useState('') const [errorMessage, setErrorMessage] = useState(''); const validatePhoneNumber = (number) => { // 假设手机号的格式为中国的11位数字 const phoneRegex = /^1[3-9]\d{9}$/; if (!phoneRegex.test(number)) { setErrorMessage('请输入有效的手机号'); } else { setErrorMessage(''); } }; const handleChange = (e) => { const value = e.target.value; setPhoneNumber(value); validatePhoneNumber(value); }; return (
{errorMessage &&

{errorMessage}

} {!errorMessage &&

请输入11位手机号

}
); } function AccountLogin({ accountName, setAccountName, password, setPassword }) { const [errorMessage, setErrorMessage] = useState(''); const validateAccountName = (name) => { if (name.length < 3) { setErrorMessage('账户名至少需要3个字符'); } else { setErrorMessage(''); } }; const handleAccountChange = (e) => { const value = e.target.value; setAccountName(value); validateAccountName(value); }; const handlePasswordChange = (e) => { setPassword(e.target.value); }; const onTestAccountLogin = () => { setAccountName('demo'); setPassword('123456'); }; return (
{errorMessage &&

{errorMessage}

} {!errorMessage &&

账户名至少需要3个字符

}
{ onTestAccountLogin(); }}> 试用账号登录
); } const LoginForm: React.FC = () => { const [phoneNumber, setPhoneNumber] = useState(''); const [verificationCode, setVerificationCode] = useState(''); const [accountName, setAccountName] = useState(''); const [password, setPassword] = useState(''); const [activeTab, setActiveTab] = useState<'phone' | 'wechat' | 'wechat-mp' | 'account'>('phone'); const userStore = useUserStore( useShallow((state) => { return { config: state.config! || {}, getCode: state.getCode, login: state.login, loginByAccount: state.loginByAccount, }; }), ); const ref = useRef(null); const handleGetCode = async () => { const loaded = await dynimicLoadTcapTcha(); if (!loaded) { message.error('验证码加载失败'); return; } const captcha = await checkCaptcha(userStore.config.captchaAppId); if (captcha.ret !== 0) { message.error('验证码发送失败'); return; } ref.current.setIsCounting(true); ref.current.setCountdown(60); userStore.getCode(phoneNumber, captcha); }; useEffect(() => { dynimicLoadTcapTcha(); if (userStore.config.loginWay?.length > 0) { setActiveTab(userStore.config.loginWay[0]); } }, [userStore.config.loginWay]); const handleLogin = () => { // alert(`登录中:手机号: ${phoneNumber}, 验证码: ${verificationCode}`) userStore.login(phoneNumber, verificationCode); }; const inLoginWay = (way: string) => { const loginWay = userStore.config?.loginWay || []; return loginWay.includes(way); }; const handleAccountLogin = () => { if (!accountName || !password) { message.error('请输入账户名和密码'); return; } userStore.loginByAccount(accountName, password); }; useListenEnter({ active: activeTab === 'phone', handleLogin }); useListenEnter({ active: activeTab === 'account', handleLogin: handleAccountLogin }); const tab = useMemo(() => { const phoneCom = ( ); const wechatCom = ( ); const wechatMpCom = ( ); const accountCom = ( ); const coms: React.ReactNode[] = []; for (const way of userStore.config.loginWay) { if (way === 'phone') { coms.push(phoneCom); } else if (way === 'wechat') { coms.push(wechatCom); } else if (way === 'account') { coms.push(accountCom); } else if (way === 'wechat-mp') { coms.push(wechatMpCom); } } return coms; }, [userStore.config.loginWay, activeTab]); return (
{/* Tabs */}
{tab}
{/* Phone Login Form */} {activeTab === 'phone' && inLoginWay('phone') && (
)} {/* WeChat Login Placeholder */} {activeTab === 'wechat' && inLoginWay('wechat') && (
)} {activeTab === 'wechat-mp' && inLoginWay('wechat-mp') && (
)} {activeTab === 'account' && inLoginWay('account') && (
)}
); }; export default LoginForm; export const useListenEnter = (opts?: { active: boolean; handleLogin: () => void }) => { useEffect(() => { if (!opts?.active) { return; } const handleEnter = (e: KeyboardEvent) => { if (e.key === 'Enter') { opts?.handleLogin?.(); } }; window.addEventListener('keydown', handleEnter); return () => { window.removeEventListener('keydown', handleEnter); }; }, [opts?.active, opts?.handleLogin]); };