|
@@ -1,5 +1,5 @@
|
|
|
import { View, Input, Button, Text, Image } from '@tarojs/components'
|
|
import { View, Input, Button, Text, Image } from '@tarojs/components'
|
|
|
-import { useState } from 'react'
|
|
|
|
|
|
|
+import { useState, useEffect } from 'react'
|
|
|
import Taro from '@tarojs/taro'
|
|
import Taro from '@tarojs/taro'
|
|
|
import { authManager } from '../../utils/auth'
|
|
import { authManager } from '../../utils/auth'
|
|
|
import './index.css'
|
|
import './index.css'
|
|
@@ -8,40 +8,148 @@ export default function Login() {
|
|
|
const [username, setUsername] = useState('')
|
|
const [username, setUsername] = useState('')
|
|
|
const [password, setPassword] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
|
const [loading, setLoading] = useState(false)
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
|
+ const [showPassword, setShowPassword] = useState(false)
|
|
|
|
|
+
|
|
|
|
|
+ // 页面加载动画效果
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ Taro.setNavigationBarTitle({
|
|
|
|
|
+ title: '用户登录'
|
|
|
|
|
+ })
|
|
|
|
|
+ }, [])
|
|
|
|
|
|
|
|
const handleLogin = async () => {
|
|
const handleLogin = async () => {
|
|
|
- if (!username || !password) {
|
|
|
|
|
|
|
+ // 输入验证
|
|
|
|
|
+ if (!username.trim()) {
|
|
|
Taro.showToast({
|
|
Taro.showToast({
|
|
|
- title: '请输入用户名和密码',
|
|
|
|
|
- icon: 'none'
|
|
|
|
|
|
|
+ title: '请输入用户名',
|
|
|
|
|
+ icon: 'none',
|
|
|
|
|
+ duration: 2000
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!password.trim()) {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '请输入密码',
|
|
|
|
|
+ icon: 'none',
|
|
|
|
|
+ duration: 2000
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (username.trim().length < 3) {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '用户名至少3个字符',
|
|
|
|
|
+ icon: 'none',
|
|
|
|
|
+ duration: 2000
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (password.trim().length < 6) {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '密码至少6个字符',
|
|
|
|
|
+ icon: 'none',
|
|
|
|
|
+ duration: 2000
|
|
|
})
|
|
})
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
setLoading(true)
|
|
setLoading(true)
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
- const user = await authManager.login(username, password)
|
|
|
|
|
|
|
+ // 添加加载动画
|
|
|
|
|
+ Taro.showLoading({
|
|
|
|
|
+ title: '登录中...',
|
|
|
|
|
+ mask: true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const user = await authManager.login(username.trim(), password.trim())
|
|
|
|
|
+
|
|
|
|
|
+ Taro.hideLoading()
|
|
|
|
|
+
|
|
|
Taro.showToast({
|
|
Taro.showToast({
|
|
|
title: '登录成功',
|
|
title: '登录成功',
|
|
|
- icon: 'success'
|
|
|
|
|
|
|
+ icon: 'success',
|
|
|
|
|
+ duration: 1500
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ // 重置表单
|
|
|
|
|
+ setUsername('')
|
|
|
|
|
+ setPassword('')
|
|
|
|
|
+
|
|
|
// 登录成功后跳转到首页
|
|
// 登录成功后跳转到首页
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
Taro.switchTab({ url: '/pages/index/index' })
|
|
Taro.switchTab({ url: '/pages/index/index' })
|
|
|
}, 1500)
|
|
}, 1500)
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
- Taro.showToast({
|
|
|
|
|
- title: error.message || '登录失败',
|
|
|
|
|
- icon: 'none'
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ Taro.hideLoading()
|
|
|
|
|
+
|
|
|
|
|
+ const errorMessage = error.message || '登录失败'
|
|
|
|
|
+
|
|
|
|
|
+ // 根据错误类型显示不同的提示
|
|
|
|
|
+ if (errorMessage.includes('用户名或密码错误')) {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '用户名或密码错误',
|
|
|
|
|
+ icon: 'none',
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ } else if (errorMessage.includes('网络')) {
|
|
|
|
|
+ Taro.showModal({
|
|
|
|
|
+ title: '网络错误',
|
|
|
|
|
+ content: '请检查网络连接后重试',
|
|
|
|
|
+ showCancel: false,
|
|
|
|
|
+ confirmText: '确定'
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: errorMessage,
|
|
|
|
|
+ icon: 'none',
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
} finally {
|
|
} finally {
|
|
|
setLoading(false)
|
|
setLoading(false)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const goToRegister = () => {
|
|
const goToRegister = () => {
|
|
|
- Taro.navigateTo({ url: '/pages/register/index' })
|
|
|
|
|
|
|
+ Taro.navigateTo({
|
|
|
|
|
+ url: '/pages/register/index',
|
|
|
|
|
+ success: () => {
|
|
|
|
|
+ // 页面跳转成功后的回调
|
|
|
|
|
+ console.log('跳转到注册页面')
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: (error) => {
|
|
|
|
|
+ console.error('跳转失败:', error)
|
|
|
|
|
+ Taro.showToast({
|
|
|
|
|
+ title: '页面跳转失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const handleUsernameInput = (e: any) => {
|
|
|
|
|
+ const value = e.detail.value
|
|
|
|
|
+ // 限制输入字符
|
|
|
|
|
+ if (value.length <= 20) {
|
|
|
|
|
+ setUsername(value.replace(/\s+/g, ''))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const handlePasswordInput = (e: any) => {
|
|
|
|
|
+ const value = e.detail.value
|
|
|
|
|
+ if (value.length <= 20) {
|
|
|
|
|
+ setPassword(value)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理键盘完成事件
|
|
|
|
|
+ const handleInputConfirm = () => {
|
|
|
|
|
+ if (username && password && !loading) {
|
|
|
|
|
+ handleLogin()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
@@ -49,12 +157,13 @@ export default function Login() {
|
|
|
<View className="login-header">
|
|
<View className="login-header">
|
|
|
<Image
|
|
<Image
|
|
|
className="login-logo"
|
|
className="login-logo"
|
|
|
- src="https://source.unsplash.com/200x200/?logo"
|
|
|
|
|
|
|
+ src="https://source.unsplash.com/400x400/?minimal,logo,blue"
|
|
|
mode="aspectFit"
|
|
mode="aspectFit"
|
|
|
|
|
+ lazyLoad
|
|
|
/>
|
|
/>
|
|
|
<View className="login-title-container">
|
|
<View className="login-title-container">
|
|
|
<Text className="login-title">欢迎回来</Text>
|
|
<Text className="login-title">欢迎回来</Text>
|
|
|
- <Text className="login-subtitle">请使用您的账号登录</Text>
|
|
|
|
|
|
|
+ <Text className="login-subtitle">请使用您的账号登录系统</Text>
|
|
|
</View>
|
|
</View>
|
|
|
</View>
|
|
</View>
|
|
|
|
|
|
|
@@ -66,8 +175,12 @@ export default function Login() {
|
|
|
className="form-input"
|
|
className="form-input"
|
|
|
placeholder="请输入用户名"
|
|
placeholder="请输入用户名"
|
|
|
value={username}
|
|
value={username}
|
|
|
- onInput={(e) => setUsername(e.detail.value)}
|
|
|
|
|
|
|
+ onInput={handleUsernameInput}
|
|
|
|
|
+ onConfirm={handleInputConfirm}
|
|
|
maxlength={20}
|
|
maxlength={20}
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ confirmType="next"
|
|
|
|
|
+ adjustPosition
|
|
|
/>
|
|
/>
|
|
|
</View>
|
|
</View>
|
|
|
</View>
|
|
</View>
|
|
@@ -78,10 +191,14 @@ export default function Login() {
|
|
|
<Input
|
|
<Input
|
|
|
className="form-input"
|
|
className="form-input"
|
|
|
placeholder="请输入密码"
|
|
placeholder="请输入密码"
|
|
|
- password
|
|
|
|
|
|
|
+ password={!showPassword}
|
|
|
value={password}
|
|
value={password}
|
|
|
- onInput={(e) => setPassword(e.detail.value)}
|
|
|
|
|
|
|
+ onInput={handlePasswordInput}
|
|
|
|
|
+ onConfirm={handleInputConfirm}
|
|
|
maxlength={20}
|
|
maxlength={20}
|
|
|
|
|
+ type={showPassword ? 'text' : undefined}
|
|
|
|
|
+ confirmType="done"
|
|
|
|
|
+ adjustPosition
|
|
|
/>
|
|
/>
|
|
|
</View>
|
|
</View>
|
|
|
</View>
|
|
</View>
|
|
@@ -90,9 +207,9 @@ export default function Login() {
|
|
|
className={`login-button ${loading ? 'loading' : ''}`}
|
|
className={`login-button ${loading ? 'loading' : ''}`}
|
|
|
loading={loading}
|
|
loading={loading}
|
|
|
onClick={handleLogin}
|
|
onClick={handleLogin}
|
|
|
- disabled={loading}
|
|
|
|
|
|
|
+ disabled={loading || !username || !password}
|
|
|
>
|
|
>
|
|
|
- {loading ? '登录中...' : '登录'}
|
|
|
|
|
|
|
+ {loading ? '登录中...' : '安全登录'}
|
|
|
</Button>
|
|
</Button>
|
|
|
|
|
|
|
|
<View className="login-footer">
|
|
<View className="login-footer">
|