From f8a7b414632442a1af6df420024e50df943fadd7 Mon Sep 17 00:00:00 2001 From: xianyi Date: Tue, 16 Dec 2025 17:42:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=99=BB=E5=BD=95=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/modals/LoginModal.tsx | 195 +++++++++++++++------------ 1 file changed, 106 insertions(+), 89 deletions(-) diff --git a/src/components/modals/LoginModal.tsx b/src/components/modals/LoginModal.tsx index c71f09c..e1e87f1 100644 --- a/src/components/modals/LoginModal.tsx +++ b/src/components/modals/LoginModal.tsx @@ -1,94 +1,94 @@ -import { useState, useEffect } from 'react'; +import { useEffect, useState } from 'react'; + +import { getVerificationCodeImage, loginByPassword } from '../../api'; import { Button, Input } from '../ui'; interface LoginModalProps { onClose: () => void; - onLoginSuccess?: (phone: string) => void; + onLoginSuccess?: (userName: string) => void; } +const APP_ID = 'b2b49e91d21446aeb14579930f732985'; + export const LoginModal = ({ onClose, onLoginSuccess }: LoginModalProps) => { - const [phone, setPhone] = useState(''); - const [code, setCode] = useState(''); - const [countdown, setCountdown] = useState(0); + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [imgCode, setImgCode] = useState(''); + const [imgCodeKey, setImgCodeKey] = useState(''); + const [imgCodeUrl, setImgCodeUrl] = useState(null); const [loading, setLoading] = useState(false); + const [imgLoading, setImgLoading] = useState(false); const [error, setError] = useState(''); - // 验证码倒计时 + const fetchImageCode = async () => { + setImgLoading(true); + setError(''); + try { + const res = await getVerificationCodeImage({ app_id: APP_ID }); + if (res.Status === 200 && res.Data) { + setImgCodeKey(res.Data.verification_code_key || ''); + // 后端返回的可能是 base64,直接作为 src + setImgCodeUrl(res.Data.verification_code_image || null); + } else { + setError(res.Message || '获取图形验证码失败'); + } + } catch (err) { + console.error('获取图形验证码失败', err); + setError('获取图形验证码失败,请稍后重试'); + } finally { + setImgLoading(false); + } + }; + useEffect(() => { - if (countdown > 0) { - const timer = setTimeout(() => setCountdown(countdown - 1), 1000); - return () => clearTimeout(timer); - } - }, [countdown]); + fetchImageCode(); + }, []); - // 验证手机号格式 - const validatePhone = (phoneNumber: string): boolean => { - return /^1[3-9]\d{9}$/.test(phoneNumber); - }; - - // 发送验证码 - const handleSendCode = async () => { - if (!phone) { - setError('请输入手机号'); - return; - } - if (!validatePhone(phone)) { - setError('请输入正确的手机号'); - return; - } - - setError(''); - setLoading(true); - - // 模拟发送验证码 API 调用 - await new Promise((resolve) => setTimeout(resolve, 1000)); - - setLoading(false); - setCountdown(60); // 60秒倒计时 - // 实际项目中,这里应该调用后端 API 发送验证码 - // 开发环境可以显示验证码(例如:123456) - // eslint-disable-next-line no-console - console.log('验证码已发送(开发环境:123456)'); - }; - - // 登录 const handleLogin = async () => { - if (!phone) { - setError('请输入手机号'); + if (!username.trim()) { + setError('请输入账号'); return; } - if (!validatePhone(phone)) { - setError('请输入正确的手机号'); + if (!password) { + setError('请输入密码'); return; } - if (!code) { - setError('请输入验证码'); + if (!imgCode.trim()) { + setError('请输入图形验证码'); return; } - if (code.length !== 6) { - setError('验证码应为6位数字'); + if (!imgCodeKey) { + setError('验证码失效,请刷新'); return; } setError(''); setLoading(true); - - // 模拟登录 API 调用 - await new Promise((resolve) => setTimeout(resolve, 1500)); - - // 开发环境:验证码为 123456 时通过 - if (code === '123456') { + try { + const res = await loginByPassword({ + username: username.trim(), + password, + verification_code: imgCode.trim(), + verification_code_key: imgCodeKey, + }); + if (res.Status === 200 && res.Data?.access_token) { + onLoginSuccess?.(res.Data.user_name || username.trim()); + onClose(); + } else { + setError(res.Message || '登录失败'); + // 登录失败时刷新验证码 + fetchImageCode(); + } + } catch (err) { + console.error('登录失败', err); + setError('登录失败,请稍后重试'); + fetchImageCode(); + } finally { setLoading(false); - onLoginSuccess?.(phone); - onClose(); - } else { - setLoading(false); - setError('验证码错误,请重新输入'); } }; - const canSendCode = countdown === 0 && !loading && phone.length === 11; - const canLogin = phone && code && !loading; + const canLogin = !!(username && password && imgCode && imgCodeKey && !loading); return (
@@ -105,47 +105,64 @@ export const LoginModal = ({ onClose, onLoginSuccess }: LoginModalProps) => {
- + { - const value = e.target.value.replace(/\D/g, '').slice(0, 11); - setPhone(value); + setUsername(e.target.value); setError(''); }} - maxLength={11} className='text-base' />
- -
+ + { + setPassword(e.target.value); + setError(''); + }} + className='text-base' + /> +
+ +
+ +
{ - const value = e.target.value.replace(/\D/g, '').slice(0, 6); - setCode(value); + setImgCode(e.target.value); setError(''); }} - maxLength={6} className='text-base flex-1' /> - -
-
- 开发环境:验证码为 123456 +
+ {imgLoading ? ( + 加载中… + ) : imgCodeUrl ? ( + 验证码 + ) : ( + + )} +
+
看不清?点击图片刷新
{error && ( @@ -156,9 +173,9 @@ export const LoginModal = ({ onClose, onLoginSuccess }: LoginModalProps) => {