first commit

This commit is contained in:
2026-06-02 10:42:33 +08:00
commit dd4975fd2c
1084 changed files with 442416 additions and 0 deletions

373
pages/Login/Login.vue Normal file
View File

@@ -0,0 +1,373 @@
<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>