Files
botgroup.chat/src/pages/login/comonents/PhoneLogin.tsx
2025-07-18 18:35:41 +08:00

161 lines
6.0 KiB
TypeScript

import React, { useState } from 'react';
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { toast } from 'sonner';
import { request } from '@/utils/request';
import { useIsMobile } from '@/hooks/use-mobile';
import ClickTextCapt from "@/components/goCaptcha/ClickTextCapt.jsx";
interface PhoneLoginProps {
onLogin: (phone: string, code: string) => void;
}
const PhoneLogin: React.FC<PhoneLoginProps> = ({ handleLoginSuccess }) => {
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [countdown, setCountdown] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const [showCaptcha, setShowCaptcha] = useState(false); // 新增弹窗状态
const isMobile = useIsMobile();
// 获取备案号配置
const icpNumber = (window as any).APP_CONFIG?.ICP_NUMBER;
// 发送验证码成功后倒计时
const handleSendCodeSuccess = () => {
// 开始倒计时
setCountdown(60);
const timer = setInterval(() => {
setCountdown((prev) => {
if (prev <= 1) {
clearInterval(timer);
return 0;
}
return prev - 1;
});
}, 1000);
}
// 点击发送验证码按钮
const handleSendCode = async () => {
if (!phone || !/^1[3-9]\d{9}$/.test(phone)) {
toast.error('请输入正确的手机号');
return;
}
setShowCaptcha(true); // 弹出图形验证码弹窗
};
// 图形验证码通过后的回调
// const handleCaptchaSuccess = async () => {
// setShowCaptcha(false);
// await realSendCode();
// };
// 提交登录
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!phone || !code) {
toast.error('请输入手机号和验证码');
return;
}
setIsLoading(true);
try {
const response = await request(`/api/login`, {
method: 'POST',
body: JSON.stringify({ phone, code }),
});
const data = await response.json();
//执行登录成功回调
handleLoginSuccess(data.data.token);
} catch (error) {
console.error('登录失败:', error);
toast.error(error instanceof Error ? error.message : '登录失败,请重试');
} finally {
setIsLoading(false);
}
};
return (
<div className="fixed inset-0 bg-white flex items-center justify-center">
<div className={`w-full ${isMobile ? 'max-w-sm px-6' : 'max-w-md px-8'} ${isMobile ? 'py-6' : 'py-8'}`}>
{/* Logo */}
<div className="flex items-center justify-center mb-6">
<span
style={{fontFamily: 'Audiowide, system-ui', color: '#ff6600'}}
className={`${isMobile ? 'text-2xl' : 'text-3xl'} ml-2`}
>
botgroup.chat
</span>
</div>
<div className={`text-gray-500 ${isMobile ? 'mb-6' : 'mb-4'} text-center ${isMobile ? 'text-sm' : 'text-base'}`}>
</div>
<form onSubmit={handleSubmit} className={`${isMobile ? 'space-y-4' : 'space-y-6'}`}>
<div>
<div className={`flex items-center border rounded-lg ${isMobile ? 'p-2.5' : 'p-3'} ${isMobile ? 'h-[42px]' : 'h-[46px]'} focus-within:border-[#ff6600]`}>
<span className={`text-gray-400 mr-2 ${isMobile ? 'text-sm' : 'text-base'}`}>+86</span>
<Input
type="tel"
placeholder="请输入手机号"
value={phone}
onChange={(e) => setPhone(e.target.value)}
maxLength={11}
className={`border-none focus:ring-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none p-0 ${isMobile ? 'text-sm' : 'text-base'}`}
/>
</div>
</div>
<div>
<div className={`flex ${isMobile ? 'gap-2' : 'gap-3'}`}>
<Input
type="text"
placeholder="请输入验证码"
value={code}
onChange={(e) => setCode(e.target.value)}
maxLength={6}
className={`border rounded-lg ${isMobile ? 'p-2.5' : 'p-3'} ${isMobile ? 'h-[42px]' : 'h-[46px]'} focus:border-[#ff6600] focus:ring-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none ${isMobile ? 'text-sm' : 'text-base'}`}
/>
<Button
type="button"
onClick={handleSendCode}
disabled={countdown > 0 || isLoading}
className={`bg-white text-[#ff6600] border border-[#ff6600] hover:bg-[#ff6600] hover:text-white rounded-lg ${isMobile ? 'px-3 h-[42px] text-xs' : 'px-6 h-[46px] text-sm'} whitespace-nowrap`}
>
{countdown > 0 ? `${countdown}秒后重试` : '发送验证码'}
</Button>
</div>
</div>
<Button
type="submit"
className={`w-full bg-[#ff6600] hover:bg-[#e65c00] text-white rounded-lg ${isMobile ? 'py-2.5 text-sm' : 'py-3 text-base'}`}
disabled={isLoading}
>
{isLoading ? (
<div className="w-4 h-4 mr-2 animate-spin rounded-full border-2 border-white border-t-transparent" />
) : '登录'}
</Button>
</form>
{/* 弹窗形式的图形验证码 */}
{showCaptcha && (
<div className="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50">
<div className={`${isMobile ? 'mx-4' : 'mx-0'}`}>
<ClickTextCapt onVisibleChange={setShowCaptcha} onSuccess={handleSendCodeSuccess} extraData={{phone}} />
</div>
</div>
)}
{/* 备案号显示 */}
{icpNumber && (
<div className={`text-center ${isMobile ? 'mt-6' : 'mt-8'} text-xs text-gray-400`}>
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">{icpNumber}</a>
</div>
)}
</div>
</div>
);
};
export default PhoneLogin;