mirror of
https://github.com/zclzone/vue-naive-admin.git
synced 2026-01-23 08:00:22 +08:00
init
This commit is contained in:
190
src/views/login/index.vue
Normal file
190
src/views/login/index.vue
Normal file
@@ -0,0 +1,190 @@
|
||||
<!--------------------------------
|
||||
- @Author: Ronnie Zhang
|
||||
- @LastEditor: Ronnie Zhang
|
||||
- @LastEditTime: 2023/12/05 21:28:36
|
||||
- @Email: zclzone@outlook.com
|
||||
- Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||
--------------------------------->
|
||||
|
||||
<template>
|
||||
<div class="wh-full flex-col bg-[url(@/assets/images/login_bg.webp)] bg-cover">
|
||||
<div
|
||||
class="m-auto max-w-700 min-w-345 f-c-c rounded-8 bg-opacity-20 bg-cover p-12 card-shadow auto-bg"
|
||||
>
|
||||
<div class="hidden w-380 px-20 py-35 md:block">
|
||||
<img src="@/assets/images/login_banner.webp" class="w-full" alt="login_banner" />
|
||||
</div>
|
||||
|
||||
<div class="w-320 flex-col px-20 py-32">
|
||||
<h2 class="f-c-c text-24 font-normal text-#6a6a6a">
|
||||
<img src="@/assets/images/logo.png" height="50" class="mr-12" />
|
||||
{{ title }}
|
||||
</h2>
|
||||
<n-input
|
||||
v-model:value="loginInfo.username"
|
||||
autofocus
|
||||
class="mt-32 h-40 items-center"
|
||||
placeholder="请输入用户名"
|
||||
:maxlength="20"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="i-fe:user mr-12 opacity-20" />
|
||||
</template>
|
||||
</n-input>
|
||||
<n-input
|
||||
v-model:value="loginInfo.password"
|
||||
class="mt-20 h-40 items-center"
|
||||
type="password"
|
||||
show-password-on="mousedown"
|
||||
placeholder="请输入密码"
|
||||
:maxlength="20"
|
||||
@keydown.enter="handleLogin"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="i-fe:lock mr-12 opacity-20" />
|
||||
</template>
|
||||
</n-input>
|
||||
|
||||
<div class="mt-20 flex items-center">
|
||||
<n-input
|
||||
v-model:value="loginInfo.captcha"
|
||||
class="h-40 items-center"
|
||||
palceholder="请输入验证码"
|
||||
:maxlength="4"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="i-fe:key mr-12 opacity-20" />
|
||||
</template>
|
||||
</n-input>
|
||||
<img
|
||||
v-if="captchaUrl"
|
||||
:src="captchaUrl"
|
||||
alt="验证码"
|
||||
height="40"
|
||||
class="ml-12 w-80 cursor-pointer"
|
||||
@click="initCaptcha"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<n-checkbox
|
||||
class="mt-20"
|
||||
:checked="isRemember"
|
||||
label="记住我"
|
||||
:on-update:checked="(val) => (isRemember = val)"
|
||||
/>
|
||||
|
||||
<div class="mt-20 flex items-center">
|
||||
<n-button class="h-40 flex-1 rounded-5 text-16" type="primary" ghost @click="quickLogin">
|
||||
一键体验
|
||||
</n-button>
|
||||
|
||||
<n-button
|
||||
class="ml-32 h-40 flex-1 rounded-5 text-16"
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="handleLogin"
|
||||
>
|
||||
登录
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TheFooter class="py-12" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { throttle, lStorage } from '@/utils'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import api from './api'
|
||||
import { useUserStore, useAuthStore } from '@/store'
|
||||
import { initUserAndPermissions } from '@/router'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const authStore = useAuthStore()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const title = import.meta.env.VITE_TITLE
|
||||
|
||||
const isLogined = computed(() => {
|
||||
return authStore.accessToken && userStore.roles
|
||||
})
|
||||
|
||||
const loginInfo = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
})
|
||||
function initLoginInfo() {
|
||||
const localLoginInfo = lStorage.get('loginInfo')
|
||||
if (localLoginInfo) {
|
||||
loginInfo.value.username = localLoginInfo.username || ''
|
||||
loginInfo.value.password = localLoginInfo.password || ''
|
||||
}
|
||||
}
|
||||
|
||||
const captchaUrl = ref('')
|
||||
const initCaptcha = throttle(() => {
|
||||
captchaUrl.value = '/api/auth/captcha?' + Date.now()
|
||||
}, 500)
|
||||
|
||||
if (isLogined.value) {
|
||||
router.push({ path: '/role-select', query: route.query })
|
||||
} else {
|
||||
initLoginInfo()
|
||||
initCaptcha()
|
||||
}
|
||||
|
||||
function quickLogin() {
|
||||
loginInfo.value.username = 'admin'
|
||||
loginInfo.value.password = '123456'
|
||||
handleLogin(true)
|
||||
}
|
||||
|
||||
const isRemember = useStorage('isRemember', true)
|
||||
const loading = ref(false)
|
||||
async function handleLogin(isQuick) {
|
||||
const { username, password, captcha } = loginInfo.value
|
||||
if (!username || !password) return $message.warning('请输入用户名和密码')
|
||||
if (!isQuick && !captcha) return $message.warning('请输入验证码')
|
||||
try {
|
||||
loading.value = true
|
||||
$message.loading('正在验证,请稍后...', { key: 'login' })
|
||||
const { data } = await api.login({ username, password: password.toString(), captcha, isQuick })
|
||||
if (isRemember.value) {
|
||||
lStorage.set('loginInfo', { username, password })
|
||||
} else {
|
||||
lStorage.remove('loginInfo')
|
||||
}
|
||||
onLoginSuccess(data)
|
||||
} catch (error) {
|
||||
// 10003为验证码错误专属业务码
|
||||
if (error?.code === 10003) {
|
||||
// 为防止爆破,验证码错误则刷新验证码
|
||||
initCaptcha()
|
||||
}
|
||||
$message.destroy('login')
|
||||
console.error(error)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function onLoginSuccess(data = {}) {
|
||||
authStore.setToken(data)
|
||||
$message.loading('登录中...', { key: 'login' })
|
||||
try {
|
||||
await initUserAndPermissions()
|
||||
$message.success('登录成功', { key: 'login' })
|
||||
if (route.query.redirect) {
|
||||
const path = route.query.redirect
|
||||
delete route.query.redirect
|
||||
router.push({ path, query: route.query })
|
||||
} else {
|
||||
router.push('/')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
$message.destroy('login')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user