928 lines
20 KiB
Vue
928 lines
20 KiB
Vue
<template>
|
||
<view class="login-page">
|
||
<!-- 背景装饰 -->
|
||
<view class="bg-decoration">
|
||
<view class="gradient-orb orb-1"></view>
|
||
<view class="gradient-orb orb-2"></view>
|
||
<view class="gradient-orb orb-3"></view>
|
||
<view class="floating-shapes">
|
||
<view class="shape shape-1"></view>
|
||
<view class="shape shape-2"></view>
|
||
<view class="shape shape-3"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 主要内容 -->
|
||
<view class="login-container">
|
||
<!-- 头部区域 -->
|
||
<view class="header-section">
|
||
<view class="logo-container">
|
||
<view class="logo-wrapper">
|
||
<image src="/static/logo.png" class="logo" mode="aspectFit"></image>
|
||
<view class="logo-ring"></view>
|
||
</view>
|
||
</view>
|
||
<view class="welcome-content">
|
||
<text class="app-title">企业办公系统</text>
|
||
<text class="welcome-subtitle">欢迎回来,开始您的工作之旅</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 登录卡片 -->
|
||
<view class="login-card">
|
||
<view class="card-header">
|
||
<text class="card-title">登录账户</text>
|
||
<view class="card-subtitle">请输入您的登录信息</view>
|
||
</view>
|
||
|
||
<view class="form-container">
|
||
<!-- 用户名输入 -->
|
||
<view class="input-field-group">
|
||
<view class="input-container" :class="{ 'focused': usernameFocused, 'error': usernameError }">
|
||
<view class="input-icon-wrapper">
|
||
<i class="fas fa-user input-icon"></i>
|
||
</view>
|
||
<input
|
||
v-model="form.username"
|
||
placeholder="用户名"
|
||
class="input"
|
||
type="text"
|
||
@focus="handleUsernameFocus"
|
||
@blur="handleUsernameBlur"
|
||
@input="clearUsernameError">
|
||
<view class="input-border"></view>
|
||
</view>
|
||
<text class="error-text" v-if="usernameError">{{ usernameError }}</text>
|
||
</view>
|
||
|
||
<!-- 密码输入 -->
|
||
<view class="input-field-group">
|
||
<view class="input-container" :class="{ 'focused': passwordFocused, 'error': passwordError }">
|
||
<view class="input-icon-wrapper">
|
||
<i class="fas fa-lock input-icon"></i>
|
||
</view>
|
||
<input
|
||
v-model="form.password"
|
||
placeholder="密码"
|
||
class="input"
|
||
:type="showPassword ? 'text' : 'password'"
|
||
@focus="handlePasswordFocus"
|
||
@blur="handlePasswordBlur"
|
||
@input="clearPasswordError">
|
||
<view class="password-toggle" @click="togglePassword">
|
||
<i :class="showPassword ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
|
||
</view>
|
||
<view class="input-border"></view>
|
||
</view>
|
||
<text class="error-text" v-if="passwordError">{{ passwordError }}</text>
|
||
</view>
|
||
|
||
<!-- 选项区域 -->
|
||
<view class="options-row">
|
||
<view class="remember-section" @click="toggleRemember">
|
||
<view class="custom-checkbox" :class="{ 'checked': rememberMe }">
|
||
<i class="fas fa-check" v-if="rememberMe"></i>
|
||
</view>
|
||
<text class="remember-text">记住我</text>
|
||
</view>
|
||
<text class="forgot-link" @click="handleForgotPassword">忘记密码?</text>
|
||
</view>
|
||
|
||
<!-- 登录按钮 -->
|
||
<button
|
||
:disabled="loading || !isFormValid"
|
||
class="login-button"
|
||
:class="{ 'loading': loading, 'disabled': !isFormValid }"
|
||
@click="handleLogin">
|
||
<view class="button-content">
|
||
<view class="button-icon" v-if="!loading">
|
||
<i class="fas fa-arrow-right"></i>
|
||
</view>
|
||
<view class="loading-spinner" v-if="loading">
|
||
<i class="fas fa-spinner fa-spin"></i>
|
||
</view>
|
||
<text class="button-text">{{ loading ? '登录中...' : '立即登录' }}</text>
|
||
</view>
|
||
<view class="button-shine" v-if="!loading"></view>
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 测试提示 -->
|
||
<view class="test-tips">
|
||
<view class="tips-icon">
|
||
<i class="fas fa-info-circle"></i>
|
||
</view>
|
||
<text class="tips-text">测试账号:test / 123456</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { userApi } from '../../src/api/index.js'
|
||
import { useAuthStore } from '../../src/store/authStore.js'
|
||
import { redirectAfterLogin } from '../../src/utils/routeGuard.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
form: {
|
||
username: '',
|
||
password: ''
|
||
},
|
||
loading: false,
|
||
usernameFocused: false,
|
||
passwordFocused: false,
|
||
showPassword: false,
|
||
rememberMe: false,
|
||
usernameError: '',
|
||
passwordError: ''
|
||
}
|
||
},
|
||
computed: {
|
||
isFormValid() {
|
||
return this.form.username.trim() && this.form.password.trim()
|
||
}
|
||
},
|
||
methods: {
|
||
async handleLogin() {
|
||
this.loading = true;
|
||
try {
|
||
const res = await userApi.login(this.form);
|
||
console.log('登录响应:', res);
|
||
|
||
// 根据你的后端返回结构调整
|
||
const token = res.accessToken || res.token;
|
||
|
||
if (!token) {
|
||
throw new Error('登录失败:未获取到访问令牌');
|
||
}
|
||
|
||
const authStore = useAuthStore();
|
||
// 从响应中获取用户信息
|
||
const userInfo = res.user || {
|
||
username: this.form.username,
|
||
id: res.id
|
||
};
|
||
|
||
authStore.login(userInfo, token);
|
||
|
||
uni.showToast({
|
||
title: '登录成功',
|
||
icon: 'success'
|
||
});
|
||
|
||
// 延迟跳转,让用户看到成功提示
|
||
setTimeout(() => {
|
||
redirectAfterLogin();
|
||
}, 500);
|
||
} catch (e) {
|
||
this.loading = false;
|
||
console.error('登录错误:', e);
|
||
|
||
// 显示错误信息
|
||
const errorMessage = e.message || e.msg || '登录失败,请检查网络连接';
|
||
uni.showToast({
|
||
title: errorMessage,
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
}
|
||
},
|
||
|
||
// async handleLogin2() {
|
||
// if(!this.form.username || !this.form.password) {
|
||
// uni.showToast({
|
||
// title: '请输入用户名和密码',
|
||
// icon: 'none'
|
||
// });
|
||
// return;
|
||
// }
|
||
|
||
// this.loading = true;
|
||
|
||
// try {
|
||
// // 模拟登录API请求
|
||
// // 实际项目中应该调用真实的后端API
|
||
// const mockLogin = () => {
|
||
// return new Promise((resolve) => {
|
||
// setTimeout(() => {
|
||
// // 模拟登录成功
|
||
// if (this.form.username === 'admin' && this.form.password === '123456') {
|
||
// resolve({
|
||
// code: 0,
|
||
// message: '登录成功',
|
||
// data: {
|
||
// token: 'mock_token_' + Date.now(),
|
||
// userInfo: {
|
||
// id: 1,
|
||
// username: this.form.username,
|
||
// name: '管理员',
|
||
// avatar: '/static/logo.png',
|
||
// department: '技术部',
|
||
// role: 'admin'
|
||
// }
|
||
// }
|
||
// });
|
||
// } else {
|
||
// resolve({
|
||
// code: 1,
|
||
// message: '用户名或密码错误'
|
||
// });
|
||
// }
|
||
// }, 1000);
|
||
// });
|
||
// };
|
||
|
||
// const result = await mockLogin();
|
||
|
||
// if (result.code === 0) {
|
||
// // 使用 Pinia store 管理登录状态
|
||
// const authStore = useAuthStore();
|
||
// authStore.login(result.data.userInfo, result.data.token);
|
||
|
||
// uni.showToast({
|
||
// title: '登录成功',
|
||
// icon: 'success'
|
||
// });
|
||
|
||
// // 延迟跳转,让用户看到成功提示
|
||
// setTimeout(() => {
|
||
// redirectAfterLogin();
|
||
// }, 500);
|
||
// } else {
|
||
// uni.showToast({
|
||
// title: result.message || '登录失败',
|
||
// icon: 'none'
|
||
// });
|
||
// }
|
||
// } catch (error) {
|
||
// console.error('登录错误:', error);
|
||
// uni.showToast({
|
||
// title: '网络异常,请稍后重试',
|
||
// icon: 'none'
|
||
// });
|
||
// }
|
||
|
||
// this.loading = false;
|
||
// },
|
||
|
||
// 切换密码显示
|
||
togglePassword() {
|
||
this.showPassword = !this.showPassword
|
||
},
|
||
|
||
// 切换记住我
|
||
toggleRemember() {
|
||
this.rememberMe = !this.rememberMe
|
||
},
|
||
|
||
// 忘记密码
|
||
handleForgotPassword() {
|
||
uni.showToast({
|
||
title: '请联系管理员重置密码',
|
||
icon: 'none'
|
||
})
|
||
},
|
||
|
||
// 处理用户名输入框焦点
|
||
handleUsernameFocus() {
|
||
this.usernameFocused = true;
|
||
this.clearUsernameError();
|
||
},
|
||
|
||
handleUsernameBlur() {
|
||
this.usernameFocused = false;
|
||
this.validateUsername();
|
||
},
|
||
|
||
// 处理密码输入框焦点
|
||
handlePasswordFocus() {
|
||
this.passwordFocused = true;
|
||
this.clearPasswordError();
|
||
},
|
||
|
||
handlePasswordBlur() {
|
||
this.passwordFocused = false;
|
||
this.validatePassword();
|
||
},
|
||
|
||
// 清除用户名错误
|
||
clearUsernameError() {
|
||
this.usernameError = '';
|
||
},
|
||
|
||
// 清除密码错误
|
||
clearPasswordError() {
|
||
this.passwordError = '';
|
||
},
|
||
|
||
// 验证用户名
|
||
validateUsername() {
|
||
if (!this.form.username.trim()) {
|
||
this.usernameError = '请输入用户名';
|
||
return false;
|
||
}
|
||
return true;
|
||
},
|
||
|
||
// 验证密码
|
||
validatePassword() {
|
||
if (!this.form.password.trim()) {
|
||
this.passwordError = '请输入密码';
|
||
return false;
|
||
}
|
||
if (this.form.password.length < 6) {
|
||
this.passwordError = '密码至少6位';
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 主容器 */
|
||
.login-page {
|
||
min-height: 100vh;
|
||
background: var(--gradient-primary);
|
||
position: relative;
|
||
overflow: hidden;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 40rpx 20rpx;
|
||
}
|
||
|
||
/* 背景装饰 */
|
||
.bg-decoration {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
}
|
||
|
||
.gradient-orb {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
|
||
animation: float 8s ease-in-out infinite;
|
||
filter: blur(1rpx);
|
||
}
|
||
|
||
.orb-1 {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
top: -150rpx;
|
||
left: -150rpx;
|
||
animation-delay: 0s;
|
||
}
|
||
|
||
.orb-2 {
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
top: 20%;
|
||
right: -100rpx;
|
||
animation-delay: 3s;
|
||
}
|
||
|
||
.orb-3 {
|
||
width: 150rpx;
|
||
height: 150rpx;
|
||
bottom: 10%;
|
||
left: 10%;
|
||
animation-delay: 6s;
|
||
}
|
||
|
||
.floating-shapes {
|
||
position: absolute;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.shape {
|
||
position: absolute;
|
||
background: rgba(255, 255, 255, 0.05);
|
||
animation: float 6s ease-in-out infinite;
|
||
}
|
||
|
||
.shape-1 {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
border-radius: 50%;
|
||
top: 30%;
|
||
left: 20%;
|
||
animation-delay: 1s;
|
||
}
|
||
|
||
.shape-2 {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
border-radius: 8rpx;
|
||
top: 60%;
|
||
right: 30%;
|
||
animation-delay: 4s;
|
||
}
|
||
|
||
.shape-3 {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
bottom: 30%;
|
||
right: 20%;
|
||
animation-delay: 2s;
|
||
}
|
||
|
||
@keyframes float {
|
||
0%, 100% {
|
||
transform: translateY(0px) rotate(0deg) scale(1);
|
||
opacity: 0.7;
|
||
}
|
||
50% {
|
||
transform: translateY(-30px) rotate(180deg) scale(1.1);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
/* 登录容器 */
|
||
.login-container {
|
||
width: 100%;
|
||
max-width: 600rpx;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
/* 头部区域 */
|
||
.header-section {
|
||
text-align: center;
|
||
margin-bottom: 60rpx;
|
||
}
|
||
|
||
.logo-container {
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.logo-wrapper {
|
||
position: relative;
|
||
display: inline-block;
|
||
}
|
||
|
||
.logo {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2);
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.logo-ring {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
left: -8rpx;
|
||
right: -8rpx;
|
||
bottom: -8rpx;
|
||
border: 2rpx solid rgba(255, 255, 255, 0.3);
|
||
border-radius: 28rpx;
|
||
animation: pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% {
|
||
transform: scale(1);
|
||
opacity: 0.7;
|
||
}
|
||
50% {
|
||
transform: scale(1.05);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.welcome-content {
|
||
color: #ffffff;
|
||
}
|
||
|
||
.app-title {
|
||
display: block;
|
||
font-size: 48rpx;
|
||
font-weight: 700;
|
||
margin-bottom: 16rpx;
|
||
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
||
letter-spacing: 1rpx;
|
||
}
|
||
|
||
.welcome-subtitle {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
opacity: 0.9;
|
||
font-weight: 400;
|
||
}
|
||
|
||
/* 登录卡片 */
|
||
.login-card {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
border-radius: 24rpx;
|
||
padding: 50rpx 40rpx;
|
||
box-shadow: var(--shadow-lg);
|
||
backdrop-filter: blur(20rpx);
|
||
border: 1rpx solid rgba(255, 255, 255, 0.2);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.login-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 4rpx;
|
||
background: var(--gradient-primary);
|
||
}
|
||
|
||
.card-header {
|
||
text-align: center;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin-bottom: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.card-subtitle {
|
||
font-size: 26rpx;
|
||
color: var(--text-secondary);
|
||
font-weight: 400;
|
||
}
|
||
|
||
/* 表单容器 */
|
||
.form-container {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
/* 输入框组 */
|
||
.input-field-group {
|
||
margin-bottom: 32rpx;
|
||
}
|
||
|
||
.input-container {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
background: var(--gray-lighter);
|
||
border-radius: 16rpx;
|
||
border: 2rpx solid var(--border);
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
overflow: hidden;
|
||
min-height: 88rpx;
|
||
}
|
||
|
||
.input-container.focused {
|
||
border-color: var(--primary-color);
|
||
background: var(--white);
|
||
box-shadow: 0 0 0 4rpx var(--info-light);
|
||
transform: translateY(-2rpx);
|
||
}
|
||
|
||
.input-container.error {
|
||
border-color: var(--error);
|
||
background: var(--error-light);
|
||
}
|
||
|
||
.input-icon-wrapper {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
.input-icon {
|
||
color: var(--text-muted);
|
||
font-size: 28rpx;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.input-container.focused .input-icon {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.input-container.error .input-icon {
|
||
color: var(--error);
|
||
}
|
||
|
||
.input {
|
||
flex: 1;
|
||
padding: 24rpx 20rpx;
|
||
border: none;
|
||
background: transparent;
|
||
font-size: 30rpx;
|
||
color: var(--text-color);
|
||
outline: none;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.input::placeholder {
|
||
color: var(--text-muted);
|
||
font-weight: 400;
|
||
}
|
||
|
||
.password-toggle {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--text-muted);
|
||
font-size: 28rpx;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.password-toggle:hover {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.input-border {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 2rpx;
|
||
background: var(--gradient-primary);
|
||
transform: scaleX(0);
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.input-container.focused .input-border {
|
||
transform: scaleX(1);
|
||
}
|
||
|
||
.error-text {
|
||
font-size: 24rpx;
|
||
color: var(--error);
|
||
margin-top: 8rpx;
|
||
margin-left: 20rpx;
|
||
display: block;
|
||
}
|
||
|
||
/* 选项区域 */
|
||
.options-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.remember-section {
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.custom-checkbox {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
border: 2rpx solid var(--border);
|
||
border-radius: 8rpx;
|
||
margin-right: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s ease;
|
||
background: var(--white);
|
||
}
|
||
|
||
.custom-checkbox.checked {
|
||
background: var(--primary-color);
|
||
border-color: var(--primary-color);
|
||
color: var(--white);
|
||
}
|
||
|
||
.custom-checkbox i {
|
||
font-size: 20rpx;
|
||
}
|
||
|
||
.remember-text {
|
||
font-size: 28rpx;
|
||
color: var(--text-color);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.forgot-link {
|
||
font-size: 28rpx;
|
||
color: var(--primary-color);
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.forgot-link:hover {
|
||
color: var(--primary-dark);
|
||
}
|
||
|
||
/* 登录按钮 */
|
||
.login-button {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background: var(--gradient-primary);
|
||
color: var(--white);
|
||
border: none;
|
||
border-radius: 16rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-lg);
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.login-button:hover:not(:disabled) {
|
||
transform: translateY(-2rpx);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
|
||
.login-button:active:not(:disabled) {
|
||
transform: translateY(0);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
|
||
.login-button.disabled {
|
||
opacity: 0.5;
|
||
transform: none;
|
||
cursor: not-allowed;
|
||
background: var(--gray);
|
||
color: var(--text-muted);
|
||
box-shadow: none;
|
||
}
|
||
|
||
.login-button.loading {
|
||
pointer-events: none;
|
||
}
|
||
|
||
.button-content {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.button-icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20rpx;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20rpx;
|
||
}
|
||
|
||
.button-text {
|
||
font-weight: 600;
|
||
}
|
||
|
||
.button-shine {
|
||
position: absolute;
|
||
top: 0;
|
||
left: -100%;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||
animation: shine 2s infinite;
|
||
}
|
||
|
||
@keyframes shine {
|
||
0% { left: -100%; }
|
||
100% { left: 100%; }
|
||
}
|
||
|
||
/* 测试提示 */
|
||
.test-tips {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 12rpx;
|
||
margin-top: 30rpx;
|
||
padding: 20rpx;
|
||
background: var(--info-light);
|
||
border-radius: 12rpx;
|
||
border: 1rpx solid var(--primary-light);
|
||
}
|
||
|
||
.tips-icon {
|
||
color: var(--primary-color);
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.tips-text {
|
||
font-size: 24rpx;
|
||
color: var(--text-color);
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media screen and (max-width: 750rpx) {
|
||
.login-container {
|
||
max-width: 95%;
|
||
}
|
||
|
||
.login-card {
|
||
padding: 40rpx 30rpx;
|
||
}
|
||
|
||
.app-title {
|
||
font-size: 42rpx;
|
||
}
|
||
|
||
.welcome-subtitle {
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.card-subtitle {
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
|
||
/* 深色模式适配 - 保持亮色主题 */
|
||
@media (prefers-color-scheme: dark) {
|
||
.login-page {
|
||
background: var(--gradient-primary);
|
||
}
|
||
|
||
.login-card {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
border-color: rgba(255, 255, 255, 0.2);
|
||
}
|
||
|
||
.card-title {
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.card-subtitle {
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.input-container {
|
||
background: var(--gray-lighter);
|
||
border-color: var(--border);
|
||
}
|
||
|
||
.input-container.focused {
|
||
background: var(--white);
|
||
}
|
||
|
||
.input {
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.input::placeholder {
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.remember-text {
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.forgot-link {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.test-tips {
|
||
background: var(--info-light);
|
||
border-color: var(--primary-light);
|
||
}
|
||
|
||
.tips-text {
|
||
color: var(--text-color);
|
||
}
|
||
}
|
||
</style>
|