Commit 58e30151 authored by 陈浩玮's avatar 陈浩玮

Merge branch 'feature/shuiluo' into 'master'

feat: 菜单权限代码处理

See merge request product/kim3-web-vue/starter-web-vue!28
parents ed54b020 445c4639
...@@ -66,9 +66,7 @@ export default { ...@@ -66,9 +66,7 @@ export default {
}, },
setHtmlTitle() { setHtmlTitle() {
const route = this.$route; const route = this.$route;
const key = if (route.name) window.title = route.name;
route.path === '/' ? 'home.name' : getI18nKey(route.matched[route.matched.length - 1].path);
document.title = process.env.VUE_APP_NAME + ' | ' + this.$t(key);
}, },
popContainer() { popContainer() {
return document.getElementById('popContainer'); return document.getElementById('popContainer');
......
<template> <template>
<a-layout-sider :theme="sideTheme" :class="['side-menu', 'beauty-scroll', isMobile ? null : 'shadow']" width="256px" :collapsible="collapsible" v-model="collapsed" :trigger="null"> <a-layout-sider
:theme="sideTheme"
:class="['side-menu', 'beauty-scroll', isMobile ? null : 'shadow']"
width="256px"
:collapsible="collapsible"
v-model="collapsed"
:trigger="null"
>
<div :class="['logo', theme]"> <div :class="['logo', theme]">
<router-link to="/dashboard/workplace"> <router-link to="/dashboard/workplace">
<img src="@/assets/img/logo.png"> <img src="@/assets/img/logo.png" />
<h1>{{systemName}}</h1> <h1>{{ systemName }}</h1>
</router-link> </router-link>
</div> </div>
<i-menu :theme="theme" :collapsed="collapsed" :options="menuData" @select="onSelect" class="menu" /> <i-menu :theme="theme" :collapsed="collapsed" :options="menuData" @select="onSelect" class="menu" />
...@@ -13,6 +20,7 @@ ...@@ -13,6 +20,7 @@
<script> <script>
import IMenu from './menu'; import IMenu from './menu';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
export default { export default {
name: 'SideMenu', name: 'SideMenu',
components: { IMenu }, components: { IMenu },
......
...@@ -27,19 +27,18 @@ ...@@ -27,19 +27,18 @@
* i18n: { * i18n: {
* messages: { * messages: {
* zh_CN: {dashboard: {name: '监控中心'}} * zh_CN: {dashboard: {name: '监控中心'}}
* *
* } * }
* } * }
**/ **/
import Menu from "ant-design-vue/es/menu"; import Menu from 'ant-design-vue/es/menu';
import Icon from "ant-design-vue/es/icon"; import Icon from 'ant-design-vue/es/icon';
import fastEqual from "fast-deep-equal"; import { getUserInfo } from '@/utils';
import {getI18nKey} from '@/utils/routerUtil'
const { Item, SubMenu } = Menu; const { Item, SubMenu } = Menu;
export default { export default {
name: "IMenu", name: 'IMenu',
props: { props: {
options: { options: {
type: Array, type: Array,
...@@ -48,12 +47,12 @@ export default { ...@@ -48,12 +47,12 @@ export default {
theme: { theme: {
type: String, type: String,
required: false, required: false,
default: "dark", default: 'dark',
}, },
mode: { mode: {
type: String, type: String,
required: false, required: false,
default: "inline", default: 'inline',
}, },
collapsed: { collapsed: {
type: Boolean, type: Boolean,
...@@ -61,43 +60,37 @@ export default { ...@@ -61,43 +60,37 @@ export default {
default: false, default: false,
}, },
i18n: Object, i18n: Object,
openKeys: Array,
}, },
data() { data() {
return { return {
selectedKeys: [], selectedKeys: [],
sOpenKeys: [], sOpenKeys: [],
cachedOpenKeys: [], cachedOpenKeys: [],
menuData: [],
}; };
}, },
computed: { computed: {
menuTheme() { menuTheme() {
return this.theme == "light" ? this.theme : "dark"; return this.theme == 'light' ? this.theme : 'dark';
}, },
}, },
created() { created() {
this.updateMenu(); const { menuList } = getUserInfo();
if (this.options.length > 0 && !this.options[0].fullPath) { this.menuData = menuList.filter(i => i.menuType === 'MENU');
this.formatOptions(this.options, ""); this.updateMenu();
} // // 自定义国际化配置
// 自定义国际化配置 // if (this.i18n && this.i18n.messages) {
if (this.i18n && this.i18n.messages) { // const messages = this.i18n.messages;
const messages = this.i18n.messages; // Object.keys(messages).forEach(key => {
Object.keys(messages).forEach((key) => { // this.$i18n.mergeLocaleMessage(key, messages[key]);
this.$i18n.mergeLocaleMessage(key, messages[key]); // });
}); // }
}
}, },
watch: { watch: {
options(val) {
if (val.length > 0 && !val[0].fullPath) {
this.formatOptions(this.options, "");
}
},
i18n(val) { i18n(val) {
if (val && val.messages) { if (val && val.messages) {
const messages = this.i18n.messages; const messages = this.i18n.messages;
Object.keys(messages).forEach((key) => { Object.keys(messages).forEach(key => {
this.$i18n.mergeLocaleMessage(key, messages[key]); this.$i18n.mergeLocaleMessage(key, messages[key]);
}); });
} }
...@@ -114,112 +107,97 @@ export default { ...@@ -114,112 +107,97 @@ export default {
this.updateMenu(); this.updateMenu();
}, },
sOpenKeys(val) { sOpenKeys(val) {
this.$emit("openChange", val); this.$emit('openChange', val);
this.$emit("update:openKeys", val); this.$emit('update:openKeys', val);
}, },
}, },
methods: { methods: {
renderIcon: function(h, icon, key) { renderIcon(h, icon, key) {
if (this.$scopedSlots.icon && icon && icon !== "none") { if (this.$scopedSlots.icon && icon && icon !== 'none') {
const vnodes = this.$scopedSlots.icon({ icon, key }); const vnodes = this.$scopedSlots.icon({ icon, key });
vnodes.forEach((vnode) => { vnodes.forEach(vnode => {
vnode.data.class = vnode.data.class ? vnode.data.class : []; vnode.data.class = vnode.data.class ? vnode.data.class : [];
vnode.data.class.push("anticon"); vnode.data.class.push('anticon');
}); });
return vnodes; return vnodes;
} }
return !icon || icon == "none" ? null : h(Icon, { props: { type: icon } }); return !icon || icon == 'none' ? null : h(Icon, { props: { type: icon } });
}, },
renderMenuItem: function(h, menu) { renderMenuItem(h, menu) {
let tag = "router-link"; const tag = 'router-link';
let config = { const config = {
props: { to: menu.fullPath }, props: { to: menu.path },
attrs: { style: "overflow:hidden;white-space:normal;text-overflow:clip;" }, attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' },
}; };
if (menu.meta && menu.meta.link) {
tag = "a"; return h(Item, { key: menu.menuId }, [
config = { h(tag, config, [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName]),
attrs: {
style: "overflow:hidden;white-space:normal;text-overflow:clip;",
href: menu.meta.link,
target: "_blank",
},
};
}
return h(Item, { key: menu.fullPath }, [
h(tag, config, [
this.renderIcon(h, menu.meta ? menu.meta.icon : "none", menu.fullPath),
this.$t(getI18nKey(menu.fullPath)),
]),
]); ]);
}, },
renderSubMenu: function(h, menu) { renderSubMenu(h, menu) {
let this_ = this; const subItem = [
let subItem = [
h( h(
"span", 'span',
{ slot: "title", attrs: { style: "overflow:hidden;white-space:normal;text-overflow:clip;" } }, {
[ slot: 'title',
this.renderIcon(h, menu.meta ? menu.meta.icon : "none", menu.fullPath), attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' },
this.$t(getI18nKey(menu.fullPath)), },
] [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName],
), ),
]; ];
let itemArr = []; const itemArr = [];
menu.children.forEach(function(item) { menu.children.forEach(item => {
itemArr.push(this_.renderItem(h, item)); itemArr.push(this.renderItem(h, item));
}); });
return h(SubMenu, { key: menu.fullPath }, subItem.concat(itemArr)); return h(SubMenu, { key: menu.menuId }, subItem.concat(itemArr));
}, },
renderItem: function(h, menu) { renderItem(h, menu) {
const meta = menu.meta; return menu.children && menu.children.length
if (!meta || !meta.invisible) { ? this.renderSubMenu(h, menu)
let renderChildren = false; : this.renderMenuItem(h, menu);
const children = menu.children;
if (children != undefined) {
for (let i = 0; i < children.length; i++) {
const childMeta = children[i].meta;
if (!childMeta || !childMeta.invisible) {
renderChildren = true;
break;
}
}
}
return menu.children && renderChildren ? this.renderSubMenu(h, menu) : this.renderMenuItem(h, menu);
}
}, },
renderMenu: function(h, menuTree) { renderMenu(h, menuTree) {
let this_ = this;
let menuArr = []; let menuArr = [];
menuTree.forEach(function(menu, i) { menuTree.forEach((menu, i) => {
menuArr.push(this_.renderItem(h, menu, "0", i)); menuArr.push(this.renderItem(h, menu));
}); });
return menuArr; return menuArr;
}, },
formatOptions(options, parentPath) {
options.forEach((route) => {
let isFullPath = route.path.substring(0, 1) == "/";
route.fullPath = isFullPath ? route.path : parentPath + "/" + route.path;
if (route.children) {
this.formatOptions(route.children, route.fullPath);
}
});
},
updateMenu() { updateMenu() {
const matchedRoutes = this.$route.matched.filter((item) => item.path !== "");
this.selectedKeys = this.getSelectedKey(this.$route); this.selectedKeys = this.getSelectedKey(this.$route);
let openKeys = matchedRoutes.map((item) => item.path);
openKeys = openKeys.slice(0, openKeys.length - 1); // let openKeys = matchedRoutes.map(item => item.path);
if (!fastEqual(openKeys, this.sOpenKeys)) {
this.collapsed || this.mode === "horizontal" // openKeys = openKeys.slice(0, openKeys.length - 1);
? (this.cachedOpenKeys = openKeys)
: (this.sOpenKeys = openKeys); // if (!fastEqual(openKeys, this.sOpenKeys)) {
} // this.collapsed || this.mode === 'horizontal'
// ? (this.cachedOpenKeys = openKeys)
// : (this.sOpenKeys = openKeys);
// }
this.sOpenKeys = this.getOpenKeysByPath(this.$route.path);
}, },
getSelectedKey(route) { getSelectedKey(route) {
return route.matched.map((item) => item.path); const { path } = route;
return [this.menuData.find(m => m.menuUrl === path).menuId];
},
getOpenKeysByPath(path) {
const { menuList } = getUserInfo();
const { parentMenuId } = this.menuData.find(m => m.menuUrl === path);
if (parentMenuId === 0) return [];
const parentMenus = [parentMenuId];
const res = [parentMenuId];
while (parentMenus.length) {
const menuId = parentMenus.pop();
const parentMenu = menuList.find(m => m.menuId === menuId);
if (parentMenu.parentMenuId !== 0) {
parentMenus.push(parentMenu.parentMenuId);
res.push(parentMenu.parentMenuId);
}
}
return res;
}, },
}, },
render(h) { render(h) {
...@@ -230,19 +208,19 @@ export default { ...@@ -230,19 +208,19 @@ export default {
theme: this.menuTheme, theme: this.menuTheme,
mode: this.$props.mode, mode: this.$props.mode,
selectedKeys: this.selectedKeys, selectedKeys: this.selectedKeys,
openKeys: this.openKeys ? this.openKeys : this.sOpenKeys, openKeys: this.sOpenKeys,
}, },
on: { on: {
"update:openKeys": (val) => { 'update:openKeys': val => {
this.sOpenKeys = val; this.sOpenKeys = val;
}, },
click: (obj) => { click: obj => {
obj.selectedKeys = [obj.key]; obj.selectedKeys = [obj.key];
this.$emit("select", obj); this.$emit('select', obj);
}, },
}, },
}, },
this.renderMenu(h, this.options) this.renderMenu(h, this.options),
); );
}, },
}; };
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
v-if="fixedSideBar && !isMobile" v-if="fixedSideBar && !isMobile"
:style="`width: ${sideMenuWidth}; min-width: ${sideMenuWidth};max-width: ${sideMenuWidth};`" :style="`width: ${sideMenuWidth}; min-width: ${sideMenuWidth};max-width: ${sideMenuWidth};`"
class="virtual-side" class="virtual-side"
></div> />
<drawer v-if="!hideSettingExtend" v-model="showSetting" placement="right"> <drawer v-if="!hideSettingExtend" v-model="showSetting" placement="right">
<div class="setting" slot="handler"> <div class="setting" slot="handler">
...@@ -59,9 +59,10 @@ ...@@ -59,9 +59,10 @@
<script> <script>
import LayoutTopHeader from '../components/header/LayoutTopHeader'; import LayoutTopHeader from '../components/header/LayoutTopHeader';
import Drawer from '@/components/tool/Drawer'; import Drawer from '@/components/tool/Drawer';
import SideMenu from '@/components/menu/SideMenu'; import SideMenu from '@/components/menu/SideMenu.vue';
import Setting from '../components/setting/Setting'; import Setting from '../components/setting/Setting';
import { mapState, mapMutations, mapGetters } from 'vuex'; import { mapState, mapMutations, mapGetters } from 'vuex';
import { convertListToTree, getUserInfo } from '@/utils';
// const minHeight = window.innerHeight - 64 - 122 // const minHeight = window.innerHeight - 64 - 122
...@@ -74,6 +75,7 @@ export default { ...@@ -74,6 +75,7 @@ export default {
collapsed: false, collapsed: false,
showSetting: false, showSetting: false,
drawerOpen: false, drawerOpen: false,
menuData: [],
}; };
}, },
provide() { provide() {
...@@ -108,7 +110,7 @@ export default { ...@@ -108,7 +110,7 @@ export default {
'multiPage', 'multiPage',
]), ]),
...mapGetters('settingModule', ['firstMenu', 'subMenu', 'menuData']), ...mapGetters('settingModule', ['firstMenu', 'subMenu']),
hideSettingExtend() { hideSettingExtend() {
if (this.hideSetting === false && process.env.NODE_ENV === 'development') { if (this.hideSetting === false && process.env.NODE_ENV === 'development') {
...@@ -161,6 +163,9 @@ export default { ...@@ -161,6 +163,9 @@ export default {
created() { created() {
this.correctPageMinHeight(this.minHeight - 24); this.correctPageMinHeight(this.minHeight - 24);
this.setActivated(this.$route); this.setActivated(this.$route);
const userInfo = getUserInfo();
const menuData = convertListToTree(userInfo?.menuList || [], false, true);
this.menuData = menuData;
}, },
beforeDestroy() { beforeDestroy() {
this.correctPageMinHeight(-this.minHeight + 24); this.correctPageMinHeight(-this.minHeight + 24);
......
...@@ -34,12 +34,16 @@ export function clearUserInfo() { ...@@ -34,12 +34,16 @@ export function clearUserInfo() {
* @param {Array} menuList 菜单列表 * @param {Array} menuList 菜单列表
* @param {Boolean} filterMenu 是否过滤掉菜单,只保留目录 * @param {Boolean} filterMenu 是否过滤掉菜单,只保留目录
*/ */
export function convertListToTree(menuList, filterMenu = false) { export function convertListToTree(menuList, filterMenu = false, toMenuData = false) {
let tempMenu = [...menuList]; let tempMenu = [...menuList];
if (filterMenu) { if (filterMenu) {
tempMenu = tempMenu.filter(m => m.menuType !== 'MENU'); tempMenu = tempMenu.filter(m => m.menuType !== 'MENU');
} }
for (const menu of menuList) { for (const menu of menuList) {
if (toMenuData) {
menu.name = menu.menuName;
menu.path = menu.menuUrl;
}
if (menu.parentMenuId === 0) continue; if (menu.parentMenuId === 0) continue;
const parent = menuList.find(m => m.menuId === menu.parentMenuId); const parent = menuList.find(m => m.menuId === menu.parentMenuId);
parent.children ? parent.children.push(menu) : (parent.children = [menu]); parent.children ? parent.children.push(menu) : (parent.children = [menu]);
......
...@@ -78,18 +78,16 @@ function loadRoutes(routesConfig) { ...@@ -78,18 +78,16 @@ function loadRoutes(routesConfig) {
// 应用配置 // 应用配置
const { router, store, i18n } = appOptions; const { router, store, i18n } = appOptions;
// 如果 routesConfig 有值,则更新到本地,否则从本地获取 routesConfig = store.getters['accountModule/routesConfig'];
if (routesConfig) {
store.commit('accountModule/setRoutesConfig', routesConfig);
} else {
routesConfig = store.getters['accountModule/routesConfig'];
}
// 提取路由国际化数据 // 提取路由国际化数据
mergeI18nFromRoutes(i18n, router.options.routes); mergeI18nFromRoutes(i18n, router.options.routes);
// 初始化Admin后台菜单数据 // 初始化Admin后台菜单数据
const rootRoute = router.options.routes.find(item => item.path === '/'); const rootRoute = router.options.routes.find(item => item.path === '/');
const menuRoutes = rootRoute && rootRoute.children; const menuRoutes = rootRoute && rootRoute.children;
if (menuRoutes) { if (menuRoutes) {
store.commit('settingModule/setMenuData', menuRoutes); store.commit('settingModule/setMenuData', menuRoutes);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment