Commit ba068ba1df797627e88dcf61af3ea13d0c2929ab
1 parent
234c1d1f
wip: refactor layout
Showing
77 changed files
with
1294 additions
and
1097 deletions
.eslintrc.js
@@ -23,7 +23,7 @@ module.exports = { | @@ -23,7 +23,7 @@ module.exports = { | ||
23 | '@typescript-eslint/no-empty-function': 'off', | 23 | '@typescript-eslint/no-empty-function': 'off', |
24 | 'vue/custom-event-name-casing': 'off', | 24 | 'vue/custom-event-name-casing': 'off', |
25 | 'no-use-before-define': 'off', | 25 | 'no-use-before-define': 'off', |
26 | - // 'no-use-before-define': [ | 26 | + // 'no-setting-before-define': [ |
27 | // 'error', | 27 | // 'error', |
28 | // { | 28 | // { |
29 | // functions: false, | 29 | // functions: false, |
@@ -31,7 +31,7 @@ module.exports = { | @@ -31,7 +31,7 @@ module.exports = { | ||
31 | // }, | 31 | // }, |
32 | // ], | 32 | // ], |
33 | '@typescript-eslint/no-use-before-define': 'off', | 33 | '@typescript-eslint/no-use-before-define': 'off', |
34 | - // '@typescript-eslint/no-use-before-define': [ | 34 | + // '@typescript-eslint/no-setting-before-define': [ |
35 | // 'error', | 35 | // 'error', |
36 | // { | 36 | // { |
37 | // functions: false, | 37 | // functions: false, |
src/components/Application/index.ts
1 | import AppLocalPicker from './src/AppLocalPicker.vue'; | 1 | import AppLocalPicker from './src/AppLocalPicker.vue'; |
2 | -import AppFooterToolbar from './src/AppFooterToolbar.vue'; | 2 | +import AppPageFooter from './src/AppPageFooter.vue'; |
3 | +import AppLogo from './src/AppLogo.vue'; | ||
3 | import { withInstall } from '../util'; | 4 | import { withInstall } from '../util'; |
4 | 5 | ||
5 | -export { AppLocalPicker, AppFooterToolbar }; | 6 | +export { AppLocalPicker, AppPageFooter, AppLogo }; |
6 | 7 | ||
7 | -export default withInstall(AppLocalPicker, AppFooterToolbar); | 8 | +export default withInstall(AppLocalPicker, AppPageFooter, AppLogo); |
src/components/Application/src/AppLocalPicker.vue
@@ -5,29 +5,44 @@ | @@ -5,29 +5,44 @@ | ||
5 | :selectedKeys="selectedKeys" | 5 | :selectedKeys="selectedKeys" |
6 | @menuEvent="handleMenuEvent" | 6 | @menuEvent="handleMenuEvent" |
7 | > | 7 | > |
8 | - <GlobalOutlined class="app-locale" /> | 8 | + <span class="app-local-picker"> |
9 | + <GlobalOutlined class="app-local-picker__icon" /> | ||
10 | + <span v-if="showText">{{ getLangText }}</span> | ||
11 | + </span> | ||
9 | </Dropdown> | 12 | </Dropdown> |
10 | </template> | 13 | </template> |
11 | <script lang="ts"> | 14 | <script lang="ts"> |
12 | - import { defineComponent, ref, watchEffect, unref } from 'vue'; | 15 | + import { defineComponent, ref, watchEffect, unref, computed } from 'vue'; |
13 | 16 | ||
14 | import { Dropdown, DropMenu } from '/@/components/Dropdown'; | 17 | import { Dropdown, DropMenu } from '/@/components/Dropdown'; |
15 | import { GlobalOutlined } from '@ant-design/icons-vue'; | 18 | import { GlobalOutlined } from '@ant-design/icons-vue'; |
16 | 19 | ||
17 | import { useLocale } from '/@/hooks/web/useLocale'; | 20 | import { useLocale } from '/@/hooks/web/useLocale'; |
18 | - import { useLocaleSetting } from '/@/settings/use/useLocaleSetting'; | 21 | + import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting'; |
19 | 22 | ||
20 | import { LocaleType } from '/@/locales/types'; | 23 | import { LocaleType } from '/@/locales/types'; |
21 | 24 | ||
22 | export default defineComponent({ | 25 | export default defineComponent({ |
23 | name: 'AppLocalPicker', | 26 | name: 'AppLocalPicker', |
24 | components: { GlobalOutlined, Dropdown }, | 27 | components: { GlobalOutlined, Dropdown }, |
28 | + props: { | ||
29 | + showText: { | ||
30 | + type: Boolean, | ||
31 | + default: true, | ||
32 | + }, | ||
33 | + }, | ||
25 | setup() { | 34 | setup() { |
26 | const { localeList } = useLocaleSetting(); | 35 | const { localeList } = useLocaleSetting(); |
27 | const selectedKeys = ref<string[]>([]); | 36 | const selectedKeys = ref<string[]>([]); |
28 | 37 | ||
29 | const { changeLocale, getLang } = useLocale(); | 38 | const { changeLocale, getLang } = useLocale(); |
30 | 39 | ||
40 | + const getLangText = computed(() => { | ||
41 | + const key = selectedKeys.value[0]; | ||
42 | + if (!key) return ''; | ||
43 | + return localeList.find((item) => item.event === key)?.text; | ||
44 | + }); | ||
45 | + | ||
31 | watchEffect(() => { | 46 | watchEffect(() => { |
32 | selectedKeys.value = [unref(getLang)]; | 47 | selectedKeys.value = [unref(getLang)]; |
33 | }); | 48 | }); |
@@ -41,13 +56,19 @@ | @@ -41,13 +56,19 @@ | ||
41 | toggleLocale(menu.event as string); | 56 | toggleLocale(menu.event as string); |
42 | } | 57 | } |
43 | 58 | ||
44 | - return { localeList, handleMenuEvent, selectedKeys }; | 59 | + return { localeList, handleMenuEvent, selectedKeys, getLangText }; |
45 | }, | 60 | }, |
46 | }); | 61 | }); |
47 | </script> | 62 | </script> |
48 | 63 | ||
49 | <style lang="less" scoped> | 64 | <style lang="less" scoped> |
50 | - .app-locale { | 65 | + .app-local-picker { |
66 | + display: flex; | ||
67 | + align-items: center; | ||
51 | cursor: pointer; | 68 | cursor: pointer; |
69 | + | ||
70 | + &__icon { | ||
71 | + margin-right: 4px; | ||
72 | + } | ||
52 | } | 73 | } |
53 | </style> | 74 | </style> |
src/layouts/logo/index.vue renamed to src/components/Application/src/AppLogo.vue
1 | <template> | 1 | <template> |
2 | - <div class="app-logo anticon" :class="theme" @click="handleGoHome" :style="wrapStyle"> | 2 | + <div class="app-logo anticon" :class="theme" @click="handleGoHome"> |
3 | <img src="/@/assets/images/logo.png" /> | 3 | <img src="/@/assets/images/logo.png" /> |
4 | - <div v-if="show" class="logo-title ml-2 ellipsis">{{ globSetting.title }}</div> | 4 | + <div class="app-logo__title ml-2 ellipsis">{{ globSetting.title }}</div> |
5 | </div> | 5 | </div> |
6 | </template> | 6 | </template> |
7 | <script lang="ts"> | 7 | <script lang="ts"> |
8 | - import { computed, defineComponent, PropType, ref, watch } from 'vue'; | ||
9 | - // hooks | ||
10 | - import { useGlobSetting } from '/@/settings/use'; | ||
11 | - import { useTimeoutFn } from '/@/hooks/core/useTimeout'; | 8 | + import type { PropType } from 'vue'; |
9 | + import { defineComponent } from 'vue'; | ||
10 | + | ||
11 | + import { useGlobSetting } from '/@/hooks/setting'; | ||
12 | import { useGo } from '/@/hooks/web/usePage'; | 12 | import { useGo } from '/@/hooks/web/usePage'; |
13 | 13 | ||
14 | import { PageEnum } from '/@/enums/pageEnum'; | 14 | import { PageEnum } from '/@/enums/pageEnum'; |
15 | - import { MenuTypeEnum } from '/@/enums/menuEnum'; | ||
16 | - | ||
17 | - import { menuStore } from '/@/store/modules/menu'; | ||
18 | - import { appStore } from '/@/store/modules/app'; | ||
19 | 15 | ||
20 | export default defineComponent({ | 16 | export default defineComponent({ |
21 | - name: 'Logo', | 17 | + name: 'AppLogo', |
22 | props: { | 18 | props: { |
23 | - showTitle: { | ||
24 | - type: Boolean as PropType<boolean>, | ||
25 | - default: true, | ||
26 | - }, | 19 | + /** |
20 | + * The theme of the current parent component | ||
21 | + */ | ||
27 | theme: { | 22 | theme: { |
28 | - type: String, | 23 | + type: String as PropType<string>, |
29 | }, | 24 | }, |
30 | }, | 25 | }, |
31 | - setup(props) { | ||
32 | - const showRef = ref<boolean>(!!props.showTitle); | 26 | + setup() { |
33 | const globSetting = useGlobSetting(); | 27 | const globSetting = useGlobSetting(); |
34 | const go = useGo(); | 28 | const go = useGo(); |
35 | 29 | ||
36 | - function handleGoHome() { | 30 | + function handleGoHome(): void { |
37 | go(PageEnum.BASE_HOME); | 31 | go(PageEnum.BASE_HOME); |
38 | } | 32 | } |
39 | 33 | ||
40 | - watch( | ||
41 | - () => props.showTitle, | ||
42 | - (show: boolean) => { | ||
43 | - if (show) { | ||
44 | - useTimeoutFn(() => { | ||
45 | - showRef.value = show; | ||
46 | - }, 280); | ||
47 | - } else { | ||
48 | - showRef.value = show; | ||
49 | - } | ||
50 | - } | ||
51 | - ); | ||
52 | - | ||
53 | - const wrapStyle = computed(() => { | ||
54 | - const { getCollapsedState } = menuStore; | ||
55 | - const { | ||
56 | - menuSetting: { menuWidth, type }, | ||
57 | - } = appStore.getProjectConfig; | ||
58 | - const miniWidth = { minWidth: `${menuWidth}px` }; | ||
59 | - if (type !== MenuTypeEnum.SIDEBAR) { | ||
60 | - return miniWidth; | ||
61 | - } | ||
62 | - return getCollapsedState ? {} : miniWidth; | ||
63 | - }); | ||
64 | - | ||
65 | return { | 34 | return { |
66 | handleGoHome, | 35 | handleGoHome, |
67 | globSetting, | 36 | globSetting, |
68 | - show: showRef, | ||
69 | - wrapStyle, | ||
70 | }; | 37 | }; |
71 | }, | 38 | }, |
72 | }); | 39 | }); |
73 | </script> | 40 | </script> |
74 | <style lang="less" scoped> | 41 | <style lang="less" scoped> |
75 | - @import (reference) '../../design/index.less'; | 42 | + @import (reference) '../../../design/index.less'; |
76 | 43 | ||
77 | .app-logo { | 44 | .app-logo { |
78 | display: flex; | 45 | display: flex; |
79 | align-items: center; | 46 | align-items: center; |
80 | padding-left: 16px; | 47 | padding-left: 16px; |
81 | cursor: pointer; | 48 | cursor: pointer; |
82 | - // justify-content: center; | 49 | + |
83 | &.light { | 50 | &.light { |
84 | border-bottom: 1px solid @border-color-base; | 51 | border-bottom: 1px solid @border-color-base; |
85 | } | 52 | } |
86 | 53 | ||
87 | - .logo-title { | 54 | + &.light &__title { |
55 | + color: @primary-color; | ||
56 | + } | ||
57 | + | ||
58 | + &.dark &__title { | ||
59 | + color: @white; | ||
60 | + } | ||
61 | + | ||
62 | + &__title { | ||
88 | font-size: 18px; | 63 | font-size: 18px; |
89 | font-weight: 700; | 64 | font-weight: 700; |
90 | opacity: 0; | 65 | opacity: 0; |
91 | transition: all 0.5s; | 66 | transition: all 0.5s; |
92 | .respond-to(medium,{ | 67 | .respond-to(medium,{ |
93 | opacity: 1; | 68 | opacity: 1; |
94 | - }); | ||
95 | - } | ||
96 | - | ||
97 | - // &.dark .logo-title { | ||
98 | - // font-weight: 400; | ||
99 | - // } | ||
100 | - | ||
101 | - &.light .logo-title { | ||
102 | - color: @primary-color; | 69 | + }); |
103 | } | 70 | } |
104 | } | 71 | } |
105 | </style> | 72 | </style> |
src/components/Application/src/AppFooterToolbar.vue renamed to src/components/Application/src/AppPageFooter.vue
1 | <template> | 1 | <template> |
2 | - <div class="app-footer" :style="{ width: getWidth }"> | 2 | + <div class="app-footer" :style="{ width: getCalcContentWidth }"> |
3 | <div class="app-footer__left"> | 3 | <div class="app-footer__left"> |
4 | <slot name="left" /> | 4 | <slot name="left" /> |
5 | </div> | 5 | </div> |
@@ -9,30 +9,16 @@ | @@ -9,30 +9,16 @@ | ||
9 | </div> | 9 | </div> |
10 | </template> | 10 | </template> |
11 | <script lang="ts"> | 11 | <script lang="ts"> |
12 | - import { defineComponent, computed, unref } from 'vue'; | 12 | + import { defineComponent } from 'vue'; |
13 | 13 | ||
14 | - import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum'; | ||
15 | - | ||
16 | - import { appStore } from '/@/store/modules/app'; | ||
17 | - import { menuStore } from '/@/store/modules/menu'; | 14 | + import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; |
18 | 15 | ||
19 | export default defineComponent({ | 16 | export default defineComponent({ |
20 | name: 'AppFooterToolbar', | 17 | name: 'AppFooterToolbar', |
21 | setup() { | 18 | setup() { |
22 | - const getMiniWidth = computed(() => { | ||
23 | - const { | ||
24 | - menuSetting: { collapsedShowTitle }, | ||
25 | - } = appStore.getProjectConfig; | ||
26 | - return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH; | ||
27 | - }); | ||
28 | - | ||
29 | - const getWidth = computed(() => { | ||
30 | - const { getCollapsedState, getMenuWidthState } = menuStore; | ||
31 | - const width = getCollapsedState ? unref(getMiniWidth) : getMenuWidthState; | ||
32 | - return `calc(100% - ${width}px)`; | ||
33 | - }); | 19 | + const { getCalcContentWidth } = useMenuSetting(); |
34 | 20 | ||
35 | - return { getWidth }; | 21 | + return { getCalcContentWidth }; |
36 | }, | 22 | }, |
37 | }); | 23 | }); |
38 | </script> | 24 | </script> |
@@ -51,7 +37,7 @@ | @@ -51,7 +37,7 @@ | ||
51 | border-top: 1px solid #f0f0f0; | 37 | border-top: 1px solid #f0f0f0; |
52 | box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05), | 38 | box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05), |
53 | 0 -12px 48px 16px rgba(0, 0, 0, 0.03); | 39 | 0 -12px 48px 16px rgba(0, 0, 0, 0.03); |
54 | - transition: width 0.3s; | 40 | + transition: width 0.4s; |
55 | 41 | ||
56 | &__left { | 42 | &__left { |
57 | flex: 1 1; | 43 | flex: 1 1; |
src/components/Authority/src/index.vue
1 | <!-- | 1 | <!-- |
2 | - * @Author: Vben | ||
3 | - * @Description:Access control component for fine-grained access control. | 2 | + Access control component for fine-grained access control. |
4 | --> | 3 | --> |
5 | <script lang="ts"> | 4 | <script lang="ts"> |
6 | import type { PropType } from 'vue'; | 5 | import type { PropType } from 'vue'; |
7 | - import { defineComponent, computed, unref } from 'vue'; | 6 | + import { defineComponent, unref } from 'vue'; |
8 | 7 | ||
9 | import { PermissionModeEnum } from '/@/enums/appEnum'; | 8 | import { PermissionModeEnum } from '/@/enums/appEnum'; |
10 | import { RoleEnum } from '/@/enums/roleEnum'; | 9 | import { RoleEnum } from '/@/enums/roleEnum'; |
10 | + import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
11 | 11 | ||
12 | import { usePermission } from '/@/hooks/web/usePermission'; | 12 | import { usePermission } from '/@/hooks/web/usePermission'; |
13 | - import { appStore } from '/@/store/modules/app'; | ||
14 | 13 | ||
15 | import { getSlot } from '/@/utils/helper/tsxHelper'; | 14 | import { getSlot } from '/@/utils/helper/tsxHelper'; |
16 | 15 | ||
@@ -29,9 +28,8 @@ | @@ -29,9 +28,8 @@ | ||
29 | }, | 28 | }, |
30 | }, | 29 | }, |
31 | setup(props, { slots }) { | 30 | setup(props, { slots }) { |
32 | - const getModeRef = computed(() => { | ||
33 | - return appStore.getProjectConfig.permissionMode; | ||
34 | - }); | 31 | + const { getPermissionMode } = useRootSetting(); |
32 | + const { hasPermission } = usePermission(); | ||
35 | 33 | ||
36 | /** | 34 | /** |
37 | * Render role button | 35 | * Render role button |
@@ -41,7 +39,6 @@ | @@ -41,7 +39,6 @@ | ||
41 | if (!value) { | 39 | if (!value) { |
42 | return getSlot(slots); | 40 | return getSlot(slots); |
43 | } | 41 | } |
44 | - const { hasPermission } = usePermission(); | ||
45 | return hasPermission(value) ? getSlot(slots) : null; | 42 | return hasPermission(value) ? getSlot(slots) : null; |
46 | } | 43 | } |
47 | 44 | ||
@@ -52,12 +49,11 @@ | @@ -52,12 +49,11 @@ | ||
52 | if (!value) { | 49 | if (!value) { |
53 | return getSlot(slots); | 50 | return getSlot(slots); |
54 | } | 51 | } |
55 | - const { hasPermission } = usePermission(); | ||
56 | return hasPermission(value) ? getSlot(slots) : null; | 52 | return hasPermission(value) ? getSlot(slots) : null; |
57 | } | 53 | } |
58 | 54 | ||
59 | return () => { | 55 | return () => { |
60 | - const mode = unref(getModeRef); | 56 | + const mode = unref(getPermissionMode); |
61 | // Role-based value control | 57 | // Role-based value control |
62 | if (mode === PermissionModeEnum.ROLE) { | 58 | if (mode === PermissionModeEnum.ROLE) { |
63 | return renderRoleAuth(); | 59 | return renderRoleAuth(); |
src/components/Description/src/index.tsx
@@ -33,7 +33,7 @@ export default defineComponent({ | @@ -33,7 +33,7 @@ export default defineComponent({ | ||
33 | }); | 33 | }); |
34 | 34 | ||
35 | /** | 35 | /** |
36 | - * @description: Whether to use title | 36 | + * @description: Whether to setting title |
37 | */ | 37 | */ |
38 | const useWrapper = computed(() => { | 38 | const useWrapper = computed(() => { |
39 | return !!unref(getMergeProps).title; | 39 | return !!unref(getMergeProps).title; |
src/components/Dropdown/src/Dropdown.tsx
@@ -15,7 +15,7 @@ export default defineComponent({ | @@ -15,7 +15,7 @@ export default defineComponent({ | ||
15 | const getMenuList = computed(() => props.dropMenuList); | 15 | const getMenuList = computed(() => props.dropMenuList); |
16 | 16 | ||
17 | function handleClickMenu({ key }: any) { | 17 | function handleClickMenu({ key }: any) { |
18 | - const menu = unref(getMenuList).find((item) => item.event === key); | 18 | + const menu = unref(getMenuList).find((item) => `${item.event}` === `${key}`); |
19 | emit('menuEvent', menu); | 19 | emit('menuEvent', menu); |
20 | } | 20 | } |
21 | 21 |
src/components/Excel/src/ImportExcel.vue
@@ -104,7 +104,7 @@ | @@ -104,7 +104,7 @@ | ||
104 | */ | 104 | */ |
105 | function handleInputClick(e: Event) { | 105 | function handleInputClick(e: Event) { |
106 | const files = e && (e.target as HTMLInputElement).files; | 106 | const files = e && (e.target as HTMLInputElement).files; |
107 | - const rawFile = files && files[0]; // only use files[0] | 107 | + const rawFile = files && files[0]; // only setting files[0] |
108 | if (!rawFile) return; | 108 | if (!rawFile) return; |
109 | upload(rawFile); | 109 | upload(rawFile); |
110 | } | 110 | } |
src/components/Form/src/componentMap.ts
@@ -2,7 +2,7 @@ import { Component } from 'vue'; | @@ -2,7 +2,7 @@ import { Component } from 'vue'; | ||
2 | import type { ComponentType } from './types/index'; | 2 | import type { ComponentType } from './types/index'; |
3 | 3 | ||
4 | /** | 4 | /** |
5 | - * Component list, register here to use it in the form | 5 | + * Component list, register here to setting it in the form |
6 | */ | 6 | */ |
7 | import { | 7 | import { |
8 | Input, | 8 | Input, |
src/components/Form/src/hooks/useLabelWidth.ts
@@ -31,7 +31,7 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref< | @@ -31,7 +31,7 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref< | ||
31 | wrapperCol: globWrapperCol, | 31 | wrapperCol: globWrapperCol, |
32 | } = unref(propsRef) as any; | 32 | } = unref(propsRef) as any; |
33 | 33 | ||
34 | - // If labelWidth is set globally, all items use | 34 | + // If labelWidth is set globally, all items setting |
35 | if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) { | 35 | if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) { |
36 | return { labelCol, wrapperCol }; | 36 | return { labelCol, wrapperCol }; |
37 | } | 37 | } |
src/components/Form/src/types/formItem.ts
@@ -68,7 +68,7 @@ export interface FormItem { | @@ -68,7 +68,7 @@ export interface FormItem { | ||
68 | */ | 68 | */ |
69 | labelAlign?: 'left' | 'right'; | 69 | labelAlign?: 'left' | 'right'; |
70 | /** | 70 | /** |
71 | - * a key of model. In the use of validate and resetFields method, the attribute is required | 71 | + * a key of model. In the setting of validate and resetFields method, the attribute is required |
72 | */ | 72 | */ |
73 | name?: NamePath; | 73 | name?: NamePath; |
74 | /** | 74 | /** |
@@ -76,7 +76,7 @@ export interface FormItem { | @@ -76,7 +76,7 @@ export interface FormItem { | ||
76 | */ | 76 | */ |
77 | rules?: object | object[]; | 77 | rules?: object | object[]; |
78 | /** | 78 | /** |
79 | - * Whether to automatically associate form fields. In most cases, you can use automatic association. | 79 | + * Whether to automatically associate form fields. In most cases, you can setting automatic association. |
80 | * If the conditions for automatic association are not met, you can manually associate them. See the notes below. | 80 | * If the conditions for automatic association are not met, you can manually associate them. See the notes below. |
81 | */ | 81 | */ |
82 | autoLink?: boolean; | 82 | autoLink?: boolean; |
src/components/Menu/index.ts
src/components/Menu/src/BasicMenu.tsx
1 | +import './index.less'; | ||
2 | + | ||
1 | import type { MenuState } from './types'; | 3 | import type { MenuState } from './types'; |
2 | import type { Menu as MenuType } from '/@/router/types'; | 4 | import type { Menu as MenuType } from '/@/router/types'; |
3 | 5 | ||
@@ -9,11 +11,10 @@ import MenuContent from './MenuContent'; | @@ -9,11 +11,10 @@ import MenuContent from './MenuContent'; | ||
9 | import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; | 11 | import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; |
10 | import { ThemeEnum } from '/@/enums/appEnum'; | 12 | import { ThemeEnum } from '/@/enums/appEnum'; |
11 | 13 | ||
12 | -import { menuStore } from '/@/store/modules/menu'; | ||
13 | import { appStore } from '/@/store/modules/app'; | 14 | import { appStore } from '/@/store/modules/app'; |
14 | 15 | ||
15 | -import { useSearchInput } from './useSearchInput'; | ||
16 | -import { useOpenKeys } from './useOpenKeys'; | 16 | +import { useSearchInput } from './hooks/useSearchInput'; |
17 | +import { useOpenKeys } from './hooks/useOpenKeys'; | ||
17 | import { useRouter } from 'vue-router'; | 18 | import { useRouter } from 'vue-router'; |
18 | 19 | ||
19 | import { isFunction } from '/@/utils/is'; | 20 | import { isFunction } from '/@/utils/is'; |
@@ -23,7 +24,7 @@ import { menuHasChildren } from './helper'; | @@ -23,7 +24,7 @@ import { menuHasChildren } from './helper'; | ||
23 | import { getCurrentParentPath } from '/@/router/menus'; | 24 | import { getCurrentParentPath } from '/@/router/menus'; |
24 | 25 | ||
25 | import { basicProps } from './props'; | 26 | import { basicProps } from './props'; |
26 | -import './index.less'; | 27 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; |
27 | export default defineComponent({ | 28 | export default defineComponent({ |
28 | name: 'BasicMenu', | 29 | name: 'BasicMenu', |
29 | props: basicProps, | 30 | props: basicProps, |
@@ -39,6 +40,8 @@ export default defineComponent({ | @@ -39,6 +40,8 @@ export default defineComponent({ | ||
39 | selectedKeys: [], | 40 | selectedKeys: [], |
40 | collapsedOpenKeys: [], | 41 | collapsedOpenKeys: [], |
41 | }); | 42 | }); |
43 | + | ||
44 | + const { getCollapsed } = useMenuSetting(); | ||
42 | const { currentRoute } = useRouter(); | 45 | const { currentRoute } = useRouter(); |
43 | 46 | ||
44 | const { items, flatItems, isAppMenu, mode, accordion } = toRefs(props); | 47 | const { items, flatItems, isAppMenu, mode, accordion } = toRefs(props); |
@@ -61,7 +64,7 @@ export default defineComponent({ | @@ -61,7 +64,7 @@ export default defineComponent({ | ||
61 | 64 | ||
62 | const getOpenKeys = computed(() => { | 65 | const getOpenKeys = computed(() => { |
63 | if (props.isAppMenu) { | 66 | if (props.isAppMenu) { |
64 | - return menuStore.getCollapsedState ? menuState.collapsedOpenKeys : menuState.openKeys; | 67 | + return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys; |
65 | } | 68 | } |
66 | return menuState.openKeys; | 69 | return menuState.openKeys; |
67 | }); | 70 | }); |
@@ -95,20 +98,20 @@ export default defineComponent({ | @@ -95,20 +98,20 @@ export default defineComponent({ | ||
95 | cls.push('basic-menu__sidebar-hor'); | 98 | cls.push('basic-menu__sidebar-hor'); |
96 | } | 99 | } |
97 | 100 | ||
98 | - if (!props.isTop && props.isAppMenu && appStore.getProjectConfig.menuSetting.split) { | 101 | + if (!props.isHorizontal && props.isAppMenu && appStore.getProjectConfig.menuSetting.split) { |
99 | cls.push('basic-menu__second'); | 102 | cls.push('basic-menu__second'); |
100 | } | 103 | } |
101 | return cls; | 104 | return cls; |
102 | }); | 105 | }); |
103 | 106 | ||
104 | - const showTitle = computed(() => props.collapsedShowTitle && menuStore.getCollapsedState); | 107 | + const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed)); |
105 | 108 | ||
106 | watch( | 109 | watch( |
107 | () => currentRoute.value.name, | 110 | () => currentRoute.value.name, |
108 | (name: string) => { | 111 | (name: string) => { |
109 | if (name === 'Redirect') return; | 112 | if (name === 'Redirect') return; |
110 | handleMenuChange(); | 113 | handleMenuChange(); |
111 | - props.isTop && appStore.getProjectConfig.menuSetting.split && getParentPath(); | 114 | + props.isHorizontal && appStore.getProjectConfig.menuSetting.split && getParentPath(); |
112 | } | 115 | } |
113 | ); | 116 | ); |
114 | 117 | ||
@@ -180,7 +183,7 @@ export default defineComponent({ | @@ -180,7 +183,7 @@ export default defineComponent({ | ||
180 | <MenuContent | 183 | <MenuContent |
181 | item={menu} | 184 | item={menu} |
182 | level={index} | 185 | level={index} |
183 | - isTop={props.isTop} | 186 | + isHorizontal={props.isHorizontal} |
184 | showTitle={unref(showTitle)} | 187 | showTitle={unref(showTitle)} |
185 | searchValue={menuState.searchValue} | 188 | searchValue={menuState.searchValue} |
186 | />, | 189 | />, |
@@ -196,7 +199,7 @@ export default defineComponent({ | @@ -196,7 +199,7 @@ export default defineComponent({ | ||
196 | showTitle={unref(showTitle)} | 199 | showTitle={unref(showTitle)} |
197 | item={menu} | 200 | item={menu} |
198 | level={index} | 201 | level={index} |
199 | - isTop={props.isTop} | 202 | + isHorizontal={props.isHorizontal} |
200 | searchValue={menuState.searchValue} | 203 | searchValue={menuState.searchValue} |
201 | />, | 204 | />, |
202 | ], | 205 | ], |
@@ -214,7 +217,7 @@ export default defineComponent({ | @@ -214,7 +217,7 @@ export default defineComponent({ | ||
214 | const inlineCollapsedObj = isInline | 217 | const inlineCollapsedObj = isInline |
215 | ? props.isAppMenu | 218 | ? props.isAppMenu |
216 | ? { | 219 | ? { |
217 | - inlineCollapsed: menuStore.getCollapsedState, | 220 | + inlineCollapsed: unref(getCollapsed), |
218 | } | 221 | } |
219 | : { inlineCollapsed: props.inlineCollapsed } | 222 | : { inlineCollapsed: props.inlineCollapsed } |
220 | : {}; | 223 | : {}; |
@@ -246,7 +249,6 @@ export default defineComponent({ | @@ -246,7 +249,6 @@ export default defineComponent({ | ||
246 | }); | 249 | }); |
247 | 250 | ||
248 | return () => { | 251 | return () => { |
249 | - const { getCollapsedState } = menuStore; | ||
250 | const { mode } = props; | 252 | const { mode } = props; |
251 | return mode === MenuModeEnum.HORIZONTAL ? ( | 253 | return mode === MenuModeEnum.HORIZONTAL ? ( |
252 | renderMenu() | 254 | renderMenu() |
@@ -258,7 +260,7 @@ export default defineComponent({ | @@ -258,7 +260,7 @@ export default defineComponent({ | ||
258 | theme={props.theme as ThemeEnum} | 260 | theme={props.theme as ThemeEnum} |
259 | onChange={handleInputChange} | 261 | onChange={handleInputChange} |
260 | onClick={handleInputClick} | 262 | onClick={handleInputClick} |
261 | - collapsed={getCollapsedState} | 263 | + collapsed={unref(getCollapsed)} |
262 | /> | 264 | /> |
263 | <section style={unref(getMenuWrapStyle)} class="basic-menu__content"> | 265 | <section style={unref(getMenuWrapStyle)} class="basic-menu__content"> |
264 | {renderMenu()} | 266 | {renderMenu()} |
src/components/Menu/src/MenuContent.tsx
@@ -26,7 +26,7 @@ export default defineComponent({ | @@ -26,7 +26,7 @@ export default defineComponent({ | ||
26 | type: Number as PropType<number>, | 26 | type: Number as PropType<number>, |
27 | default: 0, | 27 | default: 0, |
28 | }, | 28 | }, |
29 | - isTop: { | 29 | + isHorizontal: { |
30 | type: Boolean as PropType<boolean>, | 30 | type: Boolean as PropType<boolean>, |
31 | default: true, | 31 | default: true, |
32 | }, | 32 | }, |
@@ -40,8 +40,8 @@ export default defineComponent({ | @@ -40,8 +40,8 @@ export default defineComponent({ | ||
40 | } | 40 | } |
41 | 41 | ||
42 | function renderTag() { | 42 | function renderTag() { |
43 | - const { item, showTitle, isTop } = props; | ||
44 | - if (!item || showTitle || isTop) return null; | 43 | + const { item, showTitle, isHorizontal } = props; |
44 | + if (!item || showTitle || isHorizontal) return null; | ||
45 | 45 | ||
46 | const { tag } = item; | 46 | const { tag } = item; |
47 | if (!tag) return null; | 47 | if (!tag) return null; |
src/components/Menu/src/useOpenKeys.ts renamed to src/components/Menu/src/hooks/useOpenKeys.ts
1 | import { MenuModeEnum } from '/@/enums/menuEnum'; | 1 | import { MenuModeEnum } from '/@/enums/menuEnum'; |
2 | import type { Menu as MenuType } from '/@/router/types'; | 2 | import type { Menu as MenuType } from '/@/router/types'; |
3 | -import type { MenuState } from './types'; | 3 | +import type { MenuState } from '../types'; |
4 | import type { Ref } from 'vue'; | 4 | import type { Ref } from 'vue'; |
5 | 5 | ||
6 | import { unref } from 'vue'; | 6 | import { unref } from 'vue'; |
7 | -import { menuStore } from '/@/store/modules/menu'; | ||
8 | import { getAllParentPath } from '/@/utils/helper/menuHelper'; | 7 | import { getAllParentPath } from '/@/utils/helper/menuHelper'; |
9 | import { es6Unique } from '/@/utils'; | 8 | import { es6Unique } from '/@/utils'; |
9 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
10 | 10 | ||
11 | export function useOpenKeys( | 11 | export function useOpenKeys( |
12 | menuState: MenuState, | 12 | menuState: MenuState, |
@@ -16,6 +16,7 @@ export function useOpenKeys( | @@ -16,6 +16,7 @@ export function useOpenKeys( | ||
16 | mode: Ref<MenuModeEnum>, | 16 | mode: Ref<MenuModeEnum>, |
17 | accordion: Ref<boolean> | 17 | accordion: Ref<boolean> |
18 | ) { | 18 | ) { |
19 | + const { getCollapsed } = useMenuSetting(); | ||
19 | /** | 20 | /** |
20 | * @description:设置展开 | 21 | * @description:设置展开 |
21 | */ | 22 | */ |
@@ -49,7 +50,7 @@ export function useOpenKeys( | @@ -49,7 +50,7 @@ export function useOpenKeys( | ||
49 | rootSubMenuKeys.push(path); | 50 | rootSubMenuKeys.push(path); |
50 | } | 51 | } |
51 | } | 52 | } |
52 | - if (!menuStore.getCollapsedState || !unref(isAppMenu)) { | 53 | + if (!unref(getCollapsed) || !unref(isAppMenu)) { |
53 | const latestOpenKey = openKeys.find((key) => menuState.openKeys.indexOf(key) === -1); | 54 | const latestOpenKey = openKeys.find((key) => menuState.openKeys.indexOf(key) === -1); |
54 | if (rootSubMenuKeys.indexOf(latestOpenKey as string) === -1) { | 55 | if (rootSubMenuKeys.indexOf(latestOpenKey as string) === -1) { |
55 | menuState.openKeys = openKeys; | 56 | menuState.openKeys = openKeys; |
src/components/Menu/src/useSearchInput.ts renamed to src/components/Menu/src/hooks/useSearchInput.ts
1 | import type { Menu as MenuType } from '/@/router/types'; | 1 | import type { Menu as MenuType } from '/@/router/types'; |
2 | -import type { MenuState } from './types'; | 2 | +import type { MenuState } from '../types'; |
3 | import type { Ref } from 'vue'; | 3 | import type { Ref } from 'vue'; |
4 | 4 | ||
5 | import { isString } from '/@/utils/is'; | 5 | import { isString } from '/@/utils/is'; |
src/components/Menu/src/props.ts
@@ -8,6 +8,10 @@ export const basicProps = { | @@ -8,6 +8,10 @@ export const basicProps = { | ||
8 | type: Array as PropType<Menu[]>, | 8 | type: Array as PropType<Menu[]>, |
9 | default: () => [], | 9 | default: () => [], |
10 | }, | 10 | }, |
11 | + flatItems: { | ||
12 | + type: Array as PropType<Menu[]>, | ||
13 | + default: () => [], | ||
14 | + }, | ||
11 | appendClass: { | 15 | appendClass: { |
12 | type: Boolean as PropType<boolean>, | 16 | type: Boolean as PropType<boolean>, |
13 | default: false, | 17 | default: false, |
@@ -16,10 +20,6 @@ export const basicProps = { | @@ -16,10 +20,6 @@ export const basicProps = { | ||
16 | type: Boolean as PropType<boolean>, | 20 | type: Boolean as PropType<boolean>, |
17 | default: false, | 21 | default: false, |
18 | }, | 22 | }, |
19 | - flatItems: { | ||
20 | - type: Array as PropType<Menu[]>, | ||
21 | - default: () => [], | ||
22 | - }, | ||
23 | // 是否显示搜索框 | 23 | // 是否显示搜索框 |
24 | search: { | 24 | search: { |
25 | type: Boolean as PropType<boolean>, | 25 | type: Boolean as PropType<boolean>, |
@@ -55,7 +55,7 @@ export const basicProps = { | @@ -55,7 +55,7 @@ export const basicProps = { | ||
55 | type: Boolean as PropType<boolean>, | 55 | type: Boolean as PropType<boolean>, |
56 | default: true, | 56 | default: true, |
57 | }, | 57 | }, |
58 | - isTop: { | 58 | + isHorizontal: { |
59 | type: Boolean as PropType<boolean>, | 59 | type: Boolean as PropType<boolean>, |
60 | default: false, | 60 | default: false, |
61 | }, | 61 | }, |
src/components/Menu/src/types.d.ts renamed to src/components/Menu/src/types.ts
src/components/Modal/src/props.ts
@@ -35,7 +35,7 @@ export const basicProps = Object.assign({}, modalProps, { | @@ -35,7 +35,7 @@ export const basicProps = Object.assign({}, modalProps, { | ||
35 | }, | 35 | }, |
36 | // Warm reminder message | 36 | // Warm reminder message |
37 | helpMessage: [String, Array] as PropType<string | string[]>, | 37 | helpMessage: [String, Array] as PropType<string | string[]>, |
38 | - // Whether to use wrapper | 38 | + // Whether to setting wrapper |
39 | useWrapper: { | 39 | useWrapper: { |
40 | type: Boolean as PropType<boolean>, | 40 | type: Boolean as PropType<boolean>, |
41 | default: true, | 41 | default: true, |
src/components/Table/src/types/column.ts
@@ -190,7 +190,7 @@ export interface ColumnProps<T> { | @@ -190,7 +190,7 @@ export interface ColumnProps<T> { | ||
190 | onFilterDropdownVisibleChange?: (visible: boolean) => void; | 190 | onFilterDropdownVisibleChange?: (visible: boolean) => void; |
191 | 191 | ||
192 | /** | 192 | /** |
193 | - * When using columns, you can use this property to configure the properties that support the slot, | 193 | + * When using columns, you can setting this property to configure the properties that support the slot, |
194 | * such as slots: { filterIcon: 'XXX'} | 194 | * such as slots: { filterIcon: 'XXX'} |
195 | * @type object | 195 | * @type object |
196 | */ | 196 | */ |
src/components/Table/src/types/pagination.ts
@@ -86,7 +86,7 @@ export interface PaginationProps { | @@ -86,7 +86,7 @@ export interface PaginationProps { | ||
86 | size?: string; | 86 | size?: string; |
87 | 87 | ||
88 | /** | 88 | /** |
89 | - * whether to use simple mode | 89 | + * whether to setting simple mode |
90 | * @type boolean | 90 | * @type boolean |
91 | */ | 91 | */ |
92 | simple?: boolean; | 92 | simple?: boolean; |
src/components/Tinymce/src/plugins.ts
1 | -// Any plugins you want to use has to be imported | 1 | +// Any plugins you want to setting has to be imported |
2 | // Detail plugins list see https://www.tinymce.com/docs/plugins/ | 2 | // Detail plugins list see https://www.tinymce.com/docs/plugins/ |
3 | // Custom builds see https://www.tinymce.com/download/custom-builds/ | 3 | // Custom builds see https://www.tinymce.com/download/custom-builds/ |
4 | // colorpicker/contextmenu/textcolor plugin is now built in to the core editor, please remove it from your editor configuration | 4 | // colorpicker/contextmenu/textcolor plugin is now built in to the core editor, please remove it from your editor configuration |
src/components/registerGlobComp.ts
@@ -31,6 +31,7 @@ import { | @@ -31,6 +31,7 @@ import { | ||
31 | PageHeader, | 31 | PageHeader, |
32 | Result, | 32 | Result, |
33 | Empty, | 33 | Empty, |
34 | + Avatar, | ||
34 | } from 'ant-design-vue'; | 35 | } from 'ant-design-vue'; |
35 | import { getApp } from '/@/setup/App'; | 36 | import { getApp } from '/@/setup/App'; |
36 | 37 | ||
@@ -76,5 +77,6 @@ export function registerGlobComp() { | @@ -76,5 +77,6 @@ export function registerGlobComp() { | ||
76 | .use(PageHeader) | 77 | .use(PageHeader) |
77 | .use(Result) | 78 | .use(Result) |
78 | .use(Empty) | 79 | .use(Empty) |
80 | + .use(Avatar) | ||
79 | .use(Tabs); | 81 | .use(Tabs); |
80 | } | 82 | } |
src/components/types.ts
0 → 100644
src/design/var/index.less
src/enums/pageEnum.ts
@@ -5,4 +5,6 @@ export enum PageEnum { | @@ -5,4 +5,6 @@ export enum PageEnum { | ||
5 | BASE_HOME = '/dashboard', | 5 | BASE_HOME = '/dashboard', |
6 | // error page path | 6 | // error page path |
7 | ERROR_PAGE = '/exception', | 7 | ERROR_PAGE = '/exception', |
8 | + // error log page path | ||
9 | + ERROR_LOG_PAGE = '/exception/error-log', | ||
8 | } | 10 | } |
src/hooks/core/useDebouncedRef.ts
0 → 100644
1 | +import { customRef } from 'vue'; | ||
2 | + | ||
3 | +export function useDebouncedRef<T = any>(value: T, delay = 100) { | ||
4 | + let timeout: TimeoutHandle; | ||
5 | + return customRef((track, trigger) => { | ||
6 | + return { | ||
7 | + get() { | ||
8 | + track(); | ||
9 | + return value; | ||
10 | + }, | ||
11 | + set(newValue: T) { | ||
12 | + clearTimeout(timeout); | ||
13 | + timeout = setTimeout(() => { | ||
14 | + value = newValue; | ||
15 | + trigger(); | ||
16 | + }, delay); | ||
17 | + }, | ||
18 | + }; | ||
19 | + }); | ||
20 | +} |
src/settings/use/index.ts renamed to src/hooks/setting/index.ts
src/hooks/setting/useHeaderSetting.ts
0 → 100644
1 | +import type { HeaderSetting } from '/@/types/config'; | ||
2 | + | ||
3 | +import { computed, unref } from 'vue'; | ||
4 | + | ||
5 | +import { appStore } from '/@/store/modules/app'; | ||
6 | + | ||
7 | +import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; | ||
8 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
9 | +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
10 | + | ||
11 | +import { MenuModeEnum } from '/@/enums/menuEnum'; | ||
12 | + | ||
13 | +export function useHeaderSetting() { | ||
14 | + const { getShow: getShowMultipleTab } = useMultipleTabSetting(); | ||
15 | + const { getMode, getSplit, getShowHeaderTrigger, getIsSidebarType } = useMenuSetting(); | ||
16 | + const { getShowBreadCrumb, getShowLogo } = useRootSetting(); | ||
17 | + | ||
18 | + // Get header configuration | ||
19 | + const getHeaderSetting = computed(() => appStore.getProjectConfig.headerSetting); | ||
20 | + | ||
21 | + const getShowDoc = computed(() => unref(getHeaderSetting).showDoc); | ||
22 | + | ||
23 | + const getTheme = computed(() => unref(getHeaderSetting).theme); | ||
24 | + | ||
25 | + const getShowRedo = computed(() => unref(getHeaderSetting).showRedo && unref(getShowMultipleTab)); | ||
26 | + | ||
27 | + const getUseLockPage = computed(() => unref(getHeaderSetting).useLockPage); | ||
28 | + | ||
29 | + const getShowFullScreen = computed(() => unref(getHeaderSetting).showFullScreen); | ||
30 | + | ||
31 | + const getShowNotice = computed(() => unref(getHeaderSetting).showNotice); | ||
32 | + | ||
33 | + const getShowBread = computed(() => { | ||
34 | + return ( | ||
35 | + unref(getMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit) | ||
36 | + ); | ||
37 | + }); | ||
38 | + | ||
39 | + const getShowHeaderLogo = computed(() => { | ||
40 | + return unref(getShowLogo) && !unref(getIsSidebarType); | ||
41 | + }); | ||
42 | + | ||
43 | + const getShowContent = computed(() => { | ||
44 | + return unref(getShowBread) || unref(getShowHeaderTrigger); | ||
45 | + }); | ||
46 | + | ||
47 | + // Set header configuration | ||
48 | + function setHeaderSetting(headerSetting: Partial<HeaderSetting>): void { | ||
49 | + appStore.commitProjectConfigState({ headerSetting }); | ||
50 | + } | ||
51 | + | ||
52 | + return { | ||
53 | + setHeaderSetting, | ||
54 | + | ||
55 | + getHeaderSetting, | ||
56 | + | ||
57 | + getShowDoc, | ||
58 | + getTheme, | ||
59 | + getShowRedo, | ||
60 | + getUseLockPage, | ||
61 | + getShowFullScreen, | ||
62 | + getShowNotice, | ||
63 | + getShowBread, | ||
64 | + getShowContent, | ||
65 | + getShowHeaderLogo, | ||
66 | + }; | ||
67 | +} |
src/settings/use/useLocaleSetting.ts renamed to src/hooks/setting/useLocaleSetting.ts
1 | import type { LocaleSetting } from '/@/types/config'; | 1 | import type { LocaleSetting } from '/@/types/config'; |
2 | 2 | ||
3 | -import { computed } from 'vue'; | 3 | +import { computed, unref } from 'vue'; |
4 | import { appStore } from '/@/store/modules/app'; | 4 | import { appStore } from '/@/store/modules/app'; |
5 | 5 | ||
6 | import getProjectSetting from '/@/settings/projectSetting'; | 6 | import getProjectSetting from '/@/settings/projectSetting'; |
@@ -8,24 +8,16 @@ import { localeList } from '/@/locales'; | @@ -8,24 +8,16 @@ import { localeList } from '/@/locales'; | ||
8 | 8 | ||
9 | export function useLocaleSetting() { | 9 | export function useLocaleSetting() { |
10 | // Get locale configuration | 10 | // Get locale configuration |
11 | - const getLocale = computed(() => { | ||
12 | - return appStore.getProjectConfig.locale || getProjectSetting.locale; | ||
13 | - }); | 11 | + const getLocale = computed(() => appStore.getProjectConfig.locale || getProjectSetting.locale); |
14 | 12 | ||
15 | // get current language | 13 | // get current language |
16 | - const getLang = computed(() => { | ||
17 | - return getLocale.value.lang; | ||
18 | - }); | 14 | + const getLang = computed(() => unref(getLocale).lang); |
19 | 15 | ||
20 | // get Available Locales | 16 | // get Available Locales |
21 | - const getAvailableLocales = computed((): string[] => { | ||
22 | - return getLocale.value.availableLocales; | ||
23 | - }); | 17 | + const getAvailableLocales = computed((): string[] => unref(getLocale).availableLocales); |
24 | 18 | ||
25 | // get Fallback Locales | 19 | // get Fallback Locales |
26 | - const getFallbackLocale = computed((): string => { | ||
27 | - return getLocale.value.fallback; | ||
28 | - }); | 20 | + const getFallbackLocale = computed((): string => unref(getLocale).fallback); |
29 | 21 | ||
30 | // Set locale configuration | 22 | // Set locale configuration |
31 | function setLocale(locale: Partial<LocaleSetting>): void { | 23 | function setLocale(locale: Partial<LocaleSetting>): void { |
src/hooks/setting/useMenuSetting.ts
0 → 100644
1 | +import type { MenuSetting } from '/@/types/config'; | ||
2 | + | ||
3 | +import { computed, unref } from 'vue'; | ||
4 | + | ||
5 | +import { appStore } from '/@/store/modules/app'; | ||
6 | + | ||
7 | +import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum'; | ||
8 | +import { MenuModeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'; | ||
9 | + | ||
10 | +export function useMenuSetting() { | ||
11 | + // Get menu configuration | ||
12 | + const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting); | ||
13 | + | ||
14 | + const getMiniWidth = computed(() => unref(getMenuSetting).menuWidth); | ||
15 | + | ||
16 | + const getCollapsed = computed(() => unref(getMenuSetting).collapsed); | ||
17 | + | ||
18 | + const getType = computed(() => unref(getMenuSetting).type); | ||
19 | + | ||
20 | + const getMode = computed(() => unref(getMenuSetting).mode); | ||
21 | + | ||
22 | + const getShow = computed(() => unref(getMenuSetting).show); | ||
23 | + | ||
24 | + const getMenuWidth = computed(() => unref(getMenuSetting).menuWidth); | ||
25 | + | ||
26 | + const getTrigger = computed(() => unref(getMenuSetting).trigger); | ||
27 | + | ||
28 | + const getTheme = computed(() => unref(getMenuSetting).theme); | ||
29 | + | ||
30 | + const getSplit = computed(() => unref(getMenuSetting).split); | ||
31 | + | ||
32 | + const getHasDrag = computed(() => unref(getMenuSetting).hasDrag); | ||
33 | + | ||
34 | + const getAccordion = computed(() => unref(getMenuSetting).accordion); | ||
35 | + | ||
36 | + const getCollapsedShowTitle = computed(() => unref(getMenuSetting).collapsedShowTitle); | ||
37 | + | ||
38 | + const getCollapsedShowSearch = computed(() => unref(getMenuSetting).collapsedShowSearch); | ||
39 | + | ||
40 | + const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign); | ||
41 | + | ||
42 | + const getIsSidebarType = computed(() => unref(getType) === MenuTypeEnum.SIDEBAR); | ||
43 | + | ||
44 | + const getShowTopMenu = computed(() => { | ||
45 | + return unref(getMode) === MenuModeEnum.HORIZONTAL || unref(getSplit); | ||
46 | + }); | ||
47 | + | ||
48 | + const getShowHeaderTrigger = computed(() => { | ||
49 | + if ( | ||
50 | + unref(getType) === MenuTypeEnum.TOP_MENU || | ||
51 | + !unref(getShow) || | ||
52 | + !unref(getMenuSetting).hidden | ||
53 | + ) { | ||
54 | + return false; | ||
55 | + } | ||
56 | + | ||
57 | + return unref(getTrigger) === TriggerEnum.HEADER; | ||
58 | + }); | ||
59 | + | ||
60 | + const getShowSearch = computed(() => { | ||
61 | + return ( | ||
62 | + unref(getMenuSetting).showSearch && | ||
63 | + !(unref(getType) === MenuTypeEnum.MIX && unref(getMode) === MenuModeEnum.HORIZONTAL) | ||
64 | + ); | ||
65 | + }); | ||
66 | + | ||
67 | + const getIsHorizontal = computed(() => { | ||
68 | + return unref(getMode) === MenuModeEnum.HORIZONTAL; | ||
69 | + }); | ||
70 | + | ||
71 | + const getMiniWidthNumber = computed(() => { | ||
72 | + const { collapsedShowTitle } = unref(getMenuSetting); | ||
73 | + return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH; | ||
74 | + }); | ||
75 | + | ||
76 | + const getCalcContentWidth = computed(() => { | ||
77 | + const width = unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMiniWidth); | ||
78 | + return `calc(100% - ${width}px)`; | ||
79 | + }); | ||
80 | + | ||
81 | + // Set menu configuration | ||
82 | + function setMenuSetting(menuSetting: Partial<MenuSetting>): void { | ||
83 | + appStore.commitProjectConfigState({ menuSetting }); | ||
84 | + } | ||
85 | + | ||
86 | + function toggleCollapsed() { | ||
87 | + setMenuSetting({ | ||
88 | + collapsed: !unref(getCollapsed), | ||
89 | + }); | ||
90 | + } | ||
91 | + | ||
92 | + return { | ||
93 | + setMenuSetting, | ||
94 | + | ||
95 | + toggleCollapsed, | ||
96 | + | ||
97 | + getMenuSetting, | ||
98 | + getMiniWidth, | ||
99 | + getType, | ||
100 | + getMode, | ||
101 | + getShow, | ||
102 | + getCollapsed, | ||
103 | + getMiniWidthNumber, | ||
104 | + getCalcContentWidth, | ||
105 | + getMenuWidth, | ||
106 | + getTrigger, | ||
107 | + getSplit, | ||
108 | + getTheme, | ||
109 | + getHasDrag, | ||
110 | + getIsHorizontal, | ||
111 | + getShowSearch, | ||
112 | + getCollapsedShowTitle, | ||
113 | + getCollapsedShowSearch, | ||
114 | + getIsSidebarType, | ||
115 | + getAccordion, | ||
116 | + getShowTopMenu, | ||
117 | + getShowHeaderTrigger, | ||
118 | + getTopMenuAlign, | ||
119 | + }; | ||
120 | +} |
src/hooks/setting/useMultipleTabSetting.ts
0 → 100644
1 | +import type { MultiTabsSetting } from '/@/types/config'; | ||
2 | + | ||
3 | +import { computed, unref } from 'vue'; | ||
4 | + | ||
5 | +import { appStore } from '/@/store/modules/app'; | ||
6 | + | ||
7 | +export function useMultipleTabSetting() { | ||
8 | + const getMultipleTabSetting = computed(() => appStore.getProjectConfig.multiTabsSetting); | ||
9 | + | ||
10 | + const getMax = computed(() => unref(getMultipleTabSetting).max); | ||
11 | + | ||
12 | + const getShow = computed(() => unref(getMultipleTabSetting).show); | ||
13 | + | ||
14 | + function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) { | ||
15 | + appStore.commitProjectConfigState({ multiTabsSetting }); | ||
16 | + } | ||
17 | + | ||
18 | + return { | ||
19 | + setMultipleTabSetting, | ||
20 | + | ||
21 | + getMultipleTabSetting, | ||
22 | + getMax, | ||
23 | + getShow, | ||
24 | + }; | ||
25 | +} |
src/hooks/setting/useRootSetting.ts
0 → 100644
1 | +import type { ProjectConfig } from '/@/types/config'; | ||
2 | + | ||
3 | +import { computed, unref } from 'vue'; | ||
4 | + | ||
5 | +import { appStore } from '/@/store/modules/app'; | ||
6 | + | ||
7 | +type RootSetting = Omit< | ||
8 | + ProjectConfig, | ||
9 | + 'locale' | 'headerSetting' | 'menuSetting' | 'multiTabsSetting' | ||
10 | +>; | ||
11 | +export function useRootSetting() { | ||
12 | + const getRootSetting = computed((): RootSetting => appStore.getProjectConfig); | ||
13 | + | ||
14 | + const getOpenPageLoading = computed(() => unref(getRootSetting).openPageLoading); | ||
15 | + | ||
16 | + const getOpenRouterTransition = computed(() => unref(getRootSetting).openRouterTransition); | ||
17 | + | ||
18 | + const getOpenKeepAlive = computed(() => unref(getRootSetting).openKeepAlive); | ||
19 | + | ||
20 | + const getRouterTransition = computed(() => unref(getRootSetting).routerTransition); | ||
21 | + | ||
22 | + const getCanEmbedIFramePage = computed(() => unref(getRootSetting).canEmbedIFramePage); | ||
23 | + | ||
24 | + const getPermissionMode = computed(() => unref(getRootSetting).permissionMode); | ||
25 | + | ||
26 | + const getShowLogo = computed(() => unref(getRootSetting).showLogo); | ||
27 | + | ||
28 | + const getUseErrorHandle = computed(() => unref(getRootSetting).useErrorHandle); | ||
29 | + | ||
30 | + const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb); | ||
31 | + | ||
32 | + const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon); | ||
33 | + | ||
34 | + function setRootSetting(setting: RootSetting) { | ||
35 | + appStore.commitProjectConfigState(setting); | ||
36 | + } | ||
37 | + | ||
38 | + return { | ||
39 | + setRootSetting, | ||
40 | + | ||
41 | + getRootSetting, | ||
42 | + getOpenPageLoading, | ||
43 | + getOpenRouterTransition, | ||
44 | + getOpenKeepAlive, | ||
45 | + getRouterTransition, | ||
46 | + getCanEmbedIFramePage, | ||
47 | + getPermissionMode, | ||
48 | + getShowLogo, | ||
49 | + getUseErrorHandle, | ||
50 | + getShowBreadCrumb, | ||
51 | + getShowBreadCrumbIcon, | ||
52 | + }; | ||
53 | +} |
src/hooks/web/useLocale.ts
@@ -7,7 +7,7 @@ import { unref, ref } from 'vue'; | @@ -7,7 +7,7 @@ import { unref, ref } from 'vue'; | ||
7 | 7 | ||
8 | import { getI18n } from '/@/setup/i18n'; | 8 | import { getI18n } from '/@/setup/i18n'; |
9 | 9 | ||
10 | -import { useLocaleSetting } from '/@/settings/use/useLocaleSetting'; | 10 | +import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting'; |
11 | 11 | ||
12 | import moment from 'moment'; | 12 | import moment from 'moment'; |
13 | 13 | ||
@@ -67,7 +67,7 @@ export function useLocale() { | @@ -67,7 +67,7 @@ export function useLocale() { | ||
67 | } | 67 | } |
68 | 68 | ||
69 | /** | 69 | /** |
70 | - * For non-setup use | 70 | + * For non-setup setting |
71 | */ | 71 | */ |
72 | export function useExternalI18n() { | 72 | export function useExternalI18n() { |
73 | return getI18n().global; | 73 | return getI18n().global; |
src/hooks/web/usePage.ts
@@ -20,6 +20,7 @@ function handleError(e: Error) { | @@ -20,6 +20,7 @@ function handleError(e: Error) { | ||
20 | export function useGo() { | 20 | export function useGo() { |
21 | const { push, replace } = useRouter(); | 21 | const { push, replace } = useRouter(); |
22 | function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) { | 22 | function go(opt: PageEnum | RouteLocationRawEx | string = PageEnum.BASE_HOME, isReplace = false) { |
23 | + if (!opt) return; | ||
23 | if (isString(opt)) { | 24 | if (isString(opt)) { |
24 | isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError); | 25 | isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError); |
25 | } else { | 26 | } else { |
src/hooks/web/useSideBar.ts deleted
100644 → 0
1 | -import { computed } from 'vue'; | ||
2 | -import { appStore } from '/@/store/modules/app'; | ||
3 | - | ||
4 | -export function useSideBar() { | ||
5 | - const currentCollapsedRef = computed(() => { | ||
6 | - return appStore.getProjectConfig.menuSetting.collapsed; | ||
7 | - }); | ||
8 | - const changeCollapsed = (collapsed: boolean) => { | ||
9 | - appStore.commitProjectConfigState({ | ||
10 | - menuSetting: { | ||
11 | - collapsed: collapsed, | ||
12 | - }, | ||
13 | - }); | ||
14 | - }; | ||
15 | - return { | ||
16 | - openSider: changeCollapsed(false), | ||
17 | - closeSider: changeCollapsed(true), | ||
18 | - currentCollapsedRef, | ||
19 | - }; | ||
20 | -} |
src/layouts/default/LayoutSideBar.tsx deleted
100644 → 0
1 | -import { computed, defineComponent, nextTick, onMounted, ref, unref } from 'vue'; | ||
2 | - | ||
3 | -import { Layout } from 'ant-design-vue'; | ||
4 | -import LayoutTrigger from './LayoutTrigger'; | ||
5 | -import LayoutMenu from '/@/layouts/default/menu/LayoutMenu'; | ||
6 | - | ||
7 | -import { menuStore } from '/@/store/modules/menu'; | ||
8 | -import { appStore } from '/@/store/modules/app'; | ||
9 | - | ||
10 | -import { MenuModeEnum, MenuSplitTyeEnum, TriggerEnum } from '/@/enums/menuEnum'; | ||
11 | -import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum'; | ||
12 | - | ||
13 | -import { useDebounce } from '/@/hooks/core/useDebounce'; | ||
14 | - | ||
15 | -export default defineComponent({ | ||
16 | - name: 'DefaultLayoutSideBar', | ||
17 | - setup() { | ||
18 | - const initRef = ref(false); | ||
19 | - const brokenRef = ref(false); | ||
20 | - const collapseRef = ref(true); | ||
21 | - const dragBarRef = ref<Nullable<HTMLDivElement>>(null); | ||
22 | - const sideRef = ref<any>(null); | ||
23 | - | ||
24 | - const getProjectConfigRef = computed(() => { | ||
25 | - return appStore.getProjectConfig; | ||
26 | - }); | ||
27 | - | ||
28 | - const getMiniWidth = computed(() => { | ||
29 | - const { | ||
30 | - menuSetting: { collapsedShowTitle }, | ||
31 | - } = unref(getProjectConfigRef); | ||
32 | - return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH; | ||
33 | - }); | ||
34 | - | ||
35 | - function onCollapseChange(val: boolean) { | ||
36 | - if (initRef.value) { | ||
37 | - collapseRef.value = val; | ||
38 | - menuStore.commitCollapsedState(val); | ||
39 | - } else { | ||
40 | - const collapsed = appStore.getProjectConfig.menuSetting.collapsed; | ||
41 | - !collapsed && menuStore.commitCollapsedState(val); | ||
42 | - } | ||
43 | - initRef.value = true; | ||
44 | - } | ||
45 | - | ||
46 | - // Menu area drag and drop-mouse movement | ||
47 | - function handleMouseMove(ele: any, wrap: any, clientX: number) { | ||
48 | - document.onmousemove = function (innerE) { | ||
49 | - let iT = ele.left + ((innerE || event).clientX - clientX); | ||
50 | - innerE = innerE || window.event; | ||
51 | - // let tarnameb = innerE.target || innerE.srcElement; | ||
52 | - const maxT = 600; | ||
53 | - const minT = unref(getMiniWidth); | ||
54 | - iT < 0 && (iT = 0); | ||
55 | - iT > maxT && (iT = maxT); | ||
56 | - iT < minT && (iT = minT); | ||
57 | - ele.style.left = wrap.style.width = iT + 'px'; | ||
58 | - return false; | ||
59 | - }; | ||
60 | - } | ||
61 | - | ||
62 | - // 菜单区域拖拽 - 鼠标松开 | ||
63 | - function removeMouseup(ele: any) { | ||
64 | - const wrap = unref(sideRef).$el; | ||
65 | - document.onmouseup = function () { | ||
66 | - document.onmousemove = null; | ||
67 | - document.onmouseup = null; | ||
68 | - const width = parseInt(wrap.style.width); | ||
69 | - menuStore.commitDragStartState(false); | ||
70 | - if (!menuStore.getCollapsedState) { | ||
71 | - if (width > unref(getMiniWidth) + 20) { | ||
72 | - setMenuWidth(width); | ||
73 | - } else { | ||
74 | - menuStore.commitCollapsedState(true); | ||
75 | - } | ||
76 | - } else { | ||
77 | - if (width > unref(getMiniWidth)) { | ||
78 | - setMenuWidth(width); | ||
79 | - menuStore.commitCollapsedState(false); | ||
80 | - } | ||
81 | - } | ||
82 | - | ||
83 | - ele.releaseCapture && ele.releaseCapture(); | ||
84 | - }; | ||
85 | - } | ||
86 | - | ||
87 | - function setMenuWidth(width: number) { | ||
88 | - appStore.commitProjectConfigState({ | ||
89 | - menuSetting: { | ||
90 | - menuWidth: width, | ||
91 | - }, | ||
92 | - }); | ||
93 | - } | ||
94 | - | ||
95 | - function changeWrapWidth() { | ||
96 | - const ele = unref(dragBarRef) as any; | ||
97 | - const side = unref(sideRef); | ||
98 | - | ||
99 | - const wrap = (side || {}).$el; | ||
100 | - ele && | ||
101 | - (ele.onmousedown = (e: any) => { | ||
102 | - menuStore.commitDragStartState(true); | ||
103 | - wrap.style.transition = 'unset'; | ||
104 | - const clientX = (e || event).clientX; | ||
105 | - ele.left = ele.offsetLeft; | ||
106 | - handleMouseMove(ele, wrap, clientX); | ||
107 | - removeMouseup(ele); | ||
108 | - ele.setCapture && ele.setCapture(); | ||
109 | - return false; | ||
110 | - }); | ||
111 | - } | ||
112 | - function handleBreakpoint(broken: boolean) { | ||
113 | - brokenRef.value = broken; | ||
114 | - } | ||
115 | - | ||
116 | - const getDragBarStyle = computed(() => { | ||
117 | - if (menuStore.getCollapsedState) { | ||
118 | - return { left: `${unref(getMiniWidth)}px` }; | ||
119 | - } | ||
120 | - return {}; | ||
121 | - }); | ||
122 | - | ||
123 | - const getCollapsedWidth = computed(() => { | ||
124 | - return unref(brokenRef) ? 0 : unref(getMiniWidth); | ||
125 | - }); | ||
126 | - | ||
127 | - const showTrigger = computed(() => { | ||
128 | - const { | ||
129 | - menuSetting: { trigger }, | ||
130 | - } = unref(getProjectConfigRef); | ||
131 | - return trigger !== TriggerEnum.NONE && trigger === TriggerEnum.FOOTER; | ||
132 | - }); | ||
133 | - | ||
134 | - onMounted(() => { | ||
135 | - nextTick(() => { | ||
136 | - const [exec] = useDebounce(changeWrapWidth, 20); | ||
137 | - exec(); | ||
138 | - }); | ||
139 | - }); | ||
140 | - | ||
141 | - function handleSiderClick(e: ChangeEvent) { | ||
142 | - if (!e || !e.target || e.target.className !== 'basic-menu__content') return; | ||
143 | - | ||
144 | - const { collapsed, show } = appStore.getProjectConfig.menuSetting; | ||
145 | - if (!collapsed || !show) return; | ||
146 | - appStore.commitProjectConfigState({ | ||
147 | - menuSetting: { | ||
148 | - collapsed: false, | ||
149 | - }, | ||
150 | - }); | ||
151 | - } | ||
152 | - | ||
153 | - function renderDragLine() { | ||
154 | - const { menuSetting: { hasDrag = true } = {} } = unref(getProjectConfigRef); | ||
155 | - return ( | ||
156 | - <div | ||
157 | - class={[`layout-sidebar__dargbar`, !hasDrag ? 'hide' : '']} | ||
158 | - style={unref(getDragBarStyle)} | ||
159 | - ref={dragBarRef} | ||
160 | - /> | ||
161 | - ); | ||
162 | - } | ||
163 | - | ||
164 | - return () => { | ||
165 | - const { | ||
166 | - menuSetting: { theme, split: splitMenu }, | ||
167 | - } = unref(getProjectConfigRef); | ||
168 | - const { getCollapsedState, getMenuWidthState } = menuStore; | ||
169 | - | ||
170 | - const triggerDom = unref(showTrigger) | ||
171 | - ? { | ||
172 | - trigger: () => <LayoutTrigger />, | ||
173 | - } | ||
174 | - : {}; | ||
175 | - | ||
176 | - const triggerAttr = unref(showTrigger) | ||
177 | - ? {} | ||
178 | - : { | ||
179 | - trigger: null, | ||
180 | - }; | ||
181 | - | ||
182 | - return ( | ||
183 | - <Layout.Sider | ||
184 | - onClick={handleSiderClick} | ||
185 | - onCollapse={onCollapseChange} | ||
186 | - breakpoint="md" | ||
187 | - width={getMenuWidthState} | ||
188 | - collapsed={getCollapsedState} | ||
189 | - collapsible | ||
190 | - collapsedWidth={unref(getCollapsedWidth)} | ||
191 | - theme={theme} | ||
192 | - class="layout-sidebar" | ||
193 | - ref={sideRef} | ||
194 | - onBreakpoint={handleBreakpoint} | ||
195 | - {...triggerAttr} | ||
196 | - > | ||
197 | - {{ | ||
198 | - ...triggerDom, | ||
199 | - default: () => ( | ||
200 | - <> | ||
201 | - <LayoutMenu | ||
202 | - theme={theme} | ||
203 | - menuMode={splitMenu ? MenuModeEnum.INLINE : null} | ||
204 | - splitType={splitMenu ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE} | ||
205 | - /> | ||
206 | - {renderDragLine()} | ||
207 | - </> | ||
208 | - ), | ||
209 | - }} | ||
210 | - </Layout.Sider> | ||
211 | - ); | ||
212 | - }; | ||
213 | - }, | ||
214 | -}); |
src/layouts/default/LayoutTrigger.tsx
1 | +import type { PropType } from 'vue'; | ||
2 | + | ||
3 | +import { defineComponent, unref } from 'vue'; | ||
1 | import { | 4 | import { |
2 | DoubleRightOutlined, | 5 | DoubleRightOutlined, |
3 | DoubleLeftOutlined, | 6 | DoubleLeftOutlined, |
4 | MenuUnfoldOutlined, | 7 | MenuUnfoldOutlined, |
5 | MenuFoldOutlined, | 8 | MenuFoldOutlined, |
6 | } from '@ant-design/icons-vue'; | 9 | } from '@ant-design/icons-vue'; |
7 | -import { defineComponent } from 'vue'; | ||
8 | 10 | ||
9 | -// store | ||
10 | -import { menuStore } from '/@/store/modules/menu'; | 11 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; |
11 | 12 | ||
12 | export default defineComponent({ | 13 | export default defineComponent({ |
13 | name: 'LayoutTrigger', | 14 | name: 'LayoutTrigger', |
14 | props: { | 15 | props: { |
15 | sider: { | 16 | sider: { |
16 | - type: Boolean, | 17 | + type: Boolean as PropType<boolean>, |
17 | default: true, | 18 | default: true, |
18 | }, | 19 | }, |
19 | theme: { | 20 | theme: { |
20 | - type: String, | 21 | + type: String as PropType<string>, |
21 | }, | 22 | }, |
22 | }, | 23 | }, |
23 | setup(props) { | 24 | setup(props) { |
24 | - function toggleMenu() { | ||
25 | - menuStore.commitCollapsedState(!menuStore.getCollapsedState); | ||
26 | - } | 25 | + const { toggleCollapsed, getCollapsed } = useMenuSetting(); |
27 | 26 | ||
28 | return () => { | 27 | return () => { |
29 | - const siderTrigger = menuStore.getCollapsedState ? ( | ||
30 | - <DoubleRightOutlined /> | ||
31 | - ) : ( | ||
32 | - <DoubleLeftOutlined /> | ||
33 | - ); | ||
34 | - if (props.sider) return siderTrigger; | 28 | + const siderTrigger = unref(getCollapsed) ? <DoubleRightOutlined /> : <DoubleLeftOutlined />; |
29 | + | ||
30 | + if (props.sider) { | ||
31 | + return siderTrigger; | ||
32 | + } | ||
35 | 33 | ||
36 | return ( | 34 | return ( |
37 | - <span class={['layout-trigger', props.theme]} onClick={toggleMenu}> | ||
38 | - {menuStore.getCollapsedState ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} | 35 | + <span class={['layout-trigger', props.theme]} onClick={toggleCollapsed}> |
36 | + {unref(getCollapsed) ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} | ||
39 | </span> | 37 | </span> |
40 | ); | 38 | ); |
41 | }; | 39 | }; |
src/layouts/default/header/LayoutBreadcrumb.tsx
@@ -4,14 +4,17 @@ import type { PropType } from 'vue'; | @@ -4,14 +4,17 @@ import type { PropType } from 'vue'; | ||
4 | 4 | ||
5 | import { defineComponent, TransitionGroup, unref, watch, ref } from 'vue'; | 5 | import { defineComponent, TransitionGroup, unref, watch, ref } from 'vue'; |
6 | import Breadcrumb from '/@/components/Breadcrumb/Breadcrumb.vue'; | 6 | import Breadcrumb from '/@/components/Breadcrumb/Breadcrumb.vue'; |
7 | +import Icon from '/@/components/Icon'; | ||
7 | import BreadcrumbItem from '/@/components/Breadcrumb/BreadcrumbItem.vue'; | 8 | import BreadcrumbItem from '/@/components/Breadcrumb/BreadcrumbItem.vue'; |
9 | + | ||
8 | import { useRouter } from 'vue-router'; | 10 | import { useRouter } from 'vue-router'; |
9 | -import router from '/@/router'; | ||
10 | -import { PageEnum } from '/@/enums/pageEnum'; | ||
11 | -import { isBoolean } from '/@/utils/is'; | ||
12 | 11 | ||
12 | +import { isBoolean } from '/@/utils/is'; | ||
13 | import { compile } from 'path-to-regexp'; | 13 | import { compile } from 'path-to-regexp'; |
14 | -import Icon from '/@/components/Icon'; | 14 | + |
15 | +import router from '/@/router'; | ||
16 | + | ||
17 | +import { PageEnum } from '/@/enums/pageEnum'; | ||
15 | 18 | ||
16 | export default defineComponent({ | 19 | export default defineComponent({ |
17 | name: 'BasicBreadcrumb', | 20 | name: 'BasicBreadcrumb', |
@@ -40,7 +43,6 @@ export default defineComponent({ | @@ -40,7 +43,6 @@ export default defineComponent({ | ||
40 | const matchedList = matched.filter((item) => item.meta && item.meta.title).slice(1); | 43 | const matchedList = matched.filter((item) => item.meta && item.meta.title).slice(1); |
41 | const firstItem = matchedList[0]; | 44 | const firstItem = matchedList[0]; |
42 | const ret = getHomeRoute(firstItem); | 45 | const ret = getHomeRoute(firstItem); |
43 | - | ||
44 | if (!isBoolean(ret)) { | 46 | if (!isBoolean(ret)) { |
45 | matchedList.unshift(ret); | 47 | matchedList.unshift(ret); |
46 | } | 48 | } |
@@ -74,42 +76,51 @@ export default defineComponent({ | @@ -74,42 +76,51 @@ export default defineComponent({ | ||
74 | return push(pathCompile(path)); | 76 | return push(pathCompile(path)); |
75 | } | 77 | } |
76 | 78 | ||
79 | + function renderItemContent(item: AppRouteRecordRaw) { | ||
80 | + return ( | ||
81 | + <> | ||
82 | + {props.showIcon && item.meta.icon && item.meta.icon.trim() !== '' && ( | ||
83 | + <Icon | ||
84 | + icon={item.meta.icon} | ||
85 | + class="icon mr-1 " | ||
86 | + style={{ | ||
87 | + marginBottom: '2px', | ||
88 | + }} | ||
89 | + /> | ||
90 | + )} | ||
91 | + {item.meta.title} | ||
92 | + </> | ||
93 | + ); | ||
94 | + } | ||
95 | + | ||
96 | + function renderBreadcrumbItemList() { | ||
97 | + return unref(itemList).map((item) => { | ||
98 | + const isLink = | ||
99 | + (!!item.redirect && !item.meta.disabledRedirect) || | ||
100 | + !item.children || | ||
101 | + item.children.length === 0; | ||
102 | + | ||
103 | + return ( | ||
104 | + <BreadcrumbItem | ||
105 | + key={item.path} | ||
106 | + isLink={isLink} | ||
107 | + onClick={handleItemClick.bind(null, item)} | ||
108 | + > | ||
109 | + {() => renderItemContent(item as AppRouteRecordRaw)} | ||
110 | + </BreadcrumbItem> | ||
111 | + ); | ||
112 | + }); | ||
113 | + } | ||
114 | + | ||
115 | + function renderBreadcrumbDefault() { | ||
116 | + return ( | ||
117 | + <TransitionGroup name="breadcrumb">{() => renderBreadcrumbItemList()}</TransitionGroup> | ||
118 | + ); | ||
119 | + } | ||
120 | + | ||
77 | return () => ( | 121 | return () => ( |
78 | <Breadcrumb class={['layout-breadcrumb', unref(itemList).length === 0 ? 'hidden' : '']}> | 122 | <Breadcrumb class={['layout-breadcrumb', unref(itemList).length === 0 ? 'hidden' : '']}> |
79 | - {() => ( | ||
80 | - <TransitionGroup name="breadcrumb"> | ||
81 | - {() => { | ||
82 | - return unref(itemList).map((item) => { | ||
83 | - const isLink = | ||
84 | - (!!item.redirect && !item.meta.disabledRedirect) || | ||
85 | - !item.children || | ||
86 | - item.children.length === 0; | ||
87 | - return ( | ||
88 | - <BreadcrumbItem | ||
89 | - key={item.path} | ||
90 | - isLink={isLink} | ||
91 | - onClick={handleItemClick.bind(null, item)} | ||
92 | - > | ||
93 | - {() => ( | ||
94 | - <> | ||
95 | - {props.showIcon && item.meta.icon && item.meta.icon.trim() !== '' && ( | ||
96 | - <Icon | ||
97 | - icon={item.meta.icon} | ||
98 | - class="icon mr-1 " | ||
99 | - style={{ | ||
100 | - marginBottom: '2px', | ||
101 | - }} | ||
102 | - /> | ||
103 | - )} | ||
104 | - {item.meta.title} | ||
105 | - </> | ||
106 | - )} | ||
107 | - </BreadcrumbItem> | ||
108 | - ); | ||
109 | - }); | ||
110 | - }} | ||
111 | - </TransitionGroup> | ||
112 | - )} | 123 | + {() => renderBreadcrumbDefault()} |
113 | </Breadcrumb> | 124 | </Breadcrumb> |
114 | ); | 125 | ); |
115 | }, | 126 | }, |
src/layouts/default/header/LayoutHeader.tsx
1 | +import './index.less'; | ||
2 | + | ||
1 | import { defineComponent, unref, computed, ref } from 'vue'; | 3 | import { defineComponent, unref, computed, ref } from 'vue'; |
2 | 4 | ||
3 | import { Layout, Tooltip, Badge } from 'ant-design-vue'; | 5 | import { Layout, Tooltip, Badge } from 'ant-design-vue'; |
4 | -import Logo from '/@/layouts/logo/index.vue'; | 6 | +import { AppLogo } from '/@/components/Application'; |
5 | import UserDropdown from './UserDropdown'; | 7 | import UserDropdown from './UserDropdown'; |
6 | import LayoutMenu from '/@/layouts/default/menu/LayoutMenu'; | 8 | import LayoutMenu from '/@/layouts/default/menu/LayoutMenu'; |
7 | import LayoutBreadcrumb from './LayoutBreadcrumb'; | 9 | import LayoutBreadcrumb from './LayoutBreadcrumb'; |
@@ -12,50 +14,57 @@ import { | @@ -12,50 +14,57 @@ import { | ||
12 | RedoOutlined, | 14 | RedoOutlined, |
13 | FullscreenExitOutlined, | 15 | FullscreenExitOutlined, |
14 | FullscreenOutlined, | 16 | FullscreenOutlined, |
15 | - GithubFilled, | ||
16 | LockOutlined, | 17 | LockOutlined, |
17 | BugOutlined, | 18 | BugOutlined, |
18 | } from '@ant-design/icons-vue'; | 19 | } from '@ant-design/icons-vue'; |
20 | +import { useModal } from '/@/components/Modal'; | ||
19 | 21 | ||
20 | import { useFullscreen } from '/@/hooks/web/useFullScreen'; | 22 | import { useFullscreen } from '/@/hooks/web/useFullScreen'; |
21 | import { useTabs } from '/@/hooks/web/useTabs'; | 23 | import { useTabs } from '/@/hooks/web/useTabs'; |
22 | import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; | 24 | import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; |
25 | +import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; | ||
26 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
27 | +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
28 | + | ||
23 | import { useRouter } from 'vue-router'; | 29 | import { useRouter } from 'vue-router'; |
24 | -import { useModal } from '/@/components/Modal'; | ||
25 | 30 | ||
26 | -import { appStore } from '/@/store/modules/app'; | ||
27 | import { errorStore } from '/@/store/modules/error'; | 31 | import { errorStore } from '/@/store/modules/error'; |
28 | 32 | ||
29 | -import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'; | ||
30 | -import { GITHUB_URL } from '/@/settings/siteSetting'; | 33 | +import { PageEnum } from '/@/enums/pageEnum'; |
34 | +import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; | ||
35 | +import { Component } from '/@/components/types'; | ||
31 | 36 | ||
32 | -import './index.less'; | ||
33 | export default defineComponent({ | 37 | export default defineComponent({ |
34 | - name: 'DefaultLayoutHeader', | 38 | + name: 'LayoutHeader', |
35 | setup() { | 39 | setup() { |
36 | - const widthRef = ref(200); | ||
37 | let logoEl: Element | null; | 40 | let logoEl: Element | null; |
38 | 41 | ||
42 | + const widthRef = ref(200); | ||
43 | + | ||
39 | const { refreshPage } = useTabs(); | 44 | const { refreshPage } = useTabs(); |
45 | + | ||
46 | + const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting(); | ||
47 | + | ||
48 | + const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting(); | ||
49 | + | ||
50 | + const { | ||
51 | + getTheme, | ||
52 | + getShowRedo, | ||
53 | + getUseLockPage, | ||
54 | + getShowFullScreen, | ||
55 | + getShowNotice, | ||
56 | + getShowContent, | ||
57 | + getShowBread, | ||
58 | + getShowHeaderLogo, | ||
59 | + } = useHeaderSetting(); | ||
60 | + | ||
40 | const { push } = useRouter(); | 61 | const { push } = useRouter(); |
41 | const [register, { openModal }] = useModal(); | 62 | const [register, { openModal }] = useModal(); |
42 | const { toggleFullscreen, isFullscreenRef } = useFullscreen(); | 63 | const { toggleFullscreen, isFullscreenRef } = useFullscreen(); |
43 | 64 | ||
44 | - const getProjectConfigRef = computed(() => { | ||
45 | - return appStore.getProjectConfig; | ||
46 | - }); | ||
47 | - | ||
48 | - const showTopMenu = computed(() => { | ||
49 | - const getProjectConfig = unref(getProjectConfigRef); | ||
50 | - const { | ||
51 | - menuSetting: { mode, split: splitMenu }, | ||
52 | - } = getProjectConfig; | ||
53 | - return mode === MenuModeEnum.HORIZONTAL || splitMenu; | ||
54 | - }); | ||
55 | - | ||
56 | useWindowSizeFn( | 65 | useWindowSizeFn( |
57 | () => { | 66 | () => { |
58 | - if (!unref(showTopMenu)) return; | 67 | + if (!unref(getShowTopMenu)) return; |
59 | let width = 0; | 68 | let width = 0; |
60 | if (!logoEl) { | 69 | if (!logoEl) { |
61 | logoEl = document.querySelector('.layout-header__logo'); | 70 | logoEl = document.querySelector('.layout-header__logo'); |
@@ -69,24 +78,23 @@ export default defineComponent({ | @@ -69,24 +78,23 @@ export default defineComponent({ | ||
69 | { immediate: true } | 78 | { immediate: true } |
70 | ); | 79 | ); |
71 | 80 | ||
72 | - function goToGithub() { | ||
73 | - window.open(GITHUB_URL, '__blank'); | ||
74 | - } | ||
75 | - | ||
76 | const headerClass = computed(() => { | 81 | const headerClass = computed(() => { |
77 | - const theme = unref(getProjectConfigRef).headerSetting.theme; | 82 | + const theme = unref(getTheme); |
78 | return theme ? `layout-header__header--${theme}` : ''; | 83 | return theme ? `layout-header__header--${theme}` : ''; |
79 | }); | 84 | }); |
80 | 85 | ||
81 | - const showHeaderTrigger = computed(() => { | ||
82 | - const { show, trigger, hidden, type } = unref(getProjectConfigRef).menuSetting; | ||
83 | - if (type === MenuTypeEnum.TOP_MENU || !show || !hidden) return false; | ||
84 | - return trigger === TriggerEnum.HEADER; | 86 | + const getSplitType = computed(() => { |
87 | + return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE; | ||
88 | + }); | ||
89 | + | ||
90 | + const getMenuMode = computed(() => { | ||
91 | + return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null; | ||
85 | }); | 92 | }); |
86 | 93 | ||
87 | function handleToErrorList() { | 94 | function handleToErrorList() { |
88 | - errorStore.commitErrorListCountState(0); | ||
89 | - push('/exception/error-log'); | 95 | + push(PageEnum.ERROR_LOG_PAGE).then(() => { |
96 | + errorStore.commitErrorListCountState(0); | ||
97 | + }); | ||
90 | } | 98 | } |
91 | 99 | ||
92 | /** | 100 | /** |
@@ -96,162 +104,129 @@ export default defineComponent({ | @@ -96,162 +104,129 @@ export default defineComponent({ | ||
96 | openModal(true); | 104 | openModal(true); |
97 | } | 105 | } |
98 | 106 | ||
99 | - return () => { | ||
100 | - const getProjectConfig = unref(getProjectConfigRef); | ||
101 | - const { | ||
102 | - useErrorHandle, | ||
103 | - showLogo, | ||
104 | - multiTabsSetting: { show: showTab }, | ||
105 | - headerSetting: { | ||
106 | - theme: headerTheme, | ||
107 | - useLockPage, | ||
108 | - showRedo, | ||
109 | - showGithub, | ||
110 | - showFullScreen, | ||
111 | - showNotice, | ||
112 | - }, | ||
113 | - menuSetting: { mode, type: menuType, split: splitMenu, topMenuAlign }, | ||
114 | - showBreadCrumb, | ||
115 | - showBreadCrumbIcon, | ||
116 | - } = getProjectConfig; | 107 | + function renderHeaderContent() { |
108 | + const width = unref(widthRef); | ||
109 | + return ( | ||
110 | + <div class="layout-header__content "> | ||
111 | + {unref(getShowHeaderLogo) && ( | ||
112 | + <AppLogo class={`layout-header__logo`} theme={unref(getTheme)} /> | ||
113 | + )} | ||
117 | 114 | ||
118 | - const isSidebarType = menuType === MenuTypeEnum.SIDEBAR; | 115 | + {unref(getShowContent) && ( |
116 | + <div class="layout-header__left"> | ||
117 | + {unref(getShowHeaderTrigger) && ( | ||
118 | + <LayoutTrigger theme={unref(getTheme)} sider={false} /> | ||
119 | + )} | ||
120 | + {unref(getShowBread) && <LayoutBreadcrumb showIcon={unref(getShowBreadCrumbIcon)} />} | ||
121 | + </div> | ||
122 | + )} | ||
119 | 123 | ||
120 | - const width = unref(widthRef); | 124 | + {unref(getShowTopMenu) && ( |
125 | + <div class={[`layout-header__menu `]} style={{ width: `calc(100% - ${width}px)` }}> | ||
126 | + <LayoutMenu | ||
127 | + isHorizontal={true} | ||
128 | + class={`justify-${unref(getTopMenuAlign)}`} | ||
129 | + theme={unref(getTheme)} | ||
130 | + splitType={unref(getSplitType)} | ||
131 | + menuMode={unref(getMenuMode)} | ||
132 | + showSearch={false} | ||
133 | + /> | ||
134 | + </div> | ||
135 | + )} | ||
136 | + </div> | ||
137 | + ); | ||
138 | + } | ||
121 | 139 | ||
122 | - const showLeft = | ||
123 | - (mode !== MenuModeEnum.HORIZONTAL && showBreadCrumb && !splitMenu) || | ||
124 | - unref(showHeaderTrigger); | 140 | + function renderActionDefault(Comp: Component | any, event: Fn) { |
125 | return ( | 141 | return ( |
126 | - <Layout.Header class={['layout-header', 'flex p-0 px-4 ', unref(headerClass)]}> | ||
127 | - {() => ( | ||
128 | - <> | ||
129 | - <div class="layout-header__content "> | ||
130 | - {showLogo && !isSidebarType && ( | ||
131 | - <Logo class={`layout-header__logo`} theme={headerTheme} /> | ||
132 | - )} | ||
133 | - | ||
134 | - {showLeft && ( | ||
135 | - <div class="layout-header__left"> | ||
136 | - {unref(showHeaderTrigger) && ( | ||
137 | - <LayoutTrigger theme={headerTheme} sider={false} /> | ||
138 | - )} | ||
139 | - {mode !== MenuModeEnum.HORIZONTAL && showBreadCrumb && !splitMenu && ( | ||
140 | - <LayoutBreadcrumb showIcon={showBreadCrumbIcon} /> | ||
141 | - )} | ||
142 | - </div> | ||
143 | - )} | 142 | + <div class={`layout-header__action-item`} onClick={event}> |
143 | + <Comp class={`layout-header__action-icon`} /> | ||
144 | + </div> | ||
145 | + ); | ||
146 | + } | ||
144 | 147 | ||
145 | - {unref(showTopMenu) && ( | ||
146 | - <div | ||
147 | - class={[`layout-header__menu `]} | ||
148 | - style={{ width: `calc(100% - ${unref(width)}px)` }} | 148 | + function renderAction() { |
149 | + return ( | ||
150 | + <div class={`layout-header__action`}> | ||
151 | + {unref(getUseErrorHandle) && ( | ||
152 | + <Tooltip> | ||
153 | + {{ | ||
154 | + title: () => '错误日志', | ||
155 | + default: () => ( | ||
156 | + <Badge | ||
157 | + count={errorStore.getErrorListCountState} | ||
158 | + offset={[0, 10]} | ||
159 | + dot | ||
160 | + overflowCount={99} | ||
149 | > | 161 | > |
150 | - <LayoutMenu | ||
151 | - isTop={true} | ||
152 | - class={`justify-${topMenuAlign}`} | ||
153 | - theme={headerTheme} | ||
154 | - splitType={splitMenu ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE} | ||
155 | - menuMode={splitMenu ? MenuModeEnum.HORIZONTAL : null} | ||
156 | - showSearch={false} | ||
157 | - /> | ||
158 | - </div> | ||
159 | - )} | ||
160 | - </div> | 162 | + {() => renderActionDefault(BugOutlined, handleToErrorList)} |
163 | + </Badge> | ||
164 | + ), | ||
165 | + }} | ||
166 | + </Tooltip> | ||
167 | + )} | ||
161 | 168 | ||
162 | - <div class={`layout-header__action`}> | ||
163 | - {useErrorHandle && ( | ||
164 | - <Tooltip> | ||
165 | - {{ | ||
166 | - title: () => '错误日志', | ||
167 | - default: () => ( | ||
168 | - <Badge | ||
169 | - count={errorStore.getErrorListCountState} | ||
170 | - offset={[0, 10]} | ||
171 | - dot | ||
172 | - overflowCount={99} | ||
173 | - > | ||
174 | - {() => ( | ||
175 | - <div class={`layout-header__action-item`} onClick={handleToErrorList}> | ||
176 | - <BugOutlined class={`layout-header__action-icon`} /> | ||
177 | - </div> | ||
178 | - )} | ||
179 | - </Badge> | ||
180 | - ), | ||
181 | - }} | ||
182 | - </Tooltip> | ||
183 | - )} | 169 | + {unref(getUseLockPage) && ( |
170 | + <Tooltip> | ||
171 | + {{ | ||
172 | + title: () => '锁定屏幕', | ||
173 | + default: () => renderActionDefault(LockOutlined, handleLockPage), | ||
174 | + }} | ||
175 | + </Tooltip> | ||
176 | + )} | ||
177 | + | ||
178 | + {unref(getShowNotice) && ( | ||
179 | + <Tooltip> | ||
180 | + {{ | ||
181 | + title: () => '消息通知', | ||
182 | + default: () => <NoticeAction />, | ||
183 | + }} | ||
184 | + </Tooltip> | ||
185 | + )} | ||
184 | 186 | ||
185 | - {showGithub && ( | ||
186 | - <Tooltip> | ||
187 | - {{ | ||
188 | - title: () => 'github', | ||
189 | - default: () => ( | ||
190 | - <div class={`layout-header__action-item`} onClick={goToGithub}> | ||
191 | - <GithubFilled class={`layout-header__action-icon`} /> | ||
192 | - </div> | ||
193 | - ), | ||
194 | - }} | ||
195 | - </Tooltip> | ||
196 | - )} | ||
197 | - {useLockPage && ( | ||
198 | - <Tooltip> | ||
199 | - {{ | ||
200 | - title: () => '锁定屏幕', | ||
201 | - default: () => ( | ||
202 | - <div class={`layout-header__action-item`} onClick={handleLockPage}> | ||
203 | - <LockOutlined class={`layout-header__action-icon`} /> | ||
204 | - </div> | ||
205 | - ), | ||
206 | - }} | ||
207 | - </Tooltip> | ||
208 | - )} | ||
209 | - {showNotice && ( | ||
210 | - <div> | ||
211 | - <Tooltip> | ||
212 | - {{ | ||
213 | - title: () => '消息通知', | ||
214 | - default: () => <NoticeAction />, | ||
215 | - }} | ||
216 | - </Tooltip> | ||
217 | - </div> | ||
218 | - )} | ||
219 | - {showRedo && showTab && ( | ||
220 | - <Tooltip> | ||
221 | - {{ | ||
222 | - title: () => '刷新', | ||
223 | - default: () => ( | ||
224 | - <div class={`layout-header__action-item`} onClick={refreshPage}> | ||
225 | - <RedoOutlined class={`layout-header__action-icon`} /> | ||
226 | - </div> | ||
227 | - ), | ||
228 | - }} | ||
229 | - </Tooltip> | ||
230 | - )} | ||
231 | - {showFullScreen && ( | ||
232 | - <Tooltip> | ||
233 | - {{ | ||
234 | - title: () => (unref(isFullscreenRef) ? '退出全屏' : '全屏'), | ||
235 | - default: () => { | ||
236 | - const Icon: any = !unref(isFullscreenRef) ? ( | ||
237 | - <FullscreenOutlined /> | ||
238 | - ) : ( | ||
239 | - <FullscreenExitOutlined /> | ||
240 | - ); | ||
241 | - return ( | ||
242 | - <div class={`layout-header__action-item`} onClick={toggleFullscreen}> | ||
243 | - <Icon class={`layout-header__action-icon`} /> | ||
244 | - </div> | ||
245 | - ); | ||
246 | - }, | ||
247 | - }} | ||
248 | - </Tooltip> | ||
249 | - )} | ||
250 | - <UserDropdown class={`layout-header__user-dropdown`} /> | ||
251 | - </div> | ||
252 | - <LockAction onRegister={register} /> | ||
253 | - </> | 187 | + {unref(getShowRedo) && ( |
188 | + <Tooltip> | ||
189 | + {{ | ||
190 | + title: () => '刷新', | ||
191 | + default: () => renderActionDefault(RedoOutlined, refreshPage), | ||
192 | + }} | ||
193 | + </Tooltip> | ||
254 | )} | 194 | )} |
195 | + | ||
196 | + {unref(getShowFullScreen) && ( | ||
197 | + <Tooltip> | ||
198 | + {{ | ||
199 | + title: () => (unref(isFullscreenRef) ? '退出全屏' : '全屏'), | ||
200 | + default: () => { | ||
201 | + const Icon = !unref(isFullscreenRef) ? ( | ||
202 | + <FullscreenOutlined /> | ||
203 | + ) : ( | ||
204 | + <FullscreenExitOutlined /> | ||
205 | + ); | ||
206 | + return renderActionDefault(Icon, toggleFullscreen); | ||
207 | + }, | ||
208 | + }} | ||
209 | + </Tooltip> | ||
210 | + )} | ||
211 | + <UserDropdown class={`layout-header__user-dropdown`} /> | ||
212 | + </div> | ||
213 | + ); | ||
214 | + } | ||
215 | + | ||
216 | + function renderHeaderDefault() { | ||
217 | + return ( | ||
218 | + <> | ||
219 | + {renderHeaderContent()} | ||
220 | + {renderAction()} | ||
221 | + <LockAction onRegister={register} /> | ||
222 | + </> | ||
223 | + ); | ||
224 | + } | ||
225 | + | ||
226 | + return () => { | ||
227 | + return ( | ||
228 | + <Layout.Header class={['layout-header', 'flex p-0 px-4 ', unref(headerClass)]}> | ||
229 | + {() => renderHeaderDefault()} | ||
255 | </Layout.Header> | 230 | </Layout.Header> |
256 | ); | 231 | ); |
257 | }; | 232 | }; |
src/layouts/default/header/LockActionItem.less
src/layouts/default/header/LockActionItem.tsx
1 | -// 组件相关 | 1 | +import './LockActionItem.less'; |
2 | + | ||
2 | import { defineComponent } from 'vue'; | 3 | import { defineComponent } from 'vue'; |
3 | import { BasicModal, useModalInner } from '/@/components/Modal/index'; | 4 | import { BasicModal, useModalInner } from '/@/components/Modal/index'; |
4 | - | ||
5 | -// hook | 5 | +import Button from '/@/components/Button/index.vue'; |
6 | import { BasicForm, useForm } from '/@/components/Form/index'; | 6 | import { BasicForm, useForm } from '/@/components/Form/index'; |
7 | 7 | ||
8 | import headerImg from '/@/assets/images/header.jpg'; | 8 | import headerImg from '/@/assets/images/header.jpg'; |
9 | 9 | ||
10 | import { appStore } from '/@/store/modules/app'; | 10 | import { appStore } from '/@/store/modules/app'; |
11 | import { userStore } from '/@/store/modules/user'; | 11 | import { userStore } from '/@/store/modules/user'; |
12 | -import Button from '/@/components/Button/index.vue'; | ||
13 | -import './LockActionItem.less'; | 12 | + |
14 | const prefixCls = 'lock-modal'; | 13 | const prefixCls = 'lock-modal'; |
15 | export default defineComponent({ | 14 | export default defineComponent({ |
16 | name: 'LockModal', | 15 | name: 'LockModal', |
17 | setup(_, { attrs }) { | 16 | setup(_, { attrs }) { |
18 | - const [register, { setModalProps }] = useModalInner(); | ||
19 | - // 样式前缀 | 17 | + const [register, { closeModal }] = useModalInner(); |
18 | + | ||
20 | const [registerForm, { validateFields, resetFields }] = useForm({ | 19 | const [registerForm, { validateFields, resetFields }] = useForm({ |
21 | - // 隐藏按钮 | ||
22 | showActionButtonGroup: false, | 20 | showActionButtonGroup: false, |
23 | - // 表单项 | ||
24 | schemas: [ | 21 | schemas: [ |
25 | { | 22 | { |
26 | field: 'password', | 23 | field: 'password', |
27 | - label: '', | 24 | + label: '锁屏密码', |
28 | component: 'InputPassword', | 25 | component: 'InputPassword', |
29 | - componentProps: { | ||
30 | - placeholder: '请输入锁屏密码', | ||
31 | - }, | ||
32 | - rules: [{ required: true }], | 26 | + required: true, |
33 | }, | 27 | }, |
34 | ], | 28 | ], |
35 | }); | 29 | }); |
36 | - /** | ||
37 | - * @description: lock | ||
38 | - */ | 30 | + |
39 | async function lock(valid = true) { | 31 | async function lock(valid = true) { |
40 | let password: string | undefined = ''; | 32 | let password: string | undefined = ''; |
41 | 33 | ||
@@ -46,9 +38,7 @@ export default defineComponent({ | @@ -46,9 +38,7 @@ export default defineComponent({ | ||
46 | const values = (await validateFields()) as any; | 38 | const values = (await validateFields()) as any; |
47 | password = values.password; | 39 | password = values.password; |
48 | } | 40 | } |
49 | - setModalProps({ | ||
50 | - visible: false, | ||
51 | - }); | 41 | + closeModal(); |
52 | 42 | ||
53 | appStore.commitLockInfoState({ | 43 | appStore.commitLockInfoState({ |
54 | isLock: true, | 44 | isLock: true, |
@@ -57,7 +47,7 @@ export default defineComponent({ | @@ -57,7 +47,7 @@ export default defineComponent({ | ||
57 | await resetFields(); | 47 | await resetFields(); |
58 | } catch (error) {} | 48 | } catch (error) {} |
59 | } | 49 | } |
60 | - // 账号密码登录 | 50 | + |
61 | return () => ( | 51 | return () => ( |
62 | <BasicModal footer={null} title="锁定屏幕" {...attrs} class={prefixCls} onRegister={register}> | 52 | <BasicModal footer={null} title="锁定屏幕" {...attrs} class={prefixCls} onRegister={register}> |
63 | {() => ( | 53 | {() => ( |
@@ -66,7 +56,9 @@ export default defineComponent({ | @@ -66,7 +56,9 @@ export default defineComponent({ | ||
66 | <img src={headerImg} class={`${prefixCls}__header-img`} /> | 56 | <img src={headerImg} class={`${prefixCls}__header-img`} /> |
67 | <p class={`${prefixCls}__header-name`}>{userStore.getUserInfoState.realName}</p> | 57 | <p class={`${prefixCls}__header-name`}>{userStore.getUserInfoState.realName}</p> |
68 | </div> | 58 | </div> |
69 | - <BasicForm onRegister={registerForm} /> | 59 | + |
60 | + <BasicForm onRegister={registerForm} layout="vertical" /> | ||
61 | + | ||
70 | <div class={`${prefixCls}__footer`}> | 62 | <div class={`${prefixCls}__footer`}> |
71 | <Button type="primary" block class="mt-2" onClick={lock}> | 63 | <Button type="primary" block class="mt-2" onClick={lock}> |
72 | {() => '锁屏'} | 64 | {() => '锁屏'} |
src/layouts/default/header/UserDropdown.tsx
@@ -11,15 +11,23 @@ import Icon from '/@/components/Icon/index'; | @@ -11,15 +11,23 @@ import Icon from '/@/components/Icon/index'; | ||
11 | import { userStore } from '/@/store/modules/user'; | 11 | import { userStore } from '/@/store/modules/user'; |
12 | 12 | ||
13 | import { DOC_URL } from '/@/settings/siteSetting'; | 13 | import { DOC_URL } from '/@/settings/siteSetting'; |
14 | -import { appStore } from '/@/store/modules/app'; | 14 | + |
15 | +import { openWindow } from '/@/utils'; | ||
16 | + | ||
17 | +import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; | ||
18 | + | ||
19 | +interface RenderItemParams { | ||
20 | + icon: string; | ||
21 | + text: string; | ||
22 | + key: string; | ||
23 | +} | ||
15 | 24 | ||
16 | const prefixCls = 'user-dropdown'; | 25 | const prefixCls = 'user-dropdown'; |
26 | + | ||
17 | export default defineComponent({ | 27 | export default defineComponent({ |
18 | name: 'UserDropdown', | 28 | name: 'UserDropdown', |
19 | setup() { | 29 | setup() { |
20 | - const getProjectConfigRef = computed(() => { | ||
21 | - return appStore.getProjectConfig; | ||
22 | - }); | 30 | + const { getShowDoc } = useHeaderSetting(); |
23 | 31 | ||
24 | const getUserInfo = computed(() => { | 32 | const getUserInfo = computed(() => { |
25 | const { realName = '', desc } = userStore.getUserInfoState || {}; | 33 | const { realName = '', desc } = userStore.getUserInfoState || {}; |
@@ -33,7 +41,7 @@ export default defineComponent({ | @@ -33,7 +41,7 @@ export default defineComponent({ | ||
33 | 41 | ||
34 | // open doc | 42 | // open doc |
35 | function openDoc() { | 43 | function openDoc() { |
36 | - window.open(DOC_URL, '__blank'); | 44 | + openWindow(DOC_URL); |
37 | } | 45 | } |
38 | 46 | ||
39 | function handleMenuClick(e: any) { | 47 | function handleMenuClick(e: any) { |
@@ -44,7 +52,7 @@ export default defineComponent({ | @@ -44,7 +52,7 @@ export default defineComponent({ | ||
44 | } | 52 | } |
45 | } | 53 | } |
46 | 54 | ||
47 | - function renderItem({ icon, text, key }: { icon: string; text: string; key: string }) { | 55 | + function renderItem({ icon, text, key }: RenderItemParams) { |
48 | return ( | 56 | return ( |
49 | <Menu.Item key={key}> | 57 | <Menu.Item key={key}> |
50 | {() => ( | 58 | {() => ( |
@@ -57,37 +65,43 @@ export default defineComponent({ | @@ -57,37 +65,43 @@ export default defineComponent({ | ||
57 | ); | 65 | ); |
58 | } | 66 | } |
59 | 67 | ||
60 | - return () => { | 68 | + function renderSlotsDefault() { |
61 | const { realName } = unref(getUserInfo); | 69 | const { realName } = unref(getUserInfo); |
62 | - const { | ||
63 | - headerSetting: { showDoc }, | ||
64 | - } = unref(getProjectConfigRef); | 70 | + return ( |
71 | + <section class={prefixCls}> | ||
72 | + <img class={`${prefixCls}__header`} src={headerImg} /> | ||
73 | + <section class={`${prefixCls}__info`}> | ||
74 | + <section class={`${prefixCls}__name`}>{realName}</section> | ||
75 | + </section> | ||
76 | + </section> | ||
77 | + ); | ||
78 | + } | ||
79 | + | ||
80 | + function renderSlotOverlay() { | ||
81 | + const showDoc = unref(getShowDoc); | ||
82 | + return ( | ||
83 | + <Menu onClick={handleMenuClick}> | ||
84 | + {() => ( | ||
85 | + <> | ||
86 | + {showDoc && renderItem({ key: 'doc', text: '文档', icon: 'gg:loadbar-doc' })} | ||
87 | + {showDoc && <Divider />} | ||
88 | + {renderItem({ | ||
89 | + key: 'loginOut', | ||
90 | + text: '退出系统', | ||
91 | + icon: 'ant-design:poweroff-outlined', | ||
92 | + })} | ||
93 | + </> | ||
94 | + )} | ||
95 | + </Menu> | ||
96 | + ); | ||
97 | + } | ||
98 | + | ||
99 | + return () => { | ||
65 | return ( | 100 | return ( |
66 | <Dropdown placement="bottomLeft"> | 101 | <Dropdown placement="bottomLeft"> |
67 | {{ | 102 | {{ |
68 | - default: () => ( | ||
69 | - <section class={prefixCls}> | ||
70 | - <img class={`${prefixCls}__header`} src={headerImg} /> | ||
71 | - <section class={`${prefixCls}__info`}> | ||
72 | - <section class={`${prefixCls}__name`}>{realName}</section> | ||
73 | - </section> | ||
74 | - </section> | ||
75 | - ), | ||
76 | - overlay: () => ( | ||
77 | - <Menu slot="overlay" onClick={handleMenuClick}> | ||
78 | - {() => ( | ||
79 | - <> | ||
80 | - {showDoc && renderItem({ key: 'doc', text: '文档', icon: 'gg:loadbar-doc' })} | ||
81 | - {showDoc && <Divider />} | ||
82 | - {renderItem({ | ||
83 | - key: 'loginOut', | ||
84 | - text: '退出系统', | ||
85 | - icon: 'ant-design:poweroff-outlined', | ||
86 | - })} | ||
87 | - </> | ||
88 | - )} | ||
89 | - </Menu> | ||
90 | - ), | 103 | + default: () => renderSlotsDefault(), |
104 | + overlay: () => renderSlotOverlay(), | ||
91 | }} | 105 | }} |
92 | </Dropdown> | 106 | </Dropdown> |
93 | ); | 107 | ); |
src/layouts/default/header/notice/NoticeActionItem.vue
1 | <template> | 1 | <template> |
2 | <div class="layout-header__action-item notify-action"> | 2 | <div class="layout-header__action-item notify-action"> |
3 | - <Popover title="" trigger="click"> | 3 | + <Popover title="" trigger="click" overlayClassName="layout-header__notify-action"> |
4 | <Badge :count="count" dot :numberStyle="numberStyle"> | 4 | <Badge :count="count" dot :numberStyle="numberStyle"> |
5 | <BellOutlined class="layout-header__action-icon" /> | 5 | <BellOutlined class="layout-header__action-icon" /> |
6 | </Badge> | 6 | </Badge> |
@@ -31,6 +31,7 @@ | @@ -31,6 +31,7 @@ | ||
31 | components: { Popover, BellOutlined, Tabs, TabPane: Tabs.TabPane, Badge, NoticeList }, | 31 | components: { Popover, BellOutlined, Tabs, TabPane: Tabs.TabPane, Badge, NoticeList }, |
32 | setup() { | 32 | setup() { |
33 | let count = 0; | 33 | let count = 0; |
34 | + | ||
34 | for (let i = 0; i < tabListData.length; i++) { | 35 | for (let i = 0; i < tabListData.length; i++) { |
35 | count += tabListData[i].list.length; | 36 | count += tabListData[i].list.length; |
36 | } | 37 | } |
@@ -44,6 +45,10 @@ | @@ -44,6 +45,10 @@ | ||
44 | }); | 45 | }); |
45 | </script> | 46 | </script> |
46 | <style lang="less"> | 47 | <style lang="less"> |
48 | + .layout-header__notify-action { | ||
49 | + max-width: 360px; | ||
50 | + } | ||
51 | + | ||
47 | .notify-action { | 52 | .notify-action { |
48 | padding-top: 2px; | 53 | padding-top: 2px; |
49 | 54 | ||
@@ -56,7 +61,6 @@ | @@ -56,7 +61,6 @@ | ||
56 | 61 | ||
57 | .ant-badge-multiple-words { | 62 | .ant-badge-multiple-words { |
58 | padding: 0 4px; | 63 | padding: 0 4px; |
59 | - // transform: translate(26%, -40%); | ||
60 | } | 64 | } |
61 | 65 | ||
62 | svg { | 66 | svg { |
src/layouts/default/header/notice/NoticeList.vue
1 | <template> | 1 | <template> |
2 | - <List class="list"> | 2 | + <a-list class="list"> |
3 | <template v-for="item in list" :key="item.id"> | 3 | <template v-for="item in list" :key="item.id"> |
4 | - <ListItem class="list__item"> | ||
5 | - <ListItemMeta> | 4 | + <a-list-item class="list-item"> |
5 | + <a-list-item-meta> | ||
6 | <template #title> | 6 | <template #title> |
7 | <div class="title"> | 7 | <div class="title"> |
8 | {{ item.title }} | 8 | {{ item.title }} |
9 | <div class="extra" v-if="item.extra"> | 9 | <div class="extra" v-if="item.extra"> |
10 | - <Tag class="tag" :color="item.color"> | 10 | + <a-tag class="tag" :color="item.color"> |
11 | {{ item.extra }} | 11 | {{ item.extra }} |
12 | - </Tag> | 12 | + </a-tag> |
13 | </div> | 13 | </div> |
14 | </div> | 14 | </div> |
15 | </template> | 15 | </template> |
16 | + | ||
16 | <template #avatar> | 17 | <template #avatar> |
17 | - <Avatar v-if="item.avatar" class="avatar" :src="item.avatar" /> | 18 | + <a-avatar v-if="item.avatar" class="avatar" :src="item.avatar" /> |
18 | <span v-else> {{ item.avatar }}</span> | 19 | <span v-else> {{ item.avatar }}</span> |
19 | </template> | 20 | </template> |
21 | + | ||
20 | <template #description> | 22 | <template #description> |
21 | <div> | 23 | <div> |
22 | <div class="description">{{ item.description }}</div> | 24 | <div class="description">{{ item.description }}</div> |
23 | <div class="datetime">{{ item.datetime }}</div> | 25 | <div class="datetime">{{ item.datetime }}</div> |
24 | </div> | 26 | </div> |
25 | </template> | 27 | </template> |
26 | - </ListItemMeta> | ||
27 | - </ListItem> | 28 | + </a-list-item-meta> |
29 | + </a-list-item> | ||
28 | </template> | 30 | </template> |
29 | - </List> | 31 | + </a-list> |
30 | </template> | 32 | </template> |
31 | <script lang="ts"> | 33 | <script lang="ts"> |
32 | import { defineComponent, PropType } from 'vue'; | 34 | import { defineComponent, PropType } from 'vue'; |
33 | - import { List, Avatar, Tag } from 'ant-design-vue'; | ||
34 | import { ListItem } from './data'; | 35 | import { ListItem } from './data'; |
35 | 36 | ||
36 | export default defineComponent({ | 37 | export default defineComponent({ |
@@ -40,19 +41,6 @@ | @@ -40,19 +41,6 @@ | ||
40 | default: () => [], | 41 | default: () => [], |
41 | }, | 42 | }, |
42 | }, | 43 | }, |
43 | - components: { | ||
44 | - List, | ||
45 | - ListItem: List.Item, | ||
46 | - ListItemMeta: List.Item.Meta, | ||
47 | - Avatar, | ||
48 | - Tag, | ||
49 | - }, | ||
50 | - setup(props) { | ||
51 | - const { list = [] } = props; | ||
52 | - return { | ||
53 | - list, | ||
54 | - }; | ||
55 | - }, | ||
56 | }); | 44 | }); |
57 | </script> | 45 | </script> |
58 | <style lang="less" scoped> | 46 | <style lang="less" scoped> |
@@ -61,7 +49,7 @@ | @@ -61,7 +49,7 @@ | ||
61 | display: none; | 49 | display: none; |
62 | } | 50 | } |
63 | 51 | ||
64 | - &__item { | 52 | + &-item { |
65 | padding: 6px; | 53 | padding: 6px; |
66 | overflow: hidden; | 54 | overflow: hidden; |
67 | cursor: pointer; | 55 | cursor: pointer; |
src/layouts/default/header/notice/data.ts
@@ -56,14 +56,6 @@ export const tabListData: TabItem[] = [ | @@ -56,14 +56,6 @@ export const tabListData: TabItem[] = [ | ||
56 | datetime: '2017-08-07', | 56 | datetime: '2017-08-07', |
57 | type: '1', | 57 | type: '1', |
58 | }, | 58 | }, |
59 | - // { | ||
60 | - // id: '000000005', | ||
61 | - // avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', | ||
62 | - // title: '内容不要超过两行字,超出时自动截断', | ||
63 | - // description: '', | ||
64 | - // datetime: '2017-08-07', | ||
65 | - // type: '1', | ||
66 | - // }, | ||
67 | ], | 59 | ], |
68 | }, | 60 | }, |
69 | { | 61 | { |
src/layouts/default/index.less
@@ -36,47 +36,4 @@ | @@ -36,47 +36,4 @@ | ||
36 | margin: 0 auto; | 36 | margin: 0 auto; |
37 | } | 37 | } |
38 | } | 38 | } |
39 | - | ||
40 | - .layout-sidebar { | ||
41 | - background-size: 100% 100%; | ||
42 | - | ||
43 | - &.ant-layout-sider-dark { | ||
44 | - background: @sider-dark-bg-color; | ||
45 | - } | ||
46 | - | ||
47 | - &:not(.ant-layout-sider-dark) { | ||
48 | - border-right: 1px solid @border-color-light; | ||
49 | - } | ||
50 | - | ||
51 | - .ant-layout-sider-zero-width-trigger { | ||
52 | - top: 40%; | ||
53 | - z-index: 10; | ||
54 | - } | ||
55 | - | ||
56 | - &__dargbar { | ||
57 | - position: absolute; | ||
58 | - top: 0; | ||
59 | - right: -2px; | ||
60 | - z-index: @side-drag-z-index; | ||
61 | - width: 2px; | ||
62 | - height: 100%; | ||
63 | - cursor: col-resize; | ||
64 | - border-top: none; | ||
65 | - border-bottom: none; | ||
66 | - | ||
67 | - &.hide { | ||
68 | - display: none; | ||
69 | - } | ||
70 | - | ||
71 | - &:hover { | ||
72 | - background: @primary-color; | ||
73 | - box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15); | ||
74 | - } | ||
75 | - } | ||
76 | - } | ||
77 | -} | ||
78 | - | ||
79 | -.ant-layout-sider-trigger { | ||
80 | - height: 36px; | ||
81 | - line-height: 36px; | ||
82 | } | 39 | } |
src/layouts/default/index.tsx
@@ -4,7 +4,7 @@ import LayoutHeader from './header/LayoutHeader'; | @@ -4,7 +4,7 @@ import LayoutHeader from './header/LayoutHeader'; | ||
4 | 4 | ||
5 | import { appStore } from '/@/store/modules/app'; | 5 | import { appStore } from '/@/store/modules/app'; |
6 | import LayoutContent from './LayoutContent'; | 6 | import LayoutContent from './LayoutContent'; |
7 | -import LayoutSideBar from './LayoutSideBar'; | 7 | +import LayoutSideBar from './sider/LayoutSideBar'; |
8 | import SettingBtn from './setting/index.vue'; | 8 | import SettingBtn from './setting/index.vue'; |
9 | import MultipleTabs from './multitabs/index'; | 9 | import MultipleTabs from './multitabs/index'; |
10 | 10 | ||
@@ -36,7 +36,7 @@ export default defineComponent({ | @@ -36,7 +36,7 @@ export default defineComponent({ | ||
36 | return show; | 36 | return show; |
37 | }); | 37 | }); |
38 | 38 | ||
39 | - const isShowMixHeaderRef = computed(() => { | 39 | + const showMixHeaderRef = computed(() => { |
40 | const { | 40 | const { |
41 | menuSetting: { type }, | 41 | menuSetting: { type }, |
42 | } = unref(getProjectConfigRef); | 42 | } = unref(getProjectConfigRef); |
@@ -57,11 +57,11 @@ export default defineComponent({ | @@ -57,11 +57,11 @@ export default defineComponent({ | ||
57 | }); | 57 | }); |
58 | 58 | ||
59 | const showFullHeaderRef = computed(() => { | 59 | const showFullHeaderRef = computed(() => { |
60 | - return !unref(getFullContent) && unref(isShowMixHeaderRef) && unref(showHeaderRef); | 60 | + return !unref(getFullContent) && unref(showMixHeaderRef) && unref(showHeaderRef); |
61 | }); | 61 | }); |
62 | 62 | ||
63 | const showInsetHeaderRef = computed(() => { | 63 | const showInsetHeaderRef = computed(() => { |
64 | - return !unref(getFullContent) && !unref(isShowMixHeaderRef) && unref(showHeaderRef); | 64 | + return !unref(getFullContent) && !unref(showMixHeaderRef) && unref(showHeaderRef); |
65 | }); | 65 | }); |
66 | 66 | ||
67 | const fixedHeaderClsRef = computed(() => { | 67 | const fixedHeaderClsRef = computed(() => { |
src/layouts/default/menu/LayoutMenu.tsx
1 | -import type { PropType } from 'vue'; | 1 | +import './index.less'; |
2 | + | ||
3 | +import { PropType, toRef } from 'vue'; | ||
2 | import type { Menu } from '/@/router/types'; | 4 | import type { Menu } from '/@/router/types'; |
3 | 5 | ||
4 | -import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue'; | 6 | +import { computed, defineComponent, unref } from 'vue'; |
5 | import { BasicMenu } from '/@/components/Menu/index'; | 7 | import { BasicMenu } from '/@/components/Menu/index'; |
6 | -import Logo from '/@/layouts/logo/index.vue'; | ||
7 | - | ||
8 | -import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; | ||
9 | - | ||
10 | -// store | ||
11 | -import { appStore } from '/@/store/modules/app'; | ||
12 | -import { menuStore } from '/@/store/modules/menu'; | ||
13 | - | ||
14 | -import { | ||
15 | - getMenus, | ||
16 | - getFlatMenus, | ||
17 | - getShallowMenus, | ||
18 | - getChildrenMenus, | ||
19 | - getFlatChildrenMenus, | ||
20 | - getCurrentParentPath, | ||
21 | -} from '/@/router/menus/index'; | ||
22 | -import { useRouter } from 'vue-router'; | ||
23 | -import { useThrottle } from '/@/hooks/core/useThrottle'; | ||
24 | -import { permissionStore } from '/@/store/modules/permission'; | 8 | +import { AppLogo } from '/@/components/Application'; |
9 | + | ||
10 | +import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; | ||
11 | + | ||
12 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
13 | +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
14 | + | ||
15 | +import { useGo } from '/@/hooks/web/usePage'; | ||
16 | +import { useSplitMenu } from './useLayoutMenu'; | ||
17 | +import { openWindow } from '/@/utils'; | ||
25 | 18 | ||
26 | -import './index.less'; | ||
27 | export default defineComponent({ | 19 | export default defineComponent({ |
28 | name: 'DefaultLayoutMenu', | 20 | name: 'DefaultLayoutMenu', |
29 | props: { | 21 | props: { |
@@ -43,7 +35,7 @@ export default defineComponent({ | @@ -43,7 +35,7 @@ export default defineComponent({ | ||
43 | type: Boolean as PropType<boolean>, | 35 | type: Boolean as PropType<boolean>, |
44 | default: true, | 36 | default: true, |
45 | }, | 37 | }, |
46 | - isTop: { | 38 | + isHorizontal: { |
47 | type: Boolean as PropType<boolean>, | 39 | type: Boolean as PropType<boolean>, |
48 | default: false, | 40 | default: false, |
49 | }, | 41 | }, |
@@ -53,190 +45,99 @@ export default defineComponent({ | @@ -53,190 +45,99 @@ export default defineComponent({ | ||
53 | }, | 45 | }, |
54 | }, | 46 | }, |
55 | setup(props) { | 47 | setup(props) { |
56 | - // Menu array | ||
57 | - const menusRef = ref<Menu[]>([]); | ||
58 | - // flat menu array | ||
59 | - const flatMenusRef = ref<Menu[]>([]); | ||
60 | - const { currentRoute, push } = useRouter(); | ||
61 | - | ||
62 | - // get app config | ||
63 | - const getProjectConfigRef = computed(() => { | ||
64 | - return appStore.getProjectConfig; | ||
65 | - }); | 48 | + const go = useGo(); |
66 | 49 | ||
67 | - // get is Horizontal | ||
68 | - const getIsHorizontalRef = computed(() => { | ||
69 | - return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL; | ||
70 | - }); | 50 | + const { |
51 | + setMenuSetting, | ||
52 | + getShowSearch, | ||
53 | + getMode, | ||
54 | + getType, | ||
55 | + getCollapsedShowTitle, | ||
56 | + getCollapsedShowSearch, | ||
57 | + getIsSidebarType, | ||
58 | + getTheme, | ||
59 | + getCollapsed, | ||
60 | + getAccordion, | ||
61 | + } = useMenuSetting(); | ||
71 | 62 | ||
72 | - const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50); | ||
73 | - | ||
74 | - // Route change split menu | ||
75 | - watch( | ||
76 | - [() => unref(currentRoute).path, () => props.splitType], | ||
77 | - async ([path, splitType]: [string, MenuSplitTyeEnum]) => { | ||
78 | - if (splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return; | ||
79 | - const parentPath = await getCurrentParentPath(path); | ||
80 | - parentPath && throttleHandleSplitLeftMenu(parentPath); | ||
81 | - }, | ||
82 | - { | ||
83 | - immediate: true, | ||
84 | - } | ||
85 | - ); | 63 | + const { getShowLogo } = useRootSetting(); |
86 | 64 | ||
87 | - // Menu changes | ||
88 | - watch( | ||
89 | - [() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState], | ||
90 | - () => { | ||
91 | - genMenus(); | ||
92 | - } | ||
93 | - ); | ||
94 | - | ||
95 | - // split Menu changes | ||
96 | - watch([() => appStore.getProjectConfig.menuSetting.split], () => { | ||
97 | - if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return; | ||
98 | - genMenus(); | ||
99 | - }); | 65 | + const { flatMenusRef, menusRef } = useSplitMenu(toRef(props, 'splitType')); |
100 | 66 | ||
101 | - // Handle left menu split | ||
102 | - async function handleSplitLeftMenu(parentPath: string) { | ||
103 | - const isSplitMenu = unref(getProjectConfigRef).menuSetting.split; | ||
104 | - if (!isSplitMenu) return; | ||
105 | - const { splitType } = props; | ||
106 | - // spilt mode left | ||
107 | - if (splitType === MenuSplitTyeEnum.LEFT) { | ||
108 | - const children = await getChildrenMenus(parentPath); | ||
109 | - if (!children) { | ||
110 | - appStore.commitProjectConfigState({ | ||
111 | - menuSetting: { | ||
112 | - hidden: false, | ||
113 | - }, | ||
114 | - }); | ||
115 | - flatMenusRef.value = []; | ||
116 | - menusRef.value = []; | ||
117 | - return; | ||
118 | - } | ||
119 | - const flatChildren = await getFlatChildrenMenus(children); | ||
120 | - appStore.commitProjectConfigState({ | ||
121 | - menuSetting: { | ||
122 | - hidden: true, | ||
123 | - }, | ||
124 | - }); | ||
125 | - flatMenusRef.value = flatChildren; | ||
126 | - menusRef.value = children; | ||
127 | - } | ||
128 | - } | 67 | + const showLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType)); |
129 | 68 | ||
130 | - // get menus | ||
131 | - async function genMenus() { | ||
132 | - const isSplitMenu = unref(getProjectConfigRef).menuSetting.split; | 69 | + const getMenuMode = computed(() => props.menuMode || unref(getMode)); |
133 | 70 | ||
134 | - // normal mode | ||
135 | - const { splitType } = props; | ||
136 | - if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) { | ||
137 | - flatMenusRef.value = await getFlatMenus(); | ||
138 | - menusRef.value = await getMenus(); | ||
139 | - return; | ||
140 | - } | 71 | + const getMenuTheme = computed(() => props.theme || unref(getTheme)); |
141 | 72 | ||
142 | - // split-top | ||
143 | - if (splitType === MenuSplitTyeEnum.TOP) { | ||
144 | - const parentPath = await getCurrentParentPath(unref(currentRoute).path); | ||
145 | - menuStore.commitCurrentTopSplitMenuPathState(parentPath); | ||
146 | - const shallowMenus = await getShallowMenus(); | 73 | + const appendClass = computed(() => props.splitType === MenuSplitTyeEnum.TOP); |
147 | 74 | ||
148 | - flatMenusRef.value = shallowMenus; | ||
149 | - menusRef.value = shallowMenus; | ||
150 | - return; | ||
151 | - } | ||
152 | - } | 75 | + const showSearch = computed(() => { |
76 | + return ( | ||
77 | + unref(getShowSearch) && | ||
78 | + props.showSearch && | ||
79 | + (unref(getCollapsedShowSearch) ? true : !unref(getCollapsed)) | ||
80 | + ); | ||
81 | + }); | ||
153 | 82 | ||
83 | + /** | ||
84 | + * click menu | ||
85 | + * @param menu | ||
86 | + */ | ||
154 | function handleMenuClick(menu: Menu) { | 87 | function handleMenuClick(menu: Menu) { |
155 | - const { path } = menu; | ||
156 | - if (path) { | ||
157 | - push(path); | ||
158 | - const { splitType } = props; | ||
159 | - // split mode top | ||
160 | - if (splitType === MenuSplitTyeEnum.TOP) { | ||
161 | - menuStore.commitCurrentTopSplitMenuPathState(path); | ||
162 | - } | ||
163 | - } | 88 | + go(menu.path); |
164 | } | 89 | } |
165 | 90 | ||
91 | + /** | ||
92 | + * before click menu | ||
93 | + * @param menu | ||
94 | + */ | ||
166 | async function beforeMenuClickFn(menu: Menu) { | 95 | async function beforeMenuClickFn(menu: Menu) { |
167 | const { meta: { externalLink } = {} } = menu; | 96 | const { meta: { externalLink } = {} } = menu; |
168 | 97 | ||
169 | if (externalLink) { | 98 | if (externalLink) { |
170 | - window.open(externalLink, '_blank'); | 99 | + openWindow(externalLink); |
171 | return false; | 100 | return false; |
172 | } | 101 | } |
173 | - | ||
174 | return true; | 102 | return true; |
175 | } | 103 | } |
176 | 104 | ||
177 | function handleClickSearchInput() { | 105 | function handleClickSearchInput() { |
178 | - if (menuStore.getCollapsedState) { | ||
179 | - menuStore.commitCollapsedState(false); | ||
180 | - } | 106 | + unref(getCollapsed) && setMenuSetting({ collapsed: false }); |
181 | } | 107 | } |
182 | 108 | ||
183 | - const showSearchRef = computed(() => { | ||
184 | - const { showSearch, type, mode } = unref(getProjectConfigRef).menuSetting; | 109 | + function renderHeader() { |
110 | + if (!unref(showLogo)) return null; | ||
185 | return ( | 111 | return ( |
186 | - showSearch && | ||
187 | - props.showSearch && | ||
188 | - !(type === MenuTypeEnum.MIX && mode === MenuModeEnum.HORIZONTAL) | 112 | + <AppLogo |
113 | + showTitle={!unref(getCollapsed)} | ||
114 | + class={[`layout-menu__logo`, unref(getMenuTheme)]} | ||
115 | + theme={unref(getMenuTheme)} | ||
116 | + /> | ||
189 | ); | 117 | ); |
190 | - }); | ||
191 | - | ||
192 | - onMounted(() => { | ||
193 | - genMenus(); | ||
194 | - }); | 118 | + } |
195 | 119 | ||
196 | return () => { | 120 | return () => { |
197 | - const { | ||
198 | - showLogo, | ||
199 | - menuSetting: { | ||
200 | - type: menuType, | ||
201 | - mode, | ||
202 | - theme, | ||
203 | - collapsed, | ||
204 | - collapsedShowTitle, | ||
205 | - collapsedShowSearch, | ||
206 | - accordion, | ||
207 | - }, | ||
208 | - } = unref(getProjectConfigRef); | ||
209 | - | ||
210 | - const isSidebarType = menuType === MenuTypeEnum.SIDEBAR; | ||
211 | - const isShowLogo = showLogo && isSidebarType; | ||
212 | - const themeData = props.theme || theme; | ||
213 | return ( | 121 | return ( |
214 | <BasicMenu | 122 | <BasicMenu |
215 | - beforeClickFn={beforeMenuClickFn} | ||
216 | - onMenuClick={handleMenuClick} | ||
217 | - type={menuType} | ||
218 | - mode={props.menuMode || mode} | ||
219 | class="layout-menu" | 123 | class="layout-menu" |
220 | - collapsedShowTitle={collapsedShowTitle} | ||
221 | - theme={themeData} | ||
222 | - showLogo={isShowLogo} | ||
223 | - search={unref(showSearchRef) && (collapsedShowSearch ? true : !collapsed)} | 124 | + beforeClickFn={beforeMenuClickFn} |
125 | + isHorizontal={props.isHorizontal} | ||
126 | + appendClass={unref(appendClass)} | ||
127 | + type={unref(getType)} | ||
128 | + mode={unref(getMenuMode)} | ||
129 | + collapsedShowTitle={unref(getCollapsedShowTitle)} | ||
130 | + theme={unref(getMenuTheme)} | ||
131 | + showLogo={unref(showLogo)} | ||
132 | + search={unref(showSearch)} | ||
224 | items={unref(menusRef)} | 133 | items={unref(menusRef)} |
225 | flatItems={unref(flatMenusRef)} | 134 | flatItems={unref(flatMenusRef)} |
135 | + accordion={unref(getAccordion)} | ||
136 | + onMenuClick={handleMenuClick} | ||
226 | onClickSearchInput={handleClickSearchInput} | 137 | onClickSearchInput={handleClickSearchInput} |
227 | - appendClass={props.splitType === MenuSplitTyeEnum.TOP} | ||
228 | - isTop={props.isTop} | ||
229 | - accordion={accordion} | ||
230 | > | 138 | > |
231 | {{ | 139 | {{ |
232 | - header: () => | ||
233 | - isShowLogo && ( | ||
234 | - <Logo | ||
235 | - showTitle={!collapsed} | ||
236 | - class={[`layout-menu__logo`, themeData]} | ||
237 | - theme={themeData} | ||
238 | - /> | ||
239 | - ), | 140 | + header: () => renderHeader(), |
240 | }} | 141 | }} |
241 | </BasicMenu> | 142 | </BasicMenu> |
242 | ); | 143 | ); |
src/layouts/default/menu/index.less
@@ -9,17 +9,5 @@ | @@ -9,17 +9,5 @@ | ||
9 | width: @logo-width; | 9 | width: @logo-width; |
10 | height: @logo-width; | 10 | height: @logo-width; |
11 | } | 11 | } |
12 | - | ||
13 | - &.light { | ||
14 | - .logo-title { | ||
15 | - color: @text-color-base; | ||
16 | - } | ||
17 | - } | ||
18 | - | ||
19 | - &.dark { | ||
20 | - .logo-title { | ||
21 | - color: @white; | ||
22 | - } | ||
23 | - } | ||
24 | } | 12 | } |
25 | } | 13 | } |
src/layouts/default/menu/useLayoutMenu.ts
0 → 100644
1 | +import type { Menu } from '/@/router/types'; | ||
2 | +import type { Ref } from 'vue'; | ||
3 | + | ||
4 | +import { watch, unref, ref, computed } from 'vue'; | ||
5 | +import { useRouter } from 'vue-router'; | ||
6 | + | ||
7 | +import { MenuSplitTyeEnum } from '/@/enums/menuEnum'; | ||
8 | +import { useThrottle } from '/@/hooks/core/useThrottle'; | ||
9 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
10 | + | ||
11 | +import { | ||
12 | + getChildrenMenus, | ||
13 | + getCurrentParentPath, | ||
14 | + getFlatChildrenMenus, | ||
15 | + getFlatMenus, | ||
16 | + getMenus, | ||
17 | + getShallowMenus, | ||
18 | +} from '/@/router/menus'; | ||
19 | +import { permissionStore } from '/@/store/modules/permission'; | ||
20 | + | ||
21 | +export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) { | ||
22 | + // Menu array | ||
23 | + const menusRef = ref<Menu[]>([]); | ||
24 | + // flat menu array | ||
25 | + const flatMenusRef = ref<Menu[]>([]); | ||
26 | + | ||
27 | + const { currentRoute } = useRouter(); | ||
28 | + | ||
29 | + const { setMenuSetting, getIsHorizontal, getSplit } = useMenuSetting(); | ||
30 | + | ||
31 | + const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50); | ||
32 | + | ||
33 | + const splitNotLeft = computed( | ||
34 | + () => unref(splitType) !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontal) | ||
35 | + ); | ||
36 | + | ||
37 | + const splitLeft = computed(() => !unref(getSplit) || unref(splitType) !== MenuSplitTyeEnum.LEFT); | ||
38 | + | ||
39 | + const spiltTop = computed(() => unref(splitType) === MenuSplitTyeEnum.TOP); | ||
40 | + | ||
41 | + const normalType = computed(() => { | ||
42 | + return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit); | ||
43 | + }); | ||
44 | + | ||
45 | + watch( | ||
46 | + [() => unref(currentRoute).path, () => unref(splitType)], | ||
47 | + async ([path]: [string, MenuSplitTyeEnum]) => { | ||
48 | + if (unref(splitNotLeft)) return; | ||
49 | + | ||
50 | + const parentPath = await getCurrentParentPath(path); | ||
51 | + parentPath && throttleHandleSplitLeftMenu(parentPath); | ||
52 | + }, | ||
53 | + { | ||
54 | + immediate: true, | ||
55 | + } | ||
56 | + ); | ||
57 | + | ||
58 | + // Menu changes | ||
59 | + watch( | ||
60 | + [() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState], | ||
61 | + () => { | ||
62 | + genMenus(); | ||
63 | + }, | ||
64 | + { | ||
65 | + immediate: true, | ||
66 | + } | ||
67 | + ); | ||
68 | + | ||
69 | + // split Menu changes | ||
70 | + watch([() => getSplit.value], () => { | ||
71 | + if (unref(splitNotLeft)) return; | ||
72 | + genMenus(); | ||
73 | + }); | ||
74 | + | ||
75 | + // Handle left menu split | ||
76 | + async function handleSplitLeftMenu(parentPath: string) { | ||
77 | + if (unref(splitLeft)) return; | ||
78 | + | ||
79 | + // spilt mode left | ||
80 | + const children = await getChildrenMenus(parentPath); | ||
81 | + if (!children) { | ||
82 | + setMenuSetting({ hidden: false }); | ||
83 | + flatMenusRef.value = []; | ||
84 | + menusRef.value = []; | ||
85 | + return; | ||
86 | + } | ||
87 | + | ||
88 | + const flatChildren = await getFlatChildrenMenus(children); | ||
89 | + setMenuSetting({ hidden: true }); | ||
90 | + flatMenusRef.value = flatChildren; | ||
91 | + menusRef.value = children; | ||
92 | + } | ||
93 | + | ||
94 | + // get menus | ||
95 | + async function genMenus() { | ||
96 | + // normal mode | ||
97 | + if (unref(normalType)) { | ||
98 | + flatMenusRef.value = await getFlatMenus(); | ||
99 | + menusRef.value = await getMenus(); | ||
100 | + return; | ||
101 | + } | ||
102 | + | ||
103 | + // split-top | ||
104 | + if (unref(spiltTop)) { | ||
105 | + const shallowMenus = await getShallowMenus(); | ||
106 | + | ||
107 | + flatMenusRef.value = shallowMenus; | ||
108 | + menusRef.value = shallowMenus; | ||
109 | + return; | ||
110 | + } | ||
111 | + } | ||
112 | + return { flatMenusRef, menusRef }; | ||
113 | +} |
src/layouts/default/multitabs/index.tsx
@@ -33,7 +33,7 @@ export default defineComponent({ | @@ -33,7 +33,7 @@ export default defineComponent({ | ||
33 | return tabStore.getTabsState; | 33 | return tabStore.getTabsState; |
34 | }); | 34 | }); |
35 | 35 | ||
36 | - // If you monitor routing changes, tab switching will be stuck. So use this method | 36 | + // If you monitor routing changes, tab switching will be stuck. So setting this method |
37 | watch( | 37 | watch( |
38 | () => tabStore.getLastChangeRouteState, | 38 | () => tabStore.getLastChangeRouteState, |
39 | () => { | 39 | () => { |
src/layouts/default/sider/LayoutSideBar.tsx
0 → 100644
1 | +import './index.less'; | ||
2 | + | ||
3 | +import { computed, defineComponent, ref, unref } from 'vue'; | ||
4 | + | ||
5 | +import { Layout } from 'ant-design-vue'; | ||
6 | +import LayoutMenu from '/@/layouts/default/menu/LayoutMenu'; | ||
7 | + | ||
8 | +import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; | ||
9 | + | ||
10 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
11 | +import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider'; | ||
12 | + | ||
13 | +export default defineComponent({ | ||
14 | + name: 'LayoutSideBar', | ||
15 | + setup() { | ||
16 | + const dragBarRef = ref<Nullable<HTMLDivElement>>(null); | ||
17 | + const sideRef = ref<Nullable<HTMLDivElement>>(null); | ||
18 | + | ||
19 | + const { getCollapsed, getMenuWidth, getSplit, getTheme } = useMenuSetting(); | ||
20 | + | ||
21 | + const { getTriggerAttr, getTriggerSlot } = useTrigger(); | ||
22 | + | ||
23 | + const { renderDragLine } = useDragLine(sideRef, dragBarRef); | ||
24 | + | ||
25 | + const { | ||
26 | + getCollapsedWidth, | ||
27 | + onBreakpointChange, | ||
28 | + onCollapseChange, | ||
29 | + onSiderClick, | ||
30 | + } = useSiderEvent(); | ||
31 | + | ||
32 | + const getMode = computed(() => { | ||
33 | + return unref(getSplit) ? MenuModeEnum.INLINE : null; | ||
34 | + }); | ||
35 | + | ||
36 | + const getSplitType = computed(() => { | ||
37 | + return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE; | ||
38 | + }); | ||
39 | + | ||
40 | + function renderDefault() { | ||
41 | + return ( | ||
42 | + <> | ||
43 | + <LayoutMenu | ||
44 | + theme={unref(getTheme)} | ||
45 | + menuMode={unref(getMode)} | ||
46 | + splitType={unref(getSplitType)} | ||
47 | + /> | ||
48 | + {renderDragLine()} | ||
49 | + </> | ||
50 | + ); | ||
51 | + } | ||
52 | + | ||
53 | + return () => { | ||
54 | + return ( | ||
55 | + <Layout.Sider | ||
56 | + ref={sideRef} | ||
57 | + class="layout-sidebar" | ||
58 | + breakpoint="md" | ||
59 | + collapsible | ||
60 | + width={unref(getMenuWidth)} | ||
61 | + collapsed={unref(getCollapsed)} | ||
62 | + collapsedWidth={unref(getCollapsedWidth)} | ||
63 | + theme={unref(getTheme)} | ||
64 | + onClick={onSiderClick} | ||
65 | + onCollapse={onCollapseChange} | ||
66 | + onBreakpoint={onBreakpointChange} | ||
67 | + {...unref(getTriggerAttr)} | ||
68 | + > | ||
69 | + {{ | ||
70 | + ...unref(getTriggerSlot), | ||
71 | + default: () => renderDefault(), | ||
72 | + }} | ||
73 | + </Layout.Sider> | ||
74 | + ); | ||
75 | + }; | ||
76 | + }, | ||
77 | +}); |
src/layouts/default/sider/index.less
0 → 100644
1 | +@import (reference) '../../../design/index.less'; | ||
2 | + | ||
3 | +.layout-sidebar { | ||
4 | + background-size: 100% 100%; | ||
5 | + | ||
6 | + &.ant-layout-sider-dark { | ||
7 | + background: @sider-dark-bg-color; | ||
8 | + } | ||
9 | + | ||
10 | + &:not(.ant-layout-sider-dark) { | ||
11 | + border-right: 1px solid @border-color-light; | ||
12 | + } | ||
13 | + | ||
14 | + .ant-layout-sider-zero-width-trigger { | ||
15 | + top: 40%; | ||
16 | + z-index: 10; | ||
17 | + } | ||
18 | + | ||
19 | + &__darg-bar { | ||
20 | + position: absolute; | ||
21 | + top: 0; | ||
22 | + right: -2px; | ||
23 | + z-index: @side-drag-z-index; | ||
24 | + width: 2px; | ||
25 | + height: 100%; | ||
26 | + cursor: col-resize; | ||
27 | + border-top: none; | ||
28 | + border-bottom: none; | ||
29 | + | ||
30 | + &.hide { | ||
31 | + display: none; | ||
32 | + } | ||
33 | + | ||
34 | + &:hover { | ||
35 | + background: @primary-color; | ||
36 | + box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15); | ||
37 | + } | ||
38 | + } | ||
39 | +} | ||
40 | + | ||
41 | +.ant-layout-sider-trigger { | ||
42 | + height: 36px; | ||
43 | + line-height: 36px; | ||
44 | +} |
src/layouts/default/sider/useLayoutSider.tsx
0 → 100644
1 | +import type { Ref } from 'vue'; | ||
2 | + | ||
3 | +import { computed, unref, onMounted, nextTick, ref } from 'vue'; | ||
4 | +import LayoutTrigger from '/@/layouts/default/LayoutTrigger'; | ||
5 | + | ||
6 | +import { TriggerEnum } from '/@/enums/menuEnum'; | ||
7 | + | ||
8 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
9 | +import { useDebounce } from '/@/hooks/core/useDebounce'; | ||
10 | + | ||
11 | +/** | ||
12 | + * Handle related operations of menu events | ||
13 | + */ | ||
14 | +export function useSiderEvent() { | ||
15 | + const initRef = ref(false); | ||
16 | + const brokenRef = ref(false); | ||
17 | + const collapseRef = ref(true); | ||
18 | + | ||
19 | + const { setMenuSetting, getCollapsed, getMiniWidthNumber, getShow } = useMenuSetting(); | ||
20 | + | ||
21 | + const getCollapsedWidth = computed(() => { | ||
22 | + return unref(brokenRef) ? 0 : unref(getMiniWidthNumber); | ||
23 | + }); | ||
24 | + | ||
25 | + function onCollapseChange(val: boolean) { | ||
26 | + if (initRef.value) { | ||
27 | + collapseRef.value = val; | ||
28 | + setMenuSetting({ collapsed: val }); | ||
29 | + } else { | ||
30 | + !unref(getCollapsed) && setMenuSetting({ collapsed: val }); | ||
31 | + } | ||
32 | + initRef.value = true; | ||
33 | + } | ||
34 | + | ||
35 | + function onBreakpointChange(broken: boolean) { | ||
36 | + brokenRef.value = broken; | ||
37 | + } | ||
38 | + | ||
39 | + function onSiderClick(e: ChangeEvent) { | ||
40 | + if (!e || !e.target || e.target.className !== 'basic-menu__content') return; | ||
41 | + if (!unref(getCollapsed) || !unref(getShow)) return; | ||
42 | + setMenuSetting({ collapsed: false }); | ||
43 | + } | ||
44 | + return { getCollapsedWidth, onCollapseChange, onBreakpointChange, onSiderClick }; | ||
45 | +} | ||
46 | + | ||
47 | +/** | ||
48 | + * Handle related operations of menu folding | ||
49 | + */ | ||
50 | +export function useTrigger() { | ||
51 | + const { getTrigger } = useMenuSetting(); | ||
52 | + | ||
53 | + const showTrigger = computed(() => { | ||
54 | + const trigger = unref(getTrigger); | ||
55 | + return trigger !== TriggerEnum.NONE && trigger === TriggerEnum.FOOTER; | ||
56 | + }); | ||
57 | + | ||
58 | + const getTriggerAttr = computed(() => { | ||
59 | + if (unref(showTrigger)) { | ||
60 | + return {}; | ||
61 | + } | ||
62 | + return { | ||
63 | + trigger: null, | ||
64 | + }; | ||
65 | + }); | ||
66 | + | ||
67 | + const getTriggerSlot = computed(() => { | ||
68 | + if (unref(showTrigger)) { | ||
69 | + return { | ||
70 | + trigger: () => <LayoutTrigger />, | ||
71 | + }; | ||
72 | + } | ||
73 | + return {}; | ||
74 | + }); | ||
75 | + | ||
76 | + return { getTriggerAttr, getTriggerSlot }; | ||
77 | +} | ||
78 | + | ||
79 | +/** | ||
80 | + * Handle menu drag and drop related operations | ||
81 | + * @param siderRef | ||
82 | + * @param dragBarRef | ||
83 | + */ | ||
84 | +export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) { | ||
85 | + const { getMiniWidthNumber, getCollapsed, setMenuSetting, getHasDrag } = useMenuSetting(); | ||
86 | + | ||
87 | + const getDragBarStyle = computed(() => { | ||
88 | + if (unref(getCollapsed)) { | ||
89 | + return { left: `${unref(getMiniWidthNumber)}px` }; | ||
90 | + } | ||
91 | + return {}; | ||
92 | + }); | ||
93 | + | ||
94 | + onMounted(() => { | ||
95 | + nextTick(() => { | ||
96 | + const [exec] = useDebounce(changeWrapWidth, 20); | ||
97 | + exec(); | ||
98 | + }); | ||
99 | + }); | ||
100 | + | ||
101 | + function renderDragLine() { | ||
102 | + return ( | ||
103 | + <div | ||
104 | + class={[`layout-sidebar__darg-bar`, !unref(getHasDrag) ? 'hide' : '']} | ||
105 | + style={unref(getDragBarStyle)} | ||
106 | + ref={dragBarRef} | ||
107 | + /> | ||
108 | + ); | ||
109 | + } | ||
110 | + | ||
111 | + function handleMouseMove(ele: HTMLElement, wrap: HTMLElement, clientX: number) { | ||
112 | + document.onmousemove = function (innerE) { | ||
113 | + let iT = (ele as any).left + (innerE.clientX - clientX); | ||
114 | + innerE = innerE || window.event; | ||
115 | + const maxT = 600; | ||
116 | + const minT = unref(getMiniWidthNumber); | ||
117 | + iT < 0 && (iT = 0); | ||
118 | + iT > maxT && (iT = maxT); | ||
119 | + iT < minT && (iT = minT); | ||
120 | + ele.style.left = wrap.style.width = iT + 'px'; | ||
121 | + return false; | ||
122 | + }; | ||
123 | + } | ||
124 | + | ||
125 | + // Drag and drop in the menu area-release the mouse | ||
126 | + function removeMouseup(ele: any) { | ||
127 | + const wrap = unref(siderRef).$el; | ||
128 | + document.onmouseup = function () { | ||
129 | + document.onmousemove = null; | ||
130 | + document.onmouseup = null; | ||
131 | + const width = parseInt(wrap.style.width); | ||
132 | + const miniWidth = unref(getMiniWidthNumber); | ||
133 | + | ||
134 | + if (!unref(getCollapsed)) { | ||
135 | + width > miniWidth + 20 | ||
136 | + ? setMenuSetting({ menuWidth: width }) | ||
137 | + : setMenuSetting({ collapsed: true }); | ||
138 | + } else { | ||
139 | + width > miniWidth && setMenuSetting({ collapsed: false, menuWidth: width }); | ||
140 | + } | ||
141 | + ele.releaseCapture?.(); | ||
142 | + }; | ||
143 | + } | ||
144 | + | ||
145 | + function changeWrapWidth() { | ||
146 | + const ele = unref(dragBarRef) as any; | ||
147 | + const side = unref(siderRef); | ||
148 | + | ||
149 | + const wrap = (side || {}).$el; | ||
150 | + ele && | ||
151 | + (ele.onmousedown = (e: any) => { | ||
152 | + wrap.style.transition = 'unset'; | ||
153 | + const clientX = e?.clientX; | ||
154 | + ele.left = ele.offsetLeft; | ||
155 | + handleMouseMove(ele, wrap, clientX); | ||
156 | + removeMouseup(ele); | ||
157 | + ele.setCapture?.(); | ||
158 | + return false; | ||
159 | + }); | ||
160 | + } | ||
161 | + | ||
162 | + return { renderDragLine }; | ||
163 | +} |
src/layouts/iframe/useFrameKeepAlive.ts
@@ -5,12 +5,29 @@ import { useRouter } from 'vue-router'; | @@ -5,12 +5,29 @@ import { useRouter } from 'vue-router'; | ||
5 | import router from '/@/router'; | 5 | import router from '/@/router'; |
6 | 6 | ||
7 | import { tabStore } from '/@/store/modules/tab'; | 7 | import { tabStore } from '/@/store/modules/tab'; |
8 | -import { appStore } from '/@/store/modules/app'; | ||
9 | 8 | ||
10 | import { unique } from '/@/utils'; | 9 | import { unique } from '/@/utils'; |
11 | 10 | ||
11 | +import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; | ||
12 | + | ||
12 | export function useFrameKeepAlive() { | 13 | export function useFrameKeepAlive() { |
13 | const { currentRoute } = useRouter(); | 14 | const { currentRoute } = useRouter(); |
15 | + const { getShow } = useMultipleTabSetting(); | ||
16 | + | ||
17 | + const getFramePages = computed(() => { | ||
18 | + const ret = | ||
19 | + getAllFramePages((toRaw(router.getRoutes()) as unknown) as AppRouteRecordRaw[]) || []; | ||
20 | + return ret; | ||
21 | + }); | ||
22 | + | ||
23 | + const getOpenTabList = computed((): string[] => { | ||
24 | + return tabStore.getTabsState.reduce((prev: string[], next) => { | ||
25 | + if (next.meta && Reflect.has(next.meta, 'frameSrc')) { | ||
26 | + prev.push(next.path!); | ||
27 | + } | ||
28 | + return prev; | ||
29 | + }, []); | ||
30 | + }); | ||
14 | 31 | ||
15 | function getAllFramePages(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] { | 32 | function getAllFramePages(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] { |
16 | let res: AppRouteRecordRaw[] = []; | 33 | let res: AppRouteRecordRaw[] = []; |
@@ -30,26 +47,9 @@ export function useFrameKeepAlive() { | @@ -30,26 +47,9 @@ export function useFrameKeepAlive() { | ||
30 | function showIframe(item: AppRouteRecordRaw) { | 47 | function showIframe(item: AppRouteRecordRaw) { |
31 | return item.path === unref(currentRoute).path; | 48 | return item.path === unref(currentRoute).path; |
32 | } | 49 | } |
33 | - const getFramePages = computed(() => { | ||
34 | - const ret = | ||
35 | - getAllFramePages((toRaw(router.getRoutes()) as unknown) as AppRouteRecordRaw[]) || []; | ||
36 | - return ret; | ||
37 | - }); | ||
38 | - | ||
39 | - const getOpenTabList = computed((): string[] => { | ||
40 | - return tabStore.getTabsState.reduce((prev: string[], next) => { | ||
41 | - if (next.meta && Reflect.has(next.meta, 'frameSrc')) { | ||
42 | - prev.push(next.path!); | ||
43 | - } | ||
44 | - return prev; | ||
45 | - }, []); | ||
46 | - }); | ||
47 | 50 | ||
48 | function hasRenderFrame(path: string) { | 51 | function hasRenderFrame(path: string) { |
49 | - const { | ||
50 | - multiTabsSetting: { show }, | ||
51 | - } = appStore.getProjectConfig; | ||
52 | - return show ? unref(getOpenTabList).includes(path) : true; | 52 | + return unref(getShow) ? unref(getOpenTabList).includes(path) : true; |
53 | } | 53 | } |
54 | return { hasRenderFrame, getFramePages, showIframe, getAllFramePages }; | 54 | return { hasRenderFrame, getFramePages, showIframe, getAllFramePages }; |
55 | } | 55 | } |
src/layouts/page/index.tsx
1 | -import { computed, defineComponent, unref, Transition, KeepAlive, toRaw } from 'vue'; | 1 | +import type { FunctionalComponent } from 'vue'; |
2 | + | ||
3 | +import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue'; | ||
2 | import { RouterView, RouteLocation } from 'vue-router'; | 4 | import { RouterView, RouteLocation } from 'vue-router'; |
3 | 5 | ||
4 | import FrameLayout from '/@/layouts/iframe/index.vue'; | 6 | import FrameLayout from '/@/layouts/iframe/index.vue'; |
5 | 7 | ||
6 | import { useTransition } from './useTransition'; | 8 | import { useTransition } from './useTransition'; |
7 | -import { useProjectSetting } from '/@/settings/use'; | 9 | +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; |
10 | +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
11 | +import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; | ||
8 | 12 | ||
9 | import { tabStore } from '/@/store/modules/tab'; | 13 | import { tabStore } from '/@/store/modules/tab'; |
10 | -import { appStore } from '/@/store/modules/app'; | 14 | + |
15 | +interface DefaultContext { | ||
16 | + Component: FunctionalComponent; | ||
17 | + route: RouteLocation; | ||
18 | +} | ||
11 | 19 | ||
12 | export default defineComponent({ | 20 | export default defineComponent({ |
13 | name: 'PageLayout', | 21 | name: 'PageLayout', |
14 | setup() { | 22 | setup() { |
15 | - const getProjectConfigRef = computed(() => appStore.getProjectConfig); | ||
16 | - const openCacheRef = computed(() => { | ||
17 | - const { | ||
18 | - openKeepAlive, | ||
19 | - multiTabsSetting: { show }, | ||
20 | - } = unref(getProjectConfigRef); | ||
21 | - return openKeepAlive && show; | ||
22 | - }); | ||
23 | - const getCacheTabsRef = computed(() => toRaw(tabStore.getKeepAliveTabsState) as string[]); | 23 | + const { getShow } = useMenuSetting(); |
24 | + const { | ||
25 | + getOpenKeepAlive, | ||
26 | + getRouterTransition, | ||
27 | + getOpenRouterTransition, | ||
28 | + getCanEmbedIFramePage, | ||
29 | + } = useRootSetting(); | ||
24 | 30 | ||
25 | - const { openPageLoading } = unref(getProjectConfigRef); | 31 | + const { getMax } = useMultipleTabSetting(); |
26 | 32 | ||
27 | - let on = {}; | ||
28 | - if (openPageLoading) { | ||
29 | - const { on: transitionOn } = useTransition(); | ||
30 | - on = transitionOn; | ||
31 | - } | ||
32 | - const projectSetting = useProjectSetting(); | ||
33 | - return () => { | ||
34 | - const { | ||
35 | - routerTransition, | ||
36 | - openRouterTransition, | ||
37 | - multiTabsSetting: { max }, | ||
38 | - } = unref(getProjectConfigRef); | 33 | + const transitionEvent = useTransition(); |
34 | + | ||
35 | + const openCacheRef = computed(() => unref(getOpenKeepAlive) && unref(getShow)); | ||
39 | 36 | ||
37 | + const getCacheTabsRef = computed(() => tabStore.getKeepAliveTabsState as string[]); | ||
38 | + | ||
39 | + return () => { | ||
40 | return ( | 40 | return ( |
41 | <div> | 41 | <div> |
42 | <RouterView> | 42 | <RouterView> |
43 | {{ | 43 | {{ |
44 | - default: ({ Component, route }: { Component: any; route: RouteLocation }) => { | 44 | + default: ({ Component, route }: DefaultContext) => { |
45 | // No longer show animations that are already in the tab | 45 | // No longer show animations that are already in the tab |
46 | const cacheTabs = unref(getCacheTabsRef); | 46 | const cacheTabs = unref(getCacheTabsRef); |
47 | const isInCache = cacheTabs.includes(route.name as string); | 47 | const isInCache = cacheTabs.includes(route.name as string); |
48 | const name = isInCache && route.meta.inTab ? 'fade' : null; | 48 | const name = isInCache && route.meta.inTab ? 'fade' : null; |
49 | 49 | ||
50 | - const Content = unref(openCacheRef) ? ( | ||
51 | - <KeepAlive max={max} include={cacheTabs}> | ||
52 | - <Component key={route.fullPath} /> | 50 | + const renderComp = () => <Component key={route.fullPath} />; |
51 | + | ||
52 | + const PageContent = unref(openCacheRef) ? ( | ||
53 | + <KeepAlive max={unref(getMax)} include={cacheTabs}> | ||
54 | + {renderComp()} | ||
53 | </KeepAlive> | 55 | </KeepAlive> |
54 | ) : ( | 56 | ) : ( |
55 | - <Component key={route.fullPath} /> | 57 | + renderComp() |
56 | ); | 58 | ); |
57 | - return openRouterTransition ? ( | 59 | + |
60 | + return unref(getOpenRouterTransition) ? ( | ||
58 | <Transition | 61 | <Transition |
59 | - {...on} | ||
60 | - name={name || route.meta.transitionName || routerTransition} | 62 | + {...transitionEvent} |
63 | + name={name || route.meta.transitionName || unref(getRouterTransition)} | ||
61 | mode="out-in" | 64 | mode="out-in" |
62 | appear={true} | 65 | appear={true} |
63 | > | 66 | > |
64 | - {() => Content} | 67 | + {() => PageContent} |
65 | </Transition> | 68 | </Transition> |
66 | ) : ( | 69 | ) : ( |
67 | - Content | 70 | + PageContent |
68 | ); | 71 | ); |
69 | }, | 72 | }, |
70 | }} | 73 | }} |
71 | </RouterView> | 74 | </RouterView> |
72 | - {projectSetting.canEmbedIFramePage && <FrameLayout />} | 75 | + {unref(getCanEmbedIFramePage) && <FrameLayout />} |
73 | </div> | 76 | </div> |
74 | ); | 77 | ); |
75 | }; | 78 | }; |
src/layouts/page/useTransition.ts
1 | +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | ||
1 | import { appStore } from '/@/store/modules/app'; | 2 | import { appStore } from '/@/store/modules/app'; |
2 | import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; | 3 | import { tryOnUnmounted } from '/@/utils/helper/vueHelper'; |
4 | + | ||
3 | export function useTransition() { | 5 | export function useTransition() { |
4 | function handleAfterEnter() { | 6 | function handleAfterEnter() { |
5 | - const { openRouterTransition, openPageLoading } = appStore.getProjectConfig; | ||
6 | - | ||
7 | - if (!openRouterTransition || !openPageLoading) return; | 7 | + const { getOpenPageLoading, getOpenRouterTransition } = useRootSetting(); |
8 | + if (!getOpenPageLoading.value || !getOpenRouterTransition.value) return; | ||
8 | // Close loading after the route switching animation ends | 9 | // Close loading after the route switching animation ends |
9 | appStore.setPageLoadingAction(false); | 10 | appStore.setPageLoadingAction(false); |
10 | } | 11 | } |
@@ -15,9 +16,6 @@ export function useTransition() { | @@ -15,9 +16,6 @@ export function useTransition() { | ||
15 | }); | 16 | }); |
16 | 17 | ||
17 | return { | 18 | return { |
18 | - handleAfterEnter, | ||
19 | - on: { | ||
20 | - onAfterEnter: handleAfterEnter, | ||
21 | - }, | 19 | + onAfterEnter: handleAfterEnter, |
22 | }; | 20 | }; |
23 | } | 21 | } |
src/main.ts
@@ -49,7 +49,7 @@ if (isDevMode()) { | @@ -49,7 +49,7 @@ if (isDevMode()) { | ||
49 | window.__APP__ = app; | 49 | window.__APP__ = app; |
50 | } | 50 | } |
51 | 51 | ||
52 | -// If you do not need to use the mock service in the production environment, you can comment the code | 52 | +// If you do not need to setting the mock service in the production environment, you can comment the code |
53 | if (isProdMode() && isUseMock()) { | 53 | if (isProdMode() && isUseMock()) { |
54 | setupProdMockServer(); | 54 | setupProdMockServer(); |
55 | } | 55 | } |
src/router/guard/index.ts
@@ -6,7 +6,7 @@ import { createProgressGuard } from './progressGuard'; | @@ -6,7 +6,7 @@ import { createProgressGuard } from './progressGuard'; | ||
6 | import { createPermissionGuard } from './permissionGuard'; | 6 | import { createPermissionGuard } from './permissionGuard'; |
7 | import { createPageLoadingGuard } from './pageLoadingGuard'; | 7 | import { createPageLoadingGuard } from './pageLoadingGuard'; |
8 | 8 | ||
9 | -import { useGlobSetting, useProjectSetting } from '/@/settings/use'; | 9 | +import { useGlobSetting, useProjectSetting } from '/@/hooks/setting'; |
10 | 10 | ||
11 | import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper'; | 11 | import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper'; |
12 | import { setTitle } from '/@/utils/browser'; | 12 | import { setTitle } from '/@/utils/browser'; |
src/router/menus/index.ts
@@ -7,6 +7,7 @@ import { filter } from '/@/utils/helper/treeHelper'; | @@ -7,6 +7,7 @@ import { filter } from '/@/utils/helper/treeHelper'; | ||
7 | import router from '/@/router'; | 7 | import router from '/@/router'; |
8 | import { PermissionModeEnum } from '/@/enums/appEnum'; | 8 | import { PermissionModeEnum } from '/@/enums/appEnum'; |
9 | import { pathToRegexp } from 'path-to-regexp'; | 9 | import { pathToRegexp } from 'path-to-regexp'; |
10 | + | ||
10 | import modules from 'globby!/@/router/menus/modules/**/*.@(ts)'; | 11 | import modules from 'globby!/@/router/menus/modules/**/*.@(ts)'; |
11 | 12 | ||
12 | const menuModules: MenuModule[] = []; | 13 | const menuModules: MenuModule[] = []; |
@@ -44,7 +45,6 @@ async function getAsyncMenus() { | @@ -44,7 +45,6 @@ async function getAsyncMenus() { | ||
44 | // 获取深层扁平化菜单 | 45 | // 获取深层扁平化菜单 |
45 | export const getFlatMenus = async () => { | 46 | export const getFlatMenus = async () => { |
46 | const menus = await getAsyncMenus(); | 47 | const menus = await getAsyncMenus(); |
47 | - | ||
48 | return flatMenus(menus); | 48 | return flatMenus(menus); |
49 | }; | 49 | }; |
50 | 50 |
src/settings/projectSetting.ts
@@ -9,7 +9,7 @@ import { isProdMode } from '/@/utils/env'; | @@ -9,7 +9,7 @@ import { isProdMode } from '/@/utils/env'; | ||
9 | const setting: ProjectConfig = { | 9 | const setting: ProjectConfig = { |
10 | // locale setting | 10 | // locale setting |
11 | locale: { | 11 | locale: { |
12 | - // Locales | 12 | + // Locale |
13 | lang: 'zh_CN', | 13 | lang: 'zh_CN', |
14 | // Default locale | 14 | // Default locale |
15 | fallback: 'zh_CN', | 15 | fallback: 'zh_CN', |
@@ -29,17 +29,22 @@ const setting: ProjectConfig = { | @@ -29,17 +29,22 @@ const setting: ProjectConfig = { | ||
29 | 29 | ||
30 | // Whether to show the configuration button | 30 | // Whether to show the configuration button |
31 | showSettingButton: true, | 31 | showSettingButton: true, |
32 | + | ||
32 | // 权限模式 | 33 | // 权限模式 |
33 | permissionMode: PermissionModeEnum.ROLE, | 34 | permissionMode: PermissionModeEnum.ROLE, |
35 | + | ||
34 | // 网站灰色模式,用于可能悼念的日期开启 | 36 | // 网站灰色模式,用于可能悼念的日期开启 |
35 | grayMode: false, | 37 | grayMode: false, |
38 | + | ||
36 | // 色弱模式 | 39 | // 色弱模式 |
37 | colorWeak: false, | 40 | colorWeak: false, |
38 | 41 | ||
39 | // 是否取消菜单,顶部,多标签页显示, 用于可能内嵌在别的系统内 | 42 | // 是否取消菜单,顶部,多标签页显示, 用于可能内嵌在别的系统内 |
40 | fullContent: false, | 43 | fullContent: false, |
44 | + | ||
41 | // content mode | 45 | // content mode |
42 | contentMode: ContentEnum.FULL, | 46 | contentMode: ContentEnum.FULL, |
47 | + | ||
43 | // 是否显示logo | 48 | // 是否显示logo |
44 | showLogo: true, | 49 | showLogo: true, |
45 | 50 | ||
@@ -58,11 +63,10 @@ const setting: ProjectConfig = { | @@ -58,11 +63,10 @@ const setting: ProjectConfig = { | ||
58 | showFullScreen: true, | 63 | showFullScreen: true, |
59 | // 显示文档按钮 | 64 | // 显示文档按钮 |
60 | showDoc: true, | 65 | showDoc: true, |
61 | - // 是否显示github | ||
62 | - showGithub: true, | ||
63 | // 显示消息中心按钮 | 66 | // 显示消息中心按钮 |
64 | showNotice: true, | 67 | showNotice: true, |
65 | }, | 68 | }, |
69 | + | ||
66 | // 菜单配置 | 70 | // 菜单配置 |
67 | menuSetting: { | 71 | menuSetting: { |
68 | // 菜单折叠 | 72 | // 菜单折叠 |
@@ -108,13 +112,16 @@ const setting: ProjectConfig = { | @@ -108,13 +112,16 @@ const setting: ProjectConfig = { | ||
108 | // 标签页缓存最大数量 | 112 | // 标签页缓存最大数量 |
109 | max: 12, | 113 | max: 12, |
110 | }, | 114 | }, |
115 | + | ||
111 | // 是否开启KeepAlive缓存 开发时候最好关闭,不然每次都需要清除缓存 | 116 | // 是否开启KeepAlive缓存 开发时候最好关闭,不然每次都需要清除缓存 |
112 | openKeepAlive: true, | 117 | openKeepAlive: true, |
113 | 118 | ||
114 | // 自动锁屏时间,为0不锁屏。 单位分钟 默认0 | 119 | // 自动锁屏时间,为0不锁屏。 单位分钟 默认0 |
115 | lockTime: 0, | 120 | lockTime: 0, |
121 | + | ||
116 | // 显示面包屑 | 122 | // 显示面包屑 |
117 | showBreadCrumb: true, | 123 | showBreadCrumb: true, |
124 | + | ||
118 | // 显示面包屑图标 | 125 | // 显示面包屑图标 |
119 | showBreadCrumbIcon: false, | 126 | showBreadCrumbIcon: false, |
120 | 127 |
src/setup/error-handle/index.ts
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | */ | 3 | */ |
4 | 4 | ||
5 | import { errorStore, ErrorInfo } from '/@/store/modules/error'; | 5 | import { errorStore, ErrorInfo } from '/@/store/modules/error'; |
6 | -import { useProjectSetting } from '/@/settings/use'; | 6 | +import { useProjectSetting } from '/@/hooks/setting'; |
7 | import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; | 7 | import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; |
8 | import { App } from 'vue'; | 8 | import { App } from 'vue'; |
9 | 9 |
src/setup/i18n/index.ts
@@ -4,7 +4,7 @@ import type { I18n, I18nOptions } from 'vue-i18n'; | @@ -4,7 +4,7 @@ import type { I18n, I18nOptions } from 'vue-i18n'; | ||
4 | import { createI18n } from 'vue-i18n'; | 4 | import { createI18n } from 'vue-i18n'; |
5 | import localeMessages from '/@/locales'; | 5 | import localeMessages from '/@/locales'; |
6 | import { useLocale } from '/@/hooks/web/useLocale'; | 6 | import { useLocale } from '/@/hooks/web/useLocale'; |
7 | -import { useLocaleSetting } from '/@/settings/use/useLocaleSetting'; | 7 | +import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting'; |
8 | 8 | ||
9 | const { setupLocale } = useLocale(); | 9 | const { setupLocale } = useLocale(); |
10 | 10 |
src/store/modules/error.ts
@@ -4,7 +4,7 @@ import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-dec | @@ -4,7 +4,7 @@ import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-dec | ||
4 | 4 | ||
5 | import { formatToDateTime } from '/@/utils/dateUtil'; | 5 | import { formatToDateTime } from '/@/utils/dateUtil'; |
6 | import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; | 6 | import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; |
7 | -import { useProjectSetting } from '/@/settings/use'; | 7 | +import { useProjectSetting } from '/@/hooks/setting'; |
8 | 8 | ||
9 | export interface ErrorInfo { | 9 | export interface ErrorInfo { |
10 | type: ErrorTypeEnum; | 10 | type: ErrorTypeEnum; |
src/store/modules/menu.ts deleted
100644 → 0
1 | -import store from '/@/store'; | ||
2 | -import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; | ||
3 | -import { VuexModule, Module, getModule, Mutation } from 'vuex-module-decorators'; | ||
4 | - | ||
5 | -import { appStore } from '/@/store/modules/app'; | ||
6 | - | ||
7 | -const NAME = 'menu'; | ||
8 | -hotModuleUnregisterModule(NAME); | ||
9 | -@Module({ namespaced: true, name: NAME, dynamic: true, store }) | ||
10 | -class Menu extends VuexModule { | ||
11 | - // 是否开始拖拽 | ||
12 | - private dragStartState = false; | ||
13 | - | ||
14 | - private currentTopSplitMenuPathState = ''; | ||
15 | - | ||
16 | - /** | ||
17 | - * @description: 获取窗口名称 | ||
18 | - */ | ||
19 | - get getCollapsedState() { | ||
20 | - return appStore.getProjectConfig.menuSetting.collapsed; | ||
21 | - } | ||
22 | - | ||
23 | - get getCurrentTopSplitMenuPathState() { | ||
24 | - return this.currentTopSplitMenuPathState; | ||
25 | - } | ||
26 | - | ||
27 | - get getDragStartState() { | ||
28 | - return this.dragStartState; | ||
29 | - } | ||
30 | - | ||
31 | - get getMenuWidthState() { | ||
32 | - return appStore.getProjectConfig.menuSetting.menuWidth; | ||
33 | - } | ||
34 | - | ||
35 | - @Mutation | ||
36 | - commitDragStartState(dragStart: boolean): void { | ||
37 | - this.dragStartState = dragStart; | ||
38 | - } | ||
39 | - | ||
40 | - @Mutation | ||
41 | - commitCurrentTopSplitMenuPathState(path: string): void { | ||
42 | - this.currentTopSplitMenuPathState = path; | ||
43 | - } | ||
44 | - | ||
45 | - // 改变菜单展开状态 | ||
46 | - @Mutation | ||
47 | - commitCollapsedState(collapsed: boolean): void { | ||
48 | - // this.collapsedState = collapsed; | ||
49 | - appStore.commitProjectConfigState({ | ||
50 | - menuSetting: { | ||
51 | - collapsed: collapsed, | ||
52 | - }, | ||
53 | - }); | ||
54 | - } | ||
55 | - | ||
56 | - @Mutation | ||
57 | - commitMenuWidthState(menuWidth: number): void { | ||
58 | - // this.menuWidthState = menuWidth; | ||
59 | - appStore.commitProjectConfigState({ | ||
60 | - menuSetting: { | ||
61 | - menuWidth: menuWidth, | ||
62 | - }, | ||
63 | - }); | ||
64 | - } | ||
65 | -} | ||
66 | - | ||
67 | -export const menuStore = getModule<Menu>(Menu); |
src/store/modules/permission.ts
@@ -97,11 +97,6 @@ class Permission extends VuexModule { | @@ -97,11 +97,6 @@ class Permission extends VuexModule { | ||
97 | if (!roles) return true; | 97 | if (!roles) return true; |
98 | return roleList.some((role) => roles.includes(role)); | 98 | return roleList.some((role) => roles.includes(role)); |
99 | }); | 99 | }); |
100 | - // this.commitRoutesState(routes); | ||
101 | - // Background permissions | ||
102 | - // warn( | ||
103 | - // `当前权限模式为:${PermissionModeEnum.ROLE},请将src/store/modules/permission.ts内的后台菜单获取函数注释,如果已注释可以忽略此信息!` | ||
104 | - // ); | ||
105 | // 如果确定不需要做后台动态权限,请将下面整个判断注释 | 100 | // 如果确定不需要做后台动态权限,请将下面整个判断注释 |
106 | } else if (permissionMode === PermissionModeEnum.BACK) { | 101 | } else if (permissionMode === PermissionModeEnum.BACK) { |
107 | const messageKey = 'loadMenu'; | 102 | const messageKey = 'loadMenu'; |
src/types/config.d.ts
@@ -44,7 +44,6 @@ export interface HeaderSetting { | @@ -44,7 +44,6 @@ export interface HeaderSetting { | ||
44 | useLockPage: boolean; | 44 | useLockPage: boolean; |
45 | // 显示文档按钮 | 45 | // 显示文档按钮 |
46 | showDoc: boolean; | 46 | showDoc: boolean; |
47 | - showGithub: boolean; | ||
48 | // 显示消息中心按钮 | 47 | // 显示消息中心按钮 |
49 | showNotice: boolean; | 48 | showNotice: boolean; |
50 | } | 49 | } |
src/utils/file/download.ts
1 | +import { openWindow } from '..'; | ||
1 | import { dataURLtoBlob, urlToBase64 } from './base64Conver'; | 2 | import { dataURLtoBlob, urlToBase64 } from './base64Conver'; |
2 | 3 | ||
3 | /** | 4 | /** |
@@ -93,6 +94,6 @@ export function downloadByUrl({ | @@ -93,6 +94,6 @@ export function downloadByUrl({ | ||
93 | url += '?download'; | 94 | url += '?download'; |
94 | } | 95 | } |
95 | 96 | ||
96 | - window.open(url, target); | 97 | + openWindow(url, { target }); |
97 | return true; | 98 | return true; |
98 | } | 99 | } |
src/utils/helper/envHelper.ts
1 | import { getEnv } from '/@/utils/env'; | 1 | import { getEnv } from '/@/utils/env'; |
2 | -import { useGlobSetting } from '/@/settings/use'; | 2 | +import { useGlobSetting } from '/@/hooks/setting'; |
3 | import pkg from '../../../package.json'; | 3 | import pkg from '../../../package.json'; |
4 | const globSetting = useGlobSetting(); | 4 | const globSetting = useGlobSetting(); |
5 | 5 |
src/utils/http/axios/index.ts
@@ -10,7 +10,7 @@ import { AxiosTransform } from './axiosTransform'; | @@ -10,7 +10,7 @@ import { AxiosTransform } from './axiosTransform'; | ||
10 | 10 | ||
11 | import { checkStatus } from './checkStatus'; | 11 | import { checkStatus } from './checkStatus'; |
12 | 12 | ||
13 | -import { useGlobSetting } from '/@/settings/use'; | 13 | +import { useGlobSetting } from '/@/hooks/setting'; |
14 | import { useMessage } from '/@/hooks/web/useMessage'; | 14 | import { useMessage } from '/@/hooks/web/useMessage'; |
15 | 15 | ||
16 | import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; | 16 | import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; |
src/utils/index.ts
@@ -11,6 +11,7 @@ export function getPopupContainer(node?: HTMLElement): HTMLElement { | @@ -11,6 +11,7 @@ export function getPopupContainer(node?: HTMLElement): HTMLElement { | ||
11 | } | 11 | } |
12 | return document.body; | 12 | return document.body; |
13 | } | 13 | } |
14 | + | ||
14 | /** | 15 | /** |
15 | * Add the object as a parameter to the URL | 16 | * Add the object as a parameter to the URL |
16 | * @param baseUrl url | 17 | * @param baseUrl url |
@@ -64,3 +65,16 @@ export function unique<T = any>(arr: T[], key: string): T[] { | @@ -64,3 +65,16 @@ export function unique<T = any>(arr: T[], key: string): T[] { | ||
64 | export function es6Unique<T>(arr: T[]): T[] { | 65 | export function es6Unique<T>(arr: T[]): T[] { |
65 | return Array.from(new Set(arr)); | 66 | return Array.from(new Set(arr)); |
66 | } | 67 | } |
68 | + | ||
69 | +export function openWindow( | ||
70 | + url: string, | ||
71 | + opt?: { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean } | ||
72 | +) { | ||
73 | + const { target = '__blank', noopener = true, noreferrer = true } = opt || {}; | ||
74 | + const feature: string[] = []; | ||
75 | + | ||
76 | + noopener && feature.push('noopener=yes'); | ||
77 | + noreferrer && feature.push('noreferrer=yes'); | ||
78 | + | ||
79 | + window.open(url, target, feature.join(',')); | ||
80 | +} |
src/views/demo/feat/icon/index.vue
@@ -45,6 +45,8 @@ | @@ -45,6 +45,8 @@ | ||
45 | 45 | ||
46 | import Icon from '/@/components/Icon/index'; | 46 | import Icon from '/@/components/Icon/index'; |
47 | 47 | ||
48 | + import { openWindow } from '/@/utils'; | ||
49 | + | ||
48 | export default defineComponent({ | 50 | export default defineComponent({ |
49 | components: { | 51 | components: { |
50 | CollapseContainer, | 52 | CollapseContainer, |
@@ -61,7 +63,7 @@ | @@ -61,7 +63,7 @@ | ||
61 | setup() { | 63 | setup() { |
62 | return { | 64 | return { |
63 | toIconify: () => { | 65 | toIconify: () => { |
64 | - window.open('https://iconify.design/', '__blank'); | 66 | + openWindow('https://iconify.design/'); |
65 | }, | 67 | }, |
66 | }; | 68 | }; |
67 | }, | 69 | }, |
src/views/demo/page/form/high/index.vue
@@ -16,23 +16,23 @@ | @@ -16,23 +16,23 @@ | ||
16 | </a-card> | 16 | </a-card> |
17 | </div> | 17 | </div> |
18 | 18 | ||
19 | - <AppFooterToolbar> | 19 | + <AppPageFooter> |
20 | <template #right> | 20 | <template #right> |
21 | <a-button type="primary" @click="submitAll">提交</a-button> | 21 | <a-button type="primary" @click="submitAll">提交</a-button> |
22 | </template> | 22 | </template> |
23 | - </AppFooterToolbar> | 23 | + </AppPageFooter> |
24 | </div> | 24 | </div> |
25 | </template> | 25 | </template> |
26 | <script lang="ts"> | 26 | <script lang="ts"> |
27 | import { BasicForm, useForm } from '/@/components/Form'; | 27 | import { BasicForm, useForm } from '/@/components/Form'; |
28 | import { defineComponent, ref } from 'vue'; | 28 | import { defineComponent, ref } from 'vue'; |
29 | import PersonTable from './PersonTable.vue'; | 29 | import PersonTable from './PersonTable.vue'; |
30 | - import { AppFooterToolbar } from '/@/components/Application'; | 30 | + import { AppPageFooter } from '/@/components/Application'; |
31 | 31 | ||
32 | import { schemas, taskSchemas } from './data'; | 32 | import { schemas, taskSchemas } from './data'; |
33 | 33 | ||
34 | export default defineComponent({ | 34 | export default defineComponent({ |
35 | - components: { BasicForm, PersonTable, AppFooterToolbar }, | 35 | + components: { BasicForm, PersonTable, AppPageFooter }, |
36 | setup() { | 36 | setup() { |
37 | const tableRef = ref<{ getDataSource: () => any } | null>(null); | 37 | const tableRef = ref<{ getDataSource: () => any } | null>(null); |
38 | 38 |
src/views/sys/login/Login.vue
@@ -72,7 +72,7 @@ | @@ -72,7 +72,7 @@ | ||
72 | 72 | ||
73 | // import { appStore } from '/@/store/modules/app'; | 73 | // import { appStore } from '/@/store/modules/app'; |
74 | import { useMessage } from '/@/hooks/web/useMessage'; | 74 | import { useMessage } from '/@/hooks/web/useMessage'; |
75 | - import { useGlobSetting } from '/@/settings/use'; | 75 | + import { useGlobSetting } from '/@/hooks/setting'; |
76 | import logo from '/@/assets/images/logo.png'; | 76 | import logo from '/@/assets/images/logo.png'; |
77 | 77 | ||
78 | export default defineComponent({ | 78 | export default defineComponent({ |
vite.config.ts
@@ -30,7 +30,7 @@ function pathResolve(dir: string) { | @@ -30,7 +30,7 @@ function pathResolve(dir: string) { | ||
30 | 30 | ||
31 | const viteConfig: UserConfig = { | 31 | const viteConfig: UserConfig = { |
32 | /** | 32 | /** |
33 | - * Entry. Use this to specify a js entry file in use cases where an | 33 | + * Entry. Use this to specify a js entry file in setting cases where an |
34 | * `index.html` does not exist (e.g. serving vite assets from a different host) | 34 | * `index.html` does not exist (e.g. serving vite assets from a different host) |
35 | * @default 'index.html' | 35 | * @default 'index.html' |
36 | */ | 36 | */ |
@@ -51,7 +51,7 @@ const viteConfig: UserConfig = { | @@ -51,7 +51,7 @@ const viteConfig: UserConfig = { | ||
51 | */ | 51 | */ |
52 | open: false, | 52 | open: false, |
53 | /** | 53 | /** |
54 | - * Set to `false` to disable minification, or specify the minifier to use. | 54 | + * Set to `false` to disable minification, or specify the minifier to setting. |
55 | * Available options are 'terser' or 'esbuild'. | 55 | * Available options are 'terser' or 'esbuild'. |
56 | * @default 'terser' | 56 | * @default 'terser' |
57 | */ | 57 | */ |
@@ -112,7 +112,7 @@ const viteConfig: UserConfig = { | @@ -112,7 +112,7 @@ const viteConfig: UserConfig = { | ||
112 | }, | 112 | }, |
113 | define: { | 113 | define: { |
114 | __VERSION__: pkg.version, | 114 | __VERSION__: pkg.version, |
115 | - // use vue-i18-next | 115 | + // setting vue-i18-next |
116 | // Suppress warning | 116 | // Suppress warning |
117 | __VUE_I18N_LEGACY_API__: false, | 117 | __VUE_I18N_LEGACY_API__: false, |
118 | __VUE_I18N_FULL_INSTALL__: false, | 118 | __VUE_I18N_FULL_INSTALL__: false, |