一、想要实现的效果
二、搭建登录静态
1、实现左边背景和右边登录栏的总体布局布局:
<el-row class="content">
<!--el-col 列: -->
<el-col :span="16" :xs="0" class="content-left"></el-col>
<el-col :span="8" :xs="24" class="content-right">
<el-row>
2、账号密码登录和手机号码登录切换使用<el-tabs>组件实现:
3、其他省略
4、全部代码:
<el-row class="content">
<!--el-col 列: -->
<el-col :span="16" :xs="0" class="content-left"></el-col>
<el-col :span="8" :xs="24" class="content-right">
<div class="loginContent">
<div class="loginContentTop">
<div class="header">
<div class="logo">
<img src="../assets/images/logo.png" alt="" class="image" />
</div>
<div class="fontSize">JinPiKa</div>
</div>
<span class="introduce">全球最大的代码托管平台</span>
</div>
<div class="loginContentForm">
<div class="loginMethods">
<el-tabs>
<el-tab-pane
label="账号密码登录"
class="toLogin"
:class="{ option: !option }"
@click="toOption(0)"
>
<!-- loginForm: 表单数据对象-->
<el-form
:model="loginForm"
:rules="loginFormRules"
style="width: 208px"
>
<el-form-item label="" prop="username">
<el-input
:prefix-icon="User"
placeholder="用户名:user"
v-model="loginForm.username"
inline-message
></el-input>
</el-form-item>
<el-form-item label="" prop="password">
<el-input
:prefix-icon="Lock"
placeholder="密码:user"
show-password
v-model="loginForm.password"
inline-message
></el-input>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane
label="手机号码登录"
class="toLogin"
:class="{ option: !option }"
@click="toOption(0)"
>
<!-- loginForm: 表单数据对象-->
<el-form
:model="loginFormPhone"
:rules="loginFormPhoneRules"
style="width: 208px"
prop="phone"
>
<el-form-item label="">
<el-input
:prefix-icon="User"
placeholder="请输入手机号"
v-model="loginFormPhone.phone"
inline-message
></el-input>
</el-form-item>
<el-form-item label="" prop="code">
<el-input
:prefix-icon="Lock"
placeholder="请输入验证码"
v-model="loginFormPhone.code"
inline-message
></el-input>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
</div>
<div class="loginContentButton">
<div class="buttonTop">
<el-checkbox v-model="checked" label="自动登录" size="small" />
<el-link type="primary" :underline="false">
<span style="font-size: 12px">忘记密码</span>
</el-link>
</div>
<el-button type="primary" class="loginButton" @click="tologin">
登录
</el-button>
<el-divider>
<span class="fengexian">其他登录方式</span>
</el-divider>
<div class="svgItems">
<div class="svgItem">
<svg-icon
name="zhifubao"
width="18px"
height="18px"
color="pink"
></svg-icon>
</div>
<div class="svgItem">
<svg-icon
name="taobao"
width="18px"
height="18px"
color="pink"
></svg-icon>
</div>
<div class="svgItem">
<svg-icon
name="weibo"
width="18px"
height="18px"
color="pink"
></svg-icon>
</div>
</div>
</div>
</div>
</el-col>
</el-row>
三、封装接口
1、首先需要对axios进行一个二次封装,实现请求和响应拦截器,在utils文件夹(一般用于存放封装的文件)下创建一个request.ts文件,
import axios from 'axios'
const requeset=axios.create({
baseURL: import.meta.env.BASE_URL, //基础路径
timeout:5000 //发请求超时时间为5s
})
//给request实例添加请求拦截器
request.interceptors.request.use((config)=>{
// config:配置对象:里面有个headers属性请求头,经常给服务器端通过请求头携带公共参数
return config
})
//配置响应拦截器
request.interceptors.response.use(
//成功响应:返回服务端的数据
(response)=>{
return response.data
},
//失败响应:会返回错误对象,用来处理http网络错误
(error)=>{
// 存储网络错误信息
let message = ''
// 根据http状态码判断网络错误
const status = error.response.status
switch (status) {
case 401:
message = '登录已过期,请重新登录'
break
case 403:
message = '没有权限,请联系管理员'
break
case 404:
message = '请求资源不存在'
break
case 500:
message = '服务器内部错误'
break
default:
// eslint-disable-next-line @typescript-eslint/no-unused-vars
message = '网络错误'
break
}
// 提示错误信息
ElMessage({
type: 'error',
message,
})
// 返回一个失败的promise对象
return Promise.reject(error)
}
)
2、引入pinia
(1)在store文件夹下创建pinia仓库,
// 引入 pinia
import { createPinia } from 'pinia'
// 创建大仓库
const pinia = createPinia()
// 对外暴露
export default pinia
(2)在main.ts中,引入仓库并全局使用pinia
// 引入仓库
import pinia from './store'
// 全局使用 pinia
app.use(pinia)
3、在api文件夹下,封装登录接口,用于统一管理用户相关的接口
// 引入封装好的 request
import request from '@/plugins/request'
// 引入用户相关的 ts 类型检测
import { loginForm, loginResponseData } from './type'
//用户相关接口的请求地址
enum API{
//用户登录的请求地址:在接口文档中,去掉默认请求地址baseURL后剩下的部分
LOGIN='/admin/login'
}
//登录接口
export const reqLogin=(data:loginForm)=>{
request.post<any,loginResponseData>(API.LOGIN,data)
}
或者第二种普通封装方式:
// 封装登录相关接口
import { loginForm } from '@/apis/user/type'
import request from '@/utils/request'
export function useLoginAPI(data: loginForm) {
return request({
url: 'http://monitor-spring.jinxinapp.cn/api/v1/admin/login',
method: 'POST',
data,
})
}
3、在store文件夹下创建用户相关的小仓库
// 用户相关的小仓库
import { defineStore } from 'pinia'
//引入登录接口
import {reqLogin} from '@/api/user/index.ts'
const useUserStore=defineStore('user',{
state:()=>{
return{
token:localStorage.getItem('token'),
}
},
actions:{
//用户登录的方法,data是登录时传入的账号密码
async useLogin(data:loginForm){
//登录请求
const result=awiat reqLogin(data)
if(result.code==200){
this.token=result.data.token
localStorage.getItem('token',result.data.token)
return 'ok'
}else{
return Promise.reject(new Error(result.data.message))
}
}
},
getters:{}
})
export default useUserStore
4、在登录页面,点击登录按钮调用tologin方法
const tologin=async ()=>{
try{
//调用仓库里的登录方法,传入的loginForm里面是账号密码
await useStore.userLogin(loginForm)
$router.push('/home') //登录成功跳转首页,
ElNotification({
title: '成功',
message: '登录成功',
type: 'success',
})
}catch(error){
ElNotification({
message: (error as Error).message,
type: 'error',
})
}
}