Browse Source

侧边栏代码重构

master
刘力 3 years ago
parent
commit
ba4aefdaa1
  1. 5
      .editorconfig
  2. 25
      src/api/system/menu.js
  3. 117
      src/layout/index.vue
  4. 10
      src/main.js
  5. 26
      src/router/index.js
  6. 49
      src/router/routers.js
  7. 5
      src/store/index.js
  8. 8
      src/store/modules/api.js
  9. 82
      src/store/modules/permission.js
  10. 6
      src/utils/permission.js
  11. 16
      src/utils/request.js
  12. 8
      src/views/login.vue

5
.editorconfig

@ -1,3 +1,4 @@
# https://editorconfig.org
root = true root = true
[*] [*]
@ -7,3 +8,7 @@ indent_size = 2
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

25
src/api/system/menu.js

@ -1,13 +1,11 @@
import request from '@/utils/request'
import request from '@/utils/request';
//根据pid 获取菜单 //根据pid 获取菜单
export function getMenusTree(pid) { export function getMenusTree(pid) {
return request({ return request({
url: 'api/menus/lazy?pid=' + pid, url: 'api/menus/lazy?pid=' + pid,
method: 'get' method: 'get'
})
});
} }
export function getMenus(params) { export function getMenus(params) {
@ -15,17 +13,17 @@ export function getMenus(params) {
url: 'api/menus', url: 'api/menus',
method: 'get', method: 'get',
params params
})
});
} }
//根据id获取上级菜单 //根据id获取上级菜单
export function getMenuSuperior(ids) { export function getMenuSuperior(ids) {
const data = ids.length || ids.length === 0 ? ids : Array.of(ids)
const data = ids.length || ids.length === 0 ? ids : Array.of(ids);
return request({ return request({
url: 'api/menus/superior', url: 'api/menus/superior',
method: 'post', method: 'post',
data data
})
});
} }
//获取子菜单 //获取子菜单
@ -33,7 +31,7 @@ export function getChild(id) {
return request({ return request({
url: 'api/menus/child?id=' + id, url: 'api/menus/child?id=' + id,
method: 'get' method: 'get'
})
});
} }
//构建菜单 //构建菜单
@ -42,7 +40,7 @@ export function bulidMenus() {
url: 'api/menus', url: 'api/menus',
method: 'post', method: 'post',
data data
})
});
} }
//新增菜单 //新增菜单
@ -51,7 +49,7 @@ export function add(data) {
url: 'api/menus', url: 'api/menus',
method: 'post', method: 'post',
data data
})
});
} }
//删除菜单 //删除菜单
@ -60,7 +58,7 @@ export function del(ids) {
url: 'api/menus', url: 'api/menus',
method: 'delete', method: 'delete',
data: ids data: ids
})
});
} }
//修改菜单 //修改菜单
@ -69,10 +67,9 @@ export function edit(data) {
url: 'api/menus', url: 'api/menus',
method: 'put', method: 'put',
data data
})
});
} }
export default { export default {
add, add,
edit, edit,
@ -82,4 +79,4 @@ export default {
getMenuSuperior, getMenuSuperior,
getChild, getChild,
getMenusTree getMenusTree
}
};

117
src/layout/index.vue

@ -0,0 +1,117 @@
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
<right-panel v-if="showSettings">
<settings />
</right-panel>
</div>
<!-- 防止刷新后主题丢失 -->
<Theme v-show="false" ref="theme" />
</div>
</template>
<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import Theme from '@/components/ThemePicker'
import Cookies from 'js-cookie'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
RightPanel,
Settings,
Sidebar,
TagsView,
Theme
},
mixins: [ResizeMixin],
computed: {
...mapState({
sidebar: state => state.app.sidebar,
device: state => state.app.device,
showSettings: state => state.settings.showSettings,
needTagsView: state => state.settings.tagsView,
fixedHeader: state => state.settings.fixedHeader
}),
classObj () {
return {
hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
}
},
mounted () {
if (Cookies.get('theme')) {
this.$refs.theme.theme = Cookies.get('theme')
this.$store.dispatch('settings/changeSetting', {
key: 'theme',
value: Cookies.get('theme')
})
}
},
methods: {
handleClickOutside () {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
}
}
</script>
<style lang="scss" scoped>
@import '~@/assets/styles/mixin.scss';
@import '~@/assets/styles/variables.scss';
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
padding: 0;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px);
}
.mobile .fixed-header {
width: 100%;
}
</style>

10
src/main.js

@ -12,14 +12,12 @@ import 'element-ui/lib/theme-chalk/index.css'
// 代码高亮 // 代码高亮
import VueHighlightJS from 'vue-highlightjs' import VueHighlightJS from 'vue-highlightjs'
import 'highlight.js/styles/atom-one-dark.css' import 'highlight.js/styles/atom-one-dark.css'
// 加载路由
import './router/routers'
// 加载权限控制
import './router/index'
//加载权限指令 //加载权限指令
import checkPer from '@/utils/permission' import checkPer from '@/utils/permission'
//import permission from './components/Permission'
import permission from './components/Permission'
// 加载代码高亮 // 加载代码高亮
Vue.use(VueHighlightJS) Vue.use(VueHighlightJS)
@ -30,7 +28,7 @@ Vue.use(ElementUI,{
}) })
//加载权限指令 //加载权限指令
Vue.use(checkPer) Vue.use(checkPer)
Vue.use(permission)
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({

26
src/router/index.js

@ -4,17 +4,9 @@ import Config from '@/settings'
//导入进度条 //导入进度条
import NProgress from 'nprogress' import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import {
getToken
} from '@/utils/auth'
import {
filterAsyncRouter
} from '@/store/modules/permission'
import {
buildMenus
} from '@/api/system/menu'
import { getToken } from '@/utils/auth'
import { filterAsyncRouter } from '@/store/modules/permission'
import { buildMenus } from '@/api/system/menu'
NProgress.configure({ NProgress.configure({
showSpinner: false showSpinner: false
@ -42,19 +34,24 @@ router.beforeEach((to, from, next) => {
}) })
NProgress.done() NProgress.done()
} else { } else {
//判断当前用户是否拉取用户信息
//保存在store 中路由不为空则放行,判断用户是否拉取用户信息
if (store.getters.roles.length === 0) { if (store.getters.roles.length === 0) {
//拉取user_info //拉取user_info
store.dispatch('GetInfo').then(() => {
store
.dispatch('GetInfo')
.then(() => {
//加载动态路由,拉取菜单 //加载动态路由,拉取菜单
loadMenus(next, to) loadMenus(next, to)
}).catch(() => {
})
.catch(() => {
store.dispatch('LogOut').then(() => { store.dispatch('LogOut').then(() => {
//重新实例化路由对象 避免bug //重新实例化路由对象 避免bug
location.reload() location.reload()
}) })
}) })
//登录时未拉取菜单,在此拉取
} else if (store.getters.loadMenus) { } else if (store.getters.loadMenus) {
//防止死循环
store.dispatch('updateLoadMenus') store.dispatch('updateLoadMenus')
loadMenus(next, to) loadMenus(next, to)
} else { } else {
@ -76,7 +73,6 @@ router.beforeEach((to, from, next) => {
}) })
export const loadMenus = (next, to) => { export const loadMenus = (next, to) => {
buildMenus().then(res => { buildMenus().then(res => {
const sdata = JSON.parse(JSON.stringify(res)) const sdata = JSON.parse(JSON.stringify(res))
const rdata = JSON.parse(JSON.stringify(res)) const rdata = JSON.parse(JSON.stringify(res))

49
src/router/routers.js

@ -1,28 +1,59 @@
import Vue from 'vue' import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
import Config from '@/settings'
import Layout from '../layout/index'
//加载路由 //加载路由
Vue.use(Router) Vue.use(Router)
//路由映射 //路由映射
export const constantRouterMap = [ export const constantRouterMap = [
{ {
//路径 //路径
path: '/login', path: '/login',
//路由过渡信息,此处使用面包屑功能或判断用户是否登录 //路由过渡信息,此处使用面包屑功能或判断用户是否登录
meta: {
title: '登录',
noCache: true
},
meta: { title: '登录', noCache: true },
//加载组件 //加载组件
component: (resolve) => require(['@/views/login'], resolve), component: (resolve) => require(['@/views/login'], resolve),
//是否展示该理由
//是否展示该路由
hidden: true
},
{
path: '/404',
component: (resolve) => require(['@/views/features/404'], resolve),
hidden: true hidden: true
},
{
path: '/401',
component: (resolve) => require(['@/view/features/401'], resolve),
hidden: true
},
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path*',
component: (resolve) => require(['@/views/features/redirect'], resolve),
name: 'Dashboard',
meta: { title: '首页', icon: 'index', affix: true, noCache: true }
}
]
},
{
path: '/user',
component: Layout,
hidden: true,
redirect: 'noredirect',
children: [
{
path: 'center',
component: (resolve) => require(['@/views/system/user/center'], resolve),
name: '个人中心',
meta: { title: '个人中心' }
}
]
} }
] ]
export default new Router({ export default new Router({

5
src/store/index.js

@ -1,4 +1,4 @@
import Vue from "vue"
import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import getters from './getters' import getters from './getters'
@ -7,9 +7,7 @@ Vue.use(Vuex)
//实现自动导入模块 //实现自动导入模块
const modulesFiles = require.context('./modules', true, /\.js$/) const modulesFiles = require.context('./modules', true, /\.js$/)
const modules = modulesFiles.keys().reduce((modules, modulePath) => { const modules = modulesFiles.keys().reduce((modules, modulePath) => {
//获取上级目录modules的 所有后缀名为 .js的文件 //获取上级目录modules的 所有后缀名为 .js的文件
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath) const value = modulesFiles(modulePath)
@ -17,7 +15,6 @@ const modules = modulesFiles.keys().reduce((modules, modulePath) => {
return modules return modules
}, {}) }, {})
const store = new Vuex.Store({ const store = new Vuex.Store({
modules, modules,
getters getters

8
src/store/modules/api.js

@ -1,10 +1,10 @@
//适配Nginx反向代理 //适配Nginx反向代理
const baseUrl = process.env.VUE_APP_BASE_API === '/' ? '' : process.env.VUE_APP_BASE_API
const baseUrl =
process.env.VUE_APP_BASE_API === '/' ? '' : process.env.VUE_APP_BASE_API;
//适配API路径 //适配API路径
const api = { const api = {
state: { state: {
//部署包上传 //部署包上传
//deployUploadApi: baseUrl + '/api/deploy/upload', //deployUploadApi: baseUrl + '/api/deploy/upload',
@ -23,6 +23,6 @@ const api = {
//基础url //基础url
baseApi: baseUrl baseApi: baseUrl
} }
}
};
export default api
export default api;

82
src/store/modules/permission.js

@ -1,6 +1,6 @@
import { constantRouterMap } from "@/router/routers";
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'
import { constantRouterMap } from '@/router/routers';
import Layout from '@/layout/index';
import ParentView from '@/components/ParentView';
const permission = { const permission = {
//存放状态 //存放状态
@ -12,75 +12,77 @@ const permission = {
//同步更改状态 //同步更改状态
mutations: { mutations: {
SET_ROUTERS: (state, routers) => { SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRouterMap.concat(routers)
state.addRouters = routers;
state.routers = constantRouterMap.concat(routers);
}, },
SET_SIDEBAR_ROUTERS: (state, routers) => { SET_SIDEBAR_ROUTERS: (state, routers) => {
state.sidebarRouters = constantRouterMap.concat(routers)
state.sidebarRouters = constantRouterMap.concat(routers);
} }
}, },
//发送异步请求拿到数据 //发送异步请求拿到数据
actions: { actions: {
GenerateRoutes({
commit
}, asyncRouter) {
commit('SET_ROUTERS', asyncRouter)
GenerateRoutes({ commit }, asyncRouter) {
commit('SET_ROUTERS', asyncRouter);
}, },
SetSidebarRouters({
commit
}, sidebarRouter) {
commit('SET_SIDEBAR_ROUTERS', sidebarRouter)
SetSidebarRouters({ commit }, sidebarRouter) {
commit('SET_SIDEBAR_ROUTERS', sidebarRouter);
} }
} }
}
};
//遍历后台传来的路由字符串,转换为组件对象 //遍历后台传来的路由字符串,转换为组件对象
export const filterAsyncRouter = (routers, isRewrite = false) => { export const filterAsyncRouter = (routers, isRewrite = false) => {
return routers.filter(router => { return routers.filter(router => {
if (isRewrite && router.children) { if (isRewrite && router.children) {
router.children = filterChildren(router.children)
router.children = filterChildren(router.children);
} }
if (router.component) { if (router.component) {
if (router.component === 'Layout') { // Layout组件特殊处理
router.component = Layout
if (router.component === 'Layout') {
// Layout组件特殊处理
router.component = Layout;
} else if (router.component === 'ParentView') { } else if (router.component === 'ParentView') {
router.component = ParentView
router.component = ParentView;
} else { } else {
const component = router.component
router.component = loadView(component)
const component = router.component;
router.component = loadView(component);
} }
} }
if (router.children && router.children.length) { if (router.children && router.children.length) {
router.children = filterAsyncRouter(router.children, router, isRewrite)
}
return true
})
router.children = filterAsyncRouter(
router.children,
router,
isRewrite
);
} }
return true;
});
};
function filterChildren(childrenMap) { function filterChildren(childrenMap) {
var children = []
var children = [];
childrenMap.forEach((el, index) => { childrenMap.forEach((el, index) => {
if (el.children && el.children.length) { if (el.children && el.children.length) {
if (el.component === 'ParentView') { if (el.component === 'ParentView') {
el.children.forEach(c => { el.children.forEach(c => {
c.path = el.path + '/' + c.path
c.path = el.path + '/' + c.path;
if (c.children && c.children.length) { if (c.children && c.children.length) {
children = children.concat(filterChildren(c.children, c))
return
children = children.concat(
filterChildren(c.children, c)
);
return;
} }
children.push(c)
})
return
children.push(c);
});
return;
} }
} }
children = children.concat(el)
})
return children
children = children.concat(el);
});
return children;
} }
export const loadView = (view) => {
return (resolve) => require([`@/views/${view}`], resolve)
}
export const loadView = view => {
return resolve => require([`@/views/${view}`], resolve);
};
export default permission
export default permission;

6
src/utils/permission.js

@ -3,7 +3,7 @@ import store from '@/store' //引入状态管理组件
export default { export default {
install(Vue) { install(Vue) {
// 添加属性 // 添加属性
Vue.prototype.checkPer=(value)=>{
Vue.prototype.checkPer = value => {
// 判断是否为数组对象且长度小于0 // 判断是否为数组对象且长度小于0
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const roles = store.getters && store.getters.roles const roles = store.getters && store.getters.roles
@ -22,7 +22,9 @@ export default {
// 否则返回错误 // 否则返回错误
} else { } else {
//需要角色拥有admin editor 权限 //需要角色拥有admin editor 权限
console.error(`need roles! Like v-permission="['admin','editor']"`)
console.error(
`need roles! Like v-permission="['admin','editor']"`
)
return false return false
} }
} }

16
src/utils/request.js

@ -1,21 +1,22 @@
import axios from "axios"
import axios from 'axios'
import router from '@/router/routers' import router from '@/router/routers'
import { Notification } from 'element-ui' //elementUI 提示框组件 import { Notification } from 'element-ui' //elementUI 提示框组件
import store from '../store' import store from '../store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import Config from '@/settings' import Config from '@/settings'
import Cookies from "js-cookie"
import Cookies from 'js-cookie'
//二次封装axios,创建axios 实例 //二次封装axios,创建axios 实例
const service = axios.create({ const service = axios.create({
//api 的 base_url在.env.development有配置 //api 的 base_url在.env.development有配置
baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/',
baseURL:
process.env.NODE_ENV === 'production'
? process.env.VUE_APP_BASE_API
: '/',
//请求超时时间 //请求超时时间
timeout: Config.timeout timeout: Config.timeout
}) })
//添加请求拦截器 //添加请求拦截器
service.interceptors.request.use( service.interceptors.request.use(
// 在发送请求之前做些什么 // 在发送请求之前做些什么
@ -45,7 +46,10 @@ service.interceptors.response.use(
//响应错误处理 //响应错误处理
error => { error => {
//兼容blob下载出错json提示 //兼容blob下载出错json提示
if (error.response.data instanceof Blob && error.response.data.type.toLowerCase().indexOf('json') !== -1) {
if (
error.response.data instanceof Blob &&
error.response.data.type.toLowerCase().indexOf('json') !== -1
) {
//创建文件读取对象 //创建文件读取对象
const reader = new FileReader() const reader = new FileReader()
//读取指定的Blob中错误信息内容 //读取指定的Blob中错误信息内容

8
src/views/login.vue

@ -42,10 +42,10 @@
</template> </template>
<script> <script>
import { encrypt } from "@/utils/rsaEncrypt";
import Config from "@/settings";
import Cookies from "js-cookie";
import Background from "@/assets/images/background.jpg";
import { encrypt } from "@/utils/rsaEncrypt"
import Config from "@/settings"
import Cookies from "js-cookie"
import Background from "@/assets/images/background.jpg"
import { getCodeImg } from '@/api/login' import { getCodeImg } from '@/api/login'
export default { export default {

Loading…
Cancel
Save