Files
template-10519/src/passport/login.tsx
赵忠林 6bf4799789 feat(passport): 更新登录页面交互逻辑
- 修改手机号输入框提示文案为“请输入账号”- 移除手机号格式校验逻辑
- 将短信验证码输入框改为密码类型,并修改提示文案为“请输入密码”- 移除获取验证码按钮及相关倒计时逻辑
- 调整用户协议勾选框文案,去除“勾选表示您”前缀-优化登录接口调用参数格式
2025-11-04 17:03:55 +08:00

398 lines
10 KiB
TypeScript

import {useEffect, useState} from "react";
import Taro from '@tarojs/taro'
import {Input, Radio, Button} from '@nutui/nutui-react-taro'
import {loginBySms, getCaptcha, sendSmsCaptcha} from '@/api/passport/login'
const Login = () => {
const [isAgree, setIsAgree] = useState(false)
// 只保留短信登录方式
const [loginType, setLoginType] = useState('sms')
// const [username, setUsername] = useState('')
// const [password, setPassword] = useState('')
const [phone, setPhone] = useState('')
const [smsCode, setSmsCode] = useState('')
const [captchaImg, setCaptchaImg] = useState('')
const [captchaCode, setCaptchaCode] = useState('')
const [showCaptchaModal, setShowCaptchaModal] = useState(false)
const [countdown, setCountdown] = useState(0) // 短信验证码倒计时
const [loading, setLoading] = useState(false)
const reload = () => {
Taro.hideTabBar()
}
// 获取图形验证码
const fetchCaptcha = async () => {
try {
const res = await getCaptcha()
setCaptchaImg(res.base64)
} catch (error) {
Taro.showToast({
title: '获取验证码失败',
icon: 'error'
})
}
}
// 发送短信验证码
// const handleSendSmsCode = async () => {
// if (!phone) {
// Taro.showToast({
// title: '请输入手机号',
// icon: 'error'
// })
// return
// }
//
// // 验证手机号格式
// const phoneReg = /^1[3-9]\d{9}$/
// if (!phoneReg.test(phone)) {
// Taro.showToast({
// title: '手机号格式不正确',
// icon: 'error'
// })
// return
// }
//
// // 显示图形验证码弹窗
// fetchCaptcha()
// setShowCaptchaModal(true)
// }
// 确认发送短信验证码
const confirmSendSmsCode = async () => {
if (!captchaCode) {
Taro.showToast({
title: '请输入图形验证码',
icon: 'error'
})
return
}
try {
setLoading(true)
// 发送短信验证码时需要传入手机号和图形验证码
await sendSmsCaptcha({ phone, code: captchaCode })
Taro.showToast({
title: '短信验证码已发送',
icon: 'success'
})
setShowCaptchaModal(false)
setCaptchaCode('')
// 开始倒计时
setCountdown(60)
} catch (error) {
Taro.showToast({
title: error.message || '发送失败',
icon: 'error'
})
} finally {
setLoading(false)
}
}
// 短信验证码登录
const handleSmsLogin = async () => {
if (!phone) {
Taro.showToast({
title: '请输入账号',
icon: 'error'
})
return
}
// 验证手机号格式
// const phoneReg = /^1[3-9]\d{9}$/
// if (!phoneReg.test(phone)) {
// Taro.showToast({
// title: '手机号格式不正确',
// icon: 'error'
// })
// return
// }
if (!smsCode) {
Taro.showToast({
title: '请输入短信验证码',
icon: 'error'
})
return
}
try {
setLoading(true)
// 短信登录时传入手机号和短信验证码
const res = await loginBySms({ phone, code:smsCode })
console.log(res,'.......')
Taro.showToast({
title: '登录成功',
icon: 'success'
})
// 跳转到首页
setTimeout(() => {
Taro.switchTab({ url: '/pages/index/index' })
}, 1500)
} catch (error) {
Taro.showToast({
title: error.message || '登录失败',
icon: 'error'
})
} finally {
setLoading(false)
}
}
// 登录处理
const onLogin = async () => {
if (!isAgree) {
Taro.showToast({
title: '请先同意服务协议',
icon: 'error'
})
return
}
handleSmsLogin()
}
// 倒计时处理
useEffect(() => {
let timer: any
if (countdown > 0) {
timer = setTimeout(() => {
setCountdown(countdown - 1)
}, 1000)
}
return () => clearTimeout(timer)
}, [countdown])
useEffect(() => {
reload()
}, [])
return (
<>
<div style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
padding: '0 20px',
minHeight: '70vh',
backgroundColor: '#f5f5f5'
}}>
<div style={{
fontSize: '24px',
textAlign: 'center',
padding: '20px 0',
fontWeight: 'normal',
margin: '20px 0 20px 0'
}}></div>
{/* 登录方式切换 - 隐藏账号登录 */}
<div style={{
display: 'none', // 隐藏登录方式切换
justifyContent: 'center',
marginBottom: '20px'
}}>
<div
style={{
padding: '10px 20px',
borderBottom: loginType === 'account' ? '2px solid #1890ff' : 'none',
color: loginType === 'account' ? '#1890ff' : '#999',
cursor: 'pointer'
}}
onClick={() => setLoginType('account')}
>
</div>
<div
style={{
padding: '10px 20px',
borderBottom: loginType === 'sms' ? '2px solid #1890ff' : 'none',
color: loginType === 'sms' ? '#1890ff' : '#999',
cursor: 'pointer'
}}
onClick={() => setLoginType('sms')}
>
</div>
</div>
{/* 短信验证码登录 - 始终显示 */}
<div>
<div style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'center',
margin: '10px 0'
}}>
<Input
type="text"
placeholder="请输入账号"
value={phone}
onChange={(val) => setPhone(val)}
style={{
backgroundColor: '#ffffff',
borderRadius: '8px',
width: '100%',
padding: '10px'
}}
/>
</div>
<div style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'center',
margin: '10px 0'
}}>
<div style={{
display: 'flex',
width: '100%',
backgroundColor: '#ffffff',
borderRadius: '8px'
}}>
<Input
type="password"
placeholder="请输入密码"
value={smsCode}
onChange={(val) => setSmsCode(val)}
style={{
flex: 1,
border: 'none',
padding: '10px'
}}
/>
</div>
</div>
</div>
<div style={{
display: 'flex',
justifyContent: 'center',
margin: '20px 0'
}}>
<Button
type="info"
size={'large'}
style={{
width: '100%',
borderRadius: '8px',
padding: '10px'
}}
disabled={!isAgree}
loading={loading}
onClick={onLogin}
>
</Button>
</div>
<div style={{
display: 'flex',
alignItems: 'center',
padding: '0 5px',
margin: '10px 0'
}}>
<Radio
style={{color: '#333333'}}
checked={isAgree}
onClick={() => setIsAgree(!isAgree)}
/>
<span style={{color: '#999', marginLeft: '5px'}} onClick={() => setIsAgree(!isAgree)}></span>
<a
onClick={() => Taro.navigateTo({url: '/passport/agreement'})}
style={{color: '#1890ff'}}
>
</a>
</div>
</div>
{/* 图形验证码弹窗 */}
{showCaptchaModal && (
<div style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 9999
}}>
<div style={{
backgroundColor: '#fff',
borderRadius: '8px',
padding: '20px',
width: '80%'
}}>
<div style={{
textAlign: 'center',
fontWeight: 'bold',
marginBottom: '15px',
fontSize: '16px'
}}></div>
<div style={{
display: 'flex',
justifyContent: 'center',
marginBottom: '15px'
}}>
{captchaImg && (
<img
src={`data:image/png;base64,${captchaImg}`}
alt="验证码"
style={{
width: '128px',
height: '48px',
cursor: 'pointer'
}}
onClick={fetchCaptcha}
/>
)}
</div>
<Input
type="text"
placeholder="请输入验证码"
value={captchaCode}
onChange={(val) => setCaptchaCode(val)}
style={{
marginBottom: '15px'
}}
/>
<div style={{
display: 'flex',
justifyContent: 'space-between'
}}>
<Button
type="default"
onClick={() => {
setShowCaptchaModal(false)
setCaptchaCode('')
}}
>
</Button>
<Button
type="info"
loading={loading}
onClick={confirmSendSmsCode}
>
</Button>
</div>
</div>
</div>
)}
</>
)
}
export default Login