index.vue 3.52 KB
<template>
  <a-layout class="layout">
    <div class="layout-navbar">
      <Navbar />
    </div>
    <a-layout>
      <a-layout>
        <a-layout-sider
          v-if="menu"
          :breakpoint="'xl'"
          :collapsed="collapse"
          :collapsible="true"
          :hide-trigger="true"
          :style="{ paddingTop: '60px' }"
          :width="menuWidth"
          class="layout-sider"
          @collapse="setCollapsed"
        >
          <div class="menu-wrapper">
            <Menu />
          </div>
        </a-layout-sider>
        <a-layout :style="paddingStyle" class="layout-content">
          <a-layout-content>
            <router-view />
          </a-layout-content>
        </a-layout>
      </a-layout>
    </a-layout>
  </a-layout>
</template>

<script lang="ts">
import { computed, defineComponent, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useAppStore, useAuthorizedStore } from "@/store";
import usePermission from "@/hooks/permission";
import Menu from "@/layout/components/menu.vue";
import Navbar from "@/layout/components/navbar.vue";

export default defineComponent({
  // eslint-disable-next-line vue/no-reserved-component-names
  components: { Navbar, Menu },
  setup() {
    const appStore = useAppStore();
    const authorizedStore = useAuthorizedStore();
    const router = useRouter();
    const route = useRoute();
    const permission = usePermission();
    const navbarHeight = `60px`;
    const menu = computed(() => appStore.menu);
    const menuWidth = computed(() => {
      return appStore.menuCollapse ? 48 : appStore.menuWidth;
    });
    const collapse = computed(() => {
      return appStore.menuCollapse;
    });
    const paddingStyle = computed(() => {
      const paddingLeft = menu.value ? { paddingLeft: `${menuWidth.value}px` } : {};
      const paddingTop = { paddingTop: navbarHeight };
      return { ...paddingLeft, ...paddingTop };
    });
    const setCollapsed = (val: boolean) => {
      appStore.updateSettings({ menuCollapse: val });
    };
    watch(
      () => authorizedStore.permissions,
      (roleValue) => {
        if (roleValue && !permission.accessRouter(route)) router.push({ name: "notFound" });
      }
    );
    return {
      menu,
      menuWidth,
      paddingStyle,
      collapse,
      setCollapsed
    };
  }
});
</script>

<style lang="less" scoped>
@nav-size-height: 60px;
@layout-max-width: 1100px;

.layout {
  width: 100%;
  height: 100%;
}

.layout-navbar {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  width: 100%;
  min-width: @layout-max-width;
  height: @nav-size-height;
}

.layout-sider {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 99;
  height: 100%;

  &::after {
    position: absolute;
    top: 0;
    right: -1px;
    display: block;
    width: 1px;
    height: 100%;
    background-color: var(--color-border);
    content: '';
  }

  > :deep(.arco-layout-sider-children) {
    overflow-y: hidden;
  }
}

.menu-wrapper {
  height: 100%;
  overflow: auto;
  overflow-x: hidden;

  :deep(.arco-menu) {
    ::-webkit-scrollbar {
      width: 12px;
      height: 4px;
    }

    ::-webkit-scrollbar-thumb {
      border: 4px solid transparent;
      background-clip: padding-box;
      border-radius: 7px;
      background-color: var(--color-text-4);
    }

    ::-webkit-scrollbar-thumb:hover {
      background-color: var(--color-text-3);
    }
  }
}

.layout-content {
  min-width: @layout-max-width;
  min-height: 100vh;
  overflow-y: hidden;
  background-color: var(--color-fill-2);
  transition: padding-left 0.2s;
}
</style>