Commit 0e7c57bd5ecafd8283bcc950b24bb63b59b70e5a

Authored by vben
1 parent 144ab577

feat(tabs): added tab folding

CHANGELOG.zh_CN.md
... ... @@ -6,6 +6,7 @@
6 6 - 新增`mixSideFixed`配置。用于固定左侧混合模式菜单
7 7 - modal 组件新增`height`和`min-height`属性
8 8 - 新增`PageWrapper`组件。并应用于示例页面
  9 +- 新增标签页折叠功能
9 10  
10 11 ### 🐛 Bug Fixes
11 12  
... ...
mock/_createProductionServer.ts
... ... @@ -2,10 +2,18 @@ import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
2 2 import userMock from './sys/user';
3 3 import menuMock from './sys/menu';
4 4 import tableDemoMock from './demo/table-demo';
  5 +import accountDemoMock from './demo/account';
  6 +import selectDemoMock from './demo/select-demo';
5 7  
6 8 /**
7 9 * Used in a production environment. Need to manually import all modules
8 10 */
9 11 export function setupProdMockServer() {
10   - createProdMockServer([...userMock, ...menuMock, ...tableDemoMock]);
  12 + createProdMockServer([
  13 + ...userMock,
  14 + ...menuMock,
  15 + ...tableDemoMock,
  16 + ...accountDemoMock,
  17 + ...selectDemoMock,
  18 + ]);
11 19 }
... ...
src/components/Icon/src/index.vue
... ... @@ -74,7 +74,7 @@
74 74 }
75 75 );
76 76  
77   - // watch(() => props.icon, update, { flush: 'post' });
  77 + watch(() => props.icon, update, { flush: 'post' });
78 78  
79 79 onMounted(update);
80 80  
... ...
src/components/Menu/src/useOpenKeys.ts
... ... @@ -16,16 +16,20 @@ export function useOpenKeys(
16 16 mode: Ref<MenuModeEnum>,
17 17 accordion: Ref<boolean>
18 18 ) {
19   - const { getCollapsed, getIsMixSidebar, getMixSideFixed } = useMenuSetting();
  19 + const { getCollapsed, getIsMixSidebar } = useMenuSetting();
20 20  
21 21 async function setOpenKeys(path: string) {
22 22 if (mode.value === MenuModeEnum.HORIZONTAL) {
23 23 return;
24 24 }
25   - const native = unref(getIsMixSidebar) && unref(getMixSideFixed);
  25 + const native = unref(getIsMixSidebar);
26 26 useTimeoutFn(
27 27 () => {
28 28 const menuList = toRaw(menus.value);
  29 + if (menuList?.length === 0) {
  30 + menuState.openKeys = [];
  31 + return;
  32 + }
29 33 if (!unref(accordion)) {
30 34 menuState.openKeys = es6Unique([
31 35 ...menuState.openKeys,
... ...
src/components/Modal/src/BasicModal.vue
... ... @@ -51,7 +51,6 @@
51 51 watchEffect,
52 52 toRef,
53 53 getCurrentInstance,
54   - nextTick,
55 54 } from 'vue';
56 55  
57 56 import Modal from './components/Modal';
... ... @@ -111,7 +110,6 @@
111 110 visible: unref(visibleRef),
112 111 title: undefined,
113 112 };
114   -
115 113 return {
116 114 ...opt,
117 115 wrapClassName: unref(getWrapClassName),
... ...
src/components/Modal/src/components/ModalWrapper.vue
1 1 <template>
2   - <ScrollContainer ref="wrapperRef" :style="wrapStyle">
  2 + <ScrollContainer ref="wrapperRef">
3 3 <div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip">
4 4 <slot />
5 5 </div>
... ... @@ -62,19 +62,10 @@
62 62 redoModalHeight: setModalHeight,
63 63 });
64 64  
65   - const wrapStyle = computed(
66   - (): CSSProperties => {
67   - return {
68   - minHeight: `${props.minHeight}px`,
69   - height: `${unref(realHeightRef)}px`,
70   - // overflow: 'auto',
71   - };
72   - }
73   - );
74   -
75 65 const spinStyle = computed(
76 66 (): CSSProperties => {
77 67 return {
  68 + minHeight: `${props.minHeight}px`,
78 69 // padding 28
79 70 height: `${unref(realHeightRef) - 28}px`,
80 71 };
... ... @@ -159,7 +150,7 @@
159 150 }
160 151 }
161 152  
162   - return { wrapStyle, wrapperRef, spinRef, spinStyle };
  153 + return { wrapperRef, spinRef, spinStyle };
163 154 },
164 155 });
165 156 </script>
... ...
src/components/Modal/src/index.less
... ... @@ -21,12 +21,9 @@
21 21 width: 520px;
22 22 padding-bottom: 0;
23 23  
24   - .scroll-container {
  24 + .scrollbar {
25 25 padding: 14px;
26 26 }
27   - // .ant-spin-nested-loading {
28   - // padding: 16px;
29   - // }
30 27  
31 28 &-title {
32 29 font-size: 16px;
... ...
src/components/Scrollbar/src/index.vue
... ... @@ -18,7 +18,8 @@
18 18 </template>
19 19 <script lang="ts">
20 20 import { addResizeListener, removeResizeListener } from '/@/utils/event/resizeEvent';
21   -
  21 + import componentSetting from '/@/settings/componentSetting';
  22 + const { scrollbar } = componentSetting;
22 23 import { toObject } from './util';
23 24 import {
24 25 defineComponent,
... ... @@ -38,7 +39,7 @@
38 39 props: {
39 40 native: {
40 41 type: Boolean,
41   - default: false,
  42 + default: scrollbar?.native ?? false,
42 43 },
43 44 wrapStyle: {
44 45 type: [String, Array],
... ...
src/components/Table/src/components/settings/ColumnSetting.vue
... ... @@ -421,7 +421,7 @@
421 421 // flex-wrap: wrap;
422 422 }
423 423  
424   - .scroll-container {
  424 + .scrollbar {
425 425 height: 220px;
426 426 }
427 427 }
... ...
src/components/Table/src/const.ts
1   -import type { SorterResult } from './types/table';
  1 +import componentSetting from '/@/settings/componentSetting';
  2 +
  3 +const { table } = componentSetting;
  4 +
  5 +const { pageSizeOptions, defaultPageSize, fetchSetting, defaultSortFn, defaultFilterFn } = table;
2 6  
3 7 export const ROW_KEY = 'key';
4 8  
5 9 // 可选的每页显示条数;
6   -export const PAGE_SIZE_OPTIONS = ['10', '50', '80', '100'];
  10 +export const PAGE_SIZE_OPTIONS = pageSizeOptions;
7 11  
8 12 // 每页显示条数
9   -export const PAGE_SIZE = ~~PAGE_SIZE_OPTIONS[0];
  13 +export const PAGE_SIZE = defaultPageSize;
10 14  
11 15 // 通用接口字段设置
12   -// 支持 xxx.xxx.xxx格式
13   -export const FETCH_SETTING = {
14   - // 传给后台的当前页字段名
15   - pageField: 'page',
16   - // 传给后台的每页显示记录数字段名
17   - sizeField: 'pageSize',
18   - // 接口返回的表格数据字段名
19   - listField: 'items',
20   - // 接口返回的表格总数字段名
21   - totalField: 'total',
22   -};
  16 +export const FETCH_SETTING = fetchSetting;
23 17  
24 18 // 配置通用排序函数
25   -export function DEFAULT_SORT_FN(sortInfo: SorterResult) {
26   - const { field, order } = sortInfo;
27   - return {
28   - // 传给后台的排序字段你
29   - field,
30   - // 传给后台的排序方式 asc/desc
31   - order,
32   - };
33   -}
34   -
35   -export function DEFAULT_FILTER_FN(data: Partial<Recordable<string[]>>) {
36   - return data;
37   -}
  19 +export const DEFAULT_SORT_FN = defaultSortFn;
  20 +
  21 +export const DEFAULT_FILTER_FN = defaultFilterFn;
38 22  
39 23 // 表格单元格默认布局
40 24 export const DEFAULT_ALIGN = 'center';
... ...
src/hooks/setting/useMenuSetting.ts
... ... @@ -78,7 +78,9 @@ const getIsMixMode = computed(() =&gt; {
78 78 });
79 79  
80 80 const getRealWidth = computed(() => {
81   - return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth);
  81 + return unref(getCollapsed) && !unref(getMixSideFixed)
  82 + ? unref(getMiniWidthNumber)
  83 + : unref(getMenuWidth);
82 84 });
83 85  
84 86 const getMiniWidthNumber = computed(() => {
... ... @@ -94,7 +96,6 @@ const getCalcContentWidth = computed(() =&gt; {
94 96 ? SIDE_BAR_SHOW_TIT_MINI_WIDTH +
95 97 (unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0)
96 98 : unref(getRealWidth);
97   -
98 99 return `calc(100% - ${unref(width)}px)`;
99 100 });
100 101  
... ...
src/hooks/setting/useMultipleTabSetting.ts
... ... @@ -12,6 +12,8 @@ const getShowQuick = computed(() =&gt; unref(getMultipleTabSetting).showQuick);
12 12  
13 13 const getShowRedo = computed(() => unref(getMultipleTabSetting).showRedo);
14 14  
  15 +const getShowFold = computed(() => unref(getMultipleTabSetting).showFold);
  16 +
15 17 function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
16 18 appStore.commitProjectConfigState({ multiTabsSetting });
17 19 }
... ... @@ -24,5 +26,6 @@ export function useMultipleTabSetting() {
24 26 getShowMultipleTab,
25 27 getShowQuick,
26 28 getShowRedo,
  29 + getShowFold,
27 30 };
28 31 }
... ...
src/hooks/web/useTabs.ts
1 1 import { tabStore } from '/@/store/modules/tab';
2 2 import { appStore } from '/@/store/modules/app';
  3 +import type { RouteLocationNormalized } from 'vue-router';
3 4  
4 5 export function useTabs() {
5 6 function canIUseFn(): boolean {
... ... @@ -21,5 +22,7 @@ export function useTabs() {
21 22 closeRight: () => canIUseFn() && tabStore.closeRightTabAction(tabStore.getCurrentTab),
22 23 closeOther: () => canIUseFn() && tabStore.closeOtherTabAction(tabStore.getCurrentTab),
23 24 closeCurrent: () => canIUseFn() && tabStore.closeTabAction(tabStore.getCurrentTab),
  25 + close: (tab?: RouteLocationNormalized) =>
  26 + canIUseFn() && tabStore.closeTabAction(tab || tabStore.getCurrentTab),
24 27 };
25 28 }
... ...
src/layouts/default/setting/SettingDrawer.tsx
... ... @@ -85,7 +85,7 @@ export default defineComponent({
85 85 getShowSearch,
86 86 } = useHeaderSetting();
87 87  
88   - const { getShowMultipleTab, getShowQuick, getShowRedo } = useMultipleTabSetting();
  88 + const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
89 89  
90 90 const getShowMenuRef = computed(() => {
91 91 return unref(getShowMenu) && !unref(getIsHorizontal);
... ... @@ -105,33 +105,6 @@ export default defineComponent({
105 105 }}
106 106 def={unref(getMenuType)}
107 107 />
108   - <SwitchItem
109   - title={t('layout.setting.splitMenu')}
110   - event={HandlerEnum.MENU_SPLIT}
111   - def={unref(getSplit)}
112   - disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
113   - />
114   - <SwitchItem
115   - title={t('layout.setting.mixSidebarFixed')}
116   - event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
117   - def={unref(getMixSideFixed)}
118   - disabled={!unref(getIsMixSidebar)}
119   - />
120   -
121   - <SwitchItem
122   - title={t('layout.setting.closeMixSidebarOnChange')}
123   - event={HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE}
124   - def={unref(getCloseMixSidebarOnChange)}
125   - disabled={!unref(getIsMixSidebar)}
126   - />
127   -
128   - <SelectItem
129   - title={t('layout.setting.mixSidebarTrigger')}
130   - event={HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR}
131   - def={unref(getMixSideTrigger)}
132   - options={mixSidebarTriggerOptions}
133   - disabled={!unref(getIsMixSidebar)}
134   - />
135 108 </>
136 109 );
137 110 }
... ... @@ -171,6 +144,32 @@ export default defineComponent({
171 144 return (
172 145 <>
173 146 <SwitchItem
  147 + title={t('layout.setting.splitMenu')}
  148 + event={HandlerEnum.MENU_SPLIT}
  149 + def={unref(getSplit)}
  150 + disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
  151 + />
  152 + <SwitchItem
  153 + title={t('layout.setting.mixSidebarFixed')}
  154 + event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
  155 + def={unref(getMixSideFixed)}
  156 + disabled={!unref(getIsMixSidebar)}
  157 + />
  158 +
  159 + <SwitchItem
  160 + title={t('layout.setting.closeMixSidebarOnChange')}
  161 + event={HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE}
  162 + def={unref(getCloseMixSidebarOnChange)}
  163 + disabled={!unref(getIsMixSidebar)}
  164 + />
  165 + <SwitchItem
  166 + title={t('layout.setting.menuCollapse')}
  167 + event={HandlerEnum.MENU_COLLAPSED}
  168 + def={unref(getCollapsed)}
  169 + disabled={!unref(getShowMenuRef)}
  170 + />
  171 +
  172 + <SwitchItem
174 173 title={t('layout.setting.menuDrag')}
175 174 event={HandlerEnum.MENU_HAS_DRAG}
176 175 def={unref(getCanDrag)}
... ... @@ -188,17 +187,12 @@ export default defineComponent({
188 187 def={unref(getAccordion)}
189 188 disabled={!unref(getShowMenuRef)}
190 189 />
191   - <SwitchItem
192   - title={t('layout.setting.menuCollapse')}
193   - event={HandlerEnum.MENU_COLLAPSED}
194   - def={unref(getCollapsed)}
195   - disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)}
196   - />
  190 +
197 191 <SwitchItem
198 192 title={t('layout.setting.collapseMenuDisplayName')}
199 193 event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE}
200 194 def={unref(getCollapsedShowTitle)}
201   - disabled={!unref(getShowMenuRef) || !unref(getCollapsed)}
  195 + disabled={!unref(getShowMenuRef) || !unref(getCollapsed) || unref(getIsMixSidebar)}
202 196 />
203 197  
204 198 <SwitchItem
... ... @@ -214,6 +208,13 @@ export default defineComponent({
214 208 disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)}
215 209 />
216 210 <SelectItem
  211 + title={t('layout.setting.mixSidebarTrigger')}
  212 + event={HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR}
  213 + def={unref(getMixSideTrigger)}
  214 + options={mixSidebarTriggerOptions}
  215 + disabled={!unref(getIsMixSidebar)}
  216 + />
  217 + <SelectItem
217 218 title={t('layout.setting.topMenuLayout')}
218 219 event={HandlerEnum.MENU_TOP_ALIGN}
219 220 def={unref(getTopMenuAlign)}
... ... @@ -299,6 +300,12 @@ export default defineComponent({
299 300 def={unref(getShowQuick)}
300 301 disabled={!unref(getShowMultipleTab)}
301 302 />
  303 + <SwitchItem
  304 + title={t('layout.setting.tabsFoldBtn')}
  305 + event={HandlerEnum.TABS_SHOW_FOLD}
  306 + def={unref(getShowFold)}
  307 + disabled={!unref(getShowMultipleTab)}
  308 + />
302 309  
303 310 <SwitchItem
304 311 title={t('layout.setting.sidebar')}
... ...
src/layouts/default/setting/enum.ts
... ... @@ -39,6 +39,7 @@ export enum HandlerEnum {
39 39 TABS_SHOW_QUICK,
40 40 TABS_SHOW_REDO,
41 41 TABS_SHOW,
  42 + TABS_SHOW_FOLD,
42 43  
43 44 LOCK_TIME,
44 45 FULL_CONTENT,
... ...
src/layouts/default/setting/handler.ts
... ... @@ -71,7 +71,7 @@ export function handler(event: HandlerEnum, value: any): DeepPartial&lt;ProjectConf
71 71 return { menuSetting: { mixSideTrigger: value } };
72 72  
73 73 case HandlerEnum.MENU_FIXED_MIX_SIDEBAR:
74   - return { menuSetting: { mixSideTrigger: value } };
  74 + return { menuSetting: { mixSideFixed: value } };
75 75  
76 76 // ============transition==================
77 77 case HandlerEnum.OPEN_PAGE_LOADING:
... ... @@ -123,9 +123,13 @@ export function handler(event: HandlerEnum, value: any): DeepPartial&lt;ProjectConf
123 123  
124 124 case HandlerEnum.TABS_SHOW:
125 125 return { multiTabsSetting: { show: value } };
  126 +
126 127 case HandlerEnum.TABS_SHOW_REDO:
127 128 return { multiTabsSetting: { showRedo: value } };
128 129  
  130 + case HandlerEnum.TABS_SHOW_FOLD:
  131 + return { multiTabsSetting: { showFold: value } };
  132 +
129 133 // ============header==================
130 134 case HandlerEnum.HEADER_THEME:
131 135 updateHeaderBgColor(value);
... ...
src/layouts/default/sider/MixSider.vue
... ... @@ -3,11 +3,13 @@
3 3  
4 4 <div
5 5 v-click-outside="handleClickOutside"
  6 + :style="getWrapStyle"
6 7 :class="[
7 8 prefixCls,
8 9 getMenuTheme,
9 10 {
10 11 open: openMenu,
  12 + mini: getCollapsed,
11 13 },
12 14 ]"
13 15 v-bind="getMenuEvents"
... ... @@ -29,7 +31,7 @@
29 31 <MenuTag :item="item" :showTitle="false" :isHorizontal="false" />
30 32 <Icon
31 33 :class="`${prefixCls}-module__icon`"
32   - :size="22"
  34 + :size="getCollapsed ? 16 : 20"
33 35 :icon="item.meta && item.meta.icon"
34 36 />
35 37 <p :class="`${prefixCls}-module__name`">{{ t(item.name) }}</p>
... ... @@ -50,12 +52,10 @@
50 52 <span class="text"> {{ title }}</span>
51 53 <Icon
52 54 :size="16"
53   - v-if="getMixSideFixed"
54   - icon="ri:pushpin-2-fill"
  55 + :icon="getMixSideFixed ? 'ri:pushpin-2-fill' : 'ri:pushpin-2-line'"
55 56 class="pushpin"
56 57 @click="handleFixedMenu"
57 58 />
58   - <Icon :size="16" v-else icon="ri:pushpin-2-line" class="pushpin" @click="handleFixedMenu" />
59 59 </div>
60 60 <ScrollContainer :class="`${prefixCls}-menu-list__content`">
61 61 <BasicMenu
... ... @@ -92,7 +92,7 @@
92 92 import { useDragLine } from './useLayoutSider';
93 93 import { useGlobSetting } from '/@/hooks/setting';
94 94  
95   - import { SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
  95 + import { SIDE_BAR_SHOW_TIT_MINI_WIDTH, SIDE_BAR_MINI_WIDTH } from '/@/enums/appEnum';
96 96  
97 97 import clickOutside from '/@/directives/clickOutside';
98 98  
... ... @@ -130,6 +130,8 @@
130 130 getMixSideFixed,
131 131 mixSideHasChildren,
132 132 setMenuSetting,
  133 + getIsMixSidebar,
  134 + getCollapsed,
133 135 } = useMenuSetting();
134 136  
135 137 const { title } = useGlobSetting();
... ... @@ -140,6 +142,7 @@
140 142 (): CSSProperties => {
141 143 return {
142 144 width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
  145 + left: `${unref(getMixSideWidth)}px`,
143 146 };
144 147 }
145 148 );
... ... @@ -153,32 +156,33 @@
153 156 return isFixed;
154 157 });
155 158  
  159 + const getMixSideWidth = computed(() => {
  160 + return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH;
  161 + });
  162 +
156 163 const getDomStyle = computed(
157 164 (): CSSProperties => {
158 165 const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
159   - const width = `${SIDE_BAR_SHOW_TIT_MINI_WIDTH + fixedWidth}px`;
160   - return {
161   - width,
162   - maxWidth: width,
163   - minWidth: width,
164   - flex: `0 0 ${width}`,
165   - };
  166 + const width = `${unref(getMixSideWidth) + fixedWidth}px`;
  167 + return getWrapCommonStyle(width);
  168 + }
  169 + );
  170 +
  171 + const getWrapStyle = computed(
  172 + (): CSSProperties => {
  173 + const width = `${unref(getMixSideWidth)}px`;
  174 + return getWrapCommonStyle(width);
166 175 }
167 176 );
168 177  
169 178 const getMenuEvents = computed(() => {
170   - // return unref(getMixSideTrigger) === 'hover'
171   - // ? {
172   - // onMouseleave: () => {
173   - // closeMenu();
174   - // },
175   - // }
176   - // : {};
177   - return {
178   - onMouseleave: () => {
179   - closeMenu();
180   - },
181   - };
  179 + return !unref(getMixSideFixed)
  180 + ? {
  181 + onMouseleave: () => {
  182 + closeMenu();
  183 + },
  184 + }
  185 + : {};
182 186 });
183 187  
184 188 const getShowDragBar = computed(() => unref(getCanDrag));
... ... @@ -195,6 +199,16 @@
195 199 }
196 200 });
197 201  
  202 + function getWrapCommonStyle(width: string): CSSProperties {
  203 + return {
  204 + width,
  205 + maxWidth: width,
  206 + minWidth: width,
  207 + flex: `0 0 ${width}`,
  208 + };
  209 + }
  210 +
  211 + // Process module menu click
198 212 async function hanldeModuleClick(path: string, hover = false) {
199 213 const children = await getChildrenMenus(path);
200 214  
... ... @@ -223,20 +237,24 @@
223 237 chilrenMenus.value = children;
224 238 }
225 239  
  240 + // Set the currently active menu and submenu
226 241 async function setActive(setChildren = false) {
227 242 const path = currentRoute.value?.path;
228 243 if (!path) return;
229 244 const parentPath = await getCurrentParentPath(path);
230 245 activePath.value = parentPath;
231 246 // hanldeModuleClick(parentPath);
232   - if (unref(getMixSideFixed)) {
  247 + if (unref(getIsMixSidebar)) {
233 248 const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
234 249 const p = activeMenu?.path;
235 250 if (p) {
236 251 const children = await getChildrenMenus(p);
237 252 if (setChildren) {
238 253 chilrenMenus.value = children;
239   - openMenu.value = children.length > 0;
  254 +
  255 + if (unref(getMixSideFixed)) {
  256 + openMenu.value = children.length > 0;
  257 + }
240 258 }
241 259 if (children.length === 0) {
242 260 chilrenMenus.value = [];
... ... @@ -271,6 +289,7 @@
271 289 });
272 290 }
273 291  
  292 + // Close menu
274 293 function closeMenu() {
275 294 if (!unref(getIsFixed)) {
276 295 openMenu.value = false;
... ... @@ -298,6 +317,8 @@
298 317 getDomStyle,
299 318 handleFixedMenu,
300 319 getMixSideFixed,
  320 + getWrapStyle,
  321 + getCollapsed,
301 322 };
302 323 },
303 324 });
... ... @@ -312,14 +333,10 @@
312 333 top: 0;
313 334 left: 0;
314 335 z-index: @layout-mix-sider-fixed-z-index;
315   - width: @width;
316 336 height: 100%;
317   - max-width: @width;
318   - min-width: @width;
319 337 overflow: hidden;
320 338 background: @sider-dark-bg-color;
321   - transition: all 0.3s ease 0s;
322   - flex: 0 0 @width;
  339 + transition: all 0.2s ease 0s;
323 340 .@{tag-prefix-cls} {
324 341 position: absolute;
325 342 top: 6px;
... ... @@ -327,13 +344,9 @@
327 344 }
328 345  
329 346 &-dom {
330   - width: @width;
331 347 height: 100%;
332   - max-width: @width;
333   - min-width: @width;
334 348 overflow: hidden;
335 349 transition: all 0.2s ease 0s;
336   - flex: 0 0 @width;
337 350 }
338 351  
339 352 &-logo {
... ... @@ -354,7 +367,7 @@
354 367 }
355 368  
356 369 &.open {
357   - > .scroll-container {
  370 + > .scrollbar {
358 371 border-right: 1px solid rgb(238, 238, 238);
359 372 }
360 373 }
... ... @@ -390,7 +403,7 @@
390 403 border-bottom: 1px solid @border-color;
391 404 }
392 405  
393   - > .scroll-container {
  406 + > .scrollbar {
394 407 border-right: 1px solid @border-color;
395 408 }
396 409 }
... ... @@ -409,6 +422,16 @@
409 422 height: calc(100% - @header-height) !important;
410 423 }
411 424  
  425 + &.mini &-module {
  426 + &__name {
  427 + display: none;
  428 + }
  429 +
  430 + &__icon {
  431 + margin-bottom: 0;
  432 + }
  433 + }
  434 +
412 435 &-module {
413 436 position: relative;
414 437 padding-top: 1px;
... ... @@ -456,7 +479,6 @@
456 479 &-menu-list {
457 480 position: fixed;
458 481 top: 0;
459   - left: 80px;
460 482 width: 0;
461 483 width: 200px;
462 484 height: calc(100%);
... ...
src/layouts/default/tabs/components/FoldButton.vue 0 → 100644
  1 +<template>
  2 + <span :class="`${prefixCls}__extra-fold`" @click="handleFold">
  3 + <Icon :icon="getIcon" />
  4 + </span>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent, unref, computed } from 'vue';
  8 + import { RedoOutlined } from '@ant-design/icons-vue';
  9 + import { useDesign } from '/@/hooks/web/useDesign';
  10 + import { Tooltip } from 'ant-design-vue';
  11 + import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
  12 + import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
  13 +
  14 + import Icon from '/@/components/Icon';
  15 +
  16 + export default defineComponent({
  17 + name: 'FoldButton',
  18 + components: { RedoOutlined, Tooltip, Icon },
  19 +
  20 + setup() {
  21 + const { prefixCls } = useDesign('multiple-tabs-content');
  22 + const { getShowMenu, setMenuSetting } = useMenuSetting();
  23 + const { getShowHeader, setHeaderSetting } = useHeaderSetting();
  24 +
  25 + const getIsUnFold = computed(() => {
  26 + return !unref(getShowMenu) && !unref(getShowHeader);
  27 + });
  28 +
  29 + const getIcon = computed(() => {
  30 + return unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full';
  31 + });
  32 +
  33 + function handleFold() {
  34 + const isScale = !unref(getShowMenu) && !unref(getShowHeader);
  35 + setMenuSetting({
  36 + show: isScale,
  37 + hidden: !isScale,
  38 + });
  39 + setHeaderSetting({
  40 + show: isScale,
  41 + });
  42 + }
  43 +
  44 + return { prefixCls, getIcon, handleFold };
  45 + },
  46 + });
  47 +</script>
... ...
src/layouts/default/tabs/index.less
... ... @@ -153,7 +153,8 @@
153 153  
154 154 &-content {
155 155 &__extra-quick,
156   - &__extra-redo {
  156 + &__extra-redo,
  157 + &__extra-fold {
157 158 display: inline-block;
158 159 width: 36px;
159 160 height: @multiple-height;
... ...
src/layouts/default/tabs/index.vue
... ... @@ -21,6 +21,7 @@
21 21 <template #tabBarExtraContent v-if="getShowRedo || getShowQuick">
22 22 <TabRedo v-if="getShowRedo" />
23 23 <QuickButton v-if="getShowQuick" />
  24 + <FoldButton v-if="getShowFold" />
24 25 </template>
25 26 </Tabs>
26 27 </div>
... ... @@ -51,6 +52,7 @@
51 52 components: {
52 53 QuickButton: createAsyncComponent(() => import('./components/QuickButton.vue')),
53 54 TabRedo: createAsyncComponent(() => import('./components/TabRedo.vue')),
  55 + FoldButton: createAsyncComponent(() => import('./components/FoldButton.vue')),
54 56 Tabs,
55 57 TabPane: Tabs.TabPane,
56 58 TabContent,
... ... @@ -62,7 +64,7 @@
62 64 useTabsDrag(affixTextList);
63 65 const { prefixCls } = useDesign('multiple-tabs');
64 66 const go = useGo();
65   - const { getShowQuick, getShowRedo } = useMultipleTabSetting();
  67 + const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
66 68  
67 69 const getTabsState = computed(() => {
68 70 return tabStore.getTabsState.filter((item) => !item.meta?.hideTab);
... ... @@ -125,6 +127,7 @@
125 127 getTabsState,
126 128 getShowQuick,
127 129 getShowRedo,
  130 + getShowFold,
128 131 };
129 132 },
130 133 });
... ...
src/layouts/default/tabs/useTabDropdown.ts
... ... @@ -8,8 +8,6 @@ import router from &#39;/@/router&#39;;
8 8 import { RouteLocationNormalized } from 'vue-router';
9 9 import { useTabs } from '/@/hooks/web/useTabs';
10 10 import { useI18n } from '/@/hooks/web/useI18n';
11   -import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
12   -import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
13 11  
14 12 const { t } = useI18n();
15 13  
... ... @@ -21,9 +19,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
21 19  
22 20 const { currentRoute } = router;
23 21  
24   - const { getShowMenu, setMenuSetting } = useMenuSetting();
25   - const { getShowHeader, setHeaderSetting } = useHeaderSetting();
26   -
27 22 const isTabs = computed(() => tabContentProps.type === TabContentEnum.TAB_TYPE);
28 23  
29 24 const getCurrentTab = computed(
... ... @@ -32,10 +27,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
32 27 }
33 28 );
34 29  
35   - const getIsScale = computed(() => {
36   - return !unref(getShowMenu) && !unref(getShowHeader);
37   - });
38   -
39 30 /**
40 31 * @description: drop-down list
41 32 */
... ... @@ -98,16 +89,6 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
98 89 },
99 90 ];
100 91  
101   - if (!unref(isTabs)) {
102   - const isScale = unref(getIsScale);
103   - dropMenuList.unshift({
104   - icon: isScale ? 'codicon:screen-normal' : 'codicon:screen-full',
105   - event: MenuEventEnum.SCALE,
106   - text: isScale ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
107   - disabled: false,
108   - });
109   - }
110   -
111 92 return dropMenuList;
112 93 });
113 94  
... ... @@ -125,20 +106,9 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
125 106 };
126 107 }
127 108  
128   - function scaleScreen() {
129   - const isScale = !unref(getShowMenu) && !unref(getShowHeader);
130   - setMenuSetting({
131   - show: isScale,
132   - hidden: !isScale,
133   - });
134   - setHeaderSetting({
135   - show: isScale,
136   - });
137   - }
138   -
139 109 // Handle right click event
140 110 function handleMenuEvent(menu: DropMenu): void {
141   - const { refreshPage, closeAll, closeCurrent, closeLeft, closeOther, closeRight } = useTabs();
  111 + const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs();
142 112 const { event } = menu;
143 113 switch (event) {
144 114 case MenuEventEnum.SCALE:
... ... @@ -150,7 +120,7 @@ export function useTabDropdown(tabContentProps: TabContentProps) {
150 120 break;
151 121 // Close current
152 122 case MenuEventEnum.CLOSE_CURRENT:
153   - closeCurrent();
  123 + close(tabContentProps.tabItem);
154 124 break;
155 125 // Close left
156 126 case MenuEventEnum.CLOSE_LEFT:
... ...
src/locales/lang/en/layout/multipleTab.ts
... ... @@ -5,7 +5,5 @@ export default {
5 5 closeRight: 'Close Right',
6 6 closeOther: 'Close Other',
7 7 closeAll: 'Close All',
8   - putAway: 'PutAway',
9   - unfold: 'Unfold',
10 8 tooltipRedo: 'Refresh',
11 9 };
... ...
src/locales/lang/en/layout/setting.ts
... ... @@ -56,6 +56,7 @@ export default {
56 56 tabs: 'Tabs',
57 57 tabsQuickBtn: 'Tabs quick button',
58 58 tabsRedoBtn: 'Tabs redo button',
  59 + tabsFoldBtn: 'Tabs flod button',
59 60 sidebar: 'Sidebar',
60 61 header: 'Header',
61 62 footer: 'Footer',
... ...
src/locales/lang/zh_CN/layout/multipleTab.ts
1 1 export default {
2   - redo: '刷新当前',
3   - close: '关闭当前',
4   - closeLeft: '关闭左侧',
5   - closeRight: '关闭右侧',
6   - closeOther: '关闭其他',
7   - closeAll: '关闭全部',
8   - putAway: '收起',
9   - unfold: '展开',
  2 + redo: '重新加载',
  3 + close: '关闭标签页',
  4 + closeLeft: '关闭左侧标签页',
  5 + closeRight: '关闭右侧标签页',
  6 + closeOther: '关闭其它标签页',
  7 + closeAll: '关闭全部标签页',
10 8 tooltipRedo: '刷新',
11 9 };
... ...
src/locales/lang/zh_CN/layout/setting.ts
... ... @@ -55,6 +55,7 @@ export default {
55 55 tabs: '标签页',
56 56 tabsQuickBtn: '标签页快捷按钮',
57 57 tabsRedoBtn: '标签页刷新按钮',
  58 + tabsFoldBtn: '标签页折叠按钮',
58 59 sidebar: '左侧菜单',
59 60 header: '顶栏',
60 61 footer: '页脚',
... ...
src/settings/componentSetting.ts 0 → 100644
  1 +// Used to configure the general configuration of some components without modifying the components
  2 +
  3 +import type { SorterResult } from '../components/Table';
  4 +
  5 +export default {
  6 + // basic-table setting
  7 + table: {
  8 + // Form interface request general configuration
  9 + // support xxx.xxx.xxx
  10 + fetchSetting: {
  11 + // The field name of the current page passed to the background
  12 + pageField: 'page',
  13 + // The number field name of each page displayed in the background
  14 + sizeField: 'pageSize',
  15 + // Field name of the form data returned by the interface
  16 + listField: 'items',
  17 + // Total number of tables returned by the interface field name
  18 + totalField: 'total',
  19 + },
  20 + // Number of pages that can be selected
  21 + pageSizeOptions: ['10', '50', '80', '100'],
  22 + // Default display quantity on one page
  23 + defaultPageSize: 10,
  24 + // Custom general sort function
  25 + defaultSortFn: (sortInfo: SorterResult) => {
  26 + const { field, order } = sortInfo;
  27 + return {
  28 + // The sort field passed to the backend you
  29 + field,
  30 + // Sorting method passed to the background asc/desc
  31 + order,
  32 + };
  33 + },
  34 + // Custom general filter function
  35 + defaultFilterFn: (data: Partial<Recordable<string[]>>) => {
  36 + return data;
  37 + },
  38 + },
  39 + // scrollbar setting
  40 + scrollbar: {
  41 + // Whether to use native scroll bar
  42 + // After opening, the menu, modal, drawer will change the pop-up scroll bar to native
  43 + native: false,
  44 + },
  45 +};
... ...
src/settings/encryptionSetting.ts
... ... @@ -5,8 +5,8 @@ export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
5 5  
6 6 // aes encryption key
7 7 export const cacheCipher = {
8   - key: '_12345678901234@',
9   - iv: '@12345678901234_',
  8 + key: '_11111000001111@',
  9 + iv: '@11111000001111_',
10 10 };
11 11  
12 12 // Whether the system cache is encrypted using aes
... ...
src/settings/projectSetting.ts
... ... @@ -125,6 +125,8 @@ const setting: ProjectConfig = {
125 125  
126 126 // Whether to show the refresh button
127 127 showRedo: true,
  128 + // Whether to show the collapse button
  129 + showFold: true,
128 130 },
129 131  
130 132 // Transition Setting
... ...
src/types/config.d.ts
... ... @@ -33,6 +33,9 @@ export interface MultiTabsSetting {
33 33  
34 34 // 显示刷新按钮
35 35 showRedo: boolean;
  36 +
  37 + // 显示折叠按钮
  38 + showFold: boolean;
36 39 }
37 40  
38 41 export interface HeaderSetting {
... ...
src/views/demo/page/desc/high/index.vue
1 1 <template>
2 2 <PageWrapper title="单号:234231029431" contentBackgrond>
3 3 <template #extra>
4   - <a-button key="3"> 操作一 </a-button>
5   - <a-button key="2"> 操作二 </a-button>
6   - <a-button key="1" type="primary"> 主操作 </a-button>
  4 + <a-button> 操作一 </a-button>
  5 + <a-button> 操作二 </a-button>
  6 + <a-button type="primary"> 主操作 </a-button>
7 7 </template>
8 8  
9 9 <template #footer>
... ...