+
{meta && titleT(meta.title)}
);
@@ -49,7 +40,7 @@ export default defineComponent({
name: 'TabContent',
props: {
tabItem: {
- type: Object as PropType
,
+ type: Object as PropType,
default: null,
},
@@ -59,36 +50,27 @@ export default defineComponent({
},
},
setup(props) {
- const { t } = useI18n();
- const { getShowMenu } = useMenuSetting();
- const { getShowHeader } = useHeaderSetting();
- const { getShowQuick } = useMultipleTabSetting();
-
- const getIsScale = computed(() => {
- return !unref(getShowMenu) && !unref(getShowHeader);
- });
-
- const getIsTab = computed(() => {
- return !unref(getShowQuick) ? true : props.type === TabContentEnum.TAB_TYPE;
- });
-
- const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps);
+ const {
+ getDropMenuList,
+ handleMenuEvent,
+ handleContextMenu,
+ getTrigger,
+ isTabs,
+ } = useTabDropdown(props as TabContentProps);
return () => {
- const scaleAction = getScaleAction(
- unref(getIsScale) ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
- unref(getIsScale)
- );
- const dropMenuList = unref(getDropMenuList) || [];
-
- const isTab = unref(getIsTab);
return (
- {() => (isTab ? : )}
+ {() => {
+ if (!unref(isTabs)) {
+ return ;
+ }
+ return ;
+ }}
);
};
diff --git a/src/layouts/default/multitabs/data.ts b/src/layouts/default/multitabs/data.ts
deleted file mode 100644
index 22bc0d6a..00000000
--- a/src/layouts/default/multitabs/data.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { DropMenu } from '/@/components/Dropdown/index';
-import { AppRouteRecordRaw } from '/@/router/types';
-import type { TabItem } from '/@/store/modules/tab';
-
-import { useI18n } from '/@/hooks/web/useI18n';
-
-const { t } = useI18n();
-
-export enum TabContentEnum {
- TAB_TYPE,
- EXTRA_TYPE,
-}
-
-export interface TabContentProps {
- tabItem: TabItem | AppRouteRecordRaw;
- type?: TabContentEnum;
- trigger?: Array<'click' | 'hover' | 'contextmenu'>;
-}
-
-/**
- * @description: 右键:下拉菜单文字
- */
-export enum MenuEventEnum {
- // 刷新
- REFRESH_PAGE,
- // 关闭当前
- CLOSE_CURRENT,
- // 关闭左侧
- CLOSE_LEFT,
- // 关闭右侧
- CLOSE_RIGHT,
- // 关闭其他
- CLOSE_OTHER,
- // 关闭所有
- CLOSE_ALL,
- // 放大
- SCALE,
-}
-
-export function getActions() {
- const REFRESH_PAGE: DropMenu = {
- icon: 'ant-design:reload-outlined',
- event: MenuEventEnum.REFRESH_PAGE,
- text: t('layout.multipleTab.redo'),
- disabled: false,
- };
- const CLOSE_CURRENT: DropMenu = {
- icon: 'ant-design:close-outlined',
- event: MenuEventEnum.CLOSE_CURRENT,
- text: t('layout.multipleTab.close'),
- disabled: false,
- divider: true,
- };
- const CLOSE_LEFT: DropMenu = {
- icon: 'ant-design:pic-left-outlined',
- event: MenuEventEnum.CLOSE_LEFT,
- text: t('layout.multipleTab.closeLeft'),
- disabled: false,
- divider: false,
- };
- const CLOSE_RIGHT: DropMenu = {
- icon: 'ant-design:pic-right-outlined',
- event: MenuEventEnum.CLOSE_RIGHT,
- text: t('layout.multipleTab.closeRight'),
- disabled: false,
- divider: true,
- };
- const CLOSE_OTHER: DropMenu = {
- icon: 'ant-design:pic-center-outlined',
- event: MenuEventEnum.CLOSE_OTHER,
- text: t('layout.multipleTab.closeOther'),
- disabled: false,
- };
- const CLOSE_ALL: DropMenu = {
- icon: 'ant-design:line-outlined',
- event: MenuEventEnum.CLOSE_ALL,
- text: t('layout.multipleTab.closeAll'),
- disabled: false,
- };
- return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL];
-}
-
-export function getScaleAction(text: string, isZoom = false) {
- return {
- icon: isZoom ? 'codicon:screen-normal' : 'codicon:screen-full',
- event: MenuEventEnum.SCALE,
- text: text,
- disabled: false,
- };
-}
diff --git a/src/layouts/default/multitabs/index.tsx b/src/layouts/default/multitabs/index.tsx
index 2b5cbe51..0fddad6b 100644
--- a/src/layouts/default/multitabs/index.tsx
+++ b/src/layouts/default/multitabs/index.tsx
@@ -1,12 +1,8 @@
import './index.less';
-import type { TabContentProps } from './data';
-import type { TabItem } from '/@/store/modules/tab';
-import type { AppRouteRecordRaw } from '/@/router/types';
-
-import { defineComponent, watch, computed, unref, ref, onMounted, nextTick } from 'vue';
-import Sortable from 'sortablejs';
+import type { TabContentProps } from './types';
+import { defineComponent, watch, computed, unref, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Tabs } from 'ant-design-vue';
@@ -14,15 +10,12 @@ import TabContent from './TabContent';
import { useGo } from '/@/hooks/web/usePage';
-import { TabContentEnum } from './data';
+import { TabContentEnum } from './types';
import { tabStore } from '/@/store/modules/tab';
import { userStore } from '/@/store/modules/user';
-import { closeTab } from './useTabDropdown';
-import { initAffixTabs } from './useMultipleTabs';
-import { isNullAndUnDef } from '/@/utils/is';
-import { useProjectSetting } from '/@/hooks/setting';
+import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
export default defineComponent({
name: 'MultipleTabs',
@@ -31,28 +24,25 @@ export default defineComponent({
const affixTextList = initAffixTabs();
- const go = useGo();
+ useTabsDrag(affixTextList);
- const { multiTabsSetting } = useProjectSetting();
+ const go = useGo();
const { currentRoute } = useRouter();
const getTabsState = computed(() => tabStore.getTabsState);
- // If you monitor routing changes, tab switching will be stuck. So setting this method
watch(
- () => tabStore.getLastChangeRouteState,
+ () => tabStore.getLastChangeRouteState?.path,
() => {
const lastChangeRoute = unref(tabStore.getLastChangeRouteState);
-
if (!lastChangeRoute || !userStore.getTokenState) return;
-
- const { path, fullPath } = lastChangeRoute as AppRouteRecordRaw;
+ const { path, fullPath } = lastChangeRoute;
const p = fullPath || path;
if (activeKeyRef.value !== p) {
activeKeyRef.value = p;
}
- tabStore.commitAddTab(lastChangeRoute);
+ tabStore.addTabAction(lastChangeRoute);
},
{
immediate: true,
@@ -67,22 +57,19 @@ export default defineComponent({
// Close the current tab
function handleEdit(targetKey: string) {
// Added operation to hide, currently only use delete operation
- const index = unref(getTabsState).findIndex(
- (item) => (item.fullPath || item.path) === targetKey
- );
- index !== -1 && closeTab(unref(getTabsState)[index]);
+ tabStore.closeTabByKeyAction(targetKey);
}
function renderQuick() {
const tabContentProps: TabContentProps = {
- tabItem: (currentRoute as unknown) as AppRouteRecordRaw,
+ tabItem: currentRoute.value,
type: TabContentEnum.EXTRA_TYPE,
};
- return ;
+ return ;
}
function renderTabs() {
- return unref(getTabsState).map((item: TabItem) => {
+ return unref(getTabsState).map((item) => {
const key = item.query ? item.fullPath : item.path;
const closable = !(item && item.meta && item.meta.affix);
@@ -97,40 +84,6 @@ export default defineComponent({
});
}
- function initSortableTabs() {
- if (!multiTabsSetting.canDrag) return;
- nextTick(() => {
- const el = document.querySelectorAll(
- '.multiple-tabs .ant-tabs-nav > div'
- )?.[0] as HTMLElement;
-
- if (!el) return;
- Sortable.create(el, {
- animation: 500,
- delay: 400,
- delayOnTouchOnly: true,
- filter: (e: ChangeEvent) => {
- const text = e?.target?.innerText;
- if (!text) return false;
- return affixTextList.includes(text);
- },
- onEnd: (evt) => {
- const { oldIndex, newIndex } = evt;
-
- if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
- return;
- }
-
- tabStore.commitSortTabs({ oldIndex, newIndex });
- },
- });
- });
- }
-
- onMounted(() => {
- initSortableTabs();
- });
-
return () => {
const slots = {
default: () => renderTabs(),
diff --git a/src/layouts/default/multitabs/types.ts b/src/layouts/default/multitabs/types.ts
new file mode 100644
index 00000000..c8b32023
--- /dev/null
+++ b/src/layouts/default/multitabs/types.ts
@@ -0,0 +1,35 @@
+import type { DropMenu } from '/@/components/Dropdown/index';
+import type { RouteLocationNormalized } from 'vue-router';
+
+export enum TabContentEnum {
+ TAB_TYPE,
+ EXTRA_TYPE,
+}
+
+export type { DropMenu };
+
+export interface TabContentProps {
+ tabItem: RouteLocationNormalized;
+ type?: TabContentEnum;
+ trigger?: ('click' | 'hover' | 'contextmenu')[];
+}
+
+/**
+ * @description: 右键:下拉菜单文字
+ */
+export enum MenuEventEnum {
+ // 刷新
+ REFRESH_PAGE,
+ // 关闭当前
+ CLOSE_CURRENT,
+ // 关闭左侧
+ CLOSE_LEFT,
+ // 关闭右侧
+ CLOSE_RIGHT,
+ // 关闭其他
+ CLOSE_OTHER,
+ // 关闭所有
+ CLOSE_ALL,
+ // 放大
+ SCALE,
+}
diff --git a/src/layouts/default/multitabs/useMultipleTabs.ts b/src/layouts/default/multitabs/useMultipleTabs.ts
index 69c4e914..b5a7d485 100644
--- a/src/layouts/default/multitabs/useMultipleTabs.ts
+++ b/src/layouts/default/multitabs/useMultipleTabs.ts
@@ -1,19 +1,22 @@
-import { toRaw, ref } from 'vue';
+import Sortable from 'sortablejs';
+import { toRaw, ref, nextTick, onMounted } from 'vue';
+import { RouteLocationNormalized } from 'vue-router';
+import { useProjectSetting } from '/@/hooks/setting';
import router from '/@/router';
-import { AppRouteRecordRaw } from '/@/router/types';
-import { TabItem, tabStore } from '/@/store/modules/tab';
+import { tabStore } from '/@/store/modules/tab';
+import { isNullAndUnDef } from '/@/utils/is';
-export function initAffixTabs() {
- const affixList = ref([]);
+export function initAffixTabs(): string[] {
+ const affixList = ref([]);
/**
* @description: Filter all fixed routes
*/
- function filterAffixTabs(routes: AppRouteRecordRaw[]) {
- const tabs: TabItem[] = [];
+ function filterAffixTabs(routes: RouteLocationNormalized[]) {
+ const tabs: RouteLocationNormalized[] = [];
routes &&
routes.forEach((route) => {
if (route.meta && route.meta.affix) {
- tabs.push(toRaw(route) as TabItem);
+ tabs.push(toRaw(route));
}
});
return tabs;
@@ -23,10 +26,14 @@ export function initAffixTabs() {
* @description: Set fixed tabs
*/
function addAffixTabs(): void {
- const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]);
+ const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as RouteLocationNormalized[]);
affixList.value = affixTabs;
for (const tab of affixTabs) {
- tabStore.commitAddTab(tab);
+ tabStore.addTabAction(({
+ meta: tab.meta,
+ name: tab.name,
+ path: tab.path,
+ } as unknown) as RouteLocationNormalized);
}
}
@@ -37,3 +44,41 @@ export function initAffixTabs() {
}
return affixList.value.map((item) => item.meta?.title).filter(Boolean);
}
+
+export function useTabsDrag(affixTextList: string[]) {
+ const { multiTabsSetting } = useProjectSetting();
+
+ function initSortableTabs() {
+ if (!multiTabsSetting.canDrag) return;
+ nextTick(() => {
+ const el = document.querySelectorAll(
+ '.multiple-tabs .ant-tabs-nav > div'
+ )?.[0] as HTMLElement;
+
+ if (!el) return;
+ Sortable.create(el, {
+ animation: 500,
+ delay: 400,
+ delayOnTouchOnly: true,
+ filter: (e: ChangeEvent) => {
+ const text = e?.target?.innerText;
+ if (!text) return false;
+ return affixTextList.includes(text);
+ },
+ onEnd: (evt) => {
+ const { oldIndex, newIndex } = evt;
+
+ if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
+ return;
+ }
+
+ tabStore.commitSortTabs({ oldIndex, newIndex });
+ },
+ });
+ });
+ }
+
+ onMounted(() => {
+ initSortableTabs();
+ });
+}
diff --git a/src/layouts/default/multitabs/useTabDropdown.ts b/src/layouts/default/multitabs/useTabDropdown.ts
index 9ba348cc..0e521e22 100644
--- a/src/layouts/default/multitabs/useTabDropdown.ts
+++ b/src/layouts/default/multitabs/useTabDropdown.ts
@@ -1,168 +1,148 @@
-import type { AppRouteRecordRaw } from '/@/router/types';
-import type { TabContentProps } from './data';
-import type { Ref } from 'vue';
-import type { TabItem } from '/@/store/modules/tab';
+import type { TabContentProps } from './types';
import type { DropMenu } from '/@/components/Dropdown';
-import { computed, unref } from 'vue';
-import { TabContentEnum, MenuEventEnum, getActions } from './data';
+import { computed, unref, reactive } from 'vue';
+import { TabContentEnum, MenuEventEnum } from './types';
import { tabStore } from '/@/store/modules/tab';
-import { appStore } from '/@/store/modules/app';
-import { PageEnum } from '/@/enums/pageEnum';
-import { useGo, useRedo } from '/@/hooks/web/usePage';
import router from '/@/router';
-import { useTabs, isInitUseTab } from '/@/hooks/web/useTabs';
-import { RouteLocationRaw } from 'vue-router';
+import { RouteLocationNormalized } from 'vue-router';
+import { useTabs } from '/@/hooks/web/useTabs';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
+import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
+import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
-const { initTabFn } = useTabs();
+const { t } = useI18n();
export function useTabDropdown(tabContentProps: TabContentProps) {
- const { currentRoute } = router;
- const redo = useRedo();
- const go = useGo();
-
- const isTabsRef = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE);
- const getCurrentTab: Ref = computed(() => {
- return unref(isTabsRef)
- ? tabContentProps.tabItem
- : ((unref(currentRoute) as any) as AppRouteRecordRaw);
+ const state = reactive({
+ current: null as Nullable,
+ currentIndex: 0,
});
- // Current tab list
- const getTabsState = computed(() => tabStore.getTabsState);
+ const { currentRoute } = router;
+
+ const { getShowMenu, setMenuSetting } = useMenuSetting();
+ const { getShowHeader, setHeaderSetting } = useHeaderSetting();
+ const { getShowQuick } = useMultipleTabSetting();
+
+ const isTabs = computed(() =>
+ !unref(getShowQuick) ? true : tabContentProps.type === TabContentEnum.TAB_TYPE
+ );
+
+ const getCurrentTab = computed(
+ (): RouteLocationNormalized => {
+ return unref(isTabs) ? tabContentProps.tabItem : unref(currentRoute);
+ }
+ );
+
+ const getIsScale = computed(() => {
+ return !unref(getShowMenu) && !unref(getShowHeader);
+ });
/**
* @description: drop-down list
*/
const getDropMenuList = computed(() => {
- const dropMenuList = getActions();
- // Reset to initial state
- for (const item of dropMenuList) {
- item.disabled = false;
- }
-
- // No tab
- if (!unref(getTabsState) || unref(getTabsState).length <= 0) {
- return dropMenuList;
- } else if (unref(getTabsState).length === 1) {
- // Only one tab
- for (const item of dropMenuList) {
- if (item.event !== MenuEventEnum.REFRESH_PAGE) {
- item.disabled = true;
- }
- }
- return dropMenuList;
- }
if (!unref(getCurrentTab)) return;
- const { meta, path } = unref(getCurrentTab);
+ const { meta } = unref(getCurrentTab);
+ const { path } = unref(currentRoute);
// Refresh button
- const curItem = tabStore.getCurrentContextMenuState;
- const index = tabStore.getCurrentContextMenuIndexState;
+ const curItem = state.current;
+ const index = state.currentIndex;
const refreshDisabled = curItem ? curItem.path !== path : true;
// Close left
const closeLeftDisabled = index === 0;
+ const disabled = tabStore.getTabsState.length === 1;
+
// Close right
- const closeRightDisabled = index === unref(getTabsState).length - 1;
- // Currently fixed tab
- // TODO PERf
- dropMenuList[0].disabled = unref(isTabsRef) ? refreshDisabled : false;
- if (meta && meta.affix) {
- dropMenuList[1].disabled = true;
+ const closeRightDisabled =
+ index === tabStore.getTabsState.length - 1 && tabStore.getLastDragEndIndexState >= 0;
+ const dropMenuList: DropMenu[] = [
+ {
+ icon: 'ant-design:reload-outlined',
+ event: MenuEventEnum.REFRESH_PAGE,
+ text: t('layout.multipleTab.redo'),
+ disabled: refreshDisabled,
+ },
+ {
+ icon: 'ant-design:close-outlined',
+ event: MenuEventEnum.CLOSE_CURRENT,
+ text: t('layout.multipleTab.close'),
+ disabled: meta?.affix || disabled,
+ divider: true,
+ },
+ {
+ icon: 'ant-design:pic-left-outlined',
+ event: MenuEventEnum.CLOSE_LEFT,
+ text: t('layout.multipleTab.closeLeft'),
+ disabled: closeLeftDisabled,
+ divider: false,
+ },
+ {
+ icon: 'ant-design:pic-right-outlined',
+ event: MenuEventEnum.CLOSE_RIGHT,
+ text: t('layout.multipleTab.closeRight'),
+ disabled: closeRightDisabled,
+ divider: true,
+ },
+ {
+ icon: 'ant-design:pic-center-outlined',
+ event: MenuEventEnum.CLOSE_OTHER,
+ text: t('layout.multipleTab.closeOther'),
+ disabled: disabled,
+ },
+ {
+ icon: 'ant-design:line-outlined',
+ event: MenuEventEnum.CLOSE_ALL,
+ text: t('layout.multipleTab.closeAll'),
+ disabled: disabled,
+ },
+ ];
+
+ if (!unref(isTabs)) {
+ const isScale = unref(getIsScale);
+ dropMenuList.unshift({
+ icon: isScale ? 'codicon:screen-normal' : 'codicon:screen-full',
+ event: MenuEventEnum.SCALE,
+ text: isScale ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
+ disabled: false,
+ });
}
- dropMenuList[2].disabled = closeLeftDisabled;
- dropMenuList[3].disabled = closeRightDisabled;
return dropMenuList;
});
- /**
- * @description: Jump to page when closing all pages
- */
- function gotoPage() {
- const len = unref(getTabsState).length;
- const { path } = unref(currentRoute);
+ const getTrigger = computed(() => {
+ return unref(isTabs) ? ['contextmenu'] : ['click'];
+ });
- let toPath: PageEnum | string = PageEnum.BASE_HOME;
-
- if (len > 0) {
- const page = unref(getTabsState)[len - 1];
- const p = page.fullPath || page.path;
- if (p) {
- toPath = p;
- }
- }
- // Jump to the current page and report an error
- path !== toPath && go(toPath as PageEnum, true);
- }
-
- function isGotoPage(currentTab?: TabItem) {
- const { path } = unref(currentRoute);
- const currentPath = (currentTab || unref(getCurrentTab)).path;
- // Not the current tab, when you close the left/right side, you need to jump to the page
- if (path !== currentPath) {
- go(currentPath as PageEnum, true);
- }
- }
- function refreshPage(tabItem?: TabItem) {
- try {
- tabStore.commitCloseTabKeepAlive(tabItem || unref(getCurrentTab));
- } catch (error) {}
- redo();
- }
-
- function closeAll() {
- tabStore.commitCloseAllTab();
- gotoPage();
- }
-
- function closeLeft(tabItem?: TabItem) {
- tabStore.closeLeftTabAction(tabItem || unref(getCurrentTab));
- isGotoPage(tabItem);
- }
-
- function closeRight(tabItem?: TabItem) {
- tabStore.closeRightTabAction(tabItem || unref(getCurrentTab));
- isGotoPage(tabItem);
- }
-
- function closeOther(tabItem?: TabItem) {
- tabStore.closeOtherTabAction(tabItem || unref(getCurrentTab));
- isGotoPage(tabItem);
- }
-
- function closeCurrent(tabItem?: TabItem) {
- closeTab(unref(tabItem || unref(getCurrentTab)));
+ function handleContextMenu(tabItem: RouteLocationNormalized) {
+ return (e: Event) => {
+ if (!tabItem) return;
+ e?.preventDefault();
+ const index = tabStore.getTabsState.findIndex((tab) => tab.path === tabItem.path);
+ state.current = tabItem;
+ state.currentIndex = index;
+ };
}
function scaleScreen() {
- const {
- headerSetting: { show: showHeader },
- menuSetting: { show: showMenu },
- } = appStore.getProjectConfig;
- const isScale = !showHeader && !showMenu;
- appStore.commitProjectConfigState({
- headerSetting: { show: isScale },
- menuSetting: { show: isScale },
+ const isScale = !unref(getShowMenu) && !unref(getShowHeader);
+ setMenuSetting({
+ show: isScale,
});
- }
-
- if (!isInitUseTab) {
- initTabFn({
- refreshPageFn: refreshPage,
- closeAllFn: closeAll,
- closeCurrentFn: closeCurrent,
- closeLeftFn: closeLeft,
- closeOtherFn: closeOther,
- closeRightFn: closeRight,
+ setHeaderSetting({
+ show: isScale,
});
}
// Handle right click event
function handleMenuEvent(menu: DropMenu): void {
+ const { refreshPage, closeAll, closeCurrent, closeLeft, closeOther, closeRight } = useTabs();
const { event } = menu;
-
switch (event) {
case MenuEventEnum.SCALE:
scaleScreen();
@@ -193,51 +173,5 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
break;
}
}
- return { getDropMenuList, handleMenuEvent };
-}
-
-export function getObj(tabItem: TabItem) {
- const { params, path, query } = tabItem;
- return {
- params: params || {},
- path,
- query: query || {},
- };
-}
-
-export function closeTab(closedTab: TabItem | AppRouteRecordRaw) {
- const { currentRoute, replace } = router;
- // Current tab list
- const getTabsState = computed(() => tabStore.getTabsState);
-
- const { path } = unref(currentRoute);
- if (path !== closedTab.path) {
- // Closed is not the activation tab
- tabStore.commitCloseTab(closedTab);
- return;
- }
-
- // Closed is activated atb
- let toObj: RouteLocationRaw = {};
-
- const index = unref(getTabsState).findIndex((item) => item.path === path);
-
- // If the current is the leftmost tab
- if (index === 0) {
- // There is only one tab, then jump to the homepage, otherwise jump to the right tab
- if (unref(getTabsState).length === 1) {
- toObj = PageEnum.BASE_HOME;
- } else {
- // Jump to the right tab
- const page = unref(getTabsState)[index + 1];
- toObj = getObj(page);
- }
- } else {
- // Close the current tab
- const page = unref(getTabsState)[index - 1];
- toObj = getObj(page);
- }
- const route = (unref(currentRoute) as unknown) as AppRouteRecordRaw;
- tabStore.commitCloseTab(route);
- replace(toObj);
+ return { getDropMenuList, handleMenuEvent, handleContextMenu, getTrigger, isTabs };
}
diff --git a/src/layouts/iframe/index.vue b/src/layouts/iframe/index.vue
index 0dc90496..7f7fe6b5 100644
--- a/src/layouts/iframe/index.vue
+++ b/src/layouts/iframe/index.vue
@@ -1,7 +1,7 @@
diff --git a/src/layouts/iframe/useFrameKeepAlive.ts b/src/layouts/iframe/useFrameKeepAlive.ts
index ed6a9318..08880c70 100644
--- a/src/layouts/iframe/useFrameKeepAlive.ts
+++ b/src/layouts/iframe/useFrameKeepAlive.ts
@@ -23,7 +23,7 @@ export function useFrameKeepAlive() {
const getOpenTabList = computed((): string[] => {
return tabStore.getTabsState.reduce((prev: string[], next) => {
if (next.meta && Reflect.has(next.meta, 'frameSrc')) {
- prev.push(next.path!);
+ prev.push(next.name as string);
}
return prev;
}, []);
@@ -45,11 +45,14 @@ export function useFrameKeepAlive() {
}
function showIframe(item: AppRouteRecordRaw) {
- return item.path === unref(currentRoute).path;
+ return item.name === unref(currentRoute).name;
}
- function hasRenderFrame(path: string) {
- return unref(getShowMultipleTab) ? unref(getOpenTabList).includes(path) : true;
+ function hasRenderFrame(name: string) {
+ if (!unref(getShowMultipleTab)) {
+ return true;
+ }
+ return unref(getOpenTabList).includes(name);
}
return { hasRenderFrame, getFramePages, showIframe, getAllFramePages };
}
diff --git a/src/layouts/page/index.tsx b/src/layouts/page/index.tsx
deleted file mode 100644
index 24e8551f..00000000
--- a/src/layouts/page/index.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import type { FunctionalComponent } from 'vue';
-
-import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue';
-import { RouterView, RouteLocation } from 'vue-router';
-
-import FrameLayout from '/@/layouts/iframe/index.vue';
-
-import { useTransition } from './useTransition';
-import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
-
-import { tabStore } from '/@/store/modules/tab';
-import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-
-interface DefaultContext {
- Component: FunctionalComponent;
- route: RouteLocation;
-}
-
-export default defineComponent({
- name: 'PageLayout',
- setup() {
- const { getShowMenu } = useMenuSetting();
-
- const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
-
- const { getBasicTransition, getEnableTransition } = useTransitionSetting();
-
- const { getMax } = useMultipleTabSetting();
-
- const transitionEvent = useTransition();
-
- const openCacheRef = computed(() => unref(getOpenKeepAlive) && unref(getShowMenu));
-
- const getCacheTabsRef = computed(() => tabStore.getKeepAliveTabsState as string[]);
-
- return () => {
- return (
-
-
- {{
- default: ({ Component, route }: DefaultContext) => {
- // No longer show animations that are already in the tab
- const cacheTabs = unref(getCacheTabsRef);
- const isInCache = cacheTabs.includes(route.name as string);
- const name = isInCache && route.meta.inTab ? 'fade-slide' : null;
-
- const renderComp = () => ;
-
- const PageContent = unref(openCacheRef) ? (
-
- {renderComp()}
-
- ) : (
- renderComp()
- );
-
- return unref(getEnableTransition) ? (
-
- {() => PageContent}
-
- ) : (
- PageContent
- );
- },
- }}
-
- {unref(getCanEmbedIFramePage) && }
-
- );
- };
- },
-});
diff --git a/src/layouts/page/index.vue b/src/layouts/page/index.vue
new file mode 100644
index 00000000..d197b021
--- /dev/null
+++ b/src/layouts/page/index.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/src/layouts/parent/index.vue b/src/layouts/parent/index.vue
new file mode 100644
index 00000000..0fa6cd62
--- /dev/null
+++ b/src/layouts/parent/index.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/parent/useCache.ts b/src/layouts/parent/useCache.ts
new file mode 100644
index 00000000..d02df4b8
--- /dev/null
+++ b/src/layouts/parent/useCache.ts
@@ -0,0 +1,52 @@
+import { computed, ref, unref } from 'vue';
+import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+import { tryTsxEmit } from '/@/utils/helper/vueHelper';
+import { tabStore, PAGE_LAYOUT_KEY } from '/@/store/modules/tab';
+
+import { useRouter } from 'vue-router';
+
+const ParentLayoutName = 'ParentLayout';
+export function useCache(isPage: boolean) {
+ const name = ref('');
+ const { currentRoute } = useRouter();
+
+ tryTsxEmit((instance: any) => {
+ const routeName = instance.ctx.$options.name;
+
+ if (routeName && ![ParentLayoutName].includes(routeName)) {
+ name.value = routeName;
+ } else {
+ const matched = currentRoute.value.matched;
+ const len = matched.length;
+ if (len < 2) return;
+ name.value = matched[len - 2].name as string;
+ }
+ });
+ const { getOpenKeepAlive } = useRootSetting();
+
+ const getCaches = computed((): string[] => {
+ if (!unref(getOpenKeepAlive)) {
+ return [];
+ }
+ const cached = tabStore.getCachedMapState;
+
+ if (isPage) {
+ // page Layout
+ // not parent layout
+ return cached.get(PAGE_LAYOUT_KEY) || [];
+ }
+
+ const cacheSet = new Set();
+ cacheSet.add(unref(name));
+
+ const list = cached.get(unref(name));
+ if (!list) {
+ return Array.from(cacheSet);
+ }
+ list.forEach((item) => {
+ cacheSet.add(item);
+ });
+ return Array.from(cacheSet);
+ });
+ return { getCaches };
+}
diff --git a/src/layouts/page/useTransition.ts b/src/layouts/parent/useTransition.ts
similarity index 100%
rename from src/layouts/page/useTransition.ts
rename to src/layouts/parent/useTransition.ts
diff --git a/src/locales/lang/en/component/form.ts b/src/locales/lang/en/component/form.ts
index ffc8da60..75cdf858 100644
--- a/src/locales/lang/en/component/form.ts
+++ b/src/locales/lang/en/component/form.ts
@@ -4,8 +4,8 @@ export default {
putAway: 'Put away',
unfold: 'Unfold',
- input: 'Please Input',
- choose: 'Please Choose',
+ input: 'Please Input ',
+ choose: 'Please Choose ',
maxTip: 'The number of characters should be less than {0}',
};
diff --git a/src/locales/lang/en/layout/header.ts b/src/locales/lang/en/layout/header.ts
index ec885060..fee7e324 100644
--- a/src/locales/lang/en/layout/header.ts
+++ b/src/locales/lang/en/layout/header.ts
@@ -15,4 +15,6 @@ export default {
lockScreen: 'Lock screen',
lockScreenBtn: 'Locking',
notLockScreenPassword: 'No password lock screen',
+
+ home: 'Home',
};
diff --git a/src/locales/lang/en/routes/demo/level.ts b/src/locales/lang/en/routes/demo/level.ts
new file mode 100644
index 00000000..1f51dac0
--- /dev/null
+++ b/src/locales/lang/en/routes/demo/level.ts
@@ -0,0 +1,3 @@
+export default {
+ level: 'Multi menu cache',
+};
diff --git a/src/locales/lang/zh_CN/layout/header.ts b/src/locales/lang/zh_CN/layout/header.ts
index 5518bfe9..e2719c29 100644
--- a/src/locales/lang/zh_CN/layout/header.ts
+++ b/src/locales/lang/zh_CN/layout/header.ts
@@ -16,4 +16,6 @@ export default {
lockScreen: '锁定屏幕',
lockScreenBtn: '锁定',
notLockScreenPassword: '不设置密码锁屏',
+
+ home: '首页',
};
diff --git a/src/locales/lang/zh_CN/routes/demo/feat.ts b/src/locales/lang/zh_CN/routes/demo/feat.ts
index 78b7aa19..621af0e8 100644
--- a/src/locales/lang/zh_CN/routes/demo/feat.ts
+++ b/src/locales/lang/zh_CN/routes/demo/feat.ts
@@ -1,5 +1,5 @@
export default {
- feat: '页面功能',
+ feat: '功能',
icon: '图标',
tabs: '标签页操作',
contextMenu: '右键菜单',
diff --git a/src/locales/lang/zh_CN/routes/demo/level.ts b/src/locales/lang/zh_CN/routes/demo/level.ts
new file mode 100644
index 00000000..b4027515
--- /dev/null
+++ b/src/locales/lang/zh_CN/routes/demo/level.ts
@@ -0,0 +1,3 @@
+export default {
+ level: '多级菜单缓存',
+};
diff --git a/src/router/constant.ts b/src/router/constant.ts
index 855bf141..e0234e42 100644
--- a/src/router/constant.ts
+++ b/src/router/constant.ts
@@ -1,16 +1,30 @@
import type { AppRouteRecordRaw } from '/@/router/types';
+import ParentLayout from '/@/layouts/parent/index.vue';
const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception');
/**
* @description: default layout
*/
-export const DEFAULT_LAYOUT_COMPONENT = () => import('/@/layouts/default/index');
+export const LAYOUT = () => import('/@/layouts/default/index');
/**
* @description: page-layout
*/
-export const PAGE_LAYOUT_COMPONENT = () => import('/@/layouts/page/index');
+export const PAGE_LAYOUT_COMPONENT = () => import('/@/layouts/page/index.vue');
+
+/**
+ * @description: page-layout
+ */
+export const getParentLayout = (name: string) => {
+ return () =>
+ new Promise((resolve) => {
+ resolve({
+ ...ParentLayout,
+ name,
+ });
+ });
+};
// 404 on a page
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
@@ -23,12 +37,25 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
},
};
+export const REDIRECT_NAME = 'Redirect';
+
export const REDIRECT_ROUTE: AppRouteRecordRaw = {
- path: '/redirect/:path(.*)*',
- name: 'Redirect',
- component: () => import('/@/views/sys/redirect/index.vue'),
+ path: '/redirect',
+ name: REDIRECT_NAME,
+ component: LAYOUT,
meta: {
- title: 'Redirect',
+ title: REDIRECT_NAME,
hideBreadcrumb: true,
},
+ children: [
+ {
+ path: '/redirect/:path(.*)',
+ name: REDIRECT_NAME,
+ component: () => import('/@/views/sys/redirect/index.vue'),
+ meta: {
+ title: REDIRECT_NAME,
+ hideBreadcrumb: true,
+ },
+ },
+ ],
};
diff --git a/src/router/guard/index.ts b/src/router/guard/index.ts
index c5ee2f73..4850542a 100644
--- a/src/router/guard/index.ts
+++ b/src/router/guard/index.ts
@@ -8,17 +8,19 @@ import { createPageLoadingGuard } from './pageLoadingGuard';
import { useGlobSetting, useProjectSetting } from '/@/hooks/setting';
-import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper';
+import { getIsOpenTab, getRoute } from '/@/router/helper/routeHelper';
import { setTitle } from '/@/utils/browser';
import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
import { tabStore } from '/@/store/modules/tab';
import { useI18n } from '/@/hooks/web/useI18n';
+import { REDIRECT_NAME } from '/@/router/constant';
const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
const globSetting = useGlobSetting();
+
export function createGuard(router: Router) {
- let axiosCanceler: AxiosCanceler | null;
+ let axiosCanceler: Nullable;
if (removeAllHttpPending) {
axiosCanceler = new AxiosCanceler();
}
@@ -30,15 +32,7 @@ export function createGuard(router: Router) {
to.meta.inTab = isOpen;
// Notify routing changes
- const { fullPath, path, query, params, name, meta } = to;
- tabStore.commitLastChangeRouteState({
- fullPath,
- path,
- query,
- params,
- name,
- meta,
- } as any);
+ tabStore.commitLastChangeRouteState(getRoute(to));
try {
if (closeMessageOnSwitch) {
@@ -50,14 +44,13 @@ export function createGuard(router: Router) {
} catch (error) {
console.warn('basic guard error:' + error);
}
- setCurrentTo(to);
return true;
});
router.afterEach((to) => {
const { t } = useI18n();
// change html title
- to.name !== 'Redirect' && setTitle(t(to.meta.title), globSetting.title);
+ to.name !== REDIRECT_NAME && setTitle(t(to.meta.title), globSetting.title);
});
createProgressGuard(router);
createPermissionGuard(router);
diff --git a/src/router/guard/pageLoadingGuard.ts b/src/router/guard/pageLoadingGuard.ts
index a7fca560..69e8cdd8 100644
--- a/src/router/guard/pageLoadingGuard.ts
+++ b/src/router/guard/pageLoadingGuard.ts
@@ -2,7 +2,7 @@ import type { Router } from 'vue-router';
import { tabStore } from '/@/store/modules/tab';
import { appStore } from '/@/store/modules/app';
import { userStore } from '/@/store/modules/user';
-import { getParams } from '/@/utils/helper/routeHelper';
+import { getParams } from '/@/router/helper/routeHelper';
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
import { unref } from 'vue';
@@ -14,6 +14,7 @@ export function createPageLoadingGuard(router: Router) {
if (!userStore.getTokenState) {
return true;
}
+
if (!unref(getEnableTransition) && unref(getOpenPageLoading)) {
appStore.commitPageLoadingState(true);
return true;
diff --git a/src/router/guard/permissionGuard.ts b/src/router/guard/permissionGuard.ts
index 4775e859..624c1601 100644
--- a/src/router/guard/permissionGuard.ts
+++ b/src/router/guard/permissionGuard.ts
@@ -7,7 +7,7 @@ import { PageEnum } from '/@/enums/pageEnum';
import { getToken } from '/@/utils/auth';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
-import { RootRoute } from '../routes/index';
+// import { RootRoute } from '../routes/index';
const LOGIN_PATH = PageEnum.BASE_LOGIN;
@@ -59,7 +59,8 @@ export function createPermissionGuard(router: Router) {
}
const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => {
- router.addRoute(RootRoute.name!, route as RouteRecordRaw);
+ // router.addRoute(RootRoute.name!, route as RouteRecordRaw);
+ router.addRoute(route as RouteRecordRaw);
});
const redirectPath = (from.query.redirect || to.path) as string;
diff --git a/src/router/guard/progressGuard.ts b/src/router/guard/progressGuard.ts
index 8e90bf7d..a617d7ad 100644
--- a/src/router/guard/progressGuard.ts
+++ b/src/router/guard/progressGuard.ts
@@ -9,9 +9,6 @@ import { unref } from 'vue';
const { getOpenNProgress } = useTransitionSetting();
export function createProgressGuard(router: Router) {
- // NProgress.inc(0.1);
- // NProgress.configure({ easing: 'ease', speed: 200, showSpinner: false });
-
router.beforeEach(async (to) => {
!to.meta.inTab && unref(getOpenNProgress) && NProgress.start();
return true;
diff --git a/src/router/helper/dynamicImport.ts b/src/router/helper/dynamicImport.ts
new file mode 100644
index 00000000..26690ced
--- /dev/null
+++ b/src/router/helper/dynamicImport.ts
@@ -0,0 +1,5 @@
+// The content here is just for type approval. The actual file content is overwritten by transform
+// For specific coverage, see build/vite/plugin/transform/dynamic-import/index.ts
+export default function (name: string) {
+ return name as any;
+}
diff --git a/src/utils/helper/menuHelper.ts b/src/router/helper/menuHelper.ts
similarity index 83%
rename from src/utils/helper/menuHelper.ts
rename to src/router/helper/menuHelper.ts
index a00e9bec..850b4119 100644
--- a/src/utils/helper/menuHelper.ts
+++ b/src/router/helper/menuHelper.ts
@@ -1,7 +1,7 @@
-import { AppRouteModule, RouteModule } from '/@/router/types.d';
+import { AppRouteModule } from '/@/router/types.d';
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
-import { findPath, forEach, treeMap, treeToList } from './treeHelper';
+import { findPath, forEach, treeMap, treeToList } from '/@/utils/helper/treeHelper';
import { cloneDeep } from 'lodash-es';
export function getAllParentPath(treeData: any[], path: string) {
@@ -48,12 +48,11 @@ export function transformRouteToMenu(routeModList: AppRouteModule[]) {
const cloneRouteModList = cloneDeep(routeModList);
const routeList: AppRouteRecordRaw[] = [];
cloneRouteModList.forEach((item) => {
- const { layout, routes, children } = item as RouteModule;
- if (layout) {
- layout.children = routes || children;
- routeList.push(layout);
+ if (item.meta?.single) {
+ const realItem = item?.children?.[0];
+ realItem && routeList.push(realItem);
} else {
- routes && routeList.push(...routes);
+ routeList.push(item);
}
});
return treeMap(routeList, {
diff --git a/src/router/helper/routeHelper.ts b/src/router/helper/routeHelper.ts
new file mode 100644
index 00000000..4f286e65
--- /dev/null
+++ b/src/router/helper/routeHelper.ts
@@ -0,0 +1,89 @@
+import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
+import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
+
+import { appStore } from '/@/store/modules/app';
+import { tabStore } from '/@/store/modules/tab';
+import { getParentLayout, LAYOUT } from '/@/router/constant';
+import dynamicImport from './dynamicImport';
+import { cloneDeep } from 'lodash-es';
+
+// 动态引入
+function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
+ if (!routes) return;
+ routes.forEach((item) => {
+ const { component, name } = item;
+ const { children } = item;
+ if (component) {
+ item.component = dynamicImport(component);
+ } else if (name) {
+ item.component = getParentLayout(name);
+ }
+ children && asyncImportRoute(children);
+ });
+}
+
+function getLayoutComp(comp: string) {
+ return comp === 'LAYOUT' ? LAYOUT : '';
+}
+
+// Turn background objects into routing objects
+export function transformObjToRoute(routeList: AppRouteModule[]): T[] {
+ routeList.forEach((route) => {
+ if (route.component) {
+ if ((route.component as string).toUpperCase() === 'LAYOUT') {
+ route.component = getLayoutComp(route.component);
+ } else {
+ route.children = [cloneDeep(route)];
+ route.component = LAYOUT;
+ route.name = `${route.name}Parent`;
+ route.path = '';
+ const meta = route.meta || {};
+ meta.single = true;
+ meta.affix = false;
+ route.meta = meta;
+ }
+ }
+ route.children && asyncImportRoute(route.children);
+ });
+ return (routeList as unknown) as T[];
+}
+
+/**
+ * Determine whether the tab has been opened
+ * @param toPath
+ */
+export function getIsOpenTab(toPath: string) {
+ const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
+
+ if (show && openKeepAlive) {
+ const tabList = tabStore.getTabsState;
+ return tabList.some((tab) => tab.path === toPath);
+ }
+ return false;
+}
+
+export function getParams(data: any = {}) {
+ const { params = {} } = data;
+ let ret = '';
+ Object.keys(params).forEach((key) => {
+ const p = params[key];
+ ret += `/${p}`;
+ });
+ return ret;
+}
+
+// Return to the new routing structure, not affected by the original example
+export function getRoute(route: RouteLocationNormalized): RouteLocationNormalized {
+ if (!route) return route;
+ const { matched, ...opt } = route;
+ return {
+ ...opt,
+ matched: (matched
+ ? matched.map((item) => ({
+ meta: item.meta,
+ name: item.name,
+ path: item.path,
+ }))
+ : undefined) as RouteRecordNormalized[],
+ };
+}
diff --git a/src/router/menus/index.ts b/src/router/menus/index.ts
index f81de94e..a305b0d3 100644
--- a/src/router/menus/index.ts
+++ b/src/router/menus/index.ts
@@ -2,7 +2,7 @@ import type { Menu, MenuModule } from '/@/router/types';
import type { RouteRecordNormalized } from 'vue-router';
import { appStore } from '/@/store/modules/app';
import { permissionStore } from '/@/store/modules/permission';
-import { transformMenuModule, flatMenus, getAllParentPath } from '/@/utils/helper/menuHelper';
+import { transformMenuModule, flatMenus, getAllParentPath } from '/@/router/helper/menuHelper';
import { filter } from '/@/utils/helper/treeHelper';
import router from '/@/router';
import { PermissionModeEnum } from '/@/enums/appEnum';
diff --git a/src/router/menus/modules/dashboard.ts b/src/router/menus/modules/dashboard.ts
index 466d76a8..1b958862 100644
--- a/src/router/menus/modules/dashboard.ts
+++ b/src/router/menus/modules/dashboard.ts
@@ -1,33 +1,20 @@
import type { MenuModule } from '/@/router/types.d';
-const menu: MenuModule[] = [
- {
- orderNo: 0,
- menu: {
- path: '/dashboard/welcome',
- name: 'routes.dashboard.welcome',
- },
+const menu: MenuModule = {
+ orderNo: 10,
+ menu: {
+ name: 'routes.dashboard.dashboard',
+ path: '/dashboard',
+ children: [
+ {
+ path: '/workbench',
+ name: 'routes.dashboard.workbench',
+ },
+ {
+ path: '/analysis',
+ name: 'routes.dashboard.analysis',
+ },
+ ],
},
- {
- orderNo: 10,
- menu: {
- name: 'routes.dashboard.dashboard',
- path: '/dashboard',
- children: [
- {
- path: '/workbench',
- name: 'routes.dashboard.workbench',
- },
- {
- path: '/analysis',
- name: 'routes.dashboard.analysis',
- },
- // {
- // path: '/welcome',
- // name: 'routes.dashboard.welcome',
- // },
- ],
- },
- },
-];
+};
export default menu;
diff --git a/src/router/menus/modules/demo/level.ts b/src/router/menus/modules/demo/level.ts
new file mode 100644
index 00000000..34d88421
--- /dev/null
+++ b/src/router/menus/modules/demo/level.ts
@@ -0,0 +1,39 @@
+import type { MenuModule } from '/@/router/types.d';
+
+const menu: MenuModule = {
+ orderNo: 2000,
+ menu: {
+ name: 'routes.demo.level.level',
+ path: '/level',
+ tag: {
+ dot: true,
+ },
+ children: [
+ {
+ path: 'menu1',
+ name: 'Menu1',
+ children: [
+ {
+ path: 'menu1-1',
+ name: 'Menu1-1',
+ children: [
+ {
+ path: 'menu1-1-1',
+ name: 'Menu1-1-1',
+ },
+ ],
+ },
+ {
+ path: 'menu1-2',
+ name: 'Menu1-2',
+ },
+ ],
+ },
+ {
+ path: 'menu2',
+ name: 'Menu2',
+ },
+ ],
+ },
+};
+export default menu;
diff --git a/src/router/menus/modules/home.ts b/src/router/menus/modules/home.ts
new file mode 100644
index 00000000..049c595f
--- /dev/null
+++ b/src/router/menus/modules/home.ts
@@ -0,0 +1,10 @@
+import type { MenuModule } from '/@/router/types.d';
+
+const menu: MenuModule = {
+ orderNo: 0,
+ menu: {
+ path: '/home/welcome',
+ name: 'routes.dashboard.welcome',
+ },
+};
+export default menu;
diff --git a/src/router/routes/index.ts b/src/router/routes/index.ts
index 34cae664..e9f6878c 100644
--- a/src/router/routes/index.ts
+++ b/src/router/routes/index.ts
@@ -1,31 +1,28 @@
import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
-import { DEFAULT_LAYOUT_COMPONENT, PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
-import { genRouteModule } from '/@/utils/helper/routeHelper';
+import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE, LAYOUT } from '../constant';
+import { PageEnum } from '/@/enums/pageEnum';
+
import modules from 'globby!/@/router/routes/modules/**/*.@(ts)';
const routeModuleList: AppRouteModule[] = [];
Object.keys(modules).forEach((key) => {
- routeModuleList.push(modules[key]);
+ const mod = Array.isArray(modules[key]) ? [...modules[key]] : [modules[key]];
+ routeModuleList.push(...mod);
});
-export const asyncRoutes = [
- REDIRECT_ROUTE,
- PAGE_NOT_FOUND_ROUTE,
- ...genRouteModule(routeModuleList),
-];
+export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
-// 主框架根路由
-export const RootRoute: AppRouteRecordRaw = {
+const MainRoute: AppRouteModule = {
path: '/',
- name: 'Root',
- component: DEFAULT_LAYOUT_COMPONENT,
- redirect: '/dashboard',
+ name: 'MainRoute',
+ component: LAYOUT,
+ redirect: PageEnum.BASE_HOME,
meta: {
- title: 'Root',
+ icon: 'ant-design:home-outlined',
+ title: 'routes.dashboard.dashboard',
},
- children: [],
};
export const LoginRoute: AppRouteRecordRaw = {
@@ -38,4 +35,4 @@ export const LoginRoute: AppRouteRecordRaw = {
};
// 基础路由 不用权限
-export const basicRoutes = [LoginRoute, RootRoute];
+export const basicRoutes = [LoginRoute, MainRoute, REDIRECT_ROUTE];
diff --git a/src/router/routes/modules/dashboard.ts b/src/router/routes/modules/dashboard.ts
index ba647f32..70da9aa7 100644
--- a/src/router/routes/modules/dashboard.ts
+++ b/src/router/routes/modules/dashboard.ts
@@ -1,32 +1,19 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const dashboard: AppRouteModule = {
- layout: {
- path: '/dashboard',
- name: 'Dashboard',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/dashboard/welcome',
- meta: {
- icon: 'ant-design:home-outlined',
- title: 'routes.dashboard.dashboard',
- },
+ path: '/dashboard',
+ name: 'Dashboard',
+ component: LAYOUT,
+ redirect: '/dashboard/welcome',
+ meta: {
+ icon: 'ant-design:home-outlined',
+ title: 'routes.dashboard.dashboard',
},
-
- routes: [
+ children: [
{
- path: '/welcome',
- name: 'Welcome',
- component: () => import('/@/views/dashboard/welcome/index.vue'),
- meta: {
- title: 'routes.dashboard.welcome',
- affix: true,
- icon: 'ant-design:home-outlined',
- },
- },
- {
- path: '/workbench',
+ path: 'workbench',
name: 'Workbench',
component: () => import('/@/views/dashboard/workbench/index.vue'),
meta: {
@@ -34,7 +21,7 @@ const dashboard: AppRouteModule = {
},
},
{
- path: '/analysis',
+ path: 'analysis',
name: 'Analysis',
component: () => import('/@/views/dashboard/analysis/index.vue'),
meta: {
diff --git a/src/router/routes/modules/demo/charts.ts b/src/router/routes/modules/demo/charts.ts
index 29141007..44fa2f87 100644
--- a/src/router/routes/modules/demo/charts.ts
+++ b/src/router/routes/modules/demo/charts.ts
@@ -1,23 +1,21 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { getParentLayout, LAYOUT } from '/@/router/constant';
const charts: AppRouteModule = {
- layout: {
- path: '/charts',
- name: 'Charts',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/charts/apexChart',
- meta: {
- icon: 'ant-design:area-chart-outlined',
- title: 'routes.demo.charts.charts',
- },
+ path: '/charts',
+ name: 'Charts',
+ component: LAYOUT,
+ redirect: '/charts/apexChart',
+ meta: {
+ icon: 'ant-design:area-chart-outlined',
+ title: 'routes.demo.charts.charts',
},
-
- routes: [
+ children: [
{
- path: '/echarts',
+ path: 'echarts',
name: 'Echarts',
+ component: getParentLayout('Echarts'),
meta: {
title: 'Echarts',
},
@@ -49,7 +47,7 @@ const charts: AppRouteModule = {
],
},
{
- path: '/apexChart',
+ path: 'apexChart',
name: 'ApexChart',
meta: {
title: 'routes.demo.charts.apexChart',
diff --git a/src/router/routes/modules/demo/comp.ts b/src/router/routes/modules/demo/comp.ts
index b5dc6271..e7a691e5 100644
--- a/src/router/routes/modules/demo/comp.ts
+++ b/src/router/routes/modules/demo/comp.ts
@@ -1,22 +1,20 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { getParentLayout, LAYOUT } from '/@/router/constant';
const comp: AppRouteModule = {
- layout: {
- path: '/comp',
- name: 'Comp',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/comp/basic',
- meta: {
- icon: 'ant-design:table-outlined',
- title: 'routes.demo.comp.comp',
- },
+ path: '/comp',
+ name: 'Comp',
+ component: LAYOUT,
+ redirect: '/comp/basic',
+ meta: {
+ icon: 'ant-design:table-outlined',
+ title: 'routes.demo.comp.comp',
},
- routes: [
+ children: [
{
- path: '/basic',
+ path: 'basic',
name: 'BasicDemo',
component: () => import('/@/views/demo/comp/button/index.vue'),
meta: {
@@ -24,7 +22,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/transition',
+ path: 'transition',
name: 'transitionDemo',
component: () => import('/@/views/demo/comp/transition/index.vue'),
meta: {
@@ -32,7 +30,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/countTo',
+ path: 'countTo',
name: 'CountTo',
component: () => import('/@/views/demo/comp/count-to/index.vue'),
meta: {
@@ -41,9 +39,10 @@ const comp: AppRouteModule = {
},
{
- path: '/scroll',
+ path: 'scroll',
name: 'ScrollDemo',
redirect: '/comp/scroll/basic',
+ component: getParentLayout('ScrollDemo'),
meta: {
title: 'routes.demo.comp.scroll',
},
@@ -76,7 +75,7 @@ const comp: AppRouteModule = {
},
{
- path: '/modal',
+ path: 'modal',
name: 'ModalDemo',
component: () => import('/@/views/demo/comp/modal/index.vue'),
meta: {
@@ -84,7 +83,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/drawer',
+ path: 'drawer',
name: 'DrawerDemo',
component: () => import('/@/views/demo/comp/drawer/index.vue'),
meta: {
@@ -92,7 +91,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/desc',
+ path: 'desc',
name: 'DescDemo',
component: () => import('/@/views/demo/comp/desc/index.vue'),
meta: {
@@ -101,8 +100,9 @@ const comp: AppRouteModule = {
},
{
- path: '/lazy',
- name: 'lazyDemo',
+ path: 'lazy',
+ name: 'LazyDemo',
+ component: getParentLayout('LazyDemo'),
redirect: '/comp/lazy/basic',
meta: {
title: 'routes.demo.comp.lazy',
@@ -127,8 +127,9 @@ const comp: AppRouteModule = {
],
},
{
- path: '/verify',
+ path: 'verify',
name: 'VerifyDemo',
+ component: getParentLayout('VerifyDemo'),
redirect: '/comp/verify/drag',
meta: {
title: 'routes.demo.comp.verify',
@@ -155,7 +156,7 @@ const comp: AppRouteModule = {
//
{
- path: '/qrcode',
+ path: 'qrcode',
name: 'QrCodeDemo',
component: () => import('/@/views/demo/comp/qrcode/index.vue'),
meta: {
@@ -163,7 +164,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/strength-meter',
+ path: 'strength-meter',
name: 'StrengthMeterDemo',
component: () => import('/@/views/demo/comp/strength-meter/index.vue'),
meta: {
@@ -171,7 +172,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/upload',
+ path: 'upload',
name: 'UploadDemo',
component: () => import('/@/views/demo/comp/upload/index.vue'),
meta: {
@@ -179,7 +180,7 @@ const comp: AppRouteModule = {
},
},
{
- path: '/loading',
+ path: 'loading',
name: 'LoadingDemo',
component: () => import('/@/views/demo/comp/loading/index.vue'),
meta: {
diff --git a/src/router/routes/modules/demo/editor.ts b/src/router/routes/modules/demo/editor.ts
index f011f3bc..afab148a 100644
--- a/src/router/routes/modules/demo/editor.ts
+++ b/src/router/routes/modules/demo/editor.ts
@@ -1,22 +1,19 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { getParentLayout, LAYOUT } from '/@/router/constant';
const editor: AppRouteModule = {
- layout: {
- path: '/editor',
- name: 'Editor',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/editor/markdown',
- meta: {
- icon: 'ant-design:table-outlined',
- title: 'routes.demo.editor.editor',
- },
+ path: '/editor',
+ name: 'Editor',
+ component: LAYOUT,
+ redirect: '/editor/markdown',
+ meta: {
+ icon: 'ant-design:table-outlined',
+ title: 'routes.demo.editor.editor',
},
-
- routes: [
+ children: [
{
- path: '/markdown',
+ path: 'markdown',
name: 'MarkdownDemo',
component: () => import('/@/views/demo/editor/Markdown.vue'),
meta: {
@@ -24,7 +21,8 @@ const editor: AppRouteModule = {
},
},
{
- path: '/tinymce',
+ path: 'tinymce',
+ component: getParentLayout('TinymceDemo'),
name: 'TinymceDemo',
meta: {
title: 'routes.demo.editor.tinymce',
@@ -39,7 +37,6 @@ const editor: AppRouteModule = {
title: 'routes.demo.editor.tinymceBasic',
},
},
- // TODO
{
path: 'editor',
name: 'TinymceFormDemo',
diff --git a/src/router/routes/modules/demo/excel.ts b/src/router/routes/modules/demo/excel.ts
index 99ee0848..f791fc89 100644
--- a/src/router/routes/modules/demo/excel.ts
+++ b/src/router/routes/modules/demo/excel.ts
@@ -1,22 +1,20 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const excel: AppRouteModule = {
- layout: {
- path: '/excel',
- name: 'Excel',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/excel/customExport',
- meta: {
- icon: 'mdi:microsoft-excel',
- title: 'routes.demo.excel.excel',
- },
+ path: '/excel',
+ name: 'Excel',
+ component: LAYOUT,
+ redirect: '/excel/customExport',
+ meta: {
+ icon: 'mdi:microsoft-excel',
+ title: 'routes.demo.excel.excel',
},
- routes: [
+ children: [
{
- path: '/customExport',
+ path: 'customExport',
name: 'CustomExport',
component: () => import('/@/views/demo/excel/CustomExport.vue'),
meta: {
@@ -24,7 +22,7 @@ const excel: AppRouteModule = {
},
},
{
- path: '/jsonExport',
+ path: 'jsonExport',
name: 'JsonExport',
component: () => import('/@/views/demo/excel/JsonExport.vue'),
meta: {
@@ -32,7 +30,7 @@ const excel: AppRouteModule = {
},
},
{
- path: '/arrayExport',
+ path: 'arrayExport',
name: 'ArrayExport',
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
meta: {
@@ -40,7 +38,7 @@ const excel: AppRouteModule = {
},
},
{
- path: '/importExcel',
+ path: 'importExcel',
name: 'ImportExcel',
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
meta: {
diff --git a/src/router/routes/modules/demo/feat.ts b/src/router/routes/modules/demo/feat.ts
index 4885446d..1a2326de 100644
--- a/src/router/routes/modules/demo/feat.ts
+++ b/src/router/routes/modules/demo/feat.ts
@@ -1,22 +1,19 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const feat: AppRouteModule = {
- layout: {
- path: '/feat',
- name: 'FeatDemo',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/feat/icon',
- meta: {
- icon: 'ic:outline-featured-play-list',
- title: 'routes.demo.feat.feat',
- },
+ path: '/feat',
+ name: 'FeatDemo',
+ component: LAYOUT,
+ redirect: '/feat/icon',
+ meta: {
+ icon: 'ic:outline-featured-play-list',
+ title: 'routes.demo.feat.feat',
},
-
- routes: [
+ children: [
{
- path: '/icon',
+ path: 'icon',
name: 'IconDemo',
component: () => import('/@/views/demo/feat/icon/index.vue'),
meta: {
@@ -24,7 +21,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/tabs',
+ path: 'tabs',
name: 'TabsDemo',
component: () => import('/@/views/demo/feat/tabs/index.vue'),
meta: {
@@ -33,7 +30,7 @@ const feat: AppRouteModule = {
},
{
- path: '/context-menu',
+ path: 'context-menu',
name: 'ContextMenuDemo',
component: () => import('/@/views/demo/feat/context-menu/index.vue'),
meta: {
@@ -41,7 +38,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/download',
+ path: 'download',
name: 'DownLoadDemo',
component: () => import('/@/views/demo/feat/download/index.vue'),
meta: {
@@ -49,7 +46,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/click-out-side',
+ path: 'click-out-side',
name: 'ClickOutSideDemo',
component: () => import('/@/views/demo/feat/click-out-side/index.vue'),
meta: {
@@ -57,7 +54,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/img-preview',
+ path: 'img-preview',
name: 'ImgPreview',
component: () => import('/@/views/demo/feat/img-preview/index.vue'),
meta: {
@@ -65,7 +62,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/copy',
+ path: 'copy',
name: 'CopyDemo',
component: () => import('/@/views/demo/feat/copy/index.vue'),
meta: {
@@ -73,7 +70,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/msg',
+ path: 'msg',
name: 'MsgDemo',
component: () => import('/@/views/demo/feat/msg/index.vue'),
meta: {
@@ -81,7 +78,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/watermark',
+ path: 'watermark',
name: 'WatermarkDemo',
component: () => import('/@/views/demo/feat/watermark/index.vue'),
meta: {
@@ -89,7 +86,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/full-screen',
+ path: 'full-screen',
name: 'FullScreenDemo',
component: () => import('/@/views/demo/feat/full-screen/index.vue'),
meta: {
@@ -97,7 +94,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/error-log',
+ path: 'error-log',
name: 'ErrorLog',
component: () => import('/@/views/sys/error-log/index.vue'),
meta: {
@@ -105,7 +102,7 @@ const feat: AppRouteModule = {
},
},
{
- path: '/testTab/:id',
+ path: 'testTab/:id',
name: 'TestTab',
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
meta: {
diff --git a/src/router/routes/modules/demo/form.ts b/src/router/routes/modules/demo/form.ts
index cedfb144..db99ca46 100644
--- a/src/router/routes/modules/demo/form.ts
+++ b/src/router/routes/modules/demo/form.ts
@@ -1,22 +1,19 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const form: AppRouteModule = {
- layout: {
- path: '/form',
- name: 'FormDemo',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/form/basic',
- meta: {
- icon: 'ant-design:table-outlined',
- title: 'routes.demo.form.form',
- },
+ path: '/form',
+ name: 'FormDemo',
+ component: LAYOUT,
+ redirect: '/form/basic',
+ meta: {
+ icon: 'ant-design:table-outlined',
+ title: 'routes.demo.form.form',
},
-
- routes: [
+ children: [
{
- path: '/basic',
+ path: 'basic',
name: 'FormBasicDemo',
component: () => import('/@/views/demo/form/index.vue'),
meta: {
@@ -24,7 +21,7 @@ const form: AppRouteModule = {
},
},
{
- path: '/useForm',
+ path: 'useForm',
name: 'UseFormDemo',
component: () => import('/@/views/demo/form/UseForm.vue'),
meta: {
@@ -32,7 +29,7 @@ const form: AppRouteModule = {
},
},
{
- path: '/refForm',
+ path: 'refForm',
name: 'RefFormDemo',
component: () => import('/@/views/demo/form/RefForm.vue'),
meta: {
@@ -40,7 +37,7 @@ const form: AppRouteModule = {
},
},
{
- path: '/advancedForm',
+ path: 'advancedForm',
name: 'AdvancedFormDemo',
component: () => import('/@/views/demo/form/AdvancedForm.vue'),
meta: {
@@ -48,7 +45,7 @@ const form: AppRouteModule = {
},
},
{
- path: '/ruleForm',
+ path: 'ruleForm',
name: 'RuleFormDemo',
component: () => import('/@/views/demo/form/RuleForm.vue'),
meta: {
@@ -56,7 +53,7 @@ const form: AppRouteModule = {
},
},
{
- path: '/dynamicForm',
+ path: 'dynamicForm',
name: 'DynamicFormDemo',
component: () => import('/@/views/demo/form/DynamicForm.vue'),
meta: {
@@ -64,7 +61,7 @@ const form: AppRouteModule = {
},
},
{
- path: '/customerForm',
+ path: 'customerForm',
name: 'CustomerFormDemo',
component: () => import('/@/views/demo/form/CustomerForm.vue'),
meta: {
diff --git a/src/router/routes/modules/demo/iframe.ts b/src/router/routes/modules/demo/iframe.ts
index 5f1b4797..83507c21 100644
--- a/src/router/routes/modules/demo/iframe.ts
+++ b/src/router/routes/modules/demo/iframe.ts
@@ -1,23 +1,21 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');
const iframe: AppRouteModule = {
- layout: {
- path: '/frame',
- name: 'Frame',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/frame/antv',
- meta: {
- icon: 'mdi:page-next-outline',
- title: 'routes.demo.iframe.frame',
- },
+ path: '/frame',
+ name: 'Frame',
+ component: LAYOUT,
+ redirect: '/frame/antv',
+ meta: {
+ icon: 'mdi:page-next-outline',
+ title: 'routes.demo.iframe.frame',
},
- routes: [
+ children: [
{
- path: '/antv',
+ path: 'antv',
name: 'Antv',
component: IFrame,
meta: {
@@ -27,7 +25,7 @@ const iframe: AppRouteModule = {
},
},
{
- path: '/doc',
+ path: 'doc',
name: 'Doc',
component: IFrame,
meta: {
@@ -37,7 +35,7 @@ const iframe: AppRouteModule = {
},
},
{
- path: '/docExternal',
+ path: 'docExternal',
name: 'DocExternal',
component: IFrame,
meta: {
diff --git a/src/router/routes/modules/demo/level.ts b/src/router/routes/modules/demo/level.ts
new file mode 100644
index 00000000..483f9923
--- /dev/null
+++ b/src/router/routes/modules/demo/level.ts
@@ -0,0 +1,63 @@
+import type { AppRouteModule } from '/@/router/types';
+
+import { getParentLayout, LAYOUT } from '/@/router/constant';
+
+const permission: AppRouteModule = {
+ path: '/level',
+ name: 'Level',
+ component: LAYOUT,
+ redirect: '/level/menu1/menu1-1',
+ meta: {
+ icon: 'carbon:user-role',
+ title: 'routes.demo.level.level',
+ },
+
+ children: [
+ {
+ path: 'menu1',
+ name: 'Menu1Demo',
+ component: getParentLayout('Menu1Demo'),
+ meta: {
+ title: 'Menu1',
+ },
+ children: [
+ {
+ path: 'menu1-1',
+ name: 'Menu11Demo',
+ component: getParentLayout('Menu11Demo'),
+ meta: {
+ title: 'Menu1-1',
+ },
+ children: [
+ {
+ path: 'menu1-1-1',
+ name: 'Menu111Demo',
+ component: () => import('/@/views/demo/level/Menu111.vue'),
+ meta: {
+ title: 'Menu111',
+ },
+ },
+ ],
+ },
+ {
+ path: 'menu1-2',
+ name: 'Menu12Demo',
+ component: () => import('/@/views/demo/level/Menu12.vue'),
+ meta: {
+ title: 'Menu1-2',
+ },
+ },
+ ],
+ },
+ {
+ path: 'menu2',
+ name: 'Menu2Demo',
+ component: () => import('/@/views/demo/level/Menu2.vue'),
+ meta: {
+ title: 'Menu2',
+ },
+ },
+ ],
+};
+
+export default permission;
diff --git a/src/router/routes/modules/demo/page.ts b/src/router/routes/modules/demo/page.ts
index c091f337..6e0a568f 100644
--- a/src/router/routes/modules/demo/page.ts
+++ b/src/router/routes/modules/demo/page.ts
@@ -1,6 +1,6 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { getParentLayout, LAYOUT } from '/@/router/constant';
import { ExceptionEnum } from '/@/enums/exceptionEnum';
const ExceptionPage = () => import('/@/views/sys/exception/Exception');
@@ -8,7 +8,7 @@ const ExceptionPage = () => import('/@/views/sys/exception/Exception');
const page: AppRouteModule = {
path: '/page-demo',
name: 'PageDemo',
- component: PAGE_LAYOUT_COMPONENT,
+ component: LAYOUT,
redirect: '/page-demo/exception',
meta: {
icon: 'mdi:page-next-outline',
@@ -17,9 +17,10 @@ const page: AppRouteModule = {
children: [
// =============================form start=============================
{
- path: '/form',
+ path: 'form',
name: 'FormPage',
redirect: '/page-demo/form/basic',
+ component: getParentLayout('FormPage'),
meta: {
title: 'routes.demo.page.form',
},
@@ -53,8 +54,9 @@ const page: AppRouteModule = {
// =============================form end=============================
// =============================desc start=============================
{
- path: '/desc',
+ path: 'desc',
name: 'DescPage',
+ component: getParentLayout('DescPage'),
redirect: '/page-demo/desc/basic',
meta: {
title: 'routes.demo.page.desc',
@@ -82,9 +84,11 @@ const page: AppRouteModule = {
// =============================result start=============================
{
- path: '/result',
+ path: 'result',
name: 'ResultPage',
redirect: '/page-demo/result/success',
+ component: getParentLayout('ResultPage'),
+
meta: {
title: 'routes.demo.page.result',
},
@@ -111,8 +115,9 @@ const page: AppRouteModule = {
// =============================account start=============================
{
- path: '/account',
+ path: 'account',
name: 'AccountPage',
+ component: getParentLayout('AccountPage'),
redirect: '/page-demo/account/setting',
meta: {
title: 'routes.demo.page.account',
@@ -139,8 +144,9 @@ const page: AppRouteModule = {
// =============================account end=============================
// =============================exception start=============================
{
- path: '/exception',
+ path: 'exception',
name: 'ExceptionPage',
+ component: getParentLayout('ExceptionPage'),
redirect: '/page-demo/exception/404',
meta: {
title: 'routes.demo.page.exception',
@@ -211,8 +217,9 @@ const page: AppRouteModule = {
// =============================exception end=============================
// =============================list start=============================
{
- path: '/list',
+ path: 'list',
name: 'ListPage',
+ component: getParentLayout('ListPage'),
redirect: '/page-demo/list/card',
meta: {
title: 'routes.demo.page.list',
diff --git a/src/router/routes/modules/demo/permission.ts b/src/router/routes/modules/demo/permission.ts
index ac3891e3..c308572f 100644
--- a/src/router/routes/modules/demo/permission.ts
+++ b/src/router/routes/modules/demo/permission.ts
@@ -1,24 +1,23 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { getParentLayout, LAYOUT } from '/@/router/constant';
import { RoleEnum } from '/@/enums/roleEnum';
const permission: AppRouteModule = {
- layout: {
- path: '/permission',
- name: 'Permission',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/permission/front/page',
- meta: {
- icon: 'carbon:user-role',
- title: 'routes.demo.permission.permission',
- },
+ path: '/permission',
+ name: 'Permission',
+ component: LAYOUT,
+ redirect: '/permission/front/page',
+ meta: {
+ icon: 'carbon:user-role',
+ title: 'routes.demo.permission.permission',
},
- routes: [
+ children: [
{
- path: '/front',
+ path: 'front',
name: 'PermissionFrontDemo',
+ component: getParentLayout('PermissionFrontDemo'),
meta: {
title: 'routes.demo.permission.front',
},
@@ -60,8 +59,9 @@ const permission: AppRouteModule = {
],
},
{
- path: '/back',
+ path: 'back',
name: 'PermissionBackDemo',
+ component: getParentLayout('PermissionBackDemo'),
meta: {
title: 'routes.demo.permission.back',
},
diff --git a/src/router/routes/modules/demo/table.ts b/src/router/routes/modules/demo/table.ts
index 8e3bb1e1..9280b56b 100644
--- a/src/router/routes/modules/demo/table.ts
+++ b/src/router/routes/modules/demo/table.ts
@@ -1,22 +1,20 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const table: AppRouteModule = {
- layout: {
- path: '/table',
- name: 'TableDemo',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/table/basic',
- meta: {
- icon: 'ant-design:table-outlined',
- title: 'routes.demo.table.table',
- },
+ path: '/table',
+ name: 'TableDemo',
+ component: LAYOUT,
+ redirect: '/table/basic',
+ meta: {
+ icon: 'ant-design:table-outlined',
+ title: 'routes.demo.table.table',
},
- routes: [
+ children: [
{
- path: '/basic',
+ path: 'basic',
name: 'TableBasicDemo',
component: () => import('/@/views/demo/table/Basic.vue'),
meta: {
@@ -24,7 +22,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/treeTable',
+ path: 'treeTable',
name: 'TreeTableDemo',
component: () => import('/@/views/demo/table/TreeTable.vue'),
meta: {
@@ -32,7 +30,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/fetchTable',
+ path: 'fetchTable',
name: 'FetchTableDemo',
component: () => import('/@/views/demo/table/FetchTable.vue'),
meta: {
@@ -40,7 +38,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/fixedColumn',
+ path: 'fixedColumn',
name: 'FixedColumnDemo',
component: () => import('/@/views/demo/table/FixedColumn.vue'),
meta: {
@@ -48,7 +46,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/customerCell',
+ path: 'customerCell',
name: 'CustomerCellDemo',
component: () => import('/@/views/demo/table/CustomerCell.vue'),
meta: {
@@ -56,7 +54,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/formTable',
+ path: 'formTable',
name: 'FormTableDemo',
component: () => import('/@/views/demo/table/FormTable.vue'),
meta: {
@@ -64,7 +62,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/useTable',
+ path: 'useTable',
name: 'UseTableDemo',
component: () => import('/@/views/demo/table/UseTable.vue'),
meta: {
@@ -72,7 +70,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/refTable',
+ path: 'refTable',
name: 'RefTableDemo',
component: () => import('/@/views/demo/table/RefTable.vue'),
meta: {
@@ -80,7 +78,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/multipleHeader',
+ path: 'multipleHeader',
name: 'MultipleHeaderDemo',
component: () => import('/@/views/demo/table/MultipleHeader.vue'),
meta: {
@@ -88,7 +86,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/mergeHeader',
+ path: 'mergeHeader',
name: 'MergeHeaderDemo',
component: () => import('/@/views/demo/table/MergeHeader.vue'),
meta: {
@@ -96,7 +94,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/expandTable',
+ path: 'expandTable',
name: 'ExpandTableDemo',
component: () => import('/@/views/demo/table/ExpandTable.vue'),
meta: {
@@ -104,7 +102,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/fixedHeight',
+ path: 'fixedHeight',
name: 'FixedHeightDemo',
component: () => import('/@/views/demo/table/FixedHeight.vue'),
meta: {
@@ -112,7 +110,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/footerTable',
+ path: 'footerTable',
name: 'FooterTableDemo',
component: () => import('/@/views/demo/table/FooterTable.vue'),
meta: {
@@ -120,7 +118,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/editCellTable',
+ path: 'editCellTable',
name: 'EditCellTableDemo',
component: () => import('/@/views/demo/table/EditCellTable.vue'),
meta: {
@@ -128,7 +126,7 @@ const table: AppRouteModule = {
},
},
{
- path: '/editRowTable',
+ path: 'editRowTable',
name: 'EditRowTableDemo',
component: () => import('/@/views/demo/table/EditRowTable.vue'),
meta: {
diff --git a/src/router/routes/modules/demo/tree.ts b/src/router/routes/modules/demo/tree.ts
index b0c2f1c6..5d3facb8 100644
--- a/src/router/routes/modules/demo/tree.ts
+++ b/src/router/routes/modules/demo/tree.ts
@@ -1,21 +1,19 @@
import type { AppRouteModule } from '/@/router/types';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+import { LAYOUT } from '/@/router/constant';
const tree: AppRouteModule = {
- layout: {
- path: '/tree',
- name: 'TreeDemo',
- component: PAGE_LAYOUT_COMPONENT,
- redirect: '/tree/basic',
- meta: {
- icon: 'clarity:tree-view-line',
- title: 'routes.demo.tree.tree',
- },
+ path: '/tree',
+ name: 'TreeDemo',
+ component: LAYOUT,
+ redirect: '/tree/basic',
+ meta: {
+ icon: 'clarity:tree-view-line',
+ title: 'routes.demo.tree.tree',
},
- routes: [
+ children: [
{
- path: '/basic',
+ path: 'basic',
name: 'BasicTreeDemo',
component: () => import('/@/views/demo/tree/index.vue'),
meta: {
@@ -23,7 +21,7 @@ const tree: AppRouteModule = {
},
},
{
- path: '/editTree',
+ path: 'editTree',
name: 'EditTreeDemo',
component: () => import('/@/views/demo/tree/EditTree.vue'),
meta: {
@@ -31,7 +29,7 @@ const tree: AppRouteModule = {
},
},
{
- path: '/actionTree',
+ path: 'actionTree',
name: 'ActionTreeDemo',
component: () => import('/@/views/demo/tree/ActionTree.vue'),
meta: {
diff --git a/src/router/routes/modules/home.ts b/src/router/routes/modules/home.ts
new file mode 100644
index 00000000..daa54740
--- /dev/null
+++ b/src/router/routes/modules/home.ts
@@ -0,0 +1,28 @@
+import type { AppRouteModule } from '/@/router/types';
+
+import { LAYOUT } from '/@/router/constant';
+
+const dashboard: AppRouteModule = {
+ path: '/home',
+ name: 'Home',
+ component: LAYOUT,
+ redirect: '/home/welcome',
+ meta: {
+ icon: 'ant-design:home-outlined',
+ title: 'routes.dashboard.welcome',
+ },
+ children: [
+ {
+ path: 'welcome',
+ name: 'Welcome',
+ component: () => import('/@/views/dashboard/welcome/index.vue'),
+ meta: {
+ title: 'routes.dashboard.welcome',
+ affix: true,
+ icon: 'ant-design:home-outlined',
+ },
+ },
+ ],
+};
+
+export default dashboard;
diff --git a/src/router/types.d.ts b/src/router/types.d.ts
index cea77722..b85d3ce1 100644
--- a/src/router/types.d.ts
+++ b/src/router/types.d.ts
@@ -1,5 +1,6 @@
import type { RouteRecordRaw } from 'vue-router';
import { RoleEnum } from '/@/enums/roleEnum';
+import Component from '/@/components/types';
export interface RouteMeta {
// title
title: string;
@@ -24,24 +25,23 @@ export interface RouteMeta {
// Whether the route has been dynamically added
hideBreadcrumb?: boolean;
- // disabled redirect
- disabledRedirect?: boolean;
-
// close loading
afterCloseLoading?: boolean;
// Is it in the tab
inTab?: boolean;
// Carrying parameters
carryParam?: boolean;
+
+ single?: boolean;
}
export interface AppRouteRecordRaw extends Omit {
name: string;
meta: RouteMeta;
- component?: any;
- components?: any;
+ component?: Component;
+ components?: Component;
children?: AppRouteRecordRaw[];
- props?: any;
+ props?: Record;
fullPath?: string;
}
export interface MenuTag {
@@ -75,11 +75,12 @@ export interface MenuModule {
menu: Menu;
}
-interface RouteModule {
- layout: AppRouteRecordRaw;
- routes: AppRouteRecordRaw[];
- children?: AppRouteRecordRaw[];
- component?: any;
-}
+// interface RouteModule {
+// layout: AppRouteRecordRaw;
+// routes: AppRouteRecordRaw[];
+// children?: AppRouteRecordRaw[];
+// component?: Component;
+// }
-export type AppRouteModule = RouteModule | AppRouteRecordRaw;
+// export type AppRouteModule = RouteModule | AppRouteRecordRaw;
+export type AppRouteModule = AppRouteRecordRaw;
diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts
index b46f938f..ab1497bc 100644
--- a/src/store/modules/permission.ts
+++ b/src/store/modules/permission.ts
@@ -1,4 +1,3 @@
-import { REDIRECT_ROUTE } from '/@/router/constant';
import type { AppRouteRecordRaw, Menu } from '/@/router/types';
import store from '/@/store/index';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
@@ -15,15 +14,13 @@ import { filter } from '/@/utils/helper/treeHelper';
import { toRaw } from 'vue';
import { getMenuListById } from '/@/api/sys/menu';
-import { genRouteModule, transformObjToRoute } from '/@/utils/helper/routeHelper';
-import { transformRouteToMenu } from '/@/utils/helper/menuHelper';
+import { transformObjToRoute } from '/@/router/helper/routeHelper';
+import { transformRouteToMenu } from '/@/router/helper/menuHelper';
import { useMessage } from '/@/hooks/web/useMessage';
// import { warn } from '/@/utils/log';
import { useI18n } from '/@/hooks/web/useI18n';
-const { t } = useI18n();
-
const { createMessage } = useMessage();
const NAME = 'permission';
hotModuleUnregisterModule(NAME);
@@ -87,6 +84,7 @@ class Permission extends VuexModule {
@Action
async buildRoutesAction(id?: number | string): Promise {
+ const { t } = useI18n();
let routes: AppRouteRecordRaw[] = [];
const roleList = toRaw(userStore.getRoleListState);
@@ -95,17 +93,15 @@ class Permission extends VuexModule {
// role permissions
if (permissionMode === PermissionModeEnum.ROLE) {
routes = filter(asyncRoutes, (route) => {
- const { meta } = route;
- const { roles } = meta!;
+ const { meta } = route as AppRouteRecordRaw;
+ const { roles } = meta || {};
if (!roles) return true;
return roleList.some((role) => roles.includes(role));
});
// 如果确定不需要做后台动态权限,请将下面整个判断注释
} else if (permissionMode === PermissionModeEnum.BACK) {
- const messageKey = 'loadMenu';
createMessage.loading({
content: t('sys.app.menuLoading'),
- key: messageKey,
duration: 1,
});
// 这里获取后台路由菜单逻辑自行修改
@@ -118,10 +114,10 @@ class Permission extends VuexModule {
routeList = transformObjToRoute(routeList);
// 后台路由转菜单结构
const backMenuList = transformRouteToMenu(routeList);
+
this.commitBackMenuListState(backMenuList);
- // 生成路由
- routes = genRouteModule(routeList) as AppRouteRecordRaw[];
- routes.push(REDIRECT_ROUTE);
+
+ routes = routeList;
}
return routes;
}
diff --git a/src/store/modules/tab.ts b/src/store/modules/tab.ts
index f619c54c..f09900dd 100644
--- a/src/store/modules/tab.ts
+++ b/src/store/modules/tab.ts
@@ -1,53 +1,43 @@
-import { computed, toRaw } from 'vue';
-import type { AppRouteRecordRaw, RouteMeta } from '/@/router/types.d';
+import { toRaw } from 'vue';
import { unref } from 'vue';
import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { PageEnum } from '/@/enums/pageEnum';
-import { appStore } from '/@/store/modules/app';
import { userStore } from './user';
import store from '/@/store';
import router from '/@/router';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
-import { getCurrentTo } from '/@/utils/helper/routeHelper';
+import { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
+import { getRoute } from '/@/router/helper/routeHelper';
+import { useGo, useRedo } from '/@/hooks/web/usePage';
-type CacheName = string | symbol | null | undefined;
-
-/**
- * @description: vuex Tab模块
- */
// declare namespace TabsStore {
-export interface TabItem {
- fullPath: string;
- path?: string;
- params?: any;
- query?: any;
- name?: CacheName;
- meta?: RouteMeta;
-}
const NAME = 'tab';
hotModuleUnregisterModule(NAME);
-const getOpenKeepAliveRef = computed(() => appStore.getProjectConfig.openKeepAlive);
+export const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';
+
+function isGotoPage() {
+ const go = useGo();
+ go(unref(router.currentRoute).path, true);
+}
@Module({ namespaced: true, name: NAME, dynamic: true, store })
class Tab extends VuexModule {
+ cachedMapState = new Map();
+
// tab list
- tabsState: TabItem[] = [];
- // tab cache list
- keepAliveTabsState: CacheName[] = [];
-
- currentContextMenuIndexState = -1;
-
- currentContextMenuState: TabItem | null = null;
+ tabsState: RouteLocationNormalized[] = [];
// Last route change
- lastChangeRouteState: AppRouteRecordRaw | null = null;
+ lastChangeRouteState: RouteLocationNormalized | null = null;
+
+ lastDragEndIndexState = 0;
get getTabsState() {
return this.tabsState;
@@ -57,56 +47,93 @@ class Tab extends VuexModule {
return this.lastChangeRouteState;
}
- get getCurrentContextMenuIndexState() {
- return this.currentContextMenuIndexState;
- }
-
- get getCurrentContextMenuState() {
- return this.currentContextMenuState;
- }
-
- get getKeepAliveTabsState() {
- return this.keepAliveTabsState;
- }
-
- get getCurrentTab(): TabItem {
+ get getCurrentTab(): RouteLocationNormalized {
const route = unref(router.currentRoute);
return this.tabsState.find((item) => item.path === route.path)!;
}
+ get getCachedMapState(): Map {
+ return this.cachedMapState;
+ }
+
+ get getLastDragEndIndexState(): number {
+ return this.lastDragEndIndexState;
+ }
+
@Mutation
- commitLastChangeRouteState(route: AppRouteRecordRaw): void {
+ commitLastChangeRouteState(route: RouteLocationNormalized): void {
if (!userStore.getTokenState) return;
this.lastChangeRouteState = route;
}
@Mutation
commitClearCache(): void {
- this.keepAliveTabsState = [];
+ this.cachedMapState = new Map();
}
@Mutation
- commitCurrentContextMenuIndexState(index: number): void {
- this.currentContextMenuIndexState = index;
- }
+ goToPage() {
+ const go = useGo();
+ const len = this.tabsState.length;
+ const { path } = unref(router.currentRoute);
- @Mutation
- commitCurrentContextMenuState(item: TabItem): void {
- this.currentContextMenuState = item;
- }
+ let toPath: PageEnum | string = PageEnum.BASE_HOME;
- /**
- * @description: add tab
- */
- @Mutation
- commitAddTab(route: AppRouteRecordRaw | TabItem): void {
- const { path, name, meta, fullPath, params, query } = route as TabItem;
- // 404 页面不需要添加tab
- if (path === PageEnum.ERROR_PAGE || !name) {
- return;
- } else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) {
- return;
+ if (len > 0) {
+ const page = this.tabsState[len - 1];
+ const p = page.fullPath || page.path;
+ if (p) {
+ toPath = p;
+ }
}
+ // Jump to the current page and report an error
+ path !== toPath && go(toPath as PageEnum, true);
+ }
+
+ @Mutation
+ commitCachedMapState(): void {
+ const cacheMap = new Map();
+
+ const pageCacheSet = new Set();
+ this.tabsState.forEach((tab) => {
+ const item = getRoute(tab);
+ const needAuth = !item.meta.ignoreAuth;
+ if (item.meta.affix) {
+ const name = item.name as string;
+ pageCacheSet.add(name);
+ } else if (item.matched && needAuth) {
+ const matched = item.matched;
+ const len = matched.length;
+
+ if (len < 2) return;
+
+ for (let i = 0; i < matched.length; i++) {
+ const key = matched[i].name as string;
+
+ if (i < 2) {
+ pageCacheSet.add(key);
+ }
+ if (i < len - 1) {
+ const { meta, name } = matched[i + 1];
+ if (meta && (meta.affix || needAuth)) {
+ const mapList = cacheMap.get(key) || [];
+ if (!mapList.includes(name as string)) {
+ mapList.push(name as string);
+ }
+ cacheMap.set(key, mapList);
+ }
+ }
+ }
+ }
+ });
+
+ cacheMap.set(PAGE_LAYOUT_KEY, Array.from(pageCacheSet));
+ this.cachedMapState = cacheMap;
+ }
+
+ @Mutation
+ commitTabRoutesState(route: RouteLocationNormalized) {
+ const { path, fullPath, params, query } = route;
let updateIndex = -1;
// 已经存在的页面,不重复添加tab
@@ -123,39 +150,18 @@ class Tab extends VuexModule {
this.tabsState.splice(updateIndex, 1, curTab);
return;
}
- this.tabsState.push({ path, fullPath, name, meta, params, query });
- if (unref(getOpenKeepAliveRef) && name) {
- const noKeepAlive = meta && meta.ignoreKeepAlive;
- const hasName = this.keepAliveTabsState.includes(name);
- !noKeepAlive && !hasName && this.keepAliveTabsState.push(name);
- }
+ this.tabsState.push(route);
}
/**
* @description: close tab
*/
@Mutation
- commitCloseTab(route: AppRouteRecordRaw | TabItem): void {
- try {
- const { fullPath, name, meta: { affix } = {} } = route;
- if (affix) return;
- const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
- index !== -1 && this.tabsState.splice(index, 1);
-
- if (unref(getOpenKeepAliveRef) && name) {
- const i = this.keepAliveTabsState.findIndex((item) => item === name);
- i !== -1 && this.keepAliveTabsState.splice(i, 1);
- }
- } catch (error) {}
- }
-
- @Mutation
- commitCloseTabKeepAlive(route: AppRouteRecordRaw | TabItem): void {
- const { name } = route;
- if (unref(getOpenKeepAliveRef) && name) {
- const i = this.keepAliveTabsState.findIndex((item) => item === name);
- i !== -1 && toRaw(this.keepAliveTabsState).splice(i, 1);
- }
+ commitCloseTab(route: RouteLocationNormalized): void {
+ const { fullPath, meta: { affix } = {} } = route;
+ if (affix) return;
+ const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
+ index !== -1 && this.tabsState.splice(index, 1);
}
@Mutation
@@ -163,16 +169,12 @@ class Tab extends VuexModule {
this.tabsState = this.tabsState.filter((item) => {
return item.meta && item.meta.affix;
});
- const names = this.tabsState.map((item) => item.name);
- this.keepAliveTabsState = names as string[];
}
@Mutation
commitResetState(): void {
this.tabsState = [];
- this.currentContextMenuState = null;
- this.currentContextMenuIndexState = -1;
- this.keepAliveTabsState = [];
+ this.cachedMapState = new Map();
}
@Mutation
@@ -181,73 +183,149 @@ class Tab extends VuexModule {
this.tabsState.splice(oldIndex, 1);
this.tabsState.splice(newIndex, 0, currentTab);
+ this.lastDragEndIndexState = this.lastDragEndIndexState + 1;
}
@Mutation
- closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void {
+ closeMultipleTab({ pathList }: { pathList: string[] }): void {
this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
- if (unref(getOpenKeepAliveRef) && nameList) {
- this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter(
- (item) => !nameList.includes(item as string)
- );
- }
}
@Action
- closeLeftTabAction(route: AppRouteRecordRaw | TabItem): void {
+ addTabAction(route: RouteLocationNormalized) {
+ const { path, name } = route;
+ // 404 页面不需要添加tab
+ if (
+ path === PageEnum.ERROR_PAGE ||
+ !name ||
+ [REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
+ ) {
+ return;
+ }
+ this.commitTabRoutesState(getRoute(route));
+
+ this.commitCachedMapState();
+ }
+
+ @Mutation
+ commitRedoPage() {
+ const route = router.currentRoute.value;
+
+ for (const [key, value] of this.cachedMapState) {
+ const index = value.findIndex((item) => item === (route.name as string));
+ if (index === -1) {
+ continue;
+ }
+ if (value.length === 1) {
+ this.cachedMapState.delete(key);
+ continue;
+ }
+ value.splice(index, 1);
+ this.cachedMapState.set(key, value);
+ }
+ const redo = useRedo();
+ redo();
+ }
+
+ @Action
+ closeAllTabAction() {
+ this.commitCloseAllTab();
+ this.commitClearCache();
+ this.goToPage();
+ }
+
+ @Action
+ closeTabAction(tab: RouteLocationNormalized) {
+ function getObj(tabItem: RouteLocationNormalized) {
+ const { params, path, query } = tabItem;
+ return {
+ params: params || {},
+ path,
+ query: query || {},
+ };
+ }
+ const { currentRoute, replace } = router;
+
+ const { path } = unref(currentRoute);
+ if (path !== tab.path) {
+ // Closed is not the activation tab
+ this.commitCloseTab(tab);
+ return;
+ }
+
+ // Closed is activated atb
+ let toObj: RouteLocationRaw = {};
+
+ const index = this.getTabsState.findIndex((item) => item.path === path);
+
+ // If the current is the leftmost tab
+ if (index === 0) {
+ // There is only one tab, then jump to the homepage, otherwise jump to the right tab
+ if (this.getTabsState.length === 1) {
+ toObj = PageEnum.BASE_HOME;
+ } else {
+ // Jump to the right tab
+ const page = this.getTabsState[index + 1];
+ toObj = getObj(page);
+ }
+ } else {
+ // Close the current tab
+ const page = this.getTabsState[index - 1];
+ toObj = getObj(page);
+ }
+ this.commitCloseTab(currentRoute.value);
+ replace(toObj);
+ }
+
+ @Action
+ closeTabByKeyAction(key: string) {
+ const index = this.tabsState.findIndex((item) => (item.fullPath || item.path) === key);
+ index !== -1 && this.closeTabAction(this.tabsState[index]);
+ }
+
+ @Action
+ closeLeftTabAction(route: RouteLocationNormalized): void {
const index = this.tabsState.findIndex((item) => item.path === route.path);
if (index > 0) {
const leftTabs = this.tabsState.slice(0, index);
const pathList: string[] = [];
- const nameList: string[] = [];
for (const item of leftTabs) {
const affix = item.meta ? item.meta.affix : false;
if (!affix) {
pathList.push(item.fullPath);
- nameList.push(item.name as string);
}
}
- this.closeMultipleTab({ pathList, nameList });
+ this.closeMultipleTab({ pathList });
}
+ this.commitCachedMapState();
+ isGotoPage();
}
@Action
- addTabByPathAction(): void {
- const toRoute = getCurrentTo();
- if (!toRoute) return;
- const { meta } = toRoute;
- if (meta && meta.affix) {
- return;
- }
- this.commitAddTab((toRoute as unknown) as AppRouteRecordRaw);
- }
-
- @Action
- closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
+ closeRightTabAction(route: RouteLocationNormalized): void {
const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
if (index >= 0 && index < this.tabsState.length - 1) {
const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
const pathList: string[] = [];
- const nameList: string[] = [];
for (const item of rightTabs) {
const affix = item.meta ? item.meta.affix : false;
if (!affix) {
pathList.push(item.fullPath);
- nameList.push(item.name as string);
}
}
- this.closeMultipleTab({ pathList, nameList });
+ this.closeMultipleTab({ pathList });
}
+ this.commitCachedMapState();
+ isGotoPage();
}
@Action
- closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void {
+ closeOtherTabAction(route: RouteLocationNormalized): void {
const closePathList = this.tabsState.map((item) => item.fullPath);
const pathList: string[] = [];
- const nameList: string[] = [];
closePathList.forEach((path) => {
if (path !== route.fullPath) {
const closeItem = this.tabsState.find((item) => item.path === path);
@@ -255,11 +333,12 @@ class Tab extends VuexModule {
const affix = closeItem.meta ? closeItem.meta.affix : false;
if (!affix) {
pathList.push(closeItem.fullPath);
- nameList.push(closeItem.name as string);
}
}
});
- this.closeMultipleTab({ pathList, nameList });
+ this.closeMultipleTab({ pathList });
+ this.commitCachedMapState();
+ isGotoPage();
}
}
export const tabStore = getModule(Tab);
diff --git a/src/utils/helper/dynamicImport.ts b/src/utils/helper/dynamicImport.ts
deleted file mode 100644
index a1738a72..00000000
--- a/src/utils/helper/dynamicImport.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-// The content here is just for type approval. The actual file content is overwritten by transform
-export default function (id: string) {
- const dynamicImportModule: any = id;
- return dynamicImportModule;
-}
diff --git a/src/utils/helper/routeHelper.ts b/src/utils/helper/routeHelper.ts
deleted file mode 100644
index a1c8e3ba..00000000
--- a/src/utils/helper/routeHelper.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import type { AppRouteModule, AppRouteRecordRaw, RouteModule } from '/@/router/types';
-import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
-import { createRouter, createWebHashHistory } from 'vue-router';
-
-import { appStore } from '/@/store/modules/app';
-import { tabStore } from '/@/store/modules/tab';
-import { toRaw } from 'vue';
-import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
-// import { isDevMode } from '/@/utils/env';
-import dynamicImport from './dynamicImport';
-import { omit } from 'lodash-es';
-
-let currentTo: RouteLocationNormalized | null = null;
-
-export function getCurrentTo() {
- return currentTo;
-}
-
-export function setCurrentTo(to: RouteLocationNormalized) {
- currentTo = to;
-}
-// 转化路由模块
-// 将多级转成2层。keepAlive问题
-export function genRouteModule(moduleList: AppRouteModule[] | AppRouteRecordRaw[]) {
- const ret: AppRouteRecordRaw[] = [];
- for (const routeMod of moduleList) {
- let routes: RouteRecordRaw[] = [];
- let layout: AppRouteRecordRaw | undefined;
- if (Reflect.has(routeMod, 'routes')) {
- routes = (routeMod as RouteModule).routes as any;
- layout = (routeMod as RouteModule).layout;
- } else if (Reflect.has(routeMod, 'path')) {
- layout = omit(routeMod, 'children') as any;
- routes = (routeMod.children as RouteRecordRaw[]) || ([] as RouteRecordRaw[]);
- }
-
- const router = createRouter({ routes, history: createWebHashHistory() });
-
- const flatList = (toRaw(router.getRoutes()).filter(
- (item) => item.children.length === 0
- ) as unknown) as AppRouteRecordRaw[];
- flatList.forEach((item) => {
- item.path = `${layout ? layout.path : ''}${item.path}`;
- });
- if (layout) {
- layout.children = flatList;
- ret.push(layout);
- } else {
- ret.push(...flatList);
- }
- }
- return ret as RouteRecordRaw[];
-}
-
-// 动态引入
-function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
- if (!routes) return;
- routes.forEach((item) => {
- const { component } = item;
- const { children } = item;
- if (component) {
- item.component = dynamicImport(component);
- }
-
- children && asyncImportRoute(children);
- });
-}
-
-function getLayoutComp(comp: string) {
- return comp === 'PAGE_LAYOUT' ? PAGE_LAYOUT_COMPONENT : '';
-}
-
-// 将后台对象转成路由对象
-export function transformObjToRoute(routeList: AppRouteModule[]): T[] {
- routeList.forEach((route) => {
- asyncImportRoute(
- Reflect.has(route, 'routes') ? (route as RouteModule).routes : route.children || []
- );
- if ((route as RouteModule).layout) {
- (route as RouteModule).layout.component = getLayoutComp(
- (route as RouteModule).layout.component
- );
- } else {
- route.component = getLayoutComp(route.component);
- (route as RouteModule).layout = omit(route, 'children') as any;
- }
- });
- return (routeList as unknown) as T[];
-}
-
-//
-export function getIsOpenTab(toPath: string) {
- const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
-
- if (show && openKeepAlive) {
- const tabList = tabStore.getTabsState;
- return tabList.some((tab) => tab.path === toPath);
- }
- return false;
-}
-
-export function getParams(data: any = {}) {
- const { params = {} } = data;
- let ret = '';
- Object.keys(params).forEach((key) => {
- const p = params[key];
- ret += `/${p}`;
- });
- return ret;
-}
diff --git a/src/views/demo/feat/copy/index.vue b/src/views/demo/feat/copy/index.vue
index 7954a45c..6ac03a64 100644
--- a/src/views/demo/feat/copy/index.vue
+++ b/src/views/demo/feat/copy/index.vue
@@ -15,6 +15,7 @@
import { useMessage } from '/@/hooks/web/useMessage';
export default defineComponent({
+ name: 'Copy',
components: { CollapseContainer },
setup() {
const valueRef = ref('');
diff --git a/src/views/demo/level/Menu111.vue b/src/views/demo/level/Menu111.vue
new file mode 100644
index 00000000..34b30d3c
--- /dev/null
+++ b/src/views/demo/level/Menu111.vue
@@ -0,0 +1,11 @@
+
+
+ 多层级缓存-页面1-1-1
+
+
+
+
+
diff --git a/src/views/demo/level/Menu12.vue b/src/views/demo/level/Menu12.vue
new file mode 100644
index 00000000..08834352
--- /dev/null
+++ b/src/views/demo/level/Menu12.vue
@@ -0,0 +1,11 @@
+
+
+ 多层级缓存-页面1-2
+
+
+
+
+
diff --git a/src/views/demo/level/Menu2.vue b/src/views/demo/level/Menu2.vue
new file mode 100644
index 00000000..28429a65
--- /dev/null
+++ b/src/views/demo/level/Menu2.vue
@@ -0,0 +1,13 @@
+
+
+ 多层级缓存-页面2
+
+
+
+
+
diff --git a/src/views/sys/redirect/index.vue b/src/views/sys/redirect/index.vue
index cc8efda3..2ef66ec6 100644
--- a/src/views/sys/redirect/index.vue
+++ b/src/views/sys/redirect/index.vue
@@ -1,3 +1,6 @@
+
+
+
diff --git a/yarn.lock b/yarn.lock
index 548a0466..845dc34f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1061,10 +1061,10 @@
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
-"@iconify/json@^1.1.266":
- version "1.1.266"
- resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.266.tgz#3537de808399652b3ca2c89a561216324121b785"
- integrity sha512-I8S9lChQATaRroMGccdOQkFbBtMt4C2V/PQGiSjDq9yzdyqDCrPNN9X1qM4FoQt84zfW/+JMHIgShi42E+SXeA==
+"@iconify/json@^1.1.267":
+ version "1.1.267"
+ resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.267.tgz#52ab5390fcaf95e0d68260523a3a3fbc575dfe01"
+ integrity sha512-VKNvyALvbuwsXO7r2XvdoqdctmvJzp1/XYOXRfhJ4w+sjtWYp8T3oRGDJ0AZTafzGiBBUaMwCZVP+j87rqgD3w==
"@koa/cors@^3.1.0":
version "3.1.0"
@@ -1535,10 +1535,10 @@
resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==
-"@types/yargs@^15.0.10":
- version "15.0.10"
- resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.10.tgz#0fe3c8173a0d5c3e780b389050140c3f5ea6ea74"
- integrity sha512-z8PNtlhrj7eJNLmrAivM7rjBESG6JwC5xP3RVk12i/8HVP7Xnx/sEmERnRImyEuUaJfO942X0qMOYsoupaJbZQ==
+"@types/yargs@^15.0.11":
+ version "15.0.11"
+ resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.11.tgz#361d7579ecdac1527687bcebf9946621c12ab78c"
+ integrity sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA==
dependencies:
"@types/yargs-parser" "*"
@@ -1644,6 +1644,17 @@
estree-walker "^2.0.1"
source-map "^0.6.1"
+"@vue/compiler-core@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.4.tgz#0122aca6eada4cb28b39ed930af917444755e330"
+ integrity sha512-snpMICsbWTZqBFnPB03qr4DtiSxVYfDF3DvbDSkN9Z9NTM8Chl8E/lYhKBSsvauq91DAWAh8PU3lr9vrLyQsug==
+ dependencies:
+ "@babel/parser" "^7.12.0"
+ "@babel/types" "^7.12.0"
+ "@vue/shared" "3.0.4"
+ estree-walker "^2.0.1"
+ source-map "^0.6.1"
+
"@vue/compiler-dom@3.0.2":
version "3.0.2"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.2.tgz#1d40de04bcdf9aabb79fb6a802dd70a2f3c2992a"
@@ -1660,6 +1671,14 @@
"@vue/compiler-core" "3.0.3"
"@vue/shared" "3.0.3"
+"@vue/compiler-dom@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.4.tgz#834fd4b15c5698cf9f4505c2bfbccca058a843eb"
+ integrity sha512-FOxbHBIkkGjYQeTz1DlXQjS1Ms8EPXQWsdTdTPeohoS0KzCz6RiOjiAG+jLtMi6Nr5GX2h0TlCvcnI8mcsicFQ==
+ dependencies:
+ "@vue/compiler-core" "3.0.4"
+ "@vue/shared" "3.0.4"
+
"@vue/compiler-sfc@*", "@vue/compiler-sfc@^3.0.0-rc.5":
version "3.0.2"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.2.tgz#22c70fed72c347a4d5fa2db2e80594b3193dce57"
@@ -1704,6 +1723,28 @@
postcss-selector-parser "^6.0.4"
source-map "^0.6.1"
+"@vue/compiler-sfc@^3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.4.tgz#2119fe1e68d2c268aafa20461c82c139a9adf8e0"
+ integrity sha512-brDn6HTuK6R3oBCjtMPPsIpyJEZFinlnxjtBXww/goFJOJBAU9CrsdegwyZItNnixCFUIg4CLv4Nj1Eg/eKlfg==
+ dependencies:
+ "@babel/parser" "^7.12.0"
+ "@babel/types" "^7.12.0"
+ "@vue/compiler-core" "3.0.4"
+ "@vue/compiler-dom" "3.0.4"
+ "@vue/compiler-ssr" "3.0.4"
+ "@vue/shared" "3.0.4"
+ consolidate "^0.16.0"
+ estree-walker "^2.0.1"
+ hash-sum "^2.0.0"
+ lru-cache "^5.1.1"
+ magic-string "^0.25.7"
+ merge-source-map "^1.1.0"
+ postcss "^7.0.32"
+ postcss-modules "^3.2.2"
+ postcss-selector-parser "^6.0.4"
+ source-map "^0.6.1"
+
"@vue/compiler-ssr@3.0.2":
version "3.0.2"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.2.tgz#73af4d274a79bfcc72a996a9b45f1072e7deaa26"
@@ -1720,6 +1761,14 @@
"@vue/compiler-dom" "3.0.3"
"@vue/shared" "3.0.3"
+"@vue/compiler-ssr@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.4.tgz#ccbd1f55734d51d1402fad825ac102002a7a07c7"
+ integrity sha512-4aYWQEL4+LS4+D44K9Z7xMOWMEjBsz4Li9nMcj2rxRQ35ewK6uFPodvs6ORP60iBDSkwUFZoldFlNemQlu1BFw==
+ dependencies:
+ "@vue/compiler-dom" "3.0.4"
+ "@vue/shared" "3.0.4"
+
"@vue/reactivity@3.0.2":
version "3.0.2"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.2.tgz#42ed5af6025b494a5e69b05169fcddf04eebfe77"
@@ -1734,6 +1783,13 @@
dependencies:
"@vue/shared" "3.0.3"
+"@vue/reactivity@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.4.tgz#b6599dd8271a745960a03f05744ccf7991ba5d8d"
+ integrity sha512-AFTABrLhUYZY2on3ea9FxeXal7w3f6qIp9gT+/oG93H7dFTL5LvVnxygCopv7tvkIl/GSGQb/yK1D1gmXx1Pww==
+ dependencies:
+ "@vue/shared" "3.0.4"
+
"@vue/runtime-core@3.0.2":
version "3.0.2"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.2.tgz#d7ed462af1cb0bf9836668e4e6fab3f2f4b1bc00"
@@ -1750,6 +1806,14 @@
"@vue/reactivity" "3.0.3"
"@vue/shared" "3.0.3"
+"@vue/runtime-core@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.4.tgz#a5b9a001560b1fd8c01a43f68b764c555de7836c"
+ integrity sha512-qH9e4kqU7b3u1JewvLmGmoAGY+mnuBqz7aEKb2mhpEgwa1yFv496BRuUfMXXMCix3+TndUVMJ8jt41FSdNppwg==
+ dependencies:
+ "@vue/reactivity" "3.0.4"
+ "@vue/shared" "3.0.4"
+
"@vue/runtime-dom@3.0.3":
version "3.0.3"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.3.tgz#5e3e5e5418b9defcac988d2be0cf65596fa2cc03"
@@ -1759,6 +1823,15 @@
"@vue/shared" "3.0.3"
csstype "^2.6.8"
+"@vue/runtime-dom@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.4.tgz#6f81aec545f24511d2c28a315aa3391420b69c68"
+ integrity sha512-BGIoiTSESzWUhN0Ofi2X/q+HN8f6IUFmUEyyBGKbmx7DTAJNZhFfjqsepfXQrM5IGeTfJLB1ZEVyroDQJNXq3g==
+ dependencies:
+ "@vue/runtime-core" "3.0.4"
+ "@vue/shared" "3.0.4"
+ csstype "^2.6.8"
+
"@vue/runtime-dom@^3.0.0":
version "3.0.2"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.2.tgz#9d166d03225558025d3d80f5039b646e0051b71c"
@@ -1778,6 +1851,11 @@
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.3.tgz#ef12ebff93a446df281e8a0fd765b5aea8e7745b"
integrity sha512-yGgkF7u4W0Dmwri9XdeY50kOowN4UIX7aBQ///jbxx37itpzVjK7QzvD3ltQtPfWaJDGBfssGL0wpAgwX9OJpQ==
+"@vue/shared@3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.4.tgz#6dc50f593bdfdeaa6183d1dbc15e2d45e7c6b8b3"
+ integrity sha512-Swfbz31AaMX48CpFl+YmIrqOH9MgJMTrltG9e26A4ZxYx9LjGuMV+41WnxFzS3Bc9nbrc6sDPM37G6nIT8NJSg==
+
"@vuedx/analyze@0.2.4-0":
version "0.2.4-0"
resolved "https://registry.npmjs.org/@vuedx/analyze/-/analyze-0.2.4-0.tgz#52766a6dcd2867320409fe517540fd0bf0394d48"
@@ -3013,10 +3091,10 @@ crc-32@~1.2.0:
exit-on-epipe "~1.0.1"
printj "~1.1.0"
-cross-env@^7.0.2:
- version "7.0.2"
- resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
- integrity sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
dependencies:
cross-spawn "^7.0.1"
@@ -3449,17 +3527,17 @@ es-module-lexer@^0.3.25:
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
-esbuild-register@^1.1.0:
- version "1.1.0"
- resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-1.1.0.tgz#8ec1fbf6b84f0d7654b87eec04029a383dcb539d"
- integrity sha512-A+KGHDc7me/ATyNqnVQKsHxt2A/ORVvV2gmukx5ZtVcy5HVf19QBbHdfdP5QHFA8rF/WHmcnDxaxewu+VUvUhQ==
+esbuild-register@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-1.1.1.tgz#7d50e87ac0b9000085d9e6d9a78e4c2223fcce83"
+ integrity sha512-hAPWuaUkPDLXCENc/AigJZaaDCvCkpmghRw8XPyT+rk08JHcIgUrmw1uabbUTfa6B6J9Wo2bFufb01JjbmzcfQ==
dependencies:
joycon "^2.2.5"
pirates "^4.0.1"
source-map-support "^0.5.19"
strip-json-comments "^3.1.1"
-esbuild@^0.7.17, esbuild@^0.7.19:
+esbuild@^0.7.19:
version "0.7.22"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.22.tgz#9149b903f8128b7c45a754046c24199d76bbe08e"
integrity sha512-B43SYg8LGWYTCv9Gs0RnuLNwjzpuWOoCaZHTWEDEf5AfrnuDMerPVMdCEu7xOdhFvQ+UqfP2MGU9lxEy0JzccA==
@@ -3469,6 +3547,11 @@ esbuild@^0.8.12:
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.15.tgz#cbc4d82a7fc4571d455233456e6fba83fd0364f1"
integrity sha512-mSaLo9t/oYtQE6FRUEdO47Pr8PisSPzHtgr+LcihIcjBEhbYwjT6WLCQ7noDoTBfIatBCw229rtmIwl9u9UQwg==
+esbuild@^0.8.17:
+ version "0.8.17"
+ resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.17.tgz#1c16c6d5988dcfdcf27a7e1612b7fd05e1477c54"
+ integrity sha512-ReHap+Iyn5BQF0B8F3xrLwu+j57ri5uDUw2ej9XTPAuFDebYiWwRzBY4jhF610bklveXLbCGim/8/2wQKQlu1w==
+
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -3581,13 +3664,13 @@ esm@^3.2.25:
resolved "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
-esno@^0.2.4:
- version "0.2.4"
- resolved "https://registry.npmjs.org/esno/-/esno-0.2.4.tgz#b04a368181bc03e5d11d5147106bf0d0ac4f3a48"
- integrity sha512-XlgsQe2va257kc1xsZg/X22fRyLVRNkCKEXjONoltA7HeXtmhrQ3n19all0eK0X6YRNE8X9qiVyWV0vMLZvY3w==
+esno@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.npmjs.org/esno/-/esno-0.3.0.tgz#c818996bdaaf2deaf81413d6f45538ffa6e41b42"
+ integrity sha512-4sF/j8jruQv9jScU8tNkgoDFLjyGxTTB8bmjRmWHyNNygra3WS3X0U1Cc7GuOvfSEjn3NDS57P0LRnzgiupKJg==
dependencies:
- esbuild "^0.7.17"
- esbuild-register "^1.1.0"
+ esbuild "^0.8.17"
+ esbuild-register "^1.1.1"
esm "^3.2.25"
espree@^6.2.1:
@@ -8335,6 +8418,15 @@ vue@^3.0.3:
"@vue/runtime-dom" "3.0.3"
"@vue/shared" "3.0.3"
+vue@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/vue/-/vue-3.0.4.tgz#872c65c143f5717bd5387c61613d9f55f4cc0f43"
+ integrity sha512-2o+AiQF8sAupyhbyl3oxVCl3WCwC/n5NI7VMM+gVQ231qvSB8eI7sCBloloqDJK6yA367EEtmRSeSCf4sxCC+A==
+ dependencies:
+ "@vue/compiler-dom" "3.0.4"
+ "@vue/runtime-dom" "3.0.4"
+ "@vue/shared" "3.0.4"
+
vuex-module-decorators@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/vuex-module-decorators/-/vuex-module-decorators-1.0.1.tgz#d34dafb5428a3636f1c26d3d014c15fc9659ccd0"