web/src/views/Login.vue

429 lines
8.4 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.

<script setup lang="ts">
import {onMounted, onUnmounted, ref} from 'vue'
import {post} from '@/utils/request.ts'
import {useRouter} from "vue-router";
import {type Action, ElMessage, ElMessageBox} from "element-plus";
import Mask from "@/components/common/Mask.vue";
import Auth from "@/components/manger/Auth.vue";
import {apiConfig} from "@/assets/config/apiConfig";
import type {Request, Response} from "@/utils/ws.ts";
import {useWsStore} from "@/stores/wsStore.ts";
const username = ref('')
const password = ref('')
const router = useRouter();
const loading = ref(false)
const tip=ref<string>("正在获取本地网卡地址")
interface NetWorkType {
ip: string,
mac: string,
}
const netWork = ref<NetWorkType>({
ip: "192.168.1.1",
mac: "00-00-00-00-00"
})
const handleLogin = async () => {
loading.value = true
try{
await loginCore();
}catch (e:any){
error(e)
}
finally {
loading.value = false
}
}
const loginCore=async ()=>{
let token:any=await post(apiConfig.ManagerUserLogin, {username: username.value, password: password.value},{catch_error: true})
localStorage.setItem('token', token)
await post(apiConfig.signIn, {mac: netWork.value.mac, ip: netWork.value.ip}, {catch_error: true})
success()
}
const success = () => {
loading.value = false
ElMessageBox.alert('登录成功且签到,即将为您进入到首页', '签到提示', {
type:'success',
showClose: false,
callback: (action: Action) => {
router.push("/home/index")
},
})
}
const error = (message:any) => {
ElMessageBox.alert(message)
}
const wsStore = useWsStore();
const reciceMessage = (response: Response) => {
tip.value="将以IP:"+response.Data[0].IPAddress+"登录签到"
netWork.value = {
ip: response.Data[0].IPAddress,
mac: response.Data[0].MACAddress
}
}
const getNetwork = () => {
let data: any = {}
let request: Request = {
type: "getNetwork",
config: {},
data: data
}
wsStore.sendMessage(request);
}
onMounted(async () => {
wsStore.setMessageCallback(reciceMessage)
wsStore.setErrorCallback(errorCallback)
getNetwork()
});
const errorCallback = () => {
tip.value="获取本地IP失败将以默认IP进行登录"
}
onUnmounted(() => {
wsStore.removeAllMessageCallback()
wsStore.removeAllErrorCallback()
})
const isShowAuth = ref(false)
const showAuth = () => {
isShowAuth.value = true
}
</script>
<template>
<div class="login-container">
<div class="particles-bg">
<div class="particle particle-1"></div>
<div class="particle particle-2"></div>
<div class="particle particle-3"></div>
<div class="particle particle-4"></div>
</div>
<div class="login-card"
v-loading="loading"
element-loading-text="正在登录,请稍候......"
>
<h1 class="title">欢迎使用药慧精灵</h1>
<div class="input-group">
<i class="fas fa-user input-icon"></i>
<input
v-model="username"
type="text"
placeholder="请输入用户名"
class="input-field"
>
</div>
<div class="input-group">
<i class="fas fa-lock input-icon"></i>
<input
v-model="password"
type="password"
placeholder="请输入密码"
class="input-field"
>
</div>
<div class="button-group">
<button type="submit" class="login-button" @click="handleLogin">登录</button>
<button class="auth-button" @click="showAuth">授权</button>
</div>
<div class="tip" >{{tip}}</div>
</div>
</div>
<Mask :is-show="isShowAuth" @close="isShowAuth=false" :width="600" :height="500" title="授权">
<Auth></Auth>
</Mask>
</template>
<style scoped lang="scss">
.login-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #5078c8;
}
// 修改粒子容器样式
.particles-bg {
position: fixed;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: 0;
}
// 修改粒子基础样式
.particle {
position: absolute;
border-radius: 50%;
animation: float 12s infinite linear;
filter: blur(1px);
// 调整渐变颜色增加活力
background: linear-gradient(145deg, #89c3fd 0%, #a8d8ff 100%);
// 增加伪元素创建更多粒子
&::before, &::after {
content: '';
position: absolute;
width: 70%;
height: 70%;
border-radius: inherit;
background: rgba(255, 255, 255, 0.4);
}
// 新增粒子尺寸和位置
&-1 {
width: 60px;
height: 60px;
top: 15%;
left: 5%;
animation-duration: 14s;
}
&-2 {
width: 80px;
height: 80px;
top: 70%;
right: 10%;
animation-duration: 16s;
}
&-3 {
width: 40px;
height: 40px;
top: 40%;
right: 30%;
animation-duration: 12s;
}
&-4 {
width: 100px;
height: 100px;
top: 65%;
left: 15%;
animation-duration: 18s;
}
// 新增更多粒子通过伪元素实现
&:nth-child(odd)::before {
top: 20%;
left: 20%;
}
&:nth-child(even)::after {
bottom: 20%;
right: 20%;
}
}
// 优化动画效果
@keyframes float {
0%, 100% {
transform: translate(0, 0) rotate(0deg) scale(1);
opacity: 0.6;
}
33% {
transform: translate(30px, -80px) rotate(120deg) scale(0.9);
opacity: 0.8;
}
66% {
transform: translate(-20px, 60px) rotate(240deg) scale(1.1);
opacity: 0.4;
}
}
// 增加粒子数量在原有4个基础上通过伪元素生成更多
.particles-bg::before,
.particles-bg::after {
content: '';
position: absolute;
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(145deg, #c2e9fb 0%, #a1c4fd 100%);
animation: miniFloat 10s infinite linear;
opacity: 0.7;
}
.particles-bg::before {
top: 20%;
right: 5%;
animation-delay: 2s;
}
.particles-bg::after {
bottom: 30%;
left: 8%;
animation-delay: 5s;
}
@keyframes miniFloat {
0%, 100% {
transform: translate(0, 0) scale(1);
}
50% {
transform: translate(40px, -60px) scale(0.8);
}
}
/* 调整原有卡片层级 */
.login-card {
position: relative;
z-index: 1;
/* 保持原有样式 */
}
.login-card {
background: rgba(255, 255, 255, 0.95);
padding: 2.5rem;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
width: 480px;
transform: translateY(-10%);
}
.title {
text-align: center;
font-size: 2rem;
color: #2c3e50;
margin-bottom: 2rem;
font-weight: 600;
}
.input-group {
position: relative;
margin-bottom: 1.5rem;
}
.input-icon {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: #7f8c8d;
}
.input-field {
width: 100%;
padding: 1rem 1rem 1rem 2.5rem;
border: 2px solid #ecf0f1;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
&:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
outline: none;
}
}
.options {
display: flex;
justify-content: space-between;
align-items: center;
margin: 1.5rem 0;
}
.remember-me {
display: flex;
align-items: center;
gap: 0.5rem;
color: #7f8c8d;
}
.forgot-password {
color: #3498db;
text-decoration: none;
font-size: 0.9rem;
&:hover {
text-decoration: underline;
}
}
.button-group {
display: flex;
.login-button {
flex: 1;
padding: 1rem;
background: linear-gradient(135deg, #3498db, #2980b9);
border: none;
border-radius: 8px;
color: white;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s ease;
&:hover {
transform: translateY(-2px);
}
&:active {
transform: translateY(0);
}
}
.auth-button {
flex: 1;
margin-left: 10px;
padding: 1rem;
background: linear-gradient(135deg, #3498db, #2980b9);
border: none;
border-radius: 8px;
color: white;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s ease;
&:hover {
transform: translateY(-2px);
}
&:active {
transform: translateY(0);
}
}
}
.tip{
position: relative;
width: 100%;
height: 30px;
line-height: 30px;
font-size: 14px;
color: #999;
text-align: left;
box-sizing: border-box;
padding-left: 10px;
padding-right: 10px;
overflow: hidden;
margin-top: 10px;
}
.register-link {
text-align: center;
margin-top: 1.5rem;
color: #7f8c8d;
a {
color: #3498db;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
</style>