Files
phone-app------test1-/pages/Login/Login.vue
2026-06-02 10:42:33 +08:00

373 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>