Files
banban/banban-mini/src/pages/login/index.tsx
2026-06-30 14:11:31 +08:00

183 lines
6.1 KiB
TypeScript

import { View, Text, Button, Checkbox, CheckboxGroup } from '@tarojs/components'
import { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import { getToken, wechatLogin } from '@/services/auth'
import './index.scss'
export default function Login() {
const [submitting, setSubmitting] = useState(false)
const [agreementAccepted, setAgreementAccepted] = useState(false)
useEffect(() => {
if (getToken()) {
const redirectUrl = String(Taro.getStorageSync('postLoginRedirect') || '').trim()
if (redirectUrl) {
Taro.removeStorageSync('postLoginRedirect')
Taro.reLaunch({ url: redirectUrl })
return
}
Taro.reLaunch({ url: '/pages/device/index' })
return
}
}, [])
const handleLogin = async () => {
if (submitting) return
if (!agreementAccepted) {
Taro.showToast({
title: '请先阅读并同意协议',
icon: 'none',
})
return
}
setSubmitting(true)
Taro.showLoading({ title: '登录中...' })
try {
const loginRes = await Taro.login()
if (!loginRes.code) {
throw new Error('未获取到微信登录凭证')
}
const session = await wechatLogin({
code: loginRes.code,
})
const nextUserInfo = {
nickname: session.nickname || '',
}
if (nextUserInfo.nickname) {
Taro.setStorageSync('userInfo', {
nickname: nextUserInfo.nickname,
})
} else {
Taro.removeStorageSync('userInfo')
}
Taro.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => {
const redirectUrl = String(Taro.getStorageSync('postLoginRedirect') || '').trim()
if (redirectUrl) {
Taro.removeStorageSync('postLoginRedirect')
Taro.reLaunch({ url: redirectUrl })
return
}
Taro.reLaunch({ url: '/pages/device/index' })
}, 300)
} catch (error: any) {
console.error('[login] failed:', error)
const message = String(error?.message || '登录失败,请重试')
Taro.showModal({
title: '登录失败',
content: message,
showCancel: false,
})
} finally {
Taro.hideLoading()
setSubmitting(false)
}
}
const handleAgreementChange = (event) => {
const values = event.detail.value || []
setAgreementAccepted(values.includes('accepted'))
}
const openUserAgreement = () => {
Taro.showModal({
title: '用户服务协议',
content: '欢迎使用伴伴。您在使用本小程序前,应阅读并同意本协议。我们将为您提供设备绑定、状态查看、消息互动、定位展示等服务。请您遵守法律法规,不得利用本服务从事违法或侵犯他人权益的行为。',
showCancel: false,
confirmText: '我知道了',
})
}
const openPrivacyPolicy = () => {
const taroWithPrivacy = Taro as typeof Taro & {
openPrivacyContract?: (option?: {
success?: () => void
fail?: (error: unknown) => void
}) => void
}
if (typeof taroWithPrivacy.openPrivacyContract === 'function') {
taroWithPrivacy.openPrivacyContract({
fail: () => {
Taro.showModal({
title: '隐私政策',
content: '暂时无法打开隐私保护指引,请稍后重试。',
showCancel: false,
confirmText: '我知道了',
})
},
})
return
}
Taro.showModal({
title: '隐私政策',
content: '伴伴会在提供设备绑定、消息互动、定位展示等功能时,按需处理您的账号信息、设备信息和位置信息。我们仅在实现相关功能所必需的范围内使用上述信息。',
showCancel: false,
confirmText: '我知道了',
})
}
return (
<View className='login-page'>
<View className='login-header'>
<View className='logo'>
<Text className='logo-icon'>🤖</Text>
</View>
<Text className='title'></Text>
<Text className='subtitle'></Text>
</View>
<View className='login-content'>
<View className='features'>
<View className='feature-item'>
<Text className='feature-icon'>💬</Text>
<Text className='feature-text'>AI </Text>
</View>
<View className='feature-item'>
<Text className='feature-icon'>📍</Text>
<Text className='feature-text'></Text>
</View>
<View className='feature-item'>
<Text className='feature-icon'>🔋</Text>
<Text className='feature-text'></Text>
</View>
</View>
<View className='login-info-card'>
<Text className='login-info-title'></Text>
<Text className='login-info-desc'></Text>
</View>
<View className='login-btn-wrapper'>
<Button className='login-btn' loading={submitting} disabled={submitting} onClick={handleLogin}>
<Text className='btn-icon'>🌐</Text>
<Text className='btn-text'>{submitting ? '登录中...' : '登录后继续'}</Text>
</Button>
</View>
<View className='agreement-panel'>
<CheckboxGroup value={agreementAccepted ? ['accepted'] : []} onChange={handleAgreementChange}>
<View className='agreement-row'>
<Checkbox className='agreement-checkbox' value='accepted' checked={agreementAccepted} color='#07C160' />
<View className='agreement-text-wrap'>
<Text className='agreement-text'></Text>
<Text className='agreement-link' onClick={openUserAgreement}></Text>
<Text className='agreement-text'></Text>
<Text className='agreement-link' onClick={openPrivacyPolicy}></Text>
</View>
</View>
</CheckboxGroup>
</View>
</View>
</View>
)
}