feat(login): 登录页改为微信一键登录并移除账密表单

This commit is contained in:
ozh 2026-09-15 12:50:55 +08:00
parent 44918644ef
commit 90e6262c89
4 changed files with 35 additions and 41 deletions

View File

@ -42,7 +42,7 @@
color: rgba(255, 255, 255, 0.85);
}
// 表单卡上浮叠在渐变区上
// 登录卡上浮叠在渐变区上
.form {
margin: -120px 24px 0;
padding: 48px 32px;
@ -53,15 +53,6 @@
flex-direction: column;
}
.input {
height: 100px;
background: $color-bg-gray;
border-radius: $radius-md;
padding: 0 32px;
margin-bottom: 24px;
font-size: 30px;
}
.submit {
height: 96px;
background: $color-primary-grad;

View File

@ -1,8 +1,9 @@
import { useState } from 'react'
import { View, Text, Input } from '@tarojs/components'
import { useAppDispatch } from '@/store/hooks'
import { View, Text } from '@tarojs/components'
import { useDidShow } from '@tarojs/taro'
import { useAppDispatch, useAppSelector } from '@/store/hooks'
import { setAuth } from '@/store/authSlice'
import { login } from '@/api/auth'
import { performWxLogin } from './wxLoginFlow'
import { useToast } from '@/hooks/useToast'
import { ROUTES } from '@/constants/routes'
import { reLaunch } from '@/utils/navigation'
@ -11,26 +12,28 @@ import styles from './index.module.scss'
export default function Login() {
const dispatch = useAppDispatch()
const toast = useToast()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const token = useAppSelector((s) => s.auth.token)
const [loading, setLoading] = useState(false)
const handleLogin = async () => {
if (!username || !password) {
toast.error('请填写完整')
return
}
// 已有 token 直接进首页(本期不做 checkLogin 校验,spec D5)
useDidShow(() => {
if (token && !loading) reLaunch(ROUTES.HOME)
})
const handleWxLogin = async () => {
if (loading) return
setLoading(true)
try {
const res = await login({ username, password })
dispatch(setAuth(res))
const { code, userInfo } = await performWxLogin()
dispatch(setAuth({ token: code, userInfo }))
reLaunch(ROUTES.HOME)
} catch {
toast.error('登录失败')
} finally {
} catch (e) {
// code 失效/已用等场景:toast 后端 Message,用户重按按钮重新 Taro.login(code 一次性,重试安全)
toast.error(e instanceof Error && e.message ? e.message : '登录失败')
setLoading(false)
}
}
return (
<View className={styles.page}>
<View className={styles.hero}>
@ -41,21 +44,8 @@ export default function Login() {
<Text className={styles.slogan}>一起守护家人</Text>
</View>
<View className={styles.form}>
<Input
className={styles.input}
placeholder="账号"
value={username}
onInput={(e) => setUsername(e.detail.value)}
/>
<Input
className={styles.input}
placeholder="密码"
password
value={password}
onInput={(e) => setPassword(e.detail.value)}
/>
<View className={styles.submit} onClick={handleLogin}>
<Text className={styles.submitText}>{loading ? '登录中...' : '登录'}</Text>
<View className={styles.submit} onClick={handleWxLogin}>
<Text className={styles.submitText}>{loading ? '登录中...' : '微信一键登录'}</Text>
</View>
</View>
</View>

View File

@ -15,7 +15,14 @@ function resolveAppId(): string {
// 微信一键登录主流程(spec D3):
// Taro.login 换一次性 code → 组装 appId/openId → 调 miniapp/login → 缓存响应中的 openId
export async function performWxLogin(): Promise<WxLoginResult> {
const { code } = await Taro.login()
// Taro.login reject 时返回 { errMsg } 形状对象而非 Error,此处归一化为带 message 的 Error
let code: string
try {
const r = await Taro.login()
code = r.code
} catch (e) {
throw new Error(e instanceof Error ? e.message : '微信登录失败')
}
if (!code) throw new Error('获取微信登录凭证失败')
const openId = storage.get<string>(WX_OPENID_STORAGE_KEY) ?? undefined
const result = await wxMiniappLogin({ appId: resolveAppId(), code, openId })

View File

@ -77,6 +77,12 @@ describe('performWxLogin', () => {
expect(mockWxMiniappLogin).not.toHaveBeenCalled()
})
it('Taro.login reject(errMsg 形状)时抛带 message 的 Error', async () => {
mockLogin.mockRejectedValue({ errMsg: 'login:fail:cancel' })
await expect(performWxLogin()).rejects.toThrow('微信登录失败')
expect(mockWxMiniappLogin).not.toHaveBeenCalled()
})
it('getAccountInfoSync 抛错时回退常量 appId', async () => {
mockGetAccountInfo.mockImplementation(() => { throw new Error('not supported') })
mockWxMiniappLogin.mockResolvedValue(result())