|
@@ -0,0 +1,211 @@
|
|
|
+<script lang="tsx">
|
|
|
+import { usePermissionStore } from '@/store/modules/permission'
|
|
|
+import { useAppStore } from '@/store/modules/app'
|
|
|
+import { computed, unref, defineComponent, watch, ref } from 'vue'
|
|
|
+import { useI18n } from '@/hooks/web/useI18n'
|
|
|
+import { ElScrollbar } from 'element-plus'
|
|
|
+import { Icon } from '@/components/Icon'
|
|
|
+import { Menu } from '@/components/Menu'
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
+import { pathResolve } from '@/utils/routerHelper'
|
|
|
+import { cloneDeep } from 'lodash-es'
|
|
|
+import { filterMenusPath, initTabMap, tabPathMap } from './helper'
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'TabMenu',
|
|
|
+ setup() {
|
|
|
+ const { push, currentRoute } = useRouter()
|
|
|
+
|
|
|
+ const { t } = useI18n()
|
|
|
+
|
|
|
+ const appStore = useAppStore()
|
|
|
+
|
|
|
+ const collapse = computed(() => appStore.getCollapse)
|
|
|
+
|
|
|
+ const permissionStore = usePermissionStore()
|
|
|
+
|
|
|
+ const routers = computed(() => permissionStore.getRouters)
|
|
|
+
|
|
|
+ const tabRouters = computed(() => unref(routers).filter((v) => !v?.meta?.hidden))
|
|
|
+
|
|
|
+ const setCollapse = () => {
|
|
|
+ appStore.setCollapse(!unref(collapse))
|
|
|
+ }
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => routers.value,
|
|
|
+ (routers: AppRouteRecordRaw[]) => {
|
|
|
+ initTabMap(routers)
|
|
|
+ filterMenusPath(routers, routers)
|
|
|
+ console.log(tabPathMap)
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true,
|
|
|
+ deep: true
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ const showTitle = ref(true)
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => collapse.value,
|
|
|
+ (collapse: boolean) => {
|
|
|
+ if (!collapse) {
|
|
|
+ setTimeout(() => {
|
|
|
+ showTitle.value = !collapse
|
|
|
+ }, 200)
|
|
|
+ } else {
|
|
|
+ showTitle.value = !collapse
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ // 是否显示菜单
|
|
|
+ const showMenu = ref(false)
|
|
|
+
|
|
|
+ // tab高亮
|
|
|
+ const tabActive = ref('')
|
|
|
+
|
|
|
+ // tab点击事件
|
|
|
+ const tabClick = (item: AppRouteRecordRaw) => {
|
|
|
+ tabActive.value = item.children ? item.path : item.path.split('/')[0]
|
|
|
+ if (item.children) {
|
|
|
+ showMenu.value = !unref(showMenu)
|
|
|
+ if (unref(showMenu)) {
|
|
|
+ permissionStore.setMenuTabRouters(
|
|
|
+ cloneDeep(item.children).map((v) => {
|
|
|
+ v.path = pathResolve(unref(tabActive), v.path)
|
|
|
+ return v
|
|
|
+ })
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ push(item.path)
|
|
|
+ permissionStore.setMenuTabRouters([])
|
|
|
+ showMenu.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置高亮
|
|
|
+ const isActice = (currentPath: string) => {
|
|
|
+ const { path } = unref(currentRoute)
|
|
|
+ if (tabPathMap[currentPath].includes(path)) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ const mouseleave = () => {
|
|
|
+ if (!unref(showMenu)) return
|
|
|
+ showMenu.value = false
|
|
|
+ }
|
|
|
+
|
|
|
+ return () => (
|
|
|
+ <div
|
|
|
+ class={[
|
|
|
+ 'v-tab-menu relative bg-[var(--left-menu-bg-color)] top-1px',
|
|
|
+ {
|
|
|
+ 'w-[var(--tab-menu-max-width)]': !unref(collapse),
|
|
|
+ 'w-[var(--tab-menu-min-width)]': unref(collapse)
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ onMouseleave={mouseleave}
|
|
|
+ >
|
|
|
+ <ElScrollbar class="!h-[calc(100%-var(--tab-menu-collapse-height)-1px)]">
|
|
|
+ <div>
|
|
|
+ {() => {
|
|
|
+ return unref(tabRouters).map((v) => {
|
|
|
+ const item = (
|
|
|
+ v?.children?.length && v?.children?.length > 1
|
|
|
+ ? v
|
|
|
+ : {
|
|
|
+ ...(v?.children && v?.children[0]),
|
|
|
+ path: pathResolve(v.path, (v?.children && v?.children[0])?.path as string)
|
|
|
+ }
|
|
|
+ ) as AppRouteRecordRaw
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ class={[
|
|
|
+ 'v-tab-menu-item text-center text-12px relative py-12px cursor-pointer',
|
|
|
+ {
|
|
|
+ 'is-active': isActice(v.path)
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ onClick={() => {
|
|
|
+ tabClick(item)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <Icon icon={item?.meta?.icon}></Icon>
|
|
|
+ </div>
|
|
|
+ {!unref(showTitle) ? undefined : (
|
|
|
+ <p class="break-words mt-5px px-2px">{t(item.meta?.title)}</p>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ })
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ </ElScrollbar>
|
|
|
+ <div
|
|
|
+ class="v-tab-menu-collapse text-center h-[var(--tab-menu-collapse-height)] leading-[var(--tab-menu-collapse-height)] cursor-pointer"
|
|
|
+ onClick={setCollapse}
|
|
|
+ >
|
|
|
+ <Icon icon={unref(collapse) ? 'ep:d-arrow-right' : 'ep:d-arrow-left'}></Icon>
|
|
|
+ </div>
|
|
|
+ <Menu
|
|
|
+ class={[
|
|
|
+ '!absolute top-0 border-left-1 border-solid border-[var(--left-menu-bg-light-color)]',
|
|
|
+ {
|
|
|
+ '!left-[var(--tab-menu-min-width)]': unref(collapse),
|
|
|
+ '!left-[var(--tab-menu-max-width)]': !unref(collapse),
|
|
|
+ '!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu),
|
|
|
+ '!w-0': !unref(showMenu)
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ style="transition: width var(--transition-time-02), left var(--transition-time-02);"
|
|
|
+ ></Menu>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+@prefix-cls: ~'@{namespace}-tab-menu';
|
|
|
+
|
|
|
+.@{prefix-cls} {
|
|
|
+ transition: all var(--transition-time-02);
|
|
|
+
|
|
|
+ &:after {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ width: 1px;
|
|
|
+ height: 100%;
|
|
|
+ border-left: 1px solid var(--left-menu-border-color);
|
|
|
+ content: '';
|
|
|
+ }
|
|
|
+
|
|
|
+ &-item {
|
|
|
+ color: var(--left-menu-text-color);
|
|
|
+ transition: all var(--transition-time-02);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: var(--left-menu-text-active-color);
|
|
|
+ // background-color: var(--left-menu-bg-active-color);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-collapse {
|
|
|
+ color: var(--left-menu-text-color);
|
|
|
+ background-color: var(--left-menu-bg-light-color);
|
|
|
+ border-top: 1px solid var(--left-menu-border-color);
|
|
|
+ }
|
|
|
+
|
|
|
+ .is-active {
|
|
|
+ color: var(--left-menu-text-active-color);
|
|
|
+ background-color: var(--left-menu-bg-active-color);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|