提交 0e7c57bd 作者: vben

feat(tabs): added tab folding

上级 144ab577
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
- 新增`mixSideFixed`配置。用于固定左侧混合模式菜单 - 新增`mixSideFixed`配置。用于固定左侧混合模式菜单
- modal 组件新增`height``min-height`属性 - modal 组件新增`height``min-height`属性
- 新增`PageWrapper`组件。并应用于示例页面 - 新增`PageWrapper`组件。并应用于示例页面
- 新增标签页折叠功能
### 🐛 Bug Fixes ### 🐛 Bug Fixes
......
...@@ -2,10 +2,18 @@ import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; ...@@ -2,10 +2,18 @@ import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
import userMock from './sys/user'; import userMock from './sys/user';
import menuMock from './sys/menu'; import menuMock from './sys/menu';
import tableDemoMock from './demo/table-demo'; import tableDemoMock from './demo/table-demo';
import accountDemoMock from './demo/account';
import selectDemoMock from './demo/select-demo';
/** /**
* Used in a production environment. Need to manually import all modules * Used in a production environment. Need to manually import all modules
*/ */
export function setupProdMockServer() { export function setupProdMockServer() {
createProdMockServer([...userMock, ...menuMock, ...tableDemoMock]); createProdMockServer([
...userMock,
...menuMock,
...tableDemoMock,
...accountDemoMock,
...selectDemoMock,
]);
} }
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
} }
); );
// watch(() => props.icon, update, { flush: 'post' }); watch(() => props.icon, update, { flush: 'post' });
onMounted(update); onMounted(update);
......
...@@ -16,16 +16,20 @@ export function useOpenKeys( ...@@ -16,16 +16,20 @@ export function useOpenKeys(
mode: Ref<MenuModeEnum>, mode: Ref<MenuModeEnum>,
accordion: Ref<boolean> accordion: Ref<boolean>
) { ) {
const { getCollapsed, getIsMixSidebar, getMixSideFixed } = useMenuSetting(); const { getCollapsed, getIsMixSidebar } = useMenuSetting();
async function setOpenKeys(path: string) { async function setOpenKeys(path: string) {
if (mode.value === MenuModeEnum.HORIZONTAL) { if (mode.value === MenuModeEnum.HORIZONTAL) {
return; return;
} }
const native = unref(getIsMixSidebar) && unref(getMixSideFixed); const native = unref(getIsMixSidebar);
useTimeoutFn( useTimeoutFn(
() => { () => {
const menuList = toRaw(menus.value); const menuList = toRaw(menus.value);
if (menuList?.length === 0) {
menuState.openKeys = [];
return;
}
if (!unref(accordion)) { if (!unref(accordion)) {
menuState.openKeys = es6Unique([ menuState.openKeys = es6Unique([
...menuState.openKeys, ...menuState.openKeys,
......
...@@ -51,7 +51,6 @@ ...@@ -51,7 +51,6 @@
watchEffect, watchEffect,
toRef, toRef,
getCurrentInstance, getCurrentInstance,
nextTick,
} from 'vue'; } from 'vue';
import Modal from './components/Modal'; import Modal from './components/Modal';
...@@ -111,7 +110,6 @@ ...@@ -111,7 +110,6 @@
visible: unref(visibleRef), visible: unref(visibleRef),
title: undefined, title: undefined,
}; };
return { return {
...opt, ...opt,
wrapClassName: unref(getWrapClassName), wrapClassName: unref(getWrapClassName),
......
<template> <template>
<ScrollContainer ref="wrapperRef" :style="wrapStyle"> <ScrollContainer ref="wrapperRef">
<div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip"> <div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip">
<slot /> <slot />
</div> </div>
...@@ -62,19 +62,10 @@ ...@@ -62,19 +62,10 @@
redoModalHeight: setModalHeight, redoModalHeight: setModalHeight,
}); });
const wrapStyle = computed(
(): CSSProperties => {
return {
minHeight: `${props.minHeight}px`,
height: `${unref(realHeightRef)}px`,
// overflow: 'auto',
};
}
);
const spinStyle = computed( const spinStyle = computed(
(): CSSProperties => { (): CSSProperties => {
return { return {
minHeight: `${props.minHeight}px`,
// padding 28 // padding 28
height: `${unref(realHeightRef) - 28}px`, height: `${unref(realHeightRef) - 28}px`,
}; };
...@@ -159,7 +150,7 @@ ...@@ -159,7 +150,7 @@
} }
} }
return { wrapStyle, wrapperRef, spinRef, spinStyle }; return { wrapperRef, spinRef, spinStyle };
}, },
}); });
</script> </script>
...@@ -21,12 +21,9 @@ ...@@ -21,12 +21,9 @@
width: 520px; width: 520px;
padding-bottom: 0; padding-bottom: 0;
.scroll-container { .scrollbar {
padding: 14px; padding: 14px;
} }
// .ant-spin-nested-loading {
// padding: 16px;
// }
&-title { &-title {
font-size: 16px; font-size: 16px;
......
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { addResizeListener, removeResizeListener } from '/@/utils/event/resizeEvent'; import { addResizeListener, removeResizeListener } from '/@/utils/event/resizeEvent';
import componentSetting from '/@/settings/componentSetting';
const { scrollbar } = componentSetting;
import { toObject } from './util'; import { toObject } from './util';
import { import {
defineComponent, defineComponent,
...@@ -38,7 +39,7 @@ ...@@ -38,7 +39,7 @@
props: { props: {
native: { native: {
type: Boolean, type: Boolean,
default: false, default: scrollbar?.native ?? false,
}, },
wrapStyle: { wrapStyle: {
type: [String, Array], type: [String, Array],
......
...@@ -421,7 +421,7 @@ ...@@ -421,7 +421,7 @@
// flex-wrap: wrap; // flex-wrap: wrap;
} }
.scroll-container { .scrollbar {
height: 220px; height: 220px;
} }
} }
......
import type { SorterResult } from './types/table'; import componentSetting from '/@/settings/componentSetting';
const { table } = componentSetting;
const { pageSizeOptions, defaultPageSize, fetchSetting, defaultSortFn, defaultFilterFn } = table;
export const ROW_KEY = 'key'; export const ROW_KEY = 'key';
// 可选的每页显示条数; // 可选的每页显示条数;
export const PAGE_SIZE_OPTIONS = ['10', '50', '80', '100']; export const PAGE_SIZE_OPTIONS = pageSizeOptions;
// 每页显示条数 // 每页显示条数
export const PAGE_SIZE = ~~PAGE_SIZE_OPTIONS[0]; export const PAGE_SIZE = defaultPageSize;
// 通用接口字段设置 // 通用接口字段设置
// 支持 xxx.xxx.xxx格式 export const FETCH_SETTING = fetchSetting;
export const FETCH_SETTING = {
// 传给后台的当前页字段名
pageField: 'page',
// 传给后台的每页显示记录数字段名
sizeField: 'pageSize',
// 接口返回的表格数据字段名
listField: 'items',
// 接口返回的表格总数字段名
totalField: 'total',
};
// 配置通用排序函数 // 配置通用排序函数
export function DEFAULT_SORT_FN(sortInfo: SorterResult) { export const DEFAULT_SORT_FN = defaultSortFn;
const { field, order } = sortInfo;
return { export const DEFAULT_FILTER_FN = defaultFilterFn;
// 传给后台的排序字段你
field,
// 传给后台的排序方式 asc/desc
order,
};
}
export function DEFAULT_FILTER_FN(data: Partial<Recordable<string[]>>) {
return data;
}
// 表格单元格默认布局 // 表格单元格默认布局
export const DEFAULT_ALIGN = 'center'; export const DEFAULT_ALIGN = 'center';
......
...@@ -78,7 +78,9 @@ const getIsMixMode = computed(() => { ...@@ -78,7 +78,9 @@ const getIsMixMode = computed(() => {
}); });
const getRealWidth = computed(() => { const getRealWidth = computed(() => {
return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth); return unref(getCollapsed) && !unref(getMixSideFixed)
? unref(getMiniWidthNumber)
: unref(getMenuWidth);
}); });
const getMiniWidthNumber = computed(() => { const getMiniWidthNumber = computed(() => {
...@@ -94,7 +96,6 @@ const getCalcContentWidth = computed(() => { ...@@ -94,7 +96,6 @@ const getCalcContentWidth = computed(() => {
? SIDE_BAR_SHOW_TIT_MINI_WIDTH + ? SIDE_BAR_SHOW_TIT_MINI_WIDTH +
(unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0) (unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0)
: unref(getRealWidth); : unref(getRealWidth);
return `calc(100% - ${unref(width)}px)`; return `calc(100% - ${unref(width)}px)`;
}); });
......
...@@ -12,6 +12,8 @@ const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick); ...@@ -12,6 +12,8 @@ const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick);
const getShowRedo = computed(() => unref(getMultipleTabSetting).showRedo); const getShowRedo = computed(() => unref(getMultipleTabSetting).showRedo);
const getShowFold = computed(() => unref(getMultipleTabSetting).showFold);
function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) { function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
appStore.commitProjectConfigState({ multiTabsSetting }); appStore.commitProjectConfigState({ multiTabsSetting });
} }
...@@ -24,5 +26,6 @@ export function useMultipleTabSetting() { ...@@ -24,5 +26,6 @@ export function useMultipleTabSetting() {
getShowMultipleTab, getShowMultipleTab,
getShowQuick, getShowQuick,
getShowRedo, getShowRedo,
getShowFold,
}; };
} }
import { tabStore } from '/@/store/modules/tab'; import { tabStore } from '/@/store/modules/tab';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import type { RouteLocationNormalized } from 'vue-router';
export function useTabs() { export function useTabs() {
function canIUseFn(): boolean { function canIUseFn(): boolean {
...@@ -21,5 +22,7 @@ export function useTabs() { ...@@ -21,5 +22,7 @@ export function useTabs() {
closeRight: () => canIUseFn() && tabStore.closeRightTabAction(tabStore.getCurrentTab), closeRight: () => canIUseFn() && tabStore.closeRightTabAction(tabStore.getCurrentTab),
closeOther: () => canIUseFn() && tabStore.closeOtherTabAction(tabStore.getCurrentTab), closeOther: () => canIUseFn() && tabStore.closeOtherTabAction(tabStore.getCurrentTab),
closeCurrent: () => canIUseFn() && tabStore.closeTabAction(tabStore.getCurrentTab), closeCurrent: () => canIUseFn() && tabStore.closeTabAction(tabStore.getCurrentTab),
close: (tab?: RouteLocationNormalized) =>
canIUseFn() && tabStore.closeTabAction(tab || tabStore.getCurrentTab),
}; };
} }
...@@ -85,7 +85,7 @@ export default defineComponent({ ...@@ -85,7 +85,7 @@ export default defineComponent({
getShowSearch, getShowSearch,
} = useHeaderSetting(); } = useHeaderSetting();
const { getShowMultipleTab, getShowQuick, getShowRedo } = useMultipleTabSetting(); const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
const getShowMenuRef = computed(() => { const getShowMenuRef = computed(() => {
return unref(getShowMenu) && !unref(getIsHorizontal); return unref(getShowMenu) && !unref(getIsHorizontal);
...@@ -105,33 +105,6 @@ export default defineComponent({ ...@@ -105,33 +105,6 @@ export default defineComponent({
}} }}
def={unref(getMenuType)} def={unref(getMenuType)}
/> />
<SwitchItem
title={t('layout.setting.splitMenu')}
event={HandlerEnum.MENU_SPLIT}
def={unref(getSplit)}
disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
/>
<SwitchItem
title={t('layout.setting.mixSidebarFixed')}
event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
def={unref(getMixSideFixed)}
disabled={!unref(getIsMixSidebar)}
/>
<SwitchItem
title={t('layout.setting.closeMixSidebarOnChange')}
event={HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE}
def={unref(getCloseMixSidebarOnChange)}
disabled={!unref(getIsMixSidebar)}
/>
<SelectItem
title={t('layout.setting.mixSidebarTrigger')}
event={HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR}
def={unref(getMixSideTrigger)}
options={mixSidebarTriggerOptions}
disabled={!unref(getIsMixSidebar)}
/>
</> </>
); );
} }
...@@ -171,6 +144,32 @@ export default defineComponent({ ...@@ -171,6 +144,32 @@ export default defineComponent({
return ( return (
<> <>
<SwitchItem <SwitchItem
title={t('layout.setting.splitMenu')}
event={HandlerEnum.MENU_SPLIT}
def={unref(getSplit)}
disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
/>
<SwitchItem
title={t('layout.setting.mixSidebarFixed')}
event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
def={unref(getMixSideFixed)}
disabled={!unref(getIsMixSidebar)}
/>
<SwitchItem
title={t('layout.setting.closeMixSidebarOnChange')}
event={HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE}
def={unref(getCloseMixSidebarOnChange)}
disabled={!unref(getIsMixSidebar)}
/>
<SwitchItem
title={t('layout.setting.menuCollapse')}
event={HandlerEnum.MENU_COLLAPSED}
def={unref(getCollapsed)}
disabled={!unref(getShowMenuRef)}
/>
<SwitchItem
title={t('layout.setting.menuDrag')} title={t('layout.setting.menuDrag')}
event={HandlerEnum.MENU_HAS_DRAG} event={HandlerEnum.MENU_HAS_DRAG}
def={unref(getCanDrag)} def={unref(getCanDrag)}
...@@ -188,17 +187,12 @@ export default defineComponent({ ...@@ -188,17 +187,12 @@ export default defineComponent({
def={unref(getAccordion)} def={unref(getAccordion)}
disabled={!unref(getShowMenuRef)} disabled={!unref(getShowMenuRef)}
/> />
<SwitchItem
title={t('layout.setting.menuCollapse')}
event={HandlerEnum.MENU_COLLAPSED}
def={unref(getCollapsed)}
disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)}
/>
<SwitchItem <SwitchItem
title={t('layout.setting.collapseMenuDisplayName')} title={t('layout.setting.collapseMenuDisplayName')}
event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE} event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE}
def={unref(getCollapsedShowTitle)} def={unref(getCollapsedShowTitle)}
disabled={!unref(getShowMenuRef) || !unref(getCollapsed)} disabled={!unref(getShowMenuRef) || !unref(getCollapsed) || unref(getIsMixSidebar)}
/> />
<SwitchItem <SwitchItem
...@@ -214,6 +208,13 @@ export default defineComponent({ ...@@ -214,6 +208,13 @@ export default defineComponent({
disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)} disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)}
/> />
<SelectItem <SelectItem
title={t('layout.setting.mixSidebarTrigger')}
event={HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR}
def={unref(getMixSideTrigger)}
options={mixSidebarTriggerOptions}
disabled={!unref(getIsMixSidebar)}
/>
<SelectItem
title={t('layout.setting.topMenuLayout')} title={t('layout.setting.topMenuLayout')}
event={HandlerEnum.MENU_TOP_ALIGN} event={HandlerEnum.MENU_TOP_ALIGN}
def={unref(getTopMenuAlign)} def={unref(getTopMenuAlign)}
...@@ -299,6 +300,12 @@ export default defineComponent({ ...@@ -299,6 +300,12 @@ export default defineComponent({
def={unref(getShowQuick)} def={unref(getShowQuick)}
disabled={!unref(getShowMultipleTab)} disabled={!unref(getShowMultipleTab)}
/> />
<SwitchItem
title={t('layout.setting.tabsFoldBtn')}
event={HandlerEnum.TABS_SHOW_FOLD}
def={unref(getShowFold)}
disabled={!unref(getShowMultipleTab)}
/>
<SwitchItem <SwitchItem
title={t('layout.setting.sidebar')} title={t('layout.setting.sidebar')}
......
...@@ -39,6 +39,7 @@ export enum HandlerEnum { ...@@ -39,6 +39,7 @@ export enum HandlerEnum {
TABS_SHOW_QUICK, TABS_SHOW_QUICK,
TABS_SHOW_REDO, TABS_SHOW_REDO,
TABS_SHOW, TABS_SHOW,
TABS_SHOW_FOLD,
LOCK_TIME, LOCK_TIME,
FULL_CONTENT, FULL_CONTENT,
......
...@@ -71,7 +71,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf ...@@ -71,7 +71,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
return { menuSetting: { mixSideTrigger: value } }; return { menuSetting: { mixSideTrigger: value } };
case HandlerEnum.MENU_FIXED_MIX_SIDEBAR: case HandlerEnum.MENU_FIXED_MIX_SIDEBAR:
return { menuSetting: { mixSideTrigger: value } }; return { menuSetting: { mixSideFixed: value } };
// ============transition================== // ============transition==================
case HandlerEnum.OPEN_PAGE_LOADING: case HandlerEnum.OPEN_PAGE_LOADING:
...@@ -123,9 +123,13 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf ...@@ -123,9 +123,13 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
case HandlerEnum.TABS_SHOW: case HandlerEnum.TABS_SHOW:
return { multiTabsSetting: { show: value } }; return { multiTabsSetting: { show: value } };
case HandlerEnum.TABS_SHOW_REDO: case HandlerEnum.TABS_SHOW_REDO:
return { multiTabsSetting: { showRedo: value } }; return { multiTabsSetting: { showRedo: value } };
case HandlerEnum.TABS_SHOW_FOLD:
return { multiTabsSetting: { showFold: value } };
// ============header================== // ============header==================
case HandlerEnum.HEADER_THEME: case HandlerEnum.HEADER_THEME:
updateHeaderBgColor(value); updateHeaderBgColor(value);
......
...@@ -3,11 +3,13 @@ ...@@ -3,11 +3,13 @@
<div <div
v-click-outside="handleClickOutside" v-click-outside="handleClickOutside"
:style="getWrapStyle"
:class="[ :class="[
prefixCls, prefixCls,
getMenuTheme, getMenuTheme,
{ {
open: openMenu, open: openMenu,
mini: getCollapsed,
}, },
]" ]"
v-bind="getMenuEvents" v-bind="getMenuEvents"
...@@ -29,7 +31,7 @@ ...@@ -29,7 +31,7 @@
<MenuTag :item="item" :showTitle="false" :isHorizontal="false" /> <MenuTag :item="item" :showTitle="false" :isHorizontal="false" />
<Icon <Icon
:class="`${prefixCls}-module__icon`" :class="`${prefixCls}-module__icon`"
:size="22" :size="getCollapsed ? 16 : 20"
:icon="item.meta && item.meta.icon" :icon="item.meta && item.meta.icon"
/> />
<p :class="`${prefixCls}-module__name`">{{ t(item.name) }}</p> <p :class="`${prefixCls}-module__name`">{{ t(item.name) }}</p>
...@@ -50,12 +52,10 @@ ...@@ -50,12 +52,10 @@
<span class="text"> {{ title }}</span> <span class="text"> {{ title }}</span>
<Icon <Icon
:size="16" :size="16"
v-if="getMixSideFixed" :icon="getMixSideFixed ? 'ri:pushpin-2-fill' : 'ri:pushpin-2-line'"
icon="ri:pushpin-2-fill"
class="pushpin" class="pushpin"
@click="handleFixedMenu" @click="handleFixedMenu"
/> />
<Icon :size="16" v-else icon="ri:pushpin-2-line" class="pushpin" @click="handleFixedMenu" />
</div> </div>
<ScrollContainer :class="`${prefixCls}-menu-list__content`"> <ScrollContainer :class="`${prefixCls}-menu-list__content`">
<BasicMenu <BasicMenu
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
import { useDragLine } from './useLayoutSider'; import { useDragLine } from './useLayoutSider';
import { useGlobSetting } from '/@/hooks/setting'; import { useGlobSetting } from '/@/hooks/setting';
import { SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum'; import { SIDE_BAR_SHOW_TIT_MINI_WIDTH, SIDE_BAR_MINI_WIDTH } from '/@/enums/appEnum';
import clickOutside from '/@/directives/clickOutside'; import clickOutside from '/@/directives/clickOutside';
...@@ -130,6 +130,8 @@ ...@@ -130,6 +130,8 @@
getMixSideFixed, getMixSideFixed,
mixSideHasChildren, mixSideHasChildren,
setMenuSetting, setMenuSetting,
getIsMixSidebar,
getCollapsed,
} = useMenuSetting(); } = useMenuSetting();
const { title } = useGlobSetting(); const { title } = useGlobSetting();
...@@ -140,6 +142,7 @@ ...@@ -140,6 +142,7 @@
(): CSSProperties => { (): CSSProperties => {
return { return {
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0, width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
left: `${unref(getMixSideWidth)}px`,
}; };
} }
); );
...@@ -153,32 +156,33 @@ ...@@ -153,32 +156,33 @@
return isFixed; return isFixed;
}); });
const getMixSideWidth = computed(() => {
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH;
});
const getDomStyle = computed( const getDomStyle = computed(
(): CSSProperties => { (): CSSProperties => {
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0; const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
const width = `${SIDE_BAR_SHOW_TIT_MINI_WIDTH + fixedWidth}px`; const width = `${unref(getMixSideWidth) + fixedWidth}px`;
return { return getWrapCommonStyle(width);
width, }
maxWidth: width, );
minWidth: width,
flex: `0 0 ${width}`, const getWrapStyle = computed(
}; (): CSSProperties => {
const width = `${unref(getMixSideWidth)}px`;
return getWrapCommonStyle(width);
} }
); );
const getMenuEvents = computed(() => { const getMenuEvents = computed(() => {
// return unref(getMixSideTrigger) === 'hover' return !unref(getMixSideFixed)
// ? { ? {
// onMouseleave: () => {
// closeMenu();
// },
// }
// : {};
return {
onMouseleave: () => { onMouseleave: () => {
closeMenu(); closeMenu();
}, },
}; }
: {};
}); });
const getShowDragBar = computed(() => unref(getCanDrag)); const getShowDragBar = computed(() => unref(getCanDrag));
...@@ -195,6 +199,16 @@ ...@@ -195,6 +199,16 @@
} }
}); });
function getWrapCommonStyle(width: string): CSSProperties {
return {
width,
maxWidth: width,
minWidth: width,
flex: `0 0 ${width}`,
};
}
// Process module menu click
async function hanldeModuleClick(path: string, hover = false) { async function hanldeModuleClick(path: string, hover = false) {
const children = await getChildrenMenus(path); const children = await getChildrenMenus(path);
...@@ -223,21 +237,25 @@ ...@@ -223,21 +237,25 @@
chilrenMenus.value = children; chilrenMenus.value = children;
} }
// Set the currently active menu and submenu
async function setActive(setChildren = false) { async function setActive(setChildren = false) {
const path = currentRoute.value?.path; const path = currentRoute.value?.path;
if (!path) return; if (!path) return;
const parentPath = await getCurrentParentPath(path); const parentPath = await getCurrentParentPath(path);
activePath.value = parentPath; activePath.value = parentPath;
// hanldeModuleClick(parentPath); // hanldeModuleClick(parentPath);
if (unref(getMixSideFixed)) { if (unref(getIsMixSidebar)) {
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath)); const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
const p = activeMenu?.path; const p = activeMenu?.path;
if (p) { if (p) {
const children = await getChildrenMenus(p); const children = await getChildrenMenus(p);
if (setChildren) { if (setChildren) {
chilrenMenus.value = children; chilrenMenus.value = children;
if (unref(getMixSideFixed)) {
openMenu.value = children.length > 0; openMenu.value = children.length > 0;
} }
}
if (children.length === 0) { if (children.length === 0) {
chilrenMenus.value = []; chilrenMenus.value = [];
} }
...@@ -271,6 +289,7 @@ ...@@ -271,6 +289,7 @@
}); });
} }
// Close menu
function closeMenu() { function closeMenu() {
if (!unref(getIsFixed)) { if (!unref(getIsFixed)) {
openMenu.value = false; openMenu.value = false;
...@@ -298,6 +317,8 @@ ...@@ -298,6 +317,8 @@
getDomStyle, getDomStyle,
handleFixedMenu, handleFixedMenu,
getMixSideFixed, getMixSideFixed,
getWrapStyle,
getCollapsed,
}; };
}, },
}); });
...@@ -312,14 +333,10 @@ ...@@ -312,14 +333,10 @@
top: 0; top: 0;
left: 0; left: 0;
z-index: @layout-mix-sider-fixed-z-index; z-index: @layout-mix-sider-fixed-z-index;
width: @width;
height: 100%; height: 100%;
max-width: @width;
min-width: @width;
overflow: hidden; overflow: hidden;
background: @sider-dark-bg-color; background: @sider-dark-bg-color;
transition: all 0.3s ease 0s; transition: all 0.2s ease 0s;
flex: 0 0 @width;
.@{tag-prefix-cls} { .@{tag-prefix-cls} {
position: absolute; position: absolute;
top: 6px; top: 6px;
...@@ -327,13 +344,9 @@ ...@@ -327,13 +344,9 @@
} }
&-dom { &-dom {
width: @width;
height: 100%; height: 100%;
max-width: @width;
min-width: @width;
overflow: hidden; overflow: hidden;
transition: all 0.2s ease 0s; transition: all 0.2s ease 0s;
flex: 0 0 @width;
} }
&-logo { &-logo {
...@@ -354,7 +367,7 @@ ...@@ -354,7 +367,7 @@
} }
&.open { &.open {
> .scroll-container { > .scrollbar {
border-right: 1px solid rgb(238, 238, 238); border-right: 1px solid rgb(238, 238, 238);
} }
} }
...@@ -390,7 +403,7 @@ ...@@ -390,7 +403,7 @@
border-bottom: 1px solid @border-color; border-bottom: 1px solid @border-color;
} }
> .scroll-container { > .scrollbar {
border-right: 1px solid @border-color; border-right: 1px solid @border-color;
} }
} }
...@@ -409,6 +422,16 @@ ...@@ -409,6 +422,16 @@
height: calc(100% - @header-height) !important; height: calc(100% - @header-height) !important;
} }
&.mini &-module {
&__name {
display: none;
}
&__icon {
margin-bottom: 0;
}
}
&-module { &-module {
position: relative; position: relative;
padding-top: 1px; padding-top: 1px;
...@@ -456,7 +479,6 @@ ...@@ -456,7 +479,6 @@
&-menu-list { &-menu-list {
position: fixed; position: fixed;
top: 0; top: 0;
left: 80px;
width: 0; width: 0;
width: 200px; width: 200px;
height: calc(100%); height: calc(100%);
......
<template>
<span :class="`${prefixCls}__extra-fold`" @click="handleFold">
<Icon :icon="getIcon" />
</span>
</template>
<script lang="ts">
import { defineComponent, unref, computed } from 'vue';
import { RedoOutlined } from '@ant-design/icons-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { Tooltip } from 'ant-design-vue';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import Icon from '/@/components/Icon';
export default defineComponent({
name: 'FoldButton',
components: { RedoOutlined, Tooltip, Icon },
setup() {
const { prefixCls } = useDesign('multiple-tabs-content');
const { getShowMenu, setMenuSetting } = useMenuSetting();
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
const getIsUnFold = computed(() => {
return !unref(getShowMenu) && !unref(getShowHeader);
});
const getIcon = computed(() => {
return unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full';
});
function handleFold() {
const isScale = !unref(getShowMenu) && !unref(getShowHeader);
setMenuSetting({
show: isScale,
hidden: !isScale,
});
setHeaderSetting({
show: isScale,
});
}
return { prefixCls, getIcon, handleFold };
},
});
</script>
...@@ -153,7 +153,8 @@ ...@@ -153,7 +153,8 @@
&-content { &-content {
&__extra-quick, &__extra-quick,
&__extra-redo { &__extra-redo,
&__extra-fold {
display: inline-block; display: inline-block;
width: 36px; width: 36px;
height: @multiple-height; height: @multiple-height;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<template #tabBarExtraContent v-if="getShowRedo || getShowQuick"> <template #tabBarExtraContent v-if="getShowRedo || getShowQuick">
<TabRedo v-if="getShowRedo" /> <TabRedo v-if="getShowRedo" />
<QuickButton v-if="getShowQuick" /> <QuickButton v-if="getShowQuick" />
<FoldButton v-if="getShowFold" />
</template> </template>
</Tabs> </Tabs>
</div> </div>
...@@ -51,6 +52,7 @@ ...@@ -51,6 +52,7 @@
components: { components: {
QuickButton: createAsyncComponent(() => import('./components/QuickButton.vue')), QuickButton: createAsyncComponent(() => import('./components/QuickButton.vue')),
TabRedo: createAsyncComponent(() => import('./components/TabRedo.vue')), TabRedo: createAsyncComponent(() => import('./components/TabRedo.vue')),
FoldButton: createAsyncComponent(() => import('./components/FoldButton.vue')),
Tabs, Tabs,
TabPane: Tabs.TabPane, TabPane: Tabs.TabPane,
TabContent, TabContent,
...@@ -62,7 +64,7 @@ ...@@ -62,7 +64,7 @@
useTabsDrag(affixTextList); useTabsDrag(affixTextList);
const { prefixCls } = useDesign('multiple-tabs'); const { prefixCls } = useDesign('multiple-tabs');
const go = useGo(); const go = useGo();
const { getShowQuick, getShowRedo } = useMultipleTabSetting(); const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
const getTabsState = computed(() => { const getTabsState = computed(() => {
return tabStore.getTabsState.filter((item) => !item.meta?.hideTab); return tabStore.getTabsState.filter((item) => !item.meta?.hideTab);
...@@ -125,6 +127,7 @@ ...@@ -125,6 +127,7 @@
getTabsState, getTabsState,
getShowQuick, getShowQuick,
getShowRedo, getShowRedo,
getShowFold,
}; };
}, },
}); });
......
...@@ -8,8 +8,6 @@ import router from '/@/router'; ...@@ -8,8 +8,6 @@ import router from '/@/router';
import { RouteLocationNormalized } from 'vue-router'; import { RouteLocationNormalized } 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';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
const { t } = useI18n(); const { t } = useI18n();
...@@ -21,9 +19,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) { ...@@ -21,9 +19,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
const { currentRoute } = router; const { currentRoute } = router;
const { getShowMenu, setMenuSetting } = useMenuSetting();
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
const isTabs = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE); const isTabs = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE);
const getCurrentTab = computed( const getCurrentTab = computed(
...@@ -32,10 +27,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) { ...@@ -32,10 +27,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
} }
); );
const getIsScale = computed(() => {
return !unref(getShowMenu) && !unref(getShowHeader);
});
/** /**
* @description: drop-down list * @description: drop-down list
*/ */
...@@ -98,16 +89,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) { ...@@ -98,16 +89,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
}, },
]; ];
if (!unref(isTabs)) {
const isScale = unref(getIsScale);
dropMenuList.unshift({
icon: isScale ? 'codicon:screen-normal' : 'codicon:screen-full',
event: MenuEventEnum.SCALE,
text: isScale ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
disabled: false,
});
}
return dropMenuList; return dropMenuList;
}); });
...@@ -125,20 +106,9 @@ export function useTabDropdown(tabContentProps: TabContentProps) { ...@@ -125,20 +106,9 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
}; };
} }
function scaleScreen() {
const isScale = !unref(getShowMenu) && !unref(getShowHeader);
setMenuSetting({
show: isScale,
hidden: !isScale,
});
setHeaderSetting({
show: isScale,
});
}
// Handle right click event // Handle right click event
function handleMenuEvent(menu: DropMenu): void { function handleMenuEvent(menu: DropMenu): void {
const { refreshPage, closeAll, closeCurrent, closeLeft, closeOther, closeRight } = useTabs(); const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs();
const { event } = menu; const { event } = menu;
switch (event) { switch (event) {
case MenuEventEnum.SCALE: case MenuEventEnum.SCALE:
...@@ -150,7 +120,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) { ...@@ -150,7 +120,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
break; break;
// Close current // Close current
case MenuEventEnum.CLOSE_CURRENT: case MenuEventEnum.CLOSE_CURRENT:
closeCurrent(); close(tabContentProps.tabItem);
break; break;
// Close left // Close left
case MenuEventEnum.CLOSE_LEFT: case MenuEventEnum.CLOSE_LEFT:
......
...@@ -5,7 +5,5 @@ export default { ...@@ -5,7 +5,5 @@ export default {
closeRight: 'Close Right', closeRight: 'Close Right',
closeOther: 'Close Other', closeOther: 'Close Other',
closeAll: 'Close All', closeAll: 'Close All',
putAway: 'PutAway',
unfold: 'Unfold',
tooltipRedo: 'Refresh', tooltipRedo: 'Refresh',
}; };
...@@ -56,6 +56,7 @@ export default { ...@@ -56,6 +56,7 @@ export default {
tabs: 'Tabs', tabs: 'Tabs',
tabsQuickBtn: 'Tabs quick button', tabsQuickBtn: 'Tabs quick button',
tabsRedoBtn: 'Tabs redo button', tabsRedoBtn: 'Tabs redo button',
tabsFoldBtn: 'Tabs flod button',
sidebar: 'Sidebar', sidebar: 'Sidebar',
header: 'Header', header: 'Header',
footer: 'Footer', footer: 'Footer',
......
export default { export default {
redo: '刷新当前', redo: '重新加载',
close: '关闭当前', close: '关闭标签页',
closeLeft: '关闭左侧', closeLeft: '关闭左侧标签页',
closeRight: '关闭右侧', closeRight: '关闭右侧标签页',
closeOther: '关闭其他', closeOther: '关闭其它标签页',
closeAll: '关闭全部', closeAll: '关闭全部标签页',
putAway: '收起',
unfold: '展开',
tooltipRedo: '刷新', tooltipRedo: '刷新',
}; };
...@@ -55,6 +55,7 @@ export default { ...@@ -55,6 +55,7 @@ export default {
tabs: '标签页', tabs: '标签页',
tabsQuickBtn: '标签页快捷按钮', tabsQuickBtn: '标签页快捷按钮',
tabsRedoBtn: '标签页刷新按钮', tabsRedoBtn: '标签页刷新按钮',
tabsFoldBtn: '标签页折叠按钮',
sidebar: '左侧菜单', sidebar: '左侧菜单',
header: '顶栏', header: '顶栏',
footer: '页脚', footer: '页脚',
......
// Used to configure the general configuration of some components without modifying the components
import type { SorterResult } from '../components/Table';
export default {
// basic-table setting
table: {
// Form interface request general configuration
// support xxx.xxx.xxx
fetchSetting: {
// The field name of the current page passed to the background
pageField: 'page',
// The number field name of each page displayed in the background
sizeField: 'pageSize',
// Field name of the form data returned by the interface
listField: 'items',
// Total number of tables returned by the interface field name
totalField: 'total',
},
// Number of pages that can be selected
pageSizeOptions: ['10', '50', '80', '100'],
// Default display quantity on one page
defaultPageSize: 10,
// Custom general sort function
defaultSortFn: (sortInfo: SorterResult) => {
const { field, order } = sortInfo;
return {
// The sort field passed to the backend you
field,
// Sorting method passed to the background asc/desc
order,
};
},
// Custom general filter function
defaultFilterFn: (data: Partial<Recordable<string[]>>) => {
return data;
},
},
// scrollbar setting
scrollbar: {
// Whether to use native scroll bar
// After opening, the menu, modal, drawer will change the pop-up scroll bar to native
native: false,
},
};
...@@ -5,8 +5,8 @@ export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7; ...@@ -5,8 +5,8 @@ export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
// aes encryption key // aes encryption key
export const cacheCipher = { export const cacheCipher = {
key: '_12345678901234@', key: '_11111000001111@',
iv: '@12345678901234_', iv: '@11111000001111_',
}; };
// Whether the system cache is encrypted using aes // Whether the system cache is encrypted using aes
......
...@@ -125,6 +125,8 @@ const setting: ProjectConfig = { ...@@ -125,6 +125,8 @@ const setting: ProjectConfig = {
// Whether to show the refresh button // Whether to show the refresh button
showRedo: true, showRedo: true,
// Whether to show the collapse button
showFold: true,
}, },
// Transition Setting // Transition Setting
......
...@@ -33,6 +33,9 @@ export interface MultiTabsSetting { ...@@ -33,6 +33,9 @@ export interface MultiTabsSetting {
// 显示刷新按钮 // 显示刷新按钮
showRedo: boolean; showRedo: boolean;
// 显示折叠按钮
showFold: boolean;
} }
export interface HeaderSetting { export interface HeaderSetting {
......
<template> <template>
<PageWrapper title="单号:234231029431" contentBackgrond> <PageWrapper title="单号:234231029431" contentBackgrond>
<template #extra> <template #extra>
<a-button key="3"> 操作一 </a-button> <a-button> 操作一 </a-button>
<a-button key="2"> 操作二 </a-button> <a-button> 操作二 </a-button>
<a-button key="1" type="primary"> 主操作 </a-button> <a-button type="primary"> 主操作 </a-button>
</template> </template>
<template #footer> <template #footer>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论