Commit 4f6b65b8a1b7e694718b4aa42aced1e59e90ec9e
1 parent
58f988a7
feat(trigger): add trigger config
Showing
22 changed files
with
255 additions
and
68 deletions
CHANGELOG.zh_CN.md
1 | 1 | ## Wip |
2 | 2 | |
3 | +### ✨ Features | |
4 | + | |
5 | +- 菜单 trigger 可以选择位置 | |
6 | +- 增加富文本嵌入表单的示例 | |
7 | +- 表单组件 schema 增加 `required`属性。简化配置 | |
8 | +- openModal 和 openDrawer 第二个参数可以代替`transferModalData`传参到内部 | |
9 | + | |
3 | 10 | ### ⚡ Performance Improvements |
4 | 11 | |
5 | 12 | - 菜单性能继续优化,更流畅 |
6 | 13 | - 优化懒加载组件及示例 |
14 | +- layout 样式微调 | |
7 | 15 | |
8 | 16 | ### 🎫 Chores |
9 | 17 | ... | ... |
package.json
src/App.vue
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | |
12 | 12 | import zhCN from 'ant-design-vue/es/locale/zh_CN'; |
13 | 13 | import moment from 'moment'; |
14 | - import 'moment/locale/zh-cn'; | |
14 | + import 'moment/dist/locale/zh-cn'; | |
15 | 15 | |
16 | 16 | import { useConfigProvider, useInitAppConfigStore, useListenerNetWork } from './useApp'; |
17 | 17 | import { useLockPage } from '/@/hooks/web/useLockPage'; | ... | ... |
src/components/Menu/src/BasicMenu.tsx
src/components/Menu/src/MenuContent.tsx
... | ... | @@ -32,7 +32,7 @@ export default defineComponent({ |
32 | 32 | * @description: 渲染图标 |
33 | 33 | */ |
34 | 34 | function renderIcon(icon: string) { |
35 | - return icon ? <Icon icon={icon} size={18} class="mr-1 menu-item-icon" /> : null; | |
35 | + return icon ? <Icon icon={icon} size={18} class="menu-item-icon" /> : null; | |
36 | 36 | } |
37 | 37 | |
38 | 38 | return () => { | ... | ... |
src/components/Menu/src/index.less
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | font-size: 12px; |
42 | 42 | flex-direction: column; |
43 | 43 | align-items: center; |
44 | + line-height: 24px; | |
44 | 45 | } |
45 | 46 | |
46 | 47 | & > li > .ant-menu-submenu-title { |
... | ... | @@ -183,9 +184,17 @@ |
183 | 184 | transition: unset; |
184 | 185 | } |
185 | 186 | |
187 | + &:not(.basic-menu__sidebar-hor).ant-menu-inline-collapsed { | |
188 | + .basic-menu-item__level1 { | |
189 | + > div { | |
190 | + align-items: center; | |
191 | + } | |
192 | + } | |
193 | + } | |
194 | + | |
186 | 195 | &.ant-menu-dark:not(.basic-menu__sidebar-hor):not(.basic-menu__second) { |
187 | 196 | // Reset menu item row height |
188 | - .ant-menu-item, | |
197 | + .ant-menu-item:not(.basic-menu-item__level1), | |
189 | 198 | .ant-menu-sub.ant-menu-inline > .ant-menu-item, |
190 | 199 | .ant-menu-sub.ant-menu-inline > .ant-menu-submenu > .ant-menu-submenu-title { |
191 | 200 | height: @app-menu-item-height; | ... | ... |
src/enums/menuEnum.ts
... | ... | @@ -17,6 +17,16 @@ export enum MenuThemeEnum { |
17 | 17 | LIGHT = 'light', |
18 | 18 | } |
19 | 19 | |
20 | +// 折叠触发器位置 | |
21 | +export enum TriggerEnum { | |
22 | + // 不显示 | |
23 | + NONE = 'NONE', | |
24 | + // 菜单底部 | |
25 | + FOOTER = 'FOOTER', | |
26 | + // 头部 | |
27 | + HEADER = 'HEADER', | |
28 | +} | |
29 | + | |
20 | 30 | export type Mode = 'vertical' | 'vertical-right' | 'horizontal' | 'inline'; |
21 | 31 | |
22 | 32 | // menu mode | ... | ... |
src/layouts/Logo.vue
1 | 1 | <template> |
2 | - <div class="app-logo anticon" @click="handleGoHome" :style="wrapStyle"> | |
2 | + <div class="app-logo anticon" :class="theme" @click="handleGoHome" :style="wrapStyle"> | |
3 | 3 | <img :src="logo" /> |
4 | 4 | <div v-if="show" class="logo-title ml-2 ellipsis">{{ globSetting.title }}</div> |
5 | 5 | </div> |
... | ... | @@ -26,6 +26,9 @@ |
26 | 26 | type: Boolean as PropType<boolean>, |
27 | 27 | default: true, |
28 | 28 | }, |
29 | + theme: { | |
30 | + type: String, | |
31 | + }, | |
29 | 32 | }, |
30 | 33 | setup(props) { |
31 | 34 | const showRef = ref<boolean>(!!props.showTitle); |
... | ... | @@ -80,6 +83,9 @@ |
80 | 83 | padding-left: 16px; |
81 | 84 | cursor: pointer; |
82 | 85 | // justify-content: center; |
86 | + &.light { | |
87 | + border-bottom: 1px solid @border-color-base; | |
88 | + } | |
83 | 89 | |
84 | 90 | .logo-title { |
85 | 91 | font-size: 18px; | ... | ... |
src/layouts/default/LayoutContent.tsx
1 | 1 | import { defineComponent } from 'vue'; |
2 | -import { Layout } from 'ant-design-vue'; | |
2 | +// import { Layout } from 'ant-design-vue'; | |
3 | 3 | // hooks |
4 | 4 | |
5 | 5 | import { ContentEnum } from '/@/enums/appEnum'; |
... | ... | @@ -13,9 +13,9 @@ export default defineComponent({ |
13 | 13 | const { contentMode } = getProjectConfig; |
14 | 14 | const wrapClass = contentMode === ContentEnum.FULL ? 'full' : 'fixed'; |
15 | 15 | return ( |
16 | - <Layout.Content class={`layout-content ${wrapClass} `}> | |
17 | - {() => <PageLayout />} | |
18 | - </Layout.Content> | |
16 | + // <Layout.Content class={`layout-content ${wrapClass} `}> | |
17 | + <PageLayout class={`layout-content ${wrapClass} `} /> | |
18 | + // </Layout.Content> | |
19 | 19 | ); |
20 | 20 | }; |
21 | 21 | }, | ... | ... |
src/layouts/default/LayoutHeader.tsx
... | ... | @@ -6,6 +6,7 @@ import UserDropdown from './UserDropdown'; |
6 | 6 | import LayoutMenu from './LayoutMenu'; |
7 | 7 | import LayoutBreadcrumb from './LayoutBreadcrumb'; |
8 | 8 | import LockAction from './actions/LockActionItem'; |
9 | +import LayoutTrigger from './LayoutTrigger'; | |
9 | 10 | import NoticeAction from './actions/notice/NoticeActionItem.vue'; |
10 | 11 | import { |
11 | 12 | RedoOutlined, |
... | ... | @@ -25,7 +26,7 @@ import { useModal } from '/@/components/Modal/index'; |
25 | 26 | import { appStore } from '/@/store/modules/app'; |
26 | 27 | import { errorStore } from '/@/store/modules/error'; |
27 | 28 | |
28 | -import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; | |
29 | +import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'; | |
29 | 30 | import { GITHUB_URL } from '/@/settings/siteSetting'; |
30 | 31 | export default defineComponent({ |
31 | 32 | name: 'DefaultLayoutHeader', |
... | ... | @@ -75,6 +76,13 @@ export default defineComponent({ |
75 | 76 | return theme ? `layout-header__header--${theme}` : ''; |
76 | 77 | }); |
77 | 78 | |
79 | + const showHeaderTrigger = computed(() => { | |
80 | + const { show, trigger, hidden } = unref(getProjectConfigRef).menuSetting; | |
81 | + | |
82 | + if (!show || !hidden) return false; | |
83 | + return trigger === TriggerEnum.HEADER; | |
84 | + }); | |
85 | + | |
78 | 86 | function handleToErrorList() { |
79 | 87 | errorStore.commitErrorListCountState(0); |
80 | 88 | push('/exception/error-log'); |
... | ... | @@ -92,6 +100,7 @@ export default defineComponent({ |
92 | 100 | const { |
93 | 101 | useErrorHandle, |
94 | 102 | showLogo, |
103 | + multiTabsSetting: { show: showTab }, | |
95 | 104 | headerSetting: { |
96 | 105 | theme: headerTheme, |
97 | 106 | useLockPage, |
... | ... | @@ -114,11 +123,17 @@ export default defineComponent({ |
114 | 123 | {() => ( |
115 | 124 | <> |
116 | 125 | <div class="layout-header__content "> |
117 | - {showLogo && !isSidebarType && <Logo class={`layout-header__logo`} />} | |
118 | - | |
119 | - {mode !== MenuModeEnum.HORIZONTAL && showBreadCrumb && !splitMenu && ( | |
120 | - <LayoutBreadcrumb showIcon={showBreadCrumbIcon} /> | |
126 | + {showLogo && !isSidebarType && ( | |
127 | + <Logo class={`layout-header__logo`} theme={headerTheme} /> | |
121 | 128 | )} |
129 | + | |
130 | + <div class="layout-header__left"> | |
131 | + {unref(showHeaderTrigger) && <LayoutTrigger theme={headerTheme} sider={false} />} | |
132 | + {mode !== MenuModeEnum.HORIZONTAL && showBreadCrumb && !splitMenu && ( | |
133 | + <LayoutBreadcrumb showIcon={showBreadCrumbIcon} /> | |
134 | + )} | |
135 | + </div> | |
136 | + | |
122 | 137 | {unref(showTopMenu) && ( |
123 | 138 | <div |
124 | 139 | class={[`layout-header__menu `]} |
... | ... | @@ -193,7 +208,7 @@ export default defineComponent({ |
193 | 208 | </Tooltip> |
194 | 209 | </div> |
195 | 210 | )} |
196 | - {showRedo && ( | |
211 | + {showRedo && showTab && ( | |
197 | 212 | <Tooltip> |
198 | 213 | {{ |
199 | 214 | title: () => '刷新', | ... | ... |
src/layouts/default/LayoutMenu.tsx
... | ... | @@ -68,9 +68,6 @@ export default defineComponent({ |
68 | 68 | return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL; |
69 | 69 | }); |
70 | 70 | |
71 | - onMounted(() => { | |
72 | - genMenus(); | |
73 | - }); | |
74 | 71 | const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50); |
75 | 72 | |
76 | 73 | // watch( |
... | ... | @@ -90,6 +87,7 @@ export default defineComponent({ |
90 | 87 | immediate: true, |
91 | 88 | } |
92 | 89 | ); |
90 | + | |
93 | 91 | watch( |
94 | 92 | [() => permissionStore.getLastBuildMenuTimeState, permissionStore.getBackMenuListState], |
95 | 93 | () => { |
... | ... | @@ -112,7 +110,7 @@ export default defineComponent({ |
112 | 110 | if (!children) { |
113 | 111 | appStore.commitProjectConfigState({ |
114 | 112 | menuSetting: { |
115 | - show: false, | |
113 | + hidden: false, | |
116 | 114 | }, |
117 | 115 | }); |
118 | 116 | flatMenusRef.value = []; |
... | ... | @@ -122,7 +120,7 @@ export default defineComponent({ |
122 | 120 | const flatChildren = await getFlatChildrenMenus(children); |
123 | 121 | appStore.commitProjectConfigState({ |
124 | 122 | menuSetting: { |
125 | - show: true, | |
123 | + hidden: true, | |
126 | 124 | }, |
127 | 125 | }); |
128 | 126 | flatMenusRef.value = flatChildren; |
... | ... | @@ -193,6 +191,10 @@ export default defineComponent({ |
193 | 191 | ); |
194 | 192 | }); |
195 | 193 | |
194 | + onMounted(() => { | |
195 | + genMenus(); | |
196 | + }); | |
197 | + | |
196 | 198 | return () => { |
197 | 199 | const { |
198 | 200 | showLogo, |
... | ... | @@ -229,7 +231,11 @@ export default defineComponent({ |
229 | 231 | {{ |
230 | 232 | header: () => |
231 | 233 | isShowLogo && ( |
232 | - <Logo showTitle={!collapsed} class={[`layout-menu__logo`, themeData]} /> | |
234 | + <Logo | |
235 | + showTitle={!collapsed} | |
236 | + class={[`layout-menu__logo`, themeData]} | |
237 | + theme={themeData} | |
238 | + /> | |
233 | 239 | ), |
234 | 240 | }} |
235 | 241 | </BasicMenu> | ... | ... |
src/layouts/default/LayoutSideBar.tsx
1 | 1 | import { computed, defineComponent, nextTick, onMounted, ref, unref } from 'vue'; |
2 | 2 | |
3 | 3 | import { Layout } from 'ant-design-vue'; |
4 | -import SideBarTrigger from './SideBarTrigger'; | |
4 | +import LayoutTrigger from './LayoutTrigger'; | |
5 | 5 | import { menuStore } from '/@/store/modules/menu'; |
6 | 6 | |
7 | 7 | // import darkMiniIMg from '/@/assets/images/sidebar/dark-mini.png'; |
8 | 8 | // import lightMiniImg from '/@/assets/images/sidebar/light-mini.png'; |
9 | 9 | // import lightImg from '/@/assets/images/sidebar/light.png'; |
10 | 10 | import { appStore } from '/@/store/modules/app'; |
11 | -import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; | |
11 | +import { MenuModeEnum, MenuSplitTyeEnum, TriggerEnum } from '/@/enums/menuEnum'; | |
12 | 12 | import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum'; |
13 | 13 | import { useDebounce } from '/@/hooks/core/useDebounce'; |
14 | 14 | import LayoutMenu from './LayoutMenu'; |
... | ... | @@ -133,6 +133,25 @@ export default defineComponent({ |
133 | 133 | return unref(brokenRef) ? 0 : unref(getMiniWidth); |
134 | 134 | }); |
135 | 135 | |
136 | + const showTrigger = computed(() => { | |
137 | + const { | |
138 | + menuSetting: { trigger }, | |
139 | + } = unref(getProjectConfigRef); | |
140 | + return trigger !== TriggerEnum.NONE && trigger === TriggerEnum.FOOTER; | |
141 | + }); | |
142 | + | |
143 | + function handleSiderClick(e: ChangeEvent) { | |
144 | + if (!e || !e.target || e.target.className !== 'basic-menu__content') return; | |
145 | + | |
146 | + const { collapsed, show } = appStore.getProjectConfig.menuSetting; | |
147 | + if (!collapsed || !show) return; | |
148 | + appStore.commitProjectConfigState({ | |
149 | + menuSetting: { | |
150 | + collapsed: false, | |
151 | + }, | |
152 | + }); | |
153 | + } | |
154 | + | |
136 | 155 | function renderDragLine() { |
137 | 156 | const { menuSetting: { hasDrag = true } = {} } = unref(getProjectConfigRef); |
138 | 157 | return ( |
... | ... | @@ -149,8 +168,22 @@ export default defineComponent({ |
149 | 168 | menuSetting: { theme, split: splitMenu }, |
150 | 169 | } = unref(getProjectConfigRef); |
151 | 170 | const { getCollapsedState, getMenuWidthState } = menuStore; |
171 | + | |
172 | + const triggerDom = unref(showTrigger) | |
173 | + ? { | |
174 | + trigger: () => <LayoutTrigger />, | |
175 | + } | |
176 | + : {}; | |
177 | + | |
178 | + const triggerAttr = unref(showTrigger) | |
179 | + ? {} | |
180 | + : { | |
181 | + trigger: null, | |
182 | + }; | |
183 | + | |
152 | 184 | return ( |
153 | 185 | <Layout.Sider |
186 | + onClick={handleSiderClick} | |
154 | 187 | onCollapse={onCollapseChange} |
155 | 188 | breakpoint="md" |
156 | 189 | width={getMenuWidthState} |
... | ... | @@ -161,9 +194,10 @@ export default defineComponent({ |
161 | 194 | class="layout-sidebar" |
162 | 195 | ref={sideRef} |
163 | 196 | onBreakpoint={handleBreakpoint} |
197 | + {...triggerAttr} | |
164 | 198 | > |
165 | 199 | {{ |
166 | - trigger: () => <SideBarTrigger />, | |
200 | + ...triggerDom, | |
167 | 201 | default: () => ( |
168 | 202 | <> |
169 | 203 | <LayoutMenu | ... | ... |
src/layouts/default/LayoutTrigger.tsx
0 → 100644
1 | +import { | |
2 | + DoubleRightOutlined, | |
3 | + DoubleLeftOutlined, | |
4 | + MenuUnfoldOutlined, | |
5 | + MenuFoldOutlined, | |
6 | +} from '@ant-design/icons-vue'; | |
7 | +import { defineComponent } from 'vue'; | |
8 | + | |
9 | +// store | |
10 | +import { menuStore } from '/@/store/modules/menu'; | |
11 | + | |
12 | +export default defineComponent({ | |
13 | + name: 'LayoutTrigger', | |
14 | + props: { | |
15 | + sider: { | |
16 | + type: Boolean, | |
17 | + default: true, | |
18 | + }, | |
19 | + theme: { | |
20 | + type: String, | |
21 | + }, | |
22 | + }, | |
23 | + setup(props) { | |
24 | + function toggleMenu() { | |
25 | + menuStore.commitCollapsedState(!menuStore.getCollapsedState); | |
26 | + } | |
27 | + | |
28 | + return () => { | |
29 | + const siderTrigger = menuStore.getCollapsedState ? ( | |
30 | + <DoubleRightOutlined /> | |
31 | + ) : ( | |
32 | + <DoubleLeftOutlined /> | |
33 | + ); | |
34 | + if (props.sider) return siderTrigger; | |
35 | + | |
36 | + return ( | |
37 | + <span class={['layout-trigger', props.theme]} onClick={toggleMenu}> | |
38 | + {menuStore.getCollapsedState ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} | |
39 | + </span> | |
40 | + ); | |
41 | + }; | |
42 | + }, | |
43 | +}); | ... | ... |
src/layouts/default/SideBarTrigger.tsx deleted
100644 → 0
1 | -import { DoubleRightOutlined, DoubleLeftOutlined } from '@ant-design/icons-vue'; | |
2 | -import { defineComponent } from 'vue'; | |
3 | - | |
4 | -// store | |
5 | -import { menuStore } from '/@/store/modules/menu'; | |
6 | - | |
7 | -export default defineComponent({ | |
8 | - name: 'SideBarTrigger', | |
9 | - setup() { | |
10 | - return () => (menuStore.getCollapsedState ? <DoubleRightOutlined /> : <DoubleLeftOutlined />); | |
11 | - }, | |
12 | -}); |
src/layouts/default/index.less
... | ... | @@ -17,11 +17,10 @@ |
17 | 17 | &__main { |
18 | 18 | position: relative; |
19 | 19 | height: 100%; |
20 | - // overflow: hidden; | |
21 | - // overflow: auto; | |
22 | 20 | |
23 | 21 | &.fixed { |
24 | - overflow: auto; | |
22 | + overflow-x: hidden; | |
23 | + overflow-y: auto; | |
25 | 24 | } |
26 | 25 | |
27 | 26 | &.fixed.lock { |
... | ... | @@ -373,9 +372,39 @@ |
373 | 372 | } |
374 | 373 | } |
375 | 374 | |
376 | -.layout-breadcrumb { | |
377 | - padding: 0 16px; | |
375 | +.layout-header__left { | |
378 | 376 | flex-grow: 1; |
377 | + display: flex; | |
378 | + align-items: center; | |
379 | + | |
380 | + .layout-trigger { | |
381 | + padding: 4px 10px 0 16px; | |
382 | + cursor: pointer; | |
383 | + | |
384 | + .anticon { | |
385 | + font-size: 17px; | |
386 | + } | |
387 | + | |
388 | + &.light { | |
389 | + &:hover { | |
390 | + background: @header-light-bg-hover-color; | |
391 | + } | |
392 | + | |
393 | + svg { | |
394 | + fill: #000; | |
395 | + } | |
396 | + } | |
397 | + | |
398 | + &.dark { | |
399 | + &:hover { | |
400 | + background: @header-dark-bg-hover-color; | |
401 | + } | |
402 | + } | |
403 | + } | |
404 | + | |
405 | + .layout-breadcrumb { | |
406 | + padding: 0 8px; | |
407 | + } | |
379 | 408 | } |
380 | 409 | |
381 | 410 | .ant-layout-sider-trigger { | ... | ... |
src/layouts/default/index.tsx
... | ... | @@ -73,7 +73,7 @@ export default defineComponent({ |
73 | 73 | showSettingButton, |
74 | 74 | multiTabsSetting: { show: showTabs }, |
75 | 75 | headerSetting: { fixed }, |
76 | - menuSetting: { split, show }, | |
76 | + menuSetting: { split, hidden }, | |
77 | 77 | } = unref(getProjectConfigRef); |
78 | 78 | |
79 | 79 | const fixedHeaderCls = fixed |
... | ... | @@ -82,7 +82,7 @@ export default defineComponent({ |
82 | 82 | |
83 | 83 | const { isLock } = getLockInfo; |
84 | 84 | |
85 | - const showSideBar = split ? show : true; | |
85 | + const showSideBar = split ? hidden : true; | |
86 | 86 | return ( |
87 | 87 | <Layout class="default-layout relative"> |
88 | 88 | {() => ( |
... | ... | @@ -107,9 +107,7 @@ export default defineComponent({ |
107 | 107 | unref(showHeaderRef) && <LayoutHeader />} |
108 | 108 | |
109 | 109 | {showTabs && !unref(getFullContent) && ( |
110 | - <Layout.Header class={`default-layout__tabs`}> | |
111 | - {() => <MultipleTabs />} | |
112 | - </Layout.Header> | |
110 | + <MultipleTabs class={`default-layout__tabs`} /> | |
113 | 111 | )} |
114 | 112 | |
115 | 113 | {useOpenBackTop && <BackTop target={getTarget} />} | ... | ... |
src/layouts/default/setting/SettingDrawer.tsx
... | ... | @@ -2,7 +2,13 @@ import { defineComponent, computed, unref, ref } from 'vue'; |
2 | 2 | import { BasicDrawer } from '/@/components/Drawer/index'; |
3 | 3 | import { Divider, Switch, Tooltip, InputNumber, Select } from 'ant-design-vue'; |
4 | 4 | import Button from '/@/components/Button/index.vue'; |
5 | -import { MenuModeEnum, MenuTypeEnum, MenuThemeEnum, TopMenuAlignEnum } from '/@/enums/menuEnum'; | |
5 | +import { | |
6 | + MenuModeEnum, | |
7 | + MenuTypeEnum, | |
8 | + MenuThemeEnum, | |
9 | + TopMenuAlignEnum, | |
10 | + TriggerEnum, | |
11 | +} from '/@/enums/menuEnum'; | |
6 | 12 | import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum'; |
7 | 13 | import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue'; |
8 | 14 | import { appStore } from '/@/store/modules/app'; |
... | ... | @@ -23,41 +29,49 @@ const themeOptions = [ |
23 | 29 | { |
24 | 30 | value: MenuThemeEnum.LIGHT, |
25 | 31 | label: '亮色', |
26 | - key: MenuThemeEnum.LIGHT, | |
27 | 32 | }, |
28 | 33 | { |
29 | 34 | value: MenuThemeEnum.DARK, |
30 | 35 | label: '暗色', |
31 | - key: MenuThemeEnum.DARK, | |
32 | 36 | }, |
33 | 37 | ]; |
34 | 38 | const contentModeOptions = [ |
35 | 39 | { |
36 | 40 | value: ContentEnum.FULL, |
37 | 41 | label: '流式', |
38 | - key: ContentEnum.FULL, | |
39 | 42 | }, |
40 | 43 | { |
41 | 44 | value: ContentEnum.FIXED, |
42 | 45 | label: '定宽', |
43 | - key: ContentEnum.FIXED, | |
44 | 46 | }, |
45 | 47 | ]; |
46 | 48 | const topMenuAlignOptions = [ |
47 | 49 | { |
48 | 50 | value: TopMenuAlignEnum.CENTER, |
49 | 51 | label: '居中', |
50 | - key: TopMenuAlignEnum.CENTER, | |
51 | 52 | }, |
52 | 53 | { |
53 | 54 | value: TopMenuAlignEnum.START, |
54 | 55 | label: '居左', |
55 | - key: TopMenuAlignEnum.START, | |
56 | 56 | }, |
57 | 57 | { |
58 | 58 | value: TopMenuAlignEnum.END, |
59 | 59 | label: '居右', |
60 | - key: TopMenuAlignEnum.END, | |
60 | + }, | |
61 | +]; | |
62 | + | |
63 | +const menuTriggerOptions = [ | |
64 | + { | |
65 | + value: TriggerEnum.NONE, | |
66 | + label: '不显示', | |
67 | + }, | |
68 | + { | |
69 | + value: TriggerEnum.FOOTER, | |
70 | + label: '底部', | |
71 | + }, | |
72 | + { | |
73 | + value: TriggerEnum.HEADER, | |
74 | + label: '顶部', | |
61 | 75 | }, |
62 | 76 | ]; |
63 | 77 | |
... | ... | @@ -181,7 +195,7 @@ export default defineComponent({ |
181 | 195 | baseHandler('splitMenu', e); |
182 | 196 | }, |
183 | 197 | def: split, |
184 | - disabled: !unref(getShowMenuRef), | |
198 | + disabled: !unref(getShowMenuRef) || type !== MenuTypeEnum.MIX, | |
185 | 199 | }), |
186 | 200 | renderSelectItem('顶栏主题', { |
187 | 201 | handler: (e) => { |
... | ... | @@ -215,6 +229,7 @@ export default defineComponent({ |
215 | 229 | menuWidth, |
216 | 230 | topMenuAlign, |
217 | 231 | collapsedShowTitle, |
232 | + trigger, | |
218 | 233 | } = {}, |
219 | 234 | } = appStore.getProjectConfig; |
220 | 235 | return [ |
... | ... | @@ -262,6 +277,13 @@ export default defineComponent({ |
262 | 277 | options: topMenuAlignOptions, |
263 | 278 | disabled: !unref(getShowHeaderRef), |
264 | 279 | }), |
280 | + renderSelectItem('菜单折叠按钮', { | |
281 | + handler: (e) => { | |
282 | + baseHandler('menuTrigger', e); | |
283 | + }, | |
284 | + def: trigger, | |
285 | + options: menuTriggerOptions, | |
286 | + }), | |
265 | 287 | renderSelectItem('内容区域宽度', { |
266 | 288 | handler: (e) => { |
267 | 289 | baseHandler('contentMode', e); |
... | ... | @@ -298,7 +320,7 @@ export default defineComponent({ |
298 | 320 | disabled={!unref(getShowMenuRef)} |
299 | 321 | defaultValue={menuWidth} |
300 | 322 | formatter={(value: string) => `${parseInt(value)}px`} |
301 | - onChange={(e) => { | |
323 | + onChange={(e: any) => { | |
302 | 324 | baseHandler('menuWidth', e); |
303 | 325 | }} |
304 | 326 | /> |
... | ... | @@ -424,13 +446,21 @@ export default defineComponent({ |
424 | 446 | if (event === 'layout') { |
425 | 447 | const { mode, type, split } = value; |
426 | 448 | const splitOpt = split === undefined ? { split } : {}; |
449 | + let headerSetting = {}; | |
450 | + if (type === MenuTypeEnum.TOP_MENU) { | |
451 | + headerSetting = { | |
452 | + theme: MenuThemeEnum.DARK, | |
453 | + }; | |
454 | + } | |
427 | 455 | config = { |
428 | 456 | menuSetting: { |
429 | 457 | mode, |
430 | 458 | type, |
431 | 459 | collapsed: false, |
460 | + show: true, | |
432 | 461 | ...splitOpt, |
433 | 462 | }, |
463 | + headerSetting, | |
434 | 464 | }; |
435 | 465 | } |
436 | 466 | if (event === 'hasDrag') { |
... | ... | @@ -440,6 +470,13 @@ export default defineComponent({ |
440 | 470 | }, |
441 | 471 | }; |
442 | 472 | } |
473 | + if (event === 'menuTrigger') { | |
474 | + config = { | |
475 | + menuSetting: { | |
476 | + trigger: value, | |
477 | + }, | |
478 | + }; | |
479 | + } | |
443 | 480 | if (event === 'openPageLoading') { |
444 | 481 | config = { |
445 | 482 | openPageLoading: value, |
... | ... | @@ -647,7 +684,7 @@ export default defineComponent({ |
647 | 684 | <Switch |
648 | 685 | {...opt} |
649 | 686 | disabled={disabled} |
650 | - onChange={(e) => { | |
687 | + onChange={(e: any) => { | |
651 | 688 | handler && handler(e); |
652 | 689 | }} |
653 | 690 | checkedChildren="开" | ... | ... |
src/settings/projectSetting.ts
1 | 1 | import type { ProjectConfig } from '/@/types/config'; |
2 | 2 | |
3 | -import { MenuTypeEnum, MenuThemeEnum, MenuModeEnum } from '/@/enums/menuEnum'; | |
3 | +import { MenuTypeEnum, MenuThemeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum'; | |
4 | 4 | import { ContentEnum, PermissionModeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; |
5 | 5 | import { primaryColor } from '../../build/config/lessModifyVars'; |
6 | 6 | import { isProdMode } from '/@/utils/env'; |
... | ... | @@ -23,6 +23,7 @@ const setting: ProjectConfig = { |
23 | 23 | // 是否显示logo |
24 | 24 | showLogo: true, |
25 | 25 | |
26 | + // 头部配置 | |
26 | 27 | headerSetting: { |
27 | 28 | fixed: true, |
28 | 29 | // 是否显示顶部 |
... | ... | @@ -50,8 +51,10 @@ const setting: ProjectConfig = { |
50 | 51 | collapsedShowTitle: false, |
51 | 52 | // 是否可拖拽 |
52 | 53 | hasDrag: false, |
53 | - // 是否显示 | |
54 | + // 是否显示 没有dom | |
54 | 55 | show: true, |
56 | + // 是否显示 有dom | |
57 | + hidden: false, | |
55 | 58 | // 是否显示搜索框 |
56 | 59 | showSearch: true, |
57 | 60 | // 菜单宽度 |
... | ... | @@ -67,7 +70,9 @@ const setting: ProjectConfig = { |
67 | 70 | // 顶部菜单布局 |
68 | 71 | topMenuAlign: 'center', |
69 | 72 | // 折叠菜单时候隐藏搜索框 |
70 | - collapsedShowSearch: true, | |
73 | + collapsedShowSearch: false, | |
74 | + // 折叠触发器的位置 | |
75 | + trigger: TriggerEnum.HEADER, | |
71 | 76 | }, |
72 | 77 | // 消息配置 |
73 | 78 | messageSetting: { | ... | ... |
src/types/config.d.ts
1 | 1 | // 左侧菜单, 顶部菜单 |
2 | -import { MenuTypeEnum, MenuModeEnum, MenuThemeEnum } from '/@/enums/menuEnum'; | |
2 | +import { MenuTypeEnum, MenuModeEnum, MenuThemeEnum, TriggerEnum } from '/@/enums/menuEnum'; | |
3 | 3 | import { ContentEnum, PermissionModeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; |
4 | 4 | |
5 | 5 | export interface MessageSetting { |
... | ... | @@ -15,6 +15,7 @@ export interface MenuSetting { |
15 | 15 | hasDrag: boolean; |
16 | 16 | showSearch: boolean; |
17 | 17 | show: boolean; |
18 | + hidden: boolean; | |
18 | 19 | split: boolean; |
19 | 20 | menuWidth: number; |
20 | 21 | mode: MenuModeEnum; |
... | ... | @@ -22,6 +23,7 @@ export interface MenuSetting { |
22 | 23 | theme: MenuThemeEnum; |
23 | 24 | topMenuAlign: 'start' | 'center' | 'end'; |
24 | 25 | collapsedShowSearch: boolean; |
26 | + trigger: TriggerEnum; | |
25 | 27 | } |
26 | 28 | |
27 | 29 | export interface MultiTabsSetting { | ... | ... |
src/utils/helper/routeHelper.ts
vite.config.ts
... | ... | @@ -119,12 +119,7 @@ const viteConfig: UserConfig = { |
119 | 119 | }, |
120 | 120 | // The package will be recompiled using rollup, and the new package compiled into the esm module specification will be put into node_modules/.vite_opt_cache |
121 | 121 | optimizeDeps: { |
122 | - include: [ | |
123 | - 'echarts/map/js/china', | |
124 | - 'ant-design-vue/es/locale/zh_CN', | |
125 | - '@ant-design/icons-vue', | |
126 | - 'moment/locale/zh-cn', | |
127 | - ], | |
122 | + include: ['echarts/map/js/china', 'ant-design-vue/es/locale/zh_CN', '@ant-design/icons-vue'], | |
128 | 123 | }, |
129 | 124 | |
130 | 125 | // Local cross-domain proxy | ... | ... |
yarn.lock
... | ... | @@ -5513,7 +5513,7 @@ modify-values@^1.0.0: |
5513 | 5513 | resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" |
5514 | 5514 | integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== |
5515 | 5515 | |
5516 | -moment@^2.27.0: | |
5516 | +moment@^2.27.0, moment@^2.29.1: | |
5517 | 5517 | version "2.29.1" |
5518 | 5518 | resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" |
5519 | 5519 | integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== | ... | ... |