forked from gxwebsoft/mp-10550
- 切换API基础URL到生产环境地址 - 在商品详情页添加邀请参数解析和存储逻辑 - 实现分享链接携带邀请者ID和来源信息 - 新增商品分享来源类型标识 - 在短信登录成功后处理待绑定的邀请关系 - 添加邀请关系跟踪和统计功能
215 lines
5.1 KiB
TypeScript
215 lines
5.1 KiB
TypeScript
import {useEffect, useState} from "react";
|
|
import Taro from '@tarojs/taro'
|
|
import {Input, Button} from '@nutui/nutui-react-taro'
|
|
import {loginBySms, sendSmsCaptcha} from "@/api/passport/login";
|
|
import {LoginParam} from "@/api/passport/login/model";
|
|
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
|
|
|
|
const SmsLogin = () => {
|
|
const [loading, setLoading] = useState<boolean>(false)
|
|
const [sendingCode, setSendingCode] = useState<boolean>(false)
|
|
const [countdown, setCountdown] = useState<number>(0)
|
|
const [formData, setFormData] = useState<LoginParam>({
|
|
phone: '',
|
|
code: ''
|
|
})
|
|
|
|
const reload = () => {
|
|
Taro.hideTabBar()
|
|
}
|
|
|
|
useEffect(() => {
|
|
reload()
|
|
}, [])
|
|
|
|
// 倒计时效果
|
|
useEffect(() => {
|
|
let timer: NodeJS.Timeout
|
|
if (countdown > 0) {
|
|
timer = setTimeout(() => {
|
|
setCountdown(countdown - 1)
|
|
}, 1000)
|
|
}
|
|
return () => {
|
|
if (timer) clearTimeout(timer)
|
|
}
|
|
}, [countdown])
|
|
|
|
// 验证手机号格式
|
|
const validatePhone = (phone: string): boolean => {
|
|
const phoneRegex = /^1[3-9]\d{9}$/
|
|
return phoneRegex.test(phone)
|
|
}
|
|
|
|
// 发送短信验证码
|
|
const handleSendCode = async () => {
|
|
if (!formData.phone) {
|
|
Taro.showToast({
|
|
title: '请输入手机号码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
if (!validatePhone(formData.phone)) {
|
|
Taro.showToast({
|
|
title: '请输入正确的手机号码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
if (sendingCode || countdown > 0) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
setSendingCode(true)
|
|
await sendSmsCaptcha({ phone: formData.phone })
|
|
|
|
Taro.showToast({
|
|
title: '验证码已发送',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 开始60秒倒计时
|
|
setCountdown(60)
|
|
} catch (error: any) {
|
|
Taro.showToast({
|
|
title: error.message || '发送失败',
|
|
icon: 'error'
|
|
})
|
|
} finally {
|
|
setSendingCode(false)
|
|
}
|
|
}
|
|
|
|
// 处理登录
|
|
const handleLogin = async () => {
|
|
// 防止重复提交
|
|
if (loading) {
|
|
return
|
|
}
|
|
|
|
// 表单验证
|
|
if (!formData.phone) {
|
|
Taro.showToast({
|
|
title: '请输入手机号码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
if (!validatePhone(formData.phone)) {
|
|
Taro.showToast({
|
|
title: '请输入正确的手机号码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
if (!formData.code) {
|
|
Taro.showToast({
|
|
title: '请输入验证码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
if (formData.code.length !== 6) {
|
|
Taro.showToast({
|
|
title: '请输入6位验证码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
try {
|
|
setLoading(true)
|
|
|
|
await loginBySms({
|
|
phone: formData.phone,
|
|
code: formData.code
|
|
})
|
|
|
|
// 登录成功后(可能是新注册用户),检查是否存在待处理的邀请关系并尝试绑定
|
|
if (hasPendingInvite()) {
|
|
try {
|
|
await checkAndHandleInviteRelation()
|
|
} catch (e) {
|
|
console.error('短信登录后处理邀请关系失败:', e)
|
|
}
|
|
}
|
|
|
|
Taro.showToast({
|
|
title: '登录成功',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 延迟跳转到首页
|
|
setTimeout(() => {
|
|
Taro.reLaunch({
|
|
url: '/pages/index/index'
|
|
})
|
|
}, 1500)
|
|
|
|
} catch (error: any) {
|
|
Taro.showToast({
|
|
title: error.message || '登录失败',
|
|
icon: 'error'
|
|
})
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className={'flex flex-col justify-center px-5 pt-3'}>
|
|
<div className={'flex flex-col justify-between items-center my-2'}>
|
|
<Input
|
|
type="number"
|
|
placeholder="请输入手机号码"
|
|
maxLength={11}
|
|
value={formData.phone}
|
|
onChange={(value) => setFormData({...formData, phone: value})}
|
|
style={{backgroundColor: '#ffffff', borderRadius: '8px'}}
|
|
/>
|
|
</div>
|
|
<div className={'flex justify-between items-center bg-white rounded-lg my-2 pr-2'}>
|
|
<Input
|
|
type="number"
|
|
placeholder="请输入6位验证码"
|
|
maxLength={6}
|
|
value={formData.code}
|
|
onChange={(value) => setFormData({...formData, code: value})}
|
|
style={{ backgroundColor: '#ffffff', borderRadius: '8px'}}
|
|
/>
|
|
<Button
|
|
size="small"
|
|
type={countdown > 0 ? "default" : "primary"}
|
|
loading={sendingCode}
|
|
disabled={sendingCode || countdown > 0}
|
|
onClick={handleSendCode}
|
|
>
|
|
{countdown > 0 ? `${countdown}s` : sendingCode ? '发送中...' : '获取验证码'}
|
|
</Button>
|
|
</div>
|
|
<div className={'flex justify-center my-5'}>
|
|
<Button
|
|
type="info"
|
|
size={'large'}
|
|
className={'w-full rounded-lg p-2'}
|
|
loading={loading}
|
|
disabled={loading}
|
|
onClick={handleLogin}
|
|
>
|
|
{loading ? '登录中...' : '登录'}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
export default SmsLogin
|