提交 215d8bab 编写于 作者: V Vben

refactor: refactor store

上级 700306bb
......@@ -28,6 +28,7 @@ export function generateModifyVars(dark = false) {
'success-color': '#55D187', // Success color
'error-color': '#ED6F6F', // False color
'warning-color': '#EFBD47', // Warning color
'border-color-base': '#EEEEEE',
'font-size-base': '14px', // Main font size
'border-radius-base': '2px', // Component/float fillet
'link-color': primary, // Link color
......
......@@ -16,9 +16,11 @@
<script>
(() => {
var htmlRoot = document.getElementById('htmlRoot');
const theme = window.localStorage.getItem('__APP__DARK__MODE__');
if (!htmlRoot || !theme) return;
htmlRoot.setAttribute('data-theme', theme);
var theme = window.localStorage.getItem('__APP__DARK__MODE__');
if (htmlRoot && theme) {
htmlRoot.setAttribute('data-theme', theme);
theme = htmlRoot = null;
}
})();
</script>
<div id="app">
......
......@@ -32,7 +32,7 @@
},
"dependencies": {
"@iconify/iconify": "^2.0.0-rc.6",
"@vueuse/core": "^4.8.0",
"@vueuse/core": "^4.8.1",
"@zxcvbn-ts/core": "^0.3.0",
"ant-design-vue": "^2.1.2",
"axios": "^0.21.1",
......@@ -43,6 +43,7 @@
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0",
"pinia": "^2.0.0-alpha.12",
"print-js": "^1.6.0",
"qrcode": "^1.4.4",
"sortablejs": "^1.13.0",
......@@ -52,8 +53,6 @@
"vue-i18n": "9.0.0",
"vue-router": "^4.0.6",
"vue-types": "^3.0.2",
"vuex": "^4.0.0",
"vuex-module-decorators": "^1.0.1",
"xlsx": "^0.16.9"
},
"devDependencies": {
......@@ -81,7 +80,7 @@
"conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"eslint": "^7.23.0",
"eslint": "^7.24.0",
"eslint-config-prettier": "^8.1.0",
"eslint-define-config": "^1.0.7",
"eslint-plugin-prettier": "^3.3.1",
......@@ -115,13 +114,14 @@
"vite-plugin-style-import": "^0.9.2",
"vite-plugin-svg-icons": "^0.4.1",
"vite-plugin-theme": "^0.6.3",
"vite-plugin-windicss": "0.12.5",
"vite-plugin-windicss": "0.13.1",
"vue-eslint-parser": "^7.6.0"
},
"resolutions": {
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China.If it is abroad, you can delete it",
"bin-wrapper": "npm:bin-wrapper-china",
"rollup": "^2.44.0"
"rollup": "^2.45.1",
"esbuild": "^0.11.6"
},
"repository": {
"type": "git",
......
......@@ -3,22 +3,24 @@
import { createAppProviderContext } from './useAppContext';
import designSetting from '/@/settings/designSetting';
import { prefixCls } from '/@/settings/designSetting';
import { createBreakpointListen } from '/@/hooks/event/useBreakpoint';
import { propTypes } from '/@/utils/propTypes';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
export default defineComponent({
name: 'AppProvider',
inheritAttrs: false,
props: {
prefixCls: propTypes.string.def(designSetting.prefixCls),
prefixCls: propTypes.string.def(prefixCls),
},
setup(props, { slots }) {
const isMobile = ref(false);
const isSetState = ref(false);
const appStore = useAppStore();
createBreakpointListen(({ screenMap, sizeEnum, width }) => {
const lgWidth = screenMap.get(sizeEnum.LG);
if (lgWidth) {
......@@ -42,20 +44,20 @@
split: menuSplit,
},
} = appStore.getProjectConfig;
appStore.commitProjectConfigState({
appStore.setProjectConfig({
menuSetting: {
type: MenuTypeEnum.SIDEBAR,
mode: MenuModeEnum.INLINE,
split: false,
},
});
appStore.commitBeforeMiniState({ menuMode, menuCollapsed, menuType, menuSplit });
appStore.setBeforeMiniInfo({ menuMode, menuCollapsed, menuType, menuSplit });
}
} else {
if (unref(isSetState)) {
isSetState.value = false;
const { menuMode, menuCollapsed, menuType, menuSplit } = appStore.getBeforeMiniState;
appStore.commitProjectConfigState({
const { menuMode, menuCollapsed, menuType, menuSplit } = appStore.getBeforeMiniInfo;
appStore.setProjectConfig({
menuSetting: {
type: menuType,
mode: menuMode,
......
<template>
<span :class="$attrs.class">
<Icon :icon="icon" />
<g-icon :icon="icon" />
</span>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { Icon } from '/@/components/Icon';
import { propTypes } from '/@/utils/propTypes';
export default defineComponent({
components: { Icon },
props: {
icon: propTypes.string,
icon: String,
},
});
</script>
......@@ -6,7 +6,6 @@
:class="prefixCls"
:activeSubMenuNames="activeSubMenuNames"
@select="handleSelect"
@open-change="handleOpenChange"
>
<template v-for="item in items" :key="item.path">
<SimpleSubMenu
......@@ -140,17 +139,11 @@
menuState.activeName = key;
}
function handleOpenChange(v) {
console.log('======================');
console.log(v);
console.log('======================');
}
return {
prefixCls,
getBindValues,
handleSelect,
getOpenKeys,
handleOpenChange,
...toRefs(menuState),
};
},
......
......@@ -2,94 +2,89 @@ import type { HeaderSetting } from '/#/config';
import { computed, unref } from 'vue';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useFullContent } from '/@/hooks/web/useFullContent';
import { MenuModeEnum } from '/@/enums/menuEnum';
const { getFullContent } = useFullContent();
const {
getMenuMode,
getSplit,
getShowHeaderTrigger,
getIsSidebarType,
getIsMixSidebar,
getIsTopMenu,
} = useMenuSetting();
const { getShowBreadCrumb, getShowLogo } = useRootSetting();
const getShowMixHeaderRef = computed(() => !unref(getIsSidebarType) && unref(getShowHeader));
export function useHeaderSetting() {
const { getFullContent } = useFullContent();
const appStore = useAppStore();
const getShowFullHeaderRef = computed(() => {
return (
!unref(getFullContent) &&
unref(getShowMixHeaderRef) &&
unref(getShowHeader) &&
!unref(getIsTopMenu) &&
!unref(getIsMixSidebar)
);
});
const getShowFullHeaderRef = computed(() => {
return (
!unref(getFullContent) &&
unref(getShowMixHeaderRef) &&
unref(getShowHeader) &&
!unref(getIsTopMenu) &&
!unref(getIsMixSidebar)
);
});
const getShowInsetHeaderRef = computed(() => {
const need = !unref(getFullContent) && unref(getShowHeader);
return (
(need && !unref(getShowMixHeaderRef)) ||
(need && unref(getIsTopMenu)) ||
(need && unref(getIsMixSidebar))
);
});
const getUnFixedAndFull = computed(() => !unref(getFixed) && !unref(getShowFullHeaderRef));
// Get header configuration
const getHeaderSetting = computed(() => appStore.getProjectConfig.headerSetting);
const getShowInsetHeaderRef = computed(() => {
const need = !unref(getFullContent) && unref(getShowHeader);
return (
(need && !unref(getShowMixHeaderRef)) ||
(need && unref(getIsTopMenu)) ||
(need && unref(getIsMixSidebar))
);
});
const getShowDoc = computed(() => unref(getHeaderSetting).showDoc);
const {
getMenuMode,
getSplit,
getShowHeaderTrigger,
getIsSidebarType,
getIsMixSidebar,
getIsTopMenu,
} = useMenuSetting();
const { getShowBreadCrumb, getShowLogo } = useRootSetting();
const getHeaderTheme = computed(() => unref(getHeaderSetting).theme);
const getShowMixHeaderRef = computed(() => !unref(getIsSidebarType) && unref(getShowHeader));
const getShowHeader = computed(() => unref(getHeaderSetting).show);
const getShowDoc = computed(() => appStore.getHeaderSetting.showDoc);
const getFixed = computed(() => unref(getHeaderSetting).fixed);
const getHeaderTheme = computed(() => appStore.getHeaderSetting.theme);
const getHeaderBgColor = computed(() => unref(getHeaderSetting).bgColor);
const getShowHeader = computed(() => appStore.getHeaderSetting.show);
const getShowSearch = computed(() => unref(getHeaderSetting).showSearch);
const getFixed = computed(() => appStore.getHeaderSetting.fixed);
const getUseLockPage = computed(() => unref(getHeaderSetting).useLockPage);
const getHeaderBgColor = computed(() => appStore.getHeaderSetting.bgColor);
const getShowFullScreen = computed(() => unref(getHeaderSetting).showFullScreen);
const getShowSearch = computed(() => appStore.getHeaderSetting.showSearch);
const getShowNotice = computed(() => unref(getHeaderSetting).showNotice);
const getUseLockPage = computed(() => appStore.getHeaderSetting.useLockPage);
const getUnFixedAndFull = computed(() => !unref(getFixed) && !unref(getShowFullHeaderRef));
const getShowFullScreen = computed(() => appStore.getHeaderSetting.showFullScreen);
const getShowBread = computed(() => {
return (
unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit)
);
});
const getShowNotice = computed(() => appStore.getHeaderSetting.showNotice);
const getShowHeaderLogo = computed(() => {
return unref(getShowLogo) && !unref(getIsSidebarType) && !unref(getIsMixSidebar);
});
const getShowBread = computed(() => {
return (
unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit)
);
});
const getShowContent = computed(() => {
return unref(getShowBread) || unref(getShowHeaderTrigger);
});
const getShowHeaderLogo = computed(() => {
return unref(getShowLogo) && !unref(getIsSidebarType) && !unref(getIsMixSidebar);
});
// Set header configuration
function setHeaderSetting(headerSetting: Partial<HeaderSetting>): void {
appStore.commitProjectConfigState({ headerSetting });
}
const getShowContent = computed(() => {
return unref(getShowBread) || unref(getShowHeaderTrigger);
});
export function useHeaderSetting() {
// Set header configuration
function setHeaderSetting(headerSetting: Partial<HeaderSetting>) {
appStore.setProjectConfig({ headerSetting });
}
return {
setHeaderSetting,
getHeaderSetting,
getShowDoc,
getShowSearch,
getHeaderTheme,
......
......@@ -2,7 +2,7 @@ import type { MenuSetting } from '/#/config';
import { computed, unref, ref } from 'vue';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
import { MenuModeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
......@@ -10,127 +10,129 @@ import { useFullContent } from '/@/hooks/web/useFullContent';
const mixSideHasChildren = ref(false);
// Get menu configuration
const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting);
export function useMenuSetting() {
const { getFullContent: fullContent } = useFullContent();
const appStore = useAppStore();
const getShowSidebar = computed(() => {
return (
unref(getSplit) ||
(unref(getShowMenu) && unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && !unref(fullContent))
);
});
const getCollapsed = computed(() => unref(getMenuSetting).collapsed);
const getCollapsed = computed(() => appStore.getMenuSetting.collapsed);
const getMenuType = computed(() => unref(getMenuSetting).type);
const getMenuType = computed(() => appStore.getMenuSetting.type);
const getMenuMode = computed(() => unref(getMenuSetting).mode);
const getMenuMode = computed(() => appStore.getMenuSetting.mode);
const getMenuFixed = computed(() => unref(getMenuSetting).fixed);
const getMenuFixed = computed(() => appStore.getMenuSetting.fixed);
const getShowMenu = computed(() => unref(getMenuSetting).show);
const getShowMenu = computed(() => appStore.getMenuSetting.show);
const getMenuHidden = computed(() => unref(getMenuSetting).hidden);
const getMenuHidden = computed(() => appStore.getMenuSetting.hidden);
const getMenuWidth = computed(() => unref(getMenuSetting).menuWidth);
const getMenuWidth = computed(() => appStore.getMenuSetting.menuWidth);
const getTrigger = computed(() => unref(getMenuSetting).trigger);
const getTrigger = computed(() => appStore.getMenuSetting.trigger);
const getMenuTheme = computed(() => unref(getMenuSetting).theme);
const getMenuTheme = computed(() => appStore.getMenuSetting.theme);
const getSplit = computed(() => unref(getMenuSetting).split);
const getSplit = computed(() => appStore.getMenuSetting.split);
const getMenuBgColor = computed(() => unref(getMenuSetting).bgColor);
const getMenuBgColor = computed(() => appStore.getMenuSetting.bgColor);
const getMixSideTrigger = computed(() => unref(getMenuSetting).mixSideTrigger);
const getMixSideTrigger = computed(() => appStore.getMenuSetting.mixSideTrigger);
const getCanDrag = computed(() => unref(getMenuSetting).canDrag);
const getCanDrag = computed(() => appStore.getMenuSetting.canDrag);
const getAccordion = computed(() => unref(getMenuSetting).accordion);
const getAccordion = computed(() => appStore.getMenuSetting.accordion);
const getMixSideFixed = computed(() => unref(getMenuSetting).mixSideFixed);
const getMixSideFixed = computed(() => appStore.getMenuSetting.mixSideFixed);
const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign);
const getTopMenuAlign = computed(() => appStore.getMenuSetting.topMenuAlign);
const getCloseMixSidebarOnChange = computed(() => unref(getMenuSetting).closeMixSidebarOnChange);
const getCloseMixSidebarOnChange = computed(
() => appStore.getMenuSetting.closeMixSidebarOnChange
);
const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR);
const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR);
const getIsTopMenu = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU);
const getIsTopMenu = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU);
const getCollapsedShowTitle = computed(() => unref(getMenuSetting).collapsedShowTitle);
const getCollapsedShowTitle = computed(() => appStore.getMenuSetting.collapsedShowTitle);
const getShowTopMenu = computed(() => {
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL || unref(getSplit);
});
const getShowTopMenu = computed(() => {
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL || unref(getSplit);
});
const getShowHeaderTrigger = computed(() => {
if (unref(getMenuType) === MenuTypeEnum.TOP_MENU || !unref(getShowMenu) || unref(getMenuHidden)) {
return false;
}
const getShowHeaderTrigger = computed(() => {
if (
unref(getMenuType) === MenuTypeEnum.TOP_MENU ||
!unref(getShowMenu) ||
unref(getMenuHidden)
) {
return false;
}
return unref(getTrigger) === TriggerEnum.HEADER;
});
return unref(getTrigger) === TriggerEnum.HEADER;
});
const getIsHorizontal = computed(() => {
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL;
});
const getIsHorizontal = computed(() => {
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL;
});
const getIsMixSidebar = computed(() => {
return unref(getMenuType) === MenuTypeEnum.MIX_SIDEBAR;
});
const getIsMixSidebar = computed(() => {
return unref(getMenuType) === MenuTypeEnum.MIX_SIDEBAR;
});
const getIsMixMode = computed(() => {
return unref(getMenuMode) === MenuModeEnum.INLINE && unref(getMenuType) === MenuTypeEnum.MIX;
});
const getIsMixMode = computed(() => {
return unref(getMenuMode) === MenuModeEnum.INLINE && unref(getMenuType) === MenuTypeEnum.MIX;
});
const getRealWidth = computed(() => {
if (unref(getIsMixSidebar)) {
return unref(getCollapsed) && !unref(getMixSideFixed)
? unref(getMiniWidthNumber)
: unref(getMenuWidth);
}
return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth);
});
const getMiniWidthNumber = computed(() => {
const { collapsedShowTitle } = unref(getMenuSetting);
return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH;
});
const getCalcContentWidth = computed(() => {
const width =
unref(getIsTopMenu) || !unref(getShowMenu) || (unref(getSplit) && unref(getMenuHidden))
? 0
: unref(getIsMixSidebar)
? (unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH) +
(unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0)
: unref(getRealWidth);
return `calc(100% - ${unref(width)}px)`;
});
const { getFullContent: fullContent } = useFullContent();
const getShowSidebar = computed(() => {
return (
unref(getSplit) ||
(unref(getShowMenu) && unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && !unref(fullContent))
);
});
const getRealWidth = computed(() => {
if (unref(getIsMixSidebar)) {
return unref(getCollapsed) && !unref(getMixSideFixed)
? unref(getMiniWidthNumber)
: unref(getMenuWidth);
}
return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth);
});
// Set menu configuration
function setMenuSetting(menuSetting: Partial<MenuSetting>): void {
appStore.commitProjectConfigState({ menuSetting });
}
const getMiniWidthNumber = computed(() => {
const { collapsedShowTitle } = appStore.getMenuSetting;
return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH;
});
const getCalcContentWidth = computed(() => {
const width =
unref(getIsTopMenu) || !unref(getShowMenu) || (unref(getSplit) && unref(getMenuHidden))
? 0
: unref(getIsMixSidebar)
? (unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH) +
(unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0)
: unref(getRealWidth);
function toggleCollapsed() {
setMenuSetting({
collapsed: !unref(getCollapsed),
return `calc(100% - ${unref(width)}px)`;
});
}
export function useMenuSetting() {
// Set menu configuration
function setMenuSetting(menuSetting: Partial<MenuSetting>): void {
appStore.setProjectConfig({ menuSetting });
}
function toggleCollapsed() {
setMenuSetting({
collapsed: !unref(getCollapsed),
});
}
return {
setMenuSetting,
toggleCollapsed,
getMenuFixed,
getMenuSetting,
getRealWidth,
getMenuType,
getMenuMode,
......
import type { MultiTabsSetting } from '/#/config';
import { computed, unref } from 'vue';
import { computed } from 'vue';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
const getMultipleTabSetting = computed(() => appStore.getProjectConfig.multiTabsSetting);
const getShowMultipleTab = computed(() => unref(getMultipleTabSetting).show);
export function useMultipleTabSetting() {
const appStore = useAppStore();
const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick);
const getShowMultipleTab = computed(() => appStore.getMultiTabsSetting.show);
const getShowRedo = computed(() => unref(getMultipleTabSetting).showRedo);
const getShowQuick = computed(() => appStore.getMultiTabsSetting.showQuick);
const getShowFold = computed(() => unref(getMultipleTabSetting).showFold);
const getShowRedo = computed(() => appStore.getMultiTabsSetting.showRedo);
function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
appStore.commitProjectConfigState({ multiTabsSetting });
}
const getShowFold = computed(() => appStore.getMultiTabsSetting.showFold);
export function useMultipleTabSetting() {
function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
appStore.setProjectConfig({ multiTabsSetting });
}
return {
setMultipleTabSetting,
getMultipleTabSetting,
getShowMultipleTab,
getShowQuick,
getShowRedo,
......
import type { ProjectConfig } from '/#/config';
import { computed, unref } from 'vue';
import { computed } from 'vue';
import { appStore } from '/@/store/modules/app';
import { ContentEnum } from '/@/enums/appEnum';
import { ThemeEnum } from '../../enums/appEnum';
import { useAppStore } from '/@/store/modules/app';
import { ContentEnum, ThemeEnum } from '/@/enums/appEnum';
type RootSetting = Omit<
ProjectConfig,
'locale' | 'headerSetting' | 'menuSetting' | 'multiTabsSetting'
>;
const getRootSetting = computed((): RootSetting => appStore.getProjectConfig);
export function useRootSetting() {
const appStore = useAppStore();
const getPageLoading = computed(() => appStore.getPageLoading);
const getPageLoading = computed(() => appStore.getPageLoading);
const getOpenKeepAlive = computed(() => unref(getRootSetting).openKeepAlive);
const getOpenKeepAlive = computed(() => appStore.getProjectConfig.openKeepAlive);
const getSettingButtonPosition = computed(() => unref(getRootSetting).settingButtonPosition);
const getSettingButtonPosition = computed(() => appStore.getProjectConfig.settingButtonPosition);
const getCanEmbedIFramePage = computed(() => unref(getRootSetting).canEmbedIFramePage);
const getCanEmbedIFramePage = computed(() => appStore.getProjectConfig.canEmbedIFramePage);
const getPermissionMode = computed(() => unref(getRootSetting).permissionMode);
const getPermissionMode = computed(() => appStore.getProjectConfig.permissionMode);
const getShowLogo = computed(() => unref(getRootSetting).showLogo);
const getShowLogo = computed(() => appStore.getProjectConfig.showLogo);
const getContentMode = computed(() => unref(getRootSetting).contentMode);
const getContentMode = computed(() => appStore.getProjectConfig.contentMode);
const getUseOpenBackTop = computed(() => unref(getRootSetting).useOpenBackTop);
const getUseOpenBackTop = computed(() => appStore.getProjectConfig.useOpenBackTop);
const getShowSettingButton = computed(() => unref(getRootSetting).showSettingButton);
const getShowSettingButton = computed(() => appStore.getProjectConfig.showSettingButton);
const getUseErrorHandle = computed(() => unref(getRootSetting).useErrorHandle);
const getUseErrorHandle = computed(() => appStore.getProjectConfig.useErrorHandle);
const getShowFooter = computed(() => unref(getRootSetting).showFooter);
const getShowFooter = computed(() => appStore.getProjectConfig.showFooter);
const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb);
const getShowBreadCrumb = computed(() => appStore.getProjectConfig.showBreadCrumb);
const getThemeColor = computed(() => unref(getRootSetting).themeColor);
const getThemeColor = computed(() => appStore.getProjectConfig.themeColor);
const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon);
const getShowBreadCrumbIcon = computed(() => appStore.getProjectConfig.showBreadCrumbIcon);
const getFullContent = computed(() => unref(getRootSetting).fullContent);
const getFullContent = computed(() => appStore.getProjectConfig.fullContent);
const getColorWeak = computed(() => unref(getRootSetting).colorWeak);
const getColorWeak = computed(() => appStore.getProjectConfig.colorWeak);
const getGrayMode = computed(() => unref(getRootSetting).grayMode);
const getGrayMode = computed(() => appStore.getProjectConfig.grayMode);
const getLockTime = computed(() => unref(getRootSetting).lockTime);
const getLockTime = computed(() => appStore.getProjectConfig.lockTime);
const getShowDarkModeToggle = computed(() => unref(getRootSetting).showDarkModeToggle);
const getShowDarkModeToggle = computed(() => appStore.getProjectConfig.showDarkModeToggle);
const getDarkMode = computed(() => appStore.getDarkMode);
const getDarkMode = computed(() => appStore.getDarkMode);
const getLayoutContentMode = computed(() =>
unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
);
const getLayoutContentMode = computed(() =>
appStore.getProjectConfig.contentMode === ContentEnum.FULL
? ContentEnum.FULL
: ContentEnum.FIXED
);
function setRootSetting(setting: Partial<RootSetting>) {
appStore.commitProjectConfigState(setting);
}
function setRootSetting(setting: Partial<RootSetting>) {
appStore.setProjectConfig(setting);
}
function setDarkMode(mode: ThemeEnum) {
appStore.commitDarkMode(mode);
}
export function useRootSetting() {
function setDarkMode(mode: ThemeEnum) {
appStore.setDarkMode(mode);
}
return {
setRootSetting,
......@@ -73,7 +73,6 @@ export function useRootSetting() {
getFullContent,
getColorWeak,
getGrayMode,
getRootSetting,
getLayoutContentMode,
getPageLoading,
getOpenKeepAlive,
......
import type { TransitionSetting } from '/#/config';
import { computed, unref } from 'vue';
import { computed } from 'vue';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
const getTransitionSetting = computed(() => appStore.getProjectConfig.transitionSetting);
const getEnableTransition = computed(() => unref(getTransitionSetting)?.enable);
export function useTransitionSetting() {
const appStore = useAppStore();
const getOpenNProgress = computed(() => unref(getTransitionSetting)?.openNProgress);
const getEnableTransition = computed(() => appStore.getTransitionSetting?.enable);
const getOpenPageLoading = computed((): boolean => {
return !!unref(getTransitionSetting)?.openPageLoading;
});
const getOpenNProgress = computed(() => appStore.getTransitionSetting?.openNProgress);
const getBasicTransition = computed(() => unref(getTransitionSetting)?.basicTransition);
const getOpenPageLoading = computed((): boolean => {
return !!appStore.getTransitionSetting?.openPageLoading;
});
function setTransitionSetting(transitionSetting: Partial<TransitionSetting>) {
appStore.commitProjectConfigState({ transitionSetting });
}
const getBasicTransition = computed(() => appStore.getTransitionSetting?.basicTransition);
export function useTransitionSetting() {
function setTransitionSetting(transitionSetting: Partial<TransitionSetting>) {
appStore.setProjectConfig({ transitionSetting });
}
return {
setTransitionSetting,
getTransitionSetting,
getEnableTransition,
getOpenNProgress,
getOpenPageLoading,
......
import type { EChartsOption } from 'echarts';
import type { Ref } from 'vue';
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { tryOnUnmounted } from '@vueuse/core';
import { unref, Ref, nextTick, watch, computed, ref } from 'vue';
import type { EChartsOption } from 'echarts';
import { unref, nextTick, watch, computed, ref } from 'vue';
import { useDebounce } from '/@/hooks/core/useDebounce';
import { useEventListener } from '/@/hooks/event/useEventListener';
import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
import echarts from '/@/plugins/echarts';
import { useRootSetting } from '../setting/useRootSetting';
import echarts from './echarts';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
export function useECharts(
elRef: Ref<HTMLDivElement>,
......
import { computed, unref } from 'vue';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import router from '/@/router';
......@@ -8,6 +8,7 @@ import router from '/@/router';
* @description: Full screen display content
*/
export const useFullContent = () => {
const appStore = useAppStore();
const { currentRoute } = router;
// Whether to display the content in full screen without displaying the menu
......
import { computed, onUnmounted, unref, watchEffect } from 'vue';
import { useThrottle } from '/@/hooks/core/useThrottle';
import { appStore } from '/@/store/modules/app';
import { lockStore } from '/@/store/modules/lock';
import { userStore } from '/@/store/modules/user';
import { useAppStore } from '/@/store/modules/app';
import { useLockStore } from '/@/store/modules/lock';
import { useUserStore } from '/@/store/modules/user';
import { useRootSetting } from '../setting/useRootSetting';
export function useLockPage() {
const { getLockTime } = useRootSetting();
const lockStore = useLockStore();
const userStore = useUserStore();
const appStore = useAppStore();
let timeId: TimeoutHandle;
function clear(): void {
......@@ -16,7 +21,7 @@ export function useLockPage() {
function resetCalcLockTimeout(): void {
// not login
if (!userStore.getTokenState) {
if (!userStore.getToken) {
clear();
return;
}
......@@ -33,14 +38,14 @@ export function useLockPage() {
}
function lockPage(): void {
lockStore.commitLockInfoState({
lockStore.setLockInfo({
isLock: true,
pwd: undefined,
});
}
watchEffect((onClean) => {
if (userStore.getTokenState) {
if (userStore.getToken) {
resetCalcLockTimeout();
} else {
clear();
......
import type { RouteLocationRaw } from 'vue-router';
import type { RouteLocationRaw, Router } from 'vue-router';
import { PageEnum } from '/@/enums/pageEnum';
import { isString } from '/@/utils/is';
import { unref } from 'vue';
import router from '/@/router';
import { useRouter } from 'vue-router';
export type RouteLocationRawEx = Omit<RouteLocationRaw, 'path'> & { path: PageEnum };
......@@ -13,10 +13,16 @@ function handleError(e: Error) {
}
// page switch
export function useGo() {
const { push, replace } = router;
export function useGo(_router?: Router) {
let router;
if (!_router) {
router = useRouter();
}
const { push, replace } = _router || router;
function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) {
if (!opt) return;
if (!opt) {
return;
}
if (isString(opt)) {
isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError);
} else {
......@@ -30,8 +36,12 @@ export function useGo() {
/**
* @description: redo current page
*/
export const useRedo = () => {
const { push, currentRoute } = router;
export const useRedo = (_router?: Router) => {
let router;
if (!_router) {
router = useRouter();
}
const { push, currentRoute } = _router || router;
const { query, params } = currentRoute.value;
function redo(): Promise<boolean> {
return new Promise((resolve) => {
......
import type { RouteRecordRaw } from 'vue-router';
import { appStore } from '/@/store/modules/app';
import { permissionStore } from '/@/store/modules/permission';
import { userStore } from '/@/store/modules/user';
import { useAppStore } from '/@/store/modules/app';
import { usePermissionStore } from '/@/store/modules/permission';
import { useUserStore } from '/@/store/modules/user';
import { useTabs } from './useTabs';
......@@ -15,15 +15,20 @@ import { RoleEnum } from '/@/enums/roleEnum';
import { intersection } from 'lodash-es';
import { isArray } from '/@/utils/is';
import { tabStore } from '/@/store/modules/tab';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
// User permissions related operations
export function usePermission() {
const userStore = useUserStore();
const appStore = useAppStore();
const permissionStore = usePermissionStore();
const { closeAll } = useTabs(router);
/**
* Change permission mode
*/
async function togglePermissionMode() {
appStore.commitProjectConfigState({
appStore.setProjectConfig({
permissionMode:
projectSetting.permissionMode === PermissionModeEnum.BACK
? PermissionModeEnum.ROLE
......@@ -37,14 +42,14 @@ export function usePermission() {
* @param id
*/
async function resume(id?: string | number) {
tabStore.commitClearCache();
const tabStore = useMultipleTabStore();
tabStore.clearCacheTabs();
resetRouter();
const routes = await permissionStore.buildRoutesAction(id);
routes.forEach((route) => {
router.addRoute((route as unknown) as RouteRecordRaw);
});
permissionStore.commitLastBuildMenuTimeState();
const { closeAll } = useTabs();
permissionStore.setLastBuildMenuTime();
closeAll();
}
......@@ -53,22 +58,24 @@ export function usePermission() {
*/
function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
const permMode = projectSetting.permissionMode;
if (PermissionModeEnum.ROLE === permMode) {
// Visible by default
if (!value) {
return def;
}
if (!isArray(value)) {
return userStore.getRoleListState?.includes(value as RoleEnum);
return userStore.getRoleList?.includes(value as RoleEnum);
}
return (intersection(value, userStore.getRoleListState) as RoleEnum[]).length > 0;
return (intersection(value, userStore.getRoleList) as RoleEnum[]).length > 0;
}
if (PermissionModeEnum.BACK === permMode) {
// Visible by default
if (!value) {
return def;
}
const allCodeList = permissionStore.getPermCodeListState;
const allCodeList = permissionStore.getPermCodeList;
if (!isArray(value)) {
return allCodeList.includes(value as string);
}
......@@ -90,7 +97,7 @@ export function usePermission() {
if (!isArray(roles)) {
roles = [roles];
}
userStore.commitRoleListState(roles);
userStore.setRoleList(roles);
await resume();
}
......
import { tabStore } from '/@/store/modules/tab';
import { appStore } from '/@/store/modules/app';
import type { RouteLocationNormalized } from 'vue-router';
import type { RouteLocationNormalized, Router } from 'vue-router';
export function useTabs() {
function canIUseFn(): boolean {
const { multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
import { useRouter } from 'vue-router';
import { unref } from 'vue';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { useAppStore } from '/@/store/modules/app';
enum TableActionEnum {
REFRESH,
CLOSE_ALL,
CLOSE_LEFT,
CLOSE_RIGHT,
CLOSE_OTHER,
CLOSE_CURRENT,
CLOSE,
}
export function useTabs(_router: Router) {
const appStore = useAppStore();
function canIUseTabs(): boolean {
const { show } = appStore.getMultiTabsSetting;
if (!show) {
throw new Error('The multi-tab page is currently not open, please open it in the settings!');
}
return !!show;
}
const tabStore = useMultipleTabStore();
const router = _router || useRouter();
const { currentRoute } = router;
function getCurrentTab() {
const route = unref(currentRoute);
return tabStore.getTabList.find((item) => item.path === route.path)!;
}
async function handleTabAction(action: TableActionEnum, tab?: RouteLocationNormalized) {
const canIUse = canIUseTabs;
if (!canIUse) {
return;
}
const currentTab = getCurrentTab();
switch (action) {
case TableActionEnum.REFRESH:
await tabStore.refreshPage(router);
break;
case TableActionEnum.CLOSE_ALL:
await tabStore.closeAllTab(router);
break;
case TableActionEnum.CLOSE_LEFT:
await tabStore.closeLeftTabs(currentTab, router);
break;
case TableActionEnum.CLOSE_RIGHT:
await tabStore.closeRightTabs(currentTab, router);
break;
case TableActionEnum.CLOSE_OTHER:
await tabStore.closeOtherTabs(currentTab, router);
break;
case TableActionEnum.CLOSE_CURRENT:
case TableActionEnum.CLOSE:
await tabStore.closeTab(tab || currentTab, router);
break;
}
}
return {
refreshPage: async () => {
if (canIUseFn()) {
await tabStore.commitRedoPage();
}
refreshPage: () => handleTabAction(TableActionEnum.REFRESH),
closeAll: () => handleTabAction(TableActionEnum.CLOSE_ALL),
closeLeft: () => handleTabAction(TableActionEnum.CLOSE_LEFT),
closeRight: () => handleTabAction(TableActionEnum.CLOSE_RIGHT),
closeOther: () => handleTabAction(TableActionEnum.CLOSE_OTHER),
closeCurrent: () => handleTabAction(TableActionEnum.CLOSE_CURRENT),
close: (tab?: RouteLocationNormalized) => {
handleTabAction(TableActionEnum.CLOSE, tab);
},
closeAll: () => canIUseFn() && tabStore.closeAllTabAction(),
closeLeft: () => canIUseFn() && tabStore.closeLeftTabAction(tabStore.getCurrentTab),
closeRight: () => canIUseFn() && tabStore.closeRightTabAction(tabStore.getCurrentTab),
closeOther: () => canIUseFn() && tabStore.closeOtherTabAction(tabStore.getCurrentTab),
closeCurrent: () => canIUseFn() && tabStore.closeTabAction(tabStore.getCurrentTab),
close: (tab?: RouteLocationNormalized) =>
canIUseFn() && tabStore.closeTabAction(tab || tabStore.getCurrentTab),
};
}
......@@ -5,7 +5,7 @@
:mouseEnterDelay="0.5"
@click="handleToErrorList"
>
<Badge :count="getCount" :offset="[0, 10]" dot :overflowCount="99">
<Badge :count="getCount" :offset="[0, 10]" :overflowCount="99">
<Icon icon="ion:bug-outline" />
</Badge>
</Tooltip>
......@@ -16,7 +16,7 @@
import Icon from '/@/components/Icon';
import { useI18n } from '/@/hooks/web/useI18n';
import { errorStore } from '/@/store/modules/error';
import { useErrorLogStore } from '/@/store/modules/errorLog';
import { PageEnum } from '/@/enums/pageEnum';
import { useRouter } from 'vue-router';
......@@ -28,14 +28,13 @@
setup() {
const { t } = useI18n();
const { push } = useRouter();
const errorLogStore = useErrorLogStore();
const getCount = computed(() => {
return errorStore.getErrorListCountState;
});
const getCount = computed(() => errorLogStore.getErrorLogListCount);
function handleToErrorList() {
push(PageEnum.ERROR_LOG_PAGE).then(() => {
errorStore.commitErrorListCountState(0);
errorLogStore.setErrorLogListCount(0);
});
}
......
......@@ -31,8 +31,8 @@
import { BasicModal, useModalInner } from '/@/components/Modal/index';
import { BasicForm, useForm } from '/@/components/Form/index';
import { userStore } from '/@/store/modules/user';
import { lockStore } from '/@/store/modules/lock';
import { useUserStore } from '/@/store/modules/user';
import { useLockStore } from '/@/store/modules/lock';
import headerImg from '/@/assets/images/header.jpg';
export default defineComponent({
name: 'LockModal',
......@@ -41,10 +41,10 @@
setup() {
const { t } = useI18n();
const { prefixCls } = useDesign('header-lock-modal');
const userStore = useUserStore();
const lockStore = useLockStore();
const getRealName = computed(() => {
return userStore.getUserInfoState?.realName;
});
const getRealName = computed(() => userStore.getUserInfo?.realName);
const [register, { closeModal }] = useModalInner();
const [registerForm, { validateFields, resetFields }] = useForm({
......@@ -64,7 +64,7 @@
const password: string | undefined = values.password;
closeModal();
lockStore.commitLockInfoState({
lockStore.setLockInfo({
isLock: true,
pwd: password,
});
......
......@@ -41,7 +41,7 @@
import { DOC_URL } from '/@/settings/siteSetting';
import { userStore } from '/@/store/modules/user';
import { useUserStore } from '/@/store/modules/user';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useI18n } from '/@/hooks/web/useI18n';
import { useDesign } from '/@/hooks/web/useDesign';
......@@ -71,9 +71,10 @@
const { prefixCls } = useDesign('header-user-dropdown');
const { t } = useI18n();
const { getShowDoc } = useHeaderSetting();
const userStore = useUserStore();
const getUserInfo = computed(() => {
const { realName = '', desc } = userStore.getUserInfoState || {};
const { realName = '', desc } = userStore.getUserInfo || {};
return { realName, desc };
});
......
......@@ -42,13 +42,9 @@
},
setup() {
const { prefixCls } = useDesign('default-layout');
const { getIsMobile } = useAppInject();
const { getShowFullHeaderRef } = useHeaderSetting();
const { getShowSidebar, getIsMixSidebar } = useMenuSetting();
const layoutClass = computed(() => ({ 'ant-layout-has-sider': unref(getIsMixSidebar) }));
return {
......
......@@ -9,7 +9,7 @@ import { useThrottle } from '/@/hooks/core/useThrottle';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus';
import { permissionStore } from '/@/store/modules/permission';
import { usePermissionStore } from '/@/store/modules/permission';
import { useAppInject } from '/@/hooks/web/useAppInject';
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
......@@ -17,6 +17,7 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
const menusRef = ref<Menu[]>([]);
const { currentRoute } = useRouter();
const { getIsMobile } = useAppInject();
const permissionStore = usePermissionStore();
const { setMenuSetting, getIsHorizontal, getSplit } = useMenuSetting();
const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
......@@ -55,7 +56,7 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
// Menu changes
watch(
[() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState],
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
() => {
genMenus();
},
......
......@@ -21,32 +21,36 @@
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
import { appStore } from '/@/store/modules/app';
import { permissionStore } from '/@/store/modules/permission';
import { tabStore } from '/@/store/modules/tab';
import { userStore } from '/@/store/modules/user';
import { useAppStore } from '/@/store/modules/app';
import { usePermissionStore } from '/@/store/modules/permission';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { useUserStore } from '/@/store/modules/user';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
import defaultSetting from '/@/settings/projectSetting';
export default defineComponent({
name: 'SettingFooter',
components: { CopyOutlined, RedoOutlined },
setup() {
const { getRootSetting } = useRootSetting();
const permissionStore = usePermissionStore();
const { prefixCls } = useDesign('setting-footer');
const { t } = useI18n();
const { createSuccessModal, createMessage } = useMessage();
const tabStore = useMultipleTabStore();
const userStore = useUserStore();
const appStore = useAppStore();
function handleCopy() {
const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
const { isSuccessRef } = useCopyToClipboard(
JSON.stringify(unref(appStore.getProjectConfig), null, 2)
);
unref(isSuccessRef) &&
createSuccessModal({
title: t('layout.setting.operatingTitle'),
......@@ -55,7 +59,7 @@
}
function handleResetSetting() {
try {
appStore.commitProjectConfigState(defaultSetting);
appStore.setProjectConfig(defaultSetting);
const { colorWeak, grayMode } = defaultSetting;
// updateTheme(themeColor);
updateColorWeak(colorWeak);
......@@ -68,10 +72,10 @@
function handleClearAndRedo() {
localStorage.clear();
appStore.resumeAllState();
permissionStore.commitResetState();
tabStore.commitResetState();
userStore.commitResetState();
appStore.resetAllState();
permissionStore.resetState();
tabStore.resetState();
userStore.resetState();
location.reload();
}
return {
......
......@@ -3,15 +3,16 @@ import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updat
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import { ProjectConfig } from '/#/config';
import { changeTheme } from '/@/logics/theme';
import { updateDarkTheme } from '/@/logics/theme/dark';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
export function baseHandler(event: HandlerEnum, value: any) {
const appStore = useAppStore();
const config = handler(event, value);
appStore.commitProjectConfigState(config);
appStore.setProjectConfig(config);
if (event === HandlerEnum.CHANGE_THEME) {
updateHeaderBgColor();
updateSidebarBgColor();
......@@ -19,6 +20,8 @@ export function baseHandler(event: HandlerEnum, value: any) {
}
export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> {
const appStore = useAppStore();
const { getThemeColor, getDarkMode } = useRootSetting();
switch (event) {
case HandlerEnum.CHANGE_LAYOUT:
......@@ -50,7 +53,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
}
updateDarkTheme(value);
return { darkMode: value };
return {};
case HandlerEnum.MENU_HAS_DRAG:
return { menuSetting: { canDrag: value } };
......@@ -97,7 +100,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
// ============transition==================
case HandlerEnum.OPEN_PAGE_LOADING:
appStore.commitPageLoadingState(false);
appStore.setPageLoading(false);
return { transitionSetting: { openPageLoading: value } };
case HandlerEnum.ROUTER_TRANSITION:
......
......@@ -5,38 +5,33 @@
</template>
<script lang="ts">
import { defineComponent, unref, computed } from 'vue';
import { Icon } from '/@/components/Icon';
import { useDesign } from '/@/hooks/web/useDesign';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import Icon from '/@/components/Icon';
export default defineComponent({
name: 'FoldButton',
components: { Icon },
setup() {
const { prefixCls } = useDesign('multiple-tabs-content');
const { getShowMenu, setMenuSetting } = useMenuSetting();
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
const getIsUnFold = computed(() => {
return !unref(getShowMenu) && !unref(getShowHeader);
});
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
const getIcon = computed(() => {
return unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full';
});
const getIcon = computed(() =>
unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full'
);
function handleFold() {
const isScale = !unref(getShowMenu) && !unref(getShowHeader);
const isUnFold = unref(getIsUnFold);
setMenuSetting({
show: isScale,
hidden: !isScale,
});
setHeaderSetting({
show: isScale,
show: isUnFold,
hidden: !isUnFold,
});
setHeaderSetting({ show: isUnFold });
}
return { prefixCls, getIcon, handleFold };
......
<template>
<TabContent :type="TabContentEnum.EXTRA_TYPE" :tabItem="$route" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { TabContentEnum } from '../types';
import TabContent from './TabContent.vue';
export default defineComponent({
name: 'QuickButton',
components: {
TabContent,
},
setup() {
return {
TabContentEnum,
};
},
});
</script>
<template>
<Dropdown :dropMenuList="getDropMenuList" :trigger="getTrigger" @menuEvent="handleMenuEvent">
<div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="isTabs">
<div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs">
<span class="ml-1">{{ getTitle }}</span>
</div>
<span :class="`${prefixCls}__extra-quick`" v-else @click="handleContext">
<Icon icon="ion:chevron-down" />
</span>
......@@ -11,18 +10,18 @@
</template>
<script lang="ts">
import type { PropType } from 'vue';
import type { RouteLocationNormalized } from 'vue-router';
import { defineComponent, computed } from 'vue';
import { defineComponent, computed, unref } from 'vue';
import { Dropdown } from '/@/components/Dropdown/index';
import Icon from '/@/components/Icon';
import { Icon } from '/@/components/Icon';
import { TabContentProps, TabContentEnum } from '../types';
import { TabContentProps } from '../types';
import { useDesign } from '/@/hooks/web/useDesign';
import { useTabDropdown } from '../useTabDropdown';
import { useI18n } from '/@/hooks/web/useI18n';
import { useTabDropdown } from '../useTabDropdown';
import { RouteLocationNormalized } from 'vue-router';
export default defineComponent({
name: 'TabContent',
components: { Dropdown, Icon },
......@@ -31,11 +30,7 @@
type: Object as PropType<RouteLocationNormalized>,
default: null,
},
type: {
type: Number as PropType<TabContentEnum>,
default: TabContentEnum.TAB_TYPE,
},
isExtra: Boolean,
},
setup(props) {
const { prefixCls } = useDesign('multiple-tabs-content');
......@@ -43,27 +38,29 @@
const getTitle = computed(() => {
const { tabItem: { meta } = {} } = props;
return meta && t(meta.title);
return meta && t(meta.title as string);
});
const {
getDropMenuList,
handleMenuEvent,
handleContextMenu,
getTrigger,
isTabs,
} = useTabDropdown(props as TabContentProps);
const getIsTabs = computed(() => !props.isExtra);
const getTrigger = computed(() => (unref(getIsTabs) ? ['contextmenu'] : ['click']));
function handleContext(e: ChangeEvent) {
const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(
props as TabContentProps,
getIsTabs
);
function handleContext(e) {
props.tabItem && handleContextMenu(props.tabItem)(e);
}
return {
prefixCls,
getDropMenuList,
handleMenuEvent,
handleContext,
getTrigger,
isTabs,
getIsTabs,
getTitle,
};
},
......
<template>
<Tooltip :title="t('common.redo')" placement="bottom" :mouseEnterDelay="0.5">
<span :class="`${prefixCls}__extra-redo`" @click="handleRedo">
<RedoOutlined :spin="loading" />
</span>
</Tooltip>
<span :class="`${prefixCls}__extra-redo`" @click="handleRedo">
<RedoOutlined :spin="loading" />
</span>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { RedoOutlined } from '@ant-design/icons-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { Tooltip } from 'ant-design-vue';
import { useI18n } from '/@/hooks/web/useI18n';
import { useTabs } from '/@/hooks/web/useTabs';
export default defineComponent({
name: 'TabRedo',
components: { RedoOutlined, Tooltip },
components: { RedoOutlined },
setup() {
const loading = ref(false);
const { prefixCls } = useDesign('multiple-tabs-content');
const { t } = useI18n();
const { refreshPage } = useTabs();
async function handleRedo() {
......@@ -29,9 +25,9 @@
setTimeout(() => {
loading.value = false;
// Animation execution time
}, 1000);
}, 1200);
}
return { prefixCls, t, handleRedo, loading };
return { prefixCls, handleRedo, loading };
},
});
</script>
......@@ -8,13 +8,20 @@ html[data-theme='dark'] {
}
}
html[data-theme='light'] {
.@{prefix-cls} {
.ant-tabs-tab:not(.ant-tabs-tab-active) {
border: 1px solid #d9d9d9 !important;
}
}
}
.@{prefix-cls} {
z-index: 10;
height: @multiple-height + 2;
line-height: @multiple-height + 2;
background: @component-background;
border-bottom: 1px solid @border-color-base;
box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05);
.ant-tabs-small {
height: @multiple-height;
......
......@@ -20,26 +20,26 @@
<template #tabBarExtraContent v-if="getShowRedo || getShowQuick">
<TabRedo v-if="getShowRedo" />
<QuickButton v-if="getShowQuick" />
<TabContent isExtra :tabItem="$route" v-if="getShowQuick" />
<FoldButton v-if="getShowFold" />
</template>
</Tabs>
</div>
</template>
<script lang="ts">
import type { RouteLocationNormalized } from 'vue-router';
import { defineComponent, computed, unref, ref } from 'vue';
import { Tabs } from 'ant-design-vue';
import TabContent from './components/TabContent.vue';
import QuickButton from './components/QuickButton.vue';
import FoldButton from './components/FoldButton.vue';
import TabRedo from './components/TabRedo.vue';
import type { RouteLocationNormalized } from 'vue-router';
import { useGo } from '/@/hooks/web/usePage';
import { tabStore } from '/@/store/modules/tab';
import { userStore } from '/@/store/modules/user';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { useUserStore } from '/@/store/modules/user';
import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
import { useDesign } from '/@/hooks/web/useDesign';
......@@ -48,13 +48,12 @@
import { REDIRECT_NAME } from '/@/router/constant';
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
import router from '/@/router';
import { useRouter } from 'vue-router';
export default defineComponent({
name: 'MultipleTabs',
components: {
QuickButton,
TabRedo: TabRedo,
TabRedo,
FoldButton,
Tabs,
TabPane: Tabs.TabPane,
......@@ -65,12 +64,16 @@
const activeKeyRef = ref('');
useTabsDrag(affixTextList);
const tabStore = useMultipleTabStore();
const userStore = useUserStore();
const router = useRouter();
const { prefixCls } = useDesign('multiple-tabs');
const go = useGo();
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
const getTabsState = computed(() => {
return tabStore.getTabsState.filter((item) => !item.meta?.hideTab);
return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
});
const unClose = computed(() => unref(getTabsState).length === 1);
......@@ -86,10 +89,11 @@
listenerRouteChange((route) => {
const { name } = route;
if (name === REDIRECT_NAME || !route || !userStore.getTokenState) return;
if (name === REDIRECT_NAME || !route || !userStore.getToken) {
return;
}
const { path, fullPath, meta = {} } = route;
const { currentActiveMenu, hideTab } = meta;
const isHide = !hideTab ? null : currentActiveMenu;
const p = isHide || fullPath || path;
......@@ -101,10 +105,11 @@
const findParentRoute = router
.getRoutes()
.find((item) => item.path === currentActiveMenu);
findParentRoute &&
tabStore.addTabAction((findParentRoute as unknown) as RouteLocationNormalized);
tabStore.addTab((findParentRoute as unknown) as RouteLocationNormalized);
} else {
tabStore.addTabAction(unref(route));
tabStore.addTab(unref(route));
}
});
......@@ -116,9 +121,11 @@
// Close the current tab
function handleEdit(targetKey: string) {
// Added operation to hide, currently only use delete operation
if (unref(unClose)) return;
if (unref(unClose)) {
return;
}
tabStore.closeTabByKeyAction(targetKey);
tabStore.closeTabByKey(targetKey, router);
}
return {
prefixCls,
......
......@@ -14,22 +14,12 @@ export interface TabContentProps {
trigger?: ('click' | 'hover' | 'contextmenu')[];
}
/**
* @description: 右键:下拉菜单文字
*/
export enum MenuEventEnum {
// 刷新
REFRESH_PAGE,
// 关闭当前
CLOSE_CURRENT,
// 关闭左侧
CLOSE_LEFT,
// 关闭右侧
CLOSE_RIGHT,
// 关闭其他
CLOSE_OTHER,
// 关闭所有
CLOSE_ALL,
// 放大
SCALE,
}
import { toRaw, ref, nextTick } from 'vue';
import { RouteLocationNormalized } from 'vue-router';
import type { RouteLocationNormalized } from 'vue-router';
import { useDesign } from '/@/hooks/web/useDesign';
import { useSortable } from '/@/hooks/web/useSortable';
import router from '/@/router';
import { tabStore } from '/@/store/modules/tab';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { isNullAndUnDef } from '/@/utils/is';
import projectSetting from '/@/settings/projectSetting';
import { useRouter } from 'vue-router';
export function initAffixTabs(): string[] {
const affixList = ref<RouteLocationNormalized[]>([]);
const tabStore = useMultipleTabStore();
const router = useRouter();
/**
* @description: Filter all fixed routes
*/
......@@ -30,7 +33,7 @@ export function initAffixTabs(): string[] {
const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as RouteLocationNormalized[]);
affixList.value = affixTabs;
for (const tab of affixTabs) {
tabStore.addTabAction(({
tabStore.addTab(({
meta: tab.meta,
name: tab.name,
path: tab.path,
......@@ -39,6 +42,7 @@ export function initAffixTabs(): string[] {
}
let isAddAffix = false;
if (!isAddAffix) {
addAffixTabs();
isAddAffix = true;
......@@ -47,8 +51,8 @@ export function initAffixTabs(): string[] {
}
export function useTabsDrag(affixTextList: string[]) {
const tabStore = useMultipleTabStore();
const { multiTabsSetting } = projectSetting;
const { prefixCls } = useDesign('multiple-tabs');
nextTick(() => {
if (!multiTabsSetting.canDrag) return;
......@@ -66,7 +70,7 @@ export function useTabsDrag(affixTextList: string[]) {
return;
}
tabStore.commitSortTabs({ oldIndex, newIndex });
tabStore.sortTabs(oldIndex, newIndex);
},
});
initSortable();
......
import type { TabContentProps } from './types';
import type { DropMenu } from '/@/components/Dropdown';
import type { ComputedRef } from 'vue';
import { computed, unref, reactive } from 'vue';
import { TabContentEnum, MenuEventEnum } from './types';
import { tabStore } from '/@/store/modules/tab';
import router from '/@/router';
import { RouteLocationNormalized } from 'vue-router';
import { MenuEventEnum } from './types';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { RouteLocationNormalized, useRouter } from 'vue-router';
import { useTabs } from '/@/hooks/web/useTabs';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
export function useTabDropdown(tabContentProps: TabContentProps) {
export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
const state = reactive({
current: null as Nullable<RouteLocationNormalized>,
currentIndex: 0,
});
const { currentRoute } = router;
const isTabs = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE);
const { t } = useI18n();
const tabStore = useMultipleTabStore();
const { currentRoute } = useRouter();
const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs();
const getCurrentTab = computed(
const getTargetTab = computed(
(): RouteLocationNormalized => {
return unref(isTabs) ? tabContentProps.tabItem : unref(currentRoute);
return unref(getIsTabs) ? tabContentProps.tabItem : unref(currentRoute);
}
);
......@@ -31,8 +30,10 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
* @description: drop-down list
*/
const getDropMenuList = computed(() => {
if (!unref(getCurrentTab)) return;
const { meta } = unref(getCurrentTab);
if (!unref(getTargetTab)) {
return;
}
const { meta } = unref(getTargetTab);
const { path } = unref(currentRoute);
// Refresh button
......@@ -42,11 +43,11 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
// Close left
const closeLeftDisabled = index === 0;
const disabled = tabStore.getTabsState.length === 1;
const disabled = tabStore.getTabList.length === 1;
// Close right
const closeRightDisabled =
index === tabStore.getTabsState.length - 1 && tabStore.getLastDragEndIndexState >= 0;
index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0;
const dropMenuList: DropMenu[] = [
{
icon: 'ion:reload-sharp',
......@@ -58,7 +59,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
icon: 'clarity:close-line',
event: MenuEventEnum.CLOSE_CURRENT,
text: t('layout.multipleTab.close'),
disabled: meta?.affix || disabled,
disabled: !!meta?.affix || disabled,
divider: true,
},
{
......@@ -92,15 +93,13 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
return dropMenuList;
});
const getTrigger = computed(() => {
return unref(isTabs) ? ['contextmenu'] : ['click'];
});
function handleContextMenu(tabItem: RouteLocationNormalized) {
return (e: Event) => {
if (!tabItem) return;
if (!tabItem) {
return;
}
e?.preventDefault();
const index = tabStore.getTabsState.findIndex((tab) => tab.path === tabItem.path);
const index = tabStore.getTabList.findIndex((tab) => tab.path === tabItem.path);
state.current = tabItem;
state.currentIndex = index;
};
......@@ -108,12 +107,8 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
// Handle right click event
function handleMenuEvent(menu: DropMenu): void {
const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs();
const { event } = menu;
switch (event) {
case MenuEventEnum.SCALE:
scaleScreen();
break;
case MenuEventEnum.REFRESH_PAGE:
// refresh page
refreshPage();
......@@ -140,5 +135,5 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
break;
}
}
return { getDropMenuList, handleMenuEvent, handleContextMenu, getTrigger, isTabs };
return { getDropMenuList, handleMenuEvent, handleContextMenu };
}
......@@ -2,18 +2,19 @@ import type { AppRouteRecordRaw } from '/@/router/types';
import { computed, toRaw, unref } from 'vue';
import { tabStore } from '/@/store/modules/tab';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { uniqBy } from 'lodash-es';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import router from '/@/router';
import { useRouter } from 'vue-router';
export function useFrameKeepAlive() {
const router = useRouter();
const { currentRoute } = router;
const { getShowMultipleTab } = useMultipleTabSetting();
const tabStore = useMultipleTabStore();
const getFramePages = computed(() => {
const ret =
getAllFramePages((toRaw(router.getRoutes()) as unknown) as AppRouteRecordRaw[]) || [];
......@@ -21,7 +22,7 @@ export function useFrameKeepAlive() {
});
const getOpenTabList = computed((): string[] => {
return tabStore.getTabsState.reduce((prev: string[], next) => {
return tabStore.getTabList.reduce((prev: string[], next) => {
if (next.meta && Reflect.has(next.meta, 'frameSrc')) {
prev.push(next.name as string);
}
......
......@@ -35,13 +35,14 @@
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { getTransitionName } from './transition';
import { useStore } from 'vuex';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
export default defineComponent({
name: 'PageLayout',
components: { FrameLayout },
setup() {
const { getShowMultipleTab } = useMultipleTabSetting();
const tabStore = useMultipleTabStore();
const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
......@@ -49,15 +50,11 @@
const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
const { getters } = useStore();
const getCaches = computed((): string[] => {
if (!unref(getOpenKeepAlive)) {
return [];
}
// TODO The useStore is used here mainly to solve the problem of circular dependency hot update
const cacheTabs = getters['app-tab/getCachedTabsState'];
return cacheTabs;
return tabStore.getCachedTabList;
});
return {
......
......@@ -3,14 +3,15 @@ import type { I18n, I18nOptions } from 'vue-i18n';
import { createI18n } from 'vue-i18n';
import { localeStore } from '/@/store/modules/locale';
import { localeSetting } from '/@/settings/localeSetting';
import { useLocaleStoreWithOut } from '/@/store/modules/locale';
const { fallback, availableLocales } = localeSetting;
export let i18n: ReturnType<typeof createI18n>;
async function createI18nOptions(): Promise<I18nOptions> {
const localeStore = useLocaleStoreWithOut();
const locale = localeStore.getLocale;
const defaultLocal = await import(`./lang/${locale}.ts`);
const message = defaultLocal.default?.message ?? {};
......
......@@ -6,7 +6,7 @@ import type { LocaleType } from '/#/config';
import moment from 'moment';
import { i18n } from './setupI18n';
import { localeStore } from '/@/store/modules/locale';
import { useLocaleStoreWithOut } from '/@/store/modules/locale';
import { unref, computed } from 'vue';
interface LangModule {
......@@ -18,6 +18,8 @@ interface LangModule {
const loadLocalePool: LocaleType[] = [];
function setI18nLanguage(locale: LocaleType) {
const localeStore = useLocaleStoreWithOut();
if (i18n.mode === 'legacy') {
i18n.global.locale = locale;
} else {
......@@ -28,6 +30,7 @@ function setI18nLanguage(locale: LocaleType) {
}
export function useLocale() {
const localeStore = useLocaleStoreWithOut();
const getLocale = computed(() => localeStore.getLocale);
const getShowLocalePicker = computed(() => localeStore.getShowPicker);
......@@ -40,7 +43,9 @@ export function useLocale() {
async function changeLocale(locale: LocaleType) {
const globalI18n = i18n.global;
const currentLocale = unref(globalI18n.locale);
if (currentLocale === locale) return locale;
if (currentLocale === locale) {
return locale;
}
if (loadLocalePool.includes(locale)) {
setI18nLanguage(locale);
......
......@@ -2,7 +2,10 @@
* Used to configure the global error handling function, which can monitor vue errors, script errors, static resource errors and Promise errors
*/
import { errorStore, ErrorInfo } from '/@/store/modules/error';
import type { ErrorLogInfo } from '/#/store';
import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
import { App } from 'vue';
import projectSetting from '/@/settings/projectSetting';
......@@ -61,8 +64,9 @@ function formatComponentName(vm: any) {
*/
function vueErrorHandler(err: Error, vm: any, info: string) {
const errorLogStore = useErrorLogStoreWithOut();
const { name, path } = formatComponentName(vm);
errorStore.commitErrorInfoState({
errorLogStore.addErrorLogInfo({
type: ErrorTypeEnum.VUE,
name,
file: path,
......@@ -86,7 +90,7 @@ export function scriptErrorHandler(
if (event === 'Script error.' && !source) {
return false;
}
const errorInfo: Partial<ErrorInfo> = {};
const errorInfo: Partial<ErrorLogInfo> = {};
colno = colno || (window.event && (window.event as any).errorCharacter) || 0;
errorInfo.message = event as string;
if (error?.stack) {
......@@ -95,13 +99,14 @@ export function scriptErrorHandler(
errorInfo.stack = '';
}
const name = source ? source.substr(source.lastIndexOf('/') + 1) : 'script';
errorStore.commitErrorInfoState({
const errorLogStore = useErrorLogStoreWithOut();
errorLogStore.addErrorLogInfo({
type: ErrorTypeEnum.SCRIPT,
name: name,
file: source as string,
detail: 'lineno' + lineno,
url: window.location.href,
...(errorInfo as Pick<ErrorInfo, 'message' | 'stack'>),
...(errorInfo as Pick<ErrorLogInfo, 'message' | 'stack'>),
});
return true;
}
......@@ -112,8 +117,9 @@ export function scriptErrorHandler(
function registerPromiseErrorHandler() {
window.addEventListener(
'unhandledrejection',
function (event: any) {
errorStore.commitErrorInfoState({
function (event) {
const errorLogStore = useErrorLogStoreWithOut();
errorLogStore.addErrorLogInfo({
type: ErrorTypeEnum.PROMISE,
name: 'Promise Error!',
file: 'none',
......@@ -136,10 +142,10 @@ function registerResourceErrorHandler() {
'error',
function (e: Event) {
const target = e.target ? e.target : (e.srcElement as any);
errorStore.commitErrorInfoState({
const errorLogStore = useErrorLogStoreWithOut();
errorLogStore.addErrorLogInfo({
type: ErrorTypeEnum.RESOURCE,
name: 'Resouce Error!',
name: 'Resource Error!',
file: (e.target || ({} as any)).currentSrc,
detail: JSON.stringify({
tagName: target.localName,
......@@ -147,7 +153,7 @@ function registerResourceErrorHandler() {
type: e.type,
}),
url: window.location.href,
stack: 'resouce is not found',
stack: 'resource is not found',
message: (e.target || ({} as any)).localName + ' is load error',
});
},
......@@ -161,7 +167,9 @@ function registerResourceErrorHandler() {
*/
export function setupErrorHandle(app: App) {
const { useErrorHandle } = projectSetting;
if (!useErrorHandle) return;
if (!useErrorHandle) {
return;
}
// Vue exception monitoring;
app.config.errorHandler = vueErrorHandler;
......
......@@ -12,18 +12,20 @@ import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
import { updateDarkTheme } from '/@/logics/theme/dark';
import { changeTheme } from '/@/logics/theme';
import { appStore } from '/@/store/modules/app';
import { localeStore } from '/@/store/modules/locale';
import { useAppStore } from '/@/store/modules/app';
import { useLocaleStore } from '/@/store/modules/locale';
import { getCommonStoragePrefix, getStorageShortName } from '/@/utils/env';
import { primaryColor } from '../../build/config/themeConfig';
import { Persistent } from '/@/utils/cache/persistent';
import { deepMerge } from '/@/utils';
import { ThemeEnum } from '../enums/appEnum';
import { ThemeEnum } from '/@/enums/appEnum';
// Initial project configuration
export function initAppConfigStore() {
const localeStore = useLocaleStore();
const appStore = useAppStore();
let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig;
projCfg = deepMerge(projectSetting, projCfg || {});
const darkMode = appStore.getDarkMode;
......@@ -45,7 +47,7 @@ export function initAppConfigStore() {
} catch (error) {
console.log(error);
}
appStore.commitProjectConfigState(projCfg);
appStore.setProjectConfig(projCfg);
// init dark mode
updateDarkTheme(darkMode);
......
import { colorIsDark, lighten, darken } from '/@/utils/color';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import { ThemeEnum } from '/@/enums/appEnum';
import { setCssVar } from './util';
......@@ -16,12 +16,13 @@ const SIDER_LIGHTEN_BG_COLOR = '--sider-dark-lighten-bg-color';
* @param color
*/
export function updateHeaderBgColor(color?: string) {
const appStore = useAppStore();
const darkMode = appStore.getDarkMode === ThemeEnum.DARK;
if (!color) {
if (darkMode) {
color = '#151515';
} else {
color = appStore.getProjectConfig.headerSetting.bgColor;
color = appStore.getHeaderSetting.bgColor;
}
}
// bg color
......@@ -35,7 +36,7 @@ export function updateHeaderBgColor(color?: string) {
// Determine the depth of the color value and automatically switch the theme
const isDark = colorIsDark(color!);
appStore.commitProjectConfigState({
appStore.setProjectConfig({
headerSetting: {
theme: isDark || darkMode ? ThemeEnum.DARK : ThemeEnum.LIGHT,
},
......@@ -47,13 +48,15 @@ export function updateHeaderBgColor(color?: string) {
* @param color bg color
*/
export function updateSidebarBgColor(color?: string) {
const appStore = useAppStore();
// if (!isHexColor(color)) return;
const darkMode = appStore.getDarkMode === ThemeEnum.DARK;
if (!color) {
if (darkMode) {
color = '#212121';
} else {
color = appStore.getProjectConfig.menuSetting.bgColor;
color = appStore.getMenuSetting.bgColor;
}
}
setCssVar(SIDER_DARK_BG_COLOR, color);
......@@ -64,7 +67,7 @@ export function updateSidebarBgColor(color?: string) {
// Only when the background color is #fff, the theme of the menu will be changed to light
const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase());
appStore.commitProjectConfigState({
appStore.setProjectConfig({
menuSetting: {
theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK,
},
......
......@@ -5,15 +5,13 @@ import { createApp } from 'vue';
import App from './App.vue';
import router, { setupRouter } from '/@/router';
import { setupRouterGuard } from '/@/router/guard';
import { setupStore } from '/@/store';
import { setupErrorHandle } from '/@/logics/error-handle';
import { setupGlobDirectives } from '/@/directives';
import { setupI18n } from '/@/locales/setupI18n';
import { registerGlobComp } from '/@/components/registerGlobComp';
// router-guard
import '/@/router/guard';
// Register icon Sprite
import 'vite-plugin-svg-icons/register';
......@@ -27,6 +25,10 @@ if (import.meta.env.DEV) {
(async () => {
const app = createApp(App);
// Configure vuex store
setupStore(app);
// Register global components
registerGlobComp(app);
......@@ -36,8 +38,8 @@ if (import.meta.env.DEV) {
// Configure routing
setupRouter(app);
// Configure vuex store
setupStore(app);
// router-guard
setupRouterGuard();
// Register global directive
setupGlobDirectives(app);
......
......@@ -20,13 +20,3 @@ export const getParentLayout = (_name?: string) => {
});
});
};
// export const getParentLayout = (name: string) => {
// return () =>
// new Promise((resolve) => {
// resolve({
// ...ParentLayout,
// name,
// });
// });
// };
......@@ -9,11 +9,13 @@ import { createHttpGuard } from './httpGuard';
import { createPageGuard } from './pageGuard';
import { createStateGuard } from './stateGuard';
createPageGuard(router);
createPageLoadingGuard(router);
createHttpGuard(router);
createScrollGuard(router);
createMessageGuard(router);
createProgressGuard(router);
createPermissionGuard(router);
createStateGuard(router);
export function setupRouterGuard() {
createPageGuard(router);
createPageLoadingGuard(router);
createHttpGuard(router);
createScrollGuard(router);
createMessageGuard(router);
createProgressGuard(router);
createPermissionGuard(router);
createStateGuard(router);
}
import type { Router } from 'vue-router';
import { appStore } from '/@/store/modules/app';
import { userStore } from '/@/store/modules/user';
import { useAppStoreWidthOut } from '/@/store/modules/app';
import { useUserStoreWidthOut } from '/@/store/modules/user';
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
import { unref } from 'vue';
const { getOpenPageLoading } = useTransitionSetting();
export function createPageLoadingGuard(router: Router) {
const userStore = useUserStoreWidthOut();
const appStore = useAppStoreWidthOut();
const { getOpenPageLoading } = useTransitionSetting();
router.beforeEach(async (to) => {
if (!userStore.getTokenState) {
if (!userStore.getToken) {
return true;
}
if (to.meta.loaded) {
......@@ -24,7 +26,7 @@ export function createPageLoadingGuard(router: Router) {
router.afterEach(async () => {
if (unref(getOpenPageLoading)) {
setTimeout(() => {
appStore.commitPageLoadingState(false);
appStore.setPageLoading(false);
}, 220);
}
return true;
......
import type { Router, RouteRecordRaw } from 'vue-router';
import { permissionStore } from '/@/store/modules/permission';
import { usePermissionStoreWidthOut } from '/@/store/modules/permission';
import { PageEnum } from '/@/enums/pageEnum';
import { userStore } from '/@/store/modules/user';
import { useUserStoreWidthOut } from '/@/store/modules/user';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
......@@ -12,6 +12,8 @@ const LOGIN_PATH = PageEnum.BASE_LOGIN;
const whitePathList: PageEnum[] = [LOGIN_PATH];
export function createPermissionGuard(router: Router) {
const userStore = useUserStoreWidthOut();
const permissionStore = usePermissionStoreWidthOut();
router.beforeEach(async (to, from, next) => {
// Jump to the 404 page after processing the login
if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name) {
......@@ -25,7 +27,7 @@ export function createPermissionGuard(router: Router) {
return;
}
const token = userStore.getTokenState;
const token = userStore.getToken;
// token does not exist
if (!token) {
......@@ -51,7 +53,7 @@ export function createPermissionGuard(router: Router) {
next(redirectData);
return;
}
if (permissionStore.getIsDynamicAddedRouteState) {
if (permissionStore.getIsDynamicAddedRoute) {
next();
return;
}
......@@ -64,7 +66,7 @@ export function createPermissionGuard(router: Router) {
const redirectPath = (from.query.redirect || to.path) as string;
const redirect = decodeURIComponent(redirectPath);
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
permissionStore.commitDynamicAddedRouteState(true);
permissionStore.setDynamicAddedRoute(true);
next(nextData);
});
}
......@@ -6,9 +6,8 @@ import nProgress from 'nprogress';
import { unref } from 'vue';
const { getOpenNProgress } = useTransitionSetting();
export function createProgressGuard(router: Router) {
const { getOpenNProgress } = useTransitionSetting();
router.beforeEach(async (to) => {
if (to.meta.loaded) return true;
unref(getOpenNProgress) && nProgress.start();
......
import type { Router } from 'vue-router';
import { appStore } from '/@/store/modules/app';
import { tabStore } from '/@/store/modules/tab';
import { userStore } from '/@/store/modules/user';
import { permissionStore } from '/@/store/modules/permission';
import { useAppStore } from '/@/store/modules/app';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { useUserStore } from '/@/store/modules/user';
import { usePermissionStore } from '/@/store/modules/permission';
import { PageEnum } from '/@/enums/pageEnum';
import { removeTabChangeListener } from '/@/logics/mitt/routeChange';
export function createStateGuard(router: Router) {
router.afterEach((to) => {
const tabStore = useMultipleTabStore();
const userStore = useUserStore();
const appStore = useAppStore();
const permissionStore = usePermissionStore();
// Just enter the login page and clear the authentication information
if (to.path === PageEnum.BASE_LOGIN) {
appStore.resumeAllState();
permissionStore.commitResetState();
tabStore.commitResetState();
userStore.commitResetState();
appStore.resetAllState();
permissionStore.resetState();
tabStore.resetState();
userStore.resetState();
removeTabChangeListener();
}
});
......
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 { useAppStoreWidthOut } from '/@/store/modules/app';
import { usePermissionStore } from '/@/store/modules/permission';
import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper';
import { filter } from '/@/utils/helper/treeHelper';
import { isUrl } from '/@/utils/is';
......@@ -24,6 +24,7 @@ Object.keys(modules).forEach((key) => {
// ==========Helper===========
// ===========================
const isBackMode = () => {
const appStore = useAppStoreWidthOut();
return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
};
......@@ -39,7 +40,8 @@ const staticMenus: Menu[] = [];
})();
async function getAsyncMenus() {
return !isBackMode() ? staticMenus : permissionStore.getBackMenuListState;
const permissionStore = usePermissionStore();
return !isBackMode() ? staticMenus : permissionStore.getBackMenuList;
}
export const getMenus = async (): Promise<Menu[]> => {
......
import { ThemeEnum } from '../enums/appEnum';
export default {
prefixCls: 'vben',
};
export const prefixCls = 'vben';
export const darkMode = ThemeEnum.LIGHT;
......
......@@ -61,7 +61,6 @@ const setting: ProjectConfig = {
theme: ThemeEnum.LIGHT,
// Whether to enable the lock screen function
useLockPage: true,
// Whether to show the full screen button
showFullScreen: true,
// Whether to show the document button
......
// github repo url
export const GITHUB_URL = 'https://github.com/anncwb/vue-vben-admin';
// vue-vben-admin-next-doc
export const DOC_URL = 'https://vvbin.cn/doc-next/';
// site url
export const SITE_URL = 'https://vvbin.cn/next/';
import type { App } from 'vue';
import { createStore } from 'vuex';
import { config } from 'vuex-module-decorators';
import { isDevMode } from '/@/utils/env';
config.rawError = true;
const store = createStore({
strict: isDevMode(),
});
import { createPinia } from 'pinia';
const store = createPinia();
export function setupStore(app: App<Element>) {
app.use(store);
}
export default store;
export { store };
import type { ProjectConfig } from '/#/config';
import type { BeforeMiniState } from '../types';
import type { BeforeMiniState } from '/#/store';
import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
import store from '/@/store';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { PROJ_CFG_KEY, APP_DARK_MODE_KEY_ } from '/@/enums/cacheEnum';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { ThemeEnum } from '/@/enums/appEnum';
import { APP_DARK_MODE_KEY_, PROJ_CFG_KEY } from '/@/enums/cacheEnum';
import { Persistent } from '/@/utils/cache/persistent';
import { deepMerge } from '/@/utils';
import { resetRouter } from '/@/router';
import { ThemeEnum } from '../../enums/appEnum';
import { darkMode } from '/@/settings/designSetting';
import { resetRouter } from '/@/router';
import { deepMerge } from '/@/utils';
export interface LockInfo {
pwd: string | undefined;
isLock: boolean;
}
let timeId: TimeoutHandle;
const NAME = 'app';
hotModuleUnregisterModule(NAME);
@Module({ dynamic: true, namespaced: true, store, name: NAME })
export default class App extends VuexModule {
private darkMode;
interface AppState {
darkMode: ThemeEnum;
// Page loading status
private pageLoadingState = false;
pageLoading: boolean;
// project config
private projectConfigState: ProjectConfig | null = Persistent.getLocal(PROJ_CFG_KEY);
// set main overflow hidden
private lockMainScrollState = false;
projectConfig: ProjectConfig | null;
// When the window shrinks, remember some states, and restore these states when the window is restored
private beforeMiniState: BeforeMiniState = {};
get getPageLoading() {
return this.pageLoadingState;
}
get getDarkMode() {
return this.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode;
}
get getBeforeMiniState() {
return this.beforeMiniState;
}
get getLockMainScrollState() {
return this.lockMainScrollState;
}
get getProjectConfig(): ProjectConfig {
return this.projectConfigState || ({} as ProjectConfig);
}
@Mutation
commitPageLoadingState(loading: boolean): void {
this.pageLoadingState = loading;
}
@Mutation
commitDarkMode(mode: ThemeEnum): void {
this.darkMode = mode;
localStorage.setItem(APP_DARK_MODE_KEY_, mode);
}
@Mutation
commitBeforeMiniState(state: BeforeMiniState): void {
this.beforeMiniState = state;
}
@Mutation
commitLockMainScrollState(lock: boolean): void {
this.lockMainScrollState = lock;
}
@Mutation
commitProjectConfigState(proCfg: DeepPartial<ProjectConfig>): void {
this.projectConfigState = deepMerge(this.projectConfigState || {}, proCfg);
Persistent.setLocal(PROJ_CFG_KEY, this.projectConfigState);
}
@Action
async resumeAllState() {
resetRouter();
Persistent.clearAll();
}
@Action
public async setPageLoadingAction(loading: boolean): Promise<void> {
if (loading) {
clearTimeout(timeId);
// Prevent flicker
timeId = setTimeout(() => {
this.commitPageLoadingState(loading);
}, 50);
} else {
this.commitPageLoadingState(loading);
clearTimeout(timeId);
}
}
beforeMiniInfo: BeforeMiniState;
}
let timeId: TimeoutHandle;
export const useAppStore = defineStore({
id: 'app',
state: (): AppState => ({
darkMode: ThemeEnum.LIGHT,
pageLoading: false,
projectConfig: Persistent.getLocal(PROJ_CFG_KEY),
beforeMiniInfo: {},
}),
getters: {
getPageLoading() {
return this.pageLoading;
},
getDarkMode() {
return this.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode;
},
getBeforeMiniInfo() {
return this.beforeMiniInfo;
},
getProjectConfig(): ProjectConfig {
return this.projectConfig || ({} as ProjectConfig);
},
getHeaderSetting() {
return this.getProjectConfig.headerSetting;
},
getMenuSetting() {
return this.getProjectConfig.menuSetting;
},
getTransitionSetting() {
return this.getProjectConfig.transitionSetting;
},
getMultiTabsSetting() {
return this.getProjectConfig.multiTabsSetting;
},
},
actions: {
setPageLoading(loading: boolean): void {
this.pageLoading = loading;
},
setDarkMode(mode: ThemeEnum): void {
this.darkMode = mode;
localStorage.setItem(APP_DARK_MODE_KEY_, mode);
},
setBeforeMiniInfo(state: BeforeMiniState): void {
this.beforeMiniInfo = state;
},
setProjectConfig(config: DeepPartial<ProjectConfig>): void {
this.projectConfig = deepMerge(this.projectConfig || {}, config);
Persistent.setLocal(PROJ_CFG_KEY, this.projectConfig);
},
async resetAllState() {
resetRouter();
Persistent.clearAll();
},
async setPageLoadingAction(loading: boolean): Promise<void> {
if (loading) {
clearTimeout(timeId);
// Prevent flicker
timeId = setTimeout(() => {
this.setPageLoading(loading);
}, 50);
} else {
this.setPageLoading(loading);
clearTimeout(timeId);
}
},
},
});
// Need to be used outside the setup
export function useAppStoreWidthOut() {
return useAppStore(store);
}
export const appStore = getModule<App>(App);
import store from '/@/store';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
import { formatToDateTime } from '/@/utils/dateUtil';
import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
import projectSetting from '/@/settings/projectSetting';
export interface ErrorInfo {
type: ErrorTypeEnum;
file: string;
name?: string;
message: string;
stack?: string;
detail: string;
url: string;
time?: string;
}
export interface ErrorState {
errorInfoState: ErrorInfo[] | null;
errorListCountState: number;
}
const NAME = 'app-error';
hotModuleUnregisterModule(NAME);
@Module({ dynamic: true, namespaced: true, store, name: NAME })
class Error extends VuexModule implements ErrorState {
// error log list
errorInfoState: ErrorInfo[] = [];
// error log count
errorListCountState = 0;
get getErrorInfoState() {
return this.errorInfoState;
}
get getErrorListCountState() {
return this.errorListCountState;
}
@Mutation
commitErrorInfoState(info: ErrorInfo): void {
const item = {
...info,
time: formatToDateTime(new Date()),
};
this.errorInfoState = [item, ...this.errorInfoState];
this.errorListCountState += 1;
}
@Mutation
commitErrorListCountState(count: number): void {
this.errorListCountState = count;
}
@Action
setupErrorHandle(error: any) {
const { useErrorHandle } = projectSetting;
if (!useErrorHandle) return;
const errInfo: Partial<ErrorInfo> = {
message: error.message,
type: ErrorTypeEnum.AJAX,
};
if (error.response) {
const {
config: { url = '', data: params = '', method = 'get', headers = {} } = {},
data = {},
} = error.response;
errInfo.url = url;
errInfo.name = 'Ajax Error!';
errInfo.file = '-';
errInfo.stack = JSON.stringify(data);
errInfo.detail = JSON.stringify({ params, method, headers });
}
this.commitErrorInfoState(errInfo as ErrorInfo);
}
}
export const errorStore = getModule<Error>(Error);
import type { ErrorLogInfo } from '/#/store';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { formatToDateTime } from '/@/utils/dateUtil';
import projectSetting from '/@/settings/projectSetting';
import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
export interface ErrorLogState {
errorLogInfoList: Nullable<ErrorLogInfo[]>;
errorLogListCount: number;
}
export const useErrorLogStore = defineStore({
id: 'app-error-log',
state: (): ErrorLogState => ({
errorLogInfoList: null,
errorLogListCount: 0,
}),
getters: {
getErrorLogInfoList() {
return this.errorLogInfoList || [];
},
getErrorLogListCount() {
return this.errorLogListCount;
},
},
actions: {
addErrorLogInfo(info: ErrorLogInfo) {
const item = {
...info,
time: formatToDateTime(new Date()),
};
this.errorLogInfoList = [item, ...(this.errorLogInfoList || [])];
this.errorLogListCount += 1;
},
setErrorLogListCount(count: number): void {
this.errorLogListCount = count;
},
/**
* Triggered after ajax request error
* @param error
* @returns
*/
addAjaxErrorInfo(error) {
const { useErrorHandle } = projectSetting;
if (!useErrorHandle) {
return;
}
const errInfo: Partial<ErrorLogInfo> = {
message: error.message,
type: ErrorTypeEnum.AJAX,
};
if (error.response) {
const {
config: { url = '', data: params = '', method = 'get', headers = {} } = {},
data = {},
} = error.response;
errInfo.url = url;
errInfo.name = 'Ajax Error!';
errInfo.file = '-';
errInfo.stack = JSON.stringify(data);
errInfo.detail = JSON.stringify({ params, method, headers });
}
this.addErrorLogInfo(errInfo as ErrorLogInfo);
},
},
});
// Need to be used outside the setup
export function useErrorLogStoreWithOut() {
return useErrorLogStore(store);
}
import store from '/@/store';
import type { LocaleSetting, LocaleType } from '/#/config';
import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { LOCALE_KEY } from '/@/enums/cacheEnum';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { LocaleSetting, LocaleType } from '/#/config';
import { createLocalStorage } from '/@/utils/cache';
import { localeSetting } from '/@/settings/localeSetting';
const ls = createLocalStorage();
const lsSetting = (ls.get(LOCALE_KEY) || localeSetting) as LocaleSetting;
const NAME = 'app-locale';
hotModuleUnregisterModule(NAME);
@Module({ dynamic: true, namespaced: true, store, name: NAME })
class Locale extends VuexModule {
private info: LocaleSetting = lsSetting;
get getShowPicker(): boolean {
return !!this.info?.showPicker;
}
const lsLocaleSetting = (ls.get(LOCALE_KEY) || localeSetting) as LocaleSetting;
get getLocale(): LocaleType {
return this.info?.locale;
}
@Mutation
setLocaleInfo(info: Partial<LocaleSetting>): void {
this.info = { ...this.info, ...info };
ls.set(LOCALE_KEY, this.info);
}
interface LocaleState {
localInfo: LocaleSetting;
}
@Action
initLocale(): void {
this.setLocaleInfo({
...localeSetting,
...this.info,
});
}
export const useLocaleStore = defineStore({
id: 'app-locale',
state: (): LocaleState => ({
localInfo: lsLocaleSetting,
}),
getters: {
getShowPicker() {
return !!this.localInfo?.showPicker;
},
getLocale(): LocaleType {
return this.localInfo?.locale ?? 'zh_CN';
},
},
actions: {
/**
* Set up multilingual information and cache
* @param info multilingual info
*/
setLocaleInfo(info: Partial<LocaleSetting>) {
this.localInfo = { ...this.localInfo, ...info };
ls.set(LOCALE_KEY, this.localInfo);
},
/**
* Initialize multilingual information and load the existing configuration from the local cache
*/
initLocale() {
this.setLocaleInfo({
...localeSetting,
...this.localInfo,
});
},
},
});
// Need to be used outside the setup
export function useLocaleStoreWithOut() {
return useLocaleStore(store);
}
export const localeStore = getModule<Locale>(Locale);
import type { LockInfo } from '/@/store/types';
import type { LockInfo } from '/#/store';
import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
import store from '/@/store';
import { defineStore } from 'pinia';
import { LOCK_INFO_KEY } from '/@/enums/cacheEnum';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { Persistent } from '/@/utils/cache/persistent';
import { useUserStore } from './user';
import { userStore } from './user';
const NAME = 'app-lock';
hotModuleUnregisterModule(NAME);
@Module({ dynamic: true, namespaced: true, store, name: NAME })
class Lock extends VuexModule {
// lock info
private lockInfoState: LockInfo | null = Persistent.getLocal(LOCK_INFO_KEY);
get getLockInfo(): LockInfo {
return this.lockInfoState || ({} as LockInfo);
}
@Mutation
commitLockInfoState(info: LockInfo): void {
this.lockInfoState = Object.assign({}, this.lockInfoState, info);
Persistent.setLocal(LOCK_INFO_KEY, this.lockInfoState);
}
@Mutation
resetLockInfo(): void {
Persistent.removeLocal(LOCK_INFO_KEY);
this.lockInfoState = null;
}
interface LockState {
lockInfo: Nullable<LockInfo>;
}
/**
* @description: unlock page
*/
@Action
public async unLockAction({ password }: { password: string }) {
const tryLogin = async () => {
try {
const username = userStore.getUserInfoState.username;
const res = await userStore.login({ username, password, goHome: false, mode: 'none' });
if (res) {
this.resetLockInfo();
}
return res;
} catch (error) {
return false;
export const useLockStore = defineStore({
id: 'app-lock',
state: (): LockState => ({
lockInfo: Persistent.getLocal(LOCK_INFO_KEY),
}),
getters: {
getLockInfo() {
return this.lockInfo;
},
},
actions: {
setLockInfo(info: LockInfo) {
this.lockInfo = Object.assign({}, this.lockInfo, info);
Persistent.setLocal(LOCK_INFO_KEY, this.lockInfo);
},
resetLockInfo() {
Persistent.removeLocal(LOCK_INFO_KEY);
this.lockInfo = null;
},
// Unlock
async unLock(password?: string) {
const userStore = useUserStore();
if (this.lockInfo?.pwd === password) {
this.resetLockInfo();
return true;
}
};
if (this.getLockInfo?.pwd === password) {
this.resetLockInfo();
return true;
}
return await tryLogin();
}
}
export const lockStore = getModule<Lock>(Lock);
const tryLogin = async () => {
try {
const username = userStore.getUserInfo?.username;
const res = await userStore.login({
username,
password: password!,
goHome: false,
mode: 'none',
});
if (res) {
this.resetLockInfo();
}
return res;
} catch (error) {
return false;
}
};
return await tryLogin();
},
},
});
import type { RouteLocationNormalized, RouteLocationRaw, Router } from 'vue-router';
import { toRaw, unref } from 'vue';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { useGo, useRedo } from '/@/hooks/web/usePage';
import { PageEnum } from '/@/enums/pageEnum';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
import { getRawRoute } from '/@/utils';
export interface MultipleTabState {
cacheTabList: Set<string>;
tabList: RouteLocationNormalized[];
lastDragEndIndex: number;
}
function handleGotoPage(router: Router) {
const go = useGo(router);
go(unref(router.currentRoute).path, true);
}
export const useMultipleTabStore = defineStore({
id: 'app-multiple-tab',
state: (): MultipleTabState => ({
// Tabs that need to be cached
cacheTabList: new Set(),
// multiple tab list
tabList: [],
// Index of the last moved tab
lastDragEndIndex: 0,
}),
getters: {
getTabList() {
return this.tabList;
},
getCachedTabList(): string[] {
return Array.from(this.cacheTabList);
},
getLastDragEndIndex(): number {
return this.lastDragEndIndex;
},
},
actions: {
/**
* Update the cache according to the currently opened tabs
*/
async updateCacheTab() {
const cacheMap: Set<string> = new Set();
for (const tab of this.tabList) {
const item = getRawRoute(tab);
// Ignore the cache
const needCache = !item.meta?.ignoreKeepAlive;
if (!needCache) {
return;
}
const name = item.name as string;
cacheMap.add(name);
}
this.cacheTabList = cacheMap;
},
/**
* Refresh tabs
*/
async refreshPage(router: Router) {
const { currentRoute } = router;
const route = unref(currentRoute);
const name = route.name;
const findTab = this.getCachedTabList.find((item) => item === name);
if (findTab) {
this.cacheTabList.delete(findTab);
}
const redo = useRedo(router);
await redo();
},
clearCacheTabs(): void {
this.cacheTabList = new Set();
},
resetState(): void {
this.tabList = [];
this.clearCacheTabs();
},
goToPage(router: Router) {
const go = useGo(router);
const len = this.tabList.length;
const { path } = unref(router.currentRoute);
let toPath: PageEnum | string = PageEnum.BASE_HOME;
if (len > 0) {
const page = this.tabList[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);
},
async addTab(route: RouteLocationNormalized) {
const { path, name, fullPath, params, query } = getRawRoute(route);
// 404 The page does not need to add a tab
if (
path === PageEnum.ERROR_PAGE ||
!name ||
[REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
) {
return;
}
let updateIndex = -1;
// Existing pages, do not add tabs repeatedly
const tabHasExits = this.tabList.some((tab, index) => {
updateIndex = index;
return (tab.fullPath || tab.path) === (fullPath || path);
});
// If the tab already exists, perform the update operation
if (tabHasExits) {
const curTab = toRaw(this.tabList)[updateIndex];
if (!curTab) {
return;
}
curTab.params = params || curTab.params;
curTab.query = query || curTab.query;
curTab.fullPath = fullPath || curTab.fullPath;
this.tabList.splice(updateIndex, 1, curTab);
return;
}
// Add tab
this.tabList.push(route);
this.updateCacheTab();
},
async closeTab(tab: RouteLocationNormalized, router: Router) {
const getToTarget = (tabItem: RouteLocationNormalized) => {
const { params, path, query } = tabItem;
return {
params: params || {},
path,
query: query || {},
};
};
const close = (route: RouteLocationNormalized) => {
const { fullPath, meta: { affix } = {} } = route;
if (affix) {
return;
}
const index = this.tabList.findIndex((item) => item.fullPath === fullPath);
index !== -1 && this.tabList.splice(index, 1);
};
const { currentRoute, replace } = router;
const { path } = unref(currentRoute);
if (path !== tab.path) {
// Closed is not the activation tab
close(tab);
return;
}
// Closed is activated atb
let toTarget: RouteLocationRaw = {};
const index = this.tabList.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.tabList.length === 1) {
toTarget = PageEnum.BASE_HOME;
} else {
// Jump to the right tab
const page = this.tabList[index + 1];
toTarget = getToTarget(page);
}
} else {
// Close the current tab
const page = this.tabList[index - 1];
toTarget = getToTarget(page);
}
close(currentRoute.value);
replace(toTarget);
},
// Close according to key
async closeTabByKey(key: string, router: Router) {
const index = this.tabList.findIndex((item) => (item.fullPath || item.path) === key);
index !== -1 && this.closeTab(this.tabList[index], router);
},
// Sort the tabs
async sortTabs(oldIndex: number, newIndex: number) {
const currentTab = this.tabList[oldIndex];
this.tabList.splice(oldIndex, 1);
this.tabList.splice(newIndex, 0, currentTab);
this.lastDragEndIndex = this.lastDragEndIndex + 1;
},
// Close the tab on the right and jump
async closeLeftTabs(route: RouteLocationNormalized, router: Router) {
const index = this.tabList.findIndex((item) => item.path === route.path);
if (index > 0) {
const leftTabs = this.tabList.slice(0, index);
const pathList: string[] = [];
for (const item of leftTabs) {
const affix = item?.meta?.affix ?? false;
if (!affix) {
pathList.push(item.fullPath);
}
}
this.bulkCloseTabs(pathList);
}
this.updateCacheTab();
handleGotoPage(router);
},
// Close the tab on the left and jump
async closeRightTabs(route: RouteLocationNormalized, router: Router) {
const index = this.tabList.findIndex((item) => item.fullPath === route.fullPath);
if (index >= 0 && index < this.tabList.length - 1) {
const rightTabs = this.tabList.slice(index + 1, this.tabList.length);
const pathList: string[] = [];
for (const item of rightTabs) {
const affix = item?.meta?.affix ?? false;
if (!affix) {
pathList.push(item.fullPath);
}
}
this.bulkCloseTabs(pathList);
}
this.updateCacheTab();
handleGotoPage(router);
},
async closeAllTab(router: Router) {
this.tabList = this.tabList.filter((item) => item?.meta?.affix ?? false);
this.clearCacheTabs();
this.goToPage(router);
},
/**
* Close other tabs
*/
async closeOtherTabs(route: RouteLocationNormalized, router: Router) {
const closePathList = this.tabList.map((item) => item.fullPath);
const pathList: string[] = [];
for (const path of closePathList) {
if (path !== route.fullPath) {
const closeItem = this.tabList.find((item) => item.path === path);
if (!closeItem) {
return;
}
const affix = closeItem?.meta?.affix ?? false;
if (!affix) {
pathList.push(closeItem.fullPath);
}
}
}
this.bulkCloseTabs(pathList);
this.updateCacheTab();
handleGotoPage(router);
},
/**
* Close tabs in bulk
*/
async bulkCloseTabs(pathList: string[]) {
this.tabList = this.tabList.filter((item) => !pathList.includes(item.fullPath));
},
},
});
// Need to be used outside the setup
export function useMultipleTabWithOutStore() {
return useMultipleTabStore(store);
}
import type { AppRouteRecordRaw, Menu } from '/@/router/types';
import store from '/@/store';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { useI18n } from '/@/hooks/web/useI18n';
import { useUserStore } from './user';
import { useAppStoreWidthOut } from './app';
import { toRaw } from 'vue';
import { VuexModule, Mutation, Module, getModule, Action } from 'vuex-module-decorators';
import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
import { transformRouteToMenu } from '/@/router/helper/menuHelper';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import projectSetting from '/@/settings/projectSetting';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { appStore } from '/@/store/modules/app';
import { userStore } from '/@/store/modules/user';
import projectSetting from '/@/settings/projectSetting';
import { asyncRoutes } from '/@/router/routes';
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
import { transformRouteToMenu } from '/@/router/helper/menuHelper';
import { filter } from '/@/utils/helper/treeHelper';
......@@ -23,125 +22,127 @@ import { getMenuListById } from '/@/api/sys/menu';
import { getPermCodeByUserId } from '/@/api/sys/user';
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
const NAME = 'app-permission';
hotModuleUnregisterModule(NAME);
@Module({ dynamic: true, namespaced: true, store, name: NAME })
class Permission extends VuexModule {
interface PermissionState {
// Permission code list
private permCodeListState: string[] = [];
permCodeList: string[];
// Whether the route has been dynamically added
private isDynamicAddedRouteState = false;
isDynamicAddedRoute: boolean;
// To trigger a menu update
private lastBuildMenuTimeState = 0;
lastBuildMenuTime: number;
// Backstage menu list
private backMenuListState: Menu[] = [];
get getPermCodeListState() {
return this.permCodeListState;
}
get getBackMenuListState() {
return this.backMenuListState;
}
get getLastBuildMenuTimeState() {
return this.lastBuildMenuTimeState;
}
get getIsDynamicAddedRouteState() {
return this.isDynamicAddedRouteState;
}
@Mutation
commitPermCodeListState(codeList: string[]): void {
this.permCodeListState = codeList;
}
@Mutation
commitBackMenuListState(list: Menu[]): void {
this.backMenuListState = list;
}
@Mutation
commitLastBuildMenuTimeState(): void {
this.lastBuildMenuTimeState = new Date().getTime();
}
@Mutation
commitDynamicAddedRouteState(added: boolean): void {
this.isDynamicAddedRouteState = added;
}
@Mutation
commitResetState(): void {
this.isDynamicAddedRouteState = false;
this.permCodeListState = [];
this.backMenuListState = [];
this.lastBuildMenuTimeState = 0;
}
@Action
async changePermissionCode(userId: string) {
const codeList = await getPermCodeByUserId({ userId });
this.commitPermCodeListState(codeList);
}
@Action
async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
const { t } = useI18n();
let routes: AppRouteRecordRaw[] = [];
const roleList = toRaw(userStore.getRoleListState);
const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
// role permissions
if (permissionMode === PermissionModeEnum.ROLE) {
const routeFilter = (route: AppRouteRecordRaw) => {
const { meta } = route;
const { roles } = meta || {};
if (!roles) return true;
return roleList.some((role) => roles.includes(role));
};
routes = filter(asyncRoutes, routeFilter);
routes = routes.filter(routeFilter);
// Convert multi-level routing to level 2 routing
routes = flatMultiLevelRoutes(routes);
// If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
} else if (permissionMode === PermissionModeEnum.BACK) {
const { createMessage } = useMessage();
createMessage.loading({
content: t('sys.app.menuLoading'),
duration: 1,
});
// Here to get the background routing menu logic to modify by yourself
const paramId = id || userStore.getUserInfoState.userId;
// !Simulate to obtain permission codes from the background,
// this function may only need to be executed once, and the actual project can be put at the right time by itself
try {
this.changePermissionCode('1');
} catch (error) {}
if (!paramId) {
throw new Error('paramId is undefined!');
backMenuList: Menu[];
}
export const usePermissionStore = defineStore({
id: 'app-permission',
state: (): PermissionState => ({
permCodeList: [],
// Whether the route has been dynamically added
isDynamicAddedRoute: false,
// To trigger a menu update
lastBuildMenuTime: 0,
// Backstage menu list
backMenuList: [],
}),
getters: {
getPermCodeList() {
return this.permCodeList;
},
getBackMenuList() {
return this.backMenuList;
},
getLastBuildMenuTime() {
return this.lastBuildMenuTime;
},
getIsDynamicAddedRoute() {
return this.isDynamicAddedRoute;
},
},
actions: {
setPermCodeList(codeList: string[]) {
this.permCodeList = codeList;
},
setBackMenuList(list: Menu[]) {
this.backMenuList = list;
},
setLastBuildMenuTime() {
this.lastBuildMenuTime = new Date().getTime();
},
setDynamicAddedRoute(added: boolean) {
this.isDynamicAddedRoute = added;
},
resetState(): void {
this.isDynamicAddedRoute = false;
this.permCodeList = [];
this.backMenuList = [];
this.lastBuildMenuTime = 0;
},
async changePermissionCode(userId: string) {
const codeList = await getPermCodeByUserId({ userId });
this.setPermCodeList(codeList);
},
async buildRoutesAction(id?: number | string): Promise<AppRouteRecordRaw[]> {
const { t } = useI18n();
const userStore = useUserStore();
const appStore = useAppStoreWidthOut();
let routes: AppRouteRecordRaw[] = [];
const roleList = toRaw(userStore.getRoleList);
const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
// role permissions
if (permissionMode === PermissionModeEnum.ROLE) {
const routeFilter = (route: AppRouteRecordRaw) => {
const { meta } = route;
const { roles } = meta || {};
if (!roles) return true;
return roleList.some((role) => roles.includes(role));
};
routes = filter(asyncRoutes, routeFilter);
routes = routes.filter(routeFilter);
// Convert multi-level routing to level 2 routing
routes = flatMultiLevelRoutes(routes);
// If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
} else if (permissionMode === PermissionModeEnum.BACK) {
const { createMessage } = useMessage();
createMessage.loading({
content: t('sys.app.menuLoading'),
duration: 1,
});
// Here to get the background routing menu logic to modify by yourself
const paramId = id || userStore.getUserInfo?.userId;
// !Simulate to obtain permission codes from the background,
// this function may only need to be executed once, and the actual project can be put at the right time by itself
try {
this.changePermissionCode('1');
} catch (error) {}
if (!paramId) {
throw new Error('paramId is undefined!');
}
let routeList = (await getMenuListById({ id: paramId })) as AppRouteRecordRaw[];
// Dynamically introduce components
routeList = transformObjToRoute(routeList);
// Background routing to menu structure
const backMenuList = transformRouteToMenu(routeList);
this.setBackMenuList(backMenuList);
routeList = flatMultiLevelRoutes(routeList);
routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
}
let routeList = (await getMenuListById({ id: paramId })) as AppRouteRecordRaw[];
// Dynamically introduce components
routeList = transformObjToRoute(routeList);
// Background routing to menu structure
const backMenuList = transformRouteToMenu(routeList);
this.commitBackMenuListState(backMenuList);
routeList = flatMultiLevelRoutes(routeList);
routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
}
routes.push(ERROR_LOG_ROUTE);
return routes;
}
routes.push(ERROR_LOG_ROUTE);
return routes;
},
},
});
// Need to be used outside the setup
export function usePermissionStoreWidthOut() {
return usePermissionStore(store);
}
export const permissionStore = getModule<Permission>(Permission);
import type { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import { toRaw, 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 store from '/@/store';
import router from '/@/router';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
import { getRawRoute } from '/@/utils';
import { useGo, useRedo } from '/@/hooks/web/usePage';
import { cloneDeep } from 'lodash-es';
const NAME = 'app-tab';
hotModuleUnregisterModule(NAME);
function isGotoPage() {
const go = useGo();
go(unref(router.currentRoute).path, true);
}
@Module({ namespaced: true, name: NAME, dynamic: true, store })
class Tab extends VuexModule {
cachedTabsState: Set<string> = new Set();
// tab list
tabsState: RouteLocationNormalized[] = [];
lastDragEndIndexState = 0;
get getTabsState() {
return this.tabsState;
}
get getCurrentTab(): RouteLocationNormalized {
const route = unref(router.currentRoute);
return this.tabsState.find((item) => item.path === route.path)!;
}
get getCachedTabsState(): string[] {
return Array.from(this.cachedTabsState);
}
get getLastDragEndIndexState(): number {
return this.lastDragEndIndexState;
}
@Mutation
commitClearCache(): void {
this.cachedTabsState = new Set();
}
@Mutation
goToPage() {
const go = useGo();
const len = this.tabsState.length;
const { path } = unref(router.currentRoute);
let toPath: PageEnum | string = PageEnum.BASE_HOME;
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: Set<string> = new Set();
this.tabsState.forEach((tab) => {
const item = getRawRoute(tab);
const needCache = !item.meta?.ignoreKeepAlive;
if (!needCache) return;
const name = item.name as string;
cacheMap.add(name);
});
this.cachedTabsState = cacheMap;
}
@Mutation
commitTabRoutesState(route: RouteLocationNormalized) {
const { path, fullPath, params, query } = route;
let updateIndex = -1;
// Existing pages, do not add tabs repeatedly
const hasTab = this.tabsState.some((tab, index) => {
updateIndex = index;
return (tab.fullPath || tab.path) === (fullPath || path);
});
if (hasTab) {
const curTab = toRaw(this.tabsState)[updateIndex];
if (!curTab) return;
curTab.params = params || curTab.params;
curTab.query = query || curTab.query;
curTab.fullPath = fullPath || curTab.fullPath;
this.tabsState.splice(updateIndex, 1, curTab);
return;
}
this.tabsState = cloneDeep([...this.tabsState, route]);
}
/**
* @description: close tab
*/
@Mutation
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
commitCloseAllTab(): void {
this.tabsState = this.tabsState.filter((item) => {
return item.meta && item.meta.affix;
});
}
@Mutation
commitResetState(): void {
this.tabsState = [];
this.cachedTabsState = new Set();
}
@Mutation
commitSortTabs({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }): void {
const currentTab = this.tabsState[oldIndex];
this.tabsState.splice(oldIndex, 1);
this.tabsState.splice(newIndex, 0, currentTab);
this.lastDragEndIndexState = this.lastDragEndIndexState + 1;
}
@Mutation
closeMultipleTab({ pathList }: { pathList: string[] }): void {
this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
}
@Action
addTabAction(route: RouteLocationNormalized) {
const { path, name } = route;
// 404 The page does not need to add a tab
if (
path === PageEnum.ERROR_PAGE ||
!name ||
[REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
) {
return;
}
this.commitTabRoutesState(getRawRoute(route));
this.commitCachedMapState();
}
@Mutation
async commitRedoPage() {
const route = router.currentRoute.value;
const name = route.name;
const findVal = Array.from(this.cachedTabsState).find((item) => item === name);
if (findVal) {
this.cachedTabsState.delete(findVal);
// this.cachedTabsState.splice(index, 1);
}
const redo = useRedo();
await 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[] = [];
for (const item of leftTabs) {
const affix = item.meta ? item.meta.affix : false;
if (!affix) {
pathList.push(item.fullPath);
}
}
this.closeMultipleTab({ pathList });
}
this.commitCachedMapState();
isGotoPage();
}
@Action
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[] = [];
for (const item of rightTabs) {
const affix = item.meta ? item.meta.affix : false;
if (!affix) {
pathList.push(item.fullPath);
}
}
this.closeMultipleTab({ pathList });
}
this.commitCachedMapState();
isGotoPage();
}
@Action
closeOtherTabAction(route: RouteLocationNormalized): void {
const closePathList = this.tabsState.map((item) => item.fullPath);
const pathList: string[] = [];
closePathList.forEach((path) => {
if (path !== route.fullPath) {
const closeItem = this.tabsState.find((item) => item.path === path);
if (!closeItem) return;
const affix = closeItem.meta ? closeItem.meta.affix : false;
if (!affix) {
pathList.push(closeItem.fullPath);
}
}
});
this.closeMultipleTab({ pathList });
this.commitCachedMapState();
isGotoPage();
}
}
export const tabStore = getModule<Tab>(Tab);
import type {
LoginParams,
GetUserInfoByUserIdModel,
GetUserInfoByUserIdParams,
} from '/@/api/sys/model/userModel';
import type { UserInfo } from '/@/store/types';
import type { UserInfo } from '/#/store';
import type { ErrorMessageMode } from '/@/utils/http/axios/types';
import store from '/@/store/index';
import { VuexModule, Module, getModule, Mutation, Action } from 'vuex-module-decorators';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { defineStore } from 'pinia';
import { store } from '/@/store';
import { PageEnum } from '/@/enums/pageEnum';
import { RoleEnum } from '/@/enums/roleEnum';
import { PageEnum } from '/@/enums/pageEnum';
import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
import { useMessage } from '/@/hooks/web/useMessage';
import router from '/@/router';
import { getAuthCache, setAuthCache } from '/@/utils/auth';
import {
GetUserInfoByUserIdModel,
GetUserInfoByUserIdParams,
LoginParams,
} from '/@/api/sys/model/userModel';
import { loginApi, getUserInfoById } from '/@/api/sys/user';
import { getUserInfoById, loginApi } from '/@/api/sys/user';
import { useI18n } from '/@/hooks/web/useI18n';
import { ErrorMessageMode } from '/@/utils/http/axios/types';
import { getAuthCache, setAuthCache } from '/@/utils/auth/index';
const NAME = 'app-user';
hotModuleUnregisterModule(NAME);
@Module({ namespaced: true, name: NAME, dynamic: true, store })
class User extends VuexModule {
// user info
private userInfoState: UserInfo | null = null;
// token
private tokenState = '';
// roleList
private roleListState: RoleEnum[] = [];
get getUserInfoState(): UserInfo {
return this.userInfoState || getAuthCache<UserInfo>(USER_INFO_KEY) || {};
}
get getTokenState(): string {
return this.tokenState || getAuthCache<string>(TOKEN_KEY);
}
get getRoleListState(): RoleEnum[] {
return this.roleListState.length > 0 ? this.roleListState : getAuthCache<RoleEnum[]>(ROLES_KEY);
}
@Mutation
commitResetState(): void {
this.userInfoState = null;
this.tokenState = '';
this.roleListState = [];
}
@Mutation
commitUserInfoState(info: UserInfo): void {
this.userInfoState = info;
setAuthCache(USER_INFO_KEY, info);
}
@Mutation
commitRoleListState(roleList: RoleEnum[]): void {
this.roleListState = roleList;
setAuthCache(ROLES_KEY, roleList);
}
@Mutation
commitTokenState(info: string): void {
this.tokenState = info;
setAuthCache(TOKEN_KEY, info);
}
/**
* @description: login
*/
@Action
async login(
params: LoginParams & {
goHome?: boolean;
mode?: ErrorMessageMode;
}
): Promise<GetUserInfoByUserIdModel | null> {
try {
const { goHome = true, mode, ...loginParams } = params;
const data = await loginApi(loginParams, mode);
const { token, userId } = data;
// save token
this.commitTokenState(token);
import { useMessage } from '/@/hooks/web/useMessage';
import router from '/@/router';
// get user info
const userInfo = await this.getUserInfoAction({ userId });
interface UserState {
userInfo: Nullable<UserInfo>;
token?: string;
roleList: RoleEnum[];
}
goHome && (await router.replace(PageEnum.BASE_HOME));
export const useUserStore = defineStore({
id: 'app-user',
state: (): UserState => ({
// user info
userInfo: null,
// token
token: undefined,
// roleList
roleList: [],
}),
getters: {
getUserInfo(): UserInfo {
return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || {};
},
getToken(): string {
return this.token || getAuthCache<string>(TOKEN_KEY);
},
getRoleList(): RoleEnum[] {
return this.roleList.length > 0 ? this.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY);
},
},
actions: {
setToken(info: string) {
this.token = info;
setAuthCache(TOKEN_KEY, info);
},
setRoleList(roleList: RoleEnum[]) {
this.roleList = roleList;
setAuthCache(ROLES_KEY, roleList);
},
setUserInfo(info: UserInfo) {
this.userInfo = info;
setAuthCache(USER_INFO_KEY, info);
},
resetState() {
this.userInfo = null;
this.token = '';
this.roleList = [];
},
/**
* @description: login
*/
async login(
params: LoginParams & {
goHome?: boolean;
mode?: ErrorMessageMode;
}
): Promise<GetUserInfoByUserIdModel | null> {
try {
const { goHome = true, mode, ...loginParams } = params;
const data = await loginApi(loginParams, mode);
const { token, userId } = data;
// save token
this.setToken(token);
// get user info
const userInfo = await this.getUserInfoAction({ userId });
goHome && (await router.replace(PageEnum.BASE_HOME));
return userInfo;
} catch (error) {
return null;
}
},
async getUserInfoAction({ userId }: GetUserInfoByUserIdParams) {
const userInfo = await getUserInfoById({ userId });
const { roles } = userInfo;
const roleList = roles.map((item) => item.value) as RoleEnum[];
this.setUserInfo(userInfo);
this.setRoleList(roleList);
return userInfo;
} catch (error) {
return null;
}
}
@Action
async getUserInfoAction({ userId }: GetUserInfoByUserIdParams) {
const userInfo = await getUserInfoById({ userId });
const { roles } = userInfo;
const roleList = roles.map((item) => item.value) as RoleEnum[];
this.commitUserInfoState(userInfo);
this.commitRoleListState(roleList);
return userInfo;
}
/**
* @description: logout
*/
@Action
async logout(goLogin = false) {
goLogin && router.push(PageEnum.BASE_LOGIN);
}
/**
* @description: Confirm before logging out
*/
@Action
async confirmLoginOut() {
const { createConfirm } = useMessage();
const { t } = useI18n();
createConfirm({
iconType: 'warning',
title: t('sys.app.logoutTip'),
content: t('sys.app.logoutMessage'),
onOk: async () => {
await this.logout(true);
},
});
}
},
/**
* @description: logout
*/
logout(goLogin = false) {
goLogin && router.push(PageEnum.BASE_LOGIN);
},
/**
* @description: Confirm before logging out
*/
confirmLoginOut() {
const { createConfirm } = useMessage();
const { t } = useI18n();
createConfirm({
iconType: 'warning',
title: t('sys.app.logoutTip'),
content: t('sys.app.logoutMessage'),
onOk: async () => {
await this.logout(true);
},
});
},
},
});
// Need to be used outside the setup
export function useUserStoreWidthOut() {
return useUserStore(store);
}
export const userStore = getModule<User>(User);
import type { LockInfo, UserInfo } from '/@/store/types';
import { ProjectConfig } from '/#/config';
import type { LockInfo, UserInfo } from '/#/store';
import type { ProjectConfig } from '/#/config';
import { createLocalStorage, createSessionStorage } from '/@/utils/cache';
import { Memory } from './memory';
......
......@@ -35,6 +35,7 @@ export function getAppEnvConfig() {
`VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`
);
}
return {
VITE_GLOB_APP_TITLE,
VITE_GLOB_API_URL,
......
......@@ -16,7 +16,8 @@ import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum';
import { isString } from '/@/utils/is';
import { getToken } from '/@/utils/auth';
import { setObjToUrlParams, deepMerge } from '/@/utils';
import { errorStore } from '/@/store/modules/error';
import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
import { errorResult } from './const';
import { useI18n } from '/@/hooks/web/useI18n';
import { createNow, formatRequestDate } from './helper';
......@@ -150,7 +151,8 @@ const transform: AxiosTransform = {
*/
responseInterceptorsCatch: (error: any) => {
const { t } = useI18n();
errorStore.setupErrorHandle(error);
const errorLogStore = useErrorLogStoreWithOut();
errorLogStore.addAjaxErrorInfo(error);
const { response, code, message } = error || {};
const msg: string = response?.data?.error?.message ?? '';
const err: string = error?.toString?.() ?? '';
......
......@@ -10,7 +10,7 @@
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import { appStore } from '/@/store/modules/app';
import { useAppStore } from '/@/store/modules/app';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { Divider } from 'ant-design-vue';
import { usePermission } from '/@/hooks/web/usePermission';
......@@ -18,9 +18,8 @@
name: 'CurrentPermissionMode',
components: { Divider },
setup() {
const permissionMode = computed(() => {
return appStore.getProjectConfig.permissionMode;
});
const appStore = useAppStore();
const permissionMode = computed(() => appStore.getProjectConfig.permissionMode);
const { togglePermissionMode } = usePermission();
return {
......
......@@ -5,7 +5,7 @@
<CurrentPermissionMode />
<p>
当前拥有的code列表: <a> {{ permissionStore.getPermCodeListState }} </a>
当前拥有的code列表: <a> {{ permissionStore.getPermCodeList }} </a>
</p>
<Divider />
<Alert class="mt-4" type="info" message="点击后请查看按钮变化" show-icon />
......@@ -59,7 +59,7 @@
import CurrentPermissionMode from '../CurrentPermissionMode.vue';
import { usePermission } from '/@/hooks/web/usePermission';
import { Authority } from '/@/components/Authority';
import { permissionStore } from '/@/store/modules/permission';
import { usePermissionStore } from '/@/store/modules/permission';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { PageWrapper } from '/@/components/Page';
......@@ -67,6 +67,7 @@
components: { Alert, PageWrapper, CurrentPermissionMode, Divider, Authority },
setup() {
const { hasPermission } = usePermission();
const permissionStore = usePermissionStore();
function changePermissionCode(userId: string) {
permissionStore.changePermissionCode(userId);
......
......@@ -8,7 +8,7 @@
<CurrentPermissionMode />
<p>
当前角色: <a> {{ userStore.getRoleListState }} </a>
当前角色: <a> {{ userStore.getRoleList }} </a>
</p>
<Alert class="mt-4" type="info" message="点击后请查看按钮变化" show-icon />
......@@ -63,7 +63,7 @@
import { computed, defineComponent } from 'vue';
import { Alert, Divider } from 'ant-design-vue';
import CurrentPermissionMode from '../CurrentPermissionMode.vue';
import { userStore } from '/@/store/modules/user';
import { useUserStore } from '/@/store/modules/user';
import { RoleEnum } from '/@/enums/roleEnum';
import { usePermission } from '/@/hooks/web/usePermission';
import { Authority } from '/@/components/Authority';
......@@ -73,11 +73,13 @@
components: { Alert, PageWrapper, CurrentPermissionMode, Divider, Authority },
setup() {
const { changeRole, hasPermission } = usePermission();
const userStore = useUserStore();
return {
userStore,
RoleEnum,
isSuper: computed(() => userStore.getRoleListState.includes(RoleEnum.SUPER)),
isTest: computed(() => userStore.getRoleListState.includes(RoleEnum.TEST)),
isSuper: computed(() => userStore.getRoleList.includes(RoleEnum.SUPER)),
isTest: computed(() => userStore.getRoleList.includes(RoleEnum.TEST)),
changeRole,
hasPermission,
};
......
......@@ -8,7 +8,7 @@
<CurrentPermissionMode />
<p>
当前角色: <a> {{ userStore.getRoleListState }} </a>
当前角色: <a> {{ userStore.getRoleList }} </a>
</p>
<Alert class="mt-4" type="info" message="点击后请查看左侧菜单变化" show-icon />
......@@ -29,7 +29,7 @@
import { computed, defineComponent } from 'vue';
import { Alert } from 'ant-design-vue';
import CurrentPermissionMode from '../CurrentPermissionMode.vue';
import { userStore } from '/@/store/modules/user';
import { useUserStore } from '/@/store/modules/user';
import { RoleEnum } from '/@/enums/roleEnum';
import { usePermission } from '/@/hooks/web/usePermission';
import { PageWrapper } from '/@/components/Page';
......@@ -38,11 +38,13 @@
components: { Alert, CurrentPermissionMode, PageWrapper },
setup() {
const { changeRole } = usePermission();
const userStore = useUserStore();
return {
userStore,
RoleEnum,
isSuper: computed(() => userStore.getRoleListState.includes(RoleEnum.SUPER)),
isTest: computed(() => userStore.getRoleListState.includes(RoleEnum.TEST)),
isSuper: computed(() => userStore.getRoleList.includes(RoleEnum.SUPER)),
isTest: computed(() => userStore.getRoleList.includes(RoleEnum.TEST)),
changeRole,
};
},
......
......@@ -5,6 +5,7 @@
</template>
<script lang="ts">
import type { PropType } from 'vue';
import type { ErrorLogInfo } from '/#/store';
import { defineComponent } from 'vue';
import { BasicModal } from '/@/components/Modal/index';
......@@ -12,8 +13,6 @@
import { useI18n } from '/@/hooks/web/useI18n';
import { ErrorInfo } from '/@/store/modules/error';
import { getDescSchema } from './data';
export default defineComponent({
......@@ -21,7 +20,7 @@
components: { BasicModal, Description },
props: {
info: {
type: Object as PropType<ErrorInfo>,
type: Object as PropType<ErrorLogInfo>,
default: null,
},
},
......@@ -30,7 +29,7 @@
const [register] = useDescription({
column: 2,
schema: getDescSchema(),
schema: getDescSchema()!,
});
return {
......
......@@ -57,7 +57,7 @@ export function getColumns(): BasicColumn[] {
];
}
export function getDescSchema() {
export function getDescSchema(): any {
return getColumns().map((column) => {
return {
field: column.dataIndex!,
......
......@@ -28,6 +28,8 @@
</template>
<script lang="ts">
import type { ErrorLogInfo } from '/#/store';
import { defineComponent, watch, ref, nextTick } from 'vue';
import DetailModal from './DetailModal.vue';
......@@ -37,7 +39,7 @@
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import { errorStore, ErrorInfo } from '/@/store/modules/error';
import { useErrorLogStore } from '/@/store/modules/errorLog';
import { fireErrorApi } from '/@/api/demo/error';
......@@ -49,11 +51,11 @@
name: 'ErrorHandler',
components: { DetailModal, BasicTable, TableAction },
setup() {
const rowInfo = ref<ErrorInfo>();
const rowInfo = ref<ErrorLogInfo>();
const imgList = ref<string[]>([]);
const { t } = useI18n();
const errorLogStore = useErrorLogStore();
const [register, { setTableData }] = useTable({
title: t('sys.errorLog.tableTitle'),
columns: getColumns(),
......@@ -67,7 +69,7 @@
const [registerModal, { openModal }] = useModal();
watch(
() => errorStore.getErrorInfoState,
() => errorLogStore.getErrorLogInfoList,
(list) => {
nextTick(() => {
setTableData(cloneDeep(list));
......@@ -82,7 +84,7 @@
createMessage.info(t('sys.errorLog.enableMessage'));
}
// 查看详情
function handleDetail(row: ErrorInfo) {
function handleDetail(row: ErrorLogInfo) {
rowInfo.value = row;
openModal(true);
}
......
......@@ -38,7 +38,7 @@
class="enter-x"
v-model:value="password"
/>
<span :class="`${prefixCls}-entry__err-msg enter-x`" v-if="errMsgRef">
<span :class="`${prefixCls}-entry__err-msg enter-x`" v-if="errMsg">
{{ t('sys.lock.alert') }}
</span>
<div :class="`${prefixCls}-entry__footer enter-x`">
......@@ -46,7 +46,7 @@
type="link"
size="small"
class="mt-2 mr-2 enter-x"
:disabled="loadingRef"
:disabled="loading"
@click="handleShowForm(true)"
>
{{ t('common.back') }}
......@@ -55,12 +55,12 @@
type="link"
size="small"
class="mt-2 mr-2 enter-x"
:disabled="loadingRef"
:disabled="loading"
@click="goLogin"
>
{{ t('sys.lock.backToLogin') }}
</a-button>
<a-button class="mt-2" type="link" size="small" @click="unLock()" :loading="loadingRef">
<a-button class="mt-2" type="link" size="small" @click="unLock()" :loading="loading">
{{ t('sys.lock.entry') }}
</a-button>
</div>
......@@ -80,8 +80,8 @@
import { defineComponent, ref, computed } from 'vue';
import { Input } from 'ant-design-vue';
import { userStore } from '/@/store/modules/user';
import { lockStore } from '/@/store/modules/lock';
import { useUserStore } from '/@/store/modules/user';
import { useLockStore } from '/@/store/modules/lock';
import { useI18n } from '/@/hooks/web/useI18n';
import { useNow } from './useNow';
......@@ -95,19 +95,21 @@
components: { LockOutlined, InputPassword: Input.Password },
setup() {
const passwordRef = ref('');
const loadingRef = ref(false);
const errMsgRef = ref(false);
const password = ref('');
const loading = ref(false);
const errMsg = ref(false);
const showDate = ref(true);
const { prefixCls } = useDesign('lock-page');
const lockStore = useLockStore();
const userStore = useUserStore();
const { ...state } = useNow(true);
const { t } = useI18n();
const realName = computed(() => {
const { realName } = userStore.getUserInfoState || {};
const { realName } = userStore.getUserInfo || {};
return realName;
});
......@@ -115,16 +117,16 @@
* @description: unLock
*/
async function unLock() {
if (!passwordRef.value) {
if (!password.value) {
return;
}
let password = passwordRef.value;
let pwd = password.value;
try {
loadingRef.value = true;
const res = await lockStore.unLockAction({ password });
errMsgRef.value = !res;
loading.value = true;
const res = await lockStore.unLock(pwd);
errMsg.value = !res;
} finally {
loadingRef.value = false;
loading.value = false;
}
}
......@@ -141,12 +143,12 @@
goLogin,
realName,
unLock,
errMsgRef,
loadingRef,
errMsg,
loading,
t,
prefixCls,
showDate,
password: passwordRef,
password,
handleShowForm,
headerImg,
...state,
......
......@@ -7,17 +7,13 @@
import { defineComponent, computed } from 'vue';
import LockPage from './LockPage.vue';
import { lockStore } from '/@/store/modules/lock';
import { useLockStore } from '/@/store/modules/lock';
export default defineComponent({
name: 'Lock',
components: { LockPage },
setup() {
const getIsLock = computed(() => {
const { getLockInfo } = lockStore;
const { isLock } = getLockInfo;
return isLock;
});
const lockStore = useLockStore();
const getIsLock = computed(() => lockStore?.getLockInfo?.isLock ?? false);
return { getIsLock };
},
});
......
import { dateUtil } from '/@/utils/dateUtil';
import { reactive, toRefs } from 'vue';
import { localeStore } from '/@/store/modules/locale';
import { useLocaleStore } from '/@/store/modules/locale';
import { tryOnMounted, tryOnUnmounted } from '@vueuse/core';
export function useNow(immediate = true) {
const localeStore = useLocaleStore();
const localData = dateUtil.localeData(localeStore.getLocale);
let timer: IntervalHandle;
......
......@@ -58,7 +58,7 @@
import { useGlobSetting } from '/@/hooks/setting';
import { useI18n } from '/@/hooks/web/useI18n';
import { useDesign } from '/@/hooks/web/useDesign';
import { localeStore } from '/@/store/modules/locale';
import { useLocaleStore } from '/@/store/modules/locale';
export default defineComponent({
name: 'Login',
......@@ -76,6 +76,7 @@
const globSetting = useGlobSetting();
const { prefixCls } = useDesign('login');
const { t } = useI18n();
const localeStore = useLocaleStore();
return {
t,
......
......@@ -85,7 +85,7 @@
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
import { userStore } from '/@/store/modules/user';
import { useUserStore } from '/@/store/modules/user';
import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
import { useDesign } from '/@/hooks/web/useDesign';
import { useKeyPress } from '/@/hooks/event/useKeyPress';
......@@ -114,6 +114,7 @@
const { t } = useI18n();
const { notification } = useMessage();
const { prefixCls } = useDesign('login');
const userStore = useUserStore();
const { setLoginState, getLoginState } = useLoginState();
const { getFormRules } = useFormRules();
......
import { MenuModeEnum, MenuTypeEnum } from '../enums/menuEnum';
import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
// Lock screen information
export interface LockInfo {
pwd: string | undefined;
isLock: boolean;
// Password required
pwd?: string | undefined;
// Is it locked?
isLock?: boolean;
}
// Error-log information
export interface ErrorLogInfo {
// Type of error
type: ErrorTypeEnum;
// Error file
file: string;
// Error name
name?: string;
// Error message
message: string;
// Error stack
stack?: string;
// Error detail
detail: string;
// Error url
url: string;
// Error time
time?: string;
}
export interface UserInfo {
// 用户id
userId: string | number;
// 用户名
username: string;
// 真实名字
realName: string;
// 介绍
desc?: string;
}
......
......@@ -1762,25 +1762,25 @@
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.11.tgz#20d22dd0da7d358bb21c17f9bde8628152642c77"
integrity sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA==
"@vueuse/core@^4.8.0":
version "4.8.0"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.8.0.tgz#d86e36956521c0f9b6571cb58b27f0e2535259b3"
integrity sha512-nUH4Hn1DN4kkuF1r5ZcfGnjoAKDD0Kw9oFnt/TUo1aueNijq4KujagtoQN8OC4Pei10TeTDdqhmZAWnaCE1NbA==
"@vueuse/core@^4.8.1":
version "4.8.1"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.8.1.tgz#d7a7fb2e72610d1962ecb9244bd93dacb96d921c"
integrity sha512-oXFEDaKNU69Rj20/Hd7ZlmTpEtA2M19cRkZaL4A0Nl0w5Wb5In/8aK+0vtdi1VyMUXXbq6h1OGKCJcIhg5cziA==
dependencies:
"@vueuse/shared" "4.8.0"
"@vueuse/shared" "4.8.1"
vue-demi latest
"@vueuse/shared@4.8.0":
version "4.8.0"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.8.0.tgz#abf3da96ca81b4be82e885928193fef2c676cdbc"
integrity sha512-g1lSbHD4ptiS74qBUvffJ98QjRsoCH7ILjxVzJF488EPAmp5z3taLnoggt6NXfonnYve7fEPuqsJqd2BLOxT1A==
"@vueuse/shared@4.8.1":
version "4.8.1"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.8.1.tgz#45fd5f64bf4e8944db42a5b72fa2705cfc74608a"
integrity sha512-ONKJoIvZPrGCA8loK7dX+ZcjgZLikI+vPiz1lWlXs6+jZiQiZSLkmvg1NjV6Cfb6OqbDCfEScTWLbZHB7EwrRw==
dependencies:
vue-demi latest
"@windicss/plugin-utils@0.12.5":
version "0.12.5"
resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.12.5.tgz#d03517d1ae7a48b5b459e3d670e873d38b63e4a1"
integrity sha512-4ux2o4s6D/gRTD68os41oxs/0NFk/eSJxHhZL9nN2wy4RGt+pPMQJyOHV56l7zDh9B0ywU5+ZRxDjdw2cl5Yvg==
"@windicss/plugin-utils@0.13.1":
version "0.13.1"
resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.13.1.tgz#e0e172855ebcf0b8a5f0f358befdcaf44bae5cf1"
integrity sha512-Vr7f7yWxmB5AWwe+iDPV3JbhTlZHbDvM89IfJ0hyP6PqYmZNTtUfMXMbHXZJHVAbQ54dWBMG23WmeC9X327ETA==
dependencies:
debug "^4.3.2"
fast-glob "^3.2.5"
......@@ -1788,7 +1788,7 @@
micromatch "^4.0.2"
pirates "^4.0.1"
sucrase "^3.17.1"
windicss "^2.5.11"
windicss "^2.5.12"
"@zxcvbn-ts/core@^0.3.0":
version "0.3.0"
......@@ -3670,21 +3670,11 @@ esbuild-register@^2.2.0:
esbuild "^0.9.2"
jsonc-parser "^3.0.0"
esbuild@^0.11.4:
version "0.11.5"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.11.5.tgz#25b18a2ff2fb9580683edce26a48f64c08c2f2df"
integrity sha512-aRs6jAE+bVRp1tyfzUugAw1T/Y0Fwzp4Z2ROikF3h+UifoD5QlEbEYQGc6orNnnSIRhWR5VWBH7LozlAumaLHg==
esbuild@^0.11.6:
esbuild@^0.11.4, esbuild@^0.11.6, esbuild@^0.9.2, esbuild@^0.9.3:
version "0.11.6"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.11.6.tgz#20961309c4cfed00b71027e18806150358d0cbb0"
integrity sha512-L+nKW9ftVS/N2CVJMR9YmXHbkm+vHzlNYuo09rzipQhF7dYNvRLfWoEPSDRTl10and4owFBV9rJ2CTFNtLIOiw==
esbuild@^0.9.2, esbuild@^0.9.3:
version "0.9.7"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.9.7.tgz#ea0d639cbe4b88ec25fbed4d6ff00c8d788ef70b"
integrity sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
......@@ -3752,10 +3742,10 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
eslint@^7.23.0:
version "7.23.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz#8d029d252f6e8cf45894b4bee08f5493f8e94325"
integrity sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==
eslint@^7.24.0:
version "7.24.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a"
integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.0"
......@@ -6942,6 +6932,11 @@ pify@^4.0.1:
resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pinia@^2.0.0-alpha.12:
version "2.0.0-alpha.12"
resolved "https://registry.npmjs.org/pinia/-/pinia-2.0.0-alpha.12.tgz#690e9a7b4c176bb9d95fe0dc8ec4ab8847b09493"
integrity sha512-qmcDpuoAwxQKAVp7/cOkXFYDaja+vyXMWR6kvdyzeJcGGMvZf1HQ2xFhUSW5lf1eW5IiQP0cBRdF3ZDyVa+JIQ==
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
......@@ -7691,10 +7686,10 @@ rollup-plugin-visualizer@5.3.0:
source-map "^0.7.3"
yargs "^16.2.0"
rollup@^2.25.0, rollup@^2.38.5, rollup@^2.44.0:
version "2.44.0"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.44.0.tgz#8da324d1c4fd12beef9ae6e12f4068265b6d95eb"
integrity sha512-rGSF4pLwvuaH/x4nAS+zP6UNn5YUDWf/TeEU5IoXSZKBbKRNTCI3qMnYXKZgrC0D2KzS2baiOZt1OlqhMu5rnQ==
rollup@^2.25.0, rollup@^2.38.5, rollup@^2.44.0, rollup@^2.45.1:
version "2.45.1"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.45.1.tgz#eae2b94dc2088b4e0a3b7197a5a1ee0bdd589d5c"
integrity sha512-vPD+JoDj3CY8k6m1bLcAFttXMe78P4CMxoau0iLVS60+S9kLsv2379xaGy4NgYWu+h2WTlucpoLPAoUoixFBag==
optionalDependencies:
fsevents "~2.3.1"
......@@ -9187,15 +9182,15 @@ vite-plugin-theme@^0.6.3:
esbuild-plugin-alias "^0.1.2"
tinycolor2 "^1.4.2"
vite-plugin-windicss@0.12.5:
version "0.12.5"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.12.5.tgz#74a5043db3615fe432855f6ecff13be36f7a6843"
integrity sha512-M/eEA+x94kxZNpEEkJLdY7M6Lp3WFhN0Kb/a2zhdPxBviMwaHSA5A7fUqN1xTYMxlQe4xM7D7naxL7EpnSNlmg==
vite-plugin-windicss@0.13.1:
version "0.13.1"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.13.1.tgz#82a488f3395be710ae2166b83b0612a5eaec7738"
integrity sha512-WmFfTLTMSY5gRC3MWX9o72Yni2HRdrtJ2im+cCyZ2W/p4WE6T702zFCScO8Tnz/E08GDx4OH6oFCZWeZYwgxzg==
dependencies:
"@windicss/plugin-utils" "0.12.5"
"@windicss/plugin-utils" "0.13.1"
chalk "^4.1.0"
debug "^4.3.2"
windicss "^2.5.11"
windicss "^2.5.12"
vite@2.1.5:
version "2.1.5"
......@@ -9265,16 +9260,6 @@ vue@^3.0.0:
"@vue/runtime-dom" "3.0.10"
"@vue/shared" "3.0.10"
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"
integrity sha512-FLWZsXV5XAtl/bcKUyQFpnSBtpc3wK/7zSdy9oKbyp71mZd4ut5y2zSd219wWW9OG7WUOlVwac4rXFFDVnq7ug==
vuex@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/vuex/-/vuex-4.0.0.tgz#ac877aa76a9c45368c979471e461b520d38e6cf5"
integrity sha512-56VPujlHscP5q/e7Jlpqc40sja4vOhC4uJD1llBCWolVI8ND4+VzisDVkUMl+z5y0MpIImW6HjhNc+ZvuizgOw==
warning@^4.0.0:
version "4.0.3"
resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
......@@ -9326,10 +9311,10 @@ which@^2.0.1:
dependencies:
isexe "^2.0.0"
windicss@^2.5.11:
version "2.5.11"
resolved "https://registry.npmjs.org/windicss/-/windicss-2.5.11.tgz#dd4027c724c7b12a37746d1474b96a52239157d1"
integrity sha512-u7b4rOPb8MwO1glkf0gdDygZ+lIzXb/PYLNjqni5Fe2684DCEt6dWTKdk3iMxXgbKoqRNncKu7xt3pFwXHdSAw==
windicss@^2.5.12:
version "2.5.12"
resolved "https://registry.npmjs.org/windicss/-/windicss-2.5.12.tgz#7bc469b05d7a8fa3905d49d6521a1ff9107d0ea4"
integrity sha512-BZ0Ps1C0RlCHBVOPcw/DAReeR9o/mKaoFgkBsVphQ23M5nsvVfVXgGlNJZssjAQsXnlDpj97pnIhtDn1ENBjXw==
wmf@~1.0.1:
version "1.0.2"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册