From 68fcf9e66c01e78d9d6d6f0dc09d8dac3cb31672 Mon Sep 17 00:00:00 2001
From: ZhangXianQiang <1135831638@qq.com>
Date: 星期二, 18 六月 2024 13:33:48 +0800
Subject: [PATCH] feat:添加登录页
---
src/assets/logo.png | 0
src/assets/background.png | 0
src/views/login/index.vue | 390 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
components.d.ts | 2
src/router/index.js | 7
5 files changed, 398 insertions(+), 1 deletions(-)
diff --git a/components.d.ts b/components.d.ts
index 3003e8a..8742b82 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -15,6 +15,8 @@
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElCountdown: typeof import('element-plus/es')['ElCountdown']
ElDialog: typeof import('element-plus/es')['ElDialog']
+ ElForm: typeof import('element-plus/es')['ElForm']
+ ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElPagination: typeof import('element-plus/es')['ElPagination']
diff --git a/src/assets/background.png b/src/assets/background.png
new file mode 100644
index 0000000..3d819ad
--- /dev/null
+++ b/src/assets/background.png
Binary files differ
diff --git a/src/assets/logo.png b/src/assets/logo.png
index f3d2503..bad81af 100644
--- a/src/assets/logo.png
+++ b/src/assets/logo.png
Binary files differ
diff --git a/src/router/index.js b/src/router/index.js
index 802dfd4..5964487 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -5,7 +5,7 @@
const routes = [
{
path: '/',
- redirect: '/index'
+ redirect: '/login'
},
{
@@ -24,6 +24,11 @@
},
]
},
+ // 鐧诲綍
+ {
+ path: '/login',
+ component: () => import('@/views/login/index.vue'),
+ },
// 鍦ㄧ嚎鍩硅
{
path: '/train',
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..2fbd6d0
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,390 @@
+<template>
+ <div class="w-screen h-screen overflow-hidden">
+ <img src="@/assets/background.png" class="w-full h-full object-cover absolute z-0" alt="">
+ <div class="lowin lowin-blue mt-20">
+ <div class="lowin-brand">
+ <img src="@/assets/logo.png" alt="logo">
+ </div>
+ <div class="lowin-wrapper">
+ <div class="lowin-box lowin-login">
+ <div class="lowin-box-inner">
+ <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules">
+ <p>姹熻タ绌虹瀛︾敓绔�</p>
+ <div class="lowin-group">
+ <el-form-item prop="userName">
+ <label>鐢ㄦ埛鍚� </label>
+ <el-input ref="userName" v-model="loginForm.userName" class="lowin-input" placeholder="鐢ㄦ埛鍚�"
+ name="userName" type="text" tabindex="1" auto-complete="on" />
+ </el-form-item>
+ </div>
+ <div class="lowin-group password-group">
+ <el-form-item prop="password">
+ <label>瀵嗙爜 <a href="#" class="forgot-link">蹇樿瀵嗙爜?</a></label>
+ <el-input class="lowin-input" :key="passwordType" ref="password" v-model="loginForm.password"
+ :type="passwordType" placeholder="瀵嗙爜" name="password" tabindex="2" auto-complete="on"
+ @keyup.native="checkCapslock" @blur="capsTooltip = false" @keyup.enter.native="handleLogin" />
+ </el-form-item>
+ </div>
+
+ <el-button :loading="loading" class="lowin-btn login-btn" @click="handleLogin">鐧诲綍</el-button>
+ </el-form>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, nextTick } from 'vue';
+import { useRouter } from 'vue-router';
+
+const router = useRouter();
+
+const validateUsername = (rule, value, callback) => {
+ if (value.length < 5) {
+ callback(new Error('鐢ㄦ埛鍚嶄笉鑳藉皯浜�5涓瓧绗�'));
+ } else {
+ callback();
+ }
+};
+const validatePassword = (rule, value, callback) => {
+ if (value.length < 5) {
+ callback(new Error('瀵嗙爜涓嶈兘灏戜簬5涓瓧绗�'));
+ } else {
+ callback();
+ }
+};
+
+const loginForm = reactive({
+ userName: '',
+ password: '',
+ remember: false
+});
+const loginRules = reactive({
+ userName: [{ required: true, trigger: 'blur', validator: validateUsername }],
+ password: [{ required: true, trigger: 'blur', validator: validatePassword }]
+});
+const passwordType = ref('password');
+const capsTooltip = ref(false);
+const loading = ref(false);
+const showDialog = ref(false);
+
+const userName = ref(null);
+const password = ref(null);
+
+const loginFormRef = ref(null);
+
+
+
+const checkCapslock = ({ shiftKey, key } = {}) => {
+ if (key && key.length === 1) {
+ if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) {
+ capsTooltip.value = true;
+ } else {
+ capsTooltip.value = false;
+ }
+ }
+ if (key === 'CapsLock' && capsTooltip.value === true) {
+ capsTooltip.value = false;
+ }
+};
+
+const showPwd = () => {
+ if (passwordType.value === 'password') {
+ passwordType.value = '';
+ } else {
+ passwordType.value = 'password';
+ }
+ nextTick(() => {
+ password.value.focus();
+ });
+};
+
+const handleLogin = () => {
+ loginFormRef.value.validate((valid) => {
+ if (valid) {
+ router.push('/index');
+ }
+ });
+};
+
+onMounted(() => {
+ if (loginForm.userName === '') {
+ userName.value.focus();
+ } else if (loginForm.password === '') {
+ password.value.focus();
+ }
+});
+</script>
+
+<style scoped>
+.lowin {
+ /* variables */
+ --color-primary: #44a0b3;
+ --color-grey: rgba(68, 160, 179, .06);
+ --color-dark: rgba(68, 160, 179, .5);
+ --color-semidark: rgba(68, 160, 179, .5);
+
+ text-align: center;
+ font-family: 'Segoe UI';
+ font-size: 14px;
+}
+
+.lowin .lowin-wrapper {
+ -webkit-transition: all 1s;
+ -o-transition: all 1s;
+ transition: all 1s;
+ -webkit-perspective: 1000px;
+ perspective: 1000px;
+ position: relative;
+ height: 100%;
+ width: 360px;
+ margin: 0 auto;
+}
+
+.lowin.lowin-blue {
+ --color-primary: #0081C6;
+ --color-grey: rgba(0, 129, 198, .05);
+ --color-dark: rgba(0, 129, 198, .7);
+ --color-semidark: rgba(0, 129, 198, .45);
+}
+
+.lowin a {
+ color: var(--color-primary);
+ text-decoration: none;
+ border-bottom: 1px dashed var(--color-semidark);
+ margin-top: -3px;
+ padding-bottom: 2px;
+}
+
+.lowin * {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.lowin .lowin-brand {
+ overflow: hidden;
+ width: 100px;
+ height: 100px;
+ margin: 0 auto -50px auto;
+ border-radius: 50%;
+ -webkit-box-shadow: 0 4px 40px rgba(0, 0, 0, .07);
+ box-shadow: 0 4px 40px rgba(0, 0, 0, .07);
+ padding: 10px;
+ background-color: #fff;
+ z-index: 1;
+ position: relative;
+}
+
+.lowin .lowin-brand img {
+ width: 100%;
+}
+
+.lowin .lowin-box {
+ width: 100%;
+ position: absolute;
+ left: 0;
+}
+
+.lowin .lowin-box-inner {
+ background-color: #fff;
+ -webkit-box-shadow: 0 7px 25px rgba(0, 0, 0, .08);
+ box-shadow: 0 7px 25px rgba(0, 0, 0, .08);
+ padding: 60px 25px 25px 25px;
+ text-align: left;
+ border-radius: 3px;
+}
+
+.lowin .lowin-box::after {
+ content: ' ';
+ -webkit-box-shadow: 0 0 25px rgba(0, 0, 0, .1);
+ box-shadow: 0 0 25px rgba(0, 0, 0, .1);
+ -webkit-transform: translate(0, -92.6%) scale(.88);
+ -ms-transform: translate(0, -92.6%) scale(.88);
+ transform: translate(0, -92.6%) scale(.88);
+ border-radius: 3px;
+ position: absolute;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #fff;
+ z-index: -1;
+}
+
+.lowin .lowin-box.lowin-flip {
+ -webkit-transform: rotate3d(0, 1, 0, -180deg);
+ transform: rotate3d(0, 1, 0, -180deg);
+ display: none;
+ opacity: 0;
+}
+
+.lowin .lowin-box p {
+ color: var(--color-semidark);
+ font-weight: 700;
+ margin-bottom: 20px;
+ text-align: center;
+}
+
+.lowin .lowin-box .lowin-group {
+ margin-bottom: 30px;
+}
+
+.lowin .lowin-box label {
+ margin-bottom: 5px;
+ display: inline-block;
+ width: 100%;
+ color: var(--color-semidark);
+ font-weight: 700;
+}
+
+.lowin .lowin-box label a {
+ float: right;
+}
+
+.lowin .lowin-box .lowin-input {
+ background-color: var(--color-grey);
+ color: var(--color-dark);
+ border: none;
+ border-radius: 3px;
+ padding: 5px 20px;
+ width: 100%;
+ outline: 0;
+}
+
+.lowin .lowin-box .lowin-btn {
+ display: inline-block;
+ width: 100%;
+ border: none;
+ color: #fff;
+ border-radius: 3px;
+ background-color: var(--color-primary);
+ -webkit-box-shadow: 0 2px 7px var(--color-semidark);
+ box-shadow: 0 2px 7px var(--color-semidark);
+ font-weight: 700;
+ outline: 0;
+ cursor: pointer;
+ -webkit-transition: all .5s;
+ -o-transition: all .5s;
+ transition: all .5s;
+}
+
+.lowin .lowin-box .lowin-btn:active {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.lowin .lowin-box .lowin-btn:hover {
+ opacity: .9;
+}
+
+.lowin .text-foot {
+ text-align: center;
+ padding: 10px;
+ font-weight: 700;
+ margin-top: 20px;
+ color: var(--color-semidark);
+}
+
+/* animation */
+.lowin .lowin-box.lowin-animated {
+ -webkit-animation-name: LowinAnimated;
+ animation-name: LowinAnimated;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+}
+
+.lowin .lowin-box.lowin-animatedback {
+ -webkit-animation-name: LowinAnimatedBack;
+ animation-name: LowinAnimatedBack;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+}
+
+.lowin .lowin-box.lowin-animated-flip {
+ -webkit-animation-name: LowinAnimatedFlip;
+ animation-name: LowinAnimatedFlip;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+}
+
+.lowin .lowin-box.lowin-animated-flipback {
+ -webkit-animation-name: LowinAnimatedFlipBack;
+ animation-name: LowinAnimatedFlipBack;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+}
+
+.lowin .lowin-brand.lowin-animated {
+ -webkit-animation-name: LowinBrandAnimated;
+ animation-name: LowinBrandAnimated;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+}
+
+.lowin .lowin-group.password-group {
+ -webkit-transition: all 1s;
+ -o-transition: all 1s;
+ transition: all 1s;
+}
+
+.lowin .lowin-group.password-group.lowin-animated {
+ -webkit-animation-name: LowinPasswordAnimated;
+ animation-name: LowinPasswordAnimated;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ -webkit-transform-origin: 0 0;
+ -ms-transform-origin: 0 0;
+ transform-origin: 0 0;
+}
+
+.lowin .lowin-group.password-group.lowin-animated-back {
+ -webkit-animation-name: LowinPasswordAnimatedBack;
+ animation-name: LowinPasswordAnimatedBack;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ -webkit-transform-origin: 0 0;
+ -ms-transform-origin: 0 0;
+ transform-origin: 0 0;
+}
+
+@media screen and (max-width: 320px) {
+ .lowin .lowin-wrapper {
+ width: 100%;
+ }
+
+ .lowin .lowin-box {
+ padding: 0 10px;
+ }
+}
+</style>
\ No newline at end of file
--
Gitblit v1.8.0