基于vue-admin-template 后台管理系统
二次开发
ES6, vue, vuex, vue-router, vue-cli, axios, element-ui
// 从码云拉取代码
git clone https://gitee.com/panjiachen/vue-admin-template.git
克隆之后,首先查看项目文件夹,了解各个文件的作用
每个项目文件夹下,有个package.json里的scripts,记录了只有当前文件夹下才能使用的npm run 自定义命令
我们的是dev
npm run dev
注意:① 一定要看好终端要在package.json所在文件夹(项目根目录文件)
② 启动项目的时候注意是否有第三方依赖包(node_modules)
如果没有就npm i 先下载(npm i 的意思是:根据当前命令所在的文件夹下的package.json中记录的包名和版本,帮助我们全部下载到node_mudules内支撑我们整个项目的正常运行)
// 建议不要用 cnpm 安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
启动成功截图
(看一个文件找相关联的文件,不要看的太深,最多看两层)
文件名 | 作用 |
---|---|
main.js | 入口文件,挂载路由,挂载vue-store、全局注册Element、App.vue根组件 |
api 文件 | 将所有的网络请求方法放在 api 目录下统一管理,按照模块来划分对应的文件 |
assets 文件 | 存放项目的静态图片 |
components 文件 | 封装的全局组件,可以等到用的时候再去分析 |
Icons 文件 | 字体图标 |
layout | 是项目登录以后, 见到的布局的框, 左侧导航, 上部导航和下部的内容部分 |
router/index.js | 路由相关的配置, 以及路由规则对象数组 |
store | vuex结构 |
styles | 样式文件 |
utils | 整个项目用到的工具, 封装起来集中管理, 逻辑页面需要的时候进行调用 |
permission.js | 控制路由权限判断、登录和非登录的相关设置 |
settings.js | 封装了全局的一些变量, 方便一键修改 |
将common文件夹的两个文件放到到styles目录下,然后在**index.scss
**中引入该样式
详细步骤:https://blog.csdn.net/Vest_er/article/details/127508844
登录界面实现效果如图
在正式开发业务之前,先将项目的本地端口和网站名称进行一下调整
详细步骤:https://blog.csdn.net/Vest_er/article/details/127518687
<div class="title-container">
<h3 class="title">
<img src="@/assets/common/login-logo.png" alt="">
h3>
div>
如需要在样式表中使用@
别名的时候,需要在@前面加上一个~
符号,否则不识别
/* reset element-ui css */
.login-container {
background-image: url('~@/assets/common/login.jpg'); // 设置背景图片
background-position: center; // 将图片位置设置为充满整个屏幕
}
$light_gray: #68b0fe; // 将输入框颜色改成蓝色
.el-form-item {
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.7); // 输入登录表单的背景色
border-radius: 5px;
color: #454545;
}
.el-form-item__error {
color: #fff
}
.loginBtn {
background: #407ffe;
height: 64px;
line-height: 32px;
font-size: 24px;
}
<div class="tips">
<span style="margin-right:20px;">账号: 13800000002span>
<span> 密码: 123456span>
div>
目标:对登录表单进行规则校验
3个条件缺一不可(loginRules:trigger校验的触发方式 ,validator自定义函数)
字段名对应
将username改为mobile,实际接口中采用的是mobile
的字段,为了更方便的写代码,所以我们将username
改成mobile
校验手机号和校验密码
新规则:手机号必填,并且进行格式校验,密码必填,长度6-16位之间
data() {
const validateMobile = (rule, value, callback) => {
// 校验成功 callback()
validMobile(value) ? callback() : callback(new Error('请输入正确的手机号'))
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('密码长度为6-16位'))
} else {
callback()
}
}
return {
loginForm: {
mobile: '13800000002',
password: '123456'
},
loginRules: {
// trigger校验的触发方式 ,validator自定义函数
mobile: [{ required: true, trigger: 'blur', message: '手机号不能为空' }, { validator: validateMobile, trigger: 'blur' }],
password: [{ required: true, trigger: 'blur', message: '密码长度为6-16位' }, { validator: validatePassword, trigger: 'blur', min: 6, max: 16 }]
},
loading: false,
passwordType: 'password',
redirect: undefined
}
},
我们在utils/validate.js
方法中增加了一个校验手机号的方法
/**
* 校验手机号
* **/
export function validMobile(str) {
return /^1[3-9]\d{9}$/.test(str) // 校验手机号
}
utils/validate.js
是一个专门存放校验工具方法的文件
关于修饰符
@keyup.enter.native
表示监听组件的原生事件,比如 keyup就是于input的原生事件,这里写native表示keyup是一个原生事件
目的:解决浏览器跨域问题
详细讲解:vue脚手架配置代理
devServer: {
Proxy: {
'/api': { // 匹配所有以'/api'开头的请求路径
target: 'http://ihrm-java.itheima.net', // 代理目标的基本路径
changeOrigin: true // 伪装路径
}
},
}
export const login = (data) => request({ url: "/sys/login", method: "POST",data })
vuex详解:Vuex安装使用详解及案例练习(彻底搞懂vuex)
在utils/auth.js
中,基础模板已经为我们提供了获取token
,设置token
,删除token
的方法,可以直接使用
token不能每次都通过登录获取,我们可以将token放置到本地的缓存中
import { getToken, setToken, removeToken } from '@/utils/auth'
// 状态
// 初始化的时候从缓存中读取状态 并赋值到初始化的状态上
// Vuex的持久化 如何实现 ? Vuex和前端缓存相结合
const state = {
token: getToken() // 设置token初始状态 token持久化 => 放到缓存中
}
// 修改状态
const mutations = {
// 设置token
setToken(state, token) {
state.token = token // 设置token 只是修改state的数据 123 =》 1234
// vuex变化 => 缓存数据
setToken(token) // vuex和 缓存数据的同步
},
// 删除缓存
removeToken(state) {
state.token = null // 删除vuex的token
removeToken() // 先清除 vuex 再清除缓存 vuex和 缓存数据的同步
}
}
const state = {
token: getToken()
}
环境变量
在request中设置baseUrl
const service = axios.create({
// 如果执行 npm run dev 值为 /api 正确 /api 这个代理只是给开发环境配置的代理
// 如果执行 npm run build 值为 /prod-api 没关系 运维应该在上线的时候 给你配置上 /prod-api的代理
baseURL: "/api", // 设置axios请求的基础的基础地址
timeout: 5000 // 定义5秒超时
}) // 创建一个axios的实例
处理axios的响应拦截器
// 响应拦截器
service.interceptors.response.use(response => {
// axios默认加了一层data
const { success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
// 业务已经错误了 还能进then ? 不能 ! 应该进catch
Message.error(message) // 提示错误消息
return Promise.reject(new Error(message))
}
}, error => {
Message.error(error.message) // 提示错误信息
return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入 catch
})
引入actions辅助函数
import { mapActions } from 'vuex' // 引入vuex的辅助函数
引入action方法
我们调用的是Vuex中子模块的action,该模块我们进行了namespaced: true,所以引用aciton时需要带上user/
, 并且在使用该方法时,直接使用 this['user/login']
, 使用this.user/login 语法是错误的
methods: {
...mapActions(['user/login'])
}
调用登录
this.$refs.loginForm.validate(async isOK => {
if (isOK) {
try {
this.loading = true
// 只有校验通过了 我们才去调用action
await this['user/login'](this.loginForm)
// 应该登录成功之后
// async标记的函数实际上一个promise对象
// await下面的代码 都是成功执行的代码
this.$router.push('/')
} catch (error) {
console.log(error)
} finally {
// 不论执行try 还是catch 都去关闭转圈
this.loading = false
}
}
})
② 流程图转化代码
src/permission.js
是专门处理路由权限的
// 权限拦截 导航守卫 路由守卫 router
import router from "@/router"; // 引入路由实例
import store from "@/store"; // 引入vuex store实例
import NProgress from "nprogress"; // 引入一份进度条插件
import "nprogress/nprogress.css"; // 引入进度条样式
router.beforeEach((to, from, next) => {
NProgress.start(); // 开启进度条
const whileName = ["/login", "/404"];
if (store.getters.token) {
if (to.path == "/login") {
next("/");
} else {
next();
}
} else {
if (whileName.indexOf(to.path) > -1) {
next();
} else {
next();
}
}
NProgress.done();
});
router.afterEach(function () {
NProgress.done(); // 关闭进度条
});
① 主页布局架构
② 最终效果
① 获取用户资料接口
// 获取信息
export const getInfo = (data) => {
request({ url: "/sys/profile", method: "POST", data });
};
② 统一注入token`src/utils/request.js
service.interceptors.request.use(config => {
// 在这个位置需要统一的去注入token
if (store.getters.token) {
// 如果token存在 注入token
config.headers['Authorization'] = `Bearer ${store.getters.token}`
}
return config // 必须返回配置
}, error => {
return Promise.reject(error)
})
目标: 在用户的vuex模块中封装获取用户资料的action,并设置相关状态
userInfo为什么我们不设置为null,而是设置为 {}
因为我们会在**getters
**中引用userinfo的变量,如果设置为null,则会引起异常和报错
① 权限拦截器调用action
用户资料有个硬性要求,**
必须有token
**才可以获取,那么我们就可以在确定有token的位置去获取用户资料
② 获取头像接口合并数据