代码拉取完成,页面将自动刷新
26
解决配置菜单带参数的问题,菜单配置为: /admin/user/index/:username=zhangsan
已关闭
avue-router.js
const RouterPlugin = function() {
this.$router = null
this.$store = null
}
let num = 0;
RouterPlugin.install = function(router, store) {
this.$router = router
this.$store = store
function isURL(s) {
return /^http[s]?:\/\/.*/.test(s)
}
function objToform(obj) {
const result = []
Object.keys(obj).forEach(ele => {
result.push(`${ele}=${obj[ele]}`)
})
return result.join('&')
}
this.$router.$avueRouter = {
// 全局配置
$website: this.$store.getters.website,
$defaultTitle: 'DSV Warehouse Web Visibility',
routerList: [],
group: '',
safe: this,
// 设置标题
setTitle: function(title) {
title = title ? `${title}——${this.$defaultTitle}` : this.$defaultTitle
document.title = title
},
closeTag: (value) => {
const tag = value || this.$store.getters.tag
this.$store.commit('DEL_TAG', tag)
},
// 处理路由
getPath: function(params) {
const { src } = params
let result = src || '/'
if (src.includes('http') || src.includes('https')) {
result = `/myiframe/urlPath?${objToform(params)}`
}
return result
},
//更新路由名称
getRealName(toRoute=null){
const menuList = this.safe.$store.getters.newMenu;
const result = this.getMenuName(menuList,toRoute.fullPath);
return result&&result.name||'';
},
getMenuName(menuList,path){
let result =null;
for(let item of menuList){
if(item.path == path){
result = item;
break;
}
if(item.children.length){
const childResult = this.getMenuName(item.children,path);
if(childResult){
result = childResult;
break;
}
}
}
return result;
},
// 正则处理路由
vaildPath: function(list, path) {
let result = false
list.forEach(ele => {
if (new RegExp('^' + ele + '.*', 'g').test(path)) {
result = true
}
})
return result
},
// 设置路由值
getValue: function(route) {
let value = ''
if (route.query.src) {
value = route.query.src
} else {
value = route.path
}
return value
},
// 动态路由
formatRoutes: function(aMenu = [], first) {
const aRouter = []
const propsConfig = this.$website.menu.props
const propsDefault = {
label: propsConfig.label || 'label',
path: propsConfig.path || 'path',
icon: propsConfig.icon || 'icon',
children: propsConfig.children || 'children',
meta: propsConfig.meta || 'meta'
}
if (aMenu.length === 0) return
for (let i = 0; i < aMenu.length; i++) {
const oMenu = aMenu[i]
if (this.routerList.includes(oMenu[propsDefault.path])) return
let path = (() => {
if (!oMenu[propsDefault.path]) {
return
} else if (first) {
return oMenu[propsDefault.path].replace('/index', '')
} else {
return oMenu[propsDefault.path]
}
})()
path = path.replace(/\?.*$/, '')
//特殊处理组件
let component = 'views' + oMenu.path
component = component.replace(/\?.*$/, '')
//新增动态路由处理
if(path.includes('=')){
path = path.replace(/\=.*$/, '');
component = component.replace(/\/:.*$/, '');
}
const name = oMenu[propsDefault.label]
const icon = oMenu[propsDefault.icon]
const children = oMenu[propsDefault.children]
const meta = {
keepAlive: Number(oMenu['keepAlive']) === 1,
realName:aMenu[i].name||aMenu[i].label,
}
const isChild = children.length !== 0
const oRouter = {
path: path,
component(resolve) {
// 判断是否为首路由
if (first) {
require(['../page/index'], resolve)
// 判断是否为多层路由
} else if (isChild && !first) {
require(['../page/index/layout'], resolve)
// 判断是否为最终的页面视图
} else {
require([`../${component}.vue`], resolve)
}
},
name: name,
icon: icon,
meta: meta,
redirect: (() => {
if (!isChild && first && !isURL(path)) return `${path}/index`
else return ''
})(),
// 处理是否为一级路由
children: !isChild ? (() => {
if (first) {
if (!isURL(path)) oMenu[propsDefault.path] = `${path}/index`
return [{
component(resolve) { require([`../${component}.vue`], resolve) },
icon: icon,
name: name,
meta: meta,
path: 'index'
}]
}
return []
})() : (() => {
return this.formatRoutes(children, false)
})()
}
aRouter.push(oRouter)
}
if (first) {
if (!this.routerList.includes(aRouter[0][propsDefault.path])) {
this.safe.$router.addRoutes(aRouter)
this.routerList.push(aRouter[0][propsDefault.path])
}
} else {
return aRouter
}
}
}
}
export default RouterPlugin
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import PageRouter from './page/'
import ViewsRouter from './views/'
import AvueRouter from './avue-router'
import Store from '../store/'
Vue.use(VueRouter)
//===装饰Router.prototype.push==
const oldPush = VueRouter.prototype.push;
VueRouter.prototype.push= function(...location){
return oldPush.call(this,...location).catch(err=>err);
}
//===end==
let Router = new VueRouter({
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
if (from.meta.keepAlive) {
from.meta.savedPosition = document.body.scrollTop
}
return {
x: 0,
y: to.meta.savedPosition || 0
}
}
},
routes: [].concat([])
})
AvueRouter.install(Router, Store)
Router.$avueRouter.formatRoutes(Store.state.user.menu, true)
Router.addRoutes([...PageRouter, ...ViewsRouter])
export default Router
sidebar/index.vue
<template>
<div class="avue-sidebar">
<logo></logo>
<el-scrollbar style="height:100%;background-color: rgba(2, 44, 99, 0.94);">
<div v-if="validatenull(newMenu)"
class="avue-sidebar--tip" style="background-color: #11386c">No menus found
</div>
<el-menu unique-opened
:default-active="nowTagValue"
mode="vertical"
:show-timeout="200"
active-text-color="#ffd04b"
:collapse="keyCollapse">
<sidebar-item :menu="newMenu"
:screen="screen"
first
:props="website.menu.props"
:collapse="keyCollapse"></sidebar-item>
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import {mapGetters} from "vuex";
import logo from "../logo";
import sidebarItem from "./sidebarItem";
export default {
name: "sidebar",
components: {sidebarItem, logo},
data() {
return {};
},
created() {
this.$store.dispatch("GetMenu", {type: true, id: -1}).then(data => {
if (data.length === 0) return;
this.$router.$avueRouter.formatRoutes(data, true);
});
},
computed: {
...mapGetters(["website", "menu", "tag", "keyCollapse", "screen","newMenu"]),
nowTagValue: function () {
return this.$router.$avueRouter.getValue(this.$route);
},
},
mounted() {
},
methods: {
}
};
</script>
<style lang="scss" scoped>
.avue-sidebar{
background-color: white;
}
</style>
sidebar/sidebarItem.vue
<template>
<div class="menu-wrapper">
<template v-for="item in menu">
<el-menu-item v-if="validatenull(item[childrenKey]) && vaildRoles(item)"
:index="item[pathKey]"
@click="open(item)"
:key="item[labelKey]"
:class="{'is-active':vaildAvtive(item)}">
<i :class="item[iconKey]"></i>
<span slot="title"
:alt="item[pathKey]">{{item[labelKey]}}</span>
</el-menu-item>
<el-submenu v-else-if="!validatenull(item[childrenKey])&&vaildRoles(item)"
:index="item[pathKey]"
:key="item[labelKey]">
<template slot="title">
<i :class="item[iconKey]"></i>
<span slot="title"
:class="{'el-menu--display':collapse && first}">{{item[labelKey]}}</span>
</template>
<template v-for="(child,cindex) in item[childrenKey]">
<el-menu-item :index="child[pathKey],cindex"
@click="open(child)"
:class="{'is-active':vaildAvtive(child)}"
v-if="validatenull(child[childrenKey])"
:key="child[labelKey]">
<i :class="child[iconKey]"></i>
<span slot="title">{{child[labelKey]}}</span>
</el-menu-item>
<sidebar-item v-else
:menu="[child]"
:key="cindex"
:props="props"
:screen="screen"
:collapse="collapse"></sidebar-item>
</template>
</el-submenu>
</template>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { validatenull } from "@/util/validate";
import config from "./config.js";
export default {
name: "sidebarItem",
data() {
return {
config: config
};
},
props: {
menu: {
type: Array
},
screen: {
type: Number
},
first: {
type: Boolean,
default: false
},
props: {
type: Object,
default: () => {
return {};
}
},
collapse: {
type: Boolean
}
},
created() {},
mounted() {},
computed: {
...mapGetters(["roles"]),
labelKey() {
return this.props.label || this.config.propsDefault.label;
},
pathKey() {
return this.props.path || this.config.propsDefault.path;
},
iconKey() {
return this.props.icon || this.config.propsDefault.icon;
},
childrenKey() {
return this.props.children || this.config.propsDefault.children;
},
nowTagValue() {
return this.$router.$avueRouter.getValue(this.$route);
}
},
methods: {
vaildAvtive(item) {
const groupFlag = (item["group"] || []).some(ele =>
this.$route.path.includes(this.newFilterFn(ele))
);
return this.nowTagValue === item[this.pathKey] || groupFlag;
},
vaildRoles(item) {
item.meta = item.meta || {};
return item.meta.roles ? item.meta.roles.includes(this.roles) : true;
},
validatenull(val) {
return validatenull(val);
},
open(item) {
if (this.screen <= 1) this.$store.commit("SET_COLLAPSE");
this.$router.$avueRouter.group = item.group;
this.$router.push({
path: this.$router.$avueRouter.getPath({
name: item[this.labelKey],
src: item[this.pathKey]
}),
query: item.query
}).catch(() => {});
},
}
};
</script>
util/util.js
import {validatenull} from './validate'
import * as CryptoJS from 'crypto-js'
// 表单序列化
export const serialize = data => {
let list = []
Object.keys(data).forEach(ele => {
list.push(`${ele}=${data[ele]}`)
})
return list.join('&')
}
export const getObjType = obj => {
var toString = Object.prototype.toString
var map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
}
if (obj instanceof Element) {
return 'element'
}
return map[toString.call(obj)]
}
/**
* 对象深拷贝
*/
export const deepClone = data => {
var type = getObjType(data)
var obj
if (type === 'array') {
obj = []
} else if (type === 'object') {
obj = {}
} else {
// 不再具有下一层次
return data
}
if (type === 'array') {
for (var i = 0, len = data.length; i < len; i++) {
obj.push(deepClone(data[i]))
}
} else if (type === 'object') {
for (var key in data) {
obj[key] = deepClone(data[key])
}
}
return obj
}
/**
* 判断路由是否相等
*/
export const diff = (obj1, obj2) => {
delete obj1.close
var o1 = obj1 instanceof Object
var o2 = obj2 instanceof Object
if (!o1 || !o2) { /* 判断不是对象 */
return obj1 === obj2
}
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
return false
// Object.keys() 返回一个由对象的自身可枚举属性(key值)组成的数组,例如:数组返回下表:let arr = ["a", "b", "c"];console.log(Object.keys(arr))->0,1,2;
}
for (var attr in obj1) {
var t1 = obj1[attr] instanceof Object
var t2 = obj2[attr] instanceof Object
if (t1 && t2) {
return diff(obj1[attr], obj2[attr])
} else if (obj1[attr] !== obj2[attr]) {
return false
}
}
return true
}
/**
* 设置灰度模式
*/
export const toggleGrayMode = (status) => {
if (status) {
document.body.className = document.body.className + ' grayMode'
} else {
document.body.className = document.body.className.replace(' grayMode', '')
}
}
/**
* 设置主题
*/
export const setTheme = (name) => {
document.body.className = name
}
/**
*加密处理
*/
export const encryption = (params) => {
let {
data,
type,
param,
key
} = params
const result = JSON.parse(JSON.stringify(data))
if (type === 'Base64') {
param.forEach(ele => {
result[ele] = btoa(result[ele])
})
} else {
param.forEach(ele => {
var data = result[ele]
key = CryptoJS.enc.Latin1.parse(key)
var iv = key
// 加密
var encrypted = CryptoJS.AES.encrypt(
data,
key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
})
result[ele] = encrypted.toString()
})
}
return result
}
/**
* 浏览器判断是否全屏
*/
export const fullscreenToggel = () => {
if (fullscreenEnable()) {
exitFullScreen();
} else {
reqFullScreen();
}
};
/**
* esc监听全屏
*/
export const listenfullscreen = (callback) => {
function listen() {
callback()
}
document.addEventListener("fullscreenchange", function () {
listen();
});
document.addEventListener("mozfullscreenchange", function () {
listen();
});
document.addEventListener("webkitfullscreenchange", function () {
listen();
});
document.addEventListener("msfullscreenchange", function () {
listen();
});
};
/**
* 浏览器判断是否全屏
*/
export const fullscreenEnable = () => {
return document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen
}
/**
* 浏览器全屏
*/
export const reqFullScreen = () => {
if (document.documentElement.requestFullScreen) {
document.documentElement.requestFullScreen();
} else if (document.documentElement.webkitRequestFullScreen) {
document.documentElement.webkitRequestFullScreen();
} else if (document.documentElement.mozRequestFullScreen) {
document.documentElement.mozRequestFullScreen();
}
};
/**
* 浏览器退出全屏
*/
export const exitFullScreen = () => {
if (document.documentElement.requestFullScreen) {
document.exitFullScreen();
} else if (document.documentElement.webkitRequestFullScreen) {
document.webkitCancelFullScreen();
} else if (document.documentElement.mozRequestFullScreen) {
document.mozCancelFullScreen();
}
};
/**
* 递归寻找子类的父类
*/
export const findParent = (menu, id) => {
for (let i = 0; i < menu.length; i++) {
if (menu[i].children.length != 0) {
for (let j = 0; j < menu[i].children.length; j++) {
if (menu[i].children[j].id == id) {
return menu[i]
} else {
if (menu[i].children[j].children.length != 0) {
return findParent(menu[i].children[j].children, id)
}
}
}
}
}
}
/**
* 动态插入css
*/
export const loadStyle = url => {
const link = document.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
link.href = url
const head = document.getElementsByTagName('head')[0]
head.appendChild(link)
}
/**
* 判断路由是否相等
*/
export const isObjectValueEqual = (a, b) => {
let result = true
Object.keys(a).forEach(ele => {
const type = typeof (a[ele])
if (type === 'string' && a[ele] !== b[ele]) result = false
else if (type === 'object' && JSON.stringify(a[ele]) !== JSON.stringify(b[ele])) result = false
})
return result
}
/**
* 根据字典的value显示label
*/
export const findByvalue = (dic, value) => {
let result = ''
if (validatenull(dic)) return value
if (typeof (value) === 'string' || typeof (value) === 'number' || typeof (value) === 'boolean') {
let index = 0
index = findArray(dic, value)
if (index != -1) {
result = dic[index].label
} else {
result = value
}
} else if (value instanceof Array) {
result = []
let index = 0
value.forEach(ele => {
index = findArray(dic, ele)
if (index != -1) {
result.push(dic[index].label)
} else {
result.push(value)
}
})
result = result.toString()
}
return result
}
/**
* 根据字典的value查找对应的index
*/
export const findArray = (dic, value) => {
for (let i = 0; i < dic.length; i++) {
if (dic[i].value == value) {
return i
}
}
return -1
}
/**
* 生成随机len位数字
*/
export const randomLenNum = (len, date) => {
let random = ''
random = Math.ceil(Math.random() * 100000000000000).toString().substr(0, len || 4)
if (date) random = random + Date.now()
return random
}
/**
* 将xx/:params=abc转化为xx/abc
* @param {*} routePath
* @returns
*/
export const newFilterFn=(routePath='')=>{
if(routePath&&routePath.includes('/:')){
let tempSrc = routePath.replace(/\/:.*$/, ''),
paramVal = routePath.split('=')[1];
routePath = tempSrc +'/' + paramVal;
}
return routePath;
}
//map
export const newRouteArr=(arr=[])=>{
return arr.map(item=>{
item.path = newFilterFn(item.path);
if(item['children']){
item.children = newRouteArr(item.children);
}
return item;
});
}
permission.js
/**
* 全站权限配置
*
*/
import router from './router/router'
import store from '@/store'
import {validatenull} from '@/util/validate'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
NProgress.configure({showSpinner: false})
/**
* 导航守卫,相关内容可以参考:
* https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
*/
router.beforeEach((to, from, next) => {
// 缓冲设置
if (to.meta.keepAlive === true && store.state.tags.tagList.some(ele => {
return ele.value === to.fullPath
})) {
to.meta.$keepAlive = true
} else {
NProgress.start()
if (to.meta.keepAlive === true && validatenull(to.meta.$keepAlive)) {
to.meta.$keepAlive = true
} else {
to.meta.$keepAlive = false
}
}
const meta = to.meta || {}
if (store.getters.access_token) {
if (to.path === '/login') {
next({path: '/'})
} else {
// NOTE: 当用户角色不存在时,会存在无限请求用户信息接口的问题
if (store.getters.roles.length === 0) {
store.dispatch('GetUserInfo').then(() => {
next()
}).catch(() => {
store.dispatch('FedLogOut').then(() => {
next({path: '/login'})
})
})
} else {
const value = to.query.src || to.fullPath
const label = router.$avueRouter.getRealName(to) || to.query.name || to.name
// 针对外链跳转
if (value.includes('http') || value.includes('https')) {
NProgress.done();
window.open(value, '_blank')
return
}
if (meta.isTab !== false && !validatenull(value) && !validatenull(label)) {
store.commit('ADD_TAG', {
label: label,
value: value,
params: to.params,
query: to.query,
group: router.$avueRouter.group || []
})
}
next()
}
}
} else {
if (meta.isAuth === false) {
next()
} else {
next('/login')
}
}
})
router.afterEach(() => {
NProgress.done()
const title = store.getters.tag.label
router.$avueRouter.setTitle(title)
})