feat(passport): 重构短信登录页并提供手机号授权降级入口
- 修复购物车数据库缺失 spec_info 字段问题,新增迁移脚本 - 登录页处理手机号授权失败,按错误类型弹窗引导用户改用短信登录 - 登录页新增长期显示的「使用短信验证码登录」入口,提升用户降级体验 - 注册页同步改造,去除微信小程序环境下短信按钮隐藏问题 - 短信登录页整体 UI 重构,弃用 NutUI 组件,采用原生组件实现 - 短信登录页新增渐变背景、浮动光圈、圆形 logo、卡片输入区设计 - 实现手机号输入、验证码发送、倒计时及登录校验逻辑全覆盖 - 短信登录页新增返回微信快捷登录链接,避免用户被困登录流程 - 新增配套样式文件,实现多重动效及分阶段入场动画 - 保证类型检查和编译无误,增加设计稿 HTML 预览文件
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import {useEffect, useState} from "react";
|
||||
import Taro from '@tarojs/taro'
|
||||
import { View } from '@tarojs/components'
|
||||
import {Input, Button} from '@nutui/nutui-react-taro'
|
||||
import { View, Text, Input } from '@tarojs/components'
|
||||
import {loginBySms, sendSmsCaptcha} from "@/api/passport/login";
|
||||
import {LoginParam} from "@/api/passport/login/model";
|
||||
import {checkAndHandleInviteRelation, hasPendingInvite, parseInviteParams, saveInviteParams, trackInviteSource} from "@/utils/invite";
|
||||
import './sms-login.scss'
|
||||
|
||||
const SmsLogin = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
@@ -55,12 +55,8 @@ const SmsLogin = () => {
|
||||
await Taro.redirectTo({ url: redirectUrl })
|
||||
}
|
||||
|
||||
const reload = () => {
|
||||
// sms-login 页面不是 tabBar 页面,无需调用 hideTabBar
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
reload()
|
||||
// sms-login 页面不是 tabBar 页面,无需调用 hideTabBar
|
||||
}, [])
|
||||
|
||||
// 如果从分享/二维码链接进入短信登录页,先暂存邀请信息
|
||||
@@ -78,7 +74,7 @@ const SmsLogin = () => {
|
||||
|
||||
// 倒计时效果
|
||||
useEffect(() => {
|
||||
let timer: NodeJS.Timeout
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
if (countdown > 0) {
|
||||
timer = setTimeout(() => {
|
||||
setCountdown(countdown - 1)
|
||||
@@ -218,52 +214,114 @@ const SmsLogin = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const phoneValid = validatePhone(formData.phone)
|
||||
const codeValid = formData.code.length === 6
|
||||
const canSubmit = phoneValid && codeValid && !loading
|
||||
const sendDisabled = !phoneValid || sendingCode || countdown > 0
|
||||
|
||||
const sendBtnText = countdown > 0
|
||||
? `${countdown}s 后重试`
|
||||
: sendingCode
|
||||
? '发送中'
|
||||
: '获取验证码'
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className='flex flex-col justify-center px-5 pt-3'>
|
||||
<View 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'}}
|
||||
/>
|
||||
<View className='page-sms-login'>
|
||||
{/* 渐变背景 */}
|
||||
<View className='sms-login-bg'>
|
||||
<View className='sms-login-bg__gradient' />
|
||||
<View className='sms-login-bg__circle sms-login-bg__circle--1' />
|
||||
<View className='sms-login-bg__circle sms-login-bg__circle--2' />
|
||||
</View>
|
||||
|
||||
<View className='sms-login-content'>
|
||||
{/* 头部 Logo 和标题 */}
|
||||
<View className='sms-login-header'>
|
||||
<View className='sms-login-logo'>
|
||||
<Text className='sms-login-logo__icon'>📱</Text>
|
||||
</View>
|
||||
<Text className='sms-login-title'>验证码登录</Text>
|
||||
<Text className='sms-login-subtitle'>未注册的手机号验证后将自动注册</Text>
|
||||
</View>
|
||||
<View 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>
|
||||
|
||||
{/* 表单卡片 */}
|
||||
<View className='sms-login-card'>
|
||||
{/* 手机号 */}
|
||||
<View className='sms-login-field'>
|
||||
<Text className='sms-login-field__icon'>📞</Text>
|
||||
<Input
|
||||
className='sms-login-field__input'
|
||||
type='number'
|
||||
placeholder='请输入手机号码'
|
||||
placeholderClass='sms-login-field__placeholder'
|
||||
maxLength={11}
|
||||
value={formData.phone}
|
||||
onInput={(e: any) => setFormData({ ...formData, phone: e.detail.value })}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View className='sms-login-divider' />
|
||||
|
||||
{/* 验证码 */}
|
||||
<View className='sms-login-field sms-login-field--code'>
|
||||
<View className='sms-login-field__icon-wrap'>
|
||||
<Text className='sms-login-field__icon'>🔐</Text>
|
||||
<Input
|
||||
className='sms-login-field__input'
|
||||
type='number'
|
||||
placeholder='请输入6位验证码'
|
||||
placeholderClass='sms-login-field__placeholder'
|
||||
maxLength={6}
|
||||
value={formData.code}
|
||||
onInput={(e: any) => setFormData({ ...formData, code: e.detail.value })}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
className={`sms-login-send ${sendDisabled ? 'sms-login-send--disabled' : ''}`}
|
||||
onClick={handleSendCode}
|
||||
>
|
||||
{sendBtnText}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className='flex justify-center my-5'>
|
||||
<Button
|
||||
type='info'
|
||||
size='large'
|
||||
className='w-full rounded-lg p-2'
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
onClick={handleLogin}
|
||||
|
||||
{/* 登录按钮 */}
|
||||
<View
|
||||
className={`sms-login-submit ${canSubmit ? '' : 'sms-login-submit--disabled'}`}
|
||||
hoverClass={canSubmit ? 'sms-login-submit--hover' : 'none'}
|
||||
onClick={canSubmit ? handleLogin : undefined}
|
||||
>
|
||||
{loading ? '登录中...' : '登录 / 注册'}
|
||||
</View>
|
||||
|
||||
{/* 返回微信登录 */}
|
||||
<View
|
||||
className='sms-login-back'
|
||||
onClick={() => Taro.navigateBack({ delta: 1 })}
|
||||
>
|
||||
<Text className='sms-login-back__icon'>←</Text>
|
||||
<Text className='sms-login-back__text'>返回微信快捷登录</Text>
|
||||
</View>
|
||||
|
||||
{/* 协议 */}
|
||||
<View className='sms-login-tips'>
|
||||
<Text className='sms-login-tips__text'>登录即代表您已阅读并同意</Text>
|
||||
<Text
|
||||
className='sms-login-tips__link'
|
||||
onClick={() => Taro.navigateTo({ url: '/passport/agreement?type=terms' })}
|
||||
>
|
||||
{loading ? '登录中...' : '登录'}
|
||||
</Button>
|
||||
《服务协议》
|
||||
</Text>
|
||||
<Text className='sms-login-tips__text'>和</Text>
|
||||
<Text
|
||||
className='sms-login-tips__link'
|
||||
onClick={() => Taro.navigateTo({ url: '/passport/agreement?type=privacy' })}
|
||||
>
|
||||
《隐私政策》
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
export default SmsLogin
|
||||
|
||||
Reference in New Issue
Block a user