UNPKG

egg-jianghu

Version:
307 lines (287 loc) 10.1 kB
<template id="jhLayout"> <v-app id="inspire" mobile-breakpoint="sm"> <div v-if="layoutLoading" class="text-center mt-10"> <v-progress-circular :size="70" :width="7" color="success" indeterminate ></v-progress-circular> </div> <template v-else> <v-navigation-drawer v-model="drawer" app clipped v-if="isMobile" > <v-list> <v-list-item-group v-model="selectedItem" color="success" > <v-list-item v-for="item in inMenuList" :class="{'pa-2': !isMobile}" :key="item.path" @click="jump(item.path, item.query)" > <v-list-item-content :class="{'pl-3': isMobile, 'pa-0': isMobile}"> <v-list-item-title :style="{'font-weight': isMobile ? 'bold' : 'normal'}"> {{ item.title }} </v-list-item-title> </v-list-item-content> </v-list-item> </v-list-item-group> </v-list> </v-navigation-drawer> <v-app-bar app color="secondary" clipped-left dark height="55" flat > <v-app-bar-nav-icon @click.stop="drawer = !drawer" v-if="isMobile"></v-app-bar-nav-icon> <v-toolbar-title ref="toolbarTitle" class="mr-8 align-center" style="font-size: 14px" :style="{'flex': isMobile ? 1 : 'none'}"> <span class="title" style="font-size: 1rem!important;">{{ appTitle }}</span> </v-toolbar-title> <v-tabs v-model="selectedItem" v-if="!isMobile" show-arrows slider-size="5" :style="{maxWidth: tabsMaxWidth}" > <v-tabs-slider color="success"></v-tabs-slider> <template v-for="item in inMenuList"> <v-tab class="pl-3 pr-3" :key="item.path" @click="jump(item.path, item.query)" > {{ item.title }} </v-tab> <v-divider style="max-height: 35px;min-height: 35px;align-self: center;" v-if="item.path.includes('operationManual')" vertical ></v-divider> </template> </v-tabs> <div style="white-space: nowrap"> <v-menu offset-y> <template v-slot:activator="{ on }"> <template v-if="!isMobile"> <v-btn disabled text class="ml-1 text-none" style="color: #ffffff!important;" v-on="on"> {{ userInfo.user.username }} </v-btn> </template> <v-btn icon small class="ml-1" v-on="on"> <v-icon>mdi-account-circle</v-icon> </v-btn> </template> <v-list nav dense> <v-list-item class="mt-2" > <v-list-item-icon class="mr-2"> <v-icon>mdi-account</v-icon> </v-list-item-icon> <v-list-item-content> <v-list-item-title>{{ userInfo.user.userId }}</v-list-item-title> <v-list-item-subtitle>{{ userInfo.user.username }}</v-list-item-subtitle> </v-list-item-content> </v-list-item> <v-list-item v-for="(item, index) in profileMenus" :key="index" :href="item.path" class="mt-2" > <v-list-item-icon> <v-icon>{{ item.icon }}</v-icon> </v-list-item-icon> <v-list-item-content> <v-list-item-title>{{ item.title }}</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item v-for="avatarMenu of inAvatarMenuList" :key="avatarMenu.path" :href="avatarMenu.path"> <v-list-item-icon class="mr-2"> <v-icon>mdi-account-cog-outline</v-icon> </v-list-item-icon> <v-list-item-content> <v-list-item-title>{{ avatarMenu.title }}</v-list-item-title> </v-list-item-content> </v-list-item> <v-list-item @click="logout"> <v-list-item-icon class="mr-2"> <v-icon>mdi-logout</v-icon> </v-list-item-icon> <v-list-item-content> <v-list-item-title>登出</v-list-item-title> </v-list-item-content> </v-list-item> </v-list> </v-menu> </div> </v-app-bar> <v-main> <slot></slot> </v-main> </template> </v-app> </template> <!--jhLayout.html start--> <script> Vue.component("jh-layout", { vuetify: new Vuetify(), name: 'jh-layout', props: {}, data: () => ({ // 是否与登录 layoutLoading: true, selectedItem: -1, selectItemTitle: '', drawer: null, appDirectoryLink: '<$ ctx.app.config.appDirectoryLink $>', appType: '<$ ctx.app.config.appType $>', appTitle: '<$ ctx.app.config.appTitle $>', userInfo: { user: {} }, // 用户菜单 inMenuList: [], inAvatarMenuList: [], profileMenus: [], tabsMaxWidth: 'calc(100vw - 320px)' }), watch: {}, computed: { isMobile() { return window.innerWidth < 600; } }, async created() { await this.getLoginUserInfo(); this.computedMenuList(); this.locateCurrentMenuItem(); this.getTabsMaxWidth(); }, methods: { // 动态计算菜单栏目的最大宽度,按照实际的标题宽度计算 getTabsMaxWidth() { this.$nextTick(() => { if(this.$refs.toolbarTitle) { this.tabsMaxWidth = 'calc(100vw - ' + (this.$refs.toolbarTitle.offsetWidth + 200) + 'px)'; } }) }, // 跳转链接 jump(url, queryParams) { if (queryParams) { const queryStrings = Object.keys(queryParams) .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(queryParams[k])) .join('&'); window.location.href = url + '?' + queryStrings; } else { window.location.href = url; } }, // 定位当前页面在属于哪个菜单 locateCurrentMenuItem() { // 遍历菜单 path 进行匹配 const index = _.findIndex(this.inMenuList, {path: location.pathname}); if (index > -1) { // 设置标题、菜单选中 this.selectedItem = index; this.selectItemTitle = this.inMenuList[index].title; document.title = this.appTitle + (this.selectItemTitle ? " - " + this.selectItemTitle : "") } }, // 获取用户信息 async getLoginUserInfo() { const userInfo = await window.jianghuAxios({ data: { appData: { pageId: 'allPage', actionId: 'userInfo', actionData: {}, } } }).then(response => { return response.data.appData.resultData; }) this.userInfo = userInfo; this.$emit('layoutData', { userInfo: this.userInfo }) this.layoutLoading = false; }, computedMenuList() { const urlPathList = window.location.pathname.split('/'); const currentPageId = urlPathList && urlPathList[urlPathList.length - 1]; const appType = '<$ ctx.app.config.appType $>'; const urlParams = new URLSearchParams(location.search); let title = urlParams.get('title'); // 处理过长的 title if (title && title.length > 10) { title = `${title.slice(0, 5)}...${title.slice(title.length - 4, title.length)}` } this.inMenuList = _ .chain(this.userInfo.allowPageList) .filter(page => page.pageType === 'showInMenu' || (_.includes(['dynamicInMenu', 'avatarInMenu'], page.pageType) && currentPageId === page.pageId)) .map((page) => { return { path: `/${window.appInfo.appId}/page/${page.pageId}`, title: title && page.pageType === 'dynamicInMenu' ? `${page.pageName}${title}】` : page.pageName, sort: parseInt(page.sort) }; }) .orderBy(['sort'], ['asc']) .value(); if (appType === 'multiApp' && this.appDirectoryLink) { console.log(this.appDirectoryLink) this.inMenuList.unshift({ path: this.appDirectoryLink, title: '回到目录' }); } this.inAvatarMenuList = _ .chain(this.userInfo.allowPageList) .filter(['pageType', 'showInAvatarMenu']) .map((page) => { return { path: `/${window.appInfo.appId}/page/${page.pageId}`, title: page.pageName, sort: parseInt(page.sort) }; }) .orderBy(['sort'], ['asc']) .value(); }, // 登出 async logout() { try { await window.jianghuAxios({ data: { appData: { pageId: 'allPage', actionId: 'logout' } } }) vtoast.success('注销成功'); localStorage.removeItem(`${window.appInfo.appId}_authToken`); setTimeout(() => { location.href = `/${window.appInfo.appId}/page/login`; }, 700); } catch (error) { vtoast.fail(error.errorReason); localStorage.removeItem(`${window.appInfo.appId}_authToken`); setTimeout(() => { location.href = `/${window.appInfo.appId}/page/login`; }, 700); } } }, template: '#jhLayout', }) </script> <!--jhLayout.html end-->