895 lines
17 KiB
Vue
895 lines
17 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: accountFocused, error: accountError }"
|
||
>
|
||
<view class="input-icon-wrapper">
|
||
<i class="fas fa-user input-icon"></i>
|
||
</view>
|
||
<input
|
||
v-model="form.account"
|
||
placeholder="用户名"
|
||
class="input"
|
||
type="text"
|
||
@focus="handleAccountFocus"
|
||
@blur="handleAccountBlur"
|
||
@input="clearAccountError"
|
||
/>
|
||
<view class="input-border"></view>
|
||
</view>
|
||
<text class="error-text" v-if="accountError">{{
|
||
accountError
|
||
}}</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 lang="ts" setup>
|
||
import { reactive, ref, computed } from "vue";
|
||
import loginApi from "@/src/api/login";
|
||
import { useAuthStore } from "@/src/store/authStore.js";
|
||
import { redirectAfterLogin } from "@/src/utils/routeGuard.js";
|
||
|
||
interface LoginForm {
|
||
account: string;
|
||
password: string;
|
||
}
|
||
|
||
interface LoginUser {
|
||
id: number;
|
||
account: string;
|
||
name: string;
|
||
group_id: number;
|
||
}
|
||
|
||
interface LoginResponseData {
|
||
token: string;
|
||
user?: LoginUser;
|
||
id?: number;
|
||
}
|
||
|
||
const form = reactive<LoginForm>({
|
||
account: "",
|
||
password: "",
|
||
});
|
||
|
||
const loading = ref(false);
|
||
const accountFocused = ref(false);
|
||
const passwordFocused = ref(false);
|
||
const showPassword = ref(false);
|
||
const rememberMe = ref(false);
|
||
const accountError = ref("");
|
||
const passwordError = ref("");
|
||
|
||
const authStore = useAuthStore();
|
||
|
||
const isFormValid = computed<boolean>(() => {
|
||
return form.account.trim() !== "" && form.password.trim() !== "";
|
||
});
|
||
|
||
async function handleLogin() {
|
||
loading.value = true;
|
||
try {
|
||
const res = (await loginApi.login(form)) as LoginResponseData;
|
||
console.log("登录响应:", res);
|
||
|
||
const { token, user, id } = res || {};
|
||
|
||
if (!token) {
|
||
throw new Error("登录失败:未获取到访问令牌");
|
||
}
|
||
|
||
const userInfo: LoginUser | { account: string; id?: number } = user || {
|
||
account: form.account,
|
||
id: id,
|
||
};
|
||
|
||
authStore.login(userInfo, token);
|
||
|
||
uni.showToast({
|
||
title: "登录成功",
|
||
icon: "success",
|
||
});
|
||
|
||
setTimeout(() => {
|
||
redirectAfterLogin();
|
||
}, 500);
|
||
} catch (e: any) {
|
||
loading.value = false;
|
||
console.error("登录错误:", e);
|
||
|
||
const errorMessage: string =
|
||
e?.message || e?.msg || "登录失败,请检查网络连接";
|
||
uni.showToast({
|
||
title: errorMessage,
|
||
icon: "none",
|
||
duration: 3000,
|
||
});
|
||
}
|
||
}
|
||
|
||
// 切换密码显示
|
||
function togglePassword() {
|
||
showPassword.value = !showPassword.value;
|
||
}
|
||
|
||
// 切换记住我
|
||
function toggleRemember() {
|
||
rememberMe.value = !rememberMe.value;
|
||
}
|
||
|
||
// 忘记密码
|
||
function handleForgotPassword() {
|
||
uni.showToast({
|
||
title: "请联系管理员重置密码",
|
||
icon: "none",
|
||
});
|
||
}
|
||
|
||
// 处理用户名输入框焦点
|
||
function handleAccountFocus() {
|
||
accountFocused.value = true;
|
||
clearAccountError();
|
||
}
|
||
|
||
function handleAccountBlur() {
|
||
accountFocused.value = false;
|
||
validateAccount();
|
||
}
|
||
|
||
// 处理密码输入框焦点
|
||
function handlePasswordFocus() {
|
||
passwordFocused.value = true;
|
||
clearPasswordError();
|
||
}
|
||
|
||
function handlePasswordBlur() {
|
||
passwordFocused.value = false;
|
||
validatePassword();
|
||
}
|
||
|
||
// 清除用户名错误
|
||
function clearAccountError() {
|
||
accountError.value = "";
|
||
}
|
||
|
||
// 清除密码错误
|
||
function clearPasswordError() {
|
||
passwordError.value = "";
|
||
}
|
||
|
||
// 验证用户名
|
||
function validateAccount(): boolean {
|
||
if (!form.account.trim()) {
|
||
accountError.value = "请输入用户名";
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 验证密码
|
||
function validatePassword(): boolean {
|
||
if (!form.password.trim()) {
|
||
passwordError.value = "请输入密码";
|
||
return false;
|
||
}
|
||
if (form.password.length < 6) {
|
||
passwordError.value = "密码至少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>
|