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.

427 lines
13 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"
:collapsedWidth="60"
:width="sideWidth"
7 months ago
:collapsed="collapsed"
breakpoint="lg"
:trigger="null"
v-if="menuList && menuList[0] && menuList[0].children">
{{ $refs.getComputedStyle }}
7 months ago
<a-menu
mode="inline"
:inlineIndent="20"
7 months ago
: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="15" />
</span>
7 months ago
<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>
7 months ago
</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 :to="{ name: sitem.name }">
<span role="img" class="anticon" v-if="sitem.meta.icon">
<ns-icon :name="sitem.meta.icon ? sitem.meta.icon : ''" size="15" />
</span>
<span>{{ sitem?.meta?.title }}</span>
</router-link>
</a-menu-item>
7 months ago
<a-sub-menu
class="threeSubMenu"
v-if="sitem.children !== undefined && !sitem.meta.hideChildren && !sitem.isHide"
:key="sitem.name">
<template #title>
<span role="img" class="anticon" v-show="sitem.meta.icon">
<ns-icon :name="sitem.meta.icon" size="15" />
</span>
7 months ago
<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" class="anticon" v-show="ditem.meta.icon">
<ns-icon :name="ditem.meta.icon" size="15" />
</span>
7 months ago
<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 :to="{ name: fiveFloorItem.name }">
{{ fiveFloorItem?.meta?.title ? fiveFloorItem?.meta?.title : '' }}123
</router-link>
</a-menu-item>
7 months ago
</div>
</a-sub-menu>
<a-menu-item v-if="ditem.meta?.type !== 'op' && item.children === undefined">
<router-link :to="{ name: ditem.name }">
<span role="img" class="anticon" v-if="ditem.meta.icon">
<ns-icon :name="ditem.meta.icon ? ditem.meta.icon : ''" size="15" />
</span>
<span>{{ ditem?.meta?.title }}123</span>
</router-link>
</a-menu-item>
7 months ago
</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="15" />
7 months ago
</span>
<span>{{ item.meta.title }}</span>
7 months ago
</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 { computed, defineComponent, inject, onMounted, ref, watchEffect } from 'vue';
7 months ago
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 sideWidth = computed(() => {
return getComputedStyle(document.querySelector('.ns-left-menu-trigger')!).width;
});
7 months ago
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,
sideWidth,
7 months ago
};
},
});
</script>
<style lang="less" scoped>
@icon-gap: 12px;
// :deep(.ant-layout-sider) {
// width: @layout-sider-width !important;
// max-width: @layout-sider-width !important;
// }
7 months ago
.ns-left-menu {
position: fixed;
top: 0;
left: 0;
height: calc(100% - 40px);
background-color: @white;
// background-image: url(/asset/image/side.png);
7 months ago
background-size: cover;
padding-top: calc(@layout-header-height + @icon-gap);
.ant-menu-item-selected {
// color: #fff !important;
// background: @primary-color;
border-radius: 12px;
height: 40px;
line-height: 40px;
padding: 5px @ns-gap;
position: relative;
a {
color: @white !important;
}
}
.router-link-active::before {
// background-color: @primary-color;
width: 90%;
}
7 months ago
:deep(.ant-layout-sider-children) {
transition: all 0.1s;
padding: 0 @ns-gap;
// background-color: transparent;
7 months ago
.ant-menu-root {
// background-color: transparent;
7 months ago
}
.ant-menu-submenu-title,
.ant-menu-item {
height: @menu-item-height;
border-radius: @ns-border-radius;
// overflow: hidden;
// color: @black;
7 months ago
.ant-menu-submenu-arrow {
// color: @black;
7 months ago
}
}
.ant-menu {
color: rgba(@black, 0.85);
}
.ant-menu-sub.ant-menu-inline {
background-color: @white;
// > div {
// margin-inline: 20px;
// }
7 months ago
}
.ant-menu-item-active:not(.ant-menu-item-selected),
.ant-submenu-item-active {
// color: rgba(@primary-color, 0.1) !important;
background-color: rgba(@primary-color, 0.1);
border-radius: 12px;
7 months ago
}
}
}
.anticon + span {
margin-left: @icon-gap !important;
7 months ago
}
.ns-left-menu-space {
width: 100%;
height: auto;
z-index: 9;
box-shadow: @ns-box-shadow;
// background-color: #fff;
7 months ago
overflow: hidden;
transition: all 0.2s;
flex: 0 0 @layout-sider-width;
// transition: all 0.1s;
// &:not(.ns-left-menu-space-collapsed) :deep(.ant-menu-title-content) {
// padding-left: 8px;
// }
:deep(.ant-menu-item-selected) {
// color: #fff !important;
background: @primary-color;
// border-radius: 12px;
// height: 40px;
// line-height: 40px;
// width: auto;
// margin-inline: @ns-gap;
// padding-left: @ns-gap !important;
position: relative;
a {
color: @white !important;
}
7 months ago
}
}
7 months ago
.ns-left-menu-space-collapsed {
z-index: 11;
width: @layout-sider-collapsed-width;
flex: 0 0 @layout-sider-collapsed-width;
:deep(.ant-layout-sider-children) {
transition: all 0.1s;
padding: 0 calc(@ns-gap / 4) !important;
}
7 months ago
.ns-left-menu-trigger {
width: @layout-sider-collapsed-width !important;
7 months ago
justify-content: center;
padding-left: 0px;
}
.trigger {
padding: 0;
transform: rotate(180deg);
// transform: rotateX('90deg');
}
}
.ns-left-menu-trigger {
width: @layout-sider-width;
7 months ago
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;
7 months ago
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.2s;
7 months ago
}
// .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;
// }
7 months ago
.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(.firstMenuSub .ant-menu-submenu-title) {
// padding-left: 8px !important;
// }
7 months ago
: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);
7 months ago
}
</style>