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:
xingyu 2023-11-23 12:14:06 +08:00 committed by GitHub
parent 617b01338c
commit 0cfaa40bd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 1121 additions and 1517 deletions

View File

@ -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';

View File

@ -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';

View File

@ -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>;

View File

@ -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);

View File

@ -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';

View File

@ -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 &copy;2020 Vben Admin</div> <div>Copyright &copy;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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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'), {

View File

@ -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">

View File

@ -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';

View File

@ -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';

View File

@ -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>

View File

@ -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';

View File

@ -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">

View File

@ -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',

View File

@ -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

View File

@ -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,

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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'));

View File

@ -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,

View File

@ -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();

View File

@ -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>

View File

@ -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>

View File

@ -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';

View File

@ -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';

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 {

View File

@ -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');

View File

@ -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 {

View File

@ -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();

View File

@ -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({

View File

@ -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']),

View File

@ -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>

View File

@ -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';

View File

@ -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>

View File

@ -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';

View File

@ -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>

View File

@ -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,

View File

@ -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,

View File

@ -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>