|
@@ -0,0 +1,248 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { onMounted, ref } from 'vue';
|
|
|
+import { useRoute, useRouter } from 'vue-router';
|
|
|
+
|
|
|
+import { routes } from '@/router';
|
|
|
+import { translateNavigation } from '@/utils';
|
|
|
+
|
|
|
+import AsideItem from './AsideItem.vue';
|
|
|
+
|
|
|
+import type { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
|
|
|
+
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+const selectedKeys = ref<string[]>([route.path]);
|
|
|
+const openKeys = ref<string[]>([]);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const firstPath = route.path.split('/')[1];
|
|
|
+
|
|
|
+ if (firstPath) {
|
|
|
+ openKeys.value.push('/' + firstPath);
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const handleMenuClick = ({ key }: MenuInfo) => {
|
|
|
+ router.push(key as string);
|
|
|
+};
|
|
|
+
|
|
|
+const collapsed = ref<boolean>(false);
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <ALayoutSider class="aside-container" v-model:collapsed="collapsed" collapsible :trigger="null" :width="246">
|
|
|
+ <div class="aside-header">
|
|
|
+ <div class="aside-header-logo"></div>
|
|
|
+ <span class="aside-header-title">{{ $t('common.unimatIoT') }}</span>
|
|
|
+ </div>
|
|
|
+ <AMenu
|
|
|
+ class="aside-menu"
|
|
|
+ v-model:selected-keys="selectedKeys"
|
|
|
+ v-model:open-keys="openKeys"
|
|
|
+ mode="inline"
|
|
|
+ @click="handleMenuClick"
|
|
|
+ >
|
|
|
+ <template v-for="{ path, meta, children } in routes" :key="path">
|
|
|
+ <template v-if="meta && !meta.hideInMenu">
|
|
|
+ <ASubMenu v-if="!meta.hideSubMenu && children" :key="path">
|
|
|
+ <template #title>
|
|
|
+ <AsideItem :title="translateNavigation(meta.title)" :icon="meta.icon" />
|
|
|
+ </template>
|
|
|
+ <AMenuItem v-for="{ path: subPath, meta } in children" :key="`${path}/${subPath}`">
|
|
|
+ <AsideItem :title="translateNavigation(meta?.title)" />
|
|
|
+ </AMenuItem>
|
|
|
+ </ASubMenu>
|
|
|
+ <AMenuItem v-else :key="`${path}/index`">
|
|
|
+ <AsideItem :title="translateNavigation(meta.title)" :icon="meta.icon" />
|
|
|
+ </AMenuItem>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ <div class="aside-menu-ai-ctrl">{{ $t('common.aiCtrl') }}</div>
|
|
|
+ <AMenuItem key="ai-1" disabled>
|
|
|
+ <AsideItem title="一级菜单" icon="setting" />
|
|
|
+ </AMenuItem>
|
|
|
+ <AMenuItem key="ai-2" disabled>
|
|
|
+ <AsideItem title="一级菜单" icon="setting" />
|
|
|
+ </AMenuItem>
|
|
|
+ <AMenuItem key="ai-3" disabled>
|
|
|
+ <AsideItem title="一级菜单" icon="setting" />
|
|
|
+ </AMenuItem>
|
|
|
+ </AMenu>
|
|
|
+ <div class="aside-footer">
|
|
|
+ <div class="aside-footer-avatar"></div>
|
|
|
+ </div>
|
|
|
+ </ALayoutSider>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.aside-container {
|
|
|
+ --aside-border-radius: 18px;
|
|
|
+ --aside-padding: 12px;
|
|
|
+
|
|
|
+ background-color: var(--hvac-layout-bg);
|
|
|
+
|
|
|
+ :deep(.ant-layout-sider-children) {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.aside-menu) {
|
|
|
+ flex: 1;
|
|
|
+ border-inline-end: none;
|
|
|
+
|
|
|
+ & > .ant-menu-item,
|
|
|
+ .ant-menu-submenu-title {
|
|
|
+ padding-left: 6px !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-item,
|
|
|
+ .ant-menu-submenu-title {
|
|
|
+ width: calc(100%);
|
|
|
+ height: 36px;
|
|
|
+ padding-inline: 12px;
|
|
|
+ margin-block: 0;
|
|
|
+ margin-inline: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ line-height: 36px;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+
|
|
|
+ & > .ant-menu-submenu,
|
|
|
+ & > .ant-menu-item {
|
|
|
+ & + .ant-menu-submenu,
|
|
|
+ & + .ant-menu-item {
|
|
|
+ margin-top: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-submenu-title + .ant-menu-sub > li:first-child {
|
|
|
+ margin-top: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-submenu-arrow {
|
|
|
+ right: var(--aside-padding);
|
|
|
+
|
|
|
+ &::before,
|
|
|
+ &::after {
|
|
|
+ height: 1px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-sub.ant-menu-inline {
|
|
|
+ background: var(--antd-color-bg-base);
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-sub .ant-menu-item {
|
|
|
+ padding-left: 42px !important;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ position: absolute;
|
|
|
+ left: 15px;
|
|
|
+ height: 100%;
|
|
|
+ content: '';
|
|
|
+ border: 1px solid var(--antd-color-primary-bg-hover);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.ant-menu-item-selected::before {
|
|
|
+ border-color: var(--antd-color-primary);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-item-selected {
|
|
|
+ background-color: var(--antd-color-bg-base);
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
|
|
+ color: var(--antd-color-text-secondary);
|
|
|
+ background-color: var(--antd-color-primary-bg);
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-item:not(.ant-menu-item-selected):hover,
|
|
|
+ .ant-menu-submenu-title:hover {
|
|
|
+ color: var(--antd-color-primary);
|
|
|
+ background-color: initial;
|
|
|
+ }
|
|
|
+
|
|
|
+ & > .ant-menu-item.ant-menu-item-selected {
|
|
|
+ background-color: var(--antd-color-primary-bg);
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-menu-title-content {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.aside-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 24px var(--aside-padding) 32px;
|
|
|
+ background-color: var(--antd-color-bg-base);
|
|
|
+ border-top-left-radius: var(--aside-border-radius);
|
|
|
+ border-top-right-radius: var(--aside-border-radius);
|
|
|
+}
|
|
|
+
|
|
|
+.aside-header-logo {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ margin-right: 12px;
|
|
|
+ background-color: var(--antd-color-primary);
|
|
|
+ border-radius: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.aside-header-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 24px;
|
|
|
+ color: var(--antd-color-text);
|
|
|
+}
|
|
|
+
|
|
|
+.aside-menu {
|
|
|
+ padding: 0 var(--aside-padding);
|
|
|
+ color: var(--antd-color-text-secondary);
|
|
|
+}
|
|
|
+
|
|
|
+.aside-menu-ai-ctrl {
|
|
|
+ width: 48px;
|
|
|
+ height: 22px;
|
|
|
+ margin: 24px 0;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 22px;
|
|
|
+ color: var(--antd-color-text-secondary);
|
|
|
+ text-align: center;
|
|
|
+ background-color: var(--antd-color-primary-bg);
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.aside-footer {
|
|
|
+ height: 65px;
|
|
|
+ padding: var(--aside-padding);
|
|
|
+ padding-right: 23px;
|
|
|
+ margin-top: 2px;
|
|
|
+ background-color: var(--antd-color-bg-base);
|
|
|
+ border-bottom-right-radius: var(--aside-border-radius);
|
|
|
+ border-bottom-left-radius: var(--aside-border-radius);
|
|
|
+}
|
|
|
+
|
|
|
+.aside-footer-avatar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ background: var(--antd-color-primary);
|
|
|
+ border-radius: 50%;
|
|
|
+
|
|
|
+ // 临时使用
|
|
|
+ &::before {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 22px;
|
|
|
+ color: #fff;
|
|
|
+ content: '贾';
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|