2022-04-21 18:20:39 +08:00
|
|
|
<script lang="ts" setup>
|
2022-04-22 01:16:02 +08:00
|
|
|
import { reactive, ref } from "vue"
|
|
|
|
import { useRouter } from "vue-router"
|
2022-04-22 12:47:04 +08:00
|
|
|
import { useUserStore } from "@/store/modules/user"
|
2022-04-22 01:16:02 +08:00
|
|
|
import { User, Lock, Key } from "@element-plus/icons-vue"
|
|
|
|
import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
|
2022-08-19 15:25:07 +08:00
|
|
|
import type { FormInstance, FormRules } from "element-plus"
|
2022-04-21 18:20:39 +08:00
|
|
|
|
|
|
|
interface ILoginForm {
|
|
|
|
/** admin 或 editor */
|
2022-08-19 15:25:07 +08:00
|
|
|
username: "admin" | "editor"
|
2022-04-21 18:20:39 +08:00
|
|
|
/** 密码 */
|
|
|
|
password: string
|
|
|
|
/** 验证码 */
|
|
|
|
code: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const router = useRouter()
|
2022-08-19 15:25:07 +08:00
|
|
|
const loginFormRef = ref<FormInstance | null>(null)
|
2022-04-28 16:10:49 +08:00
|
|
|
|
2022-08-19 15:25:07 +08:00
|
|
|
/** 登录按钮 Loading */
|
|
|
|
const loading = ref(false)
|
|
|
|
/** 验证码图片 URL */
|
|
|
|
const codeUrl = ref("")
|
|
|
|
/** 登录表单数据 */
|
|
|
|
const loginForm: ILoginForm = reactive({
|
|
|
|
username: "admin",
|
|
|
|
password: "12345678",
|
|
|
|
code: "abcd"
|
2022-04-28 16:10:49 +08:00
|
|
|
})
|
2022-08-19 15:25:07 +08:00
|
|
|
/** 登录表单校验规则 */
|
|
|
|
const loginFormRules: FormRules = {
|
|
|
|
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
|
|
|
password: [
|
|
|
|
{ required: true, message: "请输入密码", trigger: "blur" },
|
|
|
|
{ min: 8, max: 16, message: "长度在 8 到 16 个字符", trigger: "blur" }
|
|
|
|
],
|
|
|
|
code: [{ required: true, message: "请输入验证码", trigger: "blur" }]
|
|
|
|
}
|
|
|
|
/** 登录逻辑 */
|
|
|
|
const handleLogin = () => {
|
|
|
|
loginFormRef.value?.validate((valid: boolean) => {
|
|
|
|
if (valid) {
|
|
|
|
loading.value = true
|
|
|
|
useUserStore()
|
|
|
|
.login({
|
|
|
|
username: loginForm.username,
|
|
|
|
password: loginForm.password
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
router.push({ path: "/" })
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
createCode()
|
|
|
|
loginForm.password = ""
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
loading.value = false
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
/** 创建验证码 */
|
|
|
|
const createCode = () => {
|
|
|
|
// 先清空验证码的输入
|
|
|
|
loginForm.code = ""
|
|
|
|
// 实际开发中,可替换成自己的地址,这里只是提供一个参考
|
|
|
|
codeUrl.value = `/api/v1/login/code?${Math.random() * 1000}`
|
|
|
|
}
|
2022-04-28 16:10:49 +08:00
|
|
|
|
|
|
|
/** 初始化验证码 */
|
2022-08-19 15:25:07 +08:00
|
|
|
// createCode()
|
2022-04-21 18:20:39 +08:00
|
|
|
</script>
|
|
|
|
|
2022-04-22 12:47:04 +08:00
|
|
|
<template>
|
|
|
|
<div class="login-container">
|
|
|
|
<ThemeSwitch class="theme-switch" />
|
|
|
|
<div class="login-card">
|
|
|
|
<div class="title">
|
|
|
|
<img src="@/assets/layout/logo-text-2.png" />
|
|
|
|
</div>
|
|
|
|
<div class="content">
|
2022-08-19 15:25:07 +08:00
|
|
|
<el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules" @keyup.enter="handleLogin">
|
2022-04-22 12:47:04 +08:00
|
|
|
<el-form-item prop="username">
|
|
|
|
<el-input
|
2022-08-19 15:25:07 +08:00
|
|
|
v-model.trim="loginForm.username"
|
2022-04-22 12:47:04 +08:00
|
|
|
placeholder="用户名"
|
|
|
|
type="text"
|
|
|
|
tabindex="1"
|
|
|
|
:prefix-icon="User"
|
|
|
|
size="large"
|
|
|
|
/>
|
|
|
|
</el-form-item>
|
|
|
|
<el-form-item prop="password">
|
|
|
|
<el-input
|
2022-08-19 15:25:07 +08:00
|
|
|
v-model.trim="loginForm.password"
|
2022-04-22 12:47:04 +08:00
|
|
|
placeholder="密码"
|
|
|
|
type="password"
|
|
|
|
tabindex="2"
|
|
|
|
:prefix-icon="Lock"
|
|
|
|
size="large"
|
2022-04-28 16:10:49 +08:00
|
|
|
show-password
|
2022-04-22 12:47:04 +08:00
|
|
|
/>
|
|
|
|
</el-form-item>
|
|
|
|
<el-form-item prop="code">
|
|
|
|
<el-input
|
2022-08-19 15:25:07 +08:00
|
|
|
v-model.trim="loginForm.code"
|
2022-04-22 12:47:04 +08:00
|
|
|
placeholder="验证码"
|
|
|
|
type="text"
|
|
|
|
tabindex="3"
|
|
|
|
:prefix-icon="Key"
|
|
|
|
maxlength="4"
|
|
|
|
size="large"
|
|
|
|
/>
|
|
|
|
<span class="show-code">
|
2022-08-19 15:25:07 +08:00
|
|
|
<img :src="codeUrl" @click="createCode" />
|
2022-04-22 12:47:04 +08:00
|
|
|
</span>
|
|
|
|
</el-form-item>
|
2022-08-19 15:25:07 +08:00
|
|
|
<el-button :loading="loading" type="primary" size="large" @click.prevent="handleLogin"> 登 录 </el-button>
|
2022-04-22 12:47:04 +08:00
|
|
|
</el-form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
2022-04-21 18:20:39 +08:00
|
|
|
<style lang="scss" scoped>
|
|
|
|
.login-container {
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
width: 100%;
|
|
|
|
min-height: 100%;
|
|
|
|
.theme-switch {
|
|
|
|
position: fixed;
|
|
|
|
top: 5%;
|
|
|
|
right: 5%;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
.login-card {
|
|
|
|
width: 480px;
|
|
|
|
border-radius: 20px;
|
|
|
|
box-shadow: 0 0 10px #dcdfe6;
|
|
|
|
background-color: #fff;
|
|
|
|
overflow: hidden;
|
|
|
|
.title {
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
height: 150px;
|
|
|
|
img {
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.content {
|
|
|
|
padding: 20px 50px 50px 50px;
|
|
|
|
.show-code {
|
|
|
|
position: absolute;
|
|
|
|
right: 0px;
|
|
|
|
top: 0px;
|
|
|
|
cursor: pointer;
|
|
|
|
user-select: none;
|
|
|
|
img {
|
|
|
|
width: 100px;
|
2022-05-23 14:30:06 +08:00
|
|
|
height: 40px;
|
2022-04-21 18:20:39 +08:00
|
|
|
border-radius: 4px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.el-button {
|
|
|
|
width: 100%;
|
|
|
|
margin-top: 10px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|