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