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