登录页样式
div class="logo">
<div class="icon"></div>
<img src="@/assets/common/login.svg" width="300" alt="" />
<p>开箱即用的中后台管理系统</p>
</div>
手机号规则定义
<a-form-item
name="mobile"
:rules="[
{
required: true,
message: '手机号不能为空',
trigger: ['change', 'blur']
},
{
pattern: /^1[3-9][0-9]{9}$/,
message: '手机号格式不正确',
trigger: ['change', 'blur']
}
]"
>
<a-input size="large" v-model:value="loginForm.mobile"></a-input>
双向绑定value
</a-form-item>
script代码
定义loginForm函数,属性mobile
密码规则定义
<a-form-item
name="password"
:rules="[
{
required: true,
message: '密码不能为空',
trigger: ['change', 'blur'] trigger:触发时机
}
]"
>
<a-input-password size="large" v-model:value="loginForm.password">
//双向绑定value
//Value是标签a-input的属性
</a-input-password>
</a-form-item>
script代码
定义loginForm函数,属性password
用户使用协议
<a-form-item
name="isAgree"
:rules="[
{
validator: validatorAgree
}
]"
>
<a-checkbox v-model:checked="loginForm.isAgree">用户平台使用协议</a-checkbox>
//双向绑定checked
</a-form-item>
script代码
登录按钮
<a-form-item>
<a-button size="large" type="primary" block htmlType="submit">登录</a-button>
</a-form-item>
绑定onFinish事件
script代码
onst onFinish = async (values) => {
const { updateToken } = useToken() 调用token文件下的updateToken函数
console.log(values)
const data = await login(values)
updateToken(data)
router.push('/')
}
权限管理(前置/后置路由守卫)
const whiteList = ['/login', '/404']
router.beforeEach((to, from, next) => {
nprogress.start()
const { token } = useToken()
if (token) {
// 有token的情况下
if (to.path === '/login') {
// 如果在登录页,就直接跳转到首页
next('/')
} else {
next()
//不在登录页,就直接放行
}
} else {
//没有token的情况下
if (whiteList.includes(to.path)) {
// 如果在白名单给放行
next()
} else {
next('/login')
// 否则重定向回登录页
}
}
})
router.afterEach(() => nprogress.done())
具体代码(login.vue)
<template>
<div class="login-container">
<div class="logo">
<div class="icon"></div>
<img src="@/assets/common/login.svg" width="300" alt="" />
<p>开箱即用的中后台管理系统</p>
</div>
<div class="form">
<h3>iHRM 人力资源管理系统</h3>
<a-card class="login-card">
<a-form :model="loginForm" autocomplete="off" @finish="onFinish">
<a-form-item
name="mobile"
:rules="[
{
required: true,
message: '手机号不能为空',
trigger: ['change', 'blur']
},
{
pattern: /^1[3-9][0-9]{9}$/,
message: '手机号格式不正确',
trigger: ['change', 'blur']
}
]"
>
<a-input size="large" v-model:value="loginForm.mobile"></a-input>
</a-form-item>
<a-form-item
name="password"
:rules="[
{
required: true,
message: '密码不能为空',
trigger: ['change', 'blur']
}
]"
>
<a-input-password size="large" v-model:value="loginForm.password"></a-input-password>
</a-form-item>
<a-form-item
name="isAgree"
:rules="[
{
validator: validatorAgree
}
]"
>
<a-checkbox v-model:checked="loginForm.isAgree">用户平台使用协议</a-checkbox>
</a-form-item>
<a-form-item>
<a-button size="large" type="primary" block htmlType="submit">登录</a-button>
</a-form-item>
</a-form>
</a-card>
</div>
</div>
</template>
<script setup>
// 实现表单的校验
// 1. 声明响应式数据
import { reactive } from 'vue'
import { useRouter } from 'vue-router' //引入方法
import { login } from '@/api/login'
import useToken from '@/stores/token'
const router = useRouter() //得到一个router实例
//useRouter需要放置在最上层-初始化的关系
const loginForm = reactive({
mobile: '13800000002',
password: '123456',
isAgree: false
})
const onFinish = async (values) => {
const { updateToken } = useToken()
console.log(values)
const data = await login(values)
updateToken(data)
router.push('/')
}
const validatorAgree = (rule, value) => {
return value ? Promise.resolve() : Promise.reject(new Error('您必须同意用户协议'))
}
</script>
<style lang="less" scoped>
.login-container {
display: flex;
align-items: stretch;
height: 100vh;
.logo {
flex: 3;
background: rgba(38, 72, 176) url(../../assets/common/logBg.png) no-repeat center / cover;
border-top-right-radius: 60px;
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
padding: 0 100px;
.icon {
background: url(../../assets/common/logo.png) no-repeat 70px center / contain;
width: 300px;
height: 50px;
margin-bottom: 50px;
}
p {
color: #fff;
font-size: 18px;
margin-top: 20px;
width: 300px;
text-align: center;
}
}
.form {
flex: 2;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 50px;
.ant-card {
width: 320px;
border: none;
padding: 0;
}
h3 {
padding-left: 30px;
font-size: 24px;
}
}
}
</style>
具体代码(permission.js)
//做权限控制
import router from '@/router' //可以不写index.js
import useToken from '@/stores/token'
import nprogress from 'nprogress'
import 'nprogress/nprogress.css' //引入进度条样式
const whiteList = ['/login', '/404']
router.beforeEach((to, from, next) => {
nprogress.start()
const { token } = useToken()
if (token) {
// 有token的情况下
if (to.path === '/login') {
// 如果在登录页,就直接跳转到首页
next('/')
} else {
next()
//不在登录页,就直接放行
}
} else {
//没有token的情况下
if (whiteList.includes(to.path)) {
// 如果在白名单给放行
next()
} else {
next('/login')
// 否则重定向回登录页
}
}
})
router.afterEach(() => nprogress.done())