mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-01-24 18:40:22 +08:00
refactor: layouts use setup (#3312)
* refactor: layouts use setup * refactor: dashboard use setup * fix: breadcrumbs types * fix: noticeList type check error * fix: noticeList type check error * chore(Breadcrumb): revert setup change --------- Co-authored-by: invalid w <wangjuesix@gmail.com>
This commit is contained in:
parent
617b01338c
commit
0cfaa40bd0
@ -62,7 +62,6 @@
|
|||||||
import { SearchOutlined } from '@ant-design/icons-vue';
|
import { SearchOutlined } from '@ant-design/icons-vue';
|
||||||
import AppSearchFooter from './AppSearchFooter.vue';
|
import AppSearchFooter from './AppSearchFooter.vue';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
// @ts-ignore
|
|
||||||
import vClickOutside from '@/directives/clickOutside';
|
import vClickOutside from '@/directives/clickOutside';
|
||||||
import { useDesign } from '@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useRefs } from '@vben/hooks';
|
import { useRefs } from '@vben/hooks';
|
||||||
|
@ -3,31 +3,20 @@
|
|||||||
<PageLayout />
|
<PageLayout />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import PageLayout from '@/layouts/page/index.vue';
|
||||||
import PageLayout from '/@/layouts/page/index.vue';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useTransitionSetting } from '@/hooks/setting/useTransitionSetting';
|
||||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
|
||||||
import { useContentViewHeight } from './useContentViewHeight';
|
import { useContentViewHeight } from './useContentViewHeight';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'LayoutContent' });
|
||||||
name: 'LayoutContent',
|
|
||||||
components: { PageLayout },
|
|
||||||
setup() {
|
|
||||||
const { prefixCls } = useDesign('layout-content');
|
|
||||||
const { getOpenPageLoading } = useTransitionSetting();
|
|
||||||
const { getLayoutContentMode, getPageLoading } = useRootSetting();
|
|
||||||
|
|
||||||
useContentViewHeight();
|
const { prefixCls } = useDesign('layout-content');
|
||||||
return {
|
const { getOpenPageLoading } = useTransitionSetting();
|
||||||
prefixCls,
|
const { getLayoutContentMode, getPageLoading } = useRootSetting();
|
||||||
getOpenPageLoading,
|
|
||||||
getLayoutContentMode,
|
useContentViewHeight();
|
||||||
getPageLoading,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-layout-content';
|
@prefix-cls: ~'@{namespace}-layout-content';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { InjectionKey, ComputedRef } from 'vue';
|
import type { InjectionKey, ComputedRef } from 'vue';
|
||||||
import { createContext, useContext } from '/@/hooks/core/useContext';
|
import { createContext, useContext } from '@/hooks/core/useContext';
|
||||||
|
|
||||||
export interface ContentContextProps {
|
export interface ContentContextProps {
|
||||||
contentHeight: ComputedRef<number>;
|
contentHeight: ComputedRef<number>;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ref, computed, unref } from 'vue';
|
import { ref, computed, unref } from 'vue';
|
||||||
import { createPageContext } from '/@/hooks/component/usePageContext';
|
import { createPageContext } from '@/hooks/component/usePageContext';
|
||||||
import { useWindowSizeFn } from '@vben/hooks';
|
import { useWindowSizeFn } from '@vben/hooks';
|
||||||
|
|
||||||
const headerHeightRef = ref(0);
|
const headerHeightRef = ref(0);
|
||||||
|
@ -1,63 +1,3 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { defineComponent, computed, unref } from 'vue';
|
|
||||||
import { BackTop } from 'ant-design-vue';
|
|
||||||
|
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
|
||||||
import { useUserStoreWithOut } from '/@/store/modules/user';
|
|
||||||
|
|
||||||
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
|
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
|
||||||
|
|
||||||
import SessionTimeoutLogin from '/@/views/sys/login/SessionTimeoutLogin.vue';
|
|
||||||
|
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'LayoutFeatures',
|
|
||||||
components: {
|
|
||||||
BackTop,
|
|
||||||
LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/lock/index.vue')),
|
|
||||||
SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue')),
|
|
||||||
SessionTimeoutLogin,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } =
|
|
||||||
useRootSetting();
|
|
||||||
const userStore = useUserStoreWithOut();
|
|
||||||
const { prefixCls } = useDesign('setting-drawer-feature');
|
|
||||||
const { getShowHeader } = useHeaderSetting();
|
|
||||||
|
|
||||||
const getIsSessionTimeout = computed(() => userStore.getSessionTimeout);
|
|
||||||
|
|
||||||
const getIsFixedSettingDrawer = computed(() => {
|
|
||||||
if (!unref(getShowSettingButton)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const settingButtonPosition = unref(getSettingButtonPosition);
|
|
||||||
|
|
||||||
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
|
|
||||||
return !unref(getShowHeader) || unref(getFullContent);
|
|
||||||
}
|
|
||||||
return settingButtonPosition === SettingButtonPositionEnum.FIXED;
|
|
||||||
});
|
|
||||||
|
|
||||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
|
||||||
|
|
||||||
return {
|
|
||||||
getTarget: () => document.body,
|
|
||||||
getUseOpenBackTop,
|
|
||||||
getIsFixedSettingDrawer,
|
|
||||||
prefixCls,
|
|
||||||
getIsSessionTimeout,
|
|
||||||
getShowMultipleTab,
|
|
||||||
getFullContent,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<LayoutLockPage />
|
<LayoutLockPage />
|
||||||
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
|
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
|
||||||
@ -67,7 +7,51 @@
|
|||||||
/>
|
/>
|
||||||
<SessionTimeoutLogin v-if="getIsSessionTimeout" />
|
<SessionTimeoutLogin v-if="getIsSessionTimeout" />
|
||||||
</template>
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, unref } from 'vue';
|
||||||
|
import { BackTop } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
import { useUserStoreWithOut } from '@/store/modules/user';
|
||||||
|
|
||||||
|
import { SettingButtonPositionEnum } from '@/enums/appEnum';
|
||||||
|
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
|
||||||
|
|
||||||
|
import SessionTimeoutLogin from '@/views/sys/login/SessionTimeoutLogin.vue';
|
||||||
|
|
||||||
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
|
|
||||||
|
defineOptions({ name: 'LayoutFeatures' });
|
||||||
|
|
||||||
|
const LayoutLockPage = createAsyncComponent(() => import('@/views/sys/lock/index.vue'));
|
||||||
|
const SettingDrawer = createAsyncComponent(() => import('@/layouts/default/setting/index.vue'));
|
||||||
|
|
||||||
|
const getTarget = () => document.body;
|
||||||
|
|
||||||
|
const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } =
|
||||||
|
useRootSetting();
|
||||||
|
const userStore = useUserStoreWithOut();
|
||||||
|
const { prefixCls } = useDesign('setting-drawer-feature');
|
||||||
|
const { getShowHeader } = useHeaderSetting();
|
||||||
|
|
||||||
|
const getIsSessionTimeout = computed(() => userStore.getSessionTimeout);
|
||||||
|
|
||||||
|
const getIsFixedSettingDrawer = computed(() => {
|
||||||
|
if (!unref(getShowSettingButton)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const settingButtonPosition = unref(getSettingButtonPosition);
|
||||||
|
|
||||||
|
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
|
||||||
|
return !unref(getShowHeader) || unref(getFullContent);
|
||||||
|
}
|
||||||
|
return settingButtonPosition === SettingButtonPositionEnum.FIXED;
|
||||||
|
});
|
||||||
|
|
||||||
|
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||||
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-setting-drawer-feature';
|
@prefix-cls: ~'@{namespace}-setting-drawer-feature';
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Footer :class="prefixCls" v-if="getShowLayoutFooter" ref="footerRef">
|
<Layout.Footer :class="prefixCls" v-if="getShowLayoutFooter" ref="footerRef">
|
||||||
<div :class="`${prefixCls}__links`">
|
<div :class="`${prefixCls}__links`">
|
||||||
<a @click="openWindow(SITE_URL)">{{ t('layout.footer.onlinePreview') }}</a>
|
<a @click="openWindow(SITE_URL)">{{ t('layout.footer.onlinePreview') }}</a>
|
||||||
|
|
||||||
@ -8,57 +8,41 @@
|
|||||||
<a @click="openWindow(DOC_URL)">{{ t('layout.footer.onlineDocument') }}</a>
|
<a @click="openWindow(DOC_URL)">{{ t('layout.footer.onlineDocument') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div>Copyright ©2020 Vben Admin</div>
|
<div>Copyright ©2020 Vben Admin</div>
|
||||||
</Footer>
|
</Layout.Footer>
|
||||||
</template>
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
<script lang="ts">
|
import { computed, unref, ref } from 'vue';
|
||||||
import { computed, defineComponent, unref, ref } from 'vue';
|
|
||||||
import { Layout } from 'ant-design-vue';
|
import { Layout } from 'ant-design-vue';
|
||||||
|
|
||||||
import { GithubFilled } from '@ant-design/icons-vue';
|
import { GithubFilled } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
|
import { DOC_URL, GITHUB_URL, SITE_URL } from '@/settings/siteSetting';
|
||||||
import { openWindow } from '/@/utils';
|
import { openWindow } from '@/utils';
|
||||||
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useLayoutHeight } from '../content/useContentViewHeight';
|
import { useLayoutHeight } from '../content/useContentViewHeight';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'LayoutFooter' });
|
||||||
name: 'LayoutFooter',
|
|
||||||
components: { Footer: Layout.Footer, GithubFilled },
|
|
||||||
setup() {
|
|
||||||
const { t } = useI18n();
|
|
||||||
const { getShowFooter } = useRootSetting();
|
|
||||||
const { currentRoute } = useRouter();
|
|
||||||
const { prefixCls } = useDesign('layout-footer');
|
|
||||||
|
|
||||||
const footerRef = ref<ComponentRef>(null);
|
const { t } = useI18n();
|
||||||
const { setFooterHeight } = useLayoutHeight();
|
const { getShowFooter } = useRootSetting();
|
||||||
|
const { currentRoute } = useRouter();
|
||||||
|
const { prefixCls } = useDesign('layout-footer');
|
||||||
|
|
||||||
const getShowLayoutFooter = computed(() => {
|
const footerRef = ref<ComponentRef>(null);
|
||||||
if (unref(getShowFooter)) {
|
const { setFooterHeight } = useLayoutHeight();
|
||||||
const footerEl = unref(footerRef)?.$el;
|
|
||||||
setFooterHeight(footerEl?.offsetHeight || 0);
|
|
||||||
} else {
|
|
||||||
setFooterHeight(0);
|
|
||||||
}
|
|
||||||
return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
const getShowLayoutFooter = computed(() => {
|
||||||
getShowLayoutFooter,
|
if (unref(getShowFooter)) {
|
||||||
prefixCls,
|
const footerEl = unref(footerRef)?.$el;
|
||||||
t,
|
setFooterHeight(footerEl?.offsetHeight || 0);
|
||||||
DOC_URL,
|
} else {
|
||||||
GITHUB_URL,
|
setFooterHeight(0);
|
||||||
SITE_URL,
|
}
|
||||||
openWindow,
|
return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter;
|
||||||
footerRef,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -9,111 +9,91 @@
|
|||||||
<MultipleTabs v-if="getShowTabs" :key="tabStore.getLastDragEndIndex" />
|
<MultipleTabs v-if="getShowTabs" :key="tabStore.getLastDragEndIndex" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, unref, computed, CSSProperties } from 'vue';
|
import { unref, computed, CSSProperties } from 'vue';
|
||||||
|
|
||||||
import LayoutHeader from './index.vue';
|
import LayoutHeader from './index.vue';
|
||||||
import MultipleTabs from '../tabs/index.vue';
|
import MultipleTabs from '../tabs/index.vue';
|
||||||
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { useFullContent } from '/@/hooks/web/useFullContent';
|
import { useFullContent } from '@/hooks/web/useFullContent';
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
import { useAppInject } from '@/hooks/web/useAppInject';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useLayoutHeight } from '../content/useContentViewHeight';
|
import { useLayoutHeight } from '../content/useContentViewHeight';
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
|
|
||||||
const HEADER_HEIGHT = 48;
|
const HEADER_HEIGHT = 48;
|
||||||
|
|
||||||
const TABS_HEIGHT = 32;
|
const TABS_HEIGHT = 32;
|
||||||
export default defineComponent({
|
|
||||||
name: 'LayoutMultipleHeader',
|
|
||||||
components: { LayoutHeader, MultipleTabs },
|
|
||||||
setup() {
|
|
||||||
const { setHeaderHeight } = useLayoutHeight();
|
|
||||||
const tabStore = useMultipleTabStore();
|
|
||||||
const { prefixCls } = useDesign('layout-multiple-header');
|
|
||||||
|
|
||||||
const { getCalcContentWidth, getSplit, getShowMenu } = useMenuSetting();
|
defineOptions({ name: 'LayoutMultipleHeader' });
|
||||||
const { getIsMobile } = useAppInject();
|
|
||||||
const {
|
|
||||||
getFixed,
|
|
||||||
getShowInsetHeaderRef,
|
|
||||||
getShowFullHeaderRef,
|
|
||||||
getHeaderTheme,
|
|
||||||
getShowHeader,
|
|
||||||
} = useHeaderSetting();
|
|
||||||
|
|
||||||
const { getFullContent } = useFullContent();
|
const { setHeaderHeight } = useLayoutHeight();
|
||||||
|
const tabStore = useMultipleTabStore();
|
||||||
|
const { prefixCls } = useDesign('layout-multiple-header');
|
||||||
|
|
||||||
const { getShowMultipleTab, getAutoCollapse } = useMultipleTabSetting();
|
const { getCalcContentWidth, getSplit, getShowMenu } = useMenuSetting();
|
||||||
|
const { getIsMobile } = useAppInject();
|
||||||
|
const { getFixed, getShowInsetHeaderRef, getShowFullHeaderRef, getHeaderTheme, getShowHeader } =
|
||||||
|
useHeaderSetting();
|
||||||
|
|
||||||
const getShowTabs = computed(() => {
|
const { getFullContent } = useFullContent();
|
||||||
return unref(getShowMultipleTab) && !unref(getFullContent);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getIsShowPlaceholderDom = computed(() => {
|
const { getShowMultipleTab, getAutoCollapse } = useMultipleTabSetting();
|
||||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getWrapStyle = computed((): CSSProperties => {
|
const getShowTabs = computed(() => {
|
||||||
const style: CSSProperties = {};
|
return unref(getShowMultipleTab) && !unref(getFullContent);
|
||||||
if (unref(getFixed)) {
|
});
|
||||||
style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
|
|
||||||
}
|
|
||||||
if (unref(getShowFullHeaderRef)) {
|
|
||||||
style.top = `${HEADER_HEIGHT}px`;
|
|
||||||
}
|
|
||||||
return style;
|
|
||||||
});
|
|
||||||
|
|
||||||
const getIsFixed = computed(() => {
|
const getIsShowPlaceholderDom = computed(() => {
|
||||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||||
});
|
});
|
||||||
|
|
||||||
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
const getWrapStyle = computed((): CSSProperties => {
|
||||||
|
const style: CSSProperties = {};
|
||||||
|
if (unref(getFixed)) {
|
||||||
|
style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
|
||||||
|
}
|
||||||
|
if (unref(getShowFullHeaderRef)) {
|
||||||
|
style.top = `${HEADER_HEIGHT}px`;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
});
|
||||||
|
|
||||||
const getPlaceholderDomStyle = computed((): CSSProperties => {
|
const getIsFixed = computed(() => {
|
||||||
let height = 0;
|
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||||
if (!(unref(getAutoCollapse) && unref(getIsUnFold))) {
|
});
|
||||||
if (
|
|
||||||
(unref(getShowFullHeaderRef) || !unref(getSplit)) &&
|
|
||||||
unref(getShowHeader) &&
|
|
||||||
!unref(getFullContent)
|
|
||||||
) {
|
|
||||||
height += HEADER_HEIGHT;
|
|
||||||
}
|
|
||||||
if (unref(getShowMultipleTab) && !unref(getFullContent)) {
|
|
||||||
height += TABS_HEIGHT;
|
|
||||||
}
|
|
||||||
setHeaderHeight(height);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
height: `${height}px`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getClass = computed(() => {
|
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
||||||
return [
|
|
||||||
prefixCls,
|
|
||||||
`${prefixCls}--${unref(getHeaderTheme)}`,
|
|
||||||
{ [`${prefixCls}--fixed`]: unref(getIsFixed) },
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
const getPlaceholderDomStyle = computed((): CSSProperties => {
|
||||||
getClass,
|
let height = 0;
|
||||||
prefixCls,
|
if (!(unref(getAutoCollapse) && unref(getIsUnFold))) {
|
||||||
getPlaceholderDomStyle,
|
if (
|
||||||
getIsFixed,
|
(unref(getShowFullHeaderRef) || !unref(getSplit)) &&
|
||||||
getWrapStyle,
|
unref(getShowHeader) &&
|
||||||
getIsShowPlaceholderDom,
|
!unref(getFullContent)
|
||||||
getShowTabs,
|
) {
|
||||||
getShowInsetHeaderRef,
|
height += HEADER_HEIGHT;
|
||||||
tabStore,
|
}
|
||||||
};
|
if (unref(getShowMultipleTab) && !unref(getFullContent)) {
|
||||||
},
|
height += TABS_HEIGHT;
|
||||||
|
}
|
||||||
|
setHeaderHeight(height);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
height: `${height}px`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getClass = computed(() => {
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
`${prefixCls}--${unref(getHeaderTheme)}`,
|
||||||
|
{ [`${prefixCls}--fixed`]: unref(getIsFixed) },
|
||||||
|
];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<span v-if="!hasRedirect(routesMatched, route)">
|
<span v-if="!hasRedirect(routesMatched, route)">
|
||||||
{{ t(route.name || route.meta.title) }}
|
{{ t(route.name || route.meta.title) }}
|
||||||
</span>
|
</span>
|
||||||
<router-link v-else to="" @click="handleClick(route, paths, $event)">
|
<router-link v-else to="" @click="handleClick(route, paths, $event as Event)">
|
||||||
{{ t(route.name || route.meta.title) }}
|
{{ t(route.name || route.meta.title) }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,11 +19,11 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Radio } from 'ant-design-vue';
|
import { Radio } from 'ant-design-vue';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal/index';
|
import { BasicModal, useModalInner } from '@/components/Modal';
|
||||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
import { BasicForm, useForm } from '@/components/Form';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useAppStore } from '/@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import type { ApiAddress } from '/#/store';
|
import type { ApiAddress } from '/#/store';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
@ -79,4 +79,3 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="less"></style>
|
|
||||||
|
@ -10,38 +10,27 @@
|
|||||||
</Badge>
|
</Badge>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { Tooltip, Badge } from 'ant-design-vue';
|
import { Tooltip, Badge } from 'ant-design-vue';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useErrorLogStore } from '/@/store/modules/errorLog';
|
import { useErrorLogStore } from '@/store/modules/errorLog';
|
||||||
import { PageEnum } from '/@/enums/pageEnum';
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'ErrorAction' });
|
||||||
name: 'ErrorAction',
|
|
||||||
components: { Icon, Tooltip, Badge },
|
|
||||||
|
|
||||||
setup() {
|
const { t } = useI18n();
|
||||||
const { t } = useI18n();
|
const { push } = useRouter();
|
||||||
const { push } = useRouter();
|
const errorLogStore = useErrorLogStore();
|
||||||
const errorLogStore = useErrorLogStore();
|
|
||||||
|
|
||||||
const getCount = computed(() => errorLogStore.getErrorLogListCount);
|
const getCount = computed(() => errorLogStore.getErrorLogListCount);
|
||||||
|
|
||||||
function handleToErrorList() {
|
function handleToErrorList() {
|
||||||
push(PageEnum.ERROR_LOG_PAGE).then(() => {
|
push(PageEnum.ERROR_LOG_PAGE).then(() => {
|
||||||
errorLogStore.setErrorLogListCount(0);
|
errorLogStore.setErrorLogListCount(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
t,
|
|
||||||
getCount,
|
|
||||||
handleToErrorList,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -6,40 +6,29 @@
|
|||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, computed, unref } from 'vue';
|
import { computed, unref } from 'vue';
|
||||||
import { Tooltip } from 'ant-design-vue';
|
import { Tooltip } from 'ant-design-vue';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useFullscreen } from '@vueuse/core';
|
import { useFullscreen } from '@vueuse/core';
|
||||||
|
|
||||||
import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons-vue';
|
import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'FullScreen' });
|
||||||
name: 'FullScreen',
|
|
||||||
components: { FullscreenExitOutlined, FullscreenOutlined, Tooltip },
|
|
||||||
|
|
||||||
setup() {
|
const { t } = useI18n();
|
||||||
const { t } = useI18n();
|
const { toggle, isFullscreen } = useFullscreen();
|
||||||
const { toggle, isFullscreen } = useFullscreen();
|
// 重新检查全屏状态
|
||||||
// 重新检查全屏状态
|
isFullscreen.value = !!(
|
||||||
isFullscreen.value = !!(
|
document.fullscreenElement ||
|
||||||
document.fullscreenElement ||
|
document.webkitFullscreenElement ||
|
||||||
document.webkitFullscreenElement ||
|
document.mozFullScreenElement ||
|
||||||
document.mozFullScreenElement ||
|
document.msFullscreenElement
|
||||||
document.msFullscreenElement
|
);
|
||||||
);
|
|
||||||
|
|
||||||
const getTitle = computed(() => {
|
const getTitle = computed(() => {
|
||||||
return unref(isFullscreen)
|
return unref(isFullscreen)
|
||||||
? t('layout.header.tooltipExitFull')
|
? t('layout.header.tooltipExitFull')
|
||||||
: t('layout.header.tooltipEntryFull');
|
: t('layout.header.tooltipEntryFull');
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
getTitle,
|
|
||||||
isFullscreen,
|
|
||||||
toggle,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
|
||||||
import FullScreen from './FullScreen.vue';
|
import FullScreen from './FullScreen.vue';
|
||||||
|
|
||||||
export const UserDropDown = createAsyncComponent(() => import('./user-dropdown/index.vue'), {
|
export const UserDropDown = createAsyncComponent(() => import('./user-dropdown/index.vue'), {
|
||||||
|
@ -24,75 +24,60 @@
|
|||||||
</div>
|
</div>
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal/index';
|
import { BasicModal, useModalInner } from '@/components/Modal';
|
||||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
import { BasicForm, useForm } from '@/components/Form';
|
||||||
|
|
||||||
import { useUserStore } from '/@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { useLockStore } from '/@/store/modules/lock';
|
import { useLockStore } from '@/store/modules/lock';
|
||||||
import headerImg from '/@/assets/images/header.jpg';
|
import headerImg from '@/assets/images/header.jpg';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'LockModal' });
|
||||||
name: 'LockModal',
|
|
||||||
components: { BasicModal, BasicForm },
|
|
||||||
|
|
||||||
setup() {
|
const { t } = useI18n();
|
||||||
const { t } = useI18n();
|
const { prefixCls } = useDesign('header-lock-modal');
|
||||||
const { prefixCls } = useDesign('header-lock-modal');
|
const userStore = useUserStore();
|
||||||
const userStore = useUserStore();
|
const lockStore = useLockStore();
|
||||||
const lockStore = useLockStore();
|
|
||||||
|
|
||||||
const getRealName = computed(() => userStore.getUserInfo?.realName);
|
const getRealName = computed(() => userStore.getUserInfo?.realName);
|
||||||
const [register, { closeModal }] = useModalInner();
|
const [register, { closeModal }] = useModalInner();
|
||||||
|
|
||||||
const [registerForm, { validate, resetFields }] = useForm({
|
const [registerForm, { validate, resetFields }] = useForm({
|
||||||
showActionButtonGroup: false,
|
showActionButtonGroup: false,
|
||||||
schemas: [
|
schemas: [
|
||||||
{
|
{
|
||||||
field: 'password',
|
field: 'password',
|
||||||
label: t('layout.header.lockScreenPassword'),
|
label: t('layout.header.lockScreenPassword'),
|
||||||
colProps: {
|
colProps: {
|
||||||
span: 24,
|
span: 24,
|
||||||
},
|
},
|
||||||
component: 'InputPassword',
|
component: 'InputPassword',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleLock = async () => {
|
const handleLock = async () => {
|
||||||
const { password = '' } = await validate<{
|
const { password = '' } = await validate<{
|
||||||
password: string;
|
password: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
lockStore.setLockInfo({
|
lockStore.setLockInfo({
|
||||||
isLock: true,
|
isLock: true,
|
||||||
pwd: password,
|
pwd: password,
|
||||||
});
|
});
|
||||||
|
|
||||||
await resetFields();
|
await resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
const avatar = computed(() => {
|
const avatar = computed(() => {
|
||||||
const { avatar } = userStore.getUserInfo;
|
const { avatar } = userStore.getUserInfo;
|
||||||
return avatar || headerImg;
|
return avatar || headerImg;
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
t,
|
|
||||||
prefixCls,
|
|
||||||
getRealName,
|
|
||||||
register,
|
|
||||||
registerForm,
|
|
||||||
handleLock,
|
|
||||||
avatar,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@ -1,43 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-list :class="prefixCls" bordered :pagination="getPagination">
|
<List :class="prefixCls" bordered :pagination="getPagination">
|
||||||
<template v-for="item in getData" :key="item.id">
|
<template v-for="item in getData" :key="item.id">
|
||||||
<a-list-item class="list-item">
|
<List.Item class="list-item">
|
||||||
<a-list-item-meta>
|
<List.Item.Meta>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<a-typography-paragraph
|
<Typography.Paragraph
|
||||||
@click="handleTitleClick(item)"
|
@click="handleTitleClick(item)"
|
||||||
style="width: 100%; margin-bottom: 0 !important"
|
|
||||||
:style="{ cursor: isTitleClickable ? 'pointer' : '' }"
|
|
||||||
:delete="!!item.titleDelete"
|
:delete="!!item.titleDelete"
|
||||||
:ellipsis="
|
:ellipsis="
|
||||||
$props.titleRows && $props.titleRows > 0
|
titleRows && titleRows > 0 ? { rows: titleRows, tooltip: !!item.title } : false
|
||||||
? { rows: $props.titleRows, tooltip: !!item.title }
|
|
||||||
: false
|
|
||||||
"
|
"
|
||||||
:content="item.title"
|
:content="item.title"
|
||||||
/>
|
/>
|
||||||
<div class="extra" v-if="item.extra">
|
<div class="extra" v-if="item.extra">
|
||||||
<a-tag class="tag" :color="item.color">
|
<Tag class="tag" :color="item.color">
|
||||||
{{ item.extra }}
|
{{ item.extra }}
|
||||||
</a-tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #avatar>
|
<template #avatar>
|
||||||
<a-avatar v-if="item.avatar" class="avatar" :src="item.avatar" />
|
<Avatar v-if="item.avatar" class="avatar" :src="item.avatar" />
|
||||||
<span v-else> {{ item.avatar }}</span>
|
<span v-else> {{ item.avatar }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #description>
|
<template #description>
|
||||||
<div>
|
<div>
|
||||||
<div class="description" v-if="item.description">
|
<div class="description" v-if="item.description">
|
||||||
<a-typography-paragraph
|
<Typography.Paragraph
|
||||||
style="width: 100%; margin-bottom: 0 !important"
|
|
||||||
:ellipsis="
|
:ellipsis="
|
||||||
$props.descRows && $props.descRows > 0
|
descRows && descRows > 0
|
||||||
? { rows: $props.descRows, tooltip: !!item.description }
|
? { rows: descRows, tooltip: !!item.description }
|
||||||
: false
|
: false
|
||||||
"
|
"
|
||||||
:content="item.description"
|
:content="item.description"
|
||||||
@ -48,107 +43,85 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-list-item-meta>
|
</List.Item.Meta>
|
||||||
</a-list-item>
|
</List.Item>
|
||||||
</template>
|
</template>
|
||||||
</a-list>
|
</List>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, PropType, ref, watch, unref } from 'vue';
|
import { computed, PropType, ref, watch, unref } from 'vue';
|
||||||
import { ListItem } from './data';
|
import { ListItem } from './data';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { List, Avatar, Tag, Typography } from 'ant-design-vue';
|
import { List, Avatar, Tag, Typography } from 'ant-design-vue';
|
||||||
import { isNumber } from '/@/utils/is';
|
import { isNumber } from '@/utils/is';
|
||||||
|
|
||||||
// types
|
const props = defineProps({
|
||||||
import type { StyleValue } from '/@/utils/types';
|
list: {
|
||||||
import type { FunctionalComponent } from 'vue';
|
type: Array as PropType<ListItem[]>,
|
||||||
import type { ParagraphProps } from 'ant-design-vue/es/typography/Paragraph';
|
default: () => [],
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
[Avatar.name]: Avatar,
|
|
||||||
[List.name]: List,
|
|
||||||
[List.Item.name]: List.Item,
|
|
||||||
AListItemMeta: List.Item.Meta,
|
|
||||||
ATypographyParagraph: Typography.Paragraph as FunctionalComponent<
|
|
||||||
ParagraphProps & {
|
|
||||||
style?: StyleValue;
|
|
||||||
}
|
|
||||||
>,
|
|
||||||
[Tag.name]: Tag,
|
|
||||||
},
|
},
|
||||||
props: {
|
pageSize: {
|
||||||
list: {
|
type: [Boolean, Number] as PropType<Boolean | Number>,
|
||||||
type: Array as PropType<ListItem[]>,
|
default: 5,
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
pageSize: {
|
|
||||||
type: [Boolean, Number] as PropType<Boolean | Number>,
|
|
||||||
default: 5,
|
|
||||||
},
|
|
||||||
currentPage: {
|
|
||||||
type: Number,
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
titleRows: {
|
|
||||||
type: Number,
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
descRows: {
|
|
||||||
type: Number,
|
|
||||||
default: 2,
|
|
||||||
},
|
|
||||||
onTitleClick: {
|
|
||||||
type: Function as PropType<(Recordable) => void>,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
emits: ['update:currentPage'],
|
currentPage: {
|
||||||
setup(props, { emit }) {
|
type: Number,
|
||||||
const { prefixCls } = useDesign('header-notify-list');
|
default: 1,
|
||||||
const current = ref(props.currentPage || 1);
|
},
|
||||||
const getData = computed(() => {
|
titleRows: {
|
||||||
const { pageSize, list } = props;
|
type: Number,
|
||||||
if (pageSize === false) return [];
|
default: 1,
|
||||||
let size = isNumber(pageSize) ? pageSize : 5;
|
},
|
||||||
return list.slice(size * (unref(current) - 1), size * unref(current));
|
descRows: {
|
||||||
});
|
type: Number,
|
||||||
watch(
|
default: 2,
|
||||||
() => props.currentPage,
|
},
|
||||||
(v) => {
|
onTitleClick: {
|
||||||
current.value = v;
|
type: Function as PropType<(Recordable) => void>,
|
||||||
},
|
|
||||||
);
|
|
||||||
const isTitleClickable = computed(() => !!props.onTitleClick);
|
|
||||||
const getPagination = computed(() => {
|
|
||||||
const { list, pageSize } = props;
|
|
||||||
|
|
||||||
// compatible line 104
|
|
||||||
// if typeof pageSize is boolean, Number(true) && 5 = 5, Number(false) && 5 = 0
|
|
||||||
const size = isNumber(pageSize) ? pageSize : Number(pageSize) && 5;
|
|
||||||
|
|
||||||
if (size > 0 && list && list.length > size) {
|
|
||||||
return {
|
|
||||||
total: list.length,
|
|
||||||
pageSize: size,
|
|
||||||
current: unref(current),
|
|
||||||
onChange(page) {
|
|
||||||
current.value = page;
|
|
||||||
emit('update:currentPage', page);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleTitleClick(item: ListItem) {
|
|
||||||
props.onTitleClick && props.onTitleClick(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { prefixCls, getPagination, getData, handleTitleClick, isTitleClickable };
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:currentPage']);
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('header-notify-list');
|
||||||
|
const current = ref(props.currentPage || 1);
|
||||||
|
const getData = computed(() => {
|
||||||
|
const { pageSize, list } = props;
|
||||||
|
if (pageSize === false) return [];
|
||||||
|
let size = isNumber(pageSize) ? pageSize : 5;
|
||||||
|
return list.slice(size * (unref(current) - 1), size * unref(current));
|
||||||
|
});
|
||||||
|
watch(
|
||||||
|
() => props.currentPage,
|
||||||
|
(v) => {
|
||||||
|
current.value = v;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const getPagination = computed(() => {
|
||||||
|
const { list, pageSize } = props;
|
||||||
|
|
||||||
|
// compatible line 104
|
||||||
|
// if typeof pageSize is boolean, Number(true) && 5 = 5, Number(false) && 5 = 0
|
||||||
|
const size = isNumber(pageSize) ? pageSize : Number(pageSize) && 5;
|
||||||
|
|
||||||
|
if (size > 0 && list && list.length > size) {
|
||||||
|
return {
|
||||||
|
total: list.length,
|
||||||
|
pageSize: size,
|
||||||
|
current: unref(current),
|
||||||
|
onChange(page) {
|
||||||
|
current.value = page;
|
||||||
|
emit('update:currentPage', page);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleTitleClick(item: ListItem) {
|
||||||
|
props.onTitleClick && props.onTitleClick(item);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-header-notify-list';
|
@prefix-cls: ~'@{namespace}-header-notify-list';
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<template #content>
|
<template #content>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<template v-for="item in listData" :key="item.key">
|
<template v-for="item in listData" :key="item.key">
|
||||||
<TabPane>
|
<Tabs.TabPane>
|
||||||
<template #tab>
|
<template #tab>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
<span v-if="item.list.length !== 0">({{ item.list.length }})</span>
|
<span v-if="item.list.length !== 0">({{ item.list.length }})</span>
|
||||||
@ -15,52 +15,40 @@
|
|||||||
<!-- 绑定title-click事件的通知列表中标题是“可点击”的-->
|
<!-- 绑定title-click事件的通知列表中标题是“可点击”的-->
|
||||||
<NoticeList :list="item.list" v-if="item.key === '1'" @title-click="onNoticeClick" />
|
<NoticeList :list="item.list" v-if="item.key === '1'" @title-click="onNoticeClick" />
|
||||||
<NoticeList :list="item.list" v-else />
|
<NoticeList :list="item.list" v-else />
|
||||||
</TabPane>
|
</Tabs.TabPane>
|
||||||
</template>
|
</template>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</template>
|
</template>
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { Popover, Tabs, Badge } from 'ant-design-vue';
|
import { Popover, Tabs, Badge } from 'ant-design-vue';
|
||||||
import { BellOutlined } from '@ant-design/icons-vue';
|
import { BellOutlined } from '@ant-design/icons-vue';
|
||||||
import { tabListData, ListItem } from './data';
|
import { tabListData, ListItem } from './data';
|
||||||
import NoticeList from './NoticeList.vue';
|
import NoticeList from './NoticeList.vue';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '@/hooks/web/useMessage';
|
||||||
|
|
||||||
export default defineComponent({
|
const { prefixCls } = useDesign('header-notify');
|
||||||
components: { Popover, BellOutlined, Tabs, TabPane: Tabs.TabPane, Badge, NoticeList },
|
const { createMessage } = useMessage();
|
||||||
setup() {
|
const listData = ref(tabListData);
|
||||||
const { prefixCls } = useDesign('header-notify');
|
const numberStyle = {};
|
||||||
const { createMessage } = useMessage();
|
|
||||||
const listData = ref(tabListData);
|
|
||||||
|
|
||||||
const count = computed(() => {
|
const count = computed(() => {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (let i = 0; i < tabListData.length; i++) {
|
for (let i = 0; i < tabListData.length; i++) {
|
||||||
count += tabListData[i].list.length;
|
count += tabListData[i].list.length;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
});
|
|
||||||
|
|
||||||
function onNoticeClick(record: ListItem) {
|
|
||||||
createMessage.success('你点击了通知,ID=' + record.id);
|
|
||||||
// 可以直接将其标记为已读(为标题添加删除线),此处演示的代码会切换删除线状态
|
|
||||||
record.titleDelete = !record.titleDelete;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
prefixCls,
|
|
||||||
listData,
|
|
||||||
count,
|
|
||||||
onNoticeClick,
|
|
||||||
numberStyle: {},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onNoticeClick(record: ListItem) {
|
||||||
|
createMessage.success('你点击了通知,ID=' + record.id);
|
||||||
|
// 可以直接将其标记为已读(为标题添加删除线),此处演示的代码会切换删除线状态
|
||||||
|
record.titleDelete = !record.titleDelete;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-header-notify';
|
@prefix-cls: ~'@{namespace}-header-notify';
|
||||||
|
@ -1,32 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<MenuItem :key="itemKey">
|
<Menu.Item :key="itemKey">
|
||||||
<span class="flex items-center">
|
<span class="flex items-center">
|
||||||
<Icon :icon="icon" class="mr-1" />
|
<Icon :icon="icon" class="mr-1" />
|
||||||
<span>{{ text }}</span>
|
<span>{{ text }}</span>
|
||||||
</span>
|
</span>
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { Menu } from 'ant-design-vue';
|
import { Menu } from 'ant-design-vue';
|
||||||
|
import { computed, getCurrentInstance } from 'vue';
|
||||||
import { computed, defineComponent, getCurrentInstance } from 'vue';
|
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
defineOptions({ name: 'DropdownMenuItem' });
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'DropdownMenuItem',
|
// eslint-disable-next-line
|
||||||
components: { MenuItem: Menu.Item, Icon },
|
key: propTypes.string,
|
||||||
props: {
|
text: propTypes.string,
|
||||||
// eslint-disable-next-line
|
icon: propTypes.string,
|
||||||
key: propTypes.string,
|
|
||||||
text: propTypes.string,
|
|
||||||
icon: propTypes.string,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const instance = getCurrentInstance();
|
|
||||||
const itemKey = computed(() => props.key || instance?.vnode?.props?.key);
|
|
||||||
return { itemKey };
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
const itemKey = computed(() => props.key || instance?.vnode?.props?.key);
|
||||||
</script>
|
</script>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
icon="ion:document-text-outline"
|
icon="ion:document-text-outline"
|
||||||
v-if="getShowDoc"
|
v-if="getShowDoc"
|
||||||
/>
|
/>
|
||||||
<MenuDivider v-if="getShowDoc" />
|
<Menu.Divider v-if="getShowDoc" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-if="getShowApi"
|
v-if="getShowApi"
|
||||||
key="api"
|
key="api"
|
||||||
@ -41,104 +41,80 @@
|
|||||||
<LockAction @register="register" />
|
<LockAction @register="register" />
|
||||||
<ChangeApi @register="registerApi" />
|
<ChangeApi @register="registerApi" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
// components
|
|
||||||
import { Dropdown, Menu } from 'ant-design-vue';
|
import { Dropdown, Menu } from 'ant-design-vue';
|
||||||
import type { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
import type { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
|
||||||
|
import { computed } from 'vue';
|
||||||
import { defineComponent, computed } from 'vue';
|
import { DOC_URL } from '@/settings/siteSetting';
|
||||||
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { DOC_URL } from '/@/settings/siteSetting';
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useUserStore } from '/@/store/modules/user';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useModal } from '@/components/Modal';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import headerImg from '@/assets/images/header.jpg';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
import { useModal } from '/@/components/Modal';
|
import { openWindow } from '@/utils';
|
||||||
|
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
|
||||||
import headerImg from '/@/assets/images/header.jpg';
|
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
|
||||||
import { openWindow } from '/@/utils';
|
|
||||||
|
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
|
||||||
|
|
||||||
type MenuEvent = 'logout' | 'doc' | 'lock' | 'api';
|
type MenuEvent = 'logout' | 'doc' | 'lock' | 'api';
|
||||||
|
|
||||||
export default defineComponent({
|
const MenuItem = createAsyncComponent(() => import('./DropMenuItem.vue'));
|
||||||
name: 'UserDropdown',
|
const LockAction = createAsyncComponent(() => import('../lock/LockModal.vue'));
|
||||||
components: {
|
const ChangeApi = createAsyncComponent(() => import('../ChangeApi/index.vue'));
|
||||||
Dropdown,
|
|
||||||
Menu,
|
|
||||||
MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
|
|
||||||
MenuDivider: Menu.Divider,
|
|
||||||
LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
|
|
||||||
ChangeApi: createAsyncComponent(() => import('../ChangeApi/index.vue')),
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
theme: propTypes.oneOf(['dark', 'light']),
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const { prefixCls } = useDesign('header-user-dropdown');
|
|
||||||
const { t } = useI18n();
|
|
||||||
const { getShowDoc, getUseLockPage, getShowApi } = useHeaderSetting();
|
|
||||||
const userStore = useUserStore();
|
|
||||||
|
|
||||||
const getUserInfo = computed(() => {
|
defineOptions({ name: 'UserDropdown' });
|
||||||
const { realName = '', avatar, desc } = userStore.getUserInfo || {};
|
|
||||||
return { realName, avatar: avatar || headerImg, desc };
|
|
||||||
});
|
|
||||||
|
|
||||||
const [register, { openModal }] = useModal();
|
defineProps({
|
||||||
const [registerApi, { openModal: openApiModal }] = useModal();
|
theme: propTypes.oneOf(['dark', 'light']),
|
||||||
|
|
||||||
function handleLock() {
|
|
||||||
openModal(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleApi() {
|
|
||||||
openApiModal(true, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
// login out
|
|
||||||
function handleLoginOut() {
|
|
||||||
userStore.confirmLoginOut();
|
|
||||||
}
|
|
||||||
|
|
||||||
// open doc
|
|
||||||
function openDoc() {
|
|
||||||
openWindow(DOC_URL);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMenuClick(e: MenuInfo) {
|
|
||||||
switch (e.key as MenuEvent) {
|
|
||||||
case 'logout':
|
|
||||||
handleLoginOut();
|
|
||||||
break;
|
|
||||||
case 'doc':
|
|
||||||
openDoc();
|
|
||||||
break;
|
|
||||||
case 'lock':
|
|
||||||
handleLock();
|
|
||||||
break;
|
|
||||||
case 'api':
|
|
||||||
handleApi();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
prefixCls,
|
|
||||||
t,
|
|
||||||
getUserInfo,
|
|
||||||
handleMenuClick,
|
|
||||||
getShowDoc,
|
|
||||||
getShowApi,
|
|
||||||
register,
|
|
||||||
registerApi,
|
|
||||||
getUseLockPage,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('header-user-dropdown');
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { getShowDoc, getUseLockPage, getShowApi } = useHeaderSetting();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const getUserInfo = computed(() => {
|
||||||
|
const { realName = '', avatar, desc } = userStore.getUserInfo || {};
|
||||||
|
return { realName, avatar: avatar || headerImg, desc };
|
||||||
|
});
|
||||||
|
|
||||||
|
const [register, { openModal }] = useModal();
|
||||||
|
const [registerApi, { openModal: openApiModal }] = useModal();
|
||||||
|
|
||||||
|
function handleLock() {
|
||||||
|
openModal(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleApi() {
|
||||||
|
openApiModal(true, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// login out
|
||||||
|
function handleLoginOut() {
|
||||||
|
userStore.confirmLoginOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
// open doc
|
||||||
|
function openDoc() {
|
||||||
|
openWindow(DOC_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMenuClick(e: MenuInfo) {
|
||||||
|
switch (e.key as MenuEvent) {
|
||||||
|
case 'logout':
|
||||||
|
handleLoginOut();
|
||||||
|
break;
|
||||||
|
case 'doc':
|
||||||
|
openDoc();
|
||||||
|
break;
|
||||||
|
case 'lock':
|
||||||
|
handleLock();
|
||||||
|
break;
|
||||||
|
case 'api':
|
||||||
|
handleApi();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-header-user-dropdown';
|
@prefix-cls: ~'@{namespace}-header-user-dropdown';
|
||||||
|
@ -13,69 +13,50 @@
|
|||||||
</Layout>
|
</Layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, computed, unref } from 'vue';
|
import { computed, unref } from 'vue';
|
||||||
import { Layout } from 'ant-design-vue';
|
import { Layout } from 'ant-design-vue';
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
|
||||||
|
|
||||||
import LayoutHeader from './header/index.vue';
|
import LayoutHeader from './header/index.vue';
|
||||||
import LayoutContent from './content/index.vue';
|
import LayoutContent from './content/index.vue';
|
||||||
import LayoutSideBar from './sider/index.vue';
|
import LayoutSideBar from './sider/index.vue';
|
||||||
import LayoutMultipleHeader from './header/MultipleHeader.vue';
|
import LayoutMultipleHeader from './header/MultipleHeader.vue';
|
||||||
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useLockPage } from '/@/hooks/web/useLockPage';
|
import { useLockPage } from '@/hooks/web/useLockPage';
|
||||||
|
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
import { useAppInject } from '@/hooks/web/useAppInject';
|
||||||
|
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
const LayoutFeatures = createAsyncComponent(() => import('@/layouts/default/feature/index.vue'));
|
||||||
name: 'DefaultLayout',
|
const LayoutFooter = createAsyncComponent(() => import('@/layouts/default/footer/index.vue'));
|
||||||
components: {
|
|
||||||
LayoutFeatures: createAsyncComponent(() => import('/@/layouts/default/feature/index.vue')),
|
|
||||||
LayoutFooter: createAsyncComponent(() => import('/@/layouts/default/footer/index.vue')),
|
|
||||||
LayoutHeader,
|
|
||||||
LayoutContent,
|
|
||||||
LayoutSideBar,
|
|
||||||
LayoutMultipleHeader,
|
|
||||||
Layout,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const { prefixCls } = useDesign('default-layout');
|
|
||||||
const { getIsMobile } = useAppInject();
|
|
||||||
const { getShowFullHeaderRef } = useHeaderSetting();
|
|
||||||
const { getShowSidebar, getIsMixSidebar, getShowMenu } = useMenuSetting();
|
|
||||||
const { getAutoCollapse } = useMultipleTabSetting();
|
|
||||||
|
|
||||||
// Create a lock screen monitor
|
defineOptions({ name: 'DefaultLayout' });
|
||||||
const lockEvents = useLockPage();
|
|
||||||
|
|
||||||
const layoutClass = computed(() => {
|
const { prefixCls } = useDesign('default-layout');
|
||||||
let cls: string[] = ['ant-layout'];
|
const { getIsMobile } = useAppInject();
|
||||||
if (unref(getIsMixSidebar) || unref(getShowMenu)) {
|
const { getShowFullHeaderRef } = useHeaderSetting();
|
||||||
cls.push('ant-layout-has-sider');
|
const { getShowSidebar, getIsMixSidebar, getShowMenu } = useMenuSetting();
|
||||||
}
|
const { getAutoCollapse } = useMultipleTabSetting();
|
||||||
|
|
||||||
if (!unref(getShowMenu) && unref(getAutoCollapse)) {
|
// Create a lock screen monitor
|
||||||
cls.push('ant-layout-auto-collapse-tabs');
|
const lockEvents = useLockPage();
|
||||||
}
|
|
||||||
|
|
||||||
return cls;
|
const layoutClass = computed(() => {
|
||||||
});
|
let cls: string[] = ['ant-layout'];
|
||||||
|
if (unref(getIsMixSidebar) || unref(getShowMenu)) {
|
||||||
|
cls.push('ant-layout-has-sider');
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
if (!unref(getShowMenu) && unref(getAutoCollapse)) {
|
||||||
getShowFullHeaderRef,
|
cls.push('ant-layout-auto-collapse-tabs');
|
||||||
getShowSidebar,
|
}
|
||||||
prefixCls,
|
|
||||||
getIsMobile,
|
return cls;
|
||||||
getIsMixSidebar,
|
|
||||||
layoutClass,
|
|
||||||
lockEvents,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@ -2,23 +2,23 @@
|
|||||||
import type { PropType, CSSProperties } from 'vue';
|
import type { PropType, CSSProperties } from 'vue';
|
||||||
|
|
||||||
import { computed, defineComponent, unref, toRef } from 'vue';
|
import { computed, defineComponent, unref, toRef } from 'vue';
|
||||||
import { BasicMenu } from '/@/components/Menu';
|
import { BasicMenu } from '@/components/Menu';
|
||||||
import { SimpleMenu } from '/@/components/SimpleMenu';
|
import { SimpleMenu } from '@/components/SimpleMenu';
|
||||||
import { AppLogo } from '/@/components/Application';
|
import { AppLogo } from '@/components/Application';
|
||||||
|
|
||||||
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
import { MenuModeEnum, MenuSplitTyeEnum } from '@/enums/menuEnum';
|
||||||
|
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { ScrollContainer } from '/@/components/Container';
|
import { ScrollContainer } from '@/components/Container';
|
||||||
|
|
||||||
import { useGo } from '/@/hooks/web/usePage';
|
import { useGo } from '@/hooks/web/usePage';
|
||||||
import { useSplitMenu } from './useLayoutMenu';
|
import { useSplitMenu } from './useLayoutMenu';
|
||||||
import { openWindow } from '/@/utils';
|
import { openWindow } from '@/utils';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
import { isHttpUrl } from '/@/utils/is';
|
import { isHttpUrl } from '@/utils/is';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
import { useAppInject } from '@/hooks/web/useAppInject';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'LayoutMenu',
|
name: 'LayoutMenu',
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import type { Menu } from '/@/router/types';
|
import type { Menu } from '@/router/types';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { watch, unref, ref, computed } from 'vue';
|
import { watch, unref, ref, computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
import { MenuSplitTyeEnum } from '@/enums/menuEnum';
|
||||||
import { useThrottleFn } from '@vueuse/core';
|
import { useThrottleFn } from '@vueuse/core';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus';
|
import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '@/router/menus';
|
||||||
import { usePermissionStore } from '/@/store/modules/permission';
|
import { usePermissionStore } from '@/store/modules/permission';
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
import { useAppInject } from '@/hooks/web/useAppInject';
|
||||||
|
|
||||||
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
||||||
// Menu array
|
// Menu array
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { defineComponent, computed, unref } from 'vue';
|
import { defineComponent, computed, unref } from 'vue';
|
||||||
import { BasicDrawer } from '/@/components/Drawer/index';
|
import { BasicDrawer } from '@/components/Drawer';
|
||||||
import { Divider } from 'ant-design-vue';
|
import { Divider } from 'ant-design-vue';
|
||||||
import {
|
import {
|
||||||
TypePicker,
|
TypePicker,
|
||||||
@ -10,16 +10,16 @@ import {
|
|||||||
InputNumberItem,
|
InputNumberItem,
|
||||||
} from './components';
|
} from './components';
|
||||||
|
|
||||||
import { AppDarkModeToggle } from '/@/components/Application';
|
import { AppDarkModeToggle } from '@/components/Application';
|
||||||
|
|
||||||
import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
|
import { MenuTypeEnum, TriggerEnum } from '@/enums/menuEnum';
|
||||||
|
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
import { useTransitionSetting } from '@/hooks/setting/useTransitionSetting';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
|
|
||||||
import { baseHandler } from './handler';
|
import { baseHandler } from './handler';
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ import {
|
|||||||
topMenuAlignOptions,
|
topMenuAlignOptions,
|
||||||
getMenuTriggerOptions,
|
getMenuTriggerOptions,
|
||||||
routerTransitionOptions,
|
routerTransitionOptions,
|
||||||
menuTypeList,
|
menuTypeListEnum,
|
||||||
mixSidebarTriggerOptions,
|
mixSidebarTriggerOptions,
|
||||||
} from './enum';
|
} from './enum';
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ import {
|
|||||||
// HEADER_PRESET_BG_COLOR_LIST,
|
// HEADER_PRESET_BG_COLOR_LIST,
|
||||||
// SIDE_BAR_BG_COLOR_LIST,
|
// SIDE_BAR_BG_COLOR_LIST,
|
||||||
// APP_PRESET_COLOR_LIST,
|
// APP_PRESET_COLOR_LIST,
|
||||||
// } from '/@/settings/designSetting';
|
// } from '@/settings/designSetting';
|
||||||
import { SIDE_BAR_BG_COLOR_LIST } from '/@/settings/designSetting';
|
import { SIDE_BAR_BG_COLOR_LIST } from '@/settings/designSetting';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@ -101,8 +101,8 @@ export default defineComponent({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TypePicker
|
<TypePicker
|
||||||
menuTypeList={menuTypeList}
|
menuTypeList={menuTypeListEnum}
|
||||||
handler={(item: (typeof menuTypeList)[0]) => {
|
handler={(item: (typeof menuTypeListEnum)[0]) => {
|
||||||
baseHandler(HandlerEnum.CHANGE_LAYOUT, {
|
baseHandler(HandlerEnum.CHANGE_LAYOUT, {
|
||||||
mode: item.mode,
|
mode: item.mode,
|
||||||
type: item.type,
|
type: item.type,
|
||||||
|
@ -9,37 +9,30 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
import { InputNumber } from 'ant-design-vue';
|
import { InputNumber } from 'ant-design-vue';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { baseHandler } from '../handler';
|
import { baseHandler } from '../handler';
|
||||||
import { HandlerEnum } from '../enum';
|
import { HandlerEnum } from '../enum';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'InputNumberItem' });
|
||||||
name: 'InputNumberItem',
|
|
||||||
components: { InputNumber },
|
|
||||||
props: {
|
|
||||||
event: {
|
|
||||||
type: Number as PropType<HandlerEnum>,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { prefixCls } = useDesign('setting-input-number-item');
|
|
||||||
|
|
||||||
function handleChange(e) {
|
const props = defineProps({
|
||||||
props.event && baseHandler(props.event, e);
|
event: {
|
||||||
}
|
type: Number as PropType<HandlerEnum>,
|
||||||
return {
|
},
|
||||||
prefixCls,
|
title: {
|
||||||
handleChange,
|
type: String,
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('setting-input-number-item');
|
||||||
|
|
||||||
|
function handleChange(e) {
|
||||||
|
props.event && baseHandler(props.event, e);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-setting-input-number-item';
|
@prefix-cls: ~'@{namespace}-setting-input-number-item';
|
||||||
|
@ -11,55 +11,46 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, PropType, computed } from 'vue';
|
import { PropType, computed } from 'vue';
|
||||||
|
|
||||||
import { Select, type SelectProps } from 'ant-design-vue';
|
import { Select, type SelectProps } from 'ant-design-vue';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { baseHandler } from '../handler';
|
import { baseHandler } from '../handler';
|
||||||
import { HandlerEnum } from '../enum';
|
import { HandlerEnum } from '../enum';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SelectItem' });
|
||||||
name: 'SelectItem',
|
|
||||||
components: { Select },
|
const props = defineProps({
|
||||||
props: {
|
event: {
|
||||||
event: {
|
type: Number as PropType<HandlerEnum>,
|
||||||
type: Number as PropType<HandlerEnum>,
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
def: {
|
|
||||||
type: [String, Number] as PropType<string | number>,
|
|
||||||
},
|
|
||||||
initValue: {
|
|
||||||
type: [String, Number] as PropType<string | number>,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Array as PropType<LabelValueOptions>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
setup(props) {
|
disabled: {
|
||||||
const { prefixCls } = useDesign('setting-select-item');
|
type: Boolean,
|
||||||
const getBindValue = computed(() => {
|
},
|
||||||
return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
|
title: {
|
||||||
});
|
type: String,
|
||||||
|
},
|
||||||
const handleChange: SelectProps['onChange'] = (val) => {
|
def: {
|
||||||
props.event && baseHandler(props.event, val);
|
type: [String, Number] as PropType<string | number>,
|
||||||
};
|
},
|
||||||
|
initValue: {
|
||||||
return {
|
type: [String, Number] as PropType<string | number>,
|
||||||
prefixCls,
|
},
|
||||||
handleChange,
|
options: {
|
||||||
getBindValue,
|
type: Array as PropType<LabelValueOptions>,
|
||||||
};
|
default: () => [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('setting-select-item');
|
||||||
|
const getBindValue = computed(() => {
|
||||||
|
return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange: SelectProps['onChange'] = (val) => {
|
||||||
|
props.event && baseHandler(props.event, val);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-setting-select-item';
|
@prefix-cls: ~'@{namespace}-setting-select-item';
|
||||||
|
@ -16,75 +16,64 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
|
|
||||||
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
|
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { useAppStore } from '/@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { usePermissionStore } from '/@/store/modules/permission';
|
import { usePermissionStore } from '@/store/modules/permission';
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
import { useUserStore } from '/@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '@/hooks/web/useMessage';
|
||||||
import { copyText } from '/@/utils/copyTextToClipboard';
|
import { copyText } from '@/utils/copyTextToClipboard';
|
||||||
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
|
import { updateColorWeak } from '@/logics/theme/updateColorWeak';
|
||||||
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
|
import { updateGrayMode } from '@/logics/theme/updateGrayMode';
|
||||||
import defaultSetting from '/@/settings/projectSetting';
|
import defaultSetting from '@/settings/projectSetting';
|
||||||
import { updateSidebarBgColor } from '/@/logics/theme/updateBackground';
|
import { updateSidebarBgColor } from '@/logics/theme/updateBackground';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SettingFooter' });
|
||||||
name: 'SettingFooter',
|
|
||||||
components: { CopyOutlined, RedoOutlined },
|
|
||||||
setup() {
|
|
||||||
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 permissionStore = usePermissionStore();
|
||||||
copyText(JSON.stringify(unref(appStore.getProjectConfig), null, 2), null);
|
const { prefixCls } = useDesign('setting-footer');
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { createSuccessModal, createMessage } = useMessage();
|
||||||
|
const tabStore = useMultipleTabStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
createSuccessModal({
|
function handleCopy() {
|
||||||
title: t('layout.setting.operatingTitle'),
|
copyText(JSON.stringify(unref(appStore.getProjectConfig), null, 2), null);
|
||||||
content: t('layout.setting.operatingContent'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function handleResetSetting() {
|
|
||||||
try {
|
|
||||||
appStore.setProjectConfig(defaultSetting);
|
|
||||||
const { colorWeak, grayMode } = defaultSetting;
|
|
||||||
updateSidebarBgColor();
|
|
||||||
updateColorWeak(colorWeak);
|
|
||||||
updateGrayMode(grayMode);
|
|
||||||
createMessage.success(t('layout.setting.resetSuccess'));
|
|
||||||
} catch (error: any) {
|
|
||||||
createMessage.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClearAndRedo() {
|
createSuccessModal({
|
||||||
localStorage.clear();
|
title: t('layout.setting.operatingTitle'),
|
||||||
appStore.resetAllState();
|
content: t('layout.setting.operatingContent'),
|
||||||
permissionStore.resetState();
|
});
|
||||||
tabStore.resetState();
|
}
|
||||||
userStore.resetState();
|
function handleResetSetting() {
|
||||||
location.reload();
|
try {
|
||||||
}
|
appStore.setProjectConfig(defaultSetting);
|
||||||
return {
|
const { colorWeak, grayMode } = defaultSetting;
|
||||||
prefixCls,
|
updateSidebarBgColor();
|
||||||
t,
|
updateColorWeak(colorWeak);
|
||||||
handleCopy,
|
updateGrayMode(grayMode);
|
||||||
handleResetSetting,
|
createMessage.success(t('layout.setting.resetSuccess'));
|
||||||
handleClearAndRedo,
|
} catch (error: any) {
|
||||||
};
|
createMessage.error(error);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function handleClearAndRedo() {
|
||||||
|
localStorage.clear();
|
||||||
|
appStore.resetAllState();
|
||||||
|
permissionStore.resetState();
|
||||||
|
tabStore.resetState();
|
||||||
|
userStore.resetState();
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-setting-footer';
|
@prefix-cls: ~'@{namespace}-setting-footer';
|
||||||
|
@ -10,52 +10,42 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, PropType, computed } from 'vue';
|
import { PropType, computed } from 'vue';
|
||||||
|
|
||||||
import { Switch, type SwitchProps } from 'ant-design-vue';
|
import { Switch, type SwitchProps } from 'ant-design-vue';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { baseHandler } from '../handler';
|
import { baseHandler } from '../handler';
|
||||||
import { HandlerEnum } from '../enum';
|
import { HandlerEnum } from '../enum';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SwitchItem' });
|
||||||
name: 'SwitchItem',
|
|
||||||
components: { Switch },
|
const props = defineProps({
|
||||||
props: {
|
event: {
|
||||||
event: {
|
type: Number as PropType<HandlerEnum>,
|
||||||
type: Number as PropType<HandlerEnum>,
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
def: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
setup(props) {
|
disabled: {
|
||||||
const { prefixCls } = useDesign('setting-switch-item');
|
type: Boolean,
|
||||||
const { t } = useI18n();
|
},
|
||||||
|
title: {
|
||||||
const getBindValue = computed(() => {
|
type: String,
|
||||||
return props.def ? { checked: props.def } : {};
|
},
|
||||||
});
|
def: {
|
||||||
|
type: Boolean,
|
||||||
const handleChange: SwitchProps['onChange'] = (val) => {
|
|
||||||
props.event && baseHandler(props.event, val);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
prefixCls,
|
|
||||||
t,
|
|
||||||
handleChange,
|
|
||||||
getBindValue,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('setting-switch-item');
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const getBindValue = computed(() => {
|
||||||
|
return props.def ? { checked: props.def } : {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange: SwitchProps['onChange'] = (val) => {
|
||||||
|
props.event && baseHandler(props.event, val);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-setting-switch-item';
|
@prefix-cls: ~'@{namespace}-setting-switch-item';
|
||||||
|
@ -16,42 +16,35 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { CheckOutlined } from '@ant-design/icons-vue';
|
import { CheckOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
|
||||||
import { baseHandler } from '../handler';
|
import { baseHandler } from '../handler';
|
||||||
import { HandlerEnum } from '../enum';
|
import { HandlerEnum } from '../enum';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'ThemeColorPicker' });
|
||||||
name: 'ThemeColorPicker',
|
|
||||||
components: { CheckOutlined },
|
|
||||||
props: {
|
|
||||||
colorList: {
|
|
||||||
type: Array as PropType<string[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
type: Number as PropType<HandlerEnum>,
|
|
||||||
},
|
|
||||||
def: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { prefixCls } = useDesign('setting-theme-picker');
|
|
||||||
|
|
||||||
function handleClick(color: string) {
|
const props = defineProps({
|
||||||
props.event && baseHandler(props.event, color);
|
colorList: {
|
||||||
}
|
type: Array as PropType<string[]>,
|
||||||
return {
|
default: () => [],
|
||||||
prefixCls,
|
},
|
||||||
handleClick,
|
event: {
|
||||||
};
|
type: Number as PropType<HandlerEnum>,
|
||||||
|
},
|
||||||
|
def: {
|
||||||
|
type: String,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('setting-theme-picker');
|
||||||
|
|
||||||
|
function handleClick(color: string) {
|
||||||
|
props.event && baseHandler(props.event, color);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-setting-theme-picker';
|
@prefix-cls: ~'@{namespace}-setting-theme-picker';
|
||||||
|
@ -18,39 +18,32 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
|
|
||||||
import { Tooltip } from 'ant-design-vue';
|
import { Tooltip } from 'ant-design-vue';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
|
||||||
import { menuTypeList } from '../enum';
|
import { menuTypeListEnum } from '../enum';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'MenuTypePicker' });
|
||||||
name: 'MenuTypePicker',
|
|
||||||
components: { Tooltip },
|
defineProps({
|
||||||
props: {
|
menuTypeList: {
|
||||||
menuTypeList: {
|
type: Array as PropType<typeof menuTypeListEnum>,
|
||||||
type: Array as PropType<typeof menuTypeList>,
|
default: () => [],
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
handler: {
|
|
||||||
type: Function,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
def: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
setup() {
|
handler: {
|
||||||
const { prefixCls } = useDesign('setting-menu-type-picker');
|
type: Function,
|
||||||
|
default: () => ({}),
|
||||||
return {
|
},
|
||||||
prefixCls,
|
def: {
|
||||||
};
|
type: String,
|
||||||
|
default: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('setting-menu-type-picker');
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@prefix-cls: ~'@{namespace}-setting-menu-type-picker';
|
@prefix-cls: ~'@{namespace}-setting-menu-type-picker';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
|
||||||
|
|
||||||
export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue'));
|
export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue'));
|
||||||
export const ThemeColorPicker = createAsyncComponent(() => import('./ThemeColorPicker.vue'));
|
export const ThemeColorPicker = createAsyncComponent(() => import('./ThemeColorPicker.vue'));
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum';
|
import { ContentEnum, RouterTransitionEnum } from '@/enums/appEnum';
|
||||||
import {
|
import {
|
||||||
MenuModeEnum,
|
MenuModeEnum,
|
||||||
MenuTypeEnum,
|
MenuTypeEnum,
|
||||||
TopMenuAlignEnum,
|
TopMenuAlignEnum,
|
||||||
TriggerEnum,
|
TriggerEnum,
|
||||||
MixSidebarTriggerEnum,
|
MixSidebarTriggerEnum,
|
||||||
} from '/@/enums/menuEnum';
|
} from '@/enums/menuEnum';
|
||||||
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ export const routerTransitionOptions = [
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const menuTypeList = [
|
export const menuTypeListEnum = [
|
||||||
{
|
{
|
||||||
title: t('layout.setting.menuTypeSidebar'),
|
title: t('layout.setting.menuTypeSidebar'),
|
||||||
mode: MenuModeEnum.INLINE,
|
mode: MenuModeEnum.INLINE,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { HandlerEnum } from './enum';
|
import { HandlerEnum } from './enum';
|
||||||
import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
|
import { updateHeaderBgColor, updateSidebarBgColor } from '@/logics/theme/updateBackground';
|
||||||
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
|
import { updateColorWeak } from '@/logics/theme/updateColorWeak';
|
||||||
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
|
import { updateGrayMode } from '@/logics/theme/updateGrayMode';
|
||||||
|
|
||||||
import { useAppStore } from '/@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { ProjectConfig } from '/#/config';
|
import { ProjectConfig } from '/#/config';
|
||||||
import { updateDarkTheme } from '/@/logics/theme/dark';
|
import { updateDarkTheme } from '@/logics/theme/dark';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
|
|
||||||
export function baseHandler(event: HandlerEnum, value: any) {
|
export function baseHandler(event: HandlerEnum, value: any) {
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
@ -4,23 +4,13 @@
|
|||||||
<SettingDrawer @register="register" />
|
<SettingDrawer @register="register" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import SettingDrawer from './SettingDrawer';
|
import SettingDrawer from './SettingDrawer';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
|
|
||||||
import { useDrawer } from '/@/components/Drawer';
|
import { useDrawer } from '@/components/Drawer';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SettingButton' });
|
||||||
name: 'SettingButton',
|
|
||||||
components: { SettingDrawer, Icon },
|
|
||||||
setup() {
|
|
||||||
const [register, { openDrawer }] = useDrawer();
|
|
||||||
|
|
||||||
return {
|
const [register, { openDrawer }] = useDrawer();
|
||||||
register,
|
|
||||||
openDrawer,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,43 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="getClass" :style="getDragBarStyle"></div>
|
<div :class="getClass" :style="getDragBarStyle"></div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, computed, unref } from 'vue';
|
import { computed, unref } from 'vue';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'DargBar' });
|
||||||
name: 'DargBar',
|
|
||||||
props: {
|
|
||||||
mobile: Boolean,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { getMiniWidthNumber, getCollapsed, getCanDrag } = useMenuSetting();
|
|
||||||
|
|
||||||
const { prefixCls } = useDesign('darg-bar');
|
const props = defineProps({
|
||||||
const getDragBarStyle = computed(() => {
|
mobile: Boolean,
|
||||||
if (unref(getCollapsed)) {
|
});
|
||||||
return { left: `${unref(getMiniWidthNumber)}px` };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getClass = computed(() => {
|
const { getMiniWidthNumber, getCollapsed, getCanDrag } = useMenuSetting();
|
||||||
return [
|
|
||||||
prefixCls,
|
|
||||||
{
|
|
||||||
[`${prefixCls}--hide`]: !unref(getCanDrag) || props.mobile,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
const { prefixCls } = useDesign('darg-bar');
|
||||||
prefixCls,
|
const getDragBarStyle = computed(() => {
|
||||||
getDragBarStyle,
|
if (unref(getCollapsed)) {
|
||||||
getClass,
|
return { left: `${unref(getMiniWidthNumber)}px` };
|
||||||
};
|
}
|
||||||
},
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getClass = computed(() => {
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
{
|
||||||
|
[`${prefixCls}--hide`]: !unref(getCanDrag) || props.mobile,
|
||||||
|
},
|
||||||
|
];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -83,273 +83,236 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { Menu } from '/@/router/types';
|
import type { Menu } from '@/router/types';
|
||||||
import type { CSSProperties } from 'vue';
|
import type { CSSProperties } from 'vue';
|
||||||
import { computed, defineComponent, onMounted, ref, unref, watch } from 'vue';
|
import { computed, onMounted, ref, unref, watch } from 'vue';
|
||||||
import type { RouteLocationNormalized } from 'vue-router';
|
import type { RouteLocationNormalized } from 'vue-router';
|
||||||
import { ScrollContainer } from '/@/components/Container';
|
import { ScrollContainer } from '@/components/Container';
|
||||||
import { SimpleMenu } from '/@/components/SimpleMenu';
|
import { SimpleMenu } from '@/components/SimpleMenu';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
import { AppLogo } from '/@/components/Application';
|
import { AppLogo } from '@/components/Application';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { usePermissionStore } from '/@/store/modules/permission';
|
import { usePermissionStore } from '@/store/modules/permission';
|
||||||
import { useDragLine } from './useLayoutSider';
|
import { useDragLine } from './useLayoutSider';
|
||||||
import { useGlobSetting } from '/@/hooks/setting';
|
import { useGlobSetting } from '@/hooks/setting';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useGo } from '/@/hooks/web/usePage';
|
import { useGo } from '@/hooks/web/usePage';
|
||||||
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
|
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '@/enums/appEnum';
|
||||||
import clickOutside from '/@/directives/clickOutside';
|
import vClickOutside from '@/directives/clickOutside';
|
||||||
import { getChildrenMenus, getCurrentParentPath, getShallowMenus } from '/@/router/menus';
|
import { getChildrenMenus, getCurrentParentPath, getShallowMenus } from '@/router/menus';
|
||||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
import { listenerRouteChange } from '@/logics/mitt/routeChange';
|
||||||
import LayoutTrigger from '../trigger/index.vue';
|
import LayoutTrigger from '../trigger/index.vue';
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
|
||||||
|
|
||||||
export default defineComponent({
|
const SimpleMenuTag = createAsyncComponent(
|
||||||
name: 'LayoutMixSider',
|
() => import('@/components/SimpleMenu/src/SimpleMenuTag.vue'),
|
||||||
components: {
|
);
|
||||||
ScrollContainer,
|
|
||||||
AppLogo,
|
|
||||||
SimpleMenu,
|
|
||||||
Icon,
|
|
||||||
LayoutTrigger,
|
|
||||||
SimpleMenuTag: createAsyncComponent(
|
|
||||||
() => import('/@/components/SimpleMenu/src/SimpleMenuTag.vue'),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
directives: {
|
|
||||||
clickOutside,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
let menuModules = ref<Menu[]>([]);
|
|
||||||
const activePath = ref('');
|
|
||||||
const childrenMenus = ref<Menu[]>([]);
|
|
||||||
const openMenu = ref(false);
|
|
||||||
const dragBarRef = ref(null);
|
|
||||||
const sideRef = ref(null);
|
|
||||||
const currentRoute = ref<RouteLocationNormalized | null>(null);
|
|
||||||
|
|
||||||
const { prefixCls } = useDesign('layout-mix-sider');
|
defineOptions({ name: 'LayoutMixSider' });
|
||||||
const go = useGo();
|
|
||||||
const { t } = useI18n();
|
|
||||||
const {
|
|
||||||
getMenuWidth,
|
|
||||||
getCanDrag,
|
|
||||||
getCloseMixSidebarOnChange,
|
|
||||||
getMenuTheme,
|
|
||||||
getMixSideTrigger,
|
|
||||||
getRealWidth,
|
|
||||||
getMixSideFixed,
|
|
||||||
mixSideHasChildren,
|
|
||||||
setMenuSetting,
|
|
||||||
getIsMixSidebar,
|
|
||||||
getCollapsed,
|
|
||||||
} = useMenuSetting();
|
|
||||||
|
|
||||||
const { title } = useGlobSetting();
|
let menuModules = ref<Menu[]>([]);
|
||||||
const permissionStore = usePermissionStore();
|
const activePath = ref('');
|
||||||
|
const childrenMenus = ref<Menu[]>([]);
|
||||||
|
const openMenu = ref(false);
|
||||||
|
const dragBarRef = ref(null);
|
||||||
|
const sideRef = ref(null);
|
||||||
|
const currentRoute = ref<RouteLocationNormalized | null>(null);
|
||||||
|
|
||||||
useDragLine(sideRef, dragBarRef, true);
|
const { prefixCls } = useDesign('layout-mix-sider');
|
||||||
|
const go = useGo();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const {
|
||||||
|
getMenuWidth,
|
||||||
|
getCanDrag,
|
||||||
|
getCloseMixSidebarOnChange,
|
||||||
|
getMenuTheme,
|
||||||
|
getMixSideTrigger,
|
||||||
|
getRealWidth,
|
||||||
|
getMixSideFixed,
|
||||||
|
mixSideHasChildren,
|
||||||
|
setMenuSetting,
|
||||||
|
getIsMixSidebar,
|
||||||
|
getCollapsed,
|
||||||
|
} = useMenuSetting();
|
||||||
|
|
||||||
const getMenuStyle = computed((): CSSProperties => {
|
const { title } = useGlobSetting();
|
||||||
return {
|
const permissionStore = usePermissionStore();
|
||||||
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
|
|
||||||
left: `${unref(getMixSideWidth)}px`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getIsFixed = computed(() => {
|
useDragLine(sideRef, dragBarRef, true);
|
||||||
/* eslint-disable-next-line */
|
|
||||||
mixSideHasChildren.value = unref(childrenMenus).length > 0;
|
|
||||||
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
|
|
||||||
if (isFixed) {
|
|
||||||
/* eslint-disable-next-line */
|
|
||||||
openMenu.value = true;
|
|
||||||
}
|
|
||||||
return isFixed;
|
|
||||||
});
|
|
||||||
|
|
||||||
const getMixSideWidth = computed(() => {
|
const getMenuStyle = computed((): CSSProperties => {
|
||||||
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH;
|
return {
|
||||||
});
|
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
|
||||||
|
left: `${unref(getMixSideWidth)}px`,
|
||||||
const getDomStyle = computed((): CSSProperties => {
|
};
|
||||||
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
|
|
||||||
const width = `${unref(getMixSideWidth) + fixedWidth}px`;
|
|
||||||
return getWrapCommonStyle(width);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getWrapStyle = computed((): CSSProperties => {
|
|
||||||
const width = `${unref(getMixSideWidth)}px`;
|
|
||||||
return getWrapCommonStyle(width);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getMenuEvents = computed(() => {
|
|
||||||
return !unref(getMixSideFixed)
|
|
||||||
? {
|
|
||||||
onMouseleave: () => {
|
|
||||||
setActive(true);
|
|
||||||
closeMenu();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getShowDragBar = computed(() => unref(getCanDrag));
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
menuModules.value = await getShallowMenus();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Menu changes
|
|
||||||
watch(
|
|
||||||
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
|
|
||||||
async () => {
|
|
||||||
menuModules.value = await getShallowMenus();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
listenerRouteChange((route) => {
|
|
||||||
currentRoute.value = route;
|
|
||||||
setActive(true);
|
|
||||||
if (unref(getCloseMixSidebarOnChange)) {
|
|
||||||
closeMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function getWrapCommonStyle(width: string): CSSProperties {
|
|
||||||
return {
|
|
||||||
width,
|
|
||||||
maxWidth: width,
|
|
||||||
minWidth: width,
|
|
||||||
flex: `0 0 ${width}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process module menu click
|
|
||||||
async function handleModuleClick(path: string, hover = false) {
|
|
||||||
const children = await getChildrenMenus(path);
|
|
||||||
if (unref(activePath) === path) {
|
|
||||||
if (!hover) {
|
|
||||||
if (!unref(openMenu)) {
|
|
||||||
openMenu.value = true;
|
|
||||||
} else {
|
|
||||||
closeMenu();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!unref(openMenu)) {
|
|
||||||
openMenu.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!unref(openMenu)) {
|
|
||||||
setActive();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
openMenu.value = true;
|
|
||||||
activePath.value = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!children || children.length === 0) {
|
|
||||||
if (!hover) go(path);
|
|
||||||
childrenMenus.value = [];
|
|
||||||
closeMenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
childrenMenus.value = children;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the currently active menu and submenu
|
|
||||||
async function setActive(setChildren = false) {
|
|
||||||
const path = currentRoute.value?.path;
|
|
||||||
if (!path) return;
|
|
||||||
activePath.value = await getCurrentParentPath(path);
|
|
||||||
// hanldeModuleClick(parentPath);
|
|
||||||
if (unref(getIsMixSidebar)) {
|
|
||||||
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
|
|
||||||
const p = activeMenu?.path;
|
|
||||||
if (p) {
|
|
||||||
const children = await getChildrenMenus(p);
|
|
||||||
if (setChildren) {
|
|
||||||
childrenMenus.value = children;
|
|
||||||
|
|
||||||
if (unref(getMixSideFixed)) {
|
|
||||||
openMenu.value = children.length > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (children.length === 0) {
|
|
||||||
childrenMenus.value = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMenuClick(path: string) {
|
|
||||||
go(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClickOutside() {
|
|
||||||
setActive(true);
|
|
||||||
closeMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getItemEvents(item: Menu) {
|
|
||||||
if (unref(getMixSideTrigger) === 'hover') {
|
|
||||||
return {
|
|
||||||
onMouseenter: () => handleModuleClick(item.path, true),
|
|
||||||
onClick: async () => {
|
|
||||||
const children = await getChildrenMenus(item.path);
|
|
||||||
if (item.path && (!children || children.length === 0)) go(item.path);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
onClick: () => handleModuleClick(item.path),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFixedMenu() {
|
|
||||||
setMenuSetting({
|
|
||||||
mixSideFixed: !unref(getIsFixed),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close menu
|
|
||||||
function closeMenu() {
|
|
||||||
if (!unref(getIsFixed)) {
|
|
||||||
openMenu.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
t,
|
|
||||||
prefixCls,
|
|
||||||
menuModules,
|
|
||||||
handleModuleClick: handleModuleClick,
|
|
||||||
activePath,
|
|
||||||
childrenMenus: childrenMenus,
|
|
||||||
getShowDragBar,
|
|
||||||
handleMenuClick,
|
|
||||||
getMenuStyle,
|
|
||||||
handleClickOutside,
|
|
||||||
sideRef,
|
|
||||||
dragBarRef,
|
|
||||||
title,
|
|
||||||
openMenu,
|
|
||||||
getMenuTheme,
|
|
||||||
getItemEvents,
|
|
||||||
getMenuEvents,
|
|
||||||
getDomStyle,
|
|
||||||
handleFixedMenu,
|
|
||||||
getMixSideFixed,
|
|
||||||
getWrapStyle,
|
|
||||||
getCollapsed,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getIsFixed = computed(() => {
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
mixSideHasChildren.value = unref(childrenMenus).length > 0;
|
||||||
|
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
|
||||||
|
if (isFixed) {
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
openMenu.value = true;
|
||||||
|
}
|
||||||
|
return isFixed;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMixSideWidth = computed(() => {
|
||||||
|
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getDomStyle = computed((): CSSProperties => {
|
||||||
|
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
|
||||||
|
const width = `${unref(getMixSideWidth) + fixedWidth}px`;
|
||||||
|
return getWrapCommonStyle(width);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getWrapStyle = computed((): CSSProperties => {
|
||||||
|
const width = `${unref(getMixSideWidth)}px`;
|
||||||
|
return getWrapCommonStyle(width);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMenuEvents = computed(() => {
|
||||||
|
return !unref(getMixSideFixed)
|
||||||
|
? {
|
||||||
|
onMouseleave: () => {
|
||||||
|
setActive(true);
|
||||||
|
closeMenu();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getShowDragBar = computed(() => unref(getCanDrag));
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
menuModules.value = await getShallowMenus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Menu changes
|
||||||
|
watch(
|
||||||
|
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
|
||||||
|
async () => {
|
||||||
|
menuModules.value = await getShallowMenus();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
listenerRouteChange((route) => {
|
||||||
|
currentRoute.value = route;
|
||||||
|
setActive(true);
|
||||||
|
if (unref(getCloseMixSidebarOnChange)) {
|
||||||
|
closeMenu();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function getWrapCommonStyle(width: string): CSSProperties {
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
maxWidth: width,
|
||||||
|
minWidth: width,
|
||||||
|
flex: `0 0 ${width}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process module menu click
|
||||||
|
async function handleModuleClick(path: string, hover = false) {
|
||||||
|
const children = await getChildrenMenus(path);
|
||||||
|
if (unref(activePath) === path) {
|
||||||
|
if (!hover) {
|
||||||
|
if (!unref(openMenu)) {
|
||||||
|
openMenu.value = true;
|
||||||
|
} else {
|
||||||
|
closeMenu();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!unref(openMenu)) {
|
||||||
|
openMenu.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!unref(openMenu)) {
|
||||||
|
setActive();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
openMenu.value = true;
|
||||||
|
activePath.value = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!children || children.length === 0) {
|
||||||
|
if (!hover) go(path);
|
||||||
|
childrenMenus.value = [];
|
||||||
|
closeMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
childrenMenus.value = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the currently active menu and submenu
|
||||||
|
async function setActive(setChildren = false) {
|
||||||
|
const path = currentRoute.value?.path;
|
||||||
|
if (!path) return;
|
||||||
|
activePath.value = await getCurrentParentPath(path);
|
||||||
|
// hanldeModuleClick(parentPath);
|
||||||
|
if (unref(getIsMixSidebar)) {
|
||||||
|
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
|
||||||
|
const p = activeMenu?.path;
|
||||||
|
if (p) {
|
||||||
|
const children = await getChildrenMenus(p);
|
||||||
|
if (setChildren) {
|
||||||
|
childrenMenus.value = children;
|
||||||
|
|
||||||
|
if (unref(getMixSideFixed)) {
|
||||||
|
openMenu.value = children.length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (children.length === 0) {
|
||||||
|
childrenMenus.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMenuClick(path: string) {
|
||||||
|
go(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClickOutside() {
|
||||||
|
setActive(true);
|
||||||
|
closeMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItemEvents(item: Menu) {
|
||||||
|
if (unref(getMixSideTrigger) === 'hover') {
|
||||||
|
return {
|
||||||
|
onMouseenter: () => handleModuleClick(item.path, true),
|
||||||
|
onClick: async () => {
|
||||||
|
const children = await getChildrenMenus(item.path);
|
||||||
|
if (item.path && (!children || children.length === 0)) go(item.path);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
onClick: () => handleModuleClick(item.path),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFixedMenu() {
|
||||||
|
setMenuSetting({
|
||||||
|
mixSideFixed: !unref(getIsFixed),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close menu
|
||||||
|
function closeMenu() {
|
||||||
|
if (!unref(getIsFixed)) {
|
||||||
|
openMenu.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-layout-mix-sider';
|
@prefix-cls: ~'@{namespace}-layout-mix-sider';
|
||||||
|
@ -14,34 +14,26 @@
|
|||||||
<Sider v-else />
|
<Sider v-else />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
import Sider from './LayoutSider.vue';
|
import Sider from './LayoutSider.vue';
|
||||||
import MixSider from './MixSider.vue';
|
import MixSider from './MixSider.vue';
|
||||||
import { Drawer } from 'ant-design-vue';
|
import { Drawer } from 'ant-design-vue';
|
||||||
|
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
import { useAppInject } from '@/hooks/web/useAppInject';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SiderWrapper' });
|
||||||
name: 'SiderWrapper',
|
|
||||||
components: { Sider, Drawer, MixSider },
|
|
||||||
setup() {
|
|
||||||
const { prefixCls } = useDesign('layout-sider-wrapper');
|
|
||||||
const { getIsMobile } = useAppInject();
|
|
||||||
const { setMenuSetting, getCollapsed, getMenuWidth, getIsMixSidebar } = useMenuSetting();
|
|
||||||
|
|
||||||
function handleClose() {
|
const { prefixCls } = useDesign('layout-sider-wrapper');
|
||||||
setMenuSetting({
|
const { getIsMobile } = useAppInject();
|
||||||
collapsed: true,
|
const { setMenuSetting, getCollapsed, getMenuWidth, getIsMixSidebar } = useMenuSetting();
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return { prefixCls, getIsMobile, getCollapsed, handleClose, getMenuWidth, getIsMixSidebar };
|
function handleClose() {
|
||||||
},
|
setMenuSetting({
|
||||||
});
|
collapsed: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-layout-sider-wrapper';
|
@prefix-cls: ~'@{namespace}-layout-sider-wrapper';
|
||||||
|
@ -2,11 +2,11 @@ import type { Ref } from 'vue';
|
|||||||
|
|
||||||
import { computed, unref, onMounted, nextTick } from 'vue';
|
import { computed, unref, onMounted, nextTick } from 'vue';
|
||||||
|
|
||||||
import { TriggerEnum } from '/@/enums/menuEnum';
|
import { TriggerEnum } from '@/enums/menuEnum';
|
||||||
|
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
import { useAppStore } from '/@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle related operations of menu events
|
* Handle related operations of menu events
|
||||||
|
@ -3,40 +3,34 @@
|
|||||||
<Icon :icon="getIcon" />
|
<Icon :icon="getIcon" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, unref, computed } from 'vue';
|
import { unref, computed } from 'vue';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { triggerWindowResize } from '/@/utils/event';
|
import { triggerWindowResize } from '@/utils/event';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'FoldButton' });
|
||||||
name: 'FoldButton',
|
|
||||||
components: { Icon },
|
|
||||||
setup() {
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
|
||||||
const { getShowMenu, setMenuSetting } = useMenuSetting();
|
|
||||||
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
|
|
||||||
|
|
||||||
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||||
|
const { getShowMenu, setMenuSetting } = useMenuSetting();
|
||||||
|
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
|
||||||
|
|
||||||
const getIcon = computed(() =>
|
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
||||||
unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full',
|
|
||||||
);
|
|
||||||
|
|
||||||
function handleFold() {
|
const getIcon = computed(() =>
|
||||||
const isUnFold = unref(getIsUnFold);
|
unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full',
|
||||||
setMenuSetting({
|
);
|
||||||
show: isUnFold,
|
|
||||||
hidden: !isUnFold,
|
|
||||||
});
|
|
||||||
setHeaderSetting({ show: isUnFold });
|
|
||||||
triggerWindowResize();
|
|
||||||
}
|
|
||||||
|
|
||||||
return { prefixCls, getIcon, handleFold };
|
function handleFold() {
|
||||||
},
|
const isUnFold = unref(getIsUnFold);
|
||||||
});
|
setMenuSetting({
|
||||||
|
show: isUnFold,
|
||||||
|
hidden: !isUnFold,
|
||||||
|
});
|
||||||
|
setHeaderSetting({ show: isUnFold });
|
||||||
|
triggerWindowResize();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,27 +4,16 @@
|
|||||||
<SettingDrawer @register="register" />
|
<SettingDrawer @register="register" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import SettingDrawer from '@/layouts/default/setting/SettingDrawer';
|
||||||
import SettingDrawer from '/@/layouts/default/setting/SettingDrawer';
|
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
|
|
||||||
import { useDrawer } from '/@/components/Drawer';
|
import { useDrawer } from '@/components/Drawer';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'SettingButton' });
|
||||||
name: 'SettingButton',
|
|
||||||
components: { SettingDrawer, Icon },
|
|
||||||
setup() {
|
|
||||||
const [register, { openDrawer }] = useDrawer();
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
|
||||||
|
|
||||||
return {
|
const [register, { openDrawer }] = useDrawer();
|
||||||
register,
|
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||||
openDrawer,
|
|
||||||
prefixCls,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,63 +14,50 @@
|
|||||||
</span>
|
</span>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import type { RouteLocationNormalized } from 'vue-router';
|
import type { RouteLocationNormalized } from 'vue-router';
|
||||||
|
|
||||||
import { defineComponent, computed, unref } from 'vue';
|
import { computed, unref } from 'vue';
|
||||||
import { Dropdown } from '/@/components/Dropdown/index';
|
import { Dropdown } from '@/components/Dropdown';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
|
|
||||||
import { TabContentProps } from '../types';
|
import { TabContentProps } from '../types';
|
||||||
|
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
import { useTabDropdown } from '../useTabDropdown';
|
import { useTabDropdown } from '../useTabDropdown';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'TabContent' });
|
||||||
name: 'TabContent',
|
|
||||||
components: { Dropdown, Icon },
|
const props = defineProps({
|
||||||
props: {
|
tabItem: {
|
||||||
tabItem: {
|
type: Object as PropType<RouteLocationNormalized>,
|
||||||
type: Object as PropType<RouteLocationNormalized>,
|
default: null,
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
isExtra: Boolean,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const getTitle = computed(() => {
|
|
||||||
const { tabItem: { meta } = {} } = props;
|
|
||||||
return meta && t(meta.title as string);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getIsTabs = computed(() => !props.isExtra);
|
|
||||||
|
|
||||||
const getTrigger = computed((): ('contextmenu' | 'click' | 'hover')[] =>
|
|
||||||
unref(getIsTabs) ? ['contextmenu'] : ['click'],
|
|
||||||
);
|
|
||||||
|
|
||||||
const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(
|
|
||||||
props as TabContentProps,
|
|
||||||
getIsTabs,
|
|
||||||
);
|
|
||||||
|
|
||||||
function handleContext(e) {
|
|
||||||
props.tabItem && handleContextMenu(props.tabItem)(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
prefixCls,
|
|
||||||
getDropMenuList,
|
|
||||||
handleMenuEvent,
|
|
||||||
handleContext,
|
|
||||||
getTrigger,
|
|
||||||
getIsTabs,
|
|
||||||
getTitle,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
isExtra: Boolean,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const getTitle = computed(() => {
|
||||||
|
const { tabItem: { meta } = {} } = props;
|
||||||
|
return meta && t(meta.title as string);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getIsTabs = computed(() => !props.isExtra);
|
||||||
|
|
||||||
|
const getTrigger = computed((): ('contextmenu' | 'click' | 'hover')[] =>
|
||||||
|
unref(getIsTabs) ? ['contextmenu'] : ['click'],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(
|
||||||
|
props as TabContentProps,
|
||||||
|
getIsTabs,
|
||||||
|
);
|
||||||
|
|
||||||
|
function handleContext(e) {
|
||||||
|
props.tabItem && handleContextMenu(props.tabItem)(e);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,33 +3,27 @@
|
|||||||
<RedoOutlined :spin="loading" />
|
<RedoOutlined :spin="loading" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { RedoOutlined } from '@ant-design/icons-vue';
|
import { RedoOutlined } from '@ant-design/icons-vue';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useTabs } from '/@/hooks/web/useTabs';
|
import { useTabs } from '@/hooks/web/useTabs';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'TabRedo' });
|
||||||
name: 'TabRedo',
|
|
||||||
components: { RedoOutlined },
|
|
||||||
|
|
||||||
setup() {
|
const loading = ref(false);
|
||||||
const loading = ref(false);
|
|
||||||
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||||
const { refreshPage } = useTabs();
|
const { refreshPage } = useTabs();
|
||||||
|
|
||||||
async function handleRedo() {
|
async function handleRedo() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await refreshPage();
|
await refreshPage();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
// Animation execution time
|
// Animation execution time
|
||||||
}, 1200);
|
}, 1200);
|
||||||
}
|
}
|
||||||
return { prefixCls, handleRedo, loading };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
span.anticon-redo {
|
span.anticon-redo {
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
@edit="(e) => handleEdit(`${e}`)"
|
@edit="(e) => handleEdit(`${e}`)"
|
||||||
>
|
>
|
||||||
<template v-for="item in getTabsState" :key="item.query ? item.fullPath : item.path">
|
<template v-for="item in getTabsState" :key="item.query ? item.fullPath : item.path">
|
||||||
<TabPane :closable="!(item && item.meta && item.meta.affix)">
|
<Tabs.TabPane :closable="!(item && item.meta && item.meta.affix)">
|
||||||
<template #tab>
|
<template #tab>
|
||||||
<TabContent :tabItem="item" />
|
<TabContent :tabItem="item" />
|
||||||
</template>
|
</template>
|
||||||
</TabPane>
|
</Tabs.TabPane>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #rightExtra v-if="getShowRedo || getShowQuick">
|
<template #rightExtra v-if="getShowRedo || getShowQuick">
|
||||||
@ -27,135 +27,110 @@
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { RouteLocationNormalized, RouteMeta } from 'vue-router';
|
import type { RouteLocationNormalized, RouteMeta } from 'vue-router';
|
||||||
|
|
||||||
import { defineComponent, computed, unref, ref } from 'vue';
|
import { computed, unref, ref } from 'vue';
|
||||||
|
|
||||||
import { Tabs } from 'ant-design-vue';
|
import { Tabs } from 'ant-design-vue';
|
||||||
import TabContent from './components/TabContent.vue';
|
import TabContent from './components/TabContent.vue';
|
||||||
import FoldButton from './components/FoldButton.vue';
|
import FoldButton from './components/FoldButton.vue';
|
||||||
import TabRedo from './components/TabRedo.vue';
|
import TabRedo from './components/TabRedo.vue';
|
||||||
|
|
||||||
import { useGo } from '/@/hooks/web/usePage';
|
import { useGo } from '@/hooks/web/usePage';
|
||||||
|
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
import { useUserStore } from '/@/store/modules/user';
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
|
||||||
import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
|
import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
|
|
||||||
import { REDIRECT_NAME } from '/@/router/constant';
|
import { REDIRECT_NAME } from '@/router/constant';
|
||||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
import { listenerRouteChange } from '@/logics/mitt/routeChange';
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { useMouse } from '@vueuse/core';
|
import { useMouse } from '@vueuse/core';
|
||||||
import { multipleTabHeight } from '/@/settings/designSetting';
|
import { multipleTabHeight } from '@/settings/designSetting';
|
||||||
|
|
||||||
import SettingButton from './components/SettingButton.vue';
|
import SettingButton from './components/SettingButton.vue';
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'MultipleTabs' });
|
||||||
name: 'MultipleTabs',
|
|
||||||
components: {
|
|
||||||
TabRedo,
|
|
||||||
FoldButton,
|
|
||||||
Tabs,
|
|
||||||
TabPane: Tabs.TabPane,
|
|
||||||
TabContent,
|
|
||||||
SettingButton,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const affixTextList = initAffixTabs();
|
|
||||||
const activeKeyRef = ref('');
|
|
||||||
|
|
||||||
useTabsDrag(affixTextList);
|
const affixTextList = initAffixTabs();
|
||||||
const tabStore = useMultipleTabStore();
|
const activeKeyRef = ref('');
|
||||||
const userStore = useUserStore();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs');
|
useTabsDrag(affixTextList);
|
||||||
const go = useGo();
|
const tabStore = useMultipleTabStore();
|
||||||
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
|
const userStore = useUserStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const getTabsState = computed(() => {
|
const { prefixCls } = useDesign('multiple-tabs');
|
||||||
return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
|
const go = useGo();
|
||||||
});
|
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
|
||||||
|
|
||||||
const unClose = computed(() => unref(getTabsState).length === 1);
|
const getTabsState = computed(() => {
|
||||||
|
return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
|
||||||
const { y: mouseY } = useMouse();
|
|
||||||
|
|
||||||
const { getShowMenu } = useMenuSetting();
|
|
||||||
const { getShowHeader } = useHeaderSetting();
|
|
||||||
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
|
||||||
|
|
||||||
const getWrapClass = computed(() => {
|
|
||||||
return [
|
|
||||||
prefixCls,
|
|
||||||
{
|
|
||||||
[`${prefixCls}--hide-close`]: unref(unClose),
|
|
||||||
[`${prefixCls}--hover`]: unref(mouseY) < multipleTabHeight,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
listenerRouteChange((route) => {
|
|
||||||
const { name } = route;
|
|
||||||
if (name === REDIRECT_NAME || !route || !userStore.getToken) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { path, fullPath, meta = {} } = route;
|
|
||||||
const { currentActiveMenu, hideTab } = meta as RouteMeta;
|
|
||||||
const isHide = !hideTab ? null : currentActiveMenu;
|
|
||||||
const p = isHide || fullPath || path;
|
|
||||||
if (activeKeyRef.value !== p) {
|
|
||||||
activeKeyRef.value = p as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isHide) {
|
|
||||||
const findParentRoute = router
|
|
||||||
.getRoutes()
|
|
||||||
.find((item) => item.path === currentActiveMenu);
|
|
||||||
|
|
||||||
findParentRoute && tabStore.addTab(findParentRoute as unknown as RouteLocationNormalized);
|
|
||||||
} else {
|
|
||||||
tabStore.addTab(unref(route));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleChange(activeKey: any) {
|
|
||||||
activeKeyRef.value = activeKey;
|
|
||||||
go(activeKey, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the current tab
|
|
||||||
function handleEdit(targetKey: string) {
|
|
||||||
// Added operation to hide, currently only use delete operation
|
|
||||||
if (unref(unClose)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabStore.closeTabByKey(targetKey, router);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
getWrapClass,
|
|
||||||
handleEdit,
|
|
||||||
handleChange,
|
|
||||||
activeKeyRef,
|
|
||||||
getTabsState,
|
|
||||||
getShowQuick,
|
|
||||||
getShowRedo,
|
|
||||||
getShowFold,
|
|
||||||
getIsUnFold,
|
|
||||||
getShowHeader,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const unClose = computed(() => unref(getTabsState).length === 1);
|
||||||
|
|
||||||
|
const { y: mouseY } = useMouse();
|
||||||
|
|
||||||
|
const { getShowMenu } = useMenuSetting();
|
||||||
|
const { getShowHeader } = useHeaderSetting();
|
||||||
|
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
||||||
|
|
||||||
|
const getWrapClass = computed(() => {
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
{
|
||||||
|
[`${prefixCls}--hide-close`]: unref(unClose),
|
||||||
|
[`${prefixCls}--hover`]: unref(mouseY) < multipleTabHeight,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
listenerRouteChange((route) => {
|
||||||
|
const { name } = route;
|
||||||
|
if (name === REDIRECT_NAME || !route || !userStore.getToken) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { path, fullPath, meta = {} } = route;
|
||||||
|
const { currentActiveMenu, hideTab } = meta as RouteMeta;
|
||||||
|
const isHide = !hideTab ? null : currentActiveMenu;
|
||||||
|
const p = isHide || fullPath || path;
|
||||||
|
if (activeKeyRef.value !== p) {
|
||||||
|
activeKeyRef.value = p as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHide) {
|
||||||
|
const findParentRoute = router.getRoutes().find((item) => item.path === currentActiveMenu);
|
||||||
|
|
||||||
|
findParentRoute && tabStore.addTab(findParentRoute as unknown as RouteLocationNormalized);
|
||||||
|
} else {
|
||||||
|
tabStore.addTab(unref(route));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleChange(activeKey: any) {
|
||||||
|
activeKeyRef.value = activeKey;
|
||||||
|
go(activeKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the current tab
|
||||||
|
function handleEdit(targetKey: string) {
|
||||||
|
// Added operation to hide, currently only use delete operation
|
||||||
|
if (unref(unClose)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabStore.closeTabByKey(targetKey, router);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import url('./index.less');
|
@import url('./index.less');
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { DropMenu } from '/@/components/Dropdown/index';
|
import type { DropMenu } from '@/components/Dropdown';
|
||||||
import type { RouteLocationNormalized } from 'vue-router';
|
import type { RouteLocationNormalized } from 'vue-router';
|
||||||
|
|
||||||
export enum TabContentEnum {
|
export enum TabContentEnum {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { toRaw, ref, nextTick } from 'vue';
|
import { toRaw, ref, nextTick } from 'vue';
|
||||||
import type { RouteLocationNormalized } from 'vue-router';
|
import type { RouteLocationNormalized } from 'vue-router';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { useSortable } from '/@/hooks/web/useSortable';
|
import { useSortable } from '@/hooks/web/useSortable';
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
import { isNil } from '/@/utils/is';
|
import { isNil } from '@/utils/is';
|
||||||
import projectSetting from '/@/settings/projectSetting';
|
import projectSetting from '@/settings/projectSetting';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import type { TabContentProps } from './types';
|
import type { TabContentProps } from './types';
|
||||||
import type { DropMenu } from '/@/components/Dropdown';
|
import type { DropMenu } from '@/components/Dropdown';
|
||||||
import type { ComputedRef } from 'vue';
|
import type { ComputedRef } from 'vue';
|
||||||
|
|
||||||
import { computed, unref, reactive } from 'vue';
|
import { computed, unref, reactive } from 'vue';
|
||||||
import { MenuEventEnum } from './types';
|
import { MenuEventEnum } from './types';
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
import { RouteLocationNormalized, useRouter } from 'vue-router';
|
import { RouteLocationNormalized, useRouter } from 'vue-router';
|
||||||
import { useTabs } from '/@/hooks/web/useTabs';
|
import { useTabs } from '@/hooks/web/useTabs';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
|
|
||||||
export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
|
export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
|
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
theme: propTypes.oneOf(['light', 'dark']),
|
theme: propTypes.oneOf(['light', 'dark']),
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { DoubleRightOutlined, DoubleLeftOutlined } from '@ant-design/icons-vue';
|
import { DoubleRightOutlined, DoubleLeftOutlined } from '@ant-design/icons-vue';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting';
|
||||||
|
|
||||||
const { getCollapsed, toggleCollapsed } = useMenuSetting();
|
const { getCollapsed, toggleCollapsed } = useMenuSetting();
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
import HeaderTrigger from './HeaderTrigger.vue';
|
import HeaderTrigger from './HeaderTrigger.vue';
|
||||||
import SiderTrigger from './SiderTrigger.vue';
|
import SiderTrigger from './SiderTrigger.vue';
|
||||||
|
|
||||||
|
@ -9,21 +9,15 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, unref, computed } from 'vue';
|
import { unref, computed } from 'vue';
|
||||||
import FramePage from '/@/views/sys/iframe/index.vue';
|
import FramePage from '@/views/sys/iframe/index.vue';
|
||||||
|
|
||||||
import { useFrameKeepAlive } from './useFrameKeepAlive';
|
import { useFrameKeepAlive } from './useFrameKeepAlive';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'FrameLayout' });
|
||||||
name: 'FrameLayout',
|
|
||||||
components: { FramePage },
|
|
||||||
setup() {
|
|
||||||
const { getFramePages, hasRenderFrame, showIframe } = useFrameKeepAlive();
|
|
||||||
|
|
||||||
const showFrame = computed(() => unref(getFramePages).length > 0);
|
const { getFramePages, hasRenderFrame, showIframe } = useFrameKeepAlive();
|
||||||
|
|
||||||
return { getFramePages, hasRenderFrame, showIframe, showFrame };
|
const showFrame = computed(() => unref(getFramePages).length > 0);
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import type { AppRouteRecordRaw } from '/@/router/types';
|
import type { AppRouteRecordRaw } from '@/router/types';
|
||||||
|
|
||||||
import { computed, toRaw, unref } from 'vue';
|
import { computed, toRaw, unref } from 'vue';
|
||||||
|
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
|
|
||||||
import { uniqBy } from 'lodash-es';
|
import { uniqBy } from 'lodash-es';
|
||||||
|
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -24,47 +24,34 @@
|
|||||||
<FrameLayout v-if="getCanEmbedIFramePage" />
|
<FrameLayout v-if="getCanEmbedIFramePage" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, unref } from 'vue';
|
import { computed, unref } from 'vue';
|
||||||
|
|
||||||
import FrameLayout from '/@/layouts/iframe/index.vue';
|
import FrameLayout from '@/layouts/iframe/index.vue';
|
||||||
|
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '@/hooks/setting/useRootSetting';
|
||||||
|
|
||||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
import { useTransitionSetting } from '@/hooks/setting/useTransitionSetting';
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting';
|
||||||
import { getTransitionName } from './transition';
|
import { getTransitionName } from './transition';
|
||||||
|
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
|
|
||||||
export default defineComponent({
|
defineOptions({ name: 'PageLayout' });
|
||||||
name: 'PageLayout',
|
|
||||||
components: { FrameLayout },
|
|
||||||
setup() {
|
|
||||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
|
||||||
const tabStore = useMultipleTabStore();
|
|
||||||
|
|
||||||
const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
|
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||||
|
const tabStore = useMultipleTabStore();
|
||||||
|
|
||||||
const { getBasicTransition, getEnableTransition } = useTransitionSetting();
|
const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
|
||||||
|
|
||||||
const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
|
const { getBasicTransition, getEnableTransition } = useTransitionSetting();
|
||||||
|
|
||||||
const getCaches = computed((): string[] => {
|
const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
|
||||||
if (!unref(getOpenKeepAlive)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return tabStore.getCachedTabList;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
const getCaches = computed((): string[] => {
|
||||||
getTransitionName,
|
if (!unref(getOpenKeepAlive)) {
|
||||||
openCache,
|
return [];
|
||||||
getEnableTransition,
|
}
|
||||||
getBasicTransition,
|
return tabStore.getCachedTabList;
|
||||||
getCaches,
|
|
||||||
getCanEmbedIFramePage,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="chartRef" :style="{ height, width }"></div>
|
<div ref="chartRef" :style="{ height, width }"></div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
|
||||||
import { basicProps } from './props';
|
|
||||||
</script>
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, Ref } from 'vue';
|
import { onMounted, ref, Ref } from 'vue';
|
||||||
import { useECharts } from '@/hooks/web/useECharts';
|
import { useECharts } from '@/hooks/web/useECharts';
|
||||||
|
import { basicProps } from './props';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
...basicProps,
|
...basicProps,
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="chartRef" :style="{ height, width }"></div>
|
<div ref="chartRef" :style="{ height, width }"></div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
|
||||||
import { basicProps } from './props';
|
|
||||||
</script>
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, Ref } from 'vue';
|
import { onMounted, ref, Ref } from 'vue';
|
||||||
import { useECharts } from '@/hooks/web/useECharts';
|
import { useECharts } from '@/hooks/web/useECharts';
|
||||||
|
import { basicProps } from './props';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
...basicProps,
|
...basicProps,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<a-button type="link" size="small">更多</a-button>
|
<a-button type="link" size="small">更多</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<CardGrid v-for="item in items" :key="item.title" class="!md:w-1/3 !w-full">
|
<CardGrid v-for="item in groupItems" :key="item.title" class="!md:w-1/3 !w-full">
|
||||||
<span class="flex">
|
<span class="flex">
|
||||||
<Icon :icon="item.icon" :color="item.color" size="30" />
|
<Icon :icon="item.icon" :color="item.color" size="30" />
|
||||||
<span class="text-lg ml-4">{{ item.title }}</span>
|
<span class="text-lg ml-4">{{ item.title }}</span>
|
||||||
@ -17,16 +17,8 @@
|
|||||||
</CardGrid>
|
</CardGrid>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { Card, CardGrid } from 'ant-design-vue';
|
import { Card, CardGrid } from 'ant-design-vue';
|
||||||
import Icon from '@/components/Icon/Icon.vue';
|
import Icon from '@/components/Icon/Icon.vue';
|
||||||
import { groupItems } from './data';
|
import { groupItems } from './data';
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { Card, CardGrid, Icon },
|
|
||||||
setup() {
|
|
||||||
return { items: groupItems };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user