You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
367 lines
11 KiB
367 lines
11 KiB
7 months ago
|
<!-- @format -->
|
||
|
|
||
|
<template>
|
||
|
<div class="ns-left-menu-space" :class="{ 'ns-left-menu-space-collapsed': collapsed }">
|
||
|
<a-layout-sider
|
||
|
class="ns-left-menu"
|
||
|
:width="208"
|
||
|
:collapsedWidth="48"
|
||
|
:collapsed="collapsed"
|
||
|
breakpoint="lg"
|
||
|
:trigger="null"
|
||
|
v-if="menuList && menuList[0] && menuList[0].children">
|
||
|
<a-menu
|
||
|
mode="inline"
|
||
|
:inlineIndent="16"
|
||
|
:openKeys="collapsed ? [] : initSiderOpenKey"
|
||
|
:selectedKeys="initSiderKey"
|
||
|
v-for="(item, index) in menuList[0].children"
|
||
|
:key="index">
|
||
|
<a-sub-menu
|
||
|
v-if="item.children !== undefined && !item.meta.hideChildren && !item.isHide"
|
||
|
:key="item.name">
|
||
|
<template #title>
|
||
|
<span role="img" class="anticon"
|
||
|
><ns-icon :name="item.meta.icon ? item.meta.icon : ''" size="16"
|
||
|
/></span>
|
||
|
<span>{{ item.meta.title }}</span>
|
||
|
</template>
|
||
|
<!-- 跳转外部链接 -->
|
||
|
<div v-if="item.meta?.isNewOpen">
|
||
|
<div
|
||
|
v-for="newOpen in item.meta?.itemList ? item.meta?.itemList : []"
|
||
|
:key="newOpen.code">
|
||
|
<a-menu-item v-if="checkOpAuth(newOpen.code)" :key="newOpen.code">
|
||
|
<a
|
||
|
:href="newOpen.url ? newOpen.url : newOpen.getUrl ? newOpen.getUrl() : ''"
|
||
|
target="_blank"
|
||
|
rel="noopener noreferrer">
|
||
|
{{ newOpen.name }}
|
||
|
</a></a-menu-item
|
||
|
>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div v-else>
|
||
|
<div v-for="sitem in checkAuthList(item.children)" :key="sitem.name">
|
||
|
<a-menu-item
|
||
|
v-if="(sitem.children === undefined || sitem.meta.hideChildren) && !sitem.isHide"
|
||
|
:key="sitem.name"
|
||
|
><router-link style="margin-left: 8px" :to="{ name: sitem.name }">{{
|
||
|
sitem.meta.title
|
||
|
}}</router-link></a-menu-item
|
||
|
>
|
||
|
<a-sub-menu
|
||
|
class="threeSubMenu"
|
||
|
v-if="sitem.children !== undefined && !sitem.meta.hideChildren && !sitem.isHide"
|
||
|
:key="sitem.name">
|
||
|
<template #title>
|
||
|
<span role="img" style="margin-left: 8px" class="anticon" v-show="sitem.meta.icon"
|
||
|
><ns-icon :name="sitem.meta.icon" size="16"
|
||
|
/></span>
|
||
|
<span>{{ sitem.meta.title }}</span>
|
||
|
</template>
|
||
|
<div v-for="ditem in checkAuthList(sitem.children)" :key="ditem.name">
|
||
|
<a-sub-menu
|
||
|
class="fourSubMenu"
|
||
|
v-if="ditem.children !== undefined && !ditem.isHide"
|
||
|
:key="ditem.name">
|
||
|
<template #title>
|
||
|
<span
|
||
|
role="img"
|
||
|
style="margin-left: 8px"
|
||
|
class="anticon"
|
||
|
v-show="ditem.meta.icon"
|
||
|
><ns-icon :name="ditem.meta.icon" size="16"
|
||
|
/></span>
|
||
|
<span>{{ ditem.meta.title }}</span>
|
||
|
</template>
|
||
|
<div
|
||
|
v-for="fiveFloorItem in checkAuthList(ditem.children)"
|
||
|
:key="fiveFloorItem.name">
|
||
|
<a-menu-item
|
||
|
:class="
|
||
|
initSiderKey.includes(fiveFloorItem.name) ? 'ant-menu-item-selected' : ''
|
||
|
"
|
||
|
v-if="fiveFloorItem.meta?.type !== 'op'"
|
||
|
><router-link style="margin-left: 8px" :to="{ name: fiveFloorItem.name }">{{
|
||
|
fiveFloorItem?.meta?.title ? fiveFloorItem?.meta?.title : ''
|
||
|
}}</router-link></a-menu-item
|
||
|
>
|
||
|
</div>
|
||
|
</a-sub-menu>
|
||
|
|
||
|
<a-menu-item v-if="ditem.meta?.type !== 'op' && item.children === undefined"
|
||
|
><router-link style="margin-left: 8px" :to="{ name: ditem.name }">{{
|
||
|
ditem?.meta?.title ? ditem?.meta?.title : ''
|
||
|
}}</router-link></a-menu-item
|
||
|
>
|
||
|
</div>
|
||
|
</a-sub-menu>
|
||
|
</div>
|
||
|
</div>
|
||
|
</a-sub-menu>
|
||
|
<a-menu-item
|
||
|
:class="initSiderKey.includes(item.name) ? 'firstMenuItem-selected' : ''"
|
||
|
v-if="
|
||
|
(item.children === undefined || item.meta.hideChildren) &&
|
||
|
!item.isHide &&
|
||
|
item.type !== 'op'
|
||
|
"
|
||
|
:key="item.name">
|
||
|
<router-link :to="{ name: item.name }">
|
||
|
<span role="img" class="anticon" v-show="item.meta.icon">
|
||
|
<ns-icon :name="item.meta.icon ? item.meta.icon : ''" size="16" />
|
||
|
</span>
|
||
|
<span style="margin-left: 8px">{{ item.meta.title }}</span>
|
||
|
<!-- </span> -->
|
||
|
</router-link>
|
||
|
</a-menu-item>
|
||
|
</a-menu>
|
||
|
</a-layout-sider>
|
||
|
<div class="ns-left-menu-trigger" @click="leftMenuTrigger">
|
||
|
<!-- <menu-unfold-outlined v-if="collapsed" class="trigger" />
|
||
|
<menu-fold-outlined v-else class="trigger" /> -->
|
||
|
<ns-icon name="trigger" class="trigger" size="22" />
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts">
|
||
|
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
|
||
|
import { defineComponent, inject, ref, watchEffect } from 'vue';
|
||
|
import { appConfigStore } from '/nerv-lib/saas/store/modules/app-config';
|
||
|
import { authorizationService } from '/nerv-base/store/modules/authorization-service';
|
||
|
import { Emitter } from 'mitt';
|
||
|
import { useRouter } from 'vue-router';
|
||
|
import { emitEvents } from '/nerv-base/view/system/application.d';
|
||
|
export default defineComponent({
|
||
|
name: 'NsSider',
|
||
|
components: {
|
||
|
MenuUnfoldOutlined,
|
||
|
MenuFoldOutlined,
|
||
|
},
|
||
|
props: {
|
||
|
menuList: { type: Array },
|
||
|
initSiderKey: { type: Array },
|
||
|
initSiderOpenKey: { type: Array },
|
||
|
},
|
||
|
setup: (props) => {
|
||
|
const mittEmit = inject('mittEmit') as Emitter<emitEvents>;
|
||
|
const router = useRouter();
|
||
|
const dealRouter = (menuList, routerInfo) => {
|
||
|
menuList?.forEach((item) => {
|
||
|
if (item.name === routerInfo.name) {
|
||
|
const redirectItem = item.children?.filter((x) => !x.isHide)[0];
|
||
|
if (redirectItem) {
|
||
|
router.push({ name: redirectItem.name });
|
||
|
}
|
||
|
} else {
|
||
|
if (item.children?.length) {
|
||
|
dealRouter(item.children, routerInfo);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
watchEffect(() => {
|
||
|
if (!router.currentRoute.value.redirectedFrom) {
|
||
|
dealRouter(props.menuList, router.currentRoute.value);
|
||
|
}
|
||
|
});
|
||
|
const authorizationStore = authorizationService();
|
||
|
const configStore = appConfigStore();
|
||
|
const checkOpAuth = (val: any) => {
|
||
|
if (configStore.enablePermissions) {
|
||
|
return authorizationStore.checkPermission(val);
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
const checkAuth = (val: any) => {
|
||
|
if (configStore.enablePermissions) {
|
||
|
return authorizationStore.checkPermissionRouter(val);
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
const checkAuthList = (val: any) => {
|
||
|
if (Object.prototype.toString.call(val) !== '[object Array]') return;
|
||
|
let array: any[] = [];
|
||
|
val.forEach((item: any) => {
|
||
|
if (checkAuth(item.name)) {
|
||
|
array.push(item);
|
||
|
}
|
||
|
});
|
||
|
return array;
|
||
|
};
|
||
|
const collapsed = ref<boolean>(false);
|
||
|
const leftMenuTrigger = () => {
|
||
|
collapsed.value = !collapsed.value;
|
||
|
mittEmit.emit('leftMenuTrigger', collapsed.value);
|
||
|
};
|
||
|
return {
|
||
|
leftMenuTrigger,
|
||
|
collapsed,
|
||
|
checkOpAuth,
|
||
|
checkAuthList,
|
||
|
checkAuth,
|
||
|
};
|
||
|
},
|
||
|
});
|
||
|
</script>
|
||
|
|
||
|
<style lang="less" scoped>
|
||
|
.ns-left-menu {
|
||
|
position: fixed;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
height: calc(100% - 40px);
|
||
|
// background-color: @white;
|
||
|
background-image: url(/asset/image/side.png);
|
||
|
background-size: cover;
|
||
|
padding-top: 48px;
|
||
|
:deep(.ant-layout-sider-children) {
|
||
|
background-color: transparent;
|
||
|
.ant-menu-root {
|
||
|
background-color: transparent;
|
||
|
}
|
||
|
.ant-menu-submenu-title {
|
||
|
// color: rgba(255, 255, 255, 0.9);
|
||
|
.ant-menu-submenu-arrow {
|
||
|
// color:inherit
|
||
|
// color: rgba(255, 255, 255, 0.9);
|
||
|
}
|
||
|
}
|
||
|
.ant-menu {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
}
|
||
|
.ant-menu-item a {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
}
|
||
|
.ant-menu-submenu-expand-icon,
|
||
|
.ant-menu-submenu-arrow {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
}
|
||
|
.ant-menu-sub.ant-menu-inline {
|
||
|
background-color: #001027;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#iframeApplication .ns-left-menu {
|
||
|
padding-top: 0px;
|
||
|
}
|
||
|
|
||
|
.ant-menu-submenu-title .anticon + span {
|
||
|
margin-left: 8px !important;
|
||
|
}
|
||
|
.ns-left-menu-space {
|
||
|
width: 208px;
|
||
|
height: 100%;
|
||
|
background-color: #fff;
|
||
|
overflow: hidden;
|
||
|
transition: all 0.2s;
|
||
|
flex: 0 0 208px;
|
||
|
&.ns-left-menu-space-collapsed {
|
||
|
width: 48px;
|
||
|
flex: 0 0 48px;
|
||
|
}
|
||
|
}
|
||
|
.ns-left-menu-space-collapsed {
|
||
|
.ns-left-menu-trigger {
|
||
|
width: 48px !important;
|
||
|
justify-content: center;
|
||
|
padding-left: 0px;
|
||
|
}
|
||
|
.trigger {
|
||
|
padding: 0;
|
||
|
transform: rotate(180deg);
|
||
|
// transform: rotateX('90deg');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.ns-left-menu-trigger {
|
||
|
width: 208px;
|
||
|
height: 40px;
|
||
|
transition: all 0.2s;
|
||
|
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
||
|
position: absolute;
|
||
|
z-index: 999;
|
||
|
cursor: pointer;
|
||
|
background: #163361;
|
||
|
bottom: 0px;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
justify-content: left;
|
||
|
padding-left: 24px;
|
||
|
|
||
|
// justify-content: center;
|
||
|
&:hover {
|
||
|
.trigger {
|
||
|
color: @primary-color;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
.trigger {
|
||
|
font-size: 18px;
|
||
|
line-height: 64px;
|
||
|
transform: rotate(0deg);
|
||
|
transition: color 0.3s;
|
||
|
}
|
||
|
.ant-menu-submenu-selected > .ant-menu-submenu-title > .ant-menu-submenu-expand-icon,
|
||
|
.ant-menu-submenu-selected > .ant-menu-submenu-title > .ant-menu-submenu-arrow {
|
||
|
color: red !important;
|
||
|
}
|
||
|
.ant-menu-submenu-selected .secendIcon {
|
||
|
color: @primary-color !important;
|
||
|
}
|
||
|
|
||
|
.ant-menu-inline,
|
||
|
.ant-menu-vertical,
|
||
|
.ant-menu-vertical-left {
|
||
|
border: unset;
|
||
|
}
|
||
|
|
||
|
:deep(.ant-menu-inline .ant-menu-item-selected::after) {
|
||
|
position: absolute;
|
||
|
border: unset !important;
|
||
|
content: '';
|
||
|
}
|
||
|
:deep(.ant-menu-sub .ant-menu-item-selected::after) {
|
||
|
position: absolute;
|
||
|
width: 2px;
|
||
|
height: 14px;
|
||
|
background: #fff;
|
||
|
border: unset;
|
||
|
top: 14px;
|
||
|
left: 20px;
|
||
|
right: 0;
|
||
|
bottom: 0;
|
||
|
content: '';
|
||
|
}
|
||
|
:deep(.ant-menu-submenu .ant-menu-submenu .ant-menu-sub .ant-menu-item-selected::after) {
|
||
|
position: absolute;
|
||
|
width: 2px;
|
||
|
height: 14px;
|
||
|
background: #fff;
|
||
|
border: unset;
|
||
|
top: 14px;
|
||
|
left: 40px;
|
||
|
right: 0;
|
||
|
bottom: 0;
|
||
|
content: '';
|
||
|
}
|
||
|
|
||
|
// :deep(.ant-menu-title-content) {
|
||
|
// padding-left: 8px;
|
||
|
// }
|
||
|
// :deep(.firstMenuSub .ant-menu-submenu-title) {
|
||
|
// padding-left: 8px !important;
|
||
|
// }
|
||
|
:deep(.firstMenuItem-selected) {
|
||
|
background: @primary-color!important;
|
||
|
border-radius: 4px;
|
||
|
}
|
||
|
:deep(.ns-left-menu .ant-layout-sider-children .ant-menu-submenu-arrow) {
|
||
|
color: rgba(255, 255, 255, 0.5);
|
||
|
}
|
||
|
</style>
|