From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/layout/components/Menu/src/Menu.vue | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 272 insertions(+), 0 deletions(-)
diff --git a/src/layout/components/Menu/src/Menu.vue b/src/layout/components/Menu/src/Menu.vue
new file mode 100644
index 0000000..94a1da4
--- /dev/null
+++ b/src/layout/components/Menu/src/Menu.vue
@@ -0,0 +1,272 @@
+<script lang="tsx">
+import { PropType } from 'vue'
+import { ElMenu, ElScrollbar } from 'element-plus'
+import { useAppStore } from '@/store/modules/app'
+import { usePermissionStore } from '@/store/modules/permission'
+import { useRenderMenuItem } from './components/useRenderMenuItem'
+import { isUrl } from '@/utils/is'
+import { useDesign } from '@/hooks/web/useDesign'
+import { LayoutType } from '@/types/layout'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('menu')
+
+export default defineComponent({
+ // eslint-disable-next-line vue/no-reserved-component-names
+ name: 'Menu',
+ props: {
+ menuSelect: {
+ type: Function as PropType<(index: string) => void>,
+ default: undefined
+ }
+ },
+ setup(props) {
+ const appStore = useAppStore()
+
+ const layout = computed(() => appStore.getLayout)
+
+ const { push, currentRoute } = useRouter()
+
+ const permissionStore = usePermissionStore()
+
+ const menuMode = computed((): 'vertical' | 'horizontal' => {
+ // 绔�
+ const vertical: LayoutType[] = ['classic', 'topLeft', 'cutMenu']
+
+ if (vertical.includes(unref(layout))) {
+ return 'vertical'
+ } else {
+ return 'horizontal'
+ }
+ })
+
+ const routers = computed(() =>
+ unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
+ )
+
+ const collapse = computed(() => appStore.getCollapse)
+
+ const uniqueOpened = computed(() => appStore.getUniqueOpened)
+
+ const activeMenu = computed(() => {
+ const { meta, path } = unref(currentRoute)
+ // if set path, the sidebar will highlight the path you set
+ if (meta.activeMenu) {
+ return meta.activeMenu as string
+ }
+ return path
+ })
+
+ const menuSelect = (index: string) => {
+ if (props.menuSelect) {
+ props.menuSelect(index)
+ }
+ // 鑷畾涔変簨浠�
+ if (isUrl(index)) {
+ window.open(index)
+ } else {
+ push(index)
+ }
+ }
+
+ const renderMenuWrap = () => {
+ if (unref(layout) === 'top') {
+ return renderMenu()
+ } else {
+ return <ElScrollbar>{renderMenu()}</ElScrollbar>
+ }
+ }
+
+ const renderMenu = () => {
+ return (
+ <ElMenu
+ defaultActive={unref(activeMenu)}
+ mode={unref(menuMode)}
+ collapse={
+ unref(layout) === 'top' || unref(layout) === 'cutMenu' ? false : unref(collapse)
+ }
+ uniqueOpened={unref(layout) === 'top' ? false : unref(uniqueOpened)}
+ backgroundColor="var(--left-menu-bg-color)"
+ textColor="var(--left-menu-text-color)"
+ activeTextColor="var(--left-menu-text-active-color)"
+ popperClass={
+ unref(menuMode) === 'vertical'
+ ? `${prefixCls}-popper--vertical`
+ : `${prefixCls}-popper--horizontal`
+ }
+ onSelect={menuSelect}
+ >
+ {{
+ default: () => {
+ const { renderMenuItem } = useRenderMenuItem(unref(menuMode))
+ return renderMenuItem(unref(routers))
+ }
+ }}
+ </ElMenu>
+ )
+ }
+
+ return () => (
+ <div
+ id={prefixCls}
+ class={[
+ `${prefixCls} ${prefixCls}__${unref(menuMode)}`,
+ 'h-[100%] overflow-hidden flex-col bg-[var(--left-menu-bg-color)]',
+ {
+ 'w-[var(--left-menu-min-width)]': unref(collapse) && unref(layout) !== 'cutMenu',
+ 'w-[var(--left-menu-max-width)]': !unref(collapse) && unref(layout) !== 'cutMenu'
+ }
+ ]}
+ >
+ {renderMenuWrap()}
+ </div>
+ )
+ }
+})
+</script>
+
+<style lang="scss" scoped>
+$prefix-cls: #{$namespace}-menu;
+
+.#{$prefix-cls} {
+ position: relative;
+ transition: width var(--transition-time-02);
+
+ :deep(.#{$elNamespace}-menu) {
+ width: 100% !important;
+ border-right: none;
+
+ // 璁剧疆閫変腑鏃跺瓙鏍囬鐨勯鑹�
+ .is-active {
+ & > .#{$elNamespace}-sub-menu__title {
+ color: var(--left-menu-text-active-color) !important;
+ }
+ }
+
+ // 璁剧疆瀛愯彍鍗曟偓鍋滅殑楂樹寒鍜岃儗鏅壊
+ .#{$elNamespace}-sub-menu__title,
+ .#{$elNamespace}-menu-item {
+ &:hover {
+ color: var(--left-menu-text-active-color) !important;
+ background-color: var(--left-menu-bg-color) !important;
+ }
+ }
+
+ // 璁剧疆閫変腑鏃剁殑楂樹寒鑳屾櫙鍜岄珮浜鑹�
+ .#{$elNamespace}-menu-item.is-active {
+ color: var(--left-menu-text-active-color) !important;
+ background-color: var(--left-menu-bg-active-color) !important;
+
+ &:hover {
+ background-color: var(--left-menu-bg-active-color) !important;
+ }
+ }
+
+ .#{$elNamespace}-menu-item.is-active {
+ position: relative;
+ }
+
+ // 璁剧疆瀛愯彍鍗曠殑鑳屾櫙棰滆壊
+ .#{$elNamespace}-menu {
+ .#{$elNamespace}-sub-menu__title,
+ .#{$elNamespace}-menu-item:not(.is-active) {
+ background-color: var(--left-menu-bg-light-color) !important;
+ }
+ }
+ }
+
+ // 鎶樺彔鏃剁殑鏈�灏忓搴�
+ :deep(.#{$elNamespace}-menu--collapse) {
+ width: var(--left-menu-min-width);
+
+ & > .is-active,
+ & > .is-active > .#{$elNamespace}-sub-menu__title {
+ position: relative;
+ background-color: var(--left-menu-collapse-bg-active-color) !important;
+ }
+ }
+
+ // 鎶樺彔鍔ㄧ敾鐨勬椂鍊欙紝灏遍渶瑕佹妸鏂囧瓧缁欓殣钘忔帀
+ :deep(.horizontal-collapse-transition) {
+ // transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
+ .#{$prefix-cls}__title {
+ display: none;
+ }
+ }
+
+ // 鍨傜洿鑿滃崟
+ &__vertical {
+ :deep(.#{$elNamespace}-menu--vertical) {
+ &:not(.#{$elNamespace}-menu--collapse) .#{$elNamespace}-sub-menu__title,
+ .#{$elNamespace}-menu-item {
+ padding-right: 0;
+ }
+ }
+ }
+
+ // 姘村钩鑿滃崟
+ &__horizontal {
+ height: calc(var(--top-tool-height)) !important;
+
+ :deep(.#{$elNamespace}-menu--horizontal) {
+ height: calc(var(--top-tool-height));
+ border-bottom: none;
+ // 閲嶆柊璁剧疆搴曢儴楂樹寒棰滆壊
+ & > .#{$elNamespace}-sub-menu.is-active {
+ .#{$elNamespace}-sub-menu__title {
+ border-bottom-color: var(--el-color-primary) !important;
+ }
+ }
+
+ .#{$elNamespace}-menu-item.is-active {
+ position: relative;
+
+ &::after {
+ display: none !important;
+ }
+ }
+
+ .#{$prefix-cls}__title {
+ /* stylelint-disable-next-line */
+ max-height: calc(var(--top-tool-height) - 2px) !important;
+ /* stylelint-disable-next-line */
+ line-height: calc(var(--top-tool-height) - 2px);
+ }
+ }
+ }
+}
+</style>
+
+<style lang="scss">
+$prefix-cls: #{$namespace}-menu-popper;
+
+.#{$prefix-cls}--vertical,
+.#{$prefix-cls}--horizontal {
+ // 璁剧疆閫変腑鏃跺瓙鏍囬鐨勯鑹�
+ .is-active {
+ & > .el-sub-menu__title {
+ color: var(--left-menu-text-active-color) !important;
+ }
+ }
+
+ // 璁剧疆瀛愯彍鍗曟偓鍋滅殑楂樹寒鍜岃儗鏅壊
+ .el-sub-menu__title,
+ .el-menu-item {
+ &:hover {
+ color: var(--left-menu-text-active-color) !important;
+ background-color: var(--left-menu-bg-color) !important;
+ }
+ }
+
+ // 璁剧疆閫変腑鏃剁殑楂樹寒鑳屾櫙
+ .el-menu-item.is-active {
+ position: relative;
+ background-color: var(--left-menu-bg-active-color) !important;
+
+ &:hover {
+ background-color: var(--left-menu-bg-active-color) !important;
+ }
+ }
+}
+</style>
--
Gitblit v1.8.0