Browse Source

feat: 支持多标签Tab页功能 (#89)

* feat: support tabs page

* chore: adjust position

* feat: add switch for tabs page

* feat: implement home tab
pull/91/head 0.1.4
yuyang 3 years ago
committed by GitHub
parent
commit
81eac4b732
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/config/style.ts
  2. 1
      src/layouts/blank.vue
  3. 20
      src/layouts/components/Content.vue
  4. 13
      src/layouts/components/SideNav.tsx
  5. 136
      src/layouts/index.tsx
  6. 3
      src/layouts/setting.vue
  7. 1
      src/pages/dashboard/base/index.vue
  8. 1
      src/pages/dashboard/detail/index.vue
  9. 2
      src/pages/detail/advanced/index.vue
  10. 2
      src/pages/detail/base/index.vue
  11. 2
      src/pages/detail/deploy/index.vue
  12. 2
      src/pages/detail/secondary/index.vue
  13. 7
      src/pages/form/base/index.vue
  14. 1
      src/pages/form/step/index.vue
  15. 2
      src/pages/list/base/index.vue
  16. 2
      src/pages/list/card/index.vue
  17. 2
      src/pages/list/filter/index.vue
  18. 2
      src/pages/list/tree/index.vue
  19. 2
      src/pages/result/403/index.vue
  20. 2
      src/pages/result/404/index.vue
  21. 2
      src/pages/result/500/index.vue
  22. 2
      src/pages/result/browser-incompatible/index.vue
  23. 2
      src/pages/result/fail/index.vue
  24. 2
      src/pages/result/network-error/index.vue
  25. 2
      src/pages/result/success/index.vue
  26. 2
      src/pages/user/index.vue
  27. 4
      src/router/modules/base.ts
  28. 34
      src/router/modules/components.ts
  29. 2
      src/router/modules/others.ts
  30. 2
      src/store/index.ts
  31. 6
      src/store/modules/setting.ts
  32. 63
      src/store/modules/tab-router.ts
  33. 22
      src/style/layout.less
  34. 1
      tsconfig.json

1
src/config/style.ts

@ -8,6 +8,7 @@ export default {
isFooterAside: false,
isSidebarFixed: true,
isHeaderFixed: true,
isUseTabsRouter: false,
showHeader: true,
backgroundTheme: 'blueGrey',
brandTheme: 'default',

1
src/layouts/blank.vue

@ -3,6 +3,7 @@
<router-view />
</div>
</template>
<style lang="less" scoped>
.tdesign-wrapper {
height: 100vh;

20
src/layouts/components/Content.vue

@ -1,8 +1,26 @@
<template>
<transition name="fade" mode="out-in">
<router-view />
<keep-alive :include="this.aliveViews">
<router-view v-if="!this.isRefreshing" />
</keep-alive>
</transition>
</template>
<script lang="ts">
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
tabRouterList: 'tabRouter/tabRouterList',
isRefreshing: 'tabRouter/isRefreshing',
isUseTabsRouter: 'setting/isUseTabsRouter',
}),
aliveViews() {
return this.tabRouterList.filter((route) => route.isAlive).map((route) => route.name);
},
},
};
</script>
<style lang="less" scoped>
@import '@/style/variables';

13
src/layouts/components/SideNav.tsx

@ -2,9 +2,10 @@ import Vue from 'vue';
import { prefix } from '@/config/global';
import MenuContent from './MenuContent';
import Logo from '@/assets/assets-t-logo.svg';
import LogoFull from '@/assets/assets-logo-full.svg';
import pgk from '../../../package.json';
import tLogo from '@/assets/assets-t-logo.svg';
import tLogoFull from '@/assets/assets-logo-full.svg';
const MIN_POINT = 992 - 1;
@ -12,8 +13,6 @@ export default Vue.extend({
name: 'sideNav',
components: {
MenuContent,
tLogo,
tLogoFull,
},
props: {
menu: Array,
@ -102,7 +101,7 @@ export default Vue.extend({
const isCompact = window.innerWidth <= MIN_POINT;
this.$store.commit('setting/showSidebarCompact', isCompact);
},
handleNav(url) {
handleNav(url: string) {
this.$router.push(url);
},
},
@ -117,9 +116,9 @@ export default Vue.extend({
onClick={() => this.handleNav('/dashboard/base')}
>
{this.collapsed ? (
<tLogo class={`${prefix}-side-nav-logo-t-logo`} />
<Logo class={`${prefix}-side-nav-logo-t-logo`} />
) : (
<t-logo-full class={`${prefix}-side-nav-logo-tdesign-logo`} />
<LogoFull class={`${prefix}-side-nav-logo-tdesign-logo`} />
)}
</span>
)}

136
src/layouts/index.tsx

@ -1,14 +1,15 @@
import Vue, { VNode } from 'vue';
import { mapGetters } from 'vuex';
import TdesignHeader from './components/Header.vue';
import TdesignBreadcrumb from './components/Breadcrumb.vue';
import TdesignFooter from './components/Footer.vue';
import TdesignSideNav from './components/SideNav';
import TdesignContent from './components/Content.vue';
import LayoutHeader from './components/Header.vue';
import LayoutBreadcrumb from './components/Breadcrumb.vue';
import LayoutFooter from './components/Footer.vue';
import LayoutSideNav from './components/SideNav';
import LayoutContent from './components/Content.vue';
import Setting from './setting.vue';
import { prefix } from '@/config/global';
import TdesignSetting from './setting.vue';
import { SettingType } from '@/interface';
import '@/style/layout.less';
const name = `${prefix}-base-layout`;
@ -16,11 +17,12 @@ const name = `${prefix}-base-layout`;
export default Vue.extend({
name,
components: {
TdesignHeader,
TdesignFooter,
TdesignSideNav,
TdesignSetting,
TdesignBreadcrumb,
LayoutHeader,
LayoutContent,
LayoutFooter,
LayoutSideNav,
LayoutBreadcrumb,
Setting,
},
computed: {
...mapGetters({
@ -30,7 +32,9 @@ export default Vue.extend({
showSidebarLogo: 'setting/showSidebarLogo',
showFooter: 'setting/showFooter',
mode: 'setting/mode',
isUseTabsRouter: 'setting/isUseTabsRouter',
menuRouters: 'permission/routers',
tabRouterList: 'tabRouter/tabRouterList',
}),
setting(): SettingType {
return this.$store.state.setting;
@ -62,7 +66,53 @@ export default Vue.extend({
return menuRouters;
},
},
watch: {
$route(newRoute) {
// 监听路由变化往多标签新增
const {
path,
meta: { title },
name,
} = newRoute;
this.$store.commit('tabRouter/appendTabRouterList', { path, title, name, isAlive: true });
},
},
mounted() {
const {
path,
meta: { title },
name,
} = this.$route;
this.$store.commit('tabRouter/appendTabRouterList', { path, title, name, isAlive: true });
},
methods: {
handleRemove(path: string, routeIdx: number) {
const nextRouter = this.tabRouterList[routeIdx + 1] || this.tabRouterList[routeIdx - 1];
this.$store.commit('tabRouter/subtractCurrentTabRouter', { path, routeIdx });
if (path === this.$router.history?.current?.path) {
this.$router.push(nextRouter.path);
}
},
handleChangeCurrentTab(path: string) {
this.$router.push(path);
},
handleRefresh(currentPath: string, routeIdx: number) {
this.$store.commit('tabRouter/toggleTabRouterAlive', routeIdx);
this.$nextTick(() => {
this.$store.commit('tabRouter/toggleTabRouterAlive', routeIdx);
this.$router.replace({ path: currentPath });
});
},
handleCloseAhead(path: string, routeIdx: number) {
this.$store.commit('tabRouter/subtractTabRouterAhead', { path, routeIdx });
},
handleCloseBehind(path: string, routeIdx: number) {
this.$store.commit('tabRouter/subtractTabRouterBehind', { path, routeIdx });
},
handleCloseOther(path: string, routeIdx: number) {
this.$store.commit('tabRouter/subtractTabRouterOther', { path, routeIdx });
},
renderSidebar(): VNode {
// const theme =
// this.setting.mode === 'dark' ? 'dark' : this.setting.layout === 'mix' ? 'light' : this.setting.theme;
@ -71,7 +121,7 @@ export default Vue.extend({
return (
this.showSidebar && (
<tdesign-side-nav
<layout-side-nav
showLogo={this.showSidebarLogo}
layout={this.setting.layout}
isFixed={this.setting.isSidebarFixed}
@ -87,7 +137,7 @@ export default Vue.extend({
const maxLevel = this.setting.splitMenu ? 1 : 3;
return (
this.showHeader && (
<tdesign-header
<layout-header
showLogo={this.showHeaderLogo}
maxLevel={maxLevel}
theme={this.mode}
@ -104,9 +154,59 @@ export default Vue.extend({
const { showFooter } = this;
return (
<t-layout class={[`${prefix}-layout`]}>
<t-tabs
theme="card"
class={`${prefix}-layout-tabs-nav`}
value={this.$route.path}
onChange={this.handleChangeCurrentTab}
style={{ maxWidth: '100%', position: 'fixed', overflow: 'visible' }}
>
{this.isUseTabsRouter &&
this.tabRouterList.map((route: { path: string; title: string; isHome: boolean }, idx: number) => (
<t-tab-panel
value={route.path}
key={`${route.path}_${idx}`}
label={() => (
<t-dropdown
trigger="context-menu"
minColumnWidth={128}
popupProps={{ overlayClassName: 'route-tabs-dropdown' }}
>
{!route.isHome ? route.title : <t-icon name="home" />}
{this.$route.path === route.path && (
<t-dropdown-menu slot="dropdown">
<t-dropdown-item onClick={() => this.handleRefresh(route.path, idx)}>
<t-icon name="refresh" />
</t-dropdown-item>
{idx > 0 && (
<t-dropdown-item onClick={() => this.handleCloseAhead(route.path, idx)}>
<t-icon name="arrow-left" />
</t-dropdown-item>
)}
{idx < this.tabRouterList.length - 1 && (
<t-dropdown-item onClick={() => this.handleCloseBehind(route.path, idx)}>
<t-icon name="arrow-right" />
</t-dropdown-item>
)}
<t-dropdown-item onClick={() => this.handleCloseOther(route.path, idx)}>
<t-icon name="close-circle" />
</t-dropdown-item>
</t-dropdown-menu>
)}
</t-dropdown>
)}
removable={!route.isHome}
onRemove={() => this.handleRemove(route.path, idx)}
></t-tab-panel>
))}
</t-tabs>
<t-content class={`${prefix}-content-layout`}>
{showBreadcrumb && <tdesign-breadcrumb />}
<TdesignContent />
{showBreadcrumb && <layout-breadcrumb />}
<layout-content />
</t-content>
{showFooter && this.renderFooter()}
</t-layout>
@ -116,7 +216,7 @@ export default Vue.extend({
renderFooter(): VNode {
return (
<t-footer class={`${prefix}-footer-layout`}>
<tdesign-footer />
<layout-footer />
</t-footer>
);
},
@ -127,7 +227,7 @@ export default Vue.extend({
const header = this.renderHeader();
const sidebar = this.renderSidebar();
const content = this.renderContent();
let renderLayout;
let renderLayout: VNode;
if (layout === 'side') {
renderLayout = (
<t-layout key="side">
@ -160,7 +260,7 @@ export default Vue.extend({
return (
<div>
{renderLayout}
<tdesign-setting />
<setting />
</div>
);
},

3
src/layouts/setting.vue

@ -82,6 +82,9 @@
<t-form-item label="显示 Footer" name="showFooter">
<t-switch v-model="formData.showFooter"></t-switch>
</t-form-item>
<t-form-item label="使用 多标签Tab页" name="isUseTabsRouter">
<t-switch v-model="formData.isUseTabsRouter"></t-switch>
</t-form-item>
<t-form-item
label="footer 内收"
name="footerPosition"

1
src/pages/dashboard/base/index.vue

@ -228,6 +228,7 @@ import { PANE_LIST, SALE_TEND_LIST, BUY_TEND_LIST, SALE_COLUMNS, BUY_COLUMNS } f
echarts.use([TooltipComponent, LegendComponent, PieChart, GridComponent, LineChart, BarChart, CanvasRenderer]);
export default {
name: 'DashboardBase',
components: {
Card,
Trend,

1
src/pages/dashboard/detail/index.vue

@ -77,6 +77,7 @@ import { changeChartsTheme, getFolderLineDataSet, getScatterDataSet } from '../b
echarts.use([GridComponent, LegendComponent, TooltipComponent, LineChart, ScatterChart, CanvasRenderer]);
export default {
name: 'DashboardDetail',
components: { Trend, Card, ProductCard },
data() {
return {

2
src/pages/detail/advanced/index.vue

@ -141,7 +141,7 @@ const PRODUCT_LIST = [
/** 高级详情 */
export default {
name: 'detail-base',
name: 'DetailAdvanced',
components: { Card, Product },
data() {
return {

2
src/pages/detail/base/index.vue

@ -32,7 +32,7 @@ import model from '@/service/service-detail-base';
import Card from '@/components/card/index.vue';
export default {
name: 'list-base',
name: 'DetailBase',
components: { Card },
data() {
return {

2
src/pages/detail/deploy/index.vue

@ -82,7 +82,7 @@ echarts.use([
/** 部署配置 */
export default {
name: 'detail-deploy',
name: 'DetailDeploy',
components: { Card },
data() {
return {

2
src/pages/detail/secondary/index.vue

@ -70,7 +70,7 @@ const TAB_LIST = [
];
export default {
name: 'list-base',
name: 'DetailSecondary',
data() {
return {
NOTIFICATION_TYPES,

7
src/pages/form/base/index.vue

@ -30,7 +30,7 @@
class="demo-select-base"
clearable
>
<t-option v-for="(item, index) in TYPE_OPTIONS" :key="index" :value="item.value" :label="item.label">
<t-option v-for="(item, index) in typeOptions" :key="index" :value="item.value" :label="item.label">
{{ item.label }}
</t-option>
</t-select>
@ -58,7 +58,7 @@
placeholder="请选择类型"
clearable
>
<t-option v-for="(item, index) in PARTY_A_OPTIONS" :key="index" :value="item.value" :label="item.label">
<t-option v-for="(item, index) in partyAOptions" :key="index" :value="item.value" :label="item.label">
{{ item.label }}
</t-option>
</t-select>
@ -73,7 +73,7 @@
class="demo-select-base"
clearable
>
<t-option v-for="(item, index) in PARTY_B_OPTIONS" :key="index" :value="item.value" :label="item.label">
<t-option v-for="(item, index) in partyBOptions" :key="index" :value="item.value" :label="item.label">
{{ item.label }}
</t-option>
</t-select>
@ -183,6 +183,7 @@ const FORM_RULES = {
};
export default {
name: 'FormBase',
data() {
return {
prefix,

1
src/pages/form/step/index.vue

@ -168,6 +168,7 @@ const INITIAL_DATA3 = {
};
export default {
name: 'FormStep',
components: { Card },
data() {
return {

2
src/pages/list/base/index.vue

@ -76,7 +76,7 @@ import { prefix } from '@/config/global';
import { CONTRACT_STATUS, CONTRACT_STATUS_OPTIONS, CONTRACT_TYPES, CONTRACT_PAYMENT_TYPES } from '@/constants';
export default Vue.extend({
name: 'list-base',
name: 'ListBase',
components: {
SearchIcon,
Trend,

2
src/pages/list/card/index.vue

@ -107,7 +107,7 @@ const INITIAL_DATA = {
amount: 0,
};
export default {
name: 'list-card',
name: 'ListCard',
components: {
SearchIcon,
Card,

2
src/pages/list/filter/index.vue

@ -7,7 +7,7 @@
import CommonTable from '../components/CommonTable.vue';
export default {
name: 'list-base',
name: 'ListFilter',
components: {
CommonTable,
},

2
src/pages/list/tree/index.vue

@ -18,7 +18,7 @@ import { SearchIcon } from 'tdesign-icons-vue';
import CommonTable from '../components/CommonTable.vue';
export default {
name: 'list-base',
name: 'ListTree',
components: {
SearchIcon,
CommonTable,

2
src/pages/result/403/index.vue

@ -8,7 +8,7 @@
import result from '@/components/result/index.vue';
export default {
name: 'result-403',
name: 'Result403',
components: { result },
};
</script>

2
src/pages/result/404/index.vue

@ -8,7 +8,7 @@
import result from '@/components/result/index.vue';
export default {
name: 'result-404',
name: 'Result404',
components: { result },
};
</script>

2
src/pages/result/500/index.vue

@ -8,7 +8,7 @@
import result from '@/components/result/index.vue';
export default {
name: 'result-500',
name: 'Result500',
components: { result },
};
</script>

2
src/pages/result/browser-incompatible/index.vue

@ -24,7 +24,7 @@ import Result from '@/components/result/index.vue';
import Thumbnail from '@/components/thumbnail/index.vue';
export default {
name: 'result-browser-incompatible',
name: 'ResultBrowserIncompatible',
components: { Result, Thumbnail },
};
</script>

2
src/pages/result/fail/index.vue

@ -12,7 +12,7 @@
<script>
export default {
name: 'result-fail',
name: 'ResultFail',
};
</script>

2
src/pages/result/network-error/index.vue

@ -11,7 +11,7 @@
import result from '@/components/result/index.vue';
export default {
name: 'result-network-error',
name: 'ResultNetworkError',
components: { result },
};
</script>

2
src/pages/result/success/index.vue

@ -12,7 +12,7 @@
<script>
export default {
name: 'result-success',
name: 'ResultSuccess',
};
</script>

2
src/pages/user/index.vue

@ -121,6 +121,8 @@ import Card from '@/components/card/index.vue';
echarts.use([GridComponent, TooltipComponent, LineChart, CanvasRenderer, LegendComponent]);
export default {
name: 'UserIndex',
components: {
Card,
ProductAIcon,

4
src/router/modules/base.ts

@ -11,13 +11,13 @@ export default [
children: [
{
path: 'base',
name: 'dashboardBase',
name: 'DashboardBase',
component: () => import('@/pages/dashboard/base/index.vue'),
meta: { title: '概览仪表盘' },
},
{
path: 'detail',
name: 'dashboardDetail',
name: 'DashboardDetail',
component: () => import('@/pages/dashboard/detail/index.vue'),
meta: { title: '统计报表' },
},

34
src/router/modules/components.ts

@ -13,25 +13,25 @@ export default [
children: [
{
path: 'base',
name: 'listBase',
name: 'ListBase',
component: () => import('@/pages/list/base/index.vue'),
meta: { title: '基础列表页' },
},
{
path: 'card',
name: 'listCard',
name: 'ListCard',
component: () => import('@/pages/list/card/index.vue'),
meta: { title: '卡片列表页' },
},
{
path: 'filter',
name: 'listFilter',
name: 'ListFilter',
component: () => import('@/pages/list/filter/index.vue'),
meta: { title: '筛选列表页' },
},
{
path: 'tree',
name: 'listTree',
name: 'ListTree',
component: () => import('@/pages/list/tree/index.vue'),
meta: { title: '树状筛选列表页' },
},
@ -46,13 +46,13 @@ export default [
children: [
{
path: 'base',
name: 'formBase',
name: 'FormBase',
component: () => import('@/pages/form/base/index.vue'),
meta: { title: '基础表单页' },
},
{
path: 'step',
name: 'formStep',
name: 'FormStep',
component: () => import('@/pages/form/step/index.vue'),
meta: { title: '分步表单页' },
},
@ -67,25 +67,25 @@ export default [
children: [
{
path: 'base',
name: 'detailBase',
name: 'DetailBase',
component: () => import('@/pages/detail/base/index.vue'),
meta: { title: '基础详情页' },
},
{
path: 'advanced',
name: 'detailAdvanced',
name: 'DetailAdvanced',
component: () => import('@/pages/detail/advanced/index.vue'),
meta: { title: '多卡片详情页' },
},
{
path: 'deploy',
name: 'detailDeploy',
name: 'DetailDeploy',
component: () => import('@/pages/detail/deploy/index.vue'),
meta: { title: '数据详情页' },
},
{
path: 'secondary',
name: 'detailSecondary',
name: 'DetailSecondary',
component: () => import('@/pages/detail/secondary/index.vue'),
meta: { title: '二级详情页' },
},
@ -100,43 +100,43 @@ export default [
children: [
{
path: 'success',
name: 'resultSuccess',
name: 'ResultSuccess',
component: () => import('@/pages/result/success/index.vue'),
meta: { title: '成功页' },
},
{
path: 'fail',
name: 'resultFail',
name: 'ResultFail',
component: () => import('@/pages/result/fail/index.vue'),
meta: { title: '失败页' },
},
{
path: 'network-error',
name: 'warningNetworkError',
name: 'ResultNetworkError',
component: () => import('@/pages/result/network-error/index.vue'),
meta: { title: '网络异常' },
},
{
path: '403',
name: 'warning403',
name: 'Result403',
component: () => import('@/pages/result/403/index.vue'),
meta: { title: '无权限' },
},
{
path: '404',
name: 'warning404',
name: 'Result404',
component: () => import('@/pages/result/404/index.vue'),
meta: { title: '访问页面不存在页' },
},
{
path: '500',
name: 'warning500',
name: 'Result500',
component: () => import('@/pages/result/500/index.vue'),
meta: { title: '服务器出错页' },
},
{
path: 'browser-incompatible',
name: 'warningBrowserIncompatible',
name: 'ResultBrowserIncompatible',
component: () => import('@/pages/result/browser-incompatible/index.vue'),
meta: { title: '浏览器不兼容页' },
},

2
src/router/modules/others.ts

@ -11,7 +11,7 @@ export default [
children: [
{
path: 'index',
name: 'userIndex',
name: 'UserIndex',
component: () => import('@/pages/user/index.vue'),
meta: { title: '个人中心' },
},

2
src/store/index.ts

@ -4,6 +4,7 @@ import user from './modules/user';
import notification from './modules/notification';
import setting from './modules/setting';
import permission from './modules/permission';
import tabRouter from './modules/tab-router'; // 多标签管理
Vue.use(Vuex);
@ -14,6 +15,7 @@ const store = new Vuex.Store({
setting,
notification,
permission,
tabRouter,
},
});

6
src/store/modules/setting.ts

@ -32,14 +32,17 @@ const mutations = {
state.showHeader = payload.showHeader;
state.backgroundTheme = payload.backgroundTheme;
state.brandTheme = payload.brandTheme;
state.isUseTabsRouter = payload.isUseTabsRouter;
},
toggleSidebarCompact(state: IStateType) {
state.isSidebarCompact = !state.isSidebarCompact;
},
toggleUseTabsRouter(state: IStateType) {
state.isUseTabsRouter = !state.isUseTabsRouter;
},
showSidebarCompact(state: IStateType, payload: boolean) {
state.isSidebarCompact = payload;
},
toggleSettingPanel(state: IStateType, payload: boolean) {
state.showSettingPanel = payload;
},
@ -57,6 +60,7 @@ const getters = {
showSidebarLogo: (state: IStateType) => state.layout === 'side',
showHeaderLogo: (state: IStateType) => state.layout !== 'side',
showFooter: (state: IStateType) => state.showFooter,
isUseTabsRouter: (state: IStateType) => state.isUseTabsRouter,
mode: (state: IStateType) => {
if (state.mode === 'auto') {
const media = window.matchMedia('(prefers-color-scheme:dark)');

63
src/store/modules/tab-router.ts

@ -0,0 +1,63 @@
export type TRouterInfo = {
path: string;
routeIdx: number;
name?: string;
isAlive?: boolean;
isHome?: boolean;
};
export type TTabRouterType = {
isRefreshing: boolean;
tabRouterList: Array<TRouterInfo>;
};
const state: TTabRouterType = {
tabRouterList: [{ path: '/dashboard/base', routeIdx: 0, name: '仪表盘', isHome: true }],
isRefreshing: false,
};
const mutations = {
toggleTabRouterAlive(state: TTabRouterType, routeIdx: number) {
state.isRefreshing = !state.isRefreshing;
state.tabRouterList[routeIdx].isAlive = !state.tabRouterList[routeIdx].isAlive;
},
appendTabRouterList(state: TTabRouterType, newRoute: TRouterInfo) {
if (!state.tabRouterList.find((route: TRouterInfo) => route.path === newRoute.path))
// eslint-disable-next-line no-param-reassign
state.tabRouterList = state.tabRouterList.concat(newRoute);
},
subtractCurrentTabRouter(state: TTabRouterType, newRoute: TRouterInfo) {
const { routeIdx } = newRoute;
state.tabRouterList = state.tabRouterList.slice(0, routeIdx).concat(state.tabRouterList.slice(routeIdx + 1));
},
subtractTabRouterBehind(state: TTabRouterType, newRoute: TRouterInfo) {
const { routeIdx } = newRoute;
state.tabRouterList = state.tabRouterList.slice(0, routeIdx + 1);
},
subtractTabRouterAhead(state: TTabRouterType, newRoute: TRouterInfo) {
const { routeIdx } = newRoute;
state.tabRouterList = state.tabRouterList.slice(routeIdx);
},
subtractTabRouterOther(state: TTabRouterType, newRoute: TRouterInfo) {
const { routeIdx } = newRoute;
state.tabRouterList = [state.tabRouterList?.[routeIdx]];
},
removeTabRouterList() {
state.tabRouterList = [];
},
};
const getters = {
tabRouterList: (state: TTabRouterType) => state.tabRouterList,
isRefreshing: (state: TTabRouterType) => state.isRefreshing,
};
const actions = {};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};

22
src/style/layout.less

@ -65,13 +65,23 @@
}
}
&-content-layout {
padding: @spacer-3;
}
&-layout {
height: calc(100vh - 64px);
overflow-y: scroll;
}
&-content-layout {
padding: @spacer-3;
&-tabs-nav {
max-width: 100%;
position: fixed;
overflow: visible;
z-index: 999;
}
&-tabs-nav + .@{prefix}-content-layout {
padding-top: 48px + @spacer-3;
}
}
&-footer-layout {
@ -160,6 +170,12 @@
}
}
.route-tabs-dropdown {
.t-icon {
margin-right: 8px;
}
}
.logo-container {
cursor: pointer;
display: inline-flex;

1
tsconfig.json

@ -13,6 +13,7 @@
"strictNullChecks": false,
"skipLibCheck": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"jsx": "preserve",
"noEmit": true,
"baseUrl": "./",

Loading…
Cancel
Save