refactor: refactor layout

This commit is contained in:
vben
2020-11-24 22:59:29 +08:00
parent 25d43a5f7c
commit 0692b4798c
51 changed files with 1243 additions and 912 deletions

View File

@@ -1,29 +1,36 @@
import { defineComponent, computed, unref, ref } from 'vue';
import { BasicDrawer } from '/@/components/Drawer/index';
import { Divider, Switch, Tooltip, InputNumber, Select } from 'ant-design-vue';
import Button from '/@/components/Button/index.vue';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue';
import { appStore } from '/@/store/modules/app';
import { ProjectConfig } from '/@/types/config';
import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import type { ProjectConfig } from '/@/types/config';
import defaultSetting from '/@/settings/projectSetting';
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';
import { defineComponent, computed, unref, FunctionalComponent } from 'vue';
import { BasicDrawer } from '/@/components/Drawer/index';
import { Divider, Switch, Tooltip, InputNumber, Select } from 'ant-design-vue';
import Button from '/@/components/Button/index.vue';
import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue';
import { MenuTypeEnum } from '/@/enums/menuEnum';
import { appStore } from '/@/store/modules/app';
import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
import { baseHandler } from './handler';
import {
HandlerEnum,
contentModeOptions,
topMenuAlignOptions,
menuTriggerOptions,
routerTransitionOptions,
} from './const';
menuTypeList,
} from './enum';
import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST } from '/@/settings/colorSetting';
interface SwitchOptions {
@@ -40,215 +47,280 @@ interface SelectConfig {
handler?: Fn;
}
interface ThemeOptions {
def?: string;
handler?: Fn;
interface ThemePickerProps {
colorList: string[];
handler: Fn;
def: string;
}
const { createSuccessModal, createMessage } = useMessage();
/**
* Menu type Picker comp
*/
const MenuTypePicker: FunctionalComponent = () => {
const { getIsHorizontal, getMenuType } = useMenuSetting();
return (
<div class={`setting-drawer__siderbar`}>
{menuTypeList.map((item) => {
const { title, type: ItemType, mode, src } = item;
return (
<Tooltip title={title} placement="bottom" key={title}>
{{
default: () => (
<div
onClick={baseHandler.bind(null, HandlerEnum.CHANGE_LAYOUT, {
mode: mode,
type: ItemType,
split: unref(getIsHorizontal) ? false : undefined,
})}
>
<CheckOutlined
class={['check-icon', unref(getMenuType) === ItemType ? 'active' : '']}
/>
<img src={src} />
</div>
),
}}
</Tooltip>
);
})}
</div>
);
};
const ThemePicker: FunctionalComponent<ThemePickerProps> = (props) => {
return (
<div class={`setting-drawer__theme-item`}>
{props.colorList.map((color) => {
return (
<span
onClick={() => props.handler?.(color)}
key={color}
class={[props.def === color ? 'active' : '']}
style={{
background: color,
}}
>
<CheckOutlined class="icon" />
</span>
);
})}
</div>
);
};
/**
* FooterButton component
*/
const FooterButton: FunctionalComponent = () => {
const { getRootSetting } = useRootSetting();
function handleCopy() {
const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
unref(isSuccessRef) &&
createSuccessModal({
title: '操作成功',
content: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!',
});
}
function handleResetSetting() {
try {
appStore.commitProjectConfigState(defaultSetting);
const { colorWeak, grayMode } = defaultSetting;
// updateTheme(themeColor);
updateColorWeak(colorWeak);
updateGrayMode(grayMode);
createMessage.success('重置成功!');
} catch (error) {
createMessage.error(error);
}
}
function handleClearAndRedo() {
localStorage.clear();
appStore.resumeAllState();
location.reload();
}
return (
<div class="setting-drawer__footer">
<Button type="primary" block onClick={handleCopy}>
{() => (
<>
<CopyOutlined class="mr-2" />
</>
)}
</Button>
<Button block class="mt-2" onClick={handleResetSetting} color="warning">
{() => (
<>
<RedoOutlined class="mr-2" />
</>
)}
</Button>
<Button block class="mt-2" onClick={handleClearAndRedo} color="error">
{() => (
<>
<RedoOutlined class="mr-2" />
</>
)}
</Button>
</div>
);
};
export default defineComponent({
name: 'SettingDrawer',
setup(_, { attrs }) {
const { createSuccessModal, createMessage } = useMessage();
const {
getContentMode,
getRouterTransition,
getOpenRouterTransition,
getOpenPageLoading,
getShowFooter,
getShowBreadCrumb,
getShowBreadCrumbIcon,
getShowLogo,
getFullContent,
getColorWeak,
getGrayMode,
} = useRootSetting();
const getProjectConfigRef = computed(() => {
return appStore.getProjectConfig;
});
const {
getIsHorizontal,
getShowMenu,
getMenuType,
getTrigger,
getCollapsedShowTitle,
getMenuFixed,
getCollapsed,
getShowSearch,
getHasDrag,
getTopMenuAlign,
getAccordion,
getMenuWidth,
getMenuBgColor,
getIsTopMenu,
getSplit,
} = useMenuSetting();
const getIsHorizontalRef = computed(() => {
return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
});
const { getShowHeader, getFixed: getHeaderFixed, getHeaderBgColor } = useHeaderSetting();
const getShowHeaderRef = computed(() => {
return unref(getProjectConfigRef).headerSetting.show;
});
const { getShowMultipleTab, getShowQuick } = useMultipleTabSetting();
const getShowMenuRef = computed(() => {
return unref(getProjectConfigRef).menuSetting.show && !unref(getIsHorizontalRef);
return unref(getShowMenu) && !unref(getIsHorizontal);
});
const getShowTabsRef = computed(() => {
return unref(getProjectConfigRef).multiTabsSetting.show;
});
function handleCopy() {
const { isSuccessRef } = useCopyToClipboard(
JSON.stringify(unref(getProjectConfigRef), null, 2)
);
unref(isSuccessRef) &&
createSuccessModal({
title: '操作成功',
content: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!',
});
}
function handleResetSetting() {
try {
appStore.commitProjectConfigState(defaultSetting);
const { colorWeak, grayMode } = defaultSetting;
// updateTheme(themeColor);
updateColorWeak(colorWeak);
updateGrayMode(grayMode);
createMessage.success('重置成功!');
} catch (error) {
createMessage.error(error);
}
}
function handleClearAndRedo() {
localStorage.clear();
appStore.resumeAllState();
location.reload();
}
function renderSidebar() {
const {
menuSetting: { type, split },
} = unref(getProjectConfigRef);
const typeList = ref([
{
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,
},
]);
return [
<div class={`setting-drawer__siderbar`}>
{unref(typeList).map((item) => {
const { title, type: ItemType, mode, src } = item;
return (
<Tooltip title={title} placement="bottom" key={title}>
{{
default: () => (
<div
onClick={baseHandler.bind(null, HandlerEnum.CHANGE_LAYOUT, {
mode: mode,
type: ItemType,
split: unref(getIsHorizontalRef) ? false : undefined,
})}
>
<CheckOutlined class={['check-icon', type === ItemType ? 'active' : '']} />
<img src={src} />
</div>
),
}}
</Tooltip>
);
return (
<>
<MenuTypePicker />
{renderSwitchItem('分割菜单', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_SPLIT, e);
},
def: unref(getSplit),
disabled: !unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX,
})}
</div>,
renderSwitchItem('分割菜单', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_SPLIT, e);
},
def: split,
disabled: !unref(getShowMenuRef) || type !== MenuTypeEnum.MIX,
}),
// renderSelectItem('顶栏主题', {
// handler: (e) => {
// baseHandler(HandlerEnum.HEADER_THEME, e);
// },
// def: headerTheme,
// options: themeOptions,
// disabled: !unref(getShowHeaderRef),
// }),
// renderSelectItem('菜单主题', {
// handler: (e) => {
// baseHandler(HandlerEnum.MENU_THEME, e);
// },
// def: menuTheme,
// options: themeOptions,
// disabled: !unref(getShowMenuRef),
// }),
];
</>
);
}
function renderTheme() {
return (
<>
<Divider>{() => '顶栏主题'}</Divider>
<ThemePicker
colorList={HEADER_PRESET_BG_COLOR_LIST}
def={unref(getHeaderBgColor)}
handler={(e) => {
baseHandler(HandlerEnum.HEADER_THEME, e);
}}
/>
<Divider>{() => '菜单主题'}</Divider>
<ThemePicker
colorList={SIDE_BAR_BG_COLOR_LIST}
def={unref(getMenuBgColor)}
handler={(e) => {
baseHandler(HandlerEnum.MENU_THEME, e);
}}
/>
</>
);
}
/**
* @description:
*/
function renderFeatures() {
const {
contentMode,
headerSetting: { fixed },
menuSetting: {
hasDrag,
collapsed,
showSearch,
menuWidth,
topMenuAlign,
collapsedShowTitle,
trigger,
accordion,
} = {},
} = appStore.getProjectConfig;
return [
renderSwitchItem('侧边菜单拖拽', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
},
def: hasDrag,
def: unref(getHasDrag),
disabled: !unref(getShowMenuRef),
}),
renderSwitchItem('侧边菜单搜索', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e);
},
def: showSearch,
def: unref(getShowSearch),
disabled: !unref(getShowMenuRef),
}),
renderSwitchItem('侧边菜单手风琴模式', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_ACCORDION, e);
},
def: accordion,
def: unref(getAccordion),
disabled: !unref(getShowMenuRef),
}),
renderSwitchItem('折叠菜单', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_COLLAPSED, e);
},
def: collapsed,
def: unref(getCollapsed),
disabled: !unref(getShowMenuRef),
}),
renderSwitchItem('折叠菜单显示名称', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e);
},
def: collapsedShowTitle,
disabled: !unref(getShowMenuRef) || !collapsed,
def: unref(getCollapsedShowTitle),
disabled: !unref(getShowMenuRef) || !unref(getCollapsed),
}),
renderSwitchItem('固定header', {
handler: (e) => {
baseHandler(HandlerEnum.HEADER_FIXED, e);
},
def: fixed,
disabled: !unref(getShowHeaderRef),
def: unref(getHeaderFixed),
disabled: !unref(getShowHeader),
}),
renderSwitchItem('固定Siderbar', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_FIXED, e);
},
def: unref(getMenuFixed),
disabled: !unref(getShowMenuRef),
}),
renderSelectItem('顶部菜单布局', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_TOP_ALIGN, e);
},
def: topMenuAlign,
def: unref(getTopMenuAlign),
options: topMenuAlignOptions,
disabled: !unref(getShowHeaderRef),
disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)),
}),
renderSelectItem('菜单折叠按钮', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_TRIGGER, e);
},
def: trigger,
disabled: !unref(getShowMenuRef),
def: unref(getTrigger),
options: menuTriggerOptions,
}),
@@ -256,7 +328,7 @@ export default defineComponent({
handler: (e) => {
baseHandler(HandlerEnum.CONTENT_MODE, e);
},
def: contentMode,
def: unref(getContentMode),
options: contentModeOptions,
}),
<div class={`setting-drawer__cell-item`}>
@@ -286,7 +358,7 @@ export default defineComponent({
min={100}
step={10}
disabled={!unref(getShowMenuRef)}
defaultValue={menuWidth}
defaultValue={unref(getMenuWidth)}
formatter={(value: string) => `${parseInt(value)}px`}
onChange={(e: any) => {
baseHandler(HandlerEnum.MENU_WIDTH, e);
@@ -295,120 +367,111 @@ export default defineComponent({
</div>,
];
}
function renderTransition() {
const { routerTransition, openRouterTransition, openPageLoading } = appStore.getProjectConfig;
function renderContent() {
return [
renderSwitchItem('面包屑', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
},
def: unref(getShowBreadCrumb),
disabled: !unref(getShowHeader),
}),
renderSwitchItem('面包屑图标', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
},
def: unref(getShowBreadCrumbIcon),
disabled: !unref(getShowHeader),
}),
renderSwitchItem('标签页', {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW, e);
},
def: unref(getShowMultipleTab),
}),
renderSwitchItem('标签页快捷按钮', {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
},
def: unref(getShowQuick),
disabled: !unref(getShowMultipleTab),
}),
renderSwitchItem('左侧菜单', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
},
def: unref(getShowMenu),
disabled: unref(getIsHorizontal),
}),
renderSwitchItem('顶栏', {
handler: (e) => {
baseHandler(HandlerEnum.HEADER_SHOW, e);
},
def: unref(getShowHeader),
}),
renderSwitchItem('Logo', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_LOGO, e);
},
def: unref(getShowLogo),
}),
renderSwitchItem('页脚', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_FOOTER, e);
},
def: unref(getShowFooter),
}),
renderSwitchItem('全屏内容', {
handler: (e) => {
baseHandler(HandlerEnum.FULL_CONTENT, e);
},
def: unref(getFullContent),
}),
renderSwitchItem('灰色模式', {
handler: (e) => {
baseHandler(HandlerEnum.GRAY_MODE, e);
},
def: unref(getGrayMode),
}),
renderSwitchItem('色弱模式', {
handler: (e) => {
baseHandler(HandlerEnum.COLOR_WEAK, e);
},
def: unref(getColorWeak),
}),
];
}
function renderTransition() {
return (
<>
{renderSwitchItem('页面切换loading', {
handler: (e) => {
baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
},
def: openPageLoading,
def: unref(getOpenPageLoading),
})}
{renderSwitchItem('切换动画', {
handler: (e) => {
baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e);
},
def: openRouterTransition,
def: unref(getOpenRouterTransition),
})}
{renderSelectItem('路由动画', {
handler: (e) => {
baseHandler(HandlerEnum.ROUTER_TRANSITION, e);
},
def: routerTransition,
def: unref(getRouterTransition),
options: routerTransitionOptions,
disabled: !openRouterTransition,
disabled: !unref(getOpenRouterTransition),
})}
</>
);
}
function renderContent() {
const {
grayMode,
colorWeak,
fullContent,
showLogo,
headerSetting: { show: showHeader },
menuSetting: { show: showMenu },
multiTabsSetting: { show: showMultiple, showQuick, showIcon: showTabIcon },
showBreadCrumb,
showBreadCrumbIcon,
} = unref(getProjectConfigRef);
return [
renderSwitchItem('面包屑', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
},
def: showBreadCrumb,
disabled: !unref(getShowHeaderRef),
}),
renderSwitchItem('面包屑图标', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
},
def: showBreadCrumbIcon,
disabled: !unref(getShowHeaderRef),
}),
renderSwitchItem('标签页', {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW, e);
},
def: showMultiple,
}),
renderSwitchItem('标签页快捷按钮', {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
},
def: showQuick,
disabled: !unref(getShowTabsRef),
}),
renderSwitchItem('标签页图标', {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW_ICON, e);
},
def: showTabIcon,
disabled: !unref(getShowTabsRef),
}),
renderSwitchItem('左侧菜单', {
handler: (e) => {
baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
},
def: showMenu,
disabled: unref(getIsHorizontalRef),
}),
renderSwitchItem('顶栏', {
handler: (e) => {
baseHandler(HandlerEnum.HEADER_SHOW, e);
},
def: showHeader,
}),
renderSwitchItem('Logo', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_LOGO, e);
},
def: showLogo,
}),
renderSwitchItem('全屏内容', {
handler: (e) => {
baseHandler(HandlerEnum.FULL_CONTENT, e);
},
def: fullContent,
}),
renderSwitchItem('灰色模式', {
handler: (e) => {
baseHandler(HandlerEnum.GRAY_MODE, e);
},
def: grayMode,
}),
renderSwitchItem('色弱模式', {
handler: (e) => {
baseHandler(HandlerEnum.COLOR_WEAK, e);
},
def: colorWeak,
}),
];
}
function renderSelectItem(text: string, config?: SelectConfig) {
const { handler, def, disabled = false, options } = config || {};
@@ -449,50 +512,6 @@ export default defineComponent({
);
}
function renderTheme() {
const { headerBgColor, menuBgColor } = unref(getProjectConfigRef);
return (
<>
<Divider>{() => '顶栏主题'}</Divider>
{renderThemeItem(HEADER_PRESET_BG_COLOR_LIST, {
def: headerBgColor,
handler: (e) => {
baseHandler(HandlerEnum.HEADER_THEME, e);
},
})}
<Divider>{() => '菜单主题'}</Divider>
{renderThemeItem(SIDE_BAR_BG_COLOR_LIST, {
def: menuBgColor,
handler: (e) => {
baseHandler(HandlerEnum.MENU_THEME, e);
},
})}
</>
);
}
function renderThemeItem(colorList: string[], opt: ThemeOptions) {
const { def, handler } = opt;
return (
<div class={`setting-drawer__theme-item`}>
{colorList.map((item) => {
return (
<span
onClick={() => handler && handler(item)}
key={item}
class={[def === item ? 'active' : '']}
style={{
background: item,
}}
>
<CheckOutlined class="icon" />
</span>
);
})}
</div>
);
}
return () => (
<BasicDrawer {...attrs} title="项目配置" width={300} wrapClassName="setting-drawer">
{{
@@ -500,9 +519,7 @@ export default defineComponent({
<>
<Divider>{() => '导航栏模式'}</Divider>
{renderSidebar()}
{renderTheme()}
<Divider>{() => '界面功能'}</Divider>
{renderFeatures()}
<Divider>{() => '界面显示'}</Divider>
@@ -510,32 +527,7 @@ export default defineComponent({
<Divider>{() => '切换动画'}</Divider>
{renderTransition()}
<Divider />
<div class="setting-drawer__footer">
<Button type="primary" block onClick={handleCopy}>
{() => (
<>
<CopyOutlined class="mr-2" />
</>
)}
</Button>
<Button block class="mt-2" onClick={handleResetSetting} color="warning">
{() => (
<>
<RedoOutlined class="mr-2" />
</>
)}
</Button>
<Button block class="mt-2" onClick={handleClearAndRedo} color="error">
{() => (
<>
<RedoOutlined class="mr-2" />
</>
)}
</Button>
</div>
<FooterButton />
</>
),
}}