Commit ff2b12b4094de8d3cfd954b04a603a01557ce118
1 parent
056fc131
refactor(menu): added component. Solve the menu stuck problem
Showing
43 changed files
with
1793 additions
and
213 deletions
CHANGELOG.zh_CN.md
mock/sys/user.ts
... | ... | @@ -39,7 +39,7 @@ export default [ |
39 | 39 | // mock user login |
40 | 40 | { |
41 | 41 | url: '/api/login', |
42 | - timeout: 1000, | |
42 | + timeout: 200, | |
43 | 43 | method: 'post', |
44 | 44 | response: ({ body }) => { |
45 | 45 | const { username, password } = body; |
... | ... | @@ -62,7 +62,6 @@ export default [ |
62 | 62 | }, |
63 | 63 | { |
64 | 64 | url: '/api/getUserInfoById', |
65 | - timeout: 200, | |
66 | 65 | method: 'get', |
67 | 66 | response: ({ query }) => { |
68 | 67 | const { userId } = query; | ... | ... |
package.json
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | }, |
20 | 20 | "dependencies": { |
21 | 21 | "@iconify/iconify": "^2.0.0-rc.6", |
22 | - "@vueuse/core": "^4.0.5", | |
22 | + "@vueuse/core": "^4.0.8", | |
23 | 23 | "ant-design-vue": "^2.0.0-rc.8", |
24 | 24 | "apexcharts": "^3.23.1", |
25 | 25 | "axios": "^0.21.1", |
... | ... | @@ -45,12 +45,12 @@ |
45 | 45 | "devDependencies": { |
46 | 46 | "@commitlint/cli": "^11.0.0", |
47 | 47 | "@commitlint/config-conventional": "^11.0.0", |
48 | - "@iconify/json": "^1.1.286", | |
48 | + "@iconify/json": "^1.1.287", | |
49 | 49 | "@ls-lint/ls-lint": "^1.9.2", |
50 | 50 | "@purge-icons/generated": "^0.5.1", |
51 | 51 | "@types/echarts": "^4.9.3", |
52 | 52 | "@types/fs-extra": "^9.0.6", |
53 | - "@types/http-proxy": "^1.17.4", | |
53 | + "@types/http-proxy": "^1.17.5", | |
54 | 54 | "@types/koa-static": "^4.0.1", |
55 | 55 | "@types/lodash-es": "^4.17.4", |
56 | 56 | "@types/mockjs": "^1.0.3", |
... | ... | @@ -63,24 +63,24 @@ |
63 | 63 | "@typescript-eslint/eslint-plugin": "^4.13.0", |
64 | 64 | "@typescript-eslint/parser": "^4.13.0", |
65 | 65 | "@vitejs/plugin-legacy": "^1.2.1", |
66 | - "@vitejs/plugin-vue": "^1.0.5", | |
66 | + "@vitejs/plugin-vue": "^1.0.6", | |
67 | 67 | "@vitejs/plugin-vue-jsx": "^1.0.2", |
68 | 68 | "@vue/compiler-sfc": "^3.0.5", |
69 | 69 | "@vuedx/typecheck": "^0.5.0", |
70 | 70 | "@vuedx/typescript-plugin-vue": "^0.5.0", |
71 | 71 | "autoprefixer": "^10.2.1", |
72 | - "commitizen": "^4.2.2", | |
72 | + "commitizen": "^4.2.3", | |
73 | 73 | "conventional-changelog-cli": "^2.1.1", |
74 | 74 | "conventional-changelog-custom-config": "^0.3.1", |
75 | 75 | "cross-env": "^7.0.3", |
76 | 76 | "dotenv": "^8.2.0", |
77 | - "eslint": "^7.17.0", | |
77 | + "eslint": "^7.18.0", | |
78 | 78 | "eslint-config-prettier": "^7.1.0", |
79 | 79 | "eslint-plugin-prettier": "^3.3.1", |
80 | 80 | "eslint-plugin-vue": "^7.4.1", |
81 | 81 | "esno": "^0.4.0", |
82 | 82 | "fs-extra": "^9.0.1", |
83 | - "husky": "^4.3.7", | |
83 | + "husky": "^4.3.8", | |
84 | 84 | "koa-static": "^5.0.0", |
85 | 85 | "less": "^4.1.0", |
86 | 86 | "lint-staged": "^10.5.3", |
... | ... | @@ -96,11 +96,11 @@ |
96 | 96 | "stylelint-order": "^4.1.0", |
97 | 97 | "ts-node": "^9.1.0", |
98 | 98 | "typescript": "^4.1.3", |
99 | - "vite": "^2.0.0-beta.27", | |
99 | + "vite": "^2.0.0-beta.30", | |
100 | 100 | "vite-plugin-html": "^2.0.0-beta.5", |
101 | 101 | "vite-plugin-mock": "^2.0.0-beta.3", |
102 | 102 | "vite-plugin-purge-icons": "^0.5.1", |
103 | - "vite-plugin-pwa": "^0.3.6", | |
103 | + "vite-plugin-pwa": "^0.3.8", | |
104 | 104 | "vue-eslint-parser": "^7.3.0", |
105 | 105 | "yargs": "^16.2.0" |
106 | 106 | }, | ... | ... |
src/components/Application/src/search/AppSearchModal.vue
... | ... | @@ -2,54 +2,52 @@ |
2 | 2 | <Teleport to="body"> |
3 | 3 | <transition name="zoom-fade" mode="out-in"> |
4 | 4 | <div :class="getClass" @click.stop v-if="visible"> |
5 | - <ClickOutSide @clickOutside="handleClose"> | |
6 | - <div :class="`${prefixCls}-content`"> | |
7 | - <div :class="`${prefixCls}-input__wrapper`"> | |
8 | - <a-input | |
9 | - :class="`${prefixCls}-input`" | |
10 | - :placeholder="t('common.searchText')" | |
11 | - allow-clear | |
12 | - @change="handleSearch" | |
13 | - > | |
14 | - <template #prefix> | |
15 | - <SearchOutlined /> | |
16 | - </template> | |
17 | - </a-input> | |
18 | - <span :class="`${prefixCls}-cancel`" @click="handleClose">{{ | |
19 | - t('common.cancelText') | |
20 | - }}</span> | |
21 | - </div> | |
5 | + <div :class="`${prefixCls}-content`" v-click-outside="handleClose"> | |
6 | + <div :class="`${prefixCls}-input__wrapper`"> | |
7 | + <a-input | |
8 | + :class="`${prefixCls}-input`" | |
9 | + :placeholder="t('common.searchText')" | |
10 | + allow-clear | |
11 | + @change="handleSearch" | |
12 | + > | |
13 | + <template #prefix> | |
14 | + <SearchOutlined /> | |
15 | + </template> | |
16 | + </a-input> | |
17 | + <span :class="`${prefixCls}-cancel`" @click="handleClose">{{ | |
18 | + t('common.cancelText') | |
19 | + }}</span> | |
20 | + </div> | |
22 | 21 | |
23 | - <div :class="`${prefixCls}-not-data`" v-show="getIsNotData"> | |
24 | - {{ t('component.app.searchNotData') }} | |
25 | - </div> | |
26 | - <ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap"> | |
27 | - <li | |
28 | - :ref="setRefs(index)" | |
29 | - v-for="(item, index) in searchResult" | |
30 | - :key="item.path" | |
31 | - :data-index="index" | |
32 | - @mouseenter="handleMouseenter" | |
33 | - @click="handleEnter" | |
34 | - :class="[ | |
35 | - `${prefixCls}-list__item`, | |
36 | - { | |
37 | - [`${prefixCls}-list__item--active`]: activeIndex === index, | |
38 | - }, | |
39 | - ]" | |
40 | - > | |
41 | - <div :class="`${prefixCls}-list__item-icon`"> | |
42 | - <g-icon :icon="item.icon || 'mdi:form-select'" :size="20" /> | |
43 | - </div> | |
44 | - <div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div> | |
45 | - <div :class="`${prefixCls}-list__item-enter`"> | |
46 | - <g-icon icon="ant-design:enter-outlined" :size="20" /> | |
47 | - </div> | |
48 | - </li> | |
49 | - </ul> | |
50 | - <AppSearchFooter /> | |
22 | + <div :class="`${prefixCls}-not-data`" v-show="getIsNotData"> | |
23 | + {{ t('component.app.searchNotData') }} | |
51 | 24 | </div> |
52 | - </ClickOutSide> | |
25 | + <ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap"> | |
26 | + <li | |
27 | + :ref="setRefs(index)" | |
28 | + v-for="(item, index) in searchResult" | |
29 | + :key="item.path" | |
30 | + :data-index="index" | |
31 | + @mouseenter="handleMouseenter" | |
32 | + @click="handleEnter" | |
33 | + :class="[ | |
34 | + `${prefixCls}-list__item`, | |
35 | + { | |
36 | + [`${prefixCls}-list__item--active`]: activeIndex === index, | |
37 | + }, | |
38 | + ]" | |
39 | + > | |
40 | + <div :class="`${prefixCls}-list__item-icon`"> | |
41 | + <g-icon :icon="item.icon || 'mdi:form-select'" :size="20" /> | |
42 | + </div> | |
43 | + <div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div> | |
44 | + <div :class="`${prefixCls}-list__item-enter`"> | |
45 | + <g-icon icon="ant-design:enter-outlined" :size="20" /> | |
46 | + </div> | |
47 | + </li> | |
48 | + </ul> | |
49 | + <AppSearchFooter /> | |
50 | + </div> | |
53 | 51 | </div> |
54 | 52 | </transition> |
55 | 53 | </Teleport> |
... | ... | @@ -63,17 +61,20 @@ |
63 | 61 | import { SearchOutlined } from '@ant-design/icons-vue'; |
64 | 62 | import AppSearchFooter from './AppSearchFooter.vue'; |
65 | 63 | import { useI18n } from '/@/hooks/web/useI18n'; |
66 | - import { ClickOutSide } from '/@/components/ClickOutSide'; | |
67 | 64 | import { useAppInject } from '/@/hooks/web/useAppInject'; |
65 | + import clickOutside from '/@/directives/clickOutside'; | |
68 | 66 | |
69 | 67 | export default defineComponent({ |
70 | 68 | name: 'AppSearchModal', |
71 | - components: { SearchOutlined, ClickOutSide, AppSearchFooter }, | |
69 | + components: { SearchOutlined, AppSearchFooter }, | |
72 | 70 | emits: ['close'], |
73 | 71 | |
74 | 72 | props: { |
75 | 73 | visible: Boolean, |
76 | 74 | }, |
75 | + directives: { | |
76 | + clickOutside, | |
77 | + }, | |
77 | 78 | setup(_, { emit }) { |
78 | 79 | const scrollWrap = ref<ElRef>(null); |
79 | 80 | const { prefixCls } = useDesign('app-search-modal'); | ... | ... |
src/components/MenuPlus/index.ts deleted
100644 → 0
1 | -export { default as Menu } from './src/index.vue'; |
src/components/MenuPlus/src/index.vue deleted
100644 → 0
1 | -<template> | |
2 | - <ul :class="getClass" :style="getStyle"> | |
3 | - <slot></slot> | |
4 | - </ul> | |
5 | -</template> | |
6 | - | |
7 | -<script lang="ts"> | |
8 | - import { defineComponent, ref, computed, CSSProperties, unref } from 'vue'; | |
9 | - import { useDesign } from '/@/hooks/web/useDesign'; | |
10 | - import { propTypes } from '/@/utils/propTypes'; | |
11 | - export default defineComponent({ | |
12 | - props: { | |
13 | - mode: propTypes.oneOf(['horizontal', 'vertical']).def('vertical'), | |
14 | - theme: propTypes.oneOf(['light', 'dark', 'primary']).def('light'), | |
15 | - activeName: propTypes.oneOfType([propTypes.string, propTypes.number]), | |
16 | - openNames: propTypes.array.def([]), | |
17 | - accordion: propTypes.bool, | |
18 | - width: propTypes.string.def('210px'), | |
19 | - }, | |
20 | - setup(props) { | |
21 | - const currentActiveName = ref(props.activeName); | |
22 | - const openedNames = ref<string[]>(); | |
23 | - | |
24 | - const { prefixCls } = useDesign('menu'); | |
25 | - | |
26 | - const getClass = computed(() => { | |
27 | - const { theme, mode } = props; | |
28 | - let curTheme = theme; | |
29 | - if (mode === 'vertical' && theme === 'primary') { | |
30 | - curTheme = 'light'; | |
31 | - } | |
32 | - return [ | |
33 | - prefixCls, | |
34 | - `${prefixCls}-${curTheme}`, | |
35 | - { | |
36 | - [`${prefixCls}-${mode}`]: mode, | |
37 | - }, | |
38 | - ]; | |
39 | - }); | |
40 | - | |
41 | - const getStyle = computed( | |
42 | - (): CSSProperties => { | |
43 | - const { mode, width } = props; | |
44 | - if (mode === 'vertical') { | |
45 | - return { | |
46 | - width: width, | |
47 | - }; | |
48 | - } | |
49 | - return {}; | |
50 | - } | |
51 | - ); | |
52 | - | |
53 | - function updateActiveName() { | |
54 | - if (unref(currentActiveName) === undefined) { | |
55 | - currentActiveName.value = -1; | |
56 | - } | |
57 | - } | |
58 | - | |
59 | - function updateOpened() {} | |
60 | - | |
61 | - return { getClass, getStyle }; | |
62 | - }, | |
63 | - }); | |
64 | -</script> |
src/components/SimpleMenu/index.ts
0 → 100644
1 | +export { default as SimpleMenu } from './src/SimpleMenu.vue'; | ... | ... |
src/components/SimpleMenu/src/SimpleMenu.vue
0 → 100644
1 | +<template> | |
2 | + <Menu | |
3 | + v-bind="getBindValues" | |
4 | + @select="handleSelect" | |
5 | + :activeName="activeName" | |
6 | + :openNames="openNames" | |
7 | + :class="prefixCls" | |
8 | + :activeSubMenuNames="activeSubMenuNames" | |
9 | + > | |
10 | + <template v-for="item in items" :key="item.path"> | |
11 | + <SimpleSubMenu | |
12 | + :item="item" | |
13 | + :parent="true" | |
14 | + :collapsedShowTitle="collapsedShowTitle" | |
15 | + :collapse="collapse" | |
16 | + /> | |
17 | + </template> | |
18 | + </Menu> | |
19 | +</template> | |
20 | +<script lang="ts"> | |
21 | + import type { PropType } from 'vue'; | |
22 | + import type { MenuState } from './types'; | |
23 | + import type { Menu as MenuType } from '/@/router/types'; | |
24 | + | |
25 | + import { defineComponent, computed, ref, unref, reactive, toRefs, watch } from 'vue'; | |
26 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
27 | + | |
28 | + import Menu from './components/Menu.vue'; | |
29 | + import SimpleSubMenu from './SimpleSubMenu.vue'; | |
30 | + import { listenerLastChangeTab } from '/@/logics/mitt/tabChange'; | |
31 | + import { propTypes } from '/@/utils/propTypes'; | |
32 | + import { REDIRECT_NAME } from '/@/router/constant'; | |
33 | + import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router'; | |
34 | + import { isFunction } from '/@/utils/is'; | |
35 | + | |
36 | + import { useOpenKeys } from './useOpenKeys'; | |
37 | + export default defineComponent({ | |
38 | + name: 'SimpleMenu', | |
39 | + inheritAttrs: false, | |
40 | + components: { | |
41 | + Menu, | |
42 | + SimpleSubMenu, | |
43 | + }, | |
44 | + props: { | |
45 | + items: { | |
46 | + type: Array as PropType<MenuType[]>, | |
47 | + default: () => [], | |
48 | + }, | |
49 | + collapse: propTypes.bool, | |
50 | + mixSider: propTypes.bool, | |
51 | + theme: propTypes.string, | |
52 | + accordion: propTypes.bool.def(true), | |
53 | + collapsedShowTitle: propTypes.bool, | |
54 | + beforeClickFn: { | |
55 | + type: Function as PropType<(key: string) => Promise<boolean>>, | |
56 | + }, | |
57 | + }, | |
58 | + setup(props, { attrs, emit }) { | |
59 | + const currentActiveMenu = ref(''); | |
60 | + const isClickGo = ref(false); | |
61 | + | |
62 | + const menuState = reactive<MenuState>({ | |
63 | + activeName: '', | |
64 | + openNames: [], | |
65 | + activeSubMenuNames: [], | |
66 | + }); | |
67 | + | |
68 | + const { currentRoute } = useRouter(); | |
69 | + const { prefixCls } = useDesign('simple-menu'); | |
70 | + const { items, accordion, mixSider } = toRefs(props); | |
71 | + const { setOpenKeys } = useOpenKeys(menuState, items, accordion, mixSider); | |
72 | + | |
73 | + const getBindValues = computed(() => ({ ...attrs, ...props })); | |
74 | + | |
75 | + watch( | |
76 | + () => props.collapse, | |
77 | + (collapse) => { | |
78 | + if (collapse) { | |
79 | + menuState.openNames = []; | |
80 | + } else { | |
81 | + setOpenKeys(currentRoute.value.path); | |
82 | + } | |
83 | + }, | |
84 | + { immediate: true } | |
85 | + ); | |
86 | + | |
87 | + listenerLastChangeTab((route) => { | |
88 | + if (route.name === REDIRECT_NAME) return; | |
89 | + | |
90 | + currentActiveMenu.value = route.meta?.currentActiveMenu; | |
91 | + handleMenuChange(route); | |
92 | + | |
93 | + if (unref(currentActiveMenu)) { | |
94 | + menuState.activeName = unref(currentActiveMenu); | |
95 | + setOpenKeys(unref(currentActiveMenu)); | |
96 | + } | |
97 | + }); | |
98 | + | |
99 | + async function handleMenuChange(route?: RouteLocationNormalizedLoaded) { | |
100 | + if (unref(isClickGo)) { | |
101 | + isClickGo.value = false; | |
102 | + return; | |
103 | + } | |
104 | + const path = (route || unref(currentRoute)).path; | |
105 | + menuState.activeName = path; | |
106 | + | |
107 | + setOpenKeys(path); | |
108 | + // if (unref(currentActiveMenu)) return; | |
109 | + } | |
110 | + | |
111 | + async function handleSelect(key: string) { | |
112 | + const { beforeClickFn } = props; | |
113 | + if (beforeClickFn && isFunction(beforeClickFn)) { | |
114 | + const flag = await beforeClickFn(key); | |
115 | + if (!flag) return; | |
116 | + } | |
117 | + emit('menuClick', key); | |
118 | + | |
119 | + isClickGo.value = true; | |
120 | + setOpenKeys(key); | |
121 | + menuState.activeName = key; | |
122 | + } | |
123 | + | |
124 | + return { | |
125 | + prefixCls, | |
126 | + getBindValues, | |
127 | + handleSelect, | |
128 | + ...toRefs(menuState), | |
129 | + }; | |
130 | + }, | |
131 | + }); | |
132 | +</script> | |
133 | +<style lang="less"> | |
134 | + @import './index.less'; | |
135 | +</style> | ... | ... |
src/components/SimpleMenu/src/SimpleMenuTag.vue
0 → 100644
1 | +<template> | |
2 | + <span :class="getTagClass" v-if="getShowTag">{{ getContent }}</span> | |
3 | +</template> | |
4 | +<script lang="ts"> | |
5 | + import type { Menu } from '/@/router/types'; | |
6 | + import type { PropType } from 'vue'; | |
7 | + | |
8 | + import { defineComponent, computed } from 'vue'; | |
9 | + | |
10 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
11 | + | |
12 | + export default defineComponent({ | |
13 | + name: 'SimpleMenuTag', | |
14 | + props: { | |
15 | + item: { | |
16 | + type: Object as PropType<Menu>, | |
17 | + default: {}, | |
18 | + }, | |
19 | + collapseParent: { | |
20 | + type: Boolean as PropType<boolean>, | |
21 | + default: false, | |
22 | + }, | |
23 | + }, | |
24 | + setup(props) { | |
25 | + const { prefixCls } = useDesign('simple-menu'); | |
26 | + | |
27 | + const getShowTag = computed(() => { | |
28 | + const { item } = props; | |
29 | + | |
30 | + if (!item) return false; | |
31 | + | |
32 | + const { tag } = item; | |
33 | + if (!tag) return false; | |
34 | + | |
35 | + const { dot, content } = tag; | |
36 | + if (!dot && !content) return false; | |
37 | + return true; | |
38 | + }); | |
39 | + | |
40 | + const getContent = computed(() => { | |
41 | + if (!getShowTag.value) return ''; | |
42 | + const { item, collapseParent } = props; | |
43 | + const { tag } = item; | |
44 | + const { dot, content } = tag!; | |
45 | + return dot || collapseParent ? '' : content; | |
46 | + }); | |
47 | + | |
48 | + const getTagClass = computed(() => { | |
49 | + const { item, collapseParent } = props; | |
50 | + const { tag = {} } = item || {}; | |
51 | + const { dot, type = 'error' } = tag; | |
52 | + const tagCls = `${prefixCls}-tag`; | |
53 | + return [ | |
54 | + tagCls, | |
55 | + | |
56 | + [`${tagCls}--${type}`], | |
57 | + { | |
58 | + [`${tagCls}--collapse`]: collapseParent, | |
59 | + [`${tagCls}--dot`]: dot, | |
60 | + }, | |
61 | + ]; | |
62 | + }); | |
63 | + return { | |
64 | + getTagClass, | |
65 | + getShowTag, | |
66 | + getContent, | |
67 | + }; | |
68 | + }, | |
69 | + }); | |
70 | +</script> | ... | ... |
src/components/SimpleMenu/src/SimpleSubMenu.vue
0 → 100644
1 | +<template> | |
2 | + <MenuItem | |
3 | + :name="item.path" | |
4 | + v-if="!menuHasChildren(item) && getShowMenu" | |
5 | + v-bind="$props" | |
6 | + :class="getLevelClass" | |
7 | + > | |
8 | + <Icon v-if="getIcon" :icon="getIcon" :size="16" /> | |
9 | + <div v-if="collapsedShowTitle && getIsCollapseParent" class="mt-1 collapse-title"> | |
10 | + {{ getI18nName }} | |
11 | + </div> | |
12 | + <template #title> | |
13 | + <span :class="['ml-2']"> | |
14 | + {{ getI18nName }} | |
15 | + </span> | |
16 | + <SimpleMenuTag :item="item" :collapseParent="getIsCollapseParent" /> | |
17 | + </template> | |
18 | + </MenuItem> | |
19 | + <SubMenu | |
20 | + :name="item.path" | |
21 | + v-if="menuHasChildren(item) && getShowMenu" | |
22 | + :class="[getLevelClass, theme]" | |
23 | + :collapsedShowTitle="collapsedShowTitle" | |
24 | + > | |
25 | + <template #title> | |
26 | + <Icon v-if="getIcon" :icon="getIcon" :size="16" /> | |
27 | + | |
28 | + <div v-if="collapsedShowTitle && getIsCollapseParent" class="mt-2 collapse-title"> | |
29 | + {{ getI18nName }} | |
30 | + </div> | |
31 | + | |
32 | + <span v-show="getShowSubTitle" :class="['ml-2', `${prefixCls}-sub-title`]"> | |
33 | + {{ getI18nName }} | |
34 | + </span> | |
35 | + <SimpleMenuTag :item="item" :collapseParent="!!collapse && !!parent" /> | |
36 | + </template> | |
37 | + <template v-for="childrenItem in item.children || []" :key="childrenItem.path"> | |
38 | + <SimpleSubMenu v-bind="$props" :item="childrenItem" :parent="false" /> | |
39 | + </template> | |
40 | + </SubMenu> | |
41 | +</template> | |
42 | +<script lang="ts"> | |
43 | + import type { PropType } from 'vue'; | |
44 | + import type { Menu } from '/@/router/types'; | |
45 | + | |
46 | + import { defineComponent, computed } from 'vue'; | |
47 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
48 | + import Icon from '/@/components/Icon/index'; | |
49 | + | |
50 | + import MenuItem from './components/MenuItem.vue'; | |
51 | + import SubMenu from './components/SubMenuItem.vue'; | |
52 | + import { propTypes } from '/@/utils/propTypes'; | |
53 | + import { useI18n } from '/@/hooks/web/useI18n'; | |
54 | + import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; | |
55 | + const { t } = useI18n(); | |
56 | + | |
57 | + export default defineComponent({ | |
58 | + name: 'SimpleSubMenu', | |
59 | + components: { | |
60 | + SubMenu, | |
61 | + MenuItem, | |
62 | + SimpleMenuTag: createAsyncComponent(() => import('./SimpleMenuTag.vue')), | |
63 | + Icon, | |
64 | + }, | |
65 | + props: { | |
66 | + item: { | |
67 | + type: Object as PropType<Menu>, | |
68 | + default: {}, | |
69 | + }, | |
70 | + parent: propTypes.bool, | |
71 | + collapsedShowTitle: propTypes.bool, | |
72 | + collapse: propTypes.bool, | |
73 | + theme: propTypes.oneOf(['dark', 'light']), | |
74 | + }, | |
75 | + setup(props) { | |
76 | + const { prefixCls } = useDesign('simple-menu'); | |
77 | + | |
78 | + const getShowMenu = computed(() => { | |
79 | + return !props.item.meta?.hideMenu; | |
80 | + }); | |
81 | + | |
82 | + const getIcon = computed(() => props.item?.icon); | |
83 | + const getI18nName = computed(() => t(props.item?.name)); | |
84 | + const getShowSubTitle = computed(() => !props.collapse || !props.parent); | |
85 | + const getIsCollapseParent = computed(() => !!props.collapse && !!props.parent); | |
86 | + const getLevelClass = computed(() => { | |
87 | + return [ | |
88 | + { | |
89 | + [`${prefixCls}__parent`]: props.parent, | |
90 | + [`${prefixCls}__children`]: !props.parent, | |
91 | + }, | |
92 | + ]; | |
93 | + }); | |
94 | + | |
95 | + function menuHasChildren(menuTreeItem: Menu): boolean { | |
96 | + return ( | |
97 | + Reflect.has(menuTreeItem, 'children') && | |
98 | + !!menuTreeItem.children && | |
99 | + menuTreeItem.children.length > 0 | |
100 | + ); | |
101 | + } | |
102 | + | |
103 | + return { | |
104 | + prefixCls, | |
105 | + menuHasChildren, | |
106 | + getShowMenu, | |
107 | + getIcon, | |
108 | + getI18nName, | |
109 | + getShowSubTitle, | |
110 | + getLevelClass, | |
111 | + getIsCollapseParent, | |
112 | + }; | |
113 | + }, | |
114 | + }); | |
115 | +</script> | ... | ... |
src/components/SimpleMenu/src/components/Menu.vue
0 → 100644
1 | +<template> | |
2 | + <ul :class="getClass"> | |
3 | + <slot></slot> | |
4 | + </ul> | |
5 | +</template> | |
6 | + | |
7 | +<script lang="ts"> | |
8 | + import type { PropType } from 'vue'; | |
9 | + import type { SubMenuProvider } from './types'; | |
10 | + import { | |
11 | + defineComponent, | |
12 | + ref, | |
13 | + computed, | |
14 | + onMounted, | |
15 | + watchEffect, | |
16 | + watch, | |
17 | + nextTick, | |
18 | + getCurrentInstance, | |
19 | + provide, | |
20 | + } from 'vue'; | |
21 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
22 | + import { propTypes } from '/@/utils/propTypes'; | |
23 | + import { createSimpleRootMenuContext } from './useSimpleMenuContext'; | |
24 | + import Mitt from '/@/utils/mitt'; | |
25 | + import { isString } from '/@/utils/is'; | |
26 | + export default defineComponent({ | |
27 | + name: 'Menu', | |
28 | + props: { | |
29 | + theme: propTypes.oneOf(['light', 'dark']).def('light'), | |
30 | + activeName: propTypes.oneOfType([propTypes.string, propTypes.number]), | |
31 | + openNames: { | |
32 | + type: Array as PropType<string[]>, | |
33 | + default: [], | |
34 | + }, | |
35 | + accordion: propTypes.bool.def(true), | |
36 | + width: propTypes.string.def('100%'), | |
37 | + collapsedWidth: propTypes.string.def('48px'), | |
38 | + indentSize: propTypes.number.def(16), | |
39 | + collapse: propTypes.bool.def(true), | |
40 | + activeSubMenuNames: { | |
41 | + type: Array as PropType<(string | number)[]>, | |
42 | + default: [], | |
43 | + }, | |
44 | + }, | |
45 | + emits: ['select', 'open-change'], | |
46 | + setup(props, { emit }) { | |
47 | + const rootMenuEmitter = new Mitt(); | |
48 | + const instance = getCurrentInstance(); | |
49 | + | |
50 | + const currentActiveName = ref<string | number>(''); | |
51 | + const openedNames = ref<string[]>([]); | |
52 | + | |
53 | + const { prefixCls } = useDesign('menu'); | |
54 | + | |
55 | + const isRemoveAllPopup = ref(false); | |
56 | + | |
57 | + createSimpleRootMenuContext({ | |
58 | + rootMenuEmitter: rootMenuEmitter, | |
59 | + activeName: currentActiveName, | |
60 | + }); | |
61 | + | |
62 | + const getClass = computed(() => { | |
63 | + const { theme } = props; | |
64 | + return [ | |
65 | + prefixCls, | |
66 | + `${prefixCls}-${theme}`, | |
67 | + `${prefixCls}-vertical`, | |
68 | + { | |
69 | + [`${prefixCls}-collapse`]: props.collapse, | |
70 | + }, | |
71 | + ]; | |
72 | + }); | |
73 | + | |
74 | + watchEffect(() => { | |
75 | + openedNames.value = props.openNames; | |
76 | + }); | |
77 | + | |
78 | + watchEffect(() => { | |
79 | + if (props.activeName) { | |
80 | + currentActiveName.value = props.activeName; | |
81 | + } | |
82 | + }); | |
83 | + | |
84 | + watch( | |
85 | + () => props.openNames, | |
86 | + () => { | |
87 | + nextTick(() => { | |
88 | + updateOpened(); | |
89 | + }); | |
90 | + } | |
91 | + ); | |
92 | + | |
93 | + function updateOpened() { | |
94 | + rootMenuEmitter.emit('on-update-opened', openedNames.value); | |
95 | + } | |
96 | + | |
97 | + function addSubMenu(name: string) { | |
98 | + if (openedNames.value.includes(name)) return; | |
99 | + openedNames.value.push(name); | |
100 | + updateOpened(); | |
101 | + } | |
102 | + | |
103 | + function removeSubMenu(name: string) { | |
104 | + openedNames.value = openedNames.value.filter((item) => item !== name); | |
105 | + updateOpened(); | |
106 | + } | |
107 | + | |
108 | + function removeAll() { | |
109 | + openedNames.value = []; | |
110 | + updateOpened(); | |
111 | + } | |
112 | + | |
113 | + function sliceIndex(index: number) { | |
114 | + if (index === -1) return; | |
115 | + openedNames.value = openedNames.value.slice(0, index + 1); | |
116 | + updateOpened(); | |
117 | + } | |
118 | + | |
119 | + provide<SubMenuProvider>(`subMenu:${instance?.uid}`, { | |
120 | + addSubMenu, | |
121 | + removeSubMenu, | |
122 | + getOpenNames: () => openedNames.value, | |
123 | + removeAll, | |
124 | + isRemoveAllPopup, | |
125 | + sliceIndex, | |
126 | + level: 0, | |
127 | + props, | |
128 | + }); | |
129 | + | |
130 | + onMounted(() => { | |
131 | + openedNames.value = !props.collapse ? [...props.openNames] : []; | |
132 | + updateOpened(); | |
133 | + rootMenuEmitter.on('on-menu-item-select', (name: string) => { | |
134 | + currentActiveName.value = name; | |
135 | + | |
136 | + nextTick(() => { | |
137 | + props.collapse && removeAll(); | |
138 | + }); | |
139 | + emit('select', name); | |
140 | + }); | |
141 | + }); | |
142 | + | |
143 | + return { getClass, openedNames }; | |
144 | + }, | |
145 | + }); | |
146 | +</script> | |
147 | +<style lang="less"> | |
148 | + @import './menu.less'; | |
149 | +</style> | ... | ... |
src/components/SimpleMenu/src/components/MenuCollapseTransition.vue
0 → 100644
1 | +<template> | |
2 | + <transition mode="out-in" v-on="on"> | |
3 | + <slot></slot> | |
4 | + </transition> | |
5 | +</template> | |
6 | +<script lang="ts"> | |
7 | + import { defineComponent } from 'vue'; | |
8 | + import { addClass, removeClass } from '/@/utils/domUtils'; | |
9 | + | |
10 | + export default defineComponent({ | |
11 | + name: 'MenuCollapseTransition', | |
12 | + setup() { | |
13 | + return { | |
14 | + on: { | |
15 | + beforeEnter(el: any) { | |
16 | + addClass(el, 'collapse-transition'); | |
17 | + if (!el.dataset) el.dataset = {}; | |
18 | + | |
19 | + el.dataset.oldPaddingTop = el.style.paddingTop; | |
20 | + el.dataset.oldPaddingBottom = el.style.paddingBottom; | |
21 | + | |
22 | + el.style.height = '0'; | |
23 | + el.style.paddingTop = 0; | |
24 | + el.style.paddingBottom = 0; | |
25 | + }, | |
26 | + | |
27 | + enter(el: any) { | |
28 | + el.dataset.oldOverflow = el.style.overflow; | |
29 | + if (el.scrollHeight !== 0) { | |
30 | + el.style.height = el.scrollHeight + 'px'; | |
31 | + el.style.paddingTop = el.dataset.oldPaddingTop; | |
32 | + el.style.paddingBottom = el.dataset.oldPaddingBottom; | |
33 | + } else { | |
34 | + el.style.height = ''; | |
35 | + el.style.paddingTop = el.dataset.oldPaddingTop; | |
36 | + el.style.paddingBottom = el.dataset.oldPaddingBottom; | |
37 | + } | |
38 | + | |
39 | + el.style.overflow = 'hidden'; | |
40 | + }, | |
41 | + | |
42 | + afterEnter(el: any) { | |
43 | + removeClass(el, 'collapse-transition'); | |
44 | + el.style.height = ''; | |
45 | + el.style.overflow = el.dataset.oldOverflow; | |
46 | + }, | |
47 | + | |
48 | + beforeLeave(el: any) { | |
49 | + if (!el.dataset) el.dataset = {}; | |
50 | + el.dataset.oldPaddingTop = el.style.paddingTop; | |
51 | + el.dataset.oldPaddingBottom = el.style.paddingBottom; | |
52 | + el.dataset.oldOverflow = el.style.overflow; | |
53 | + | |
54 | + el.style.height = el.scrollHeight + 'px'; | |
55 | + el.style.overflow = 'hidden'; | |
56 | + }, | |
57 | + | |
58 | + leave(el: any) { | |
59 | + if (el.scrollHeight !== 0) { | |
60 | + addClass(el, 'collapse-transition'); | |
61 | + el.style.height = 0; | |
62 | + el.style.paddingTop = 0; | |
63 | + el.style.paddingBottom = 0; | |
64 | + } | |
65 | + }, | |
66 | + | |
67 | + afterLeave(el: any) { | |
68 | + removeClass(el, 'collapse-transition'); | |
69 | + el.style.height = ''; | |
70 | + el.style.overflow = el.dataset.oldOverflow; | |
71 | + el.style.paddingTop = el.dataset.oldPaddingTop; | |
72 | + el.style.paddingBottom = el.dataset.oldPaddingBottom; | |
73 | + }, | |
74 | + }, | |
75 | + }; | |
76 | + }, | |
77 | + }); | |
78 | +</script> | ... | ... |
src/components/SimpleMenu/src/components/MenuItem.vue
0 → 100644
1 | +<template> | |
2 | + <li :class="getClass" @click.stop="handleClickItem" :style="getCollapse ? {} : getItemStyle"> | |
3 | + <Tooltip placement="right" v-if="showTooptip"> | |
4 | + <template #title> | |
5 | + <slot name="title"></slot> | |
6 | + </template> | |
7 | + <div :class="`${prefixCls}-tooltip`"> | |
8 | + <slot /> | |
9 | + </div> | |
10 | + </Tooltip> | |
11 | + | |
12 | + <template v-else> | |
13 | + <slot></slot> | |
14 | + <slot name="title"></slot> | |
15 | + </template> | |
16 | + </li> | |
17 | +</template> | |
18 | + | |
19 | +<script lang="ts"> | |
20 | + import { PropType } from 'vue'; | |
21 | + import { defineComponent, ref, computed, unref, getCurrentInstance, watch } from 'vue'; | |
22 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
23 | + import { propTypes } from '/@/utils/propTypes'; | |
24 | + import { useMenuItem } from './useMenu'; | |
25 | + import { Tooltip } from 'ant-design-vue'; | |
26 | + import { useSimpleRootMenuContext } from './useSimpleMenuContext'; | |
27 | + export default defineComponent({ | |
28 | + name: 'MenuItem', | |
29 | + components: { Tooltip }, | |
30 | + props: { | |
31 | + name: { | |
32 | + type: [String, Number] as PropType<string | number>, | |
33 | + required: true, | |
34 | + }, | |
35 | + disabled: propTypes.bool, | |
36 | + }, | |
37 | + setup(props, { slots }) { | |
38 | + const instance = getCurrentInstance(); | |
39 | + | |
40 | + const active = ref(false); | |
41 | + | |
42 | + const { getItemStyle, getParentList, getParentMenu, getParentRootMenu } = useMenuItem( | |
43 | + instance | |
44 | + ); | |
45 | + | |
46 | + const { prefixCls } = useDesign('menu'); | |
47 | + | |
48 | + const { rootMenuEmitter, activeName } = useSimpleRootMenuContext(); | |
49 | + | |
50 | + const getClass = computed(() => { | |
51 | + return [ | |
52 | + `${prefixCls}-item`, | |
53 | + { | |
54 | + [`${prefixCls}-item-active`]: unref(active), | |
55 | + [`${prefixCls}-item-selected`]: unref(active), | |
56 | + [`${prefixCls}-item-disabled`]: !!props.disabled, | |
57 | + }, | |
58 | + ]; | |
59 | + }); | |
60 | + | |
61 | + const getCollapse = computed(() => unref(getParentRootMenu)?.props.collapse); | |
62 | + | |
63 | + const showTooptip = computed(() => { | |
64 | + return unref(getParentMenu)?.type.name === 'Menu' && unref(getCollapse) && slots.title; | |
65 | + }); | |
66 | + | |
67 | + function handleClickItem() { | |
68 | + const { disabled } = props; | |
69 | + if (disabled) return; | |
70 | + | |
71 | + rootMenuEmitter.emit('on-menu-item-select', props.name); | |
72 | + if (unref(getCollapse)) return; | |
73 | + const { uidList } = getParentList(); | |
74 | + rootMenuEmitter.emit('on-update-opened', { | |
75 | + opend: false, | |
76 | + parent: instance?.parent, | |
77 | + uidList: uidList, | |
78 | + }); | |
79 | + } | |
80 | + watch( | |
81 | + () => activeName.value, | |
82 | + (name: string) => { | |
83 | + if (name === props.name) { | |
84 | + const { list, uidList } = getParentList(); | |
85 | + active.value = true; | |
86 | + list.forEach((item) => { | |
87 | + if (item.proxy) { | |
88 | + (item.proxy as any).active = true; | |
89 | + } | |
90 | + }); | |
91 | + | |
92 | + rootMenuEmitter.emit('on-update-active-name:submenu', uidList); | |
93 | + } else { | |
94 | + active.value = false; | |
95 | + } | |
96 | + }, | |
97 | + { immediate: true } | |
98 | + ); | |
99 | + | |
100 | + return { getClass, prefixCls, getItemStyle, getCollapse, handleClickItem, showTooptip }; | |
101 | + }, | |
102 | + }); | |
103 | +</script> | ... | ... |
src/components/SimpleMenu/src/components/SubMenuItem.vue
0 → 100644
1 | +<template> | |
2 | + <li :class="getClass"> | |
3 | + <template v-if="!getCollapse"> | |
4 | + <div :class="`${prefixCls}-submenu-title`" @click.stop="handleClick" :style="getItemStyle"> | |
5 | + <slot name="title"></slot> | |
6 | + <Icon | |
7 | + icon="eva:arrow-ios-downward-outline" | |
8 | + :size="14" | |
9 | + :class="`${prefixCls}-submenu-title-icon`" | |
10 | + /> | |
11 | + </div> | |
12 | + <MenuCollapseTransition> | |
13 | + <ul :class="prefixCls" v-show="opened"> | |
14 | + <slot></slot> | |
15 | + </ul> | |
16 | + </MenuCollapseTransition> | |
17 | + </template> | |
18 | + | |
19 | + <Popover | |
20 | + placement="right" | |
21 | + :overlayClassName="`${prefixCls}-menu-popover`" | |
22 | + v-else | |
23 | + :visible="getIsOpend" | |
24 | + @visibleChange="handleVisibleChange" | |
25 | + :overlayStyle="getOverlayStyle" | |
26 | + :align="{ offset: [0, 0] }" | |
27 | + > | |
28 | + <div :class="getSubClass" v-bind="getEvents(false)"> | |
29 | + <div | |
30 | + :class="[ | |
31 | + { | |
32 | + [`${prefixCls}-submenu-popup`]: !getParentSubMenu, | |
33 | + [`${prefixCls}-submenu-collapsed-show-tit`]: collapsedShowTitle, | |
34 | + }, | |
35 | + ]" | |
36 | + > | |
37 | + <slot name="title"></slot> | |
38 | + </div> | |
39 | + <Icon | |
40 | + v-if="getParentSubMenu" | |
41 | + icon="eva:arrow-ios-downward-outline" | |
42 | + :size="14" | |
43 | + :class="`${prefixCls}-submenu-title-icon`" | |
44 | + /> | |
45 | + </div> | |
46 | + <template #content v-show="opened"> | |
47 | + <div v-bind="getEvents(true)"> | |
48 | + <ul :class="[prefixCls, `${prefixCls}-${getTheme}`, `${prefixCls}-popup`]"> | |
49 | + <slot></slot> | |
50 | + </ul> | |
51 | + </div> | |
52 | + </template> | |
53 | + </Popover> | |
54 | + </li> | |
55 | +</template> | |
56 | + | |
57 | +<script lang="ts"> | |
58 | + import type { CSSProperties, PropType } from 'vue'; | |
59 | + import type { SubMenuProvider } from './types'; | |
60 | + import { | |
61 | + defineComponent, | |
62 | + computed, | |
63 | + unref, | |
64 | + getCurrentInstance, | |
65 | + toRefs, | |
66 | + reactive, | |
67 | + provide, | |
68 | + onBeforeMount, | |
69 | + inject, | |
70 | + } from 'vue'; | |
71 | + import { useDesign } from '/@/hooks/web/useDesign'; | |
72 | + import { propTypes } from '/@/utils/propTypes'; | |
73 | + import { useMenuItem } from './useMenu'; | |
74 | + import { useSimpleRootMenuContext } from './useSimpleMenuContext'; | |
75 | + import MenuCollapseTransition from './MenuCollapseTransition.vue'; | |
76 | + import Icon from '/@/components/Icon'; | |
77 | + import { Popover } from 'ant-design-vue'; | |
78 | + import { isBoolean, isObject } from '/@/utils/is'; | |
79 | + import Mitt from '/@/utils/mitt'; | |
80 | + | |
81 | + const DELAY = 200; | |
82 | + export default defineComponent({ | |
83 | + name: 'SubMenu', | |
84 | + components: { | |
85 | + Icon, | |
86 | + MenuCollapseTransition, | |
87 | + Popover, | |
88 | + }, | |
89 | + props: { | |
90 | + name: { | |
91 | + type: [String, Number] as PropType<string | number>, | |
92 | + required: true, | |
93 | + }, | |
94 | + disabled: propTypes.bool, | |
95 | + collapsedShowTitle: propTypes.bool, | |
96 | + }, | |
97 | + setup(props) { | |
98 | + const instance = getCurrentInstance(); | |
99 | + | |
100 | + const state = reactive({ | |
101 | + active: false, | |
102 | + opened: false, | |
103 | + }); | |
104 | + | |
105 | + const data = reactive({ | |
106 | + timeout: null as TimeoutHandle | null, | |
107 | + mouseInChild: false, | |
108 | + isChild: false, | |
109 | + }); | |
110 | + | |
111 | + const { getParentSubMenu, getItemStyle, getParentMenu, getParentList } = useMenuItem( | |
112 | + instance | |
113 | + ); | |
114 | + | |
115 | + const { prefixCls } = useDesign('menu'); | |
116 | + | |
117 | + const subMenuEmitter = new Mitt(); | |
118 | + | |
119 | + const { rootMenuEmitter } = useSimpleRootMenuContext(); | |
120 | + | |
121 | + const { | |
122 | + addSubMenu: parentAddSubmenu, | |
123 | + removeSubMenu: parentRemoveSubmenu, | |
124 | + removeAll: parentRemoveAll, | |
125 | + getOpenNames: parentGetOpenNames, | |
126 | + isRemoveAllPopup, | |
127 | + sliceIndex, | |
128 | + level, | |
129 | + props: rootProps, | |
130 | + handleMouseleave: parentHandleMouseleave, | |
131 | + } = inject<SubMenuProvider>(`subMenu:${getParentMenu.value?.uid}`)!; | |
132 | + | |
133 | + const getClass = computed(() => { | |
134 | + return [ | |
135 | + `${prefixCls}-submenu`, | |
136 | + { | |
137 | + [`${prefixCls}-item-active`]: state.active, | |
138 | + [`${prefixCls}-opened`]: state.opened, | |
139 | + [`${prefixCls}-submenu-disabled`]: props.disabled, | |
140 | + [`${prefixCls}-submenu-has-parent-submenu`]: unref(getParentSubMenu), | |
141 | + [`${prefixCls}-child-item-active`]: state.active, | |
142 | + }, | |
143 | + ]; | |
144 | + }); | |
145 | + | |
146 | + const getAccordion = computed(() => rootProps.accordion); | |
147 | + const getCollapse = computed(() => rootProps.collapse); | |
148 | + const getTheme = computed(() => rootProps.theme); | |
149 | + | |
150 | + const getOverlayStyle = computed( | |
151 | + (): CSSProperties => { | |
152 | + return { | |
153 | + minWidth: '200px', | |
154 | + }; | |
155 | + } | |
156 | + ); | |
157 | + | |
158 | + const getIsOpend = computed(() => { | |
159 | + const name = props.name; | |
160 | + if (unref(getCollapse)) { | |
161 | + return parentGetOpenNames().includes(name); | |
162 | + } | |
163 | + return state.opened; | |
164 | + }); | |
165 | + | |
166 | + const getSubClass = computed(() => { | |
167 | + const isActive = rootProps.activeSubMenuNames.includes(props.name); | |
168 | + return [ | |
169 | + `${prefixCls}-submenu-title`, | |
170 | + { | |
171 | + [`${prefixCls}-submenu-active`]: isActive, | |
172 | + [`${prefixCls}-submenu-active-border`]: isActive && level === 0, | |
173 | + [`${prefixCls}-submenu-collapse`]: unref(getCollapse) && level === 0, | |
174 | + }, | |
175 | + ]; | |
176 | + }); | |
177 | + | |
178 | + function getEvents(deep: boolean) { | |
179 | + if (!unref(getCollapse)) { | |
180 | + return {}; | |
181 | + } | |
182 | + return { | |
183 | + onMouseenter: handleMouseenter, | |
184 | + onMouseleave: () => handleMouseleave(deep), | |
185 | + }; | |
186 | + } | |
187 | + | |
188 | + function handleClick() { | |
189 | + const { disabled } = props; | |
190 | + if (disabled || unref(getCollapse)) return; | |
191 | + const opened = state.opened; | |
192 | + if (unref(getAccordion)) { | |
193 | + const { uidList } = getParentList(); | |
194 | + rootMenuEmitter.emit('on-update-opened', { | |
195 | + opend: false, | |
196 | + parent: instance?.parent, | |
197 | + uidList: uidList, | |
198 | + }); | |
199 | + } | |
200 | + state.opened = !opened; | |
201 | + } | |
202 | + | |
203 | + function handleMouseenter() { | |
204 | + const disabled = props.disabled; | |
205 | + if (disabled) return; | |
206 | + | |
207 | + subMenuEmitter.emit('submenu:mouse-enter-child'); | |
208 | + | |
209 | + const index = parentGetOpenNames().findIndex((item) => item === props.name); | |
210 | + | |
211 | + sliceIndex(index); | |
212 | + | |
213 | + const isRoot = level === 0 && parentGetOpenNames().length === 2; | |
214 | + if (isRoot) { | |
215 | + parentRemoveAll(); | |
216 | + } | |
217 | + data.isChild = parentGetOpenNames().includes(props.name); | |
218 | + clearTimeout(data.timeout!); | |
219 | + data.timeout = setTimeout(() => { | |
220 | + parentAddSubmenu(props.name); | |
221 | + }, DELAY); | |
222 | + } | |
223 | + | |
224 | + function handleMouseleave(deepDispatch = false) { | |
225 | + const parentName = getParentMenu.value?.props.name; | |
226 | + if (!parentName) { | |
227 | + isRemoveAllPopup.value = true; | |
228 | + } | |
229 | + | |
230 | + if (parentGetOpenNames().slice(-1)[0] === props.name) { | |
231 | + data.isChild = false; | |
232 | + } | |
233 | + | |
234 | + subMenuEmitter.emit('submenu:mouse-leave-child'); | |
235 | + if (data.timeout) { | |
236 | + clearTimeout(data.timeout!); | |
237 | + data.timeout = setTimeout(() => { | |
238 | + if (isRemoveAllPopup.value) { | |
239 | + parentRemoveAll(); | |
240 | + } else if (!data.mouseInChild) { | |
241 | + parentRemoveSubmenu(props.name); | |
242 | + } | |
243 | + }, DELAY); | |
244 | + } | |
245 | + if (deepDispatch) { | |
246 | + if (getParentSubMenu.value) { | |
247 | + parentHandleMouseleave?.(true); | |
248 | + } | |
249 | + } | |
250 | + } | |
251 | + | |
252 | + onBeforeMount(() => { | |
253 | + subMenuEmitter.on('submenu:mouse-enter-child', () => { | |
254 | + data.mouseInChild = true; | |
255 | + isRemoveAllPopup.value = false; | |
256 | + clearTimeout(data.timeout!); | |
257 | + }); | |
258 | + subMenuEmitter.on('submenu:mouse-leave-child', () => { | |
259 | + if (data.isChild) return; | |
260 | + data.mouseInChild = false; | |
261 | + clearTimeout(data.timeout!); | |
262 | + }); | |
263 | + | |
264 | + rootMenuEmitter.on( | |
265 | + 'on-update-opened', | |
266 | + (data: boolean | (string | number)[] | Recordable) => { | |
267 | + if (unref(getCollapse)) return; | |
268 | + if (isBoolean(data)) { | |
269 | + state.opened = data; | |
270 | + return; | |
271 | + } | |
272 | + | |
273 | + if (isObject(data)) { | |
274 | + const { opend, parent, uidList } = data as Recordable; | |
275 | + if (parent === instance?.parent) { | |
276 | + state.opened = opend; | |
277 | + } else if (!uidList.includes(instance?.uid)) { | |
278 | + state.opened = false; | |
279 | + } | |
280 | + return; | |
281 | + } | |
282 | + | |
283 | + if (props.name && Array.isArray(data)) { | |
284 | + state.opened = (data as (string | number)[]).includes(props.name); | |
285 | + } | |
286 | + } | |
287 | + ); | |
288 | + | |
289 | + rootMenuEmitter.on('on-update-active-name:submenu', (data: number[]) => { | |
290 | + state.active = data.includes(instance?.uid!); | |
291 | + }); | |
292 | + }); | |
293 | + | |
294 | + function handleVisibleChange(visible: boolean) { | |
295 | + state.opened = visible; | |
296 | + } | |
297 | + | |
298 | + // provide | |
299 | + provide<SubMenuProvider>(`subMenu:${instance?.uid}`, { | |
300 | + addSubMenu: parentAddSubmenu, | |
301 | + removeSubMenu: parentRemoveSubmenu, | |
302 | + getOpenNames: parentGetOpenNames, | |
303 | + removeAll: parentRemoveAll, | |
304 | + isRemoveAllPopup, | |
305 | + sliceIndex, | |
306 | + level: level + 1, | |
307 | + handleMouseleave, | |
308 | + props: rootProps, | |
309 | + }); | |
310 | + | |
311 | + return { | |
312 | + getClass, | |
313 | + prefixCls, | |
314 | + getCollapse, | |
315 | + getItemStyle, | |
316 | + handleClick, | |
317 | + handleVisibleChange, | |
318 | + getParentSubMenu, | |
319 | + getOverlayStyle, | |
320 | + getTheme, | |
321 | + getIsOpend, | |
322 | + getEvents, | |
323 | + getSubClass, | |
324 | + ...toRefs(state), | |
325 | + ...toRefs(data), | |
326 | + }; | |
327 | + }, | |
328 | + }); | |
329 | +</script> | ... | ... |
src/components/SimpleMenu/src/components/menu.less
0 → 100644
1 | +@menu-prefix-cls: ~'@{namespace}-menu'; | |
2 | +@menu-popup-prefix-cls: ~'@{namespace}-menu-popup'; | |
3 | +@submenu-popup-prefix-cls: ~'@{namespace}-menu-submenu-popup'; | |
4 | + | |
5 | +// @menu-dark: #191a23; | |
6 | +// @menu-dark-active-bg: #101117; | |
7 | +@transition-time: 0.2s; | |
8 | +@menu-dark-subsidiary-color: rgba(255, 255, 255, 0.7); | |
9 | + | |
10 | +.light-border { | |
11 | + &::after { | |
12 | + position: absolute; | |
13 | + top: 0; | |
14 | + right: 0; | |
15 | + bottom: 0; | |
16 | + display: block; | |
17 | + width: 2px; | |
18 | + background: @primary-color; | |
19 | + content: ''; | |
20 | + } | |
21 | +} | |
22 | + | |
23 | +.@{menu-prefix-cls}-menu-popover { | |
24 | + .ant-popover-arrow { | |
25 | + display: none; | |
26 | + } | |
27 | + | |
28 | + .ant-popover-inner-content { | |
29 | + padding: 0; | |
30 | + } | |
31 | + | |
32 | + .@{menu-prefix-cls} { | |
33 | + &-opened > * > &-submenu-title-icon { | |
34 | + transform: translateY(-50%) rotate(90deg) !important; | |
35 | + } | |
36 | + | |
37 | + &-item, | |
38 | + &-submenu-title { | |
39 | + position: relative; | |
40 | + z-index: 1; | |
41 | + padding: 12px 20px; | |
42 | + color: @menu-dark-subsidiary-color; | |
43 | + cursor: pointer; | |
44 | + transition: all @transition-time @ease-in-out; | |
45 | + | |
46 | + // &:hover { | |
47 | + // color: @primary-color; | |
48 | + // } | |
49 | + | |
50 | + &-icon { | |
51 | + position: absolute; | |
52 | + top: 50%; | |
53 | + right: 18px; | |
54 | + transform: translateY(-50%) rotate(-90deg); | |
55 | + transition: transform @transition-time @ease-in-out; | |
56 | + } | |
57 | + } | |
58 | + | |
59 | + &-dark { | |
60 | + .@{menu-prefix-cls}-item, | |
61 | + .@{menu-prefix-cls}-submenu-title { | |
62 | + color: @menu-dark-subsidiary-color; | |
63 | + // background: @menu-dark-active-bg; | |
64 | + | |
65 | + &:hover { | |
66 | + color: #fff; | |
67 | + } | |
68 | + | |
69 | + &-selected { | |
70 | + color: #fff; | |
71 | + background: @primary-color !important; | |
72 | + } | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + &-light { | |
77 | + .@{menu-prefix-cls}-item, | |
78 | + .@{menu-prefix-cls}-submenu-title { | |
79 | + color: @text-color-base; | |
80 | + | |
81 | + &:hover { | |
82 | + color: @primary-color; | |
83 | + } | |
84 | + | |
85 | + &-selected { | |
86 | + z-index: 2; | |
87 | + color: @primary-color; | |
88 | + background: fade(@primary-color, 8); | |
89 | + | |
90 | + .light-border(); | |
91 | + } | |
92 | + } | |
93 | + } | |
94 | + } | |
95 | +} | |
96 | + | |
97 | +.content(); | |
98 | +.content() { | |
99 | + .@{menu-prefix-cls} { | |
100 | + position: relative; | |
101 | + display: block; | |
102 | + width: 100%; | |
103 | + padding: 0; | |
104 | + margin: 0; | |
105 | + font-size: @font-size-base; | |
106 | + color: @text-color-base; | |
107 | + list-style: none; | |
108 | + outline: none; | |
109 | + | |
110 | + .collapse-transition { | |
111 | + transition: @transition-time height ease-in-out, @transition-time padding-top ease-in-out, | |
112 | + @transition-time padding-bottom ease-in-out; | |
113 | + } | |
114 | + | |
115 | + &-light { | |
116 | + background: #fff; | |
117 | + | |
118 | + .@{menu-prefix-cls}-submenu-active { | |
119 | + color: @primary-color !important; | |
120 | + // background: fade(@primary-color, 8); | |
121 | + | |
122 | + &-border { | |
123 | + .light-border(); | |
124 | + } | |
125 | + } | |
126 | + } | |
127 | + | |
128 | + &-dark { | |
129 | + // background: @menu-dark; | |
130 | + | |
131 | + .@{menu-prefix-cls}-submenu-active { | |
132 | + color: #fff !important; | |
133 | + } | |
134 | + } | |
135 | + | |
136 | + &-item { | |
137 | + position: relative; | |
138 | + z-index: 1; | |
139 | + display: flex; | |
140 | + font-size: @font-size-base; | |
141 | + color: inherit; | |
142 | + list-style: none; | |
143 | + cursor: pointer; | |
144 | + outline: none; | |
145 | + align-items: center; | |
146 | + // transition: all @transition-time @ease-in-out; | |
147 | + | |
148 | + &:hover, | |
149 | + &:active { | |
150 | + color: inherit; | |
151 | + } | |
152 | + } | |
153 | + | |
154 | + &-item > i { | |
155 | + margin-right: 6px; | |
156 | + } | |
157 | + | |
158 | + &-submenu-title > i, | |
159 | + &-submenu-title span > i { | |
160 | + margin-right: 8px; | |
161 | + } | |
162 | + | |
163 | + // vertical | |
164 | + &-vertical &-item, | |
165 | + &-vertical &-submenu-title { | |
166 | + position: relative; | |
167 | + z-index: 1; | |
168 | + padding: 12px 24px; | |
169 | + cursor: pointer; | |
170 | + // transition: all @transition-time @ease-in-out; | |
171 | + | |
172 | + &:hover { | |
173 | + color: @primary-color; | |
174 | + } | |
175 | + | |
176 | + .@{menu-prefix-cls}-tooltip { | |
177 | + width: calc(100% - 0px); | |
178 | + padding: 12px 0; | |
179 | + text-align: center; | |
180 | + } | |
181 | + .@{menu-prefix-cls}-submenu-popup { | |
182 | + padding: 12px 0; | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + &-vertical &-submenu-collapse { | |
187 | + .@{submenu-popup-prefix-cls} { | |
188 | + display: flex; | |
189 | + justify-content: center; | |
190 | + align-items: center; | |
191 | + } | |
192 | + .@{menu-prefix-cls}-submenu-collapsed-show-tit { | |
193 | + flex-direction: column; | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + &-vertical&-collapse &-item, | |
198 | + &-vertical&-collapse &-submenu-title { | |
199 | + padding: 0 0; | |
200 | + } | |
201 | + | |
202 | + &-vertical &-submenu-title-icon { | |
203 | + position: absolute; | |
204 | + top: 50%; | |
205 | + right: 18px; | |
206 | + transform: translateY(-50%); | |
207 | + } | |
208 | + | |
209 | + &-submenu-title-icon { | |
210 | + transition: transform @transition-time @ease-in-out; | |
211 | + } | |
212 | + | |
213 | + &-vertical &-opened > * > &-submenu-title-icon { | |
214 | + transform: translateY(-50%) rotate(180deg); | |
215 | + } | |
216 | + | |
217 | + &-vertical &-submenu { | |
218 | + &-nested { | |
219 | + padding-left: 20px; | |
220 | + } | |
221 | + .@{menu-prefix-cls}-item { | |
222 | + padding-left: 43px; | |
223 | + } | |
224 | + } | |
225 | + | |
226 | + &-light&-vertical &-item { | |
227 | + &-active:not(.@{menu-prefix-cls}-submenu) { | |
228 | + z-index: 2; | |
229 | + color: @primary-color; | |
230 | + background: fade(@primary-color, 8); | |
231 | + | |
232 | + .light-border(); | |
233 | + } | |
234 | + &-active.@{menu-prefix-cls}-submenu { | |
235 | + color: @primary-color; | |
236 | + } | |
237 | + } | |
238 | + | |
239 | + &-light&-vertical&-collapse { | |
240 | + > li.@{menu-prefix-cls}-item-active, | |
241 | + .@{menu-prefix-cls}-submenu-active { | |
242 | + position: relative; | |
243 | + background: fade(@primary-color, 3); | |
244 | + | |
245 | + &::after { | |
246 | + display: none; | |
247 | + } | |
248 | + | |
249 | + &::before { | |
250 | + position: absolute; | |
251 | + top: 0; | |
252 | + left: 0; | |
253 | + width: 3px; | |
254 | + height: 100%; | |
255 | + background: @primary-color; | |
256 | + content: ''; | |
257 | + } | |
258 | + } | |
259 | + } | |
260 | + | |
261 | + &-dark&-vertical &-item, | |
262 | + &-dark&-vertical &-submenu-title { | |
263 | + color: @menu-dark-subsidiary-color; | |
264 | + &-active:not(.@{menu-prefix-cls}-submenu) { | |
265 | + color: #fff !important; | |
266 | + background: @primary-color !important; | |
267 | + } | |
268 | + | |
269 | + &:hover { | |
270 | + color: #fff; | |
271 | + // background: @menu-dark; | |
272 | + } | |
273 | + | |
274 | + // &-active:not(.@{menu-prefix-cls}-submenu) { | |
275 | + // color: @primary-color; | |
276 | + // } | |
277 | + } | |
278 | + | |
279 | + &-dark&-vertical&-collapse { | |
280 | + > li.@{menu-prefix-cls}-item-active, | |
281 | + .@{menu-prefix-cls}-submenu-active { | |
282 | + position: relative; | |
283 | + color: #fff !important; | |
284 | + background-color: @sider-dark-darken-bg-color !important; | |
285 | + | |
286 | + &::before { | |
287 | + position: absolute; | |
288 | + top: 0; | |
289 | + left: 0; | |
290 | + width: 3px; | |
291 | + height: 100%; | |
292 | + background: @primary-color; | |
293 | + content: ''; | |
294 | + } | |
295 | + | |
296 | + .@{menu-prefix-cls}-submenu-collapse { | |
297 | + background-color: transparent; | |
298 | + } | |
299 | + } | |
300 | + } | |
301 | + | |
302 | + &-dark&-vertical &-submenu &-item { | |
303 | + // &:hover { | |
304 | + // color: #fff; | |
305 | + // background: transparent; | |
306 | + // } | |
307 | + | |
308 | + &-active, | |
309 | + &-active:hover { | |
310 | + color: #fff; | |
311 | + border-right: none; | |
312 | + } | |
313 | + } | |
314 | + | |
315 | + &-dark&-vertical &-child-item-active > &-submenu-title { | |
316 | + color: #fff; | |
317 | + } | |
318 | + | |
319 | + &-dark&-vertical &-opened { | |
320 | + // background: @menu-dark-active-bg; | |
321 | + // .@{menu-prefix-cls}-submenu-title { | |
322 | + // background: @menu-dark; | |
323 | + // } | |
324 | + | |
325 | + .@{menu-prefix-cls}-submenu-has-parent-submenu { | |
326 | + .@{menu-prefix-cls}-submenu-title { | |
327 | + background: transparent; | |
328 | + } | |
329 | + } | |
330 | + } | |
331 | + } | |
332 | +} | ... | ... |
src/components/SimpleMenu/src/components/types.ts
0 → 100644
1 | +import { Ref } from 'vue'; | |
2 | + | |
3 | +export interface Props { | |
4 | + theme: string; | |
5 | + activeName?: string | number | undefined; | |
6 | + openNames: string[]; | |
7 | + accordion: boolean; | |
8 | + width: string; | |
9 | + collapsedWidth: string; | |
10 | + indentSize: number; | |
11 | + collapse: boolean; | |
12 | + activeSubMenuNames: (string | number)[]; | |
13 | +} | |
14 | + | |
15 | +export interface SubMenuProvider { | |
16 | + addSubMenu: (name: string | number, update?: boolean) => void; | |
17 | + removeSubMenu: (name: string | number, update?: boolean) => void; | |
18 | + removeAll: () => void; | |
19 | + sliceIndex: (index: number) => void; | |
20 | + isRemoveAllPopup: Ref<boolean>; | |
21 | + getOpenNames: () => (string | number)[]; | |
22 | + handleMouseleave?: Fn; | |
23 | + level: number; | |
24 | + props: Props; | |
25 | +} | ... | ... |
src/components/SimpleMenu/src/components/useMenu.ts
0 → 100644
1 | +import { computed, ComponentInternalInstance, unref } from 'vue'; | |
2 | +import type { CSSProperties } from 'vue'; | |
3 | + | |
4 | +export function useMenuItem(instance: ComponentInternalInstance | null) { | |
5 | + const getParentMenu = computed(() => { | |
6 | + return findParentMenu(['Menu', 'SubMenu']); | |
7 | + }); | |
8 | + | |
9 | + const getParentRootMenu = computed(() => { | |
10 | + return findParentMenu(['Menu']); | |
11 | + }); | |
12 | + | |
13 | + const getParentSubMenu = computed(() => { | |
14 | + return findParentMenu(['SubMenu']); | |
15 | + }); | |
16 | + | |
17 | + const getItemStyle = computed( | |
18 | + (): CSSProperties => { | |
19 | + let parent = instance?.parent; | |
20 | + if (!parent) return {}; | |
21 | + const indentSize = (unref(getParentRootMenu)?.props.indentSize as number) ?? 20; | |
22 | + let padding = indentSize; | |
23 | + | |
24 | + if (unref(getParentRootMenu)?.props.collapse) { | |
25 | + padding = indentSize; | |
26 | + } else { | |
27 | + while (parent && parent.type.name !== 'Menu') { | |
28 | + if (parent.type.name === 'SubMenu') { | |
29 | + padding += indentSize; | |
30 | + } | |
31 | + parent = parent.parent; | |
32 | + } | |
33 | + } | |
34 | + return { paddingLeft: padding + 'px' }; | |
35 | + } | |
36 | + ); | |
37 | + | |
38 | + function findParentMenu(name: string[]) { | |
39 | + let parent = instance?.parent; | |
40 | + if (!parent) return null; | |
41 | + while (parent && name.indexOf(parent.type.name!) === -1) { | |
42 | + parent = parent.parent; | |
43 | + } | |
44 | + return parent; | |
45 | + } | |
46 | + | |
47 | + function getParentList() { | |
48 | + let parent = instance; | |
49 | + if (!parent) | |
50 | + return { | |
51 | + uidList: [], | |
52 | + list: [], | |
53 | + }; | |
54 | + const ret = []; | |
55 | + while (parent && parent.type.name !== 'Menu') { | |
56 | + if (parent.type.name === 'SubMenu') { | |
57 | + ret.push(parent); | |
58 | + } | |
59 | + parent = parent.parent; | |
60 | + } | |
61 | + return { | |
62 | + uidList: ret.map((item) => item.uid), | |
63 | + list: ret, | |
64 | + }; | |
65 | + } | |
66 | + | |
67 | + function getParentInstance(instance: ComponentInternalInstance, name = 'SubMenu') { | |
68 | + let parent = instance.parent; | |
69 | + while (parent) { | |
70 | + if (parent.type.name !== name) { | |
71 | + return parent; | |
72 | + } | |
73 | + parent = parent.parent; | |
74 | + } | |
75 | + return parent; | |
76 | + } | |
77 | + | |
78 | + return { | |
79 | + getParentMenu, | |
80 | + getParentInstance, | |
81 | + getParentRootMenu, | |
82 | + getParentList, | |
83 | + getParentSubMenu, | |
84 | + getItemStyle, | |
85 | + }; | |
86 | +} | ... | ... |
src/components/SimpleMenu/src/components/useSimpleMenuContext.ts
0 → 100644
1 | +import type { InjectionKey, Ref } from 'vue'; | |
2 | +import { createContext, useContext } from '/@/hooks/core/useContext'; | |
3 | +import Mitt from '/@/utils/mitt'; | |
4 | + | |
5 | +export interface SimpleRootMenuContextProps { | |
6 | + rootMenuEmitter: Mitt; | |
7 | + activeName: Ref<string | number>; | |
8 | +} | |
9 | + | |
10 | +const key: InjectionKey<SimpleRootMenuContextProps> = Symbol(); | |
11 | + | |
12 | +export function createSimpleRootMenuContext(context: SimpleRootMenuContextProps) { | |
13 | + return createContext<SimpleRootMenuContextProps>(context, key, { readonly: false, native: true }); | |
14 | +} | |
15 | + | |
16 | +export function useSimpleRootMenuContext() { | |
17 | + return useContext<SimpleRootMenuContextProps>(key); | |
18 | +} | ... | ... |
src/components/SimpleMenu/src/index.less
0 → 100644
1 | +@simple-prefix-cls: ~'@{namespace}-simple-menu'; | |
2 | +@prefix-cls: ~'@{namespace}-menu'; | |
3 | + | |
4 | +.@{prefix-cls} { | |
5 | + &-dark&-vertical .@{simple-prefix-cls}__parent { | |
6 | + background-color: @sider-dark-bg-color; | |
7 | + > .@{prefix-cls}-submenu-title { | |
8 | + background-color: @sider-dark-bg-color; | |
9 | + } | |
10 | + } | |
11 | + | |
12 | + &-dark&-vertical .@{simple-prefix-cls}__children, | |
13 | + &-dark&-popup .@{simple-prefix-cls}__children { | |
14 | + background-color: @sider-dark-lighten-1-bg-color; | |
15 | + > .@{prefix-cls}-submenu-title { | |
16 | + background-color: @sider-dark-lighten-1-bg-color; | |
17 | + } | |
18 | + } | |
19 | + | |
20 | + .collapse-title { | |
21 | + font-size: 12px; | |
22 | + } | |
23 | +} | |
24 | + | |
25 | +.@{simple-prefix-cls} { | |
26 | + &-tag { | |
27 | + position: absolute; | |
28 | + top: calc(50% - 10px); | |
29 | + right: 30px; | |
30 | + display: inline-block; | |
31 | + padding: 2px 3px; | |
32 | + margin-right: 4px; | |
33 | + font-size: 10px; | |
34 | + line-height: 14px; | |
35 | + color: #fff; | |
36 | + border-radius: 2px; | |
37 | + | |
38 | + &--collapse { | |
39 | + top: 6px !important; | |
40 | + right: 2px; | |
41 | + } | |
42 | + | |
43 | + &--dot { | |
44 | + top: calc(50% - 4px); | |
45 | + width: 6px; | |
46 | + height: 6px; | |
47 | + padding: 0; | |
48 | + border-radius: 50%; | |
49 | + } | |
50 | + | |
51 | + &--primary { | |
52 | + background: @primary-color; | |
53 | + } | |
54 | + | |
55 | + &--error { | |
56 | + background: @error-color; | |
57 | + } | |
58 | + | |
59 | + &--success { | |
60 | + background: @success-color; | |
61 | + } | |
62 | + | |
63 | + &--warn { | |
64 | + background: @warning-color; | |
65 | + } | |
66 | + } | |
67 | +} | ... | ... |
src/components/SimpleMenu/src/types.ts
0 → 100644
src/components/SimpleMenu/src/useOpenKeys.ts
0 → 100644
1 | +import type { Menu as MenuType } from '/@/router/types'; | |
2 | +import type { MenuState } from './types'; | |
3 | + | |
4 | +import { Ref, toRaw } from 'vue'; | |
5 | + | |
6 | +import { unref } from 'vue'; | |
7 | +import { es6Unique } from '/@/utils'; | |
8 | +import { getAllParentPath } from '/@/router/helper/menuHelper'; | |
9 | +import { useTimeoutFn } from '/@/hooks/core/useTimeout'; | |
10 | + | |
11 | +export function useOpenKeys( | |
12 | + menuState: MenuState, | |
13 | + menus: Ref<MenuType[]>, | |
14 | + accordion: Ref<boolean>, | |
15 | + mixSider: Ref<boolean> | |
16 | + // mode: Ref<MenuModeEnum>, | |
17 | +) { | |
18 | + async function setOpenKeys(path: string) { | |
19 | + // if (mode.value === MenuModeEnum.HORIZONTAL) { | |
20 | + // return; | |
21 | + // } | |
22 | + const native = !mixSider.value; | |
23 | + useTimeoutFn( | |
24 | + () => { | |
25 | + const menuList = toRaw(menus.value); | |
26 | + if (menuList?.length === 0) { | |
27 | + menuState.activeSubMenuNames = []; | |
28 | + menuState.openNames = []; | |
29 | + return; | |
30 | + } | |
31 | + const keys = getAllParentPath(menuList, path); | |
32 | + if (!unref(accordion)) { | |
33 | + menuState.openNames = es6Unique([...menuState.openNames, ...keys]); | |
34 | + } else { | |
35 | + menuState.openNames = keys; | |
36 | + } | |
37 | + menuState.activeSubMenuNames = menuState.openNames; | |
38 | + }, | |
39 | + 16, | |
40 | + native | |
41 | + ); | |
42 | + } | |
43 | + | |
44 | + return { setOpenKeys }; | |
45 | +} | ... | ... |
src/components/Table/src/components/editable/EditableCell.vue
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | import type { CSSProperties, PropType } from 'vue'; |
32 | 32 | import type { BasicColumn } from '../../types/table'; |
33 | 33 | |
34 | - import { defineComponent, ref, unref, nextTick, computed, watchEffect, toRaw } from 'vue'; | |
34 | + import { defineComponent, ref, unref, nextTick, computed, watchEffect } from 'vue'; | |
35 | 35 | import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue'; |
36 | 36 | |
37 | 37 | import { useDesign } from '/@/hooks/web/useDesign'; | ... | ... |
src/components/Table/src/hooks/useProvinceTable.ts deleted
100644 → 0
1 | -import type { Ref } from 'vue'; | |
2 | -import type { TableActionType } from '../types/table'; | |
3 | - | |
4 | -import { provide, inject } from 'vue'; | |
5 | - | |
6 | -const key = Symbol('table'); | |
7 | - | |
8 | -type Instance = TableActionType & { wrapRef: Ref<Nullable<HTMLElement>> }; | |
9 | - | |
10 | -export function provideTable(instance: Instance) { | |
11 | - provide(key, instance); | |
12 | -} | |
13 | - | |
14 | -export function injectTable(): Instance { | |
15 | - return inject(key) as Instance; | |
16 | -} |
src/design/ant/index.less
... | ... | @@ -22,6 +22,12 @@ |
22 | 22 | background: rgba(0, 0, 0, 0.3); |
23 | 23 | } |
24 | 24 | |
25 | +.ant-popover { | |
26 | + &-content { | |
27 | + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); | |
28 | + } | |
29 | +} | |
30 | + | |
25 | 31 | // ================================= |
26 | 32 | // ==============descriptions======= |
27 | 33 | // ================================= | ... | ... |
src/design/color.less
... | ... | @@ -9,7 +9,6 @@ |
9 | 9 | --sider-dark-darken-bg-color: #273352; |
10 | 10 | --sider-dark-lighten-1-bg-color: #273352; |
11 | 11 | --sider-dark-lighten-2-bg-color: #273352; |
12 | - --sider-dark-lighten-3-bg-color: #273352; | |
13 | 12 | } |
14 | 13 | |
15 | 14 | @white: #fff; |
... | ... | @@ -88,7 +87,6 @@ |
88 | 87 | @sider-dark-darken-bg-color: var(--sider-dark-darken-bg-color); |
89 | 88 | @sider-dark-lighten-1-bg-color: var(--sider-dark-lighten-1-bg-color); |
90 | 89 | @sider-dark-lighten-2-bg-color: var(--sider-dark-lighten-2-bg-color); |
91 | -@sider-dark-lighten-3-bg-color: var(--sider-dark-lighten-3-bg-color); | |
92 | 90 | |
93 | 91 | // trigger |
94 | 92 | @trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2); | ... | ... |
src/hooks/setting/useMenuSetting.ts
... | ... | @@ -78,9 +78,12 @@ const getIsMixMode = computed(() => { |
78 | 78 | }); |
79 | 79 | |
80 | 80 | const getRealWidth = computed(() => { |
81 | - return unref(getCollapsed) && !unref(getMixSideFixed) | |
82 | - ? unref(getMiniWidthNumber) | |
83 | - : unref(getMenuWidth); | |
81 | + if (unref(getIsMixSidebar)) { | |
82 | + return unref(getCollapsed) && !unref(getMixSideFixed) | |
83 | + ? unref(getMiniWidthNumber) | |
84 | + : unref(getMenuWidth); | |
85 | + } | |
86 | + return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth); | |
84 | 87 | }); |
85 | 88 | |
86 | 89 | const getMiniWidthNumber = computed(() => { | ... | ... |
src/layouts/default/header/index.vue
src/layouts/default/menu/index.tsx
... | ... | @@ -4,6 +4,7 @@ import type { PropType, CSSProperties } from 'vue'; |
4 | 4 | |
5 | 5 | import { computed, defineComponent, unref, toRef } from 'vue'; |
6 | 6 | import { BasicMenu } from '/@/components/Menu'; |
7 | +import { SimpleMenu } from '/@/components/SimpleMenu'; | |
7 | 8 | import { AppLogo } from '/@/components/Application'; |
8 | 9 | |
9 | 10 | import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; |
... | ... | @@ -126,7 +127,18 @@ export default defineComponent({ |
126 | 127 | } |
127 | 128 | |
128 | 129 | function renderMenu() { |
129 | - return ( | |
130 | + const menus = unref(menusRef); | |
131 | + if (!menus || !menus.length) return null; | |
132 | + return !props.isHorizontal ? ( | |
133 | + <SimpleMenu | |
134 | + items={menus} | |
135 | + theme={unref(getComputedMenuTheme)} | |
136 | + accordion={unref(getAccordion)} | |
137 | + collapse={unref(getCollapsed)} | |
138 | + collapsedShowTitle={unref(getCollapsedShowTitle)} | |
139 | + onMenuClick={handleMenuClick} | |
140 | + /> | |
141 | + ) : ( | |
130 | 142 | <BasicMenu |
131 | 143 | beforeClickFn={beforeMenuClickFn} |
132 | 144 | isHorizontal={props.isHorizontal} |
... | ... | @@ -135,7 +147,7 @@ export default defineComponent({ |
135 | 147 | showLogo={unref(getIsShowLogo)} |
136 | 148 | mode={unref(getComputedMenuMode)} |
137 | 149 | theme={unref(getComputedMenuTheme)} |
138 | - items={unref(menusRef)} | |
150 | + items={menus} | |
139 | 151 | accordion={unref(getAccordion)} |
140 | 152 | onMenuClick={handleMenuClick} |
141 | 153 | /> | ... | ... |
src/layouts/default/menu/useLayoutMenu.ts
... | ... | @@ -40,7 +40,12 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) { |
40 | 40 | async ([path]: [string, MenuSplitTyeEnum]) => { |
41 | 41 | if (unref(splitNotLeft) || unref(getIsMobile)) return; |
42 | 42 | |
43 | - const parentPath = await getCurrentParentPath(path); | |
43 | + const { meta } = unref(currentRoute); | |
44 | + const currentActiveMenu = meta.currentActiveMenu; | |
45 | + let parentPath = await getCurrentParentPath(path); | |
46 | + if (!parentPath) { | |
47 | + parentPath = await getCurrentParentPath(currentActiveMenu); | |
48 | + } | |
44 | 49 | parentPath && throttleHandleSplitLeftMenu(parentPath); |
45 | 50 | }, |
46 | 51 | { |
... | ... | @@ -67,11 +72,15 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) { |
67 | 72 | |
68 | 73 | // Handle left menu split |
69 | 74 | async function handleSplitLeftMenu(parentPath: string) { |
75 | + console.log('======================'); | |
76 | + console.log(unref(getSplitLeft)); | |
77 | + console.log('======================'); | |
70 | 78 | if (unref(getSplitLeft) || unref(getIsMobile)) return; |
71 | 79 | |
72 | 80 | // spilt mode left |
73 | 81 | const children = await getChildrenMenus(parentPath); |
74 | - if (!children) { | |
82 | + | |
83 | + if (!children || !children.length) { | |
75 | 84 | setMenuSetting({ hidden: true }); |
76 | 85 | menusRef.value = []; |
77 | 86 | return; | ... | ... |
src/layouts/default/sider/MixSider.vue
... | ... | @@ -61,9 +61,7 @@ |
61 | 61 | /> |
62 | 62 | </div> |
63 | 63 | <ScrollContainer :class="`${prefixCls}-menu-list__content`"> |
64 | - <BasicMenu | |
65 | - :isHorizontal="false" | |
66 | - mode="inline" | |
64 | + <SimpleMenu | |
67 | 65 | :items="chilrenMenus" |
68 | 66 | :theme="getMenuTheme" |
69 | 67 | mixSider |
... | ... | @@ -85,7 +83,7 @@ |
85 | 83 | |
86 | 84 | import { defineComponent, onMounted, ref, computed, unref } from 'vue'; |
87 | 85 | |
88 | - import { BasicMenu, MenuTag } from '/@/components/Menu'; | |
86 | + import { MenuTag } from '/@/components/Menu'; | |
89 | 87 | import { ScrollContainer } from '/@/components/Container'; |
90 | 88 | import Icon from '/@/components/Icon'; |
91 | 89 | import { AppLogo } from '/@/components/Application'; |
... | ... | @@ -103,13 +101,14 @@ |
103 | 101 | import clickOutside from '/@/directives/clickOutside'; |
104 | 102 | import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus'; |
105 | 103 | import { listenerLastChangeTab } from '/@/logics/mitt/tabChange'; |
104 | + import { SimpleMenu } from '/@/components/SimpleMenu'; | |
106 | 105 | |
107 | 106 | export default defineComponent({ |
108 | 107 | name: 'LayoutMixSider', |
109 | 108 | components: { |
110 | 109 | ScrollContainer, |
111 | 110 | AppLogo, |
112 | - BasicMenu, | |
111 | + SimpleMenu, | |
113 | 112 | MenuTag, |
114 | 113 | Icon, |
115 | 114 | Trigger, |
... | ... | @@ -335,6 +334,7 @@ |
335 | 334 | <style lang="less"> |
336 | 335 | @prefix-cls: ~'@{namespace}-layout-mix-sider'; |
337 | 336 | @tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag'; |
337 | + @menu-prefix-cls: ~'@{namespace}-menu'; | |
338 | 338 | @width: 80px; |
339 | 339 | .@{prefix-cls} { |
340 | 340 | position: fixed; |
... | ... | @@ -351,6 +351,10 @@ |
351 | 351 | right: 2px; |
352 | 352 | } |
353 | 353 | |
354 | + .@{menu-prefix-cls} { | |
355 | + width: 100% !important; | |
356 | + } | |
357 | + | |
354 | 358 | &-dom { |
355 | 359 | height: 100%; |
356 | 360 | overflow: hidden; |
... | ... | @@ -392,6 +396,10 @@ |
392 | 396 | } |
393 | 397 | } |
394 | 398 | .@{prefix-cls}-menu-list { |
399 | + &__content { | |
400 | + box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1); | |
401 | + } | |
402 | + | |
395 | 403 | &__title { |
396 | 404 | .pushpin { |
397 | 405 | color: rgba(0, 0, 0, 0.35); |
... | ... | @@ -578,10 +586,10 @@ |
578 | 586 | |
579 | 587 | &-drag-bar { |
580 | 588 | position: absolute; |
581 | - top: 0; | |
582 | - right: -3px; | |
583 | - width: 3px; | |
584 | - height: 100%; | |
589 | + top: 50px; | |
590 | + right: -1px; | |
591 | + width: 1px; | |
592 | + height: calc(100% - 50px); | |
585 | 593 | cursor: ew-resize; |
586 | 594 | background: #f8f8f9; |
587 | 595 | border-top: none; | ... | ... |
src/locales/lang/en/component/drawer.ts
0 → 100644
src/locales/lang/en/component/menu.ts
0 → 100644
src/locales/lang/en/component/modal.ts
0 → 100644
src/locales/lang/zh_CN/component/drawer.ts
0 → 100644
src/locales/lang/zh_CN/component/menu.ts
0 → 100644
src/locales/lang/zh_CN/component/modal.ts
0 → 100644
src/logics/theme/index.ts
... | ... | @@ -71,7 +71,7 @@ export function updateSidebarBgColor(color: string) { |
71 | 71 | |
72 | 72 | setCssVar(SIDER_DARK_BG_COLOR, color); |
73 | 73 | setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color, 6)); |
74 | - setCssVar(SIDER_LIGHTEN_1_BG_COLOR, lighten(color, 4)); | |
74 | + setCssVar(SIDER_LIGHTEN_1_BG_COLOR, lighten(color, 5)); | |
75 | 75 | setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8)); |
76 | 76 | |
77 | 77 | // only #ffffff is light | ... | ... |
src/router/guard/index.ts
... | ... | @@ -8,6 +8,7 @@ import { createMessageGuard } from './messageGuard'; |
8 | 8 | import { createScrollGuard } from './scrollGuard'; |
9 | 9 | import { createHttpGuard } from './httpGuard'; |
10 | 10 | import { createPageGuard } from './pageGuard'; |
11 | +import { createStateGuard } from './stateGuard'; | |
11 | 12 | |
12 | 13 | export function createGuard(router: Router) { |
13 | 14 | createPageGuard(router); |
... | ... | @@ -18,4 +19,5 @@ export function createGuard(router: Router) { |
18 | 19 | createTitleGuard(router); |
19 | 20 | createProgressGuard(router); |
20 | 21 | createPermissionGuard(router); |
22 | + createStateGuard(router); | |
21 | 23 | } | ... | ... |
src/router/guard/stateGuard.ts
... | ... | @@ -3,7 +3,7 @@ import { appStore } from '/@/store/modules/app'; |
3 | 3 | import { PageEnum } from '/@/enums/pageEnum'; |
4 | 4 | import { removeTabChangeListener } from '/@/logics/mitt/tabChange'; |
5 | 5 | |
6 | -export function createHttpGuard(router: Router) { | |
6 | +export function createStateGuard(router: Router) { | |
7 | 7 | router.afterEach((to) => { |
8 | 8 | // Just enter the login page and clear the authentication information |
9 | 9 | if (to.path === PageEnum.BASE_LOGIN) { | ... | ... |
src/router/menus/index.ts
... | ... | @@ -54,7 +54,9 @@ export const getMenus = async (): Promise<Menu[]> => { |
54 | 54 | // 获取当前路径的顶级路径 |
55 | 55 | export async function getCurrentParentPath(currentPath: string) { |
56 | 56 | const menus = await getAsyncMenus(); |
57 | + | |
57 | 58 | const allParentPath = await getAllParentPath(menus, currentPath); |
59 | + | |
58 | 60 | return allParentPath?.[0]; |
59 | 61 | } |
60 | 62 | ... | ... |
src/utils/mitt.ts
... | ... | @@ -28,7 +28,7 @@ export default class Mitt { |
28 | 28 | * @param {Function} handler Function to call in response to given event |
29 | 29 | */ |
30 | 30 | on(type: string | Symbol, handler: Fn) { |
31 | - const handlers = this.cache.get(type); | |
31 | + const handlers = this.cache?.get(type); | |
32 | 32 | const added = handlers && handlers.push(handler); |
33 | 33 | if (!added) { |
34 | 34 | this.cache.set(type, [handler]); |
... | ... | @@ -57,7 +57,7 @@ export default class Mitt { |
57 | 57 | * @param {string|symbol} type The event type to invoke |
58 | 58 | * @param {*} [evt] Any value (object is recommended and powerful), passed to each handler |
59 | 59 | */ |
60 | - emit(type: string | Symbol, evt: any) { | |
60 | + emit(type: string | Symbol, evt?: any) { | |
61 | 61 | for (const handler of (this.cache.get(type) || []).slice()) handler(evt); |
62 | 62 | for (const handler of (this.cache.get('*') || []).slice()) handler(type, evt); |
63 | 63 | } | ... | ... |
vite.config.ts
... | ... | @@ -89,6 +89,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => { |
89 | 89 | optimizeDeps: { |
90 | 90 | include: [ |
91 | 91 | '@ant-design/icons-vue', |
92 | + 'echarts/map/js/china', | |
92 | 93 | 'ant-design-vue/es/locale/zh_CN', |
93 | 94 | 'moment/dist/locale/zh-cn', |
94 | 95 | 'ant-design-vue/es/locale/en_US', | ... | ... |
yarn.lock
... | ... | @@ -1123,10 +1123,10 @@ |
1123 | 1123 | resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.2.1.tgz#29a5a86bcfaa41555c8483a287294e520cc28cd6" |
1124 | 1124 | integrity sha512-WmvsSfVKQx62vLbHXJvdh4PDjSK9YU6VW9ppXTlbjgDKCYtpy2sMWbK4i9OBdxY6RRwMMVctZhWo6Y5jfMRyTg== |
1125 | 1125 | |
1126 | -"@eslint/eslintrc@^0.2.2": | |
1127 | - version "0.2.2" | |
1128 | - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" | |
1129 | - integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== | |
1126 | +"@eslint/eslintrc@^0.3.0": | |
1127 | + version "0.3.0" | |
1128 | + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz#d736d6963d7003b6514e6324bec9c602ac340318" | |
1129 | + integrity sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg== | |
1130 | 1130 | dependencies: |
1131 | 1131 | ajv "^6.12.4" |
1132 | 1132 | debug "^4.1.1" |
... | ... | @@ -1135,7 +1135,7 @@ |
1135 | 1135 | ignore "^4.0.6" |
1136 | 1136 | import-fresh "^3.2.1" |
1137 | 1137 | js-yaml "^3.13.1" |
1138 | - lodash "^4.17.19" | |
1138 | + lodash "^4.17.20" | |
1139 | 1139 | minimatch "^3.0.4" |
1140 | 1140 | strip-json-comments "^3.1.1" |
1141 | 1141 | |
... | ... | @@ -1184,10 +1184,10 @@ |
1184 | 1184 | dependencies: |
1185 | 1185 | cross-fetch "^3.0.6" |
1186 | 1186 | |
1187 | -"@iconify/json@^1.1.285": | |
1188 | - version "1.1.285" | |
1189 | - resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.285.tgz#2f1665c9f3ce4cd9eb2e0c980c0ac8955ce520fc" | |
1190 | - integrity sha512-ABoWg/GibeN3hzTvvzd9oSmSo3V8Hyb3f0LMMUD195xlrd8083nBzFFhA12EfEMnxNsouj6ZtvlgIDnYWEXRow== | |
1187 | +"@iconify/json@^1.1.287": | |
1188 | + version "1.1.287" | |
1189 | + resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.287.tgz#31fe253ce97fb2bf673a60c2467810a3f48a00c3" | |
1190 | + integrity sha512-wvmQDpHqzbYZv2mDsdp1eXUN+ff53FjElT19uVxFRPOkY2kaIhs7dMPS/ZeDD38TE2eH1arTzZ2KhtB+Mxe8VQ== | |
1191 | 1191 | |
1192 | 1192 | "@intlify/core-base@9.0.0-beta.16": |
1193 | 1193 | version "9.0.0-beta.16" |
... | ... | @@ -1494,10 +1494,10 @@ |
1494 | 1494 | resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69" |
1495 | 1495 | integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA== |
1496 | 1496 | |
1497 | -"@types/http-proxy@^1.17.4": | |
1498 | - version "1.17.4" | |
1499 | - resolved "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.4.tgz#e7c92e3dbe3e13aa799440ff42e6d3a17a9d045b" | |
1500 | - integrity sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q== | |
1497 | +"@types/http-proxy@^1.17.5": | |
1498 | + version "1.17.5" | |
1499 | + resolved "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz#c203c5e6e9dc6820d27a40eb1e511c70a220423d" | |
1500 | + integrity sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q== | |
1501 | 1501 | dependencies: |
1502 | 1502 | "@types/node" "*" |
1503 | 1503 | |
... | ... | @@ -1751,10 +1751,10 @@ |
1751 | 1751 | "@typescript-eslint/types" "4.13.0" |
1752 | 1752 | eslint-visitor-keys "^2.0.0" |
1753 | 1753 | |
1754 | -"@vitejs/plugin-legacy@^1.2.0": | |
1755 | - version "1.2.0" | |
1756 | - resolved "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.2.0.tgz#e6a2f7802f1a81c712f72656300fcdf7541eeab0" | |
1757 | - integrity sha512-eoJi1M7Or16bkRjXFtdG39c8ElvbgxUxlXFo8GO2VmgOGO42r6Ku5MJD4ZkweIM7XGunyFvmEwTYgpUVC4PiPg== | |
1754 | +"@vitejs/plugin-legacy@^1.2.1": | |
1755 | + version "1.2.1" | |
1756 | + resolved "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.2.1.tgz#783a72c56ce987f00caf334acc33195a0bbf6f24" | |
1757 | + integrity sha512-bVOYH7WxffDSvfFfCGk/UYCzKw59n18fHGOV3VXRSQmeaBmbxuq0CRdAS3EtPvp74DjgA4GiZ+BsrQ0LyF0/yA== | |
1758 | 1758 | dependencies: |
1759 | 1759 | "@babel/standalone" "^7.12.12" |
1760 | 1760 | core-js "^3.8.2" |
... | ... | @@ -1772,10 +1772,10 @@ |
1772 | 1772 | "@vue/babel-plugin-jsx" "^1.0.1" |
1773 | 1773 | hash-sum "^2.0.0" |
1774 | 1774 | |
1775 | -"@vitejs/plugin-vue@^1.0.5": | |
1776 | - version "1.0.5" | |
1777 | - resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.0.5.tgz#2639178e975bebc505e9be1c88d25faf9bc4dd06" | |
1778 | - integrity sha512-Fq/Z1rTs7j3QhvmIjeIHqInw2YneXa8Td3z7cYQhyAZXF/WmGMegbapeBqGAoAcGSOfWpOO7Tr0c/T+Qke0O6Q== | |
1775 | +"@vitejs/plugin-vue@^1.0.6": | |
1776 | + version "1.0.6" | |
1777 | + resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.0.6.tgz#698afa5a77a6dcd22cf7757801f46a6f01cdbb53" | |
1778 | + integrity sha512-cWJewtxnVVpjlhq6DoZ7VP7sF1jTZYVg66ehslZ0tJANWk1uRiCXdqD8yQ4npZ4XewDICQzK+c+9i3Xsubx59w== | |
1779 | 1779 | |
1780 | 1780 | "@vue/babel-helper-vue-transform-on@^1.0.0": |
1781 | 1781 | version "1.0.0" |
... | ... | @@ -2023,18 +2023,18 @@ |
2023 | 2023 | vscode-languageserver-textdocument "^1.0.1" |
2024 | 2024 | vscode-uri "^2.1.2" |
2025 | 2025 | |
2026 | -"@vueuse/core@^4.0.5": | |
2027 | - version "4.0.5" | |
2028 | - resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.0.5.tgz#97bd5f24a28401598436629312eafe66ed0e1bed" | |
2029 | - integrity sha512-Kfy5ys9o1XIY6NwX9O7iad4/FbHrcDuP/LtsgIFvl7XDQtbYArHu5ZSOQyBwqE32TdAqnFi5sYd4vjSvVvpD4A== | |
2026 | +"@vueuse/core@^4.0.8": | |
2027 | + version "4.0.8" | |
2028 | + resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.0.8.tgz#d5690154c147ae787bf5d67bf8fe3046dff96d85" | |
2029 | + integrity sha512-wD0JJUXpRgRBPCnGsAqcVk9Zz545zOmIjGv/1Mlco3rVmal7LEZ3rJh8SnBelxuyVNvRwifkK1gtbT24jY6V8Q== | |
2030 | 2030 | dependencies: |
2031 | - "@vueuse/shared" "4.0.5" | |
2031 | + "@vueuse/shared" "4.0.8" | |
2032 | 2032 | vue-demi latest |
2033 | 2033 | |
2034 | -"@vueuse/shared@4.0.5": | |
2035 | - version "4.0.5" | |
2036 | - resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.0.5.tgz#0610210da9a01843cdb3fa88c177b29b62738efc" | |
2037 | - integrity sha512-PUSlwoSaerwHA1PPjBGnerXPIvAcVGoxcpjNdbHW44lPqoWskWl2CxG+l2Iz+Zf2iapCatp3ovXnMd16RRvQ1Q== | |
2034 | +"@vueuse/shared@4.0.8": | |
2035 | + version "4.0.8" | |
2036 | + resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.0.8.tgz#ba6c350b5f0ef12e2a603d956cc6d2809ff5be4f" | |
2037 | + integrity sha512-euAfdZeFHGAyCBoy7izgufC/kTt+yEjuVjeCmfuDQNAj7QsdzEpRlyblD+EGifHbyGFx8F3Ql6/bQzdTdwRFHA== | |
2038 | 2038 | dependencies: |
2039 | 2039 | vue-demi latest |
2040 | 2040 | |
... | ... | @@ -2800,7 +2800,7 @@ commander@~2.17.1: |
2800 | 2800 | resolved "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" |
2801 | 2801 | integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== |
2802 | 2802 | |
2803 | -commitizen@^4.0.3, commitizen@^4.2.2: | |
2803 | +commitizen@^4.0.3: | |
2804 | 2804 | version "4.2.2" |
2805 | 2805 | resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.2.2.tgz#1a93dd07208521ea1ebbf832593542dac714cc79" |
2806 | 2806 | integrity sha512-uz+E6lGsDBDI2mYA4QfOxFeqdWUYwR1ky11YmLgg2BnEEP3YbeejpT4lxzGjkYqumnXr062qTOGavR9NtX/iwQ== |
... | ... | @@ -2820,6 +2820,26 @@ commitizen@^4.0.3, commitizen@^4.2.2: |
2820 | 2820 | strip-bom "4.0.0" |
2821 | 2821 | strip-json-comments "3.0.1" |
2822 | 2822 | |
2823 | +commitizen@^4.2.3: | |
2824 | + version "4.2.3" | |
2825 | + resolved "https://registry.npmjs.org/commitizen/-/commitizen-4.2.3.tgz#088d0ef72500240d331b11e02e288223667c1475" | |
2826 | + integrity sha512-pYlYEng7XMV2TW4xtjDKBGqeJ0Teq2zyRSx2S3Ml1XAplHSlJZK8vm1KdGclpMEZuGafbS5TeHXIVnHk8RWIzQ== | |
2827 | + dependencies: | |
2828 | + cachedir "2.2.0" | |
2829 | + cz-conventional-changelog "3.2.0" | |
2830 | + dedent "0.7.0" | |
2831 | + detect-indent "6.0.0" | |
2832 | + find-node-modules "2.0.0" | |
2833 | + find-root "1.1.0" | |
2834 | + fs-extra "8.1.0" | |
2835 | + glob "7.1.4" | |
2836 | + inquirer "6.5.2" | |
2837 | + is-utf8 "^0.2.1" | |
2838 | + lodash "^4.17.20" | |
2839 | + minimist "1.2.5" | |
2840 | + strip-bom "4.0.0" | |
2841 | + strip-json-comments "3.0.1" | |
2842 | + | |
2823 | 2843 | common-tags@^1.8.0: |
2824 | 2844 | version "1.8.0" |
2825 | 2845 | resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" |
... | ... | @@ -3159,6 +3179,20 @@ currently-unhandled@^0.4.1: |
3159 | 3179 | dependencies: |
3160 | 3180 | array-find-index "^1.0.1" |
3161 | 3181 | |
3182 | +cz-conventional-changelog@3.2.0: | |
3183 | + version "3.2.0" | |
3184 | + resolved "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz#6aef1f892d64113343d7e455529089ac9f20e477" | |
3185 | + integrity sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg== | |
3186 | + dependencies: | |
3187 | + chalk "^2.4.1" | |
3188 | + commitizen "^4.0.3" | |
3189 | + conventional-commit-types "^3.0.0" | |
3190 | + lodash.map "^4.5.1" | |
3191 | + longest "^2.0.1" | |
3192 | + word-wrap "^1.0.3" | |
3193 | + optionalDependencies: | |
3194 | + "@commitlint/load" ">6.1.1" | |
3195 | + | |
3162 | 3196 | cz-conventional-changelog@3.3.0: |
3163 | 3197 | version "3.3.0" |
3164 | 3198 | resolved "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz#9246947c90404149b3fe2cf7ee91acad3b7d22d2" |
... | ... | @@ -3571,13 +3605,13 @@ eslint-visitor-keys@^2.0.0: |
3571 | 3605 | resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" |
3572 | 3606 | integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== |
3573 | 3607 | |
3574 | -eslint@^7.17.0: | |
3575 | - version "7.17.0" | |
3576 | - resolved "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz#4ccda5bf12572ad3bf760e6f195886f50569adb0" | |
3577 | - integrity sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ== | |
3608 | +eslint@^7.18.0: | |
3609 | + version "7.18.0" | |
3610 | + resolved "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz#7fdcd2f3715a41fe6295a16234bd69aed2c75e67" | |
3611 | + integrity sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ== | |
3578 | 3612 | dependencies: |
3579 | 3613 | "@babel/code-frame" "^7.0.0" |
3580 | - "@eslint/eslintrc" "^0.2.2" | |
3614 | + "@eslint/eslintrc" "^0.3.0" | |
3581 | 3615 | ajv "^6.10.0" |
3582 | 3616 | chalk "^4.0.0" |
3583 | 3617 | cross-spawn "^7.0.2" |
... | ... | @@ -3601,7 +3635,7 @@ eslint@^7.17.0: |
3601 | 3635 | js-yaml "^3.13.1" |
3602 | 3636 | json-stable-stringify-without-jsonify "^1.0.1" |
3603 | 3637 | levn "^0.4.1" |
3604 | - lodash "^4.17.19" | |
3638 | + lodash "^4.17.20" | |
3605 | 3639 | minimatch "^3.0.4" |
3606 | 3640 | natural-compare "^1.4.0" |
3607 | 3641 | optionator "^0.9.1" |
... | ... | @@ -4423,10 +4457,10 @@ human-signals@^1.1.1: |
4423 | 4457 | resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" |
4424 | 4458 | integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== |
4425 | 4459 | |
4426 | -husky@^4.3.7: | |
4427 | - version "4.3.7" | |
4428 | - resolved "https://registry.npmjs.org/husky/-/husky-4.3.7.tgz#ca47bbe6213c1aa8b16bbd504530d9600de91e88" | |
4429 | - integrity sha512-0fQlcCDq/xypoyYSJvEuzbDPHFf8ZF9IXKJxlrnvxABTSzK1VPT2RKYQKrcgJ+YD39swgoB6sbzywUqFxUiqjw== | |
4460 | +husky@^4.3.8: | |
4461 | + version "4.3.8" | |
4462 | + resolved "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" | |
4463 | + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== | |
4430 | 4464 | dependencies: |
4431 | 4465 | chalk "^4.0.0" |
4432 | 4466 | ci-info "^2.0.0" |
... | ... | @@ -7840,20 +7874,20 @@ vite-plugin-purge-icons@^0.5.1: |
7840 | 7874 | "@purge-icons/generated" "^0.5.1" |
7841 | 7875 | rollup-plugin-purge-icons "^0.5.1" |
7842 | 7876 | |
7843 | -vite-plugin-pwa@^0.3.6: | |
7844 | - version "0.3.6" | |
7845 | - resolved "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.3.6.tgz#a522af3fd5461991907f6829975b437f2c847339" | |
7846 | - integrity sha512-GDgT8jFGHUz2j11I7Z0W+X5mnkaUoMVitJ/UjN/ezjy9HcXrvxaIVnhzMdESJSv+dxy4DD9ymD91cF9Ei6//cQ== | |
7877 | +vite-plugin-pwa@^0.3.8: | |
7878 | + version "0.3.8" | |
7879 | + resolved "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.3.8.tgz#c98a683ddbbe87bd55db79acb6a5c849f2a29879" | |
7880 | + integrity sha512-W5FBJeS3KjaCG1qu7LMTX9+E0u6qNHFk+hk917s4MnAlQ/XnBs30kgRXVBXtVAPhgvn8rqj2ww+2OYed+MKtIg== | |
7847 | 7881 | dependencies: |
7848 | 7882 | debug "^4.3.2" |
7849 | 7883 | fast-glob "^3.2.4" |
7850 | 7884 | pretty-bytes "^5.5.0" |
7851 | 7885 | workbox-build "^6.0.2" |
7852 | 7886 | |
7853 | -vite@^2.0.0-beta.27: | |
7854 | - version "2.0.0-beta.27" | |
7855 | - resolved "https://registry.npmjs.org/vite/-/vite-2.0.0-beta.27.tgz#a2e4b3a698e67c89fd963ff51ee5283ec564c65c" | |
7856 | - integrity sha512-1fGPjSVE4MmCGVguFy7pPurCLnvHu4fJSzVjejd9GoFqCNie+JKCpe3KGsxIb9B8ot/aDd4ISCB0+fH1/01FUA== | |
7887 | +vite@^2.0.0-beta.30: | |
7888 | + version "2.0.0-beta.30" | |
7889 | + resolved "https://registry.npmjs.org/vite/-/vite-2.0.0-beta.30.tgz#d0c1056d1fb05c489614360f92363eebec41a6b4" | |
7890 | + integrity sha512-wOeO64J3k4jGjCOkH/6RUcIyT/HOTaDZSiXE75aWYqV9hI7Q6uEeSXbAFtb9bG82RGLEWdsqtCvx5t7gaeqtsw== | |
7857 | 7891 | dependencies: |
7858 | 7892 | esbuild "^0.8.26" |
7859 | 7893 | postcss "^8.2.1" | ... | ... |