提交 0692b479 编写于 作者: V vben

refactor: refactor layout

上级 25d43a5f
## Wip
### ✨ Refactor
- 重构整体 layout。更改代码实现方式。代码更精简
### ✨ Features
- 缓存可以配置是否加密
......@@ -7,6 +11,7 @@
### 🎫 Chores
- 移除 messageSetting 配置
- 暂时删除 `@vueuse/core`.等稳定后在集成。目前不太稳定。
## 2.0.0-rc.11 (2020-11-18)
......
......@@ -154,15 +154,17 @@ const globTransform = function (config: SharedConfig): Transform {
const groups: Array<string>[] = [];
const replaceFiles = files.map((f, i) => {
const fileNameWithAlias = resolver.fileToRequest(f);
const file = bareExporter + fileNameWithAlias + bareExporter;
const filePath = resolver.fileToRequest(f);
const file = bareExporter + filePath + bareExporter;
if (isLocale) {
const globrexRes = globrex(globPath, { extended: true, globstar: true });
// Get segments for files like an en/system ch/modules for:
// ['en', 'system'] ['ch', 'modules']
// TODO The window system and mac system path are inconsistent?
const fileNameWithAlias = filePath.replace(/^(\/src\/)/, '/@/');
const matchedGroups = globrexRes.regex.exec(fileNameWithAlias);
if (matchedGroups && matchedGroups.length) {
......
<template>
<div class="app-logo anticon" :class="theme" @click="handleGoHome">
<div
class="app-logo anticon"
:class="{ theme, 'collapsed-show-title': getCollapsedShowTitle }"
@click="handleGoHome"
>
<img src="/@/assets/images/logo.png" />
<div class="app-logo__title ml-2 ellipsis">{{ globSetting.title }}</div>
<div class="app-logo__title ml-2 ellipsis" v-show="showTitle">{{ globSetting.title }}</div>
</div>
</template>
<script lang="ts">
......@@ -10,6 +14,7 @@
import { useGlobSetting } from '/@/hooks/setting';
import { useGo } from '/@/hooks/web/usePage';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { PageEnum } from '/@/enums/pageEnum';
......@@ -22,8 +27,13 @@
theme: {
type: String as PropType<string>,
},
showTitle: {
type: Boolean,
default: true,
},
},
setup() {
const { getCollapsedShowTitle } = useMenuSetting();
const globSetting = useGlobSetting();
const go = useGo();
......@@ -34,6 +44,7 @@
return {
handleGoHome,
globSetting,
getCollapsedShowTitle,
};
},
});
......@@ -44,9 +55,13 @@
.app-logo {
display: flex;
align-items: center;
padding-left: 16px;
padding-left: 10px;
cursor: pointer;
&.collapsed-show-title {
padding-left: 20px;
}
&.light {
border-bottom: 1px solid @border-color-base;
}
......@@ -64,6 +79,7 @@
font-weight: 700;
opacity: 0;
transition: all 0.5s;
.respond-to(medium,{
opacity: 1;
});
......
......@@ -49,7 +49,7 @@ export default defineComponent({
? `${opt.wrapClassName} ${prefixCls}__detail`
: `${prefixCls}__detail`;
if (!opt.getContainer) {
opt.getContainer = `.default-layout__main`;
opt.getContainer = '.layout-content';
}
}
return opt;
......
......@@ -80,7 +80,7 @@ export default defineComponent({
offset += 46;
}
return {
height: `calc(100% - ${offset - 12}px)`,
height: `calc(100% - ${offset}px)`,
position: 'relative',
overflowY: 'auto',
};
......
......@@ -219,11 +219,7 @@ export default defineComponent({
emit('register', modalMethods, uuid);
return () => (
<Modal
onCancel={handleCancel}
getContainer={() => document.querySelector('.default-layout__main')}
{...{ ...attrs, ...props, ...unref(getProps) }}
>
<Modal onCancel={handleCancel} {...{ ...attrs, ...props, ...unref(getProps) }}>
{{
footer: () => renderFooter(),
closeIcon: () => renderClose(),
......
......@@ -33,6 +33,7 @@ export function useModal(): UseModalReturnType {
modalRef.value = modalMethod;
}
const getInstance = () => {
const instance = unref(modalRef);
if (!instance) {
......@@ -50,6 +51,7 @@ export function useModal(): UseModalReturnType {
getInstance().setModalProps({
visible: visible,
});
if (data) {
dataTransferRef[unref(uidRef)] = openOnSet
? {
......
......@@ -43,7 +43,6 @@ export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRe
const tableEl: Element = table.$el;
if (!tableEl) return;
const headEl = tableEl.querySelector('.ant-table-thead ');
// const layoutMain: Element | null = document.querySelector('.default-layout__main ');
if (!headEl) return;
// 表格距离底部高度
......
......@@ -35,7 +35,7 @@ html,
body {
width: 100%;
height: 100%;
overflow: hidden;
overflow-x: hidden;
&.color-weak {
filter: invert(80%);
......@@ -160,9 +160,7 @@ object {
vertical-align: baseline !important;
}
#app,
#app > div,
.ant-layout {
#app {
width: 100%;
height: 100%;
}
......@@ -170,8 +168,8 @@ object {
.ant-layout {
background: #f0f2f5;
&-content {
position: relative;
overflow: hidden;
}
// &-content {
// position: relative;
// overflow: hidden;
// }
}
......@@ -101,14 +101,3 @@
}
}
}
.reset-layout() {
.ant-layout {
background: #f1f1f6 !important;
&-content {
position: relative;
overflow: hidden;
}
}
}
import { InjectionKey, provide, inject, reactive, readonly } from 'vue';
export const createContext = <T>(
context: any,
contextInjectKey: InjectionKey<T> = Symbol(),
_readonly = true
) => {
const state = reactive({
...context,
});
const provideData = _readonly ? readonly(state) : state;
provide(contextInjectKey, provideData);
};
export const useContext = <T>(
contextInjectKey: InjectionKey<T> = Symbol(),
defaultValue?: any,
_readonly = true
): T => {
const state = inject(contextInjectKey, defaultValue || {});
return _readonly ? readonly(state) : state;
};
......@@ -7,20 +7,50 @@ import { appStore } from '/@/store/modules/app';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useFullContent } from '/@/hooks/web/useFullContent';
import { MenuModeEnum } from '/@/enums/menuEnum';
export function useHeaderSetting() {
const { getShow: getShowMultipleTab } = useMultipleTabSetting();
const { getMode, getSplit, getShowHeaderTrigger, getIsSidebarType } = useMenuSetting();
const { getFullContent } = useFullContent();
const { getShowMultipleTab } = useMultipleTabSetting();
const {
getMenuMode,
getSplit,
getShowHeaderTrigger,
getIsSidebarType,
getIsTopMenu,
} = useMenuSetting();
const { getShowBreadCrumb, getShowLogo } = useRootSetting();
const getShowMixHeaderRef = computed(() => !unref(getIsSidebarType) && unref(getShowHeader));
const getShowFullHeaderRef = computed(() => {
return (
!unref(getFullContent) &&
unref(getShowMixHeaderRef) &&
unref(getShowHeader) &&
!unref(getIsTopMenu)
);
});
const getShowInsetHeaderRef = computed(() => {
const need = !unref(getFullContent) && unref(getShowHeader);
return (need && !unref(getShowMixHeaderRef)) || (need && unref(getIsTopMenu));
});
// Get header configuration
const getHeaderSetting = computed(() => appStore.getProjectConfig.headerSetting);
const getShowDoc = computed(() => unref(getHeaderSetting).showDoc);
const getTheme = computed(() => unref(getHeaderSetting).theme);
const getHeaderTheme = computed(() => unref(getHeaderSetting).theme);
const getShowHeader = computed(() => unref(getHeaderSetting).show);
const getFixed = computed(() => unref(getHeaderSetting).fixed);
const getHeaderBgColor = computed(() => unref(getHeaderSetting).bgColor);
const getShowRedo = computed(() => unref(getHeaderSetting).showRedo && unref(getShowMultipleTab));
......@@ -30,9 +60,11 @@ export function useHeaderSetting() {
const getShowNotice = computed(() => unref(getHeaderSetting).showNotice);
const getUnFixedAndFull = computed(() => !unref(getFixed) && !unref(getShowFullHeaderRef));
const getShowBread = computed(() => {
return (
unref(getMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit)
unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit)
);
});
......@@ -55,7 +87,7 @@ export function useHeaderSetting() {
getHeaderSetting,
getShowDoc,
getTheme,
getHeaderTheme,
getShowRedo,
getUseLockPage,
getShowFullScreen,
......@@ -63,5 +95,12 @@ export function useHeaderSetting() {
getShowBread,
getShowContent,
getShowHeaderLogo,
getShowHeader,
getFixed,
getShowMixHeaderRef,
getShowFullHeaderRef,
getShowInsetHeaderRef,
getUnFixedAndFull,
getHeaderBgColor,
};
}
......@@ -11,24 +11,28 @@ export function useMenuSetting() {
// Get menu configuration
const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting);
const getMiniWidth = computed(() => unref(getMenuSetting).menuWidth);
const getCollapsed = computed(() => unref(getMenuSetting).collapsed);
const getType = computed(() => unref(getMenuSetting).type);
const getMenuType = computed(() => unref(getMenuSetting).type);
const getMenuMode = computed(() => unref(getMenuSetting).mode);
const getMode = computed(() => unref(getMenuSetting).mode);
const getMenuFixed = computed(() => unref(getMenuSetting).fixed);
const getShow = computed(() => unref(getMenuSetting).show);
const getShowMenu = computed(() => unref(getMenuSetting).show);
const getMenuHidden = computed(() => unref(getMenuSetting).hidden);
const getMenuWidth = computed(() => unref(getMenuSetting).menuWidth);
const getTrigger = computed(() => unref(getMenuSetting).trigger);
const getTheme = computed(() => unref(getMenuSetting).theme);
const getMenuTheme = computed(() => unref(getMenuSetting).theme);
const getSplit = computed(() => unref(getMenuSetting).split);
const getMenuBgColor = computed(() => unref(getMenuSetting).bgColor);
const getHasDrag = computed(() => unref(getMenuSetting).hasDrag);
const getAccordion = computed(() => unref(getMenuSetting).accordion);
......@@ -39,17 +43,19 @@ export function useMenuSetting() {
const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign);
const getIsSidebarType = computed(() => unref(getType) === MenuTypeEnum.SIDEBAR);
const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR);
const getIsTopMenu = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU);
const getShowTopMenu = computed(() => {
return unref(getMode) === MenuModeEnum.HORIZONTAL || unref(getSplit);
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL || unref(getSplit);
});
const getShowHeaderTrigger = computed(() => {
if (
unref(getType) === MenuTypeEnum.TOP_MENU ||
!unref(getShow) ||
!unref(getMenuSetting).hidden
unref(getMenuType) === MenuTypeEnum.TOP_MENU ||
!unref(getShowMenu) ||
!unref(getMenuHidden)
) {
return false;
}
......@@ -60,12 +66,16 @@ export function useMenuSetting() {
const getShowSearch = computed(() => {
return (
unref(getMenuSetting).showSearch &&
!(unref(getType) === MenuTypeEnum.MIX && unref(getMode) === MenuModeEnum.HORIZONTAL)
!(unref(getMenuType) === MenuTypeEnum.MIX && unref(getMenuMode) === MenuModeEnum.HORIZONTAL)
);
});
const getIsHorizontal = computed(() => {
return unref(getMode) === MenuModeEnum.HORIZONTAL;
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL;
});
const getRealWidth = computed(() => {
return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth);
});
const getMiniWidthNumber = computed(() => {
......@@ -74,8 +84,8 @@ export function useMenuSetting() {
});
const getCalcContentWidth = computed(() => {
const width = unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMiniWidth);
return `calc(100% - ${width}px)`;
const width = unref(getIsTopMenu) || !unref(getShowMenu) ? 0 : unref(getRealWidth);
return `calc(100% - ${unref(width)}px)`;
});
// Set menu configuration
......@@ -94,18 +104,19 @@ export function useMenuSetting() {
toggleCollapsed,
getMenuFixed,
getMenuSetting,
getMiniWidth,
getType,
getMode,
getShow,
getRealWidth,
getMenuType,
getMenuMode,
getShowMenu,
getCollapsed,
getMiniWidthNumber,
getCalcContentWidth,
getMenuWidth,
getTrigger,
getSplit,
getTheme,
getMenuTheme,
getHasDrag,
getIsHorizontal,
getShowSearch,
......@@ -116,5 +127,8 @@ export function useMenuSetting() {
getShowTopMenu,
getShowHeaderTrigger,
getTopMenuAlign,
getMenuHidden,
getIsTopMenu,
getMenuBgColor,
};
}
......@@ -9,7 +9,9 @@ export function useMultipleTabSetting() {
const getMax = computed(() => unref(getMultipleTabSetting).max);
const getShow = computed(() => unref(getMultipleTabSetting).show);
const getShowMultipleTab = computed(() => unref(getMultipleTabSetting).show);
const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick);
function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
appStore.commitProjectConfigState({ multiTabsSetting });
......@@ -20,6 +22,7 @@ export function useMultipleTabSetting() {
getMultipleTabSetting,
getMax,
getShow,
getShowMultipleTab,
getShowQuick,
};
}
......@@ -3,6 +3,7 @@ import type { ProjectConfig } from '/@/types/config';
import { computed, unref } from 'vue';
import { appStore } from '/@/store/modules/app';
import { ContentEnum } from '/@/enums/appEnum';
type RootSetting = Omit<
ProjectConfig,
......@@ -13,6 +14,8 @@ export function useRootSetting() {
const getOpenPageLoading = computed(() => unref(getRootSetting).openPageLoading);
const getPageLoading = computed(() => appStore.getPageLoading);
const getOpenRouterTransition = computed(() => unref(getRootSetting).openRouterTransition);
const getOpenKeepAlive = computed(() => unref(getRootSetting).openKeepAlive);
......@@ -25,12 +28,30 @@ export function useRootSetting() {
const getShowLogo = computed(() => unref(getRootSetting).showLogo);
const getContentMode = computed(() => unref(getRootSetting).contentMode);
const getUseOpenBackTop = computed(() => unref(getRootSetting).useOpenBackTop);
const getShowSettingButton = computed(() => unref(getRootSetting).showSettingButton);
const getUseErrorHandle = computed(() => unref(getRootSetting).useErrorHandle);
const getShowFooter = computed(() => unref(getRootSetting).showFooter);
const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb);
const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon);
const getFullContent = computed(() => unref(getRootSetting).fullContent);
const getColorWeak = computed(() => unref(getRootSetting).colorWeak);
const getGrayMode = computed(() => unref(getRootSetting).grayMode);
const getLayoutContentMode = computed(() =>
unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
);
function setRootSetting(setting: RootSetting) {
appStore.commitProjectConfigState(setting);
}
......@@ -38,7 +59,12 @@ export function useRootSetting() {
return {
setRootSetting,
getFullContent,
getColorWeak,
getGrayMode,
getRootSetting,
getLayoutContentMode,
getPageLoading,
getOpenPageLoading,
getOpenRouterTransition,
getOpenKeepAlive,
......@@ -49,5 +75,9 @@ export function useRootSetting() {
getUseErrorHandle,
getShowBreadCrumb,
getShowBreadCrumbIcon,
getUseOpenBackTop,
getShowSettingButton,
getShowFooter,
getContentMode,
};
}
import { computed, defineComponent, unref } from 'vue';
import { Layout } from 'ant-design-vue';
import { FullLoading } from '/@/components/Loading/index';
import { RouterView } from 'vue-router';
import { ContentEnum } from '/@/enums/appEnum';
import { appStore } from '/@/store/modules/app';
export default defineComponent({
name: 'DefaultLayoutContent',
setup() {
const getProjectConfigRef = computed(() => {
return appStore.getProjectConfig;
});
return () => {
const { contentMode, openPageLoading } = unref(getProjectConfigRef);
const { getPageLoading } = appStore;
const wrapClass = contentMode === ContentEnum.FULL ? 'full' : 'fixed';
return (
<div class={[`default-layout__main`]}>
{openPageLoading && (
<FullLoading class={[`default-layout__loading`, !getPageLoading && 'hidden']} />
)}
<Layout.Content class={`layout-content ${wrapClass} `}>
{() => <RouterView />}
</Layout.Content>
</div>
);
};
},
});
import type { PropType } from 'vue';
import type { PropType, FunctionalComponent } from 'vue';
import { defineComponent, unref } from 'vue';
import {
......@@ -10,6 +10,22 @@ import {
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
const SiderTrigger: FunctionalComponent = () => {
const { getCollapsed } = useMenuSetting();
return unref(getCollapsed) ? <DoubleRightOutlined /> : <DoubleLeftOutlined />;
};
const HeaderTrigger: FunctionalComponent<{
theme?: string;
}> = (props) => {
const { toggleCollapsed, getCollapsed } = useMenuSetting();
return (
<span class={['layout-trigger', props.theme]} onClick={toggleCollapsed}>
{unref(getCollapsed) ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</span>
);
};
export default defineComponent({
name: 'LayoutTrigger',
props: {
......@@ -22,20 +38,8 @@ export default defineComponent({
},
},
setup(props) {
const { toggleCollapsed, getCollapsed } = useMenuSetting();
return () => {
const siderTrigger = unref(getCollapsed) ? <DoubleRightOutlined /> : <DoubleLeftOutlined />;
if (props.sider) {
return siderTrigger;
}
return (
<span class={['layout-trigger', props.theme]} onClick={toggleCollapsed}>
{unref(getCollapsed) ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</span>
);
return props.sider ? <SiderTrigger /> : <HeaderTrigger theme={props.theme} />;
};
},
});
@import (reference) '../../../design/index.less';
.layout-content {
position: relative;
flex: 1 1 auto;
min-height: 0;
&.fixed {
width: 1200px;
margin: 0 auto;
}
&__loading {
position: fixed;
z-index: @page-loading-z-index;
> .basic-loading {
margin-bottom: 20%;
}
}
}
import './index.less';
import { defineComponent, unref } from 'vue';
import { FullLoading } from '/@/components/Loading/index';
import { RouterView } from 'vue-router';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
export default defineComponent({
name: 'LayoutContent',
setup() {
const { getOpenPageLoading, getLayoutContentMode, getPageLoading } = useRootSetting();
return () => {
return (
<div class={['layout-content', unref(getLayoutContentMode)]}>
{unref(getOpenPageLoading) && (
<FullLoading class={[`layout-content__loading`, { hidden: !unref(getPageLoading) }]} />
)}
<RouterView />
</div>
);
};
},
});
@normal-color: rgba(0, 0, 0, 0.45);
@hover-color: rgba(0, 0, 0, 0.85);
.layout-footer {
color: @normal-color;
text-align: center;
&__links {
margin-bottom: 8px;
a {
color: @normal-color;
&:hover {
color: @hover-color;
}
}
.github {
margin: 0 30px;
&:hover {
color: @hover-color;
}
}
}
}
import './index.less';
import { defineComponent } from 'vue';
import { Layout } from 'ant-design-vue';
import { GithubFilled } from '@ant-design/icons-vue';
import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
import { openWindow } from '/@/utils';
export default defineComponent({
name: 'LayoutContent',
setup() {
return () => {
return (
<Layout.Footer class="layout-footer">
{() => (
<>
<div class="layout-footer__links">
<a onClick={() => openWindow(SITE_URL)}>在线预览</a>
<GithubFilled onClick={() => openWindow(GITHUB_URL)} class="github" />
<a onClick={() => openWindow(DOC_URL)}>在线文档</a>
</div>
<div>Copyright &copy;2020 Vben Admin</div>
</>
)}
</Layout.Footer>
);
};
},
});
import './index.less';
import type { FunctionalComponent } from 'vue';
import { defineComponent, unref, computed, ref, nextTick } from 'vue';
import { Layout, Tooltip, Badge } from 'ant-design-vue';
import { AppLogo } from '/@/components/Application';
import UserDropdown from './UserDropdown';
import LayoutMenu from '/@/layouts/default/menu/LayoutMenu';
import LayoutMenu from '../menu';
import LayoutBreadcrumb from './LayoutBreadcrumb';
import LockAction from './LockActionItem';
import LockAction from '../lock/LockAction';
import LayoutTrigger from '../LayoutTrigger';
import NoticeAction from './notice/NoticeActionItem.vue';
import {
......@@ -34,9 +36,30 @@ import { PageEnum } from '/@/enums/pageEnum';
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
import { Component } from '/@/components/types';
interface TooltipItemProps {
title: string;
}
const TooltipItem: FunctionalComponent<TooltipItemProps> = (props, { slots }) => {
return (
<Tooltip>
{{
title: () => props.title,
default: () => slots.default?.(),
}}
</Tooltip>
);
};
export default defineComponent({
name: 'LayoutHeader',
setup() {
props: {
fixed: {
type: Boolean,
default: false,
},
},
setup(props) {
let logoEl: Element | null;
const logoWidthRef = ref(200);
......@@ -48,7 +71,7 @@ export default defineComponent({
const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting();
const {
getTheme,
getHeaderTheme,
getShowRedo,
getUseLockPage,
getShowFullScreen,
......@@ -69,8 +92,7 @@ export default defineComponent({
let width = 0;
if (!logoEl) {
logoEl = logoRef.value.$el;
}
if (logoEl) {
} else {
width += logoEl.clientWidth;
}
logoWidthRef.value = width + 80;
......@@ -81,7 +103,7 @@ export default defineComponent({
);
const headerClass = computed(() => {
const theme = unref(getTheme);
const theme = unref(getHeaderTheme);
return theme ? `layout-header__header--${theme}` : '';
});
......@@ -99,9 +121,6 @@ export default defineComponent({
});
}
/**
* @description: 锁定屏幕
*/
function handleLockPage() {
openModal(true);
}
......@@ -111,13 +130,13 @@ export default defineComponent({
return (
<div class="layout-header__content ">
{unref(getShowHeaderLogo) && (
<AppLogo class={`layout-header__logo`} ref={logoRef} theme={unref(getTheme)} />
<AppLogo class={`layout-header__logo`} ref={logoRef} theme={unref(getHeaderTheme)} />
)}
{unref(getShowContent) && (
<div class="layout-header__left">
{unref(getShowHeaderTrigger) && (
<LayoutTrigger theme={unref(getTheme)} sider={false} />
<LayoutTrigger theme={unref(getHeaderTheme)} sider={false} />
)}
{unref(getShowBread) && <LayoutBreadcrumb showIcon={unref(getShowBreadCrumbIcon)} />}
</div>
......@@ -128,7 +147,7 @@ export default defineComponent({
<LayoutMenu
isHorizontal={true}
class={`justify-${unref(getTopMenuAlign)}`}
theme={unref(getTheme)}
theme={unref(getHeaderTheme)}
splitType={unref(getSplitType)}
menuMode={unref(getMenuMode)}
showSearch={false}
......@@ -151,64 +170,47 @@ export default defineComponent({
return (
<div class={`layout-header__action`}>
{unref(getUseErrorHandle) && (
<Tooltip>
{{
title: () => '错误日志',
default: () => (
<Badge
count={errorStore.getErrorListCountState}
offset={[0, 10]}
dot
overflowCount={99}
>
{() => renderActionDefault(BugOutlined, handleToErrorList)}
</Badge>
),
}}
</Tooltip>
<TooltipItem title="错误日志">
{() => (
<Badge
count={errorStore.getErrorListCountState}
offset={[0, 10]}
dot
overflowCount={99}
>
{() => renderActionDefault(BugOutlined, handleToErrorList)}
</Badge>
)}
</TooltipItem>
)}
{unref(getUseLockPage) && (
<Tooltip>
{{
title: () => '锁定屏幕',
default: () => renderActionDefault(LockOutlined, handleLockPage),
}}
</Tooltip>
<TooltipItem title="锁定屏幕">
{() => renderActionDefault(LockOutlined, handleLockPage)}
</TooltipItem>
)}
{unref(getShowNotice) && (
<Tooltip>
{{
title: () => '消息通知',
default: () => <NoticeAction />,
}}
</Tooltip>
<TooltipItem title="消息通知">{() => <NoticeAction />}</TooltipItem>
)}
{unref(getShowRedo) && (
<Tooltip>
{{
title: () => '刷新',
default: () => renderActionDefault(RedoOutlined, refreshPage),
}}
</Tooltip>
<TooltipItem title="刷新">
{() => renderActionDefault(RedoOutlined, refreshPage)}
</TooltipItem>
)}
{unref(getShowFullScreen) && (
<Tooltip>
{{
title: () => (unref(isFullscreenRef) ? '退出全屏' : '全屏'),
default: () => {
const Icon = !unref(isFullscreenRef) ? (
<FullscreenOutlined />
) : (
<FullscreenExitOutlined />
);
return renderActionDefault(Icon, toggleFullscreen);
},
<TooltipItem title={unref(isFullscreenRef) ? '退出全屏' : '全屏'}>
{() => {
const Icon = !unref(isFullscreenRef) ? (
<FullscreenOutlined />
) : (
<FullscreenExitOutlined />
);
return renderActionDefault(Icon, toggleFullscreen);
}}
</Tooltip>
</TooltipItem>
)}
<UserDropdown class={`layout-header__user-dropdown`} />
</div>
......@@ -227,7 +229,9 @@ export default defineComponent({
return () => {
return (
<Layout.Header class={['layout-header', 'flex p-0 px-4 ', unref(headerClass)]}>
<Layout.Header
class={['layout-header', 'flex p-0 px-4 ', unref(headerClass), { fixed: props.fixed }]}
>
{() => renderHeaderDefault()}
</Layout.Header>
);
......
.multiple-tab-header {
flex: 0 0 auto;
&.fixed {
position: fixed;
top: 0;
z-index: 100;
width: 100%;
}
}
import './LayoutMultipleHeader.less';
import { defineComponent, unref, computed, ref, watch, nextTick, CSSProperties } from 'vue';
import LayoutHeader from './LayoutHeader';
import MultipleTabs from '../multitabs/index';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useFullContent } from '/@/hooks/web/useFullContent';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { useLayoutContext } from '../useLayoutContext';
export default defineComponent({
name: 'LayoutMultipleHeader',
setup() {
const placeholderHeightRef = ref(0);
const fullHeaderHeightRef = ref(0);
const headerElRef = ref<ComponentRef>(null);
const tabElRef = ref<ComponentRef>(null);
const injectValue = useLayoutContext();
const { getCalcContentWidth } = useMenuSetting();
const {
getFixed,
getShowInsetHeaderRef,
getShowFullHeaderRef,
getShowHeader,
getUnFixedAndFull,
} = useHeaderSetting();
const { getFullContent } = useFullContent();
const { getShowMultipleTab } = useMultipleTabSetting();
const showTabsRef = computed(() => {
return unref(getShowMultipleTab) && !unref(getFullContent);
});
const getPlaceholderDomStyle = computed(() => {
return {
height: `${unref(placeholderHeightRef)}px`,
};
});
const getIsShowPlaceholderDom = computed(() => {
return unref(getFixed) || unref(getShowFullHeaderRef);
});
const getWrapStyle = computed(() => {
const style: CSSProperties = {};
if (unref(getFixed)) {
style.width = unref(getCalcContentWidth);
}
if (unref(getShowFullHeaderRef)) {
style.top = `${unref(fullHeaderHeightRef)}px`;
}
return style;
});
const getIsFixed = computed(() => {
return unref(getFixed) || unref(getShowFullHeaderRef);
});
watch(
() => [
unref(getFixed),
unref(getShowFullHeaderRef),
unref(getShowHeader),
unref(getShowMultipleTab),
],
() => {
if (unref(getUnFixedAndFull)) return;
nextTick(() => {
const headerEl = unref(headerElRef)?.$el;
const tabEl = unref(tabElRef)?.$el;
const fullHeaderEl = unref(injectValue.fullHeaderRef)?.$el;
let height = 0;
if (headerEl && !unref(getShowFullHeaderRef)) {
height += headerEl.offsetHeight;
}
if (tabEl) {
height += tabEl.offsetHeight;
}
if (fullHeaderEl && unref(getShowFullHeaderRef)) {
const fullHeaderHeight = fullHeaderEl.offsetHeight;
height += fullHeaderHeight;
fullHeaderHeightRef.value = fullHeaderHeight;
}
placeholderHeightRef.value = height;
});
},
{
immediate: true,
}
);
return () => {
return (
<>
{unref(getIsShowPlaceholderDom) && <div style={unref(getPlaceholderDomStyle)} />}
<div
style={unref(getWrapStyle)}
class={['multiple-tab-header', { fixed: unref(getIsFixed) }]}
>
{unref(getShowInsetHeaderRef) && <LayoutHeader ref={headerElRef} />}
{unref(showTabsRef) && <MultipleTabs ref={tabElRef} />}
</div>
</>
);
};
},
});
......@@ -15,15 +15,31 @@ import { DOC_URL } from '/@/settings/siteSetting';
import { openWindow } from '/@/utils';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { FunctionalComponent } from 'vue';
interface RenderItemParams {
type MenuEvent = 'loginOut' | 'doc';
interface MenuItemProps {
icon: string;
text: string;
key: string;
key: MenuEvent;
}
const prefixCls = 'user-dropdown';
const MenuItem: FunctionalComponent<MenuItemProps> = (props) => {
const { key, icon, text } = props;
return (
<Menu.Item key={key}>
{() => (
<span class="flex items-center">
<Icon icon={icon} class="mr-1" />
<span>{text}</span>
</span>
)}
</Menu.Item>
);
};
export default defineComponent({
name: 'UserDropdown',
setup() {
......@@ -44,27 +60,17 @@ export default defineComponent({
openWindow(DOC_URL);
}
function handleMenuClick(e: any) {
if (e.key === 'loginOut') {
handleLoginOut();
} else if (e.key === 'doc') {
openDoc();
function handleMenuClick(e: { key: MenuEvent }) {
switch (e.key) {
case 'loginOut':
handleLoginOut();
break;
case 'doc':
openDoc();
break;
}
}
function renderItem({ icon, text, key }: RenderItemParams) {
return (
<Menu.Item key={key}>
{() => (
<span class="flex items-center">
<Icon icon={icon} class="mr-1" />
<span>{text}</span>
</span>
)}
</Menu.Item>
);
}
function renderSlotsDefault() {
const { realName } = unref(getUserInfo);
return (
......@@ -83,13 +89,9 @@ export default defineComponent({
<Menu onClick={handleMenuClick}>
{() => (
<>
{showDoc && renderItem({ key: 'doc', text: '文档', icon: 'gg:loadbar-doc' })}
{showDoc && <MenuItem key="doc" text="文档" icon="gg:loadbar-doc" />}
{showDoc && <Divider />}
{renderItem({
key: 'loginOut',
text: '退出系统',
icon: 'ant-design:poweroff-outlined',
})}
<MenuItem key="loginOut" text="退出系统" icon="ant-design:poweroff-outlined" />
</>
)}
</Menu>
......
......@@ -10,13 +10,21 @@
align-items: center;
justify-content: space-between;
&.fixed {
position: fixed;
top: 0;
left: 0;
z-index: 1000;
width: 100%;
}
&__left {
display: flex;
// flex-grow: 1;
align-items: center;
.layout-trigger {
padding: 4px 10px 0 16px;
padding: 1px 10px 0 16px;
cursor: pointer;
.anticon {
......@@ -150,6 +158,7 @@
}
&__inner,
&__inner.is-link,
&__separator {
color: @white;
}
......
@import (reference) '../../design/index.less';
.default-layout {
&__content {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
min-height: 100%;
&.fixed {
overflow: hidden;
}
}
&__loading {
position: absolute;
z-index: @page-loading-z-index;
}
&__main {
position: relative;
height: 100%;
&.fixed {
overflow-x: hidden;
overflow-y: auto;
}
&.fixed.lock {
overflow: hidden;
}
}
.layout-content {
position: relative;
&.fixed {
width: 1200px;
margin: 0 auto;
}
> .ant-layout {
min-height: 100%;
}
}
import { defineComponent, unref, computed } from 'vue';
import './index.less';
import { defineComponent, unref, computed, ref } from 'vue';
import { Layout, BackTop } from 'ant-design-vue';
import LayoutHeader from './header/LayoutHeader';
import { appStore } from '/@/store/modules/app';
import LayoutContent from './LayoutContent';
import LayoutSideBar from './sider/LayoutSideBar';
import LayoutContent from './content';
import LayoutFooter from './footer';
import LayoutLockPage from './lock';
import LayoutSideBar from './sider';
import SettingBtn from './setting/index.vue';
import MultipleTabs from './multitabs/index';
import LayoutMultipleHeader from './header/LayoutMultipleHeader';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { MenuModeEnum } from '/@/enums/menuEnum';
import { useRouter } from 'vue-router';
import { useFullContent } from '/@/hooks/web/useFullContent';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { createLayoutContext } from './useLayoutContext';
import LockPage from '/@/views/sys/lock/index.vue';
import { registerGlobComp } from '/@/components/registerGlobComp';
import './index.less';
export default defineComponent({
name: 'DefaultLayout',
setup() {
const { currentRoute } = useRouter();
const headerRef = ref<ComponentRef>(null);
createLayoutContext({ fullHeaderRef: headerRef });
// ! Only register global components here
// ! Can reduce the size of the first screen code
// default layout It is loaded after login. So it won’t be packaged to the first screen
registerGlobComp();
const { getFullContent } = useFullContent();
const getProjectConfigRef = computed(() => appStore.getProjectConfig);
const { getShowFullHeaderRef } = useHeaderSetting();
const getLockMainScrollStateRef = computed(() => appStore.getLockMainScrollState);
const { getUseOpenBackTop, getShowSettingButton, getShowFooter } = useRootSetting();
const showHeaderRef = computed(() => {
const {
headerSetting: { show },
} = unref(getProjectConfigRef);
return show;
});
const { getShowMenu, getMenuMode, getSplit } = useMenuSetting();
const showMixHeaderRef = computed(() => {
const {
menuSetting: { type },
} = unref(getProjectConfigRef);
return type !== MenuTypeEnum.SIDEBAR && unref(showHeaderRef);
});
const { getFullContent } = useFullContent();
const getIsLockRef = computed(() => {
const { getLockInfo } = appStore;
const { isLock } = getLockInfo;
return isLock;
const getShowLayoutFooter = computed(() => {
return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter;
});
const showSideBarRef = computed(() => {
const {
menuSetting: { show, mode, split },
} = unref(getProjectConfigRef);
return split || (show && mode !== MenuModeEnum.HORIZONTAL && !unref(getFullContent));
});
const showFullHeaderRef = computed(() => {
return !unref(getFullContent) && unref(showMixHeaderRef) && unref(showHeaderRef);
});
const showInsetHeaderRef = computed(() => {
return !unref(getFullContent) && !unref(showMixHeaderRef) && unref(showHeaderRef);
});
const fixedHeaderClsRef = computed(() => {
const {
headerSetting: { fixed },
} = unref(getProjectConfigRef);
const fixedHeaderCls = fixed
? 'fixed' + (unref(getLockMainScrollStateRef) ? ' lock' : '')
: '';
return fixedHeaderCls;
});
const showTabsRef = computed(() => {
const {
multiTabsSetting: { show },
} = unref(getProjectConfigRef);
return show && !unref(getFullContent);
});
const showClassSideBarRef = computed(() => {
const {
menuSetting: { split, hidden },
} = unref(getProjectConfigRef);
return split ? hidden : true;
return (
unref(getSplit) ||
(unref(getShowMenu) &&
unref(getMenuMode) !== MenuModeEnum.HORIZONTAL &&
!unref(getFullContent))
);
});
function getTarget(): any {
const {
headerSetting: { fixed },
} = unref(getProjectConfigRef);
return document.querySelector(`.default-layout__${fixed ? 'main' : 'content'}`);
function renderFeatures() {
return (
<>
<LayoutLockPage />
{/* back top */}
{unref(getUseOpenBackTop) && <BackTop target={() => document.body} />}
{/* open setting drawer */}
{unref(getShowSettingButton) && <SettingBtn />}
</>
);
}
return () => {
const { useOpenBackTop, showSettingButton } = unref(getProjectConfigRef);
return (
<Layout class="default-layout relative">
<Layout class="default-layout">
{() => (
<>
{/* lock page */}
{unref(getIsLockRef) && <LockPage />}
{/* back top */}
{useOpenBackTop && <BackTop target={getTarget} />}
{/* open setting drawer */}
{showSettingButton && <SettingBtn />}
{renderFeatures()}
{unref(showFullHeaderRef) && <LayoutHeader />}
{unref(getShowFullHeaderRef) && <LayoutHeader fixed={true} ref={headerRef} />}
<Layout>
{() => (
<>
{unref(showSideBarRef) && (
<LayoutSideBar class={unref(showClassSideBarRef) ? '' : 'hidden'} />
)}
<Layout class={[`default-layout__content`, unref(fixedHeaderClsRef)]}>
{unref(showSideBarRef) && <LayoutSideBar />}
<Layout>
{() => (
<>
{unref(showInsetHeaderRef) && <LayoutHeader />}
{unref(showTabsRef) && <MultipleTabs />}
<LayoutContent class={unref(fixedHeaderClsRef)} />
<LayoutMultipleHeader />
<LayoutContent />
{unref(getShowLayoutFooter) && <LayoutFooter />}
</>
)}
</Layout>
......
import './LockActionItem.less';
import './LockAction.less';
import { defineComponent } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal/index';
......
import { defineComponent, unref, computed } from 'vue';
import { appStore } from '/@/store/modules/app';
import LockPage from '/@/views/sys/lock/index.vue';
export default defineComponent({
name: 'LayoutLockPage',
setup() {
const getIsLockRef = computed(() => {
const { getLockInfo } = appStore;
const { isLock } = getLockInfo;
return isLock;
});
return () => {
return unref(getIsLockRef) ? <LockPage /> : null;
};
},
});
......@@ -17,7 +17,7 @@ import { useSplitMenu } from './useLayoutMenu';
import { openWindow } from '/@/utils';
export default defineComponent({
name: 'DefaultLayoutMenu',
name: 'LayoutMenu',
props: {
theme: {
type: String as PropType<string>,
......@@ -50,12 +50,12 @@ export default defineComponent({
const {
setMenuSetting,
getShowSearch,
getMode,
getType,
getMenuMode,
getMenuType,
getCollapsedShowTitle,
getCollapsedShowSearch,
getIsSidebarType,
getTheme,
getMenuTheme,
getCollapsed,
getAccordion,
} = useMenuSetting();
......@@ -66,9 +66,9 @@ export default defineComponent({
const showLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType));
const getMenuMode = computed(() => props.menuMode || unref(getMode));
const getComputedMenuMode = computed(() => props.menuMode || unref(getMenuMode));
const getMenuTheme = computed(() => props.theme || unref(getTheme));
const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
const appendClass = computed(() => props.splitType === MenuSplitTyeEnum.TOP);
......@@ -111,8 +111,8 @@ export default defineComponent({
return (
<AppLogo
showTitle={!unref(getCollapsed)}
class={[`layout-menu__logo`, unref(getMenuTheme)]}
theme={unref(getMenuTheme)}
class={[`layout-menu__logo`, unref(getComputedMenuTheme)]}
theme={unref(getComputedMenuTheme)}
/>
);
}
......@@ -124,10 +124,10 @@ export default defineComponent({
beforeClickFn={beforeMenuClickFn}
isHorizontal={props.isHorizontal}
appendClass={unref(appendClass)}
type={unref(getType)}
mode={unref(getMenuMode)}
type={unref(getMenuType)}
mode={unref(getComputedMenuMode)}
collapsedShowTitle={unref(getCollapsedShowTitle)}
theme={unref(getMenuTheme)}
theme={unref(getComputedMenuTheme)}
showLogo={unref(showLogo)}
search={unref(showSearch)}
items={unref(menusRef)}
......
......@@ -6,7 +6,6 @@ import { TabItem, tabStore } from '/@/store/modules/tab';
import { getScaleAction, TabContentProps } from './tab.data';
import { Dropdown } from '/@/components/Dropdown/index';
import Icon from '/@/components/Icon/index';
import { RightOutlined } from '@ant-design/icons-vue';
import { appStore } from '/@/store/modules/app';
......@@ -57,18 +56,11 @@ export default defineComponent({
/**
* @description: 渲染图标
*/
function renderIcon() {
const { tabItem } = props;
if (!tabItem) return;
const icon = tabItem.meta && tabItem.meta.icon;
if (!icon || !unref(getProjectConfigRef).multiTabsSetting.showIcon) return null;
return <Icon icon={icon} class="align-middle " style={{ marginBottom: '2px' }} />;
}
function renderTabContent() {
const { tabItem: { meta } = {} } = props;
return (
<div class={`multiple-tabs-content__content `} onContextmenu={handleContextMenu}>
{renderIcon()}
<span class="ml-1">{meta && meta.title}</span>
</div>
);
......
import { ContentEnum, RouterTransitionEnum, ThemeEnum } from '/@/enums/appEnum';
import { TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum';
import { MenuModeEnum, MenuTypeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum';
import mixImg from '/@/assets/images/layout/menu-mix.svg';
import sidebarImg from '/@/assets/images/layout/menu-sidebar.svg';
import menuTopImg from '/@/assets/images/layout/menu-top.svg';
export enum HandlerEnum {
CHANGE_LAYOUT,
......@@ -15,6 +19,7 @@ export enum HandlerEnum {
MENU_THEME,
MENU_SPLIT,
MENU_SHOW_SEARCH,
MENU_FIXED,
// header
HEADER_SHOW,
......@@ -23,7 +28,6 @@ export enum HandlerEnum {
TABS_SHOW_QUICK,
TABS_SHOW,
TABS_SHOW_ICON,
OPEN_PAGE_LOADING,
OPEN_ROUTE_TRANSITION,
......@@ -36,6 +40,7 @@ export enum HandlerEnum {
GRAY_MODE,
COLOR_WEAK,
SHOW_LOGO,
SHOW_FOOTER,
}
export const themeOptions = [
......@@ -102,3 +107,25 @@ export const routerTransitionOptions = [
value: item,
};
});
export const menuTypeList = [
{
title: '左侧菜单模式',
mode: MenuModeEnum.INLINE,
type: MenuTypeEnum.SIDEBAR,
src: sidebarImg,
},
{
title: '混合模式',
mode: MenuModeEnum.INLINE,
type: MenuTypeEnum.MIX,
src: mixImg,
},
{
title: '顶部菜单模式',
mode: MenuModeEnum.HORIZONTAL,
type: MenuTypeEnum.TOP_MENU,
src: menuTopImg,
},
];
import { HandlerEnum } from './const';
// import { MenuThemeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { HandlerEnum } from './enum';
import {
updateColorWeak,
updateGrayMode,
......@@ -19,12 +18,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
case HandlerEnum.CHANGE_LAYOUT:
const { mode, type, split } = value;
const splitOpt = split === undefined ? { split } : {};
// let headerSetting = {};
// if (type === MenuTypeEnum.TOP_MENU) {
// headerSetting = {
// theme: MenuThemeEnum.DARK,
// };
// }
return {
menuSetting: {
mode,
......@@ -33,159 +27,103 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
show: true,
...splitOpt,
},
// headerSetting,
};
case HandlerEnum.MENU_HAS_DRAG:
return {
menuSetting: {
hasDrag: value,
},
};
return { menuSetting: { hasDrag: value } };
case HandlerEnum.MENU_ACCORDION:
return {
menuSetting: {
accordion: value,
},
};
return { menuSetting: { accordion: value } };
case HandlerEnum.MENU_TRIGGER:
return {
menuSetting: {
trigger: value,
},
};
return { menuSetting: { trigger: value } };
case HandlerEnum.MENU_TOP_ALIGN:
return {
menuSetting: {
topMenuAlign: value,
},
};
return { menuSetting: { topMenuAlign: value } };
case HandlerEnum.MENU_COLLAPSED:
return {
menuSetting: {
collapsed: value,
},
};
return { menuSetting: { collapsed: value } };
case HandlerEnum.MENU_WIDTH:
return {
menuSetting: {
menuWidth: value,
},
};
return { menuSetting: { menuWidth: value } };
case HandlerEnum.MENU_COLLAPSED_SHOW_TITLE:
return {
menuSetting: {
collapsedShowTitle: value,
},
};
return { menuSetting: { collapsedShowTitle: value } };
case HandlerEnum.MENU_SHOW_SIDEBAR:
return {
menuSetting: {
show: value,
},
};
return { menuSetting: { show: value } };
case HandlerEnum.MENU_THEME:
updateSidebarBgColor(value);
return {
menuBgColor: value,
// menuSetting: {
// theme: value,
// },
};
return { menuSetting: { bgColor: value } };
case HandlerEnum.MENU_SPLIT:
return {
menuSetting: {
split: value,
},
};
return { menuSetting: { split: value } };
case HandlerEnum.MENU_FIXED:
return { menuSetting: { fixed: value } };
case HandlerEnum.MENU_SHOW_SEARCH:
return {
menuSetting: {
showSearch: value,
},
};
return { menuSetting: { showSearch: value } };
// ============root==================
case HandlerEnum.OPEN_PAGE_LOADING:
return {
openPageLoading: value,
};
appStore.commitPageLoadingState(false);
return { openPageLoading: value };
case HandlerEnum.OPEN_ROUTE_TRANSITION:
return {
openRouterTransition: value,
};
return { openRouterTransition: value };
case HandlerEnum.ROUTER_TRANSITION:
return {
routerTransition: value,
};
return { routerTransition: value };
case HandlerEnum.LOCK_TIME:
return {
lockTime: value,
};
return { lockTime: value };
case HandlerEnum.FULL_CONTENT:
return {
fullContent: value,
};
return { fullContent: value };
case HandlerEnum.CONTENT_MODE:
return {
contentMode: value,
};
return { contentMode: value };
case HandlerEnum.SHOW_BREADCRUMB:
return {
showBreadCrumb: value,
};
return { showBreadCrumb: value };
case HandlerEnum.SHOW_BREADCRUMB_ICON:
return {
showBreadCrumbIcon: value,
};
return { showBreadCrumbIcon: value };
case HandlerEnum.GRAY_MODE:
updateGrayMode(value);
return {
grayMode: value,
};
return { grayMode: value };
case HandlerEnum.SHOW_FOOTER:
return { showFooter: value };
case HandlerEnum.COLOR_WEAK:
updateColorWeak(value);
return {
colorWeak: value,
};
return { colorWeak: value };
case HandlerEnum.SHOW_LOGO:
return {
showLogo: value,
};
return { showLogo: value };
// ============tabs==================
case HandlerEnum.TABS_SHOW_QUICK:
return {
multiTabsSetting: {
showQuick: value,
},
};
case HandlerEnum.TABS_SHOW_ICON:
return {
multiTabsSetting: {
showIcon: value,
},
};
return { multiTabsSetting: { showQuick: value } };
case HandlerEnum.TABS_SHOW:
return {
multiTabsSetting: {
show: value,
},
};
return { multiTabsSetting: { show: value } };
// ============header==================
case HandlerEnum.HEADER_THEME:
updateHeaderBgColor(value);
return {
headerBgColor: value,
};
return { headerSetting: { bgColor: value } };
case HandlerEnum.HEADER_FIXED:
return {
headerSetting: {
fixed: value,
},
};
return { headerSetting: { fixed: value } };
case HandlerEnum.HEADER_SHOW:
return {
headerSetting: {
show: value,
},
};
return { headerSetting: { show: value } };
default:
return {};
}
......
......@@ -10,7 +10,7 @@
import SettingDrawer from './SettingDrawer';
import { useDrawer } from '/@/components/Drawer';
//
export default defineComponent({
name: 'SettingBtn',
components: { SettingOutlined, SettingDrawer },
......
import './index.less';
import { computed, defineComponent, ref, unref } from 'vue';
import { Layout } from 'ant-design-vue';
import LayoutMenu from '/@/layouts/default/menu/LayoutMenu';
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider';
export default defineComponent({
name: 'LayoutSideBar',
setup() {
const dragBarRef = ref<Nullable<HTMLDivElement>>(null);
const sideRef = ref<Nullable<HTMLDivElement>>(null);
const { getCollapsed, getMenuWidth, getSplit, getTheme } = useMenuSetting();
const { getTriggerAttr, getTriggerSlot } = useTrigger();
const { renderDragLine } = useDragLine(sideRef, dragBarRef);
const {
getCollapsedWidth,
onBreakpointChange,
onCollapseChange,
onSiderClick,
} = useSiderEvent();
const getMode = computed(() => {
return unref(getSplit) ? MenuModeEnum.INLINE : null;
});
const getSplitType = computed(() => {
return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE;
});
function renderDefault() {
return (
<>
<LayoutMenu
theme={unref(getTheme)}
menuMode={unref(getMode)}
splitType={unref(getSplitType)}
/>
{renderDragLine()}
</>
);
}
return () => {
return (
<Layout.Sider
ref={sideRef}
class="layout-sidebar"
breakpoint="md"
collapsible
width={unref(getMenuWidth)}
collapsed={unref(getCollapsed)}
collapsedWidth={unref(getCollapsedWidth)}
theme={unref(getTheme)}
onClick={onSiderClick}
onCollapse={onCollapseChange}
onBreakpoint={onBreakpointChange}
{...unref(getTriggerAttr)}
>
{{
...unref(getTriggerSlot),
default: () => renderDefault(),
}}
</Layout.Sider>
);
};
},
});
@import (reference) '../../../design/index.less';
.layout-sidebar {
background-size: 100% 100%;
overflow: hidden;
&.fixed {
position: fixed;
top: 0;
left: 0;
height: 100%;
}
&.ant-layout-sider-dark {
background: @sider-dark-bg-color;
......@@ -9,6 +16,7 @@
&:not(.ant-layout-sider-dark) {
border-right: 1px solid @border-color-light;
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
}
.ant-layout-sider-zero-width-trigger {
......
import './index.less';
import { computed, defineComponent, ref, unref, watch, nextTick } from 'vue';
import { Layout } from 'ant-design-vue';
import LayoutMenu from '../menu';
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider';
import { useLayoutContext } from '../useLayoutContext';
export default defineComponent({
name: 'LayoutSideBar',
setup() {
const topRef = ref(0);
const dragBarRef = ref<ElRef>(null);
const sideRef = ref<ElRef>(null);
const {
getCollapsed,
getMenuWidth,
getSplit,
getMenuTheme,
getRealWidth,
getMenuHidden,
getMenuFixed,
} = useMenuSetting();
const { getShowFullHeaderRef, getUnFixedAndFull } = useHeaderSetting();
const injectValue = useLayoutContext();
const { getTriggerAttr, getTriggerSlot } = useTrigger();
const { renderDragLine } = useDragLine(sideRef, dragBarRef);
const {
getCollapsedWidth,
onBreakpointChange,
onCollapseChange,
onSiderClick,
} = useSiderEvent();
const getMode = computed(() => {
return unref(getSplit) ? MenuModeEnum.INLINE : null;
});
const getSplitType = computed(() => {
return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE;
});
const showClassSideBarRef = computed(() => {
return unref(getSplit) ? unref(getMenuHidden) : true;
});
const getSiderClass = computed(() => {
return {
'layout-sidebar': true,
fixed: unref(getMenuFixed),
hidden: !unref(showClassSideBarRef),
};
});
const getSiderStyle = computed(() => {
const top = `${unref(topRef)}px`;
if (!unref(getMenuFixed)) {
return { top };
}
return {
top,
height: `calc(100% - ${top})`,
};
});
watch(
() => getShowFullHeaderRef.value,
() => {
topRef.value = 0;
if (unref(getUnFixedAndFull)) return;
nextTick(() => {
const fullHeaderEl = unref(injectValue.fullHeaderRef)?.$el;
if (!fullHeaderEl) return;
topRef.value = fullHeaderEl.offsetHeight;
});
},
{
immediate: true,
}
);
const getHiddenDomStyle = computed(() => {
const width = `${unref(getRealWidth)}px`;
return {
width: width,
overflow: 'hidden',
flex: `0 0 ${width}`,
'max-width': width,
'min-width': width,
transition: 'all 0.2s',
};
});
function renderDefault() {
return (
<>
<LayoutMenu
theme={unref(getMenuTheme)}
menuMode={unref(getMode)}
splitType={unref(getSplitType)}
/>
{renderDragLine()}
</>
);
}
return () => {
return (
<>
{unref(getMenuFixed) && (
<div style={unref(getHiddenDomStyle)} class={{ hidden: !unref(showClassSideBarRef) }} />
)}
<Layout.Sider
ref={sideRef}
breakpoint="md"
collapsible
class={unref(getSiderClass)}
style={unref(getSiderStyle)}
width={unref(getMenuWidth)}
collapsed={unref(getCollapsed)}
collapsedWidth={unref(getCollapsedWidth)}
theme={unref(getMenuTheme)}
onClick={onSiderClick}
onCollapse={onCollapseChange}
onBreakpoint={onBreakpointChange}
{...unref(getTriggerAttr)}
>
{{
...unref(getTriggerSlot),
default: () => renderDefault(),
}}
</Layout.Sider>
</>
);
};
},
});
......@@ -16,7 +16,7 @@ export function useSiderEvent() {
const brokenRef = ref(false);
const collapseRef = ref(true);
const { setMenuSetting, getCollapsed, getMiniWidthNumber, getShow } = useMenuSetting();
const { setMenuSetting, getCollapsed, getMiniWidthNumber, getShowMenu } = useMenuSetting();
const getCollapsedWidth = computed(() => {
return unref(brokenRef) ? 0 : unref(getMiniWidthNumber);
......@@ -38,7 +38,7 @@ export function useSiderEvent() {
function onSiderClick(e: ChangeEvent) {
if (!e || !e.target || e.target.className !== 'basic-menu__content') return;
if (!unref(getCollapsed) || !unref(getShow)) return;
if (!unref(getCollapsed) || !unref(getShowMenu)) return;
setMenuSetting({ collapsed: false });
}
return { getCollapsedWidth, onCollapseChange, onBreakpointChange, onSiderClick };
......
import { InjectionKey, Ref } from 'vue';
import { createContext, useContext } from '/@/hooks/core/useContext';
export interface LayoutContextProps {
fullHeaderRef: Ref<ComponentRef>;
}
const layoutContextInjectKey: InjectionKey<LayoutContextProps> = Symbol();
export function createLayoutContext(context: LayoutContextProps) {
return createContext<LayoutContextProps>(context, layoutContextInjectKey);
}
export function useLayoutContext() {
return useContext<LayoutContextProps>(layoutContextInjectKey);
}
......@@ -12,7 +12,7 @@ import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
export function useFrameKeepAlive() {
const { currentRoute } = useRouter();
const { getShow } = useMultipleTabSetting();
const { getShowMultipleTab } = useMultipleTabSetting();
const getFramePages = computed(() => {
const ret =
......@@ -49,7 +49,7 @@ export function useFrameKeepAlive() {
}
function hasRenderFrame(path: string) {
return unref(getShow) ? unref(getOpenTabList).includes(path) : true;
return unref(getShowMultipleTab) ? unref(getOpenTabList).includes(path) : true;
}
return { hasRenderFrame, getFramePages, showIframe, getAllFramePages };
}
......@@ -20,7 +20,7 @@ interface DefaultContext {
export default defineComponent({
name: 'PageLayout',
setup() {
const { getShow } = useMenuSetting();
const { getShowMenu } = useMenuSetting();
const {
getOpenKeepAlive,
getRouterTransition,
......@@ -32,7 +32,7 @@ export default defineComponent({
const transitionEvent = useTransition();
const openCacheRef = computed(() => unref(getOpenKeepAlive) && unref(getShow));
const openCacheRef = computed(() => unref(getOpenKeepAlive) && unref(getShowMenu));
const getCacheTabsRef = computed(() => tabStore.getKeepAliveTabsState as string[]);
......
......@@ -21,12 +21,6 @@ const setting: ProjectConfig = {
// TODO 主题色
themeColor: primaryColor,
// header bg color
headerBgColor: '#ffffff',
// sidebar menu bg color
menuBgColor: '#273352',
// Whether to show the configuration button
showSettingButton: true,
......@@ -48,8 +42,13 @@ const setting: ProjectConfig = {
// 是否显示logo
showLogo: true,
// 是否显示页脚
showFooter: true,
// 头部配置
headerSetting: {
// header bg color
bgColor: '#ffffff',
fixed: true,
// 是否显示顶部
show: true,
......@@ -69,6 +68,10 @@ const setting: ProjectConfig = {
// 菜单配置
menuSetting: {
// sidebar menu bg color
bgColor: '#273352',
fixed: true,
// 菜单折叠
collapsed: false,
// 折叠菜单时候是否显示菜单名
......@@ -107,8 +110,7 @@ const setting: ProjectConfig = {
show: true,
// 开启快速操作
showQuick: true,
// 显示icon
showIcon: false,
// 标签页缓存最大数量
max: 12,
},
......
......@@ -2,3 +2,5 @@
export const GITHUB_URL = 'https://github.com/anncwb/vue-vben-admin';
// vue-vben-admin-next-doc
export const DOC_URL = 'https://vvbin.cn/doc-next/';
// site url
export const SITE_URL = 'https://vvbin.cn/next/';
......@@ -53,7 +53,12 @@ export function initAppConfigStore() {
if (!projCfg) {
projCfg = projectSetting;
}
const { colorWeak, grayMode, headerBgColor, menuBgColor } = projCfg;
const {
colorWeak,
grayMode,
headerSetting: { bgColor: headerBgColor },
menuSetting: { bgColor },
} = projCfg;
try {
// if (
// themeColor !== primaryColor &&
......@@ -63,7 +68,7 @@ export function initAppConfigStore() {
// updateTheme(themeColor);
// }
headerBgColor && updateHeaderBgColor(headerBgColor);
menuBgColor && updateSidebarBgColor(menuBgColor);
bgColor && updateSidebarBgColor(bgColor);
grayMode && updateGrayMode(grayMode);
colorWeak && updateColorWeak(colorWeak);
} catch (error) {
......
......@@ -4,6 +4,8 @@ import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from
import type { LocaleType } from '/@/locales/types';
export interface MenuSetting {
bgColor: string;
fixed: boolean;
collapsed: boolean;
collapsedShowTitle: boolean;
hasDrag: boolean;
......@@ -26,13 +28,13 @@ export interface MultiTabsSetting {
show: boolean;
// 开启快速操作
showQuick: boolean;
// 显示icon
showIcon: boolean;
// 缓存最大数量
max: number;
}
export interface HeaderSetting {
bgColor: string;
fixed: boolean;
show: boolean;
theme: ThemeEnum;
......@@ -59,10 +61,7 @@ export interface LocaleSetting {
export interface ProjectConfig {
locale: LocaleSetting;
// header背景色
headerBgColor: string;
// 左侧菜单背景色
menuBgColor: string;
// 是否显示配置按钮
showSettingButton: boolean;
// 权限模式
......@@ -79,6 +78,7 @@ export interface ProjectConfig {
contentMode: ContentEnum;
// 是否显示logo
showLogo: boolean;
showFooter: boolean;
headerSetting: HeaderSetting;
// 菜单类型
// menuType: MenuTypeEnum;
......
......@@ -55,3 +55,11 @@ declare type TargetContext = '_self' | '_blank';
declare type TimeoutHandle = ReturnType<typeof setTimeout>;
declare type IntervalHandle = ReturnType<typeof setInterval>;
declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> {
$el: T;
}
declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null;
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>;
......@@ -1737,21 +1737,6 @@
vscode-languageserver-textdocument "^1.0.1"
vscode-uri "^2.1.2"
"@vueuse/core@^4.0.0-rc.3":
version "4.0.0-rc.3"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.0.0-rc.3.tgz#5381ca657e10df596cd7027fc5c96b2d4b3a090c"
integrity sha512-dQ/FZgo0z7kBFOvDWxuzaUrmuO8X1AlQk17e3PU1TVtG2Uu+mCvjPNbuvI2fjhTjl5rzPJawwoU2WZFj+nlFvw==
dependencies:
"@vueuse/shared" "4.0.0-rc.3"
vue-demi latest
"@vueuse/shared@4.0.0-rc.3":
version "4.0.0-rc.3"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.0.0-rc.3.tgz#42fb56fed3779f3b8a17a82c16a364bad20d01b7"
integrity sha512-VY0x/XxpeTMHp/0FDiv1cgUUxkJGQl7liiM2AjR/J7+Ys/2Y2dijD5cAKViq9FGUPQQsOcLptMvMvUsDMoN4DA==
dependencies:
vue-demi latest
JSONStream@^1.0.4:
version "1.3.5"
resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
......@@ -8177,11 +8162,6 @@ vscode-uri@^2.1.2:
resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c"
integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==
vue-demi@latest:
version "0.4.3"
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.4.3.tgz#6aaa9b52f02c32b4f9d4d11f02a1ae71031453c3"
integrity sha512-1DzLcZgHC9ZyFEYR4qZ83TdS1u9DglG8XVesBXqtbbmqFuO7sb8KG36kMfZCszieAweRDwAAVSAzjmEMG0+WwA==
vue-eslint-parser@^7.1.1:
version "7.1.1"
resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.1.1.tgz#c43c1c715ff50778b9a7e9a4e16921185f3425d3"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册