From 0e7c57bd5ecafd8283bcc950b24bb63b59b70e5a Mon Sep 17 00:00:00 2001 From: vben <anncwb@126.com> Date: Wed, 6 Jan 2021 20:10:16 +0800 Subject: [PATCH] feat(tabs): added tab folding --- CHANGELOG.zh_CN.md | 1 + mock/_createProductionServer.ts | 10 +++++++++- src/components/Icon/src/index.vue | 2 +- src/components/Menu/src/useOpenKeys.ts | 8 ++++++-- src/components/Modal/src/BasicModal.vue | 2 -- src/components/Modal/src/components/ModalWrapper.vue | 15 +++------------ src/components/Modal/src/index.less | 5 +---- src/components/Scrollbar/src/index.vue | 5 +++-- src/components/Table/src/components/settings/ColumnSetting.vue | 2 +- src/components/Table/src/const.ts | 38 +++++++++++--------------------------- src/hooks/setting/useMenuSetting.ts | 5 +++-- src/hooks/setting/useMultipleTabSetting.ts | 3 +++ src/hooks/web/useTabs.ts | 3 +++ src/layouts/default/setting/SettingDrawer.tsx | 77 ++++++++++++++++++++++++++++++++++++++++++----------------------------------- src/layouts/default/setting/enum.ts | 1 + src/layouts/default/setting/handler.ts | 6 +++++- src/layouts/default/sider/MixSider.vue | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------- src/layouts/default/tabs/components/FoldButton.vue | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/layouts/default/tabs/index.less | 3 ++- src/layouts/default/tabs/index.vue | 5 ++++- src/layouts/default/tabs/useTabDropdown.ts | 34 ++-------------------------------- src/locales/lang/en/layout/multipleTab.ts | 2 -- src/locales/lang/en/layout/setting.ts | 1 + src/locales/lang/zh_CN/layout/multipleTab.ts | 14 ++++++-------- src/locales/lang/zh_CN/layout/setting.ts | 1 + src/settings/componentSetting.ts | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/settings/encryptionSetting.ts | 4 ++-- src/settings/projectSetting.ts | 2 ++ src/types/config.d.ts | 3 +++ src/views/demo/page/desc/high/index.vue | 6 +++--- 30 files changed, 271 insertions(+), 177 deletions(-) create mode 100644 src/layouts/default/tabs/components/FoldButton.vue create mode 100644 src/settings/componentSetting.ts diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index f55aae0..aa333a8 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -6,6 +6,7 @@ - 新增`mixSideFixed`配置。用于固定左侧混合模式菜单 - modal 组件新增`height`和`min-height`属性 - 新增`PageWrapper`组件。并应用于示例页面 +- 新增标签页折叠功能 ### 🐛 Bug Fixes diff --git a/mock/_createProductionServer.ts b/mock/_createProductionServer.ts index f72b41c..f078610 100644 --- a/mock/_createProductionServer.ts +++ b/mock/_createProductionServer.ts @@ -2,10 +2,18 @@ import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; import userMock from './sys/user'; import menuMock from './sys/menu'; 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 */ export function setupProdMockServer() { - createProdMockServer([...userMock, ...menuMock, ...tableDemoMock]); + createProdMockServer([ + ...userMock, + ...menuMock, + ...tableDemoMock, + ...accountDemoMock, + ...selectDemoMock, + ]); } diff --git a/src/components/Icon/src/index.vue b/src/components/Icon/src/index.vue index 9e48335..821369f 100644 --- a/src/components/Icon/src/index.vue +++ b/src/components/Icon/src/index.vue @@ -74,7 +74,7 @@ } ); - // watch(() => props.icon, update, { flush: 'post' }); + watch(() => props.icon, update, { flush: 'post' }); onMounted(update); diff --git a/src/components/Menu/src/useOpenKeys.ts b/src/components/Menu/src/useOpenKeys.ts index a028764..e2078ff 100644 --- a/src/components/Menu/src/useOpenKeys.ts +++ b/src/components/Menu/src/useOpenKeys.ts @@ -16,16 +16,20 @@ export function useOpenKeys( mode: Ref<MenuModeEnum>, accordion: Ref<boolean> ) { - const { getCollapsed, getIsMixSidebar, getMixSideFixed } = useMenuSetting(); + const { getCollapsed, getIsMixSidebar } = useMenuSetting(); async function setOpenKeys(path: string) { if (mode.value === MenuModeEnum.HORIZONTAL) { return; } - const native = unref(getIsMixSidebar) && unref(getMixSideFixed); + const native = unref(getIsMixSidebar); useTimeoutFn( () => { const menuList = toRaw(menus.value); + if (menuList?.length === 0) { + menuState.openKeys = []; + return; + } if (!unref(accordion)) { menuState.openKeys = es6Unique([ ...menuState.openKeys, diff --git a/src/components/Modal/src/BasicModal.vue b/src/components/Modal/src/BasicModal.vue index 4b44200..a3afa0a 100644 --- a/src/components/Modal/src/BasicModal.vue +++ b/src/components/Modal/src/BasicModal.vue @@ -51,7 +51,6 @@ watchEffect, toRef, getCurrentInstance, - nextTick, } from 'vue'; import Modal from './components/Modal'; @@ -111,7 +110,6 @@ visible: unref(visibleRef), title: undefined, }; - return { ...opt, wrapClassName: unref(getWrapClassName), diff --git a/src/components/Modal/src/components/ModalWrapper.vue b/src/components/Modal/src/components/ModalWrapper.vue index 981990f..1e1fcec 100644 --- a/src/components/Modal/src/components/ModalWrapper.vue +++ b/src/components/Modal/src/components/ModalWrapper.vue @@ -1,5 +1,5 @@ <template> - <ScrollContainer ref="wrapperRef" :style="wrapStyle"> + <ScrollContainer ref="wrapperRef"> <div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip"> <slot /> </div> @@ -62,19 +62,10 @@ redoModalHeight: setModalHeight, }); - const wrapStyle = computed( - (): CSSProperties => { - return { - minHeight: `${props.minHeight}px`, - height: `${unref(realHeightRef)}px`, - // overflow: 'auto', - }; - } - ); - const spinStyle = computed( (): CSSProperties => { return { + minHeight: `${props.minHeight}px`, // padding 28 height: `${unref(realHeightRef) - 28}px`, }; @@ -159,7 +150,7 @@ } } - return { wrapStyle, wrapperRef, spinRef, spinStyle }; + return { wrapperRef, spinRef, spinStyle }; }, }); </script> diff --git a/src/components/Modal/src/index.less b/src/components/Modal/src/index.less index a5f0e39..8205095 100644 --- a/src/components/Modal/src/index.less +++ b/src/components/Modal/src/index.less @@ -21,12 +21,9 @@ width: 520px; padding-bottom: 0; - .scroll-container { + .scrollbar { padding: 14px; } - // .ant-spin-nested-loading { - // padding: 16px; - // } &-title { font-size: 16px; diff --git a/src/components/Scrollbar/src/index.vue b/src/components/Scrollbar/src/index.vue index ebda1b2..77cbad4 100644 --- a/src/components/Scrollbar/src/index.vue +++ b/src/components/Scrollbar/src/index.vue @@ -18,7 +18,8 @@ </template> <script lang="ts"> import { addResizeListener, removeResizeListener } from '/@/utils/event/resizeEvent'; - + import componentSetting from '/@/settings/componentSetting'; + const { scrollbar } = componentSetting; import { toObject } from './util'; import { defineComponent, @@ -38,7 +39,7 @@ props: { native: { type: Boolean, - default: false, + default: scrollbar?.native ?? false, }, wrapStyle: { type: [String, Array], diff --git a/src/components/Table/src/components/settings/ColumnSetting.vue b/src/components/Table/src/components/settings/ColumnSetting.vue index f83f5d5..72fa887 100644 --- a/src/components/Table/src/components/settings/ColumnSetting.vue +++ b/src/components/Table/src/components/settings/ColumnSetting.vue @@ -421,7 +421,7 @@ // flex-wrap: wrap; } - .scroll-container { + .scrollbar { height: 220px; } } diff --git a/src/components/Table/src/const.ts b/src/components/Table/src/const.ts index e1371a4..2352144 100644 --- a/src/components/Table/src/const.ts +++ b/src/components/Table/src/const.ts @@ -1,40 +1,24 @@ -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 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 = { - // 传给后台的当前页字段名 - pageField: 'page', - // 传给后台的每页显示记录数字段名 - sizeField: 'pageSize', - // 接口返回的表格数据字段名 - listField: 'items', - // 接口返回的表格总数字段名 - totalField: 'total', -}; +export const FETCH_SETTING = fetchSetting; // 配置通用排序函数 -export function DEFAULT_SORT_FN(sortInfo: SorterResult) { - const { field, order } = sortInfo; - return { - // 传给后台的排序字段你 - field, - // 传给后台的排序方式 asc/desc - order, - }; -} - -export function DEFAULT_FILTER_FN(data: Partial<Recordable<string[]>>) { - return data; -} +export const DEFAULT_SORT_FN = defaultSortFn; + +export const DEFAULT_FILTER_FN = defaultFilterFn; // 表格单元格默认布局 export const DEFAULT_ALIGN = 'center'; diff --git a/src/hooks/setting/useMenuSetting.ts b/src/hooks/setting/useMenuSetting.ts index 2edcafb..e85cbbe 100644 --- a/src/hooks/setting/useMenuSetting.ts +++ b/src/hooks/setting/useMenuSetting.ts @@ -78,7 +78,9 @@ const getIsMixMode = computed(() => { }); const getRealWidth = computed(() => { - return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth); + return unref(getCollapsed) && !unref(getMixSideFixed) + ? unref(getMiniWidthNumber) + : unref(getMenuWidth); }); const getMiniWidthNumber = computed(() => { @@ -94,7 +96,6 @@ const getCalcContentWidth = computed(() => { ? SIDE_BAR_SHOW_TIT_MINI_WIDTH + (unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0) : unref(getRealWidth); - return `calc(100% - ${unref(width)}px)`; }); diff --git a/src/hooks/setting/useMultipleTabSetting.ts b/src/hooks/setting/useMultipleTabSetting.ts index f3fd840..859e8eb 100644 --- a/src/hooks/setting/useMultipleTabSetting.ts +++ b/src/hooks/setting/useMultipleTabSetting.ts @@ -12,6 +12,8 @@ const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick); const getShowRedo = computed(() => unref(getMultipleTabSetting).showRedo); +const getShowFold = computed(() => unref(getMultipleTabSetting).showFold); + function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) { appStore.commitProjectConfigState({ multiTabsSetting }); } @@ -24,5 +26,6 @@ export function useMultipleTabSetting() { getShowMultipleTab, getShowQuick, getShowRedo, + getShowFold, }; } diff --git a/src/hooks/web/useTabs.ts b/src/hooks/web/useTabs.ts index 0f2c3ea..b0bf1a4 100644 --- a/src/hooks/web/useTabs.ts +++ b/src/hooks/web/useTabs.ts @@ -1,5 +1,6 @@ import { tabStore } from '/@/store/modules/tab'; import { appStore } from '/@/store/modules/app'; +import type { RouteLocationNormalized } from 'vue-router'; export function useTabs() { function canIUseFn(): boolean { @@ -21,5 +22,7 @@ export function useTabs() { closeRight: () => canIUseFn() && tabStore.closeRightTabAction(tabStore.getCurrentTab), closeOther: () => canIUseFn() && tabStore.closeOtherTabAction(tabStore.getCurrentTab), closeCurrent: () => canIUseFn() && tabStore.closeTabAction(tabStore.getCurrentTab), + close: (tab?: RouteLocationNormalized) => + canIUseFn() && tabStore.closeTabAction(tab || tabStore.getCurrentTab), }; } diff --git a/src/layouts/default/setting/SettingDrawer.tsx b/src/layouts/default/setting/SettingDrawer.tsx index 6b8f013..2d6ea16 100644 --- a/src/layouts/default/setting/SettingDrawer.tsx +++ b/src/layouts/default/setting/SettingDrawer.tsx @@ -85,7 +85,7 @@ export default defineComponent({ getShowSearch, } = useHeaderSetting(); - const { getShowMultipleTab, getShowQuick, getShowRedo } = useMultipleTabSetting(); + const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting(); const getShowMenuRef = computed(() => { return unref(getShowMenu) && !unref(getIsHorizontal); @@ -105,33 +105,6 @@ export default defineComponent({ }} 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({ return ( <> <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')} event={HandlerEnum.MENU_HAS_DRAG} def={unref(getCanDrag)} @@ -188,17 +187,12 @@ export default defineComponent({ def={unref(getAccordion)} disabled={!unref(getShowMenuRef)} /> - <SwitchItem - title={t('layout.setting.menuCollapse')} - event={HandlerEnum.MENU_COLLAPSED} - def={unref(getCollapsed)} - disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)} - /> + <SwitchItem title={t('layout.setting.collapseMenuDisplayName')} event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE} def={unref(getCollapsedShowTitle)} - disabled={!unref(getShowMenuRef) || !unref(getCollapsed)} + disabled={!unref(getShowMenuRef) || !unref(getCollapsed) || unref(getIsMixSidebar)} /> <SwitchItem @@ -214,6 +208,13 @@ export default defineComponent({ disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)} /> <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')} event={HandlerEnum.MENU_TOP_ALIGN} def={unref(getTopMenuAlign)} @@ -299,6 +300,12 @@ export default defineComponent({ def={unref(getShowQuick)} disabled={!unref(getShowMultipleTab)} /> + <SwitchItem + title={t('layout.setting.tabsFoldBtn')} + event={HandlerEnum.TABS_SHOW_FOLD} + def={unref(getShowFold)} + disabled={!unref(getShowMultipleTab)} + /> <SwitchItem title={t('layout.setting.sidebar')} diff --git a/src/layouts/default/setting/enum.ts b/src/layouts/default/setting/enum.ts index 3a5afc5..99de4d4 100644 --- a/src/layouts/default/setting/enum.ts +++ b/src/layouts/default/setting/enum.ts @@ -39,6 +39,7 @@ export enum HandlerEnum { TABS_SHOW_QUICK, TABS_SHOW_REDO, TABS_SHOW, + TABS_SHOW_FOLD, LOCK_TIME, FULL_CONTENT, diff --git a/src/layouts/default/setting/handler.ts b/src/layouts/default/setting/handler.ts index 9abe34a..28be936 100644 --- a/src/layouts/default/setting/handler.ts +++ b/src/layouts/default/setting/handler.ts @@ -71,7 +71,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf return { menuSetting: { mixSideTrigger: value } }; case HandlerEnum.MENU_FIXED_MIX_SIDEBAR: - return { menuSetting: { mixSideTrigger: value } }; + return { menuSetting: { mixSideFixed: value } }; // ============transition================== case HandlerEnum.OPEN_PAGE_LOADING: @@ -123,9 +123,13 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf case HandlerEnum.TABS_SHOW: return { multiTabsSetting: { show: value } }; + case HandlerEnum.TABS_SHOW_REDO: return { multiTabsSetting: { showRedo: value } }; + case HandlerEnum.TABS_SHOW_FOLD: + return { multiTabsSetting: { showFold: value } }; + // ============header================== case HandlerEnum.HEADER_THEME: updateHeaderBgColor(value); diff --git a/src/layouts/default/sider/MixSider.vue b/src/layouts/default/sider/MixSider.vue index ee28598..ba76ee9 100644 --- a/src/layouts/default/sider/MixSider.vue +++ b/src/layouts/default/sider/MixSider.vue @@ -3,11 +3,13 @@ <div v-click-outside="handleClickOutside" + :style="getWrapStyle" :class="[ prefixCls, getMenuTheme, { open: openMenu, + mini: getCollapsed, }, ]" v-bind="getMenuEvents" @@ -29,7 +31,7 @@ <MenuTag :item="item" :showTitle="false" :isHorizontal="false" /> <Icon :class="`${prefixCls}-module__icon`" - :size="22" + :size="getCollapsed ? 16 : 20" :icon="item.meta && item.meta.icon" /> <p :class="`${prefixCls}-module__name`">{{ t(item.name) }}</p> @@ -50,12 +52,10 @@ <span class="text"> {{ title }}</span> <Icon :size="16" - v-if="getMixSideFixed" - icon="ri:pushpin-2-fill" + :icon="getMixSideFixed ? 'ri:pushpin-2-fill' : 'ri:pushpin-2-line'" class="pushpin" @click="handleFixedMenu" /> - <Icon :size="16" v-else icon="ri:pushpin-2-line" class="pushpin" @click="handleFixedMenu" /> </div> <ScrollContainer :class="`${prefixCls}-menu-list__content`"> <BasicMenu @@ -92,7 +92,7 @@ import { useDragLine } from './useLayoutSider'; 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'; @@ -130,6 +130,8 @@ getMixSideFixed, mixSideHasChildren, setMenuSetting, + getIsMixSidebar, + getCollapsed, } = useMenuSetting(); const { title } = useGlobSetting(); @@ -140,6 +142,7 @@ (): CSSProperties => { return { width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0, + left: `${unref(getMixSideWidth)}px`, }; } ); @@ -153,32 +156,33 @@ return isFixed; }); + const getMixSideWidth = computed(() => { + return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH; + }); + const getDomStyle = computed( (): CSSProperties => { const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0; - const width = `${SIDE_BAR_SHOW_TIT_MINI_WIDTH + fixedWidth}px`; - return { - width, - maxWidth: width, - minWidth: width, - flex: `0 0 ${width}`, - }; + const width = `${unref(getMixSideWidth) + fixedWidth}px`; + return getWrapCommonStyle(width); + } + ); + + const getWrapStyle = computed( + (): CSSProperties => { + const width = `${unref(getMixSideWidth)}px`; + return getWrapCommonStyle(width); } ); const getMenuEvents = computed(() => { - // return unref(getMixSideTrigger) === 'hover' - // ? { - // onMouseleave: () => { - // closeMenu(); - // }, - // } - // : {}; - return { - onMouseleave: () => { - closeMenu(); - }, - }; + return !unref(getMixSideFixed) + ? { + onMouseleave: () => { + closeMenu(); + }, + } + : {}; }); const getShowDragBar = computed(() => unref(getCanDrag)); @@ -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) { const children = await getChildrenMenus(path); @@ -223,20 +237,24 @@ chilrenMenus.value = children; } + // Set the currently active menu and submenu async function setActive(setChildren = false) { const path = currentRoute.value?.path; if (!path) return; const parentPath = await getCurrentParentPath(path); activePath.value = parentPath; // hanldeModuleClick(parentPath); - if (unref(getMixSideFixed)) { + if (unref(getIsMixSidebar)) { const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath)); const p = activeMenu?.path; if (p) { const children = await getChildrenMenus(p); if (setChildren) { chilrenMenus.value = children; - openMenu.value = children.length > 0; + + if (unref(getMixSideFixed)) { + openMenu.value = children.length > 0; + } } if (children.length === 0) { chilrenMenus.value = []; @@ -271,6 +289,7 @@ }); } + // Close menu function closeMenu() { if (!unref(getIsFixed)) { openMenu.value = false; @@ -298,6 +317,8 @@ getDomStyle, handleFixedMenu, getMixSideFixed, + getWrapStyle, + getCollapsed, }; }, }); @@ -312,14 +333,10 @@ top: 0; left: 0; z-index: @layout-mix-sider-fixed-z-index; - width: @width; height: 100%; - max-width: @width; - min-width: @width; overflow: hidden; background: @sider-dark-bg-color; - transition: all 0.3s ease 0s; - flex: 0 0 @width; + transition: all 0.2s ease 0s; .@{tag-prefix-cls} { position: absolute; top: 6px; @@ -327,13 +344,9 @@ } &-dom { - width: @width; height: 100%; - max-width: @width; - min-width: @width; overflow: hidden; transition: all 0.2s ease 0s; - flex: 0 0 @width; } &-logo { @@ -354,7 +367,7 @@ } &.open { - > .scroll-container { + > .scrollbar { border-right: 1px solid rgb(238, 238, 238); } } @@ -390,7 +403,7 @@ border-bottom: 1px solid @border-color; } - > .scroll-container { + > .scrollbar { border-right: 1px solid @border-color; } } @@ -409,6 +422,16 @@ height: calc(100% - @header-height) !important; } + &.mini &-module { + &__name { + display: none; + } + + &__icon { + margin-bottom: 0; + } + } + &-module { position: relative; padding-top: 1px; @@ -456,7 +479,6 @@ &-menu-list { position: fixed; top: 0; - left: 80px; width: 0; width: 200px; height: calc(100%); diff --git a/src/layouts/default/tabs/components/FoldButton.vue b/src/layouts/default/tabs/components/FoldButton.vue new file mode 100644 index 0000000..c80c4bd --- /dev/null +++ b/src/layouts/default/tabs/components/FoldButton.vue @@ -0,0 +1,47 @@ +<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> diff --git a/src/layouts/default/tabs/index.less b/src/layouts/default/tabs/index.less index 5a5f111..1c46858 100644 --- a/src/layouts/default/tabs/index.less +++ b/src/layouts/default/tabs/index.less @@ -153,7 +153,8 @@ &-content { &__extra-quick, - &__extra-redo { + &__extra-redo, + &__extra-fold { display: inline-block; width: 36px; height: @multiple-height; diff --git a/src/layouts/default/tabs/index.vue b/src/layouts/default/tabs/index.vue index 58a6388..ba01ceb 100644 --- a/src/layouts/default/tabs/index.vue +++ b/src/layouts/default/tabs/index.vue @@ -21,6 +21,7 @@ <template #tabBarExtraContent v-if="getShowRedo || getShowQuick"> <TabRedo v-if="getShowRedo" /> <QuickButton v-if="getShowQuick" /> + <FoldButton v-if="getShowFold" /> </template> </Tabs> </div> @@ -51,6 +52,7 @@ components: { QuickButton: createAsyncComponent(() => import('./components/QuickButton.vue')), TabRedo: createAsyncComponent(() => import('./components/TabRedo.vue')), + FoldButton: createAsyncComponent(() => import('./components/FoldButton.vue')), Tabs, TabPane: Tabs.TabPane, TabContent, @@ -62,7 +64,7 @@ useTabsDrag(affixTextList); const { prefixCls } = useDesign('multiple-tabs'); const go = useGo(); - const { getShowQuick, getShowRedo } = useMultipleTabSetting(); + const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting(); const getTabsState = computed(() => { return tabStore.getTabsState.filter((item) => !item.meta?.hideTab); @@ -125,6 +127,7 @@ getTabsState, getShowQuick, getShowRedo, + getShowFold, }; }, }); diff --git a/src/layouts/default/tabs/useTabDropdown.ts b/src/layouts/default/tabs/useTabDropdown.ts index 21e295b..db9748f 100644 --- a/src/layouts/default/tabs/useTabDropdown.ts +++ b/src/layouts/default/tabs/useTabDropdown.ts @@ -8,8 +8,6 @@ import router from '/@/router'; import { RouteLocationNormalized } from 'vue-router'; import { useTabs } from '/@/hooks/web/useTabs'; import { useI18n } from '/@/hooks/web/useI18n'; -import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; -import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; const { t } = useI18n(); @@ -21,9 +19,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) { const { currentRoute } = router; - const { getShowMenu, setMenuSetting } = useMenuSetting(); - const { getShowHeader, setHeaderSetting } = useHeaderSetting(); - const isTabs = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE); const getCurrentTab = computed( @@ -32,10 +27,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) { } ); - const getIsScale = computed(() => { - return !unref(getShowMenu) && !unref(getShowHeader); - }); - /** * @description: drop-down list */ @@ -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; }); @@ -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 function handleMenuEvent(menu: DropMenu): void { - const { refreshPage, closeAll, closeCurrent, closeLeft, closeOther, closeRight } = useTabs(); + const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs(); const { event } = menu; switch (event) { case MenuEventEnum.SCALE: @@ -150,7 +120,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) { break; // Close current case MenuEventEnum.CLOSE_CURRENT: - closeCurrent(); + close(tabContentProps.tabItem); break; // Close left case MenuEventEnum.CLOSE_LEFT: diff --git a/src/locales/lang/en/layout/multipleTab.ts b/src/locales/lang/en/layout/multipleTab.ts index 596f007..a3b4966 100644 --- a/src/locales/lang/en/layout/multipleTab.ts +++ b/src/locales/lang/en/layout/multipleTab.ts @@ -5,7 +5,5 @@ export default { closeRight: 'Close Right', closeOther: 'Close Other', closeAll: 'Close All', - putAway: 'PutAway', - unfold: 'Unfold', tooltipRedo: 'Refresh', }; diff --git a/src/locales/lang/en/layout/setting.ts b/src/locales/lang/en/layout/setting.ts index 771e9e5..9844572 100644 --- a/src/locales/lang/en/layout/setting.ts +++ b/src/locales/lang/en/layout/setting.ts @@ -56,6 +56,7 @@ export default { tabs: 'Tabs', tabsQuickBtn: 'Tabs quick button', tabsRedoBtn: 'Tabs redo button', + tabsFoldBtn: 'Tabs flod button', sidebar: 'Sidebar', header: 'Header', footer: 'Footer', diff --git a/src/locales/lang/zh_CN/layout/multipleTab.ts b/src/locales/lang/zh_CN/layout/multipleTab.ts index 5e6cc7f..3ca8c49 100644 --- a/src/locales/lang/zh_CN/layout/multipleTab.ts +++ b/src/locales/lang/zh_CN/layout/multipleTab.ts @@ -1,11 +1,9 @@ export default { - redo: '刷新当前', - close: '关闭当前', - closeLeft: '关闭左侧', - closeRight: '关闭右侧', - closeOther: '关闭其他', - closeAll: '关闭全部', - putAway: '收起', - unfold: '展开', + redo: '重新加载', + close: '关闭标签页', + closeLeft: '关闭左侧标签页', + closeRight: '关闭右侧标签页', + closeOther: '关闭其它标签页', + closeAll: '关闭全部标签页', tooltipRedo: '刷新', }; diff --git a/src/locales/lang/zh_CN/layout/setting.ts b/src/locales/lang/zh_CN/layout/setting.ts index 3b2e847..bd0db70 100644 --- a/src/locales/lang/zh_CN/layout/setting.ts +++ b/src/locales/lang/zh_CN/layout/setting.ts @@ -55,6 +55,7 @@ export default { tabs: '标签页', tabsQuickBtn: '标签页快捷按钮', tabsRedoBtn: '标签页刷新按钮', + tabsFoldBtn: '标签页折叠按钮', sidebar: '左侧菜单', header: '顶栏', footer: '页脚', diff --git a/src/settings/componentSetting.ts b/src/settings/componentSetting.ts new file mode 100644 index 0000000..8b3ba8e --- /dev/null +++ b/src/settings/componentSetting.ts @@ -0,0 +1,45 @@ +// 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, + }, +}; diff --git a/src/settings/encryptionSetting.ts b/src/settings/encryptionSetting.ts index 9490e57..3d61776 100644 --- a/src/settings/encryptionSetting.ts +++ b/src/settings/encryptionSetting.ts @@ -5,8 +5,8 @@ export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7; // aes encryption key export const cacheCipher = { - key: '_12345678901234@', - iv: '@12345678901234_', + key: '_11111000001111@', + iv: '@11111000001111_', }; // Whether the system cache is encrypted using aes diff --git a/src/settings/projectSetting.ts b/src/settings/projectSetting.ts index f99215f..c5c9a63 100644 --- a/src/settings/projectSetting.ts +++ b/src/settings/projectSetting.ts @@ -125,6 +125,8 @@ const setting: ProjectConfig = { // Whether to show the refresh button showRedo: true, + // Whether to show the collapse button + showFold: true, }, // Transition Setting diff --git a/src/types/config.d.ts b/src/types/config.d.ts index f7c11e3..cc64fef 100644 --- a/src/types/config.d.ts +++ b/src/types/config.d.ts @@ -33,6 +33,9 @@ export interface MultiTabsSetting { // 显示刷新按钮 showRedo: boolean; + + // 显示折叠按钮 + showFold: boolean; } export interface HeaderSetting { diff --git a/src/views/demo/page/desc/high/index.vue b/src/views/demo/page/desc/high/index.vue index f6997e8..d25bf29 100644 --- a/src/views/demo/page/desc/high/index.vue +++ b/src/views/demo/page/desc/high/index.vue @@ -1,9 +1,9 @@ <template> <PageWrapper title="单号:234231029431" contentBackgrond> <template #extra> - <a-button key="3"> 操作一 </a-button> - <a-button key="2"> 操作二 </a-button> - <a-button key="1" type="primary"> 主操作 </a-button> + <a-button> 操作一 </a-button> + <a-button> 操作二 </a-button> + <a-button type="primary"> 主操作 </a-button> </template> <template #footer> -- libgit2 0.23.3