502 lines
10 KiB
Vue
502 lines
10 KiB
Vue
<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>
|