fix bugs
This commit is contained in:
501
pages/login/login.vue
Normal file
501
pages/login/login.vue
Normal file
@@ -0,0 +1,501 @@
|
||||
<template>
|
||||
<view class="login-page">
|
||||
<!-- 背景装饰 -->
|
||||
<view class="bg-decoration">
|
||||
<view class="circle circle-1"></view>
|
||||
<view class="circle circle-2"></view>
|
||||
<view class="circle circle-3"></view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部Logo区域 -->
|
||||
<view class="login-header">
|
||||
<view class="logo-container">
|
||||
<image class="logo" src="/static/logo.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<text class="title">武术赛事管理系统</text>
|
||||
<text class="subtitle">MARTIAL ARTS COMPETITION</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view class="login-form">
|
||||
<view class="form-title">账号登录</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="input-wrapper">
|
||||
<view class="input-icon">📱</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="form.username"
|
||||
placeholder="请输入手机号或用户名"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="input-wrapper">
|
||||
<view class="input-icon">🔒</view>
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="form.password"
|
||||
:password="!showPassword"
|
||||
placeholder="请输入密码"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
<view class="eye-icon" @click="showPassword = !showPassword">
|
||||
<text>{{ showPassword ? '👁️' : '👁️🗨️' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-options">
|
||||
<label class="checkbox-label" @click="rememberPassword = !rememberPassword">
|
||||
<view :class="['checkbox', rememberPassword ? 'checked' : '']">
|
||||
<text v-if="rememberPassword" class="check-icon">✓</text>
|
||||
</view>
|
||||
<text class="checkbox-text">记住密码</text>
|
||||
</label>
|
||||
<text class="forgot-password" @click="handleForgotPassword">忘记密码?</text>
|
||||
</view>
|
||||
|
||||
<button class="login-btn" @click="handleLogin" :loading="loading" :disabled="loading">
|
||||
<text class="btn-text">{{ loading ? '登录中...' : '立即登录' }}</text>
|
||||
</button>
|
||||
|
||||
<view class="register-link">
|
||||
还没有账号?<text class="link-text" @click="goToRegister">立即注册</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部装饰 -->
|
||||
<view class="footer-decoration">
|
||||
<view class="wave"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import userAPI from '@/api/user.js'
|
||||
import { setToken, setRefreshToken, setUserInfo } from '@/utils/auth.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
showPassword: false,
|
||||
rememberPassword: false,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 读取记住的密码
|
||||
const savedUsername = uni.getStorageSync('saved_username')
|
||||
const savedPassword = uni.getStorageSync('saved_password')
|
||||
if (savedUsername && savedPassword) {
|
||||
this.form.username = savedUsername
|
||||
this.form.password = savedPassword
|
||||
this.rememberPassword = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleLogin() {
|
||||
// 表单验证
|
||||
if (!this.form.username) {
|
||||
uni.showToast({
|
||||
title: '请输入手机号或用户名',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.form.password) {
|
||||
uni.showToast({
|
||||
title: '请输入密码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
// 调用登录接口
|
||||
const res = await userAPI.login(this.form)
|
||||
|
||||
// 保存Token
|
||||
setToken(res.access_token)
|
||||
setRefreshToken(res.refresh_token)
|
||||
|
||||
// 保存用户信息
|
||||
const userInfo = {
|
||||
userId: res.user_id,
|
||||
account: res.account,
|
||||
userName: res.user_name,
|
||||
avatar: res.avatar,
|
||||
tenantId: res.tenant_id
|
||||
}
|
||||
setUserInfo(userInfo)
|
||||
|
||||
// 记住密码
|
||||
if (this.rememberPassword) {
|
||||
uni.setStorageSync('saved_username', this.form.username)
|
||||
uni.setStorageSync('saved_password', this.form.password)
|
||||
} else {
|
||||
uni.removeStorageSync('saved_username')
|
||||
uni.removeStorageSync('saved_password')
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: '/pages/home/home'
|
||||
})
|
||||
}, 1500)
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '登录失败',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
handleForgotPassword() {
|
||||
uni.showToast({
|
||||
title: '请联系管理员重置密码',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
goToRegister() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/register/register'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #C93639 0%, #A82E31 50%, #8B1F22 100%);
|
||||
padding: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 背景装饰圆圈 */
|
||||
.bg-decoration {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.circle-1 {
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
top: -100rpx;
|
||||
right: -50rpx;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.circle-2 {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
bottom: 100rpx;
|
||||
left: -50rpx;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.circle-3 {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
top: 40%;
|
||||
right: 50rpx;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-30rpx) scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
/* 顶部Logo区域 */
|
||||
.login-header {
|
||||
text-align: center;
|
||||
padding: 120rpx 60rpx 80rpx;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
margin: 0 auto 40rpx;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(10rpx);
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
letter-spacing: 4rpx;
|
||||
text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
letter-spacing: 2rpx;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
/* 登录表单 */
|
||||
.login-form {
|
||||
background: #fff;
|
||||
border-radius: 40rpx 40rpx 0 0;
|
||||
padding: 60rpx 50rpx 80rpx;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||||
min-height: calc(100vh - 480rpx);
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 50rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #F7F8FA;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.input-wrapper:focus-within {
|
||||
background: #fff;
|
||||
border-color: #C93639;
|
||||
box-shadow: 0 4rpx 16rpx rgba(201, 54, 57, 0.1);
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
width: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
height: 96rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding-right: 30rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.eye-icon {
|
||||
width: 80rpx;
|
||||
height: 96rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.eye-icon:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* 表单选项 */
|
||||
.form-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 40rpx 0 50rpx;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border: 2rpx solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 12rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background: #C93639;
|
||||
border-color: #C93639;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.checkbox-text {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
font-size: 26rpx;
|
||||
color: #C93639;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.forgot-password:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 登录按钮 */
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
background: linear-gradient(135deg, #C93639 0%, #A82E31 100%);
|
||||
border-radius: 16rpx;
|
||||
border: none;
|
||||
box-shadow: 0 8rpx 24rpx rgba(201, 54, 57, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.login-btn:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 4rpx 16rpx rgba(201, 54, 57, 0.2);
|
||||
}
|
||||
|
||||
.login-btn:active::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
/* 注册链接 */
|
||||
.register-link {
|
||||
text-align: center;
|
||||
margin-top: 50rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.link-text {
|
||||
color: #C93639;
|
||||
font-weight: bold;
|
||||
margin-left: 8rpx;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.link-text:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 底部装饰 */
|
||||
.footer-decoration {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wave {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, transparent 0%, rgba(255, 255, 255, 0.05) 100%);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user