<route lang="yaml"> meta: title: 登录 constant: true layout: false </route> <script lang="ts" setup name="Login"> import type { FormInstance, FormRules } from 'element-plus' import { ElMessage } from 'element-plus' import useUserStore from '@/store/modules/user' import { RSAdecrypt, RSAencrypt } from '@/utils/security' import { getPrivateKey, removePrivateKey } from '@/utils/auth' import { tryOnBeforeUnmount } from '@vueuse/core' const route = useRoute() const router = useRouter() const userStore = useUserStore() const bgUrl = new URL('@/assets/images/login-image/theme0/bg.png', import.meta.url) // 背景图片 const leftUrl = new URL('@/assets/images/login-image/theme0/left.jpg', import.meta.url)// 左边图片 const title = import.meta.env.VITE_APP_TITLE // 表单类型,login 登录,reset 重置密码 const formType = ref('login') // 加载状态 const loading = ref(false) // 密码类型:password 密码 const passwordType = ref('password') // 重定向路径 const redirect = ref(route.query.redirect?.toString() ?? '/') // 是否需要验证码 const showKaptcha = ref(false) // 公钥 const publicKey = ref('') // sid const sid = ref('') // 获取系统基础配置: 公钥,是否开启验证码 function getBaseConfig() { userStore.getBaseConfig().then((res) => { showKaptcha.value = res.kaptcha publicKey.value = res.publicKey sid.value = res.sid ElMessage({ message: '连接服务器成功', type: 'success', }) }) } // 登录 const loginFormRef = ref<FormInstance>() const loginPasswordRef = ref<HTMLElement>() const loginForm = ref({ username: '', password: '', kaptcha: '', remember: !!localStorage.login_username, }) const loginRules = ref<FormRules>({ username: [{ required: true, trigger: 'blur', message: '请输入用户名' }], password: [ { required: true, trigger: 'blur', message: '请输入密码' }, { min: 6, max: 18, trigger: 'blur', message: '密码长度为6到18位' }, ], }) // 处理登录 function handleLogin() { loginFormRef.value && loginFormRef.value.validate(async (valid) => { if (valid) { loading.value = true // 表单对象 const finalForm = { sid: sid.value, username: loginForm.value.username, password: '', kaptcha: loginForm.value.kaptcha, } // 加密 finalForm.password = await RSAencrypt(loginForm.value.password) userStore .login(finalForm) .then(() => { ElMessage({ message: '登录成功', type: 'success', }) loading.value = true if (loginForm.value.remember) { // 保存用户名 localStorage.setItem('login_username', loginForm.value.username) // 保存 加密密码串 localStorage.setItem('login_password', finalForm.password) } else { // 移除用户名 localStorage.removeItem('login_username') // 移除 加密密码串 localStorage.removeItem('login_password') // 移除私钥 removePrivateKey() } router.push(redirect.value) }) .catch(() => { loading.value = false }) } }) } onBeforeUnmount(() => { loading.value = false }) // 注册 const registerFormRef = ref<FormInstance>() const registerPasswordRef = ref<HTMLElement>() const registerCheckPasswordRef = ref<HTMLElement>() const registerForm = ref({ username: '', captcha: '', password: '', checkPassword: '', }) const registerRules = ref<FormRules>({ username: [{ required: true, trigger: 'blur', message: '请输入用户名' }], captcha: [{ required: true, trigger: 'blur', message: '请输入验证码' }], password: [ { required: true, trigger: 'blur', message: '请输入密码' }, { min: 6, max: 18, trigger: 'blur', message: '密码长度为6到18位' }, ], checkPassword: [ { required: true, trigger: 'blur', message: '请再次输入密码' }, { validator: (rule, value, callback) => { if (value !== registerForm.value.password) { callback(new Error('两次输入的密码不一致')) } else { callback() } }, }, ], }) function handleRegister() { ElMessage({ message: '注册模块仅提供界面演示,无实际功能,需开发者自行扩展', type: 'warning', }) registerFormRef.value && registerFormRef.value.validate((valid) => { if (valid) { // 这里编写业务代码 } }) } // 重置密码 const resetFormRef = ref<FormInstance>() const resetNewPasswordRef = ref<HTMLElement>() const resetForm = ref({ username: localStorage.login_username || '', captcha: '', newPassword: '', }) const resetRules = ref<FormRules>({ username: [{ required: true, trigger: 'blur', message: '请输入用户名' }], captcha: [{ required: true, trigger: 'blur', message: '请输入验证码' }], newPassword: [ { required: true, trigger: 'blur', message: '请输入新密码' }, { min: 6, max: 18, trigger: 'blur', message: '密码长度为6到18位' }, ], }) function handleReset() { ElMessage({ message: '重置密码模块仅提供界面演示,无实际功能,需开发者自行扩展', type: 'warning', }) resetFormRef.value && resetFormRef.value.validate((valid) => { if (valid) { // 这里编写业务代码 } }) } function showPassword(passwordEl: HTMLElement | undefined) { passwordType.value = passwordType.value === 'password' ? '' : 'password' nextTick(() => { passwordEl?.focus() }) } function testusername(username: string) { loginForm.value.username = username loginForm.value.password = '111111' handleLogin() } onBeforeMount(async () => { loginForm.value.username = localStorage.login_username || '' if (localStorage.login_username) { const passwoed = await RSAdecrypt(localStorage.login_password) loginForm.value.password = passwoed } getBaseConfig() }) const element = ref() onMounted(() => { var rightHeight = window.getComputedStyle(element.value).height document.getElementById('left-div').style.height = rightHeight }) </script> <template> <div :style="{ backgroundImage: 'url(' + bgUrl + ')' }" class="login-container"> <div class="login-div"> <div id="left-div" :style="{ backgroundImage: 'url(' + leftUrl + ')' }" class="left-div"> <!-- <div class="logo-div"> <img> </div> --> <div class="title-div"> <div class="title" style="text-align: center;padding-top: 10px;"> {{ title }} </div> </div> </div> <div ref="element" class="right-div"> <el-form id="login-form" ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form"> <h5 class="login-title"> 登录 </h5> <el-form-item prop="username"> <el-input ref="name" v-model="loginForm.username" placeholder="用户名" text tabindex="1" autocomplete="on" style="width: 100%;height: 40px;"> <template #prefix> <el-icon> <svg-icon name="ep:user" /> </el-icon> </template> </el-input> </el-form-item> <el-form-item prop="password"> <el-input ref="loginPasswordRef" v-model="loginForm.password" :type="passwordType" placeholder="密码" tabindex="2" autocomplete="on" style="width: 100%;height: 40px;"> <template #prefix> <el-icon> <svg-icon name="ep:lock" /> </el-icon> </template> <!-- <template #suffix> <el-icon> <svg-icon class="eyes" :name="passwordType === 'password' ? 'eye' : 'eye-open'" @click="showPassword(loginPasswordRef)" /> </el-icon> </template> --> </el-input> </el-form-item> <el-form-item> <el-button :loading="loading" :disabled="loading" type="primary" style="width:100%;" @click="handleLogin"> 登录 </el-button> </el-form-item> </el-form> </div> <div class="clear-div" /> </div> </div> </template> <style rel="stylesheet/scss" lang="scss" scoped> $bg: #FFFFFF; $dark_gray: #889aa4; $light_gray: #fff; .login-container { position: relative; height: 100%; width: 100%; /*background: #000000 url("/static/images/login_images/bg.png") no-repeat;*/ background-color: #000000; background-repeat: no-repeat; -webkit-background-size: 100% 100%; background-size: 100% 100%; background-color: $bg; .login-div { /*height:385px;*/ width: 800px; position: absolute; overflow: hidden; left: 50%; top: 50%; margin-left: -400px; margin-top: -220px; border: 1px solid #889aa4; border-radius: 3px; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04); } .left-div { width: 60%; float: left; /*background: url("/static/images/login_images/left.jpg");*/ background-color: #ffffffff; } .title-div { /*margin: 20px 30px 30px 30px; */ } .title { color: $light_gray; font-size: 26px; font-weight: 400; } .right-div { width: 40%; float: left; background-color: white } .clear-div { clear: both; } .login-form { max-width: 100%; padding: 15px 15px 5px 15px; margin: auto; overflow: hidden; border-radius: 3px; box-shadow: 0 5px 8px rgba(0, 0, 0, .12), 0 0 10px rgba(0, 0, 0, .04); } .tips { font-size: 14px; /*color: #fff;*/ margin-bottom: 10px; span { &:first-of-type { margin-right: 16px; } } } .svg-container { padding: 0px 3px 0px 10px; color: $dark_gray; vertical-align: middle; width: 30px; display: inline-block; } .login-title { font-size: 18px; font-weight: 400; color: #000; margin: 10px auto 30px auto; text-align: center; } .show-pwd { position: absolute; right: 10px; top: 7px; font-size: 16px; color: $dark_gray; cursor: pointer; user-select: none; } } .eyes { &:hover { cursor: pointer; } } </style>