Src/network/request.js
import axios from 'axios'
export let request = (config) => {
//创建axios实例
let instance = axios.create({})
return instance(config)
}
src/api/login.js
import {request} from '../network/request'
function loginByUsername(username, password) {
let data = {
username,
password
}
return request({
url: "https://elm.cangdu.org/v2/login",
method: "post",
data//这就是向服务器发送了用户填写的数据
})
//axios是promise对象,返回的是服务器返回的东西
}
export { loginByUsername }
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import {loginByUsername} from '../api/login'
let store = new Vuex.Store({
state:{
token:""
},
mutations:{
Set_Token(state,token){
state.token=token
}
},
actions:{
LoginByUsername({commit},userInfo){
//userInfo,就是用户传来的用户名+密码信息
let username=userInfo.username.trim()
return new Promise((resolve,reject)=>{
loginByUsername(username,userInfo.password).then(response=>{
//response 是服务器发回来的数据
//我们使用的是里面的data数据
let data=response.data
commit('Set_Token',data.token)
//我感觉用cookie或者storage都可以啊 做一个本地储存很重要
window.localStorage.setItem('token',data.token)
resolve()
}).catch(err=>{
reject(err)
})
})
}
}
})
export default store
Login.vue
<template>
<div>
<el-form
:model="ruleForm"
:rules="rules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="用户名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="ruleForm.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "Login",
data() {
return {
loading:false,
ruleForm: {
username: "",
password: ""
},
rules: {
name: [
{ required: true, message: "请输入用户名", trigger: "blur" },
],
password:[
{ required: true, message: "请输入密码", trigger: "blur" },
]
}
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
//把用户填写的用户名+密码发送过去
this.$store.dispatch('LoginByUsername',this.ruleForm).then(()=>{
this.$router.push('/home')
}).catch(()=>{
this.loading=false
console.log(123);
})
} else {
console.log("error submit!!");
return false;
}
});
}
}
};
</script>
<style scoped>
</style>
每个用户可以访问的路由是不一样的,有路由权限
当我们获取服务器发过来的token值后,我们再利用这个token值向服务器发送请求,获取该用户的role信息,再根据role信息,知道该用户可以访问哪些路由
使用全局守卫,在进入下一个路由之前,如果还没有获取用户的role信息,就先获取role信息
router/index.js
router.beforeEach((to, from, next) => {
//用户已经登录,获取了token信息,但是用户还没有获取路由信息的话
//利用token发送请求,获取可以访问的路由信息
if (store.state.token) {
if (store.state.roles.length === 0) {
store.dispatch('getInfo', store.state.token).then(() => {
next()
})
}
}else{
next()
}
})
Store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import loadByUsername from '../api/login'
import {request} from '../network/request'
Vue.use(Vuex)
let store = new Vuex.Store({
state:{
token:"",
//用户获取用户的可以访问的路由信息
roles: []
},
mutations:{
setToken(state,token){
state.token=token
},
setRoles(state,roles){
state.roles=roles
}
},
actions:{
LoadByUsername({commit},userInfo){
return new Promise((resolve,reject)=>{
let username=userInfo.username.trim()
loadByUsername(username,userInfo.password).then(data=>{
let dataFromEnd=data.data
//服务器返回一个token
commit('setToken',dataFromEnd.message)
window.localStorage.setItem('token',dataFromEnd.message)
resolve()
}).catch(err=>reject(err))
})
},
getInfo({commit},token){
return new Promise((resolve,reject)=>{
request({
url: "https://elm.cangdu.org/v2/login",
method:"post",
token
}).then(response=>{
commit('setRoles',response.data.roles)
resolve()
}).catch(err=>reject(err))
})
}
}
})
export default store
https://juejin.im/post/591aa14f570c35006961acac
使用了mock
自己写得:
Router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import store from '../store'
let Login = () => import('@/components/Login')
let Home = () => import('@/components/Home')
let SystemHome = () => import('@/components/SystemHome')
let BasicTable = () => import('@/components/BasicTable')
let Tab = () => import('@/components/Tab')
let RelevantInput = () => import('@/components/RelevantInput')
let BasicInput = () => import('@/components/BasicInput')
let ThirdMenu = () => import('@/components/ThirdMenu')
let Editor = () => import('../components/Editor/Editor.vue')
let MarkDown = () => import('@/components/MarkDown')
let Echart = () => import('@/components/Echart')
let Drag = () => import('@/components/Drag')
let DragTable = () => import('@/components/DragTable')
let DragBox = () => import('@/components/DragBox')
let Language = () => import('@/components/Language')
let ChangeColor = () => import('@/components/ChangeColor')
let Lint = () => import('@/components/Lint')
let Icon = () => import('@/components/Icon')
Vue.use(Router)
let constantRouterMap = [
{
path: "",
redirect: "/login"
},
{
path: "/login",
name: "Login",
component: Login
},
]
let router = new Router({
mode: "history",
routes: constantRouterMap
})
let asyncRouterMap = [
{
path: "/home",
name: "Home",
component: Home,
meta: {
role: ['admin', 'editor'],
icon: "el-icon-delete",
title:"后台管理系统"
},
children: [
{
path: "/home",
name: "SystemHome",
component: SystemHome,
meta: {
role: ['admin', 'editor'],
icon: "el-icon-s-home",
title: "系统首页"
}
},
{
path: "/icon",
name: "Icon",
component: Icon,
meta: {
role: ['admin', 'editor'],
icon: "el-icon-view",
title: "Icon图标"
}
},
{
path: "/tab",
name: "Tab",
component: Tab,
meta: {
role: ['admin', 'editor'], icon: "el-icon-s-order",
title: "Tab选项卡"
},
},
{
//大家都可以进入用户界面,只是admin和edtior的导航会不一样
path: "/input",
name: "RelevantInput",
component: RelevantInput,
meta: {
role: ['admin', 'editor'], icon: "el-icon-tickets",
title: "表单相关"
},
children: [
{
path: "/basicinput",
name: "BasicInput",
component: BasicInput,
meta: {
role: ['admin', 'editor'],
title: "基本表单"
},
},
{
path: "/thirdmenu",
name: 'ThirdMenu',
component: ThirdMenu,
meta: {
role: ['admin', 'editor'],
title: "三级菜单"
},
children: [
{
path: "/editor",
name: "Editor",
component: Editor,
meta: {
role: ['admin', 'editor'], icon: "",
title: "富文本编辑器"
},
},
{
path: "/markdown",
name: "MarkDown",
component: MarkDown,
meta: {
role: ['admin', 'editor'], icon: "",
title: "Mark Down编辑器"
},
}
]
}
]
},
{
path: "/echart",
name: "Echart",
component: Echart,
meta: {
role: ['admin'], icon: "el-icon-pie-chart",
title: "Echart图表"
},
},
{
path: "/drag",
name: "Drag",
component: Drag,
meta: {
role: ['admin', 'editor'], icon: "el-icon-s-data",
title: "表格展示"
},
children: [
{
path: "/basictable",
name: "BasicTable",
component: BasicTable,
meta: {
role: ['admin', 'editor'],
icon: "el-icon-menu",
title: "基本表格"
}
},
{
path: "/DragTable",
name: "DragTable",
component: DragTable,
meta: {
role: ['admin', 'editor'], icon: "",
title: "拖拽表格"
},
},
{
path: "/dragbox",
name: "DragBox",
component: DragBox,
meta: {
role: ['admin', 'editor'], icon: "",
title: "动态表格"
},
},
]
},
{
path: "/language",
name: "Language",
component: Language,
meta: {
role: ['admin', 'editor'], icon: "el-icon-coordinate",
title: "国际化功能"
},
},
{
path: "/changecolor",
name: "ChangeColor",
component: ChangeColor,
meta: {
role: ['admin', 'editor'], icon: "el-icon-orange",
title: "个性换肤"
},
},
{
path: "/lint",
name: "Lint",
component: Lint,
meta: {
role: ['admin'], icon: "el-icon-s-custom",
title: "权限测试"
},
}
]
},
];
router.beforeEach((to, from, next) => {
//结合本地 储存账户信息
if(window.sessionStorage.getItem('token')){
store.commit('setToken',window.sessionStorage.getItem('token'))
}
if (store.state.token) { // 判断是否有token
if (to.path === '/login') {
next({ path: '/home' });
} else {
if(store.state.roles.length===0){
store.dispatch('getRole', store.state.token).then(res => { // 拉取info
const role = res;//admin/editor
store.dispatch('GenerateRoutes', role).then(() => { // 生成可访问的路由表
router.addRoutes(store.state.addRouters) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
}).catch(err => {
console.log(err);
});
}else{
next()
}
}
} else {
//最后这么写
if (to.path === '/login') {
next()
} else {
next('/login'); // 否则全部重定向到登录页
}
}
});
export { router, asyncRouterMap, constantRouterMap }
Store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from '../network'
import { router, asyncRouterMap, constantRouterMap } from '../router'
Vue.use(Vuex)
function hasPermission(roles, route) {
if (route.meta && route.meta.role) {
return roles.some(role => route.meta.role.indexOf(role) >= 0)
} else {
return true
}
}
let store = new Vuex.Store({
state: {
bgcolor:"rgba(119, 152, 187, 0.66)",
token: "",
roles: [],
routers: constantRouterMap,
addRouters: [],
messageBadge:true
},
getters:{
changeSrc(state) {
if (state.roles[0] === "admin") {
return "https://tvax4.sinaimg.cn/crop.0.0.996.996.180/0074HXD9ly8gaoj4s7bm8j30ro0roac8.jpg?KID=imgbed,tva&Expires=1578838255&ssig=HU9QjO0%2BIJ";
}
if (state.roles[0] === "editor") {
return "https://wx2.sinaimg.cn/mw1024/0074HXD9gy1gadxbg0q2zj30460463yd.jpg";
}
}
},
mutations: {
changeBgcolor(state,color){
state.bgcolor=color
},
changeMessageBadge(state,boo){
state.messageBadge=boo
},
setToken(state, token) {
state.token = token
},
setRole(state, role) {
state.roles.pop()
state.roles.push(role)
},
backRole(state, role) {
state.roles=[]
},
backRouters(state) {
state.routers=constantRouterMap
},
changeRole(state, role) {
state.roles.pop()
state.roles.push(role)
},
SET_ROUTERS: (state, routers) => {
state.addRouters = routers;
state.routers = constantRouterMap.concat(routers);
}
},
actions: {
LoadByUsername({ commit }, userForm) {
return new Promise((resolve, reject) => {
let username = userForm.username.trim()
let password = userForm.password
let data = {
username, password
}
axios({
//因为接口不能判断用户名,所以我创建了两个接口
url: '/news/gettoken',
method: "post",
data
}).then(response => {
let res = response.data.data
commit('setToken', res.token)
window.sessionStorage.setItem('token', res.token)
router.push('/home')
resolve()
}).catch(err => reject(err))
})
},
getRole(context,tok) {
//把独一无二的token信息打出去
return new Promise((resolve, reject) => {
if(tok==='adminToken'){
axios({
//尽管这里是发送了token信息,可是不知道为什么在mock中,token值为null,不能进行判断,所以我直接在这里进行判断
//Yinwei返回的都是false
url:"/news/adminrole",
method: "get",
}).then(response => {
let role = response.data.data.role
context.commit('setRole', role)
resolve(role)
// console.log(role)
}).catch(err => reject(err))
} else if (tok === 'editorToken'){
axios({
//尽管这里是发送了token信息,可是不知道为什么在mock中,token值为null,不能进行判断,所以我直接在这里进行判断
//Yinwei返回的都是false
url:"/news/editorrole",
method: "get",
}).then(response => {
let role = response.data.data.role
context.commit('setRole', role)
resolve(role)
// console.log(role)
}).catch(err => reject(err))
}
})
},
GenerateRoutes({ commit }, data) {
commit('setRole', data)
return new Promise(resolve => {
const roles = []
roles.push(data)//roles=['admin']/['editor']
const accessedRouters = asyncRouterMap.filter(v => {
if (roles.indexOf('admin') >= 0) return true;
if (hasPermission(roles, v)) {
if (v.children && v.children.length > 0) {
v.children = v.children.filter(child => {
if (hasPermission(roles, child)) {
return child
}
return false;
});
return v
} else {
return v
}
}
return false;
});
commit('SET_ROUTERS', accessedRouters);
resolve();
})
}
},
})
export default store
假如退出当前账户:
this.$store.commit("setToken", null);
window.sessionStorage.clear()
this.$store.commit("backRole");
this.$store.commit("backRouters");
this.$router.push("/login");
mock和axios自然连接,要在axios中引入mock
感觉只要写好mock就可以了啊
Mock/index.js
import Mock from 'mockjs'
Mock.mock('/news/gettoken', "post", function (options) {
let obj = JSON.parse(options.body)//from
if (obj.username === 'admin') {
return {
data: {
token: "adminToken"
}
}
} else {
return {
data: {
token: "editorToken"
}
}
}
})
Mock.mock('/news/adminrole', 'post', function (options) {
return {
data: {
role: "admin"
}
}
})
Mock.mock('/news/editorrole', 'post', function (options) {
return {
data: {
role: "editor"
}
}
})
export default Mock
Axios/index.js
import axios from 'axios'
import Mock from '../mock'
// axios.defaults.baseURL ='http://localhost:8080'
export default axios
导航栏,使用了三级菜单
<template>
<div>
<el-container style="border:1px solid black">
<el-aside width="200px">
<el-menu :collapse="collapse" background-color="#eeefef" text-color="#666" active-text-color="#20a0ff" unique-opened router @select="addTab">
<!-- 一级菜单 -->
<template v-for="item in showRouters" >
<el-submenu v-if="item.children&&item.children.length" :index="item.path" :key="item.path">
<template slot="title"><span>{{item.name}}</span></template>
<!-- 二级菜单 -->
<template v-for="itemChild in item.children">
<el-submenu v-if="itemChild.children&&itemChild.children.length" :index="itemChild.path" :key="itemChild.path" >
<template slot="title"><span>{{itemChild.name}}</span></template>
<!-- 三级菜单 -->
<el-menu-item v-for="itemChild_Child in itemChild.children" :index="itemChild_Child.path" :key="itemChild_Child.path">
<span slot="title">{{itemChild_Child.name}}</span>
</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="itemChild.path" :key="itemChild.path"><span slot="title">{{itemChild.name}}</span></el-menu-item>
</template>
</el-submenu>
<el-menu-item v-else :index="item.path" :key="item.path"><span slot="title">{{item.name}}</span></el-menu-item>
</template>
</el-menu>
</el-aside>
<el-main>
<router-link to="/cart">购物车</router-link>
<router-view />
</el-main>
</el-container>
</div>
</template>
<script>
export default {
name: "Home",
methods: {
moreBtn() {
this.$router.push("/more");
}
},
computed: {
showRouters() {
let homeRoutes = this.$store.state.routers.filter(
r => r.path === "/home"
)[0].children;
console.log(homeRoutes);
return homeRoutes.filter(route => {
if (!route.path) {
return false;
} else if (route.path === "/login") {
return false;
} else {
return true;
}
});
return homeRoutes;
}
},
mounted() {
window.vue = this;
},
};
</script>
点击check,cell可以添加样式
有删除和编辑功能
<el-table
:data="tableData"
style="width: 100%"
@selection-change="handleSelectionChange"
:cell-style="addTextDecoration" fit
>
<el-table-column type="selection" label='打卡'></el-table-column>
<el-table-column prop="project" label='事项名称'>
<template slot-scope="scope">
<div v-if="show&&scope.$index==i">
<el-input v-model="scope.row.project"></el-input>
</div>
<div v-else>
<span>{{scope.row.project}}</span>
</div>
</template>
</el-table-column>
<el-table-column align='right'>
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index)">
<span v-if="show&&scope.$index==i">确定</span>
<span v-else>编辑</span>
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
data() {
return {
tableData: [
{
id: 0,
project: "背50个单词背50个单词背50个单词"
},
{
id: 1,
project: "三篇阅读三篇阅读三篇阅读"
},
{
id: 2,
project: "两张试卷两张试卷两张试卷"
},
{
id: 3,
project: "vue练习vue练习vue练习"
},
{
id: 4,
project: "后台管理系统项目后台管理系统项目"
}
],
i: -1,
multipleSelection: [],
show: true
};
},
methods: {
handleSelectionChange(rere) {
let arr = [];
rere.forEach((val, index) => {
this.tableData.forEach((v, i) => {
if (val.id == v.id) {
arr.push(i);
}
});
});
this.multipleSelection = arr;
},
handleDelete(index, row) {
console.log(row);
this.tableData.splice(index, 1);
},
handleEdit(index) {
console.log(index);
this.i = index;
this.show = !this.show;
},
// hehe({row, column, rowIndex, columnIndex}){
// if(this.checkedId.indexOf(rowIndex)){return 'text-decoration:line-through'}
// },
addTextDecoration({ row, rowIndex }) {
let arr = this.multipleSelection;
for (let i = 0; i < arr.length; i++) {
if (rowIndex === arr[i]) {
return "text-decoration:line-through";
}
}
},
addproject() {
let thisid = this.tableData[this.tableData.length - 1].id;
let obj = {
id: thisid + 1,
project: ""
};
this.tableData.push(obj);
}
},
container中
左边aside右边main
aside是导航栏
我们可以设置整个container的高度是window的innerheight,
main设置overflow-y:scroll
(另外这里通过mock,axios获得数据)
<template>
<div>
<el-table :data="tableData" fit>
<el-table-column prop="ID" label="ID"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="price" label="账户余额"></el-table-column>
<el-table-column label="头像">
<template slot-scope="scope">
<img :src="scope.row.image" style="width:50px;height:50px" @click="imageClick(scope.row)" />
</template>
</el-table-column>
<el-table-column prop="location" label="地址"></el-table-column>
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
<el-button
size="mini"
plain
:type="(scope.row.status==='成功')?'success':'warning'"
>{{scope.row.status}}</el-button>
</template>
</el-table-column>
<el-table-column prop="date" label="注册日期"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<div style="display:flex;flex-direction:row">
<el-button type="primary" @click="editData(scope.row,scope.$index)">编辑</el-button>
<el-button type="danger" @click="deleteData(scope.$index)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialogTableVisible" style="padding:0;">
<img :src="showImage" alt />
</el-dialog>
<el-dialog title="编辑信息" :visible.sync="editBox">
<el-form :model="form">
<el-form-item label="ID">
<el-input v-model.lazy="form.ID" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="账户余额">
<el-input v-model="form.price" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="头像">
<el-input v-model="form.image" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-input v-model="form.status" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="注册日期">
<el-input v-model="form.date" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editBox = false">取 消</el-button>
<el-button type="primary" @click="handleUpdate('form')">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import axios from "../network";
export default {
name: "BasicTable",
data() {
return {
tableData: [],
dialogTableVisible: false,
showImage: "",
editBox: false,
form: {
ID: "3",
name: "dsd",
image: "ssaa",
date: "dssd",
status: "sas",
price: "g"
},
i:0
};
},
methods: {
imageClick(row, index) {
this.dialogTableVisible = true;
this.showImage = row.image;
},
deleteData(index) {
this.tableData.splice(index, 1);
},
editData(row, index) {
this.editBox = true;
this.i=index//关键
//表格展示row的内容,同时在表单改写的内容还是储存到this.form
this.form=Object.assign({},row)
},
handleUpdate(forName) {
//对tableData进行修改,页面上的内容自然修改
this.tableData.splice(this.i,1,this.form)
this.editBox = false;
}
},
created() {
axios.get("/news/gettable").then(res => {
this.tableData = res.data.data.tableData;
});
}
};
</script>
<style scoped>
</style>