373 lines
8.0 KiB
Vue
373 lines
8.0 KiB
Vue
<template>
|
||
<view class="status-bar"></view>
|
||
<view class="login-container page-container">
|
||
<view class="login-card">
|
||
<!-- <view class="conner conner-tl"></view>
|
||
<view class="conner conner-tr"></view>
|
||
<view class="conner conner-bl"></view>
|
||
<view class="conner conner-br"></view> -->
|
||
<view class="login-header">
|
||
<view class="login-header-logo">
|
||
<view class="icon-wrapper">
|
||
<view class="iconfont icon-brain-2-fill danao-style"></view>
|
||
</view>
|
||
<text>YXD</text>
|
||
</view>
|
||
<view class="sub-title">File Handling Chat</view>
|
||
|
||
</view>
|
||
<!-- 表单 -->
|
||
<view class="form-wrapper">
|
||
<view class="form-item">
|
||
<view class="form-label">
|
||
<!-- <uni-icons type="person" size="24" color="#aaaaff"></uni-icons> -->
|
||
<text>用户名</text>
|
||
</view>
|
||
<input class="form-input" :class="{focused: isUsernameFocused, error: isUsernameError}"
|
||
v-model="UsernameValue" @focus="usernameFocused" @blur="handleUsernameBlur"
|
||
@input="validateUsername" placeholder="请输入用户名" />
|
||
</view>
|
||
<view class="form-item">
|
||
<view class="form-label">
|
||
<!-- <uni-icons type="locked" size="24" color="#aaaaff"></uni-icons> -->
|
||
<text>密码</text>
|
||
</view>
|
||
<input type="password" class="form-input"
|
||
:class="{focused: isPasswordFocused, error: isPasswordError}" v-model="PasswordValue"
|
||
@focus="passwordFocused" @blur="handlePasswordBlur" placeholder="请输入密码" />
|
||
</view>
|
||
<text v-if="formDataHasNull" class="error-info">用户名或密码不能为空</text>
|
||
<view class="form-option">
|
||
<view class="checkbox-wrapper" @click="form.remember = !form.remember">
|
||
<view class="checkbox" :class="{ checked: form.remember}">
|
||
<text v-if="form.remember">✓</text>
|
||
</view>
|
||
<text class="checkbox-text">记住密码</text>
|
||
|
||
</view>
|
||
<text class="forget-pwd">忘记密码?</text>
|
||
</view>
|
||
<button class="login-btn" :disabled="loading" :loading="loading"
|
||
@click="handleLogin">{{loading ? 'Loading...' : '登录'}}</button>
|
||
</view>
|
||
|
||
</view>
|
||
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
reactive,
|
||
ref,
|
||
computed,
|
||
onMounted
|
||
} from 'vue';
|
||
import {
|
||
login
|
||
} from '../../utils/cloud-api';
|
||
|
||
// 表单用户名变量
|
||
const UsernameValue = ref('');
|
||
const isUsernameFocused = ref(false);
|
||
const isUsernameError = ref(false)
|
||
const usernameFocused = () => {
|
||
isUsernameFocused.value = true;
|
||
formDataHasNull.value = false;
|
||
}
|
||
const handleUsernameBlur = () => {
|
||
isUsernameFocused.value = false;
|
||
}
|
||
// 用户名实时校验
|
||
const validateUsername = () => {
|
||
// if (UsernameValue.value && UsernameValue.value.length < 3) {
|
||
// isUsernameError.value = true;
|
||
// } else {
|
||
// isUsernameError.value = false;
|
||
// }
|
||
};
|
||
// 表单密码变量
|
||
const PasswordValue = ref('');
|
||
const isPasswordFocused = ref(false);
|
||
const isPasswordError = ref(false);
|
||
const passwordFocused = () => {
|
||
isPasswordFocused.value = true;
|
||
formDataHasNull.value = false;
|
||
}
|
||
const handlePasswordBlur = () => {
|
||
isPasswordFocused.value = false;
|
||
}
|
||
|
||
// 表单数据
|
||
const form = reactive({
|
||
username: computed(() => UsernameValue.value),
|
||
password: computed(() => PasswordValue.value),
|
||
remember: true
|
||
})
|
||
// 登录状态
|
||
const loading = ref(false)
|
||
|
||
//用户名密码是否非空
|
||
const formDataHasNull = ref(false)
|
||
const handleLogin = async() => {
|
||
checkFormData();
|
||
if (formDataHasNull.value) return
|
||
loading.value = true
|
||
try {
|
||
const token = await login(UsernameValue.value, PasswordValue.value)
|
||
// 登陆成功,保存登录数据到手机
|
||
saveLoginInfo();
|
||
uni.reLaunch({
|
||
url: '/pages/Chat/Chat'
|
||
})
|
||
} catch(err) {
|
||
console.log('登录失败',err);
|
||
uni.showToast({
|
||
title:err || '失败',
|
||
icon:'error'
|
||
})
|
||
}finally {
|
||
loading.value = false
|
||
}
|
||
|
||
|
||
}
|
||
|
||
// 检查用户名或密码是否为空
|
||
const checkFormData = () => {
|
||
if (!UsernameValue.value || !PasswordValue.value) {
|
||
formDataHasNull.value = true;
|
||
}
|
||
}
|
||
|
||
// 保存登录信息到手机
|
||
const saveLoginInfo = () => {
|
||
if (form.remember) {
|
||
const loginInfo = {
|
||
username: form.username,
|
||
password: form.password,
|
||
remember: true
|
||
}
|
||
uni.setStorageSync('login_info', loginInfo)
|
||
uni.setStorageSync('chatType', 0)
|
||
} else {
|
||
uni.removeStorageSync('login_info')
|
||
}
|
||
}
|
||
|
||
// 从手机加载登录消息
|
||
const loadLoginInfo = () => {
|
||
try {
|
||
const loginInfo = uni.getStorageSync('login_info')
|
||
if (loginInfo) {
|
||
UsernameValue.value = loginInfo.username || '';
|
||
PasswordValue.value = loginInfo.password || '';
|
||
form.remember = loginInfo.remember ?? true;
|
||
}
|
||
} catch (e) {
|
||
console.error('读取登录信息失败', e)
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadLoginInfo();
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.login-container {
|
||
padding: 140rpx 60rpx 100rpx 60rpx;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.login-card {
|
||
position: relative;
|
||
flex: 1;
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
background: #ffffff;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.conner {
|
||
position: absolute;
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.conner-tl {
|
||
top: 0;
|
||
left: 0;
|
||
border-top: 2px solid #aaaaff;
|
||
border-left: 2px solid #aaaaff;
|
||
}
|
||
|
||
.conner-tr {
|
||
top: 0;
|
||
right: 0;
|
||
border-top: 2px solid #aaaaff;
|
||
border-right: 2px solid #aaaaff;
|
||
}
|
||
|
||
.conner-bl {
|
||
bottom: 0;
|
||
left: 0;
|
||
border-bottom: 2px solid #aaaaff;
|
||
border-left: 2px solid #aaaaff;
|
||
}
|
||
|
||
.conner-br {
|
||
bottom: 0;
|
||
right: 0;
|
||
border-bottom: 2px solid #aaaaff;
|
||
border-right: 2px solid #aaaaff;
|
||
}
|
||
|
||
|
||
|
||
.login-header {
|
||
/* position: absolute;
|
||
top: 80rpx; */
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.login-header-logo {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.login-header-logo text {
|
||
margin-left: 8rpx;
|
||
font-size: 60rpx;
|
||
font-weight: bold;
|
||
color: #aaaaff;
|
||
text-shadow: 0 0 10rpx rgba(170, 170, 255, 0.4),
|
||
0 0 20rpx rgba(170, 170, 255, 0.3);
|
||
}
|
||
|
||
.icon-wrapper {
|
||
width: 90rpx;
|
||
height: 90rpx;
|
||
border-radius: 50%;
|
||
background-color: rgb(255, 255, 255);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
animation: glow 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes glow {
|
||
|
||
0%,
|
||
100% {
|
||
box-shadow: 0 0 20rpx rgba(170, 170, 255, 0.3);
|
||
}
|
||
|
||
50% {
|
||
box-shadow: 0 0 20rpx rgba(170, 170, 255, 0.4),
|
||
0 0 30rpx rgba(170, 170, 255, 0.3),
|
||
0 0 50rpx rgba(170, 170, 255, 0.2);
|
||
}
|
||
}
|
||
|
||
.icon-wrapper .danao-style {
|
||
font-size: 70rpx;
|
||
color: #aaaaff;
|
||
}
|
||
|
||
.sub-title {
|
||
margin-top: 20rpx;
|
||
font-size: 36rpx;
|
||
font-weight: 500;
|
||
color: #666;
|
||
text-shadow: 0 0 10rpx #999;
|
||
}
|
||
|
||
.form-wrapper {
|
||
margin-top: 50rpx;
|
||
width: 500rpx;
|
||
padding: 80rpx 30rpx;
|
||
background-color: rgba(170, 170, 255, 0.05);
|
||
border-radius: 20rpx;
|
||
/* border: 1rpx solid #aaaaff; */
|
||
box-shadow: 0 0 10rpx rgba(170, 170, 255, 0.5);
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.form-item {
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.form-item .form-input {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
padding: 0 10px;
|
||
box-sizing: border-box;
|
||
border-radius: 30rpx;
|
||
border: 1rpx solid #e5e5e5;
|
||
}
|
||
|
||
.form-item .focused {
|
||
border-color: #aaaaff;
|
||
box-shadow: 0 0 10rpx rgba(170, 170, 255, 0.5);
|
||
}
|
||
|
||
.form-item .error {
|
||
border-color: #ff0000;
|
||
box-shadow: 0 0 10rpx rgba(255, 0, 0, 0.5);
|
||
}
|
||
|
||
.error-info {
|
||
font-size: 24rpx;
|
||
color: #ff0000;
|
||
}
|
||
|
||
.form-option {
|
||
margin-top: 10rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.form-option .checkbox-wrapper {
|
||
display: flex;
|
||
justify-content: start;
|
||
align-items: center;
|
||
}
|
||
|
||
.form-option .checkbox-wrapper .checkbox {
|
||
width: 30rpx;
|
||
height: 30rpx;
|
||
border: 1rpx solid #666;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.form-option .checkbox-wrapper .checked {
|
||
background-color: #aaaaff;
|
||
}
|
||
|
||
.form-option .checkbox-wrapper .checkbox text {
|
||
color: #ffffff;
|
||
}
|
||
|
||
:deep(.login-btn) {
|
||
margin-top: 30rpx;
|
||
width: 500rpx;
|
||
height: 100rpx;
|
||
border-radius: 80rpx;
|
||
background: linear-gradient(to right, #aaaaff, #2969ed);
|
||
}
|
||
</style> |