@robot-admin/naive-ui-components 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/C_Menu.cjs +1 -1
  3. package/dist/C_Menu.js +1 -1
  4. package/dist/C_Menu.js.map +1 -1
  5. package/dist/C_Menu2.js.map +1 -1
  6. package/dist/_shared.cjs +1 -1
  7. package/dist/_shared.js +1 -1
  8. package/dist/constants.d.ts +1 -1
  9. package/dist/constants2.d.ts +2 -2
  10. package/dist/constants3.d.ts +5 -5
  11. package/dist/constants4.d.ts +3 -3
  12. package/dist/constants5.d.ts +2 -2
  13. package/dist/data.d.ts +2 -2
  14. package/dist/index.vue.d.ts +1 -1
  15. package/dist/index11.vue.d.ts +7 -7
  16. package/dist/index13.vue.d.ts +4 -4
  17. package/dist/index15.vue.d.ts +3 -3
  18. package/dist/index16.vue.d.ts +1 -1
  19. package/dist/index17.vue.d.ts +1 -1
  20. package/dist/index19.vue.d.ts +3 -3
  21. package/dist/index2.vue.d.ts +1 -1
  22. package/dist/index7.vue.d.ts +3 -3
  23. package/dist/index8.vue.d.ts +1 -1
  24. package/dist/index9.vue.d.ts +2 -2
  25. package/dist/menuAdapter.js +1 -1
  26. package/dist/menuAdapter.js.map +1 -1
  27. package/dist/useCalendarEvents.d.ts +1 -1
  28. package/dist/useCollapsePanel.d.ts +4 -4
  29. package/dist/useCropperCore.d.ts +4 -4
  30. package/dist/useDraggableLayout.d.ts +9 -9
  31. package/dist/useDynamicFormState.d.ts +116 -116
  32. package/dist/useEdgeInteraction.d.ts +2 -2
  33. package/dist/useInfiniteScroll.d.ts +2 -2
  34. package/dist/useModalEdit.d.ts +2 -2
  35. package/dist/useQRCode.d.ts +4 -4
  36. package/dist/useSignatureHistory.d.ts +2 -2
  37. package/dist/useSplitResize.d.ts +5 -5
  38. package/dist/useTimeSelection.d.ts +2 -2
  39. package/dist/useTreeOperations.d.ts +6 -6
  40. package/dist/useWorkflowValidation.d.ts +2 -2
  41. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @robot-admin/naive-ui-components
2
2
 
3
+ ## 0.6.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 菜单图标渲染统一使用 C_Icon 组件
8
+ - menuAdapter.defaultRenderIcon 改用组件库自有的 C_Icon 替代直接使用 NIcon + @iconify/vue
9
+ - 与 C_Breadcrumb、C_TagsView 等组件保持一致的图标渲染方式
10
+ - 彻底解决生产环境图标对齐问题
11
+
3
12
  ## 0.6.2
4
13
 
5
14
  ### Patch Changes
package/dist/C_Menu.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./C_Menu.js`);exports.C_Menu=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./C_Icon.js`);const e=require(`./C_Menu.js`);exports.C_Menu=e.t;
package/dist/C_Menu.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./C_Menu2.js";export{e as C_Menu};
1
+ import"./C_Icon2.js";import{t as e}from"./C_Menu2.js";export{e as C_Menu};
@@ -1 +1 @@
1
- {"version":3,"file":"C_Menu.js","names":["mode","collapsed","collapsedWidth","collapsedIconSize","inverted","themeOverrides","dropdownProps","indent","rootIndent"],"sources":["../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\r\n *\r\n * 支持两种数据输入模式:\r\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\r\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\r\n *\r\n * @example 路由模式(推荐)\r\n * ```vue\r\n * <C_Menu\r\n * :routes=\"menuData\"\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 原生模式\r\n * ```vue\r\n * <C_Menu\r\n * :options=\"nMenuOptions\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NMenu\r\n ref=\"menuRef\"\r\n :options=\"mergedOptions\"\r\n :expanded-keys=\"expandedKeys\"\r\n :value=\"activeKey\"\r\n :mode=\"mode\"\r\n :collapsed=\"collapsed\"\r\n :collapsed-width=\"collapsedWidth\"\r\n :collapsed-icon-size=\"collapsedIconSize\"\r\n :inverted=\"inverted\"\r\n :theme-overrides=\"themeOverrides\"\r\n :dropdown-props=\"dropdownProps\"\r\n :indent=\"indent\"\r\n :root-indent=\"rootIndent\"\r\n @update:value=\"handleMenuClick\"\r\n @update:expanded-keys=\"onExpandedKeysChange\"\r\n />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\r\n import {\r\n type MenuOption,\r\n type MenuInst,\r\n type DropdownProps,\r\n } from 'naive-ui/es'\r\n import {\r\n createMenuOptions,\r\n type RouteItem,\r\n type MenuAdapterConfig,\r\n } from '../_shared'\r\n\r\n defineOptions({ name: 'C_Menu' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 模式一:直传 NMenu 原生 MenuOption[]\r\n * 与 `routes` 二选一,`options` 优先级更高\r\n */\r\n options?: MenuOption[]\r\n /**\r\n * 模式二:传入路由数据,自动转换为 MenuOption[]\r\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\r\n */\r\n routes?: RouteItem[]\r\n /**\r\n * 适配器配置(仅 routes 模式生效)\r\n * 可自定义 key/label/icon 取值、过滤逻辑等\r\n */\r\n adapterConfig?: MenuAdapterConfig\r\n /**\r\n * 标签文本格式化函数(routes 模式的快捷方式)\r\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 当前激活的菜单 key */\r\n value?: string\r\n /** 菜单模式 */\r\n mode?: 'vertical' | 'horizontal'\r\n /** 是否折叠 */\r\n collapsed?: boolean\r\n /** 折叠宽度 */\r\n collapsedWidth?: number\r\n /** 折叠图标大小 */\r\n collapsedIconSize?: number\r\n /** 是否反色 */\r\n inverted?: boolean\r\n /** 主题覆盖 */\r\n themeOverrides?: Record<string, any>\r\n /** 缩进像素 */\r\n indent?: number\r\n /** 根缩进像素 */\r\n rootIndent?: number\r\n /** 下拉菜单属性(折叠模式) */\r\n dropdownProps?: DropdownProps\r\n }>(),\r\n {\r\n mode: 'vertical',\r\n collapsed: false,\r\n collapsedWidth: 64,\r\n collapsedIconSize: 22,\r\n inverted: false,\r\n indent: 24,\r\n rootIndent: 16,\r\n dropdownProps: () => ({\r\n placement: 'right-start' as const,\r\n trigger: 'hover' as const,\r\n arrowStyle: { color: 'var(--n-color)' },\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 菜单项被选中 */\r\n select: [key: string]\r\n /** 展开项变化 */\r\n 'update:expandedKeys': [keys: string[]]\r\n }>()\r\n\r\n const menuRef = ref<MenuInst | null>(null)\r\n const expandedKeys = ref<string[]>([])\r\n\r\n const activeKey = computed(() => props.value ?? '')\r\n\r\n // ====== 数据合成 ======\r\n\r\n /** 合并后的最终 MenuOption[] */\r\n const mergedOptions = computed<MenuOption[]>(() => {\r\n // 优先使用 options 直传模式\r\n if (props.options) return props.options\r\n\r\n // routes 模式 → 适配器转换\r\n if (props.routes) {\r\n const config: MenuAdapterConfig = {\r\n ...props.adapterConfig,\r\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\r\n }\r\n return createMenuOptions(props.routes, config)\r\n }\r\n\r\n return []\r\n })\r\n\r\n // ====== 展开逻辑 ======\r\n\r\n /** 从 MenuOption[] 中查找所有祖先 key */\r\n const findParentKeys = (\r\n items: MenuOption[],\r\n targetKey: string,\r\n parentKeys: string[] = []\r\n ): string[] => {\r\n for (const item of items) {\r\n const children = item.children as MenuOption[] | undefined\r\n if (children?.length) {\r\n const currentKeys = [...parentKeys, item.key as string]\r\n if (children.some(child => child.key === targetKey)) {\r\n return currentKeys\r\n }\r\n const result = findParentKeys(children, targetKey, currentKeys)\r\n if (result.length > 0) return result\r\n }\r\n }\r\n return []\r\n }\r\n\r\n /** 通过路径段推导展开 key + 查找祖先 key */\r\n const computeExpandedKeys = (path: string): Set<string> => {\r\n const segments = path.split('/').filter(Boolean)\r\n const keys = new Set<string>()\r\n let currentPath = ''\r\n segments.forEach(segment => {\r\n currentPath += `/${segment}`\r\n keys.add(currentPath)\r\n })\r\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\r\n return keys\r\n }\r\n\r\n // ====== 事件处理 ======\r\n\r\n const handleMenuClick = (key: string) => {\r\n if (key && key !== activeKey.value) {\r\n emit('select', key)\r\n }\r\n }\r\n\r\n const onExpandedKeysChange = (keys: string[]) => {\r\n expandedKeys.value = keys\r\n emit('update:expandedKeys', keys)\r\n }\r\n\r\n // ====== 暴露方法 ======\r\n const showOption = (key: string) => menuRef.value?.showOption(key)\r\n defineExpose({ showOption, menuRef })\r\n\r\n // ====== 路由跟踪 ======\r\n\r\n watch(\r\n () => activeKey.value,\r\n newKey => {\r\n if (!newKey) return\r\n const newKeys = computeExpandedKeys(newKey)\r\n expandedKeys.value = Array.from(\r\n new Set([...expandedKeys.value, ...newKeys])\r\n )\r\n nextTick(() => menuRef.value?.showOption(newKey))\r\n },\r\n { immediate: true }\r\n )\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n if (activeKey.value) {\r\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\r\n menuRef.value?.showOption(activeKey.value)\r\n }\r\n })\r\n })\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\r\n *\r\n * 支持两种数据输入模式:\r\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\r\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\r\n *\r\n * @example 路由模式(推荐)\r\n * ```vue\r\n * <C_Menu\r\n * :routes=\"menuData\"\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 原生模式\r\n * ```vue\r\n * <C_Menu\r\n * :options=\"nMenuOptions\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NMenu\r\n ref=\"menuRef\"\r\n :options=\"mergedOptions\"\r\n :expanded-keys=\"expandedKeys\"\r\n :value=\"activeKey\"\r\n :mode=\"mode\"\r\n :collapsed=\"collapsed\"\r\n :collapsed-width=\"collapsedWidth\"\r\n :collapsed-icon-size=\"collapsedIconSize\"\r\n :inverted=\"inverted\"\r\n :theme-overrides=\"themeOverrides\"\r\n :dropdown-props=\"dropdownProps\"\r\n :indent=\"indent\"\r\n :root-indent=\"rootIndent\"\r\n @update:value=\"handleMenuClick\"\r\n @update:expanded-keys=\"onExpandedKeysChange\"\r\n />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\r\n import {\r\n type MenuOption,\r\n type MenuInst,\r\n type DropdownProps,\r\n } from 'naive-ui/es'\r\n import {\r\n createMenuOptions,\r\n type RouteItem,\r\n type MenuAdapterConfig,\r\n } from '../_shared'\r\n\r\n defineOptions({ name: 'C_Menu' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 模式一:直传 NMenu 原生 MenuOption[]\r\n * 与 `routes` 二选一,`options` 优先级更高\r\n */\r\n options?: MenuOption[]\r\n /**\r\n * 模式二:传入路由数据,自动转换为 MenuOption[]\r\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\r\n */\r\n routes?: RouteItem[]\r\n /**\r\n * 适配器配置(仅 routes 模式生效)\r\n * 可自定义 key/label/icon 取值、过滤逻辑等\r\n */\r\n adapterConfig?: MenuAdapterConfig\r\n /**\r\n * 标签文本格式化函数(routes 模式的快捷方式)\r\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 当前激活的菜单 key */\r\n value?: string\r\n /** 菜单模式 */\r\n mode?: 'vertical' | 'horizontal'\r\n /** 是否折叠 */\r\n collapsed?: boolean\r\n /** 折叠宽度 */\r\n collapsedWidth?: number\r\n /** 折叠图标大小 */\r\n collapsedIconSize?: number\r\n /** 是否反色 */\r\n inverted?: boolean\r\n /** 主题覆盖 */\r\n themeOverrides?: Record<string, any>\r\n /** 缩进像素 */\r\n indent?: number\r\n /** 根缩进像素 */\r\n rootIndent?: number\r\n /** 下拉菜单属性(折叠模式) */\r\n dropdownProps?: DropdownProps\r\n }>(),\r\n {\r\n mode: 'vertical',\r\n collapsed: false,\r\n collapsedWidth: 64,\r\n collapsedIconSize: 22,\r\n inverted: false,\r\n indent: 24,\r\n rootIndent: 16,\r\n dropdownProps: () => ({\r\n placement: 'right-start' as const,\r\n trigger: 'hover' as const,\r\n arrowStyle: { color: 'var(--n-color)' },\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 菜单项被选中 */\r\n select: [key: string]\r\n /** 展开项变化 */\r\n 'update:expandedKeys': [keys: string[]]\r\n }>()\r\n\r\n const menuRef = ref<MenuInst | null>(null)\r\n const expandedKeys = ref<string[]>([])\r\n\r\n const activeKey = computed(() => props.value ?? '')\r\n\r\n // ====== 数据合成 ======\r\n\r\n /** 合并后的最终 MenuOption[] */\r\n const mergedOptions = computed<MenuOption[]>(() => {\r\n // 优先使用 options 直传模式\r\n if (props.options) return props.options\r\n\r\n // routes 模式 → 适配器转换\r\n if (props.routes) {\r\n const config: MenuAdapterConfig = {\r\n ...props.adapterConfig,\r\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\r\n }\r\n return createMenuOptions(props.routes, config)\r\n }\r\n\r\n return []\r\n })\r\n\r\n // ====== 展开逻辑 ======\r\n\r\n /** 从 MenuOption[] 中查找所有祖先 key */\r\n const findParentKeys = (\r\n items: MenuOption[],\r\n targetKey: string,\r\n parentKeys: string[] = []\r\n ): string[] => {\r\n for (const item of items) {\r\n const children = item.children as MenuOption[] | undefined\r\n if (children?.length) {\r\n const currentKeys = [...parentKeys, item.key as string]\r\n if (children.some(child => child.key === targetKey)) {\r\n return currentKeys\r\n }\r\n const result = findParentKeys(children, targetKey, currentKeys)\r\n if (result.length > 0) return result\r\n }\r\n }\r\n return []\r\n }\r\n\r\n /** 通过路径段推导展开 key + 查找祖先 key */\r\n const computeExpandedKeys = (path: string): Set<string> => {\r\n const segments = path.split('/').filter(Boolean)\r\n const keys = new Set<string>()\r\n let currentPath = ''\r\n segments.forEach(segment => {\r\n currentPath += `/${segment}`\r\n keys.add(currentPath)\r\n })\r\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\r\n return keys\r\n }\r\n\r\n // ====== 事件处理 ======\r\n\r\n const handleMenuClick = (key: string) => {\r\n if (key && key !== activeKey.value) {\r\n emit('select', key)\r\n }\r\n }\r\n\r\n const onExpandedKeysChange = (keys: string[]) => {\r\n expandedKeys.value = keys\r\n emit('update:expandedKeys', keys)\r\n }\r\n\r\n // ====== 暴露方法 ======\r\n const showOption = (key: string) => menuRef.value?.showOption(key)\r\n defineExpose({ showOption, menuRef })\r\n\r\n // ====== 路由跟踪 ======\r\n\r\n watch(\r\n () => activeKey.value,\r\n newKey => {\r\n if (!newKey) return\r\n const newKeys = computeExpandedKeys(newKey)\r\n expandedKeys.value = Array.from(\r\n new Set([...expandedKeys.value, ...newKeys])\r\n )\r\n nextTick(() => menuRef.value?.showOption(newKey))\r\n },\r\n { immediate: true }\r\n )\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n if (activeKey.value) {\r\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\r\n menuRef.value?.showOption(activeKey.value)\r\n }\r\n })\r\n })\r\n</script>\r\n","<!--\r\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\r\n *\r\n * 支持两种数据输入模式:\r\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\r\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\r\n *\r\n * @example 路由模式(推荐)\r\n * ```vue\r\n * <C_Menu\r\n * :routes=\"menuData\"\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 原生模式\r\n * ```vue\r\n * <C_Menu\r\n * :options=\"nMenuOptions\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NMenu\r\n ref=\"menuRef\"\r\n :options=\"mergedOptions\"\r\n :expanded-keys=\"expandedKeys\"\r\n :value=\"activeKey\"\r\n :mode=\"mode\"\r\n :collapsed=\"collapsed\"\r\n :collapsed-width=\"collapsedWidth\"\r\n :collapsed-icon-size=\"collapsedIconSize\"\r\n :inverted=\"inverted\"\r\n :theme-overrides=\"themeOverrides\"\r\n :dropdown-props=\"dropdownProps\"\r\n :indent=\"indent\"\r\n :root-indent=\"rootIndent\"\r\n @update:value=\"handleMenuClick\"\r\n @update:expanded-keys=\"onExpandedKeysChange\"\r\n />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\r\n import {\r\n type MenuOption,\r\n type MenuInst,\r\n type DropdownProps,\r\n } from 'naive-ui/es'\r\n import {\r\n createMenuOptions,\r\n type RouteItem,\r\n type MenuAdapterConfig,\r\n } from '../_shared'\r\n\r\n defineOptions({ name: 'C_Menu' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 模式一:直传 NMenu 原生 MenuOption[]\r\n * 与 `routes` 二选一,`options` 优先级更高\r\n */\r\n options?: MenuOption[]\r\n /**\r\n * 模式二:传入路由数据,自动转换为 MenuOption[]\r\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\r\n */\r\n routes?: RouteItem[]\r\n /**\r\n * 适配器配置(仅 routes 模式生效)\r\n * 可自定义 key/label/icon 取值、过滤逻辑等\r\n */\r\n adapterConfig?: MenuAdapterConfig\r\n /**\r\n * 标签文本格式化函数(routes 模式的快捷方式)\r\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 当前激活的菜单 key */\r\n value?: string\r\n /** 菜单模式 */\r\n mode?: 'vertical' | 'horizontal'\r\n /** 是否折叠 */\r\n collapsed?: boolean\r\n /** 折叠宽度 */\r\n collapsedWidth?: number\r\n /** 折叠图标大小 */\r\n collapsedIconSize?: number\r\n /** 是否反色 */\r\n inverted?: boolean\r\n /** 主题覆盖 */\r\n themeOverrides?: Record<string, any>\r\n /** 缩进像素 */\r\n indent?: number\r\n /** 根缩进像素 */\r\n rootIndent?: number\r\n /** 下拉菜单属性(折叠模式) */\r\n dropdownProps?: DropdownProps\r\n }>(),\r\n {\r\n mode: 'vertical',\r\n collapsed: false,\r\n collapsedWidth: 64,\r\n collapsedIconSize: 22,\r\n inverted: false,\r\n indent: 24,\r\n rootIndent: 16,\r\n dropdownProps: () => ({\r\n placement: 'right-start' as const,\r\n trigger: 'hover' as const,\r\n arrowStyle: { color: 'var(--n-color)' },\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 菜单项被选中 */\r\n select: [key: string]\r\n /** 展开项变化 */\r\n 'update:expandedKeys': [keys: string[]]\r\n }>()\r\n\r\n const menuRef = ref<MenuInst | null>(null)\r\n const expandedKeys = ref<string[]>([])\r\n\r\n const activeKey = computed(() => props.value ?? '')\r\n\r\n // ====== 数据合成 ======\r\n\r\n /** 合并后的最终 MenuOption[] */\r\n const mergedOptions = computed<MenuOption[]>(() => {\r\n // 优先使用 options 直传模式\r\n if (props.options) return props.options\r\n\r\n // routes 模式 → 适配器转换\r\n if (props.routes) {\r\n const config: MenuAdapterConfig = {\r\n ...props.adapterConfig,\r\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\r\n }\r\n return createMenuOptions(props.routes, config)\r\n }\r\n\r\n return []\r\n })\r\n\r\n // ====== 展开逻辑 ======\r\n\r\n /** 从 MenuOption[] 中查找所有祖先 key */\r\n const findParentKeys = (\r\n items: MenuOption[],\r\n targetKey: string,\r\n parentKeys: string[] = []\r\n ): string[] => {\r\n for (const item of items) {\r\n const children = item.children as MenuOption[] | undefined\r\n if (children?.length) {\r\n const currentKeys = [...parentKeys, item.key as string]\r\n if (children.some(child => child.key === targetKey)) {\r\n return currentKeys\r\n }\r\n const result = findParentKeys(children, targetKey, currentKeys)\r\n if (result.length > 0) return result\r\n }\r\n }\r\n return []\r\n }\r\n\r\n /** 通过路径段推导展开 key + 查找祖先 key */\r\n const computeExpandedKeys = (path: string): Set<string> => {\r\n const segments = path.split('/').filter(Boolean)\r\n const keys = new Set<string>()\r\n let currentPath = ''\r\n segments.forEach(segment => {\r\n currentPath += `/${segment}`\r\n keys.add(currentPath)\r\n })\r\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\r\n return keys\r\n }\r\n\r\n // ====== 事件处理 ======\r\n\r\n const handleMenuClick = (key: string) => {\r\n if (key && key !== activeKey.value) {\r\n emit('select', key)\r\n }\r\n }\r\n\r\n const onExpandedKeysChange = (keys: string[]) => {\r\n expandedKeys.value = keys\r\n emit('update:expandedKeys', keys)\r\n }\r\n\r\n // ====== 暴露方法 ======\r\n const showOption = (key: string) => menuRef.value?.showOption(key)\r\n defineExpose({ showOption, menuRef })\r\n\r\n // ====== 路由跟踪 ======\r\n\r\n watch(\r\n () => activeKey.value,\r\n newKey => {\r\n if (!newKey) return\r\n const newKeys = computeExpandedKeys(newKey)\r\n expandedKeys.value = Array.from(\r\n new Set([...expandedKeys.value, ...newKeys])\r\n )\r\n nextTick(() => menuRef.value?.showOption(newKey))\r\n },\r\n { immediate: true }\r\n )\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n if (activeKey.value) {\r\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\r\n menuRef.value?.showOption(activeKey.value)\r\n }\r\n })\r\n })\r\n</script>\r\n"],"mappings":"gnBE6DE,IAAM,EAAQ,EA2DR,EAAO,EAOP,GAAA,EAAA,EAAA,KAA+B,KAAK,CACpC,GAAA,EAAA,EAAA,KAA6B,EAAE,CAAC,CAEhC,GAAA,EAAA,EAAA,cAA2B,EAAM,OAAS,GAAG,CAK7C,GAAA,EAAA,EAAA,cAA6C,CAEjD,GAAI,EAAM,QAAS,OAAO,EAAM,QAGhC,GAAI,EAAM,OAAQ,CAChB,IAAM,EAA4B,CAChC,GAAG,EAAM,cACT,GAAI,EAAM,gBAAkB,CAAE,eAAgB,EAAM,eAAgB,CACrE,CACD,OAAO,EAAA,EAAkB,EAAM,OAAQ,EAAO,CAGhD,MAAO,EAAE,EACT,CAKI,GACJ,EACA,EACA,EAAuB,EAAE,GACZ,CACb,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,SACtB,GAAI,GAAU,OAAQ,CACpB,IAAM,EAAc,CAAC,GAAG,EAAY,EAAK,IAAc,CACvD,GAAI,EAAS,KAAK,GAAS,EAAM,MAAQ,EAAU,CACjD,OAAO,EAET,IAAM,EAAS,EAAe,EAAU,EAAW,EAAY,CAC/D,GAAI,EAAO,OAAS,EAAG,OAAO,GAGlC,MAAO,EAAE,EAIL,EAAuB,GAA8B,CACzD,IAAM,EAAW,EAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAC1C,EAAO,IAAI,IACb,EAAc,GAMlB,OALA,EAAS,QAAQ,GAAW,CAC1B,GAAe,IAAI,IACnB,EAAK,IAAI,EAAY,EACrB,CACF,EAAe,EAAc,MAAO,EAAK,CAAC,QAAQ,GAAO,EAAK,IAAI,EAAI,CAAC,CAChE,GAKH,EAAmB,GAAgB,CACnC,GAAO,IAAQ,EAAU,OAC3B,EAAK,SAAU,EAAI,EAIjB,EAAwB,GAAmB,CAC/C,EAAa,MAAQ,EACrB,EAAK,sBAAuB,EAAK,SAKnC,EAAa,CAAE,WADK,GAAgB,EAAQ,OAAO,WAAW,EAAI,CACvC,UAAS,CAAC,EAIrC,EAAA,EAAA,WACQ,EAAU,MAChB,GAAU,CACR,GAAI,CAAC,EAAQ,OACb,IAAM,EAAU,EAAoB,EAAO,CAC3C,EAAa,MAAQ,MAAM,KACzB,IAAI,IAAI,CAAC,GAAG,EAAa,MAAO,GAAG,EAAQ,CAAC,CAC7C,EACD,EAAA,EAAA,cAAe,EAAQ,OAAO,WAAW,EAAO,CAAC,EAEnD,CAAE,UAAW,GAAM,CACpB,EAED,EAAA,EAAA,eAAgB,EACd,EAAA,EAAA,cAAe,CACT,EAAU,QACZ,EAAa,MAAQ,MAAM,KAAK,EAAoB,EAAU,MAAM,CAAC,CACrE,EAAQ,OAAO,WAAW,EAAU,MAAM,GAE5C,EACF,iEAtLA,EAAA,SAfI,UAAJ,IAAI,EACH,QAAS,EAAA,MACT,gBAAe,EAAA,MACf,MAAO,EAAA,MACP,KAAMA,EAAAA,KACN,UAAWC,EAAAA,UACX,kBAAiBC,EAAAA,eACjB,sBAAqBC,EAAAA,kBACrB,SAAUC,EAAAA,SACV,kBAAiBC,EAAAA,eACjB,iBAAgBC,EAAAA,cAChB,OAAQC,EAAAA,OACR,cAAaC,EAAAA,WACb,iBAAc,EACd,wBAAsB"}
1
+ {"version":3,"file":"C_Menu.js","names":["mode","collapsed","collapsedWidth","collapsedIconSize","inverted","themeOverrides","dropdownProps","indent","rootIndent"],"sources":["../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\n *\n * 支持两种数据输入模式:\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\n *\n * @example 路由模式(推荐)\n * ```vue\n * <C_Menu\n * :routes=\"menuData\"\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 原生模式\n * ```vue\n * <C_Menu\n * :options=\"nMenuOptions\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <NMenu\n ref=\"menuRef\"\n :options=\"mergedOptions\"\n :expanded-keys=\"expandedKeys\"\n :value=\"activeKey\"\n :mode=\"mode\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"collapsedWidth\"\n :collapsed-icon-size=\"collapsedIconSize\"\n :inverted=\"inverted\"\n :theme-overrides=\"themeOverrides\"\n :dropdown-props=\"dropdownProps\"\n :indent=\"indent\"\n :root-indent=\"rootIndent\"\n @update:value=\"handleMenuClick\"\n @update:expanded-keys=\"onExpandedKeysChange\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\n import {\n type MenuOption,\n type MenuInst,\n type DropdownProps,\n } from 'naive-ui/es'\n import {\n createMenuOptions,\n type RouteItem,\n type MenuAdapterConfig,\n } from '../_shared'\n\n defineOptions({ name: 'C_Menu' })\n\n const props = withDefaults(\n defineProps<{\n /**\n * 模式一:直传 NMenu 原生 MenuOption[]\n * 与 `routes` 二选一,`options` 优先级更高\n */\n options?: MenuOption[]\n /**\n * 模式二:传入路由数据,自动转换为 MenuOption[]\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\n */\n routes?: RouteItem[]\n /**\n * 适配器配置(仅 routes 模式生效)\n * 可自定义 key/label/icon 取值、过滤逻辑等\n */\n adapterConfig?: MenuAdapterConfig\n /**\n * 标签文本格式化函数(routes 模式的快捷方式)\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\n */\n labelFormatter?: (label: string) => string\n /** 当前激活的菜单 key */\n value?: string\n /** 菜单模式 */\n mode?: 'vertical' | 'horizontal'\n /** 是否折叠 */\n collapsed?: boolean\n /** 折叠宽度 */\n collapsedWidth?: number\n /** 折叠图标大小 */\n collapsedIconSize?: number\n /** 是否反色 */\n inverted?: boolean\n /** 主题覆盖 */\n themeOverrides?: Record<string, any>\n /** 缩进像素 */\n indent?: number\n /** 根缩进像素 */\n rootIndent?: number\n /** 下拉菜单属性(折叠模式) */\n dropdownProps?: DropdownProps\n }>(),\n {\n mode: 'vertical',\n collapsed: false,\n collapsedWidth: 64,\n collapsedIconSize: 22,\n inverted: false,\n indent: 24,\n rootIndent: 16,\n dropdownProps: () => ({\n placement: 'right-start' as const,\n trigger: 'hover' as const,\n arrowStyle: { color: 'var(--n-color)' },\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 菜单项被选中 */\n select: [key: string]\n /** 展开项变化 */\n 'update:expandedKeys': [keys: string[]]\n }>()\n\n const menuRef = ref<MenuInst | null>(null)\n const expandedKeys = ref<string[]>([])\n\n const activeKey = computed(() => props.value ?? '')\n\n // ====== 数据合成 ======\n\n /** 合并后的最终 MenuOption[] */\n const mergedOptions = computed<MenuOption[]>(() => {\n // 优先使用 options 直传模式\n if (props.options) return props.options\n\n // routes 模式 → 适配器转换\n if (props.routes) {\n const config: MenuAdapterConfig = {\n ...props.adapterConfig,\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\n }\n return createMenuOptions(props.routes, config)\n }\n\n return []\n })\n\n // ====== 展开逻辑 ======\n\n /** 从 MenuOption[] 中查找所有祖先 key */\n const findParentKeys = (\n items: MenuOption[],\n targetKey: string,\n parentKeys: string[] = []\n ): string[] => {\n for (const item of items) {\n const children = item.children as MenuOption[] | undefined\n if (children?.length) {\n const currentKeys = [...parentKeys, item.key as string]\n if (children.some(child => child.key === targetKey)) {\n return currentKeys\n }\n const result = findParentKeys(children, targetKey, currentKeys)\n if (result.length > 0) return result\n }\n }\n return []\n }\n\n /** 通过路径段推导展开 key + 查找祖先 key */\n const computeExpandedKeys = (path: string): Set<string> => {\n const segments = path.split('/').filter(Boolean)\n const keys = new Set<string>()\n let currentPath = ''\n segments.forEach(segment => {\n currentPath += `/${segment}`\n keys.add(currentPath)\n })\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\n return keys\n }\n\n // ====== 事件处理 ======\n\n const handleMenuClick = (key: string) => {\n if (key && key !== activeKey.value) {\n emit('select', key)\n }\n }\n\n const onExpandedKeysChange = (keys: string[]) => {\n expandedKeys.value = keys\n emit('update:expandedKeys', keys)\n }\n\n // ====== 暴露方法 ======\n const showOption = (key: string) => menuRef.value?.showOption(key)\n defineExpose({ showOption, menuRef })\n\n // ====== 路由跟踪 ======\n\n watch(\n () => activeKey.value,\n newKey => {\n if (!newKey) return\n const newKeys = computeExpandedKeys(newKey)\n expandedKeys.value = Array.from(\n new Set([...expandedKeys.value, ...newKeys])\n )\n nextTick(() => menuRef.value?.showOption(newKey))\n },\n { immediate: true }\n )\n\n onMounted(() => {\n nextTick(() => {\n if (activeKey.value) {\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\n menuRef.value?.showOption(activeKey.value)\n }\n })\n })\n</script>\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\n *\n * 支持两种数据输入模式:\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\n *\n * @example 路由模式(推荐)\n * ```vue\n * <C_Menu\n * :routes=\"menuData\"\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 原生模式\n * ```vue\n * <C_Menu\n * :options=\"nMenuOptions\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <NMenu\n ref=\"menuRef\"\n :options=\"mergedOptions\"\n :expanded-keys=\"expandedKeys\"\n :value=\"activeKey\"\n :mode=\"mode\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"collapsedWidth\"\n :collapsed-icon-size=\"collapsedIconSize\"\n :inverted=\"inverted\"\n :theme-overrides=\"themeOverrides\"\n :dropdown-props=\"dropdownProps\"\n :indent=\"indent\"\n :root-indent=\"rootIndent\"\n @update:value=\"handleMenuClick\"\n @update:expanded-keys=\"onExpandedKeysChange\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\n import {\n type MenuOption,\n type MenuInst,\n type DropdownProps,\n } from 'naive-ui/es'\n import {\n createMenuOptions,\n type RouteItem,\n type MenuAdapterConfig,\n } from '../_shared'\n\n defineOptions({ name: 'C_Menu' })\n\n const props = withDefaults(\n defineProps<{\n /**\n * 模式一:直传 NMenu 原生 MenuOption[]\n * 与 `routes` 二选一,`options` 优先级更高\n */\n options?: MenuOption[]\n /**\n * 模式二:传入路由数据,自动转换为 MenuOption[]\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\n */\n routes?: RouteItem[]\n /**\n * 适配器配置(仅 routes 模式生效)\n * 可自定义 key/label/icon 取值、过滤逻辑等\n */\n adapterConfig?: MenuAdapterConfig\n /**\n * 标签文本格式化函数(routes 模式的快捷方式)\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\n */\n labelFormatter?: (label: string) => string\n /** 当前激活的菜单 key */\n value?: string\n /** 菜单模式 */\n mode?: 'vertical' | 'horizontal'\n /** 是否折叠 */\n collapsed?: boolean\n /** 折叠宽度 */\n collapsedWidth?: number\n /** 折叠图标大小 */\n collapsedIconSize?: number\n /** 是否反色 */\n inverted?: boolean\n /** 主题覆盖 */\n themeOverrides?: Record<string, any>\n /** 缩进像素 */\n indent?: number\n /** 根缩进像素 */\n rootIndent?: number\n /** 下拉菜单属性(折叠模式) */\n dropdownProps?: DropdownProps\n }>(),\n {\n mode: 'vertical',\n collapsed: false,\n collapsedWidth: 64,\n collapsedIconSize: 22,\n inverted: false,\n indent: 24,\n rootIndent: 16,\n dropdownProps: () => ({\n placement: 'right-start' as const,\n trigger: 'hover' as const,\n arrowStyle: { color: 'var(--n-color)' },\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 菜单项被选中 */\n select: [key: string]\n /** 展开项变化 */\n 'update:expandedKeys': [keys: string[]]\n }>()\n\n const menuRef = ref<MenuInst | null>(null)\n const expandedKeys = ref<string[]>([])\n\n const activeKey = computed(() => props.value ?? '')\n\n // ====== 数据合成 ======\n\n /** 合并后的最终 MenuOption[] */\n const mergedOptions = computed<MenuOption[]>(() => {\n // 优先使用 options 直传模式\n if (props.options) return props.options\n\n // routes 模式 → 适配器转换\n if (props.routes) {\n const config: MenuAdapterConfig = {\n ...props.adapterConfig,\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\n }\n return createMenuOptions(props.routes, config)\n }\n\n return []\n })\n\n // ====== 展开逻辑 ======\n\n /** 从 MenuOption[] 中查找所有祖先 key */\n const findParentKeys = (\n items: MenuOption[],\n targetKey: string,\n parentKeys: string[] = []\n ): string[] => {\n for (const item of items) {\n const children = item.children as MenuOption[] | undefined\n if (children?.length) {\n const currentKeys = [...parentKeys, item.key as string]\n if (children.some(child => child.key === targetKey)) {\n return currentKeys\n }\n const result = findParentKeys(children, targetKey, currentKeys)\n if (result.length > 0) return result\n }\n }\n return []\n }\n\n /** 通过路径段推导展开 key + 查找祖先 key */\n const computeExpandedKeys = (path: string): Set<string> => {\n const segments = path.split('/').filter(Boolean)\n const keys = new Set<string>()\n let currentPath = ''\n segments.forEach(segment => {\n currentPath += `/${segment}`\n keys.add(currentPath)\n })\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\n return keys\n }\n\n // ====== 事件处理 ======\n\n const handleMenuClick = (key: string) => {\n if (key && key !== activeKey.value) {\n emit('select', key)\n }\n }\n\n const onExpandedKeysChange = (keys: string[]) => {\n expandedKeys.value = keys\n emit('update:expandedKeys', keys)\n }\n\n // ====== 暴露方法 ======\n const showOption = (key: string) => menuRef.value?.showOption(key)\n defineExpose({ showOption, menuRef })\n\n // ====== 路由跟踪 ======\n\n watch(\n () => activeKey.value,\n newKey => {\n if (!newKey) return\n const newKeys = computeExpandedKeys(newKey)\n expandedKeys.value = Array.from(\n new Set([...expandedKeys.value, ...newKeys])\n )\n nextTick(() => menuRef.value?.showOption(newKey))\n },\n { immediate: true }\n )\n\n onMounted(() => {\n nextTick(() => {\n if (activeKey.value) {\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\n menuRef.value?.showOption(activeKey.value)\n }\n })\n })\n</script>\n","<!--\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\n *\n * 支持两种数据输入模式:\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\n *\n * @example 路由模式(推荐)\n * ```vue\n * <C_Menu\n * :routes=\"menuData\"\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 原生模式\n * ```vue\n * <C_Menu\n * :options=\"nMenuOptions\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <NMenu\n ref=\"menuRef\"\n :options=\"mergedOptions\"\n :expanded-keys=\"expandedKeys\"\n :value=\"activeKey\"\n :mode=\"mode\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"collapsedWidth\"\n :collapsed-icon-size=\"collapsedIconSize\"\n :inverted=\"inverted\"\n :theme-overrides=\"themeOverrides\"\n :dropdown-props=\"dropdownProps\"\n :indent=\"indent\"\n :root-indent=\"rootIndent\"\n @update:value=\"handleMenuClick\"\n @update:expanded-keys=\"onExpandedKeysChange\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\n import {\n type MenuOption,\n type MenuInst,\n type DropdownProps,\n } from 'naive-ui/es'\n import {\n createMenuOptions,\n type RouteItem,\n type MenuAdapterConfig,\n } from '../_shared'\n\n defineOptions({ name: 'C_Menu' })\n\n const props = withDefaults(\n defineProps<{\n /**\n * 模式一:直传 NMenu 原生 MenuOption[]\n * 与 `routes` 二选一,`options` 优先级更高\n */\n options?: MenuOption[]\n /**\n * 模式二:传入路由数据,自动转换为 MenuOption[]\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\n */\n routes?: RouteItem[]\n /**\n * 适配器配置(仅 routes 模式生效)\n * 可自定义 key/label/icon 取值、过滤逻辑等\n */\n adapterConfig?: MenuAdapterConfig\n /**\n * 标签文本格式化函数(routes 模式的快捷方式)\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\n */\n labelFormatter?: (label: string) => string\n /** 当前激活的菜单 key */\n value?: string\n /** 菜单模式 */\n mode?: 'vertical' | 'horizontal'\n /** 是否折叠 */\n collapsed?: boolean\n /** 折叠宽度 */\n collapsedWidth?: number\n /** 折叠图标大小 */\n collapsedIconSize?: number\n /** 是否反色 */\n inverted?: boolean\n /** 主题覆盖 */\n themeOverrides?: Record<string, any>\n /** 缩进像素 */\n indent?: number\n /** 根缩进像素 */\n rootIndent?: number\n /** 下拉菜单属性(折叠模式) */\n dropdownProps?: DropdownProps\n }>(),\n {\n mode: 'vertical',\n collapsed: false,\n collapsedWidth: 64,\n collapsedIconSize: 22,\n inverted: false,\n indent: 24,\n rootIndent: 16,\n dropdownProps: () => ({\n placement: 'right-start' as const,\n trigger: 'hover' as const,\n arrowStyle: { color: 'var(--n-color)' },\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 菜单项被选中 */\n select: [key: string]\n /** 展开项变化 */\n 'update:expandedKeys': [keys: string[]]\n }>()\n\n const menuRef = ref<MenuInst | null>(null)\n const expandedKeys = ref<string[]>([])\n\n const activeKey = computed(() => props.value ?? '')\n\n // ====== 数据合成 ======\n\n /** 合并后的最终 MenuOption[] */\n const mergedOptions = computed<MenuOption[]>(() => {\n // 优先使用 options 直传模式\n if (props.options) return props.options\n\n // routes 模式 → 适配器转换\n if (props.routes) {\n const config: MenuAdapterConfig = {\n ...props.adapterConfig,\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\n }\n return createMenuOptions(props.routes, config)\n }\n\n return []\n })\n\n // ====== 展开逻辑 ======\n\n /** 从 MenuOption[] 中查找所有祖先 key */\n const findParentKeys = (\n items: MenuOption[],\n targetKey: string,\n parentKeys: string[] = []\n ): string[] => {\n for (const item of items) {\n const children = item.children as MenuOption[] | undefined\n if (children?.length) {\n const currentKeys = [...parentKeys, item.key as string]\n if (children.some(child => child.key === targetKey)) {\n return currentKeys\n }\n const result = findParentKeys(children, targetKey, currentKeys)\n if (result.length > 0) return result\n }\n }\n return []\n }\n\n /** 通过路径段推导展开 key + 查找祖先 key */\n const computeExpandedKeys = (path: string): Set<string> => {\n const segments = path.split('/').filter(Boolean)\n const keys = new Set<string>()\n let currentPath = ''\n segments.forEach(segment => {\n currentPath += `/${segment}`\n keys.add(currentPath)\n })\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\n return keys\n }\n\n // ====== 事件处理 ======\n\n const handleMenuClick = (key: string) => {\n if (key && key !== activeKey.value) {\n emit('select', key)\n }\n }\n\n const onExpandedKeysChange = (keys: string[]) => {\n expandedKeys.value = keys\n emit('update:expandedKeys', keys)\n }\n\n // ====== 暴露方法 ======\n const showOption = (key: string) => menuRef.value?.showOption(key)\n defineExpose({ showOption, menuRef })\n\n // ====== 路由跟踪 ======\n\n watch(\n () => activeKey.value,\n newKey => {\n if (!newKey) return\n const newKeys = computeExpandedKeys(newKey)\n expandedKeys.value = Array.from(\n new Set([...expandedKeys.value, ...newKeys])\n )\n nextTick(() => menuRef.value?.showOption(newKey))\n },\n { immediate: true }\n )\n\n onMounted(() => {\n nextTick(() => {\n if (activeKey.value) {\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\n menuRef.value?.showOption(activeKey.value)\n }\n })\n })\n</script>\n"],"mappings":"gnBE6DE,IAAM,EAAQ,EA2DR,EAAO,EAOP,GAAA,EAAA,EAAA,KAA+B,KAAI,CACnC,GAAA,EAAA,EAAA,KAA6B,EAAE,CAAA,CAE/B,GAAA,EAAA,EAAA,cAA2B,EAAM,OAAS,GAAE,CAK5C,GAAA,EAAA,EAAA,cAA6C,CAEjD,GAAI,EAAM,QAAS,OAAO,EAAM,QAGhC,GAAI,EAAM,OAAQ,CAChB,IAAM,EAA4B,CAChC,GAAG,EAAM,cACT,GAAI,EAAM,gBAAkB,CAAE,eAAgB,EAAM,eAAgB,CACtE,CACA,OAAO,EAAA,EAAkB,EAAM,OAAQ,EAAM,CAG/C,MAAO,EAAC,EACT,CAKK,GACJ,EACA,EACA,EAAuB,EAAC,GACX,CACb,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,SACtB,GAAI,GAAU,OAAQ,CACpB,IAAM,EAAc,CAAC,GAAG,EAAY,EAAK,IAAa,CACtD,GAAI,EAAS,KAAK,GAAS,EAAM,MAAQ,EAAU,CACjD,OAAO,EAET,IAAM,EAAS,EAAe,EAAU,EAAW,EAAW,CAC9D,GAAI,EAAO,OAAS,EAAG,OAAO,GAGlC,MAAO,EAAC,EAIJ,EAAuB,GAA8B,CACzD,IAAM,EAAW,EAAK,MAAM,IAAI,CAAC,OAAO,QAAO,CACzC,EAAO,IAAI,IACb,EAAc,GAMlB,OALA,EAAS,QAAQ,GAAW,CAC1B,GAAe,IAAI,IACnB,EAAK,IAAI,EAAW,EACrB,CACD,EAAe,EAAc,MAAO,EAAK,CAAC,QAAQ,GAAO,EAAK,IAAI,EAAI,CAAA,CAC/D,GAKH,EAAmB,GAAgB,CACnC,GAAO,IAAQ,EAAU,OAC3B,EAAK,SAAU,EAAG,EAIhB,EAAwB,GAAmB,CAC/C,EAAa,MAAQ,EACrB,EAAK,sBAAuB,EAAI,SAKlC,EAAa,CAAE,WADK,GAAgB,EAAQ,OAAO,WAAW,EAAG,CACtC,UAAS,CAAA,EAIpC,EAAA,EAAA,WACQ,EAAU,MAChB,GAAU,CACR,GAAI,CAAC,EAAQ,OACb,IAAM,EAAU,EAAoB,EAAM,CAC1C,EAAa,MAAQ,MAAM,KACzB,IAAI,IAAI,CAAC,GAAG,EAAa,MAAO,GAAG,EAAQ,CAAA,CAC7C,EACA,EAAA,EAAA,cAAe,EAAQ,OAAO,WAAW,EAAO,CAAA,EAElD,CAAE,UAAW,GAAK,CACpB,EAEA,EAAA,EAAA,eAAgB,EACd,EAAA,EAAA,cAAe,CACT,EAAU,QACZ,EAAa,MAAQ,MAAM,KAAK,EAAoB,EAAU,MAAM,CAAA,CACpE,EAAQ,OAAO,WAAW,EAAU,MAAK,GAE5C,EACF,iEAtLC,EAAA,SAfI,UAAJ,IAAI,EACH,QAAS,EAAA,MACT,gBAAe,EAAA,MACf,MAAO,EAAA,MACP,KAAMA,EAAAA,KACN,UAAWC,EAAAA,UACX,kBAAiBC,EAAAA,eACjB,sBAAqBC,EAAAA,kBACrB,SAAUC,EAAAA,SACV,kBAAiBC,EAAAA,eACjB,iBAAgBC,EAAAA,cAChB,OAAQC,EAAAA,OACR,cAAaC,EAAAA,WACb,iBAAc,EACd,wBAAsB"}
@@ -1 +1 @@
1
- {"version":3,"file":"C_Menu2.js","names":["mode","collapsed","collapsedWidth","collapsedIconSize","inverted","themeOverrides","dropdownProps","indent","rootIndent"],"sources":["../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\r\n *\r\n * 支持两种数据输入模式:\r\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\r\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\r\n *\r\n * @example 路由模式(推荐)\r\n * ```vue\r\n * <C_Menu\r\n * :routes=\"menuData\"\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 原生模式\r\n * ```vue\r\n * <C_Menu\r\n * :options=\"nMenuOptions\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NMenu\r\n ref=\"menuRef\"\r\n :options=\"mergedOptions\"\r\n :expanded-keys=\"expandedKeys\"\r\n :value=\"activeKey\"\r\n :mode=\"mode\"\r\n :collapsed=\"collapsed\"\r\n :collapsed-width=\"collapsedWidth\"\r\n :collapsed-icon-size=\"collapsedIconSize\"\r\n :inverted=\"inverted\"\r\n :theme-overrides=\"themeOverrides\"\r\n :dropdown-props=\"dropdownProps\"\r\n :indent=\"indent\"\r\n :root-indent=\"rootIndent\"\r\n @update:value=\"handleMenuClick\"\r\n @update:expanded-keys=\"onExpandedKeysChange\"\r\n />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\r\n import {\r\n type MenuOption,\r\n type MenuInst,\r\n type DropdownProps,\r\n } from 'naive-ui/es'\r\n import {\r\n createMenuOptions,\r\n type RouteItem,\r\n type MenuAdapterConfig,\r\n } from '../_shared'\r\n\r\n defineOptions({ name: 'C_Menu' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 模式一:直传 NMenu 原生 MenuOption[]\r\n * 与 `routes` 二选一,`options` 优先级更高\r\n */\r\n options?: MenuOption[]\r\n /**\r\n * 模式二:传入路由数据,自动转换为 MenuOption[]\r\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\r\n */\r\n routes?: RouteItem[]\r\n /**\r\n * 适配器配置(仅 routes 模式生效)\r\n * 可自定义 key/label/icon 取值、过滤逻辑等\r\n */\r\n adapterConfig?: MenuAdapterConfig\r\n /**\r\n * 标签文本格式化函数(routes 模式的快捷方式)\r\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 当前激活的菜单 key */\r\n value?: string\r\n /** 菜单模式 */\r\n mode?: 'vertical' | 'horizontal'\r\n /** 是否折叠 */\r\n collapsed?: boolean\r\n /** 折叠宽度 */\r\n collapsedWidth?: number\r\n /** 折叠图标大小 */\r\n collapsedIconSize?: number\r\n /** 是否反色 */\r\n inverted?: boolean\r\n /** 主题覆盖 */\r\n themeOverrides?: Record<string, any>\r\n /** 缩进像素 */\r\n indent?: number\r\n /** 根缩进像素 */\r\n rootIndent?: number\r\n /** 下拉菜单属性(折叠模式) */\r\n dropdownProps?: DropdownProps\r\n }>(),\r\n {\r\n mode: 'vertical',\r\n collapsed: false,\r\n collapsedWidth: 64,\r\n collapsedIconSize: 22,\r\n inverted: false,\r\n indent: 24,\r\n rootIndent: 16,\r\n dropdownProps: () => ({\r\n placement: 'right-start' as const,\r\n trigger: 'hover' as const,\r\n arrowStyle: { color: 'var(--n-color)' },\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 菜单项被选中 */\r\n select: [key: string]\r\n /** 展开项变化 */\r\n 'update:expandedKeys': [keys: string[]]\r\n }>()\r\n\r\n const menuRef = ref<MenuInst | null>(null)\r\n const expandedKeys = ref<string[]>([])\r\n\r\n const activeKey = computed(() => props.value ?? '')\r\n\r\n // ====== 数据合成 ======\r\n\r\n /** 合并后的最终 MenuOption[] */\r\n const mergedOptions = computed<MenuOption[]>(() => {\r\n // 优先使用 options 直传模式\r\n if (props.options) return props.options\r\n\r\n // routes 模式 → 适配器转换\r\n if (props.routes) {\r\n const config: MenuAdapterConfig = {\r\n ...props.adapterConfig,\r\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\r\n }\r\n return createMenuOptions(props.routes, config)\r\n }\r\n\r\n return []\r\n })\r\n\r\n // ====== 展开逻辑 ======\r\n\r\n /** 从 MenuOption[] 中查找所有祖先 key */\r\n const findParentKeys = (\r\n items: MenuOption[],\r\n targetKey: string,\r\n parentKeys: string[] = []\r\n ): string[] => {\r\n for (const item of items) {\r\n const children = item.children as MenuOption[] | undefined\r\n if (children?.length) {\r\n const currentKeys = [...parentKeys, item.key as string]\r\n if (children.some(child => child.key === targetKey)) {\r\n return currentKeys\r\n }\r\n const result = findParentKeys(children, targetKey, currentKeys)\r\n if (result.length > 0) return result\r\n }\r\n }\r\n return []\r\n }\r\n\r\n /** 通过路径段推导展开 key + 查找祖先 key */\r\n const computeExpandedKeys = (path: string): Set<string> => {\r\n const segments = path.split('/').filter(Boolean)\r\n const keys = new Set<string>()\r\n let currentPath = ''\r\n segments.forEach(segment => {\r\n currentPath += `/${segment}`\r\n keys.add(currentPath)\r\n })\r\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\r\n return keys\r\n }\r\n\r\n // ====== 事件处理 ======\r\n\r\n const handleMenuClick = (key: string) => {\r\n if (key && key !== activeKey.value) {\r\n emit('select', key)\r\n }\r\n }\r\n\r\n const onExpandedKeysChange = (keys: string[]) => {\r\n expandedKeys.value = keys\r\n emit('update:expandedKeys', keys)\r\n }\r\n\r\n // ====== 暴露方法 ======\r\n const showOption = (key: string) => menuRef.value?.showOption(key)\r\n defineExpose({ showOption, menuRef })\r\n\r\n // ====== 路由跟踪 ======\r\n\r\n watch(\r\n () => activeKey.value,\r\n newKey => {\r\n if (!newKey) return\r\n const newKeys = computeExpandedKeys(newKey)\r\n expandedKeys.value = Array.from(\r\n new Set([...expandedKeys.value, ...newKeys])\r\n )\r\n nextTick(() => menuRef.value?.showOption(newKey))\r\n },\r\n { immediate: true }\r\n )\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n if (activeKey.value) {\r\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\r\n menuRef.value?.showOption(activeKey.value)\r\n }\r\n })\r\n })\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\r\n *\r\n * 支持两种数据输入模式:\r\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\r\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\r\n *\r\n * @example 路由模式(推荐)\r\n * ```vue\r\n * <C_Menu\r\n * :routes=\"menuData\"\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 原生模式\r\n * ```vue\r\n * <C_Menu\r\n * :options=\"nMenuOptions\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NMenu\r\n ref=\"menuRef\"\r\n :options=\"mergedOptions\"\r\n :expanded-keys=\"expandedKeys\"\r\n :value=\"activeKey\"\r\n :mode=\"mode\"\r\n :collapsed=\"collapsed\"\r\n :collapsed-width=\"collapsedWidth\"\r\n :collapsed-icon-size=\"collapsedIconSize\"\r\n :inverted=\"inverted\"\r\n :theme-overrides=\"themeOverrides\"\r\n :dropdown-props=\"dropdownProps\"\r\n :indent=\"indent\"\r\n :root-indent=\"rootIndent\"\r\n @update:value=\"handleMenuClick\"\r\n @update:expanded-keys=\"onExpandedKeysChange\"\r\n />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\r\n import {\r\n type MenuOption,\r\n type MenuInst,\r\n type DropdownProps,\r\n } from 'naive-ui/es'\r\n import {\r\n createMenuOptions,\r\n type RouteItem,\r\n type MenuAdapterConfig,\r\n } from '../_shared'\r\n\r\n defineOptions({ name: 'C_Menu' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 模式一:直传 NMenu 原生 MenuOption[]\r\n * 与 `routes` 二选一,`options` 优先级更高\r\n */\r\n options?: MenuOption[]\r\n /**\r\n * 模式二:传入路由数据,自动转换为 MenuOption[]\r\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\r\n */\r\n routes?: RouteItem[]\r\n /**\r\n * 适配器配置(仅 routes 模式生效)\r\n * 可自定义 key/label/icon 取值、过滤逻辑等\r\n */\r\n adapterConfig?: MenuAdapterConfig\r\n /**\r\n * 标签文本格式化函数(routes 模式的快捷方式)\r\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 当前激活的菜单 key */\r\n value?: string\r\n /** 菜单模式 */\r\n mode?: 'vertical' | 'horizontal'\r\n /** 是否折叠 */\r\n collapsed?: boolean\r\n /** 折叠宽度 */\r\n collapsedWidth?: number\r\n /** 折叠图标大小 */\r\n collapsedIconSize?: number\r\n /** 是否反色 */\r\n inverted?: boolean\r\n /** 主题覆盖 */\r\n themeOverrides?: Record<string, any>\r\n /** 缩进像素 */\r\n indent?: number\r\n /** 根缩进像素 */\r\n rootIndent?: number\r\n /** 下拉菜单属性(折叠模式) */\r\n dropdownProps?: DropdownProps\r\n }>(),\r\n {\r\n mode: 'vertical',\r\n collapsed: false,\r\n collapsedWidth: 64,\r\n collapsedIconSize: 22,\r\n inverted: false,\r\n indent: 24,\r\n rootIndent: 16,\r\n dropdownProps: () => ({\r\n placement: 'right-start' as const,\r\n trigger: 'hover' as const,\r\n arrowStyle: { color: 'var(--n-color)' },\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 菜单项被选中 */\r\n select: [key: string]\r\n /** 展开项变化 */\r\n 'update:expandedKeys': [keys: string[]]\r\n }>()\r\n\r\n const menuRef = ref<MenuInst | null>(null)\r\n const expandedKeys = ref<string[]>([])\r\n\r\n const activeKey = computed(() => props.value ?? '')\r\n\r\n // ====== 数据合成 ======\r\n\r\n /** 合并后的最终 MenuOption[] */\r\n const mergedOptions = computed<MenuOption[]>(() => {\r\n // 优先使用 options 直传模式\r\n if (props.options) return props.options\r\n\r\n // routes 模式 → 适配器转换\r\n if (props.routes) {\r\n const config: MenuAdapterConfig = {\r\n ...props.adapterConfig,\r\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\r\n }\r\n return createMenuOptions(props.routes, config)\r\n }\r\n\r\n return []\r\n })\r\n\r\n // ====== 展开逻辑 ======\r\n\r\n /** 从 MenuOption[] 中查找所有祖先 key */\r\n const findParentKeys = (\r\n items: MenuOption[],\r\n targetKey: string,\r\n parentKeys: string[] = []\r\n ): string[] => {\r\n for (const item of items) {\r\n const children = item.children as MenuOption[] | undefined\r\n if (children?.length) {\r\n const currentKeys = [...parentKeys, item.key as string]\r\n if (children.some(child => child.key === targetKey)) {\r\n return currentKeys\r\n }\r\n const result = findParentKeys(children, targetKey, currentKeys)\r\n if (result.length > 0) return result\r\n }\r\n }\r\n return []\r\n }\r\n\r\n /** 通过路径段推导展开 key + 查找祖先 key */\r\n const computeExpandedKeys = (path: string): Set<string> => {\r\n const segments = path.split('/').filter(Boolean)\r\n const keys = new Set<string>()\r\n let currentPath = ''\r\n segments.forEach(segment => {\r\n currentPath += `/${segment}`\r\n keys.add(currentPath)\r\n })\r\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\r\n return keys\r\n }\r\n\r\n // ====== 事件处理 ======\r\n\r\n const handleMenuClick = (key: string) => {\r\n if (key && key !== activeKey.value) {\r\n emit('select', key)\r\n }\r\n }\r\n\r\n const onExpandedKeysChange = (keys: string[]) => {\r\n expandedKeys.value = keys\r\n emit('update:expandedKeys', keys)\r\n }\r\n\r\n // ====== 暴露方法 ======\r\n const showOption = (key: string) => menuRef.value?.showOption(key)\r\n defineExpose({ showOption, menuRef })\r\n\r\n // ====== 路由跟踪 ======\r\n\r\n watch(\r\n () => activeKey.value,\r\n newKey => {\r\n if (!newKey) return\r\n const newKeys = computeExpandedKeys(newKey)\r\n expandedKeys.value = Array.from(\r\n new Set([...expandedKeys.value, ...newKeys])\r\n )\r\n nextTick(() => menuRef.value?.showOption(newKey))\r\n },\r\n { immediate: true }\r\n )\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n if (activeKey.value) {\r\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\r\n menuRef.value?.showOption(activeKey.value)\r\n }\r\n })\r\n })\r\n</script>\r\n","<!--\r\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\r\n *\r\n * 支持两种数据输入模式:\r\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\r\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\r\n *\r\n * @example 路由模式(推荐)\r\n * ```vue\r\n * <C_Menu\r\n * :routes=\"menuData\"\r\n * :label-formatter=\"$t\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * @example 原生模式\r\n * ```vue\r\n * <C_Menu\r\n * :options=\"nMenuOptions\"\r\n * @select=\"router.push\"\r\n * />\r\n * ```\r\n *\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NMenu\r\n ref=\"menuRef\"\r\n :options=\"mergedOptions\"\r\n :expanded-keys=\"expandedKeys\"\r\n :value=\"activeKey\"\r\n :mode=\"mode\"\r\n :collapsed=\"collapsed\"\r\n :collapsed-width=\"collapsedWidth\"\r\n :collapsed-icon-size=\"collapsedIconSize\"\r\n :inverted=\"inverted\"\r\n :theme-overrides=\"themeOverrides\"\r\n :dropdown-props=\"dropdownProps\"\r\n :indent=\"indent\"\r\n :root-indent=\"rootIndent\"\r\n @update:value=\"handleMenuClick\"\r\n @update:expanded-keys=\"onExpandedKeysChange\"\r\n />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\r\n import {\r\n type MenuOption,\r\n type MenuInst,\r\n type DropdownProps,\r\n } from 'naive-ui/es'\r\n import {\r\n createMenuOptions,\r\n type RouteItem,\r\n type MenuAdapterConfig,\r\n } from '../_shared'\r\n\r\n defineOptions({ name: 'C_Menu' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n /**\r\n * 模式一:直传 NMenu 原生 MenuOption[]\r\n * 与 `routes` 二选一,`options` 优先级更高\r\n */\r\n options?: MenuOption[]\r\n /**\r\n * 模式二:传入路由数据,自动转换为 MenuOption[]\r\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\r\n */\r\n routes?: RouteItem[]\r\n /**\r\n * 适配器配置(仅 routes 模式生效)\r\n * 可自定义 key/label/icon 取值、过滤逻辑等\r\n */\r\n adapterConfig?: MenuAdapterConfig\r\n /**\r\n * 标签文本格式化函数(routes 模式的快捷方式)\r\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\r\n */\r\n labelFormatter?: (label: string) => string\r\n /** 当前激活的菜单 key */\r\n value?: string\r\n /** 菜单模式 */\r\n mode?: 'vertical' | 'horizontal'\r\n /** 是否折叠 */\r\n collapsed?: boolean\r\n /** 折叠宽度 */\r\n collapsedWidth?: number\r\n /** 折叠图标大小 */\r\n collapsedIconSize?: number\r\n /** 是否反色 */\r\n inverted?: boolean\r\n /** 主题覆盖 */\r\n themeOverrides?: Record<string, any>\r\n /** 缩进像素 */\r\n indent?: number\r\n /** 根缩进像素 */\r\n rootIndent?: number\r\n /** 下拉菜单属性(折叠模式) */\r\n dropdownProps?: DropdownProps\r\n }>(),\r\n {\r\n mode: 'vertical',\r\n collapsed: false,\r\n collapsedWidth: 64,\r\n collapsedIconSize: 22,\r\n inverted: false,\r\n indent: 24,\r\n rootIndent: 16,\r\n dropdownProps: () => ({\r\n placement: 'right-start' as const,\r\n trigger: 'hover' as const,\r\n arrowStyle: { color: 'var(--n-color)' },\r\n }),\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n /** 菜单项被选中 */\r\n select: [key: string]\r\n /** 展开项变化 */\r\n 'update:expandedKeys': [keys: string[]]\r\n }>()\r\n\r\n const menuRef = ref<MenuInst | null>(null)\r\n const expandedKeys = ref<string[]>([])\r\n\r\n const activeKey = computed(() => props.value ?? '')\r\n\r\n // ====== 数据合成 ======\r\n\r\n /** 合并后的最终 MenuOption[] */\r\n const mergedOptions = computed<MenuOption[]>(() => {\r\n // 优先使用 options 直传模式\r\n if (props.options) return props.options\r\n\r\n // routes 模式 → 适配器转换\r\n if (props.routes) {\r\n const config: MenuAdapterConfig = {\r\n ...props.adapterConfig,\r\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\r\n }\r\n return createMenuOptions(props.routes, config)\r\n }\r\n\r\n return []\r\n })\r\n\r\n // ====== 展开逻辑 ======\r\n\r\n /** 从 MenuOption[] 中查找所有祖先 key */\r\n const findParentKeys = (\r\n items: MenuOption[],\r\n targetKey: string,\r\n parentKeys: string[] = []\r\n ): string[] => {\r\n for (const item of items) {\r\n const children = item.children as MenuOption[] | undefined\r\n if (children?.length) {\r\n const currentKeys = [...parentKeys, item.key as string]\r\n if (children.some(child => child.key === targetKey)) {\r\n return currentKeys\r\n }\r\n const result = findParentKeys(children, targetKey, currentKeys)\r\n if (result.length > 0) return result\r\n }\r\n }\r\n return []\r\n }\r\n\r\n /** 通过路径段推导展开 key + 查找祖先 key */\r\n const computeExpandedKeys = (path: string): Set<string> => {\r\n const segments = path.split('/').filter(Boolean)\r\n const keys = new Set<string>()\r\n let currentPath = ''\r\n segments.forEach(segment => {\r\n currentPath += `/${segment}`\r\n keys.add(currentPath)\r\n })\r\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\r\n return keys\r\n }\r\n\r\n // ====== 事件处理 ======\r\n\r\n const handleMenuClick = (key: string) => {\r\n if (key && key !== activeKey.value) {\r\n emit('select', key)\r\n }\r\n }\r\n\r\n const onExpandedKeysChange = (keys: string[]) => {\r\n expandedKeys.value = keys\r\n emit('update:expandedKeys', keys)\r\n }\r\n\r\n // ====== 暴露方法 ======\r\n const showOption = (key: string) => menuRef.value?.showOption(key)\r\n defineExpose({ showOption, menuRef })\r\n\r\n // ====== 路由跟踪 ======\r\n\r\n watch(\r\n () => activeKey.value,\r\n newKey => {\r\n if (!newKey) return\r\n const newKeys = computeExpandedKeys(newKey)\r\n expandedKeys.value = Array.from(\r\n new Set([...expandedKeys.value, ...newKeys])\r\n )\r\n nextTick(() => menuRef.value?.showOption(newKey))\r\n },\r\n { immediate: true }\r\n )\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n if (activeKey.value) {\r\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\r\n menuRef.value?.showOption(activeKey.value)\r\n }\r\n })\r\n })\r\n</script>\r\n"],"mappings":"ksBE6DE,IAAM,EAAQ,EA2DR,EAAO,EAOP,EAAU,EAAqB,KAAK,CACpC,EAAe,EAAc,EAAE,CAAC,CAEhC,EAAY,MAAe,EAAM,OAAS,GAAG,CAK7C,EAAgB,MAA6B,CAEjD,GAAI,EAAM,QAAS,OAAO,EAAM,QAGhC,GAAI,EAAM,OAAQ,CAChB,IAAM,EAA4B,CAChC,GAAG,EAAM,cACT,GAAI,EAAM,gBAAkB,CAAE,eAAgB,EAAM,eAAgB,CACrE,CACD,OAAO,EAAkB,EAAM,OAAQ,EAAO,CAGhD,MAAO,EAAE,EACT,CAKI,GACJ,EACA,EACA,EAAuB,EAAE,GACZ,CACb,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,SACtB,GAAI,GAAU,OAAQ,CACpB,IAAM,EAAc,CAAC,GAAG,EAAY,EAAK,IAAc,CACvD,GAAI,EAAS,KAAK,GAAS,EAAM,MAAQ,EAAU,CACjD,OAAO,EAET,IAAM,EAAS,EAAe,EAAU,EAAW,EAAY,CAC/D,GAAI,EAAO,OAAS,EAAG,OAAO,GAGlC,MAAO,EAAE,EAIL,EAAuB,GAA8B,CACzD,IAAM,EAAW,EAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAC1C,EAAO,IAAI,IACb,EAAc,GAMlB,OALA,EAAS,QAAQ,GAAW,CAC1B,GAAe,IAAI,IACnB,EAAK,IAAI,EAAY,EACrB,CACF,EAAe,EAAc,MAAO,EAAK,CAAC,QAAQ,GAAO,EAAK,IAAI,EAAI,CAAC,CAChE,GAKH,EAAmB,GAAgB,CACnC,GAAO,IAAQ,EAAU,OAC3B,EAAK,SAAU,EAAI,EAIjB,EAAwB,GAAmB,CAC/C,EAAa,MAAQ,EACrB,EAAK,sBAAuB,EAAK,SAKnC,EAAa,CAAE,WADK,GAAgB,EAAQ,OAAO,WAAW,EAAI,CACvC,UAAS,CAAC,CAIrC,MACQ,EAAU,MAChB,GAAU,CACR,GAAI,CAAC,EAAQ,OACb,IAAM,EAAU,EAAoB,EAAO,CAC3C,EAAa,MAAQ,MAAM,KACzB,IAAI,IAAI,CAAC,GAAG,EAAa,MAAO,GAAG,EAAQ,CAAC,CAC7C,CACD,MAAe,EAAQ,OAAO,WAAW,EAAO,CAAC,EAEnD,CAAE,UAAW,GAAM,CACpB,CAED,MAAgB,CACd,MAAe,CACT,EAAU,QACZ,EAAa,MAAQ,MAAM,KAAK,EAAoB,EAAU,MAAM,CAAC,CACrE,EAAQ,OAAO,WAAW,EAAU,MAAM,GAE5C,EACF,4BAtMF,EAgBE,EAAA,SAfI,UAAJ,IAAI,EACH,QAAS,EAAA,MACT,gBAAe,EAAA,MACf,MAAO,EAAA,MACP,KAAMA,EAAAA,KACN,UAAWC,EAAAA,UACX,kBAAiBC,EAAAA,eACjB,sBAAqBC,EAAAA,kBACrB,SAAUC,EAAAA,SACV,kBAAiBC,EAAAA,eACjB,iBAAgBC,EAAAA,cAChB,OAAQC,EAAAA,OACR,cAAaC,EAAAA,WACb,iBAAc,EACd,wBAAsB"}
1
+ {"version":3,"file":"C_Menu2.js","names":["mode","collapsed","collapsedWidth","collapsedIconSize","inverted","themeOverrides","dropdownProps","indent","rootIndent"],"sources":["../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue","../src/components/C_Menu/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\n *\n * 支持两种数据输入模式:\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\n *\n * @example 路由模式(推荐)\n * ```vue\n * <C_Menu\n * :routes=\"menuData\"\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 原生模式\n * ```vue\n * <C_Menu\n * :options=\"nMenuOptions\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <NMenu\n ref=\"menuRef\"\n :options=\"mergedOptions\"\n :expanded-keys=\"expandedKeys\"\n :value=\"activeKey\"\n :mode=\"mode\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"collapsedWidth\"\n :collapsed-icon-size=\"collapsedIconSize\"\n :inverted=\"inverted\"\n :theme-overrides=\"themeOverrides\"\n :dropdown-props=\"dropdownProps\"\n :indent=\"indent\"\n :root-indent=\"rootIndent\"\n @update:value=\"handleMenuClick\"\n @update:expanded-keys=\"onExpandedKeysChange\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\n import {\n type MenuOption,\n type MenuInst,\n type DropdownProps,\n } from 'naive-ui/es'\n import {\n createMenuOptions,\n type RouteItem,\n type MenuAdapterConfig,\n } from '../_shared'\n\n defineOptions({ name: 'C_Menu' })\n\n const props = withDefaults(\n defineProps<{\n /**\n * 模式一:直传 NMenu 原生 MenuOption[]\n * 与 `routes` 二选一,`options` 优先级更高\n */\n options?: MenuOption[]\n /**\n * 模式二:传入路由数据,自动转换为 MenuOption[]\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\n */\n routes?: RouteItem[]\n /**\n * 适配器配置(仅 routes 模式生效)\n * 可自定义 key/label/icon 取值、过滤逻辑等\n */\n adapterConfig?: MenuAdapterConfig\n /**\n * 标签文本格式化函数(routes 模式的快捷方式)\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\n */\n labelFormatter?: (label: string) => string\n /** 当前激活的菜单 key */\n value?: string\n /** 菜单模式 */\n mode?: 'vertical' | 'horizontal'\n /** 是否折叠 */\n collapsed?: boolean\n /** 折叠宽度 */\n collapsedWidth?: number\n /** 折叠图标大小 */\n collapsedIconSize?: number\n /** 是否反色 */\n inverted?: boolean\n /** 主题覆盖 */\n themeOverrides?: Record<string, any>\n /** 缩进像素 */\n indent?: number\n /** 根缩进像素 */\n rootIndent?: number\n /** 下拉菜单属性(折叠模式) */\n dropdownProps?: DropdownProps\n }>(),\n {\n mode: 'vertical',\n collapsed: false,\n collapsedWidth: 64,\n collapsedIconSize: 22,\n inverted: false,\n indent: 24,\n rootIndent: 16,\n dropdownProps: () => ({\n placement: 'right-start' as const,\n trigger: 'hover' as const,\n arrowStyle: { color: 'var(--n-color)' },\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 菜单项被选中 */\n select: [key: string]\n /** 展开项变化 */\n 'update:expandedKeys': [keys: string[]]\n }>()\n\n const menuRef = ref<MenuInst | null>(null)\n const expandedKeys = ref<string[]>([])\n\n const activeKey = computed(() => props.value ?? '')\n\n // ====== 数据合成 ======\n\n /** 合并后的最终 MenuOption[] */\n const mergedOptions = computed<MenuOption[]>(() => {\n // 优先使用 options 直传模式\n if (props.options) return props.options\n\n // routes 模式 → 适配器转换\n if (props.routes) {\n const config: MenuAdapterConfig = {\n ...props.adapterConfig,\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\n }\n return createMenuOptions(props.routes, config)\n }\n\n return []\n })\n\n // ====== 展开逻辑 ======\n\n /** 从 MenuOption[] 中查找所有祖先 key */\n const findParentKeys = (\n items: MenuOption[],\n targetKey: string,\n parentKeys: string[] = []\n ): string[] => {\n for (const item of items) {\n const children = item.children as MenuOption[] | undefined\n if (children?.length) {\n const currentKeys = [...parentKeys, item.key as string]\n if (children.some(child => child.key === targetKey)) {\n return currentKeys\n }\n const result = findParentKeys(children, targetKey, currentKeys)\n if (result.length > 0) return result\n }\n }\n return []\n }\n\n /** 通过路径段推导展开 key + 查找祖先 key */\n const computeExpandedKeys = (path: string): Set<string> => {\n const segments = path.split('/').filter(Boolean)\n const keys = new Set<string>()\n let currentPath = ''\n segments.forEach(segment => {\n currentPath += `/${segment}`\n keys.add(currentPath)\n })\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\n return keys\n }\n\n // ====== 事件处理 ======\n\n const handleMenuClick = (key: string) => {\n if (key && key !== activeKey.value) {\n emit('select', key)\n }\n }\n\n const onExpandedKeysChange = (keys: string[]) => {\n expandedKeys.value = keys\n emit('update:expandedKeys', keys)\n }\n\n // ====== 暴露方法 ======\n const showOption = (key: string) => menuRef.value?.showOption(key)\n defineExpose({ showOption, menuRef })\n\n // ====== 路由跟踪 ======\n\n watch(\n () => activeKey.value,\n newKey => {\n if (!newKey) return\n const newKeys = computeExpandedKeys(newKey)\n expandedKeys.value = Array.from(\n new Set([...expandedKeys.value, ...newKeys])\n )\n nextTick(() => menuRef.value?.showOption(newKey))\n },\n { immediate: true }\n )\n\n onMounted(() => {\n nextTick(() => {\n if (activeKey.value) {\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\n menuRef.value?.showOption(activeKey.value)\n }\n })\n })\n</script>\n","/* unplugin-vue-components disabled */<!--\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\n *\n * 支持两种数据输入模式:\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\n *\n * @example 路由模式(推荐)\n * ```vue\n * <C_Menu\n * :routes=\"menuData\"\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 原生模式\n * ```vue\n * <C_Menu\n * :options=\"nMenuOptions\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <NMenu\n ref=\"menuRef\"\n :options=\"mergedOptions\"\n :expanded-keys=\"expandedKeys\"\n :value=\"activeKey\"\n :mode=\"mode\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"collapsedWidth\"\n :collapsed-icon-size=\"collapsedIconSize\"\n :inverted=\"inverted\"\n :theme-overrides=\"themeOverrides\"\n :dropdown-props=\"dropdownProps\"\n :indent=\"indent\"\n :root-indent=\"rootIndent\"\n @update:value=\"handleMenuClick\"\n @update:expanded-keys=\"onExpandedKeysChange\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\n import {\n type MenuOption,\n type MenuInst,\n type DropdownProps,\n } from 'naive-ui/es'\n import {\n createMenuOptions,\n type RouteItem,\n type MenuAdapterConfig,\n } from '../_shared'\n\n defineOptions({ name: 'C_Menu' })\n\n const props = withDefaults(\n defineProps<{\n /**\n * 模式一:直传 NMenu 原生 MenuOption[]\n * 与 `routes` 二选一,`options` 优先级更高\n */\n options?: MenuOption[]\n /**\n * 模式二:传入路由数据,自动转换为 MenuOption[]\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\n */\n routes?: RouteItem[]\n /**\n * 适配器配置(仅 routes 模式生效)\n * 可自定义 key/label/icon 取值、过滤逻辑等\n */\n adapterConfig?: MenuAdapterConfig\n /**\n * 标签文本格式化函数(routes 模式的快捷方式)\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\n */\n labelFormatter?: (label: string) => string\n /** 当前激活的菜单 key */\n value?: string\n /** 菜单模式 */\n mode?: 'vertical' | 'horizontal'\n /** 是否折叠 */\n collapsed?: boolean\n /** 折叠宽度 */\n collapsedWidth?: number\n /** 折叠图标大小 */\n collapsedIconSize?: number\n /** 是否反色 */\n inverted?: boolean\n /** 主题覆盖 */\n themeOverrides?: Record<string, any>\n /** 缩进像素 */\n indent?: number\n /** 根缩进像素 */\n rootIndent?: number\n /** 下拉菜单属性(折叠模式) */\n dropdownProps?: DropdownProps\n }>(),\n {\n mode: 'vertical',\n collapsed: false,\n collapsedWidth: 64,\n collapsedIconSize: 22,\n inverted: false,\n indent: 24,\n rootIndent: 16,\n dropdownProps: () => ({\n placement: 'right-start' as const,\n trigger: 'hover' as const,\n arrowStyle: { color: 'var(--n-color)' },\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 菜单项被选中 */\n select: [key: string]\n /** 展开项变化 */\n 'update:expandedKeys': [keys: string[]]\n }>()\n\n const menuRef = ref<MenuInst | null>(null)\n const expandedKeys = ref<string[]>([])\n\n const activeKey = computed(() => props.value ?? '')\n\n // ====== 数据合成 ======\n\n /** 合并后的最终 MenuOption[] */\n const mergedOptions = computed<MenuOption[]>(() => {\n // 优先使用 options 直传模式\n if (props.options) return props.options\n\n // routes 模式 → 适配器转换\n if (props.routes) {\n const config: MenuAdapterConfig = {\n ...props.adapterConfig,\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\n }\n return createMenuOptions(props.routes, config)\n }\n\n return []\n })\n\n // ====== 展开逻辑 ======\n\n /** 从 MenuOption[] 中查找所有祖先 key */\n const findParentKeys = (\n items: MenuOption[],\n targetKey: string,\n parentKeys: string[] = []\n ): string[] => {\n for (const item of items) {\n const children = item.children as MenuOption[] | undefined\n if (children?.length) {\n const currentKeys = [...parentKeys, item.key as string]\n if (children.some(child => child.key === targetKey)) {\n return currentKeys\n }\n const result = findParentKeys(children, targetKey, currentKeys)\n if (result.length > 0) return result\n }\n }\n return []\n }\n\n /** 通过路径段推导展开 key + 查找祖先 key */\n const computeExpandedKeys = (path: string): Set<string> => {\n const segments = path.split('/').filter(Boolean)\n const keys = new Set<string>()\n let currentPath = ''\n segments.forEach(segment => {\n currentPath += `/${segment}`\n keys.add(currentPath)\n })\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\n return keys\n }\n\n // ====== 事件处理 ======\n\n const handleMenuClick = (key: string) => {\n if (key && key !== activeKey.value) {\n emit('select', key)\n }\n }\n\n const onExpandedKeysChange = (keys: string[]) => {\n expandedKeys.value = keys\n emit('update:expandedKeys', keys)\n }\n\n // ====== 暴露方法 ======\n const showOption = (key: string) => menuRef.value?.showOption(key)\n defineExpose({ showOption, menuRef })\n\n // ====== 路由跟踪 ======\n\n watch(\n () => activeKey.value,\n newKey => {\n if (!newKey) return\n const newKeys = computeExpandedKeys(newKey)\n expandedKeys.value = Array.from(\n new Set([...expandedKeys.value, ...newKeys])\n )\n nextTick(() => menuRef.value?.showOption(newKey))\n },\n { immediate: true }\n )\n\n onMounted(() => {\n nextTick(() => {\n if (activeKey.value) {\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\n menuRef.value?.showOption(activeKey.value)\n }\n })\n })\n</script>\n","<!--\n * @Description: 通用菜单组件 — 基于 NMenu 的树形导航菜单\n *\n * 支持两种数据输入模式:\n * 1. `options` — 直传 NMenu 原生 MenuOption[](零转换,高级用户)\n * 2. `routes` — 传入路由数据,自动通过内置适配器转换为 MenuOption[]\n *\n * @example 路由模式(推荐)\n * ```vue\n * <C_Menu\n * :routes=\"menuData\"\n * :label-formatter=\"$t\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * @example 原生模式\n * ```vue\n * <C_Menu\n * :options=\"nMenuOptions\"\n * @select=\"router.push\"\n * />\n * ```\n *\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <NMenu\n ref=\"menuRef\"\n :options=\"mergedOptions\"\n :expanded-keys=\"expandedKeys\"\n :value=\"activeKey\"\n :mode=\"mode\"\n :collapsed=\"collapsed\"\n :collapsed-width=\"collapsedWidth\"\n :collapsed-icon-size=\"collapsedIconSize\"\n :inverted=\"inverted\"\n :theme-overrides=\"themeOverrides\"\n :dropdown-props=\"dropdownProps\"\n :indent=\"indent\"\n :root-indent=\"rootIndent\"\n @update:value=\"handleMenuClick\"\n @update:expanded-keys=\"onExpandedKeysChange\"\n />\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, nextTick, onMounted } from 'vue'\n import {\n type MenuOption,\n type MenuInst,\n type DropdownProps,\n } from 'naive-ui/es'\n import {\n createMenuOptions,\n type RouteItem,\n type MenuAdapterConfig,\n } from '../_shared'\n\n defineOptions({ name: 'C_Menu' })\n\n const props = withDefaults(\n defineProps<{\n /**\n * 模式一:直传 NMenu 原生 MenuOption[]\n * 与 `routes` 二选一,`options` 优先级更高\n */\n options?: MenuOption[]\n /**\n * 模式二:传入路由数据,自动转换为 MenuOption[]\n * 兼容 Vue Router RouteRecordRaw / 后端 JSON 路由表\n */\n routes?: RouteItem[]\n /**\n * 适配器配置(仅 routes 模式生效)\n * 可自定义 key/label/icon 取值、过滤逻辑等\n */\n adapterConfig?: MenuAdapterConfig\n /**\n * 标签文本格式化函数(routes 模式的快捷方式)\n * 等同于 `adapterConfig.labelFormatter`,但优先级更高\n */\n labelFormatter?: (label: string) => string\n /** 当前激活的菜单 key */\n value?: string\n /** 菜单模式 */\n mode?: 'vertical' | 'horizontal'\n /** 是否折叠 */\n collapsed?: boolean\n /** 折叠宽度 */\n collapsedWidth?: number\n /** 折叠图标大小 */\n collapsedIconSize?: number\n /** 是否反色 */\n inverted?: boolean\n /** 主题覆盖 */\n themeOverrides?: Record<string, any>\n /** 缩进像素 */\n indent?: number\n /** 根缩进像素 */\n rootIndent?: number\n /** 下拉菜单属性(折叠模式) */\n dropdownProps?: DropdownProps\n }>(),\n {\n mode: 'vertical',\n collapsed: false,\n collapsedWidth: 64,\n collapsedIconSize: 22,\n inverted: false,\n indent: 24,\n rootIndent: 16,\n dropdownProps: () => ({\n placement: 'right-start' as const,\n trigger: 'hover' as const,\n arrowStyle: { color: 'var(--n-color)' },\n }),\n }\n )\n\n const emit = defineEmits<{\n /** 菜单项被选中 */\n select: [key: string]\n /** 展开项变化 */\n 'update:expandedKeys': [keys: string[]]\n }>()\n\n const menuRef = ref<MenuInst | null>(null)\n const expandedKeys = ref<string[]>([])\n\n const activeKey = computed(() => props.value ?? '')\n\n // ====== 数据合成 ======\n\n /** 合并后的最终 MenuOption[] */\n const mergedOptions = computed<MenuOption[]>(() => {\n // 优先使用 options 直传模式\n if (props.options) return props.options\n\n // routes 模式 → 适配器转换\n if (props.routes) {\n const config: MenuAdapterConfig = {\n ...props.adapterConfig,\n ...(props.labelFormatter && { labelFormatter: props.labelFormatter }),\n }\n return createMenuOptions(props.routes, config)\n }\n\n return []\n })\n\n // ====== 展开逻辑 ======\n\n /** 从 MenuOption[] 中查找所有祖先 key */\n const findParentKeys = (\n items: MenuOption[],\n targetKey: string,\n parentKeys: string[] = []\n ): string[] => {\n for (const item of items) {\n const children = item.children as MenuOption[] | undefined\n if (children?.length) {\n const currentKeys = [...parentKeys, item.key as string]\n if (children.some(child => child.key === targetKey)) {\n return currentKeys\n }\n const result = findParentKeys(children, targetKey, currentKeys)\n if (result.length > 0) return result\n }\n }\n return []\n }\n\n /** 通过路径段推导展开 key + 查找祖先 key */\n const computeExpandedKeys = (path: string): Set<string> => {\n const segments = path.split('/').filter(Boolean)\n const keys = new Set<string>()\n let currentPath = ''\n segments.forEach(segment => {\n currentPath += `/${segment}`\n keys.add(currentPath)\n })\n findParentKeys(mergedOptions.value, path).forEach(key => keys.add(key))\n return keys\n }\n\n // ====== 事件处理 ======\n\n const handleMenuClick = (key: string) => {\n if (key && key !== activeKey.value) {\n emit('select', key)\n }\n }\n\n const onExpandedKeysChange = (keys: string[]) => {\n expandedKeys.value = keys\n emit('update:expandedKeys', keys)\n }\n\n // ====== 暴露方法 ======\n const showOption = (key: string) => menuRef.value?.showOption(key)\n defineExpose({ showOption, menuRef })\n\n // ====== 路由跟踪 ======\n\n watch(\n () => activeKey.value,\n newKey => {\n if (!newKey) return\n const newKeys = computeExpandedKeys(newKey)\n expandedKeys.value = Array.from(\n new Set([...expandedKeys.value, ...newKeys])\n )\n nextTick(() => menuRef.value?.showOption(newKey))\n },\n { immediate: true }\n )\n\n onMounted(() => {\n nextTick(() => {\n if (activeKey.value) {\n expandedKeys.value = Array.from(computeExpandedKeys(activeKey.value))\n menuRef.value?.showOption(activeKey.value)\n }\n })\n })\n</script>\n"],"mappings":"ksBE6DE,IAAM,EAAQ,EA2DR,EAAO,EAOP,EAAU,EAAqB,KAAI,CACnC,EAAe,EAAc,EAAE,CAAA,CAE/B,EAAY,MAAe,EAAM,OAAS,GAAE,CAK5C,EAAgB,MAA6B,CAEjD,GAAI,EAAM,QAAS,OAAO,EAAM,QAGhC,GAAI,EAAM,OAAQ,CAChB,IAAM,EAA4B,CAChC,GAAG,EAAM,cACT,GAAI,EAAM,gBAAkB,CAAE,eAAgB,EAAM,eAAgB,CACtE,CACA,OAAO,EAAkB,EAAM,OAAQ,EAAM,CAG/C,MAAO,EAAC,EACT,CAKK,GACJ,EACA,EACA,EAAuB,EAAC,GACX,CACb,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,EAAK,SACtB,GAAI,GAAU,OAAQ,CACpB,IAAM,EAAc,CAAC,GAAG,EAAY,EAAK,IAAa,CACtD,GAAI,EAAS,KAAK,GAAS,EAAM,MAAQ,EAAU,CACjD,OAAO,EAET,IAAM,EAAS,EAAe,EAAU,EAAW,EAAW,CAC9D,GAAI,EAAO,OAAS,EAAG,OAAO,GAGlC,MAAO,EAAC,EAIJ,EAAuB,GAA8B,CACzD,IAAM,EAAW,EAAK,MAAM,IAAI,CAAC,OAAO,QAAO,CACzC,EAAO,IAAI,IACb,EAAc,GAMlB,OALA,EAAS,QAAQ,GAAW,CAC1B,GAAe,IAAI,IACnB,EAAK,IAAI,EAAW,EACrB,CACD,EAAe,EAAc,MAAO,EAAK,CAAC,QAAQ,GAAO,EAAK,IAAI,EAAI,CAAA,CAC/D,GAKH,EAAmB,GAAgB,CACnC,GAAO,IAAQ,EAAU,OAC3B,EAAK,SAAU,EAAG,EAIhB,EAAwB,GAAmB,CAC/C,EAAa,MAAQ,EACrB,EAAK,sBAAuB,EAAI,SAKlC,EAAa,CAAE,WADK,GAAgB,EAAQ,OAAO,WAAW,EAAG,CACtC,UAAS,CAAA,CAIpC,MACQ,EAAU,MAChB,GAAU,CACR,GAAI,CAAC,EAAQ,OACb,IAAM,EAAU,EAAoB,EAAM,CAC1C,EAAa,MAAQ,MAAM,KACzB,IAAI,IAAI,CAAC,GAAG,EAAa,MAAO,GAAG,EAAQ,CAAA,CAC7C,CACA,MAAe,EAAQ,OAAO,WAAW,EAAO,CAAA,EAElD,CAAE,UAAW,GAAK,CACpB,CAEA,MAAgB,CACd,MAAe,CACT,EAAU,QACZ,EAAa,MAAQ,MAAM,KAAK,EAAoB,EAAU,MAAM,CAAA,CACpE,EAAQ,OAAO,WAAW,EAAU,MAAK,GAE5C,EACF,4BAtMD,EAgBE,EAAA,SAfI,UAAJ,IAAI,EACH,QAAS,EAAA,MACT,gBAAe,EAAA,MACf,MAAO,EAAA,MACP,KAAMA,EAAAA,KACN,UAAWC,EAAAA,UACX,kBAAiBC,EAAAA,eACjB,sBAAqBC,EAAAA,kBACrB,SAAUC,EAAAA,SACV,kBAAiBC,EAAAA,eACjB,iBAAgBC,EAAAA,cAChB,OAAQC,EAAAA,OACR,cAAaC,EAAAA,WACb,iBAAc,EACd,wBAAsB"}
package/dist/_shared.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./menuAdapter.js`);exports.createMenuOptions=e.t,exports.flattenRoutes=e.n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./C_Icon.js`);const e=require(`./menuAdapter.js`);exports.createMenuOptions=e.t,exports.flattenRoutes=e.n;
package/dist/_shared.js CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./menuAdapter.js";export{t as createMenuOptions,e as flattenRoutes};
1
+ import"./C_Icon2.js";import{n as e,t}from"./menuAdapter.js";export{t as createMenuOptions,e as flattenRoutes};
@@ -118,9 +118,9 @@ declare const __VLS_export: vue.DefineComponent<CronProps, {
118
118
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
119
119
  "onValidation-change"?: ((result: CronValidation) => any) | undefined;
120
120
  }>, {
121
- height: string | number;
122
121
  disabled: boolean;
123
122
  modelValue: string;
123
+ height: string | number;
124
124
  showPreview: boolean;
125
125
  previewCount: number;
126
126
  showTemplates: boolean;
@@ -120,10 +120,10 @@ declare const __VLS_export: vue.DefineComponent<FormulaEditorProps, FormulaEdito
120
120
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
121
121
  "onValidation-change"?: ((result: FormulaValidation) => any) | undefined;
122
122
  }>, {
123
- height: string | number;
124
123
  disabled: boolean;
125
- placeholder: string;
126
124
  modelValue: string;
125
+ height: string | number;
126
+ placeholder: string;
127
127
  variables: FormulaVariable[];
128
128
  functions: FormulaFunction[];
129
129
  sampleData: Record<string, number | string | boolean>;
@@ -151,8 +151,8 @@ interface NotificationCenterExpose {
151
151
  //#region src/components/C_NotificationCenter/index.vue.d.ts
152
152
  declare const __VLS_export: vue.DefineComponent<NotificationCenterProps, NotificationCenterExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
153
153
  delete: (ids: string[]) => any;
154
- itemClick: (message: NotificationMessage) => any;
155
154
  read: (ids: string[]) => any;
155
+ itemClick: (message: NotificationMessage) => any;
156
156
  allRead: (category?: NotificationCategory | undefined) => any;
157
157
  unreadChange: (count: number) => any;
158
158
  wsStatusChange: (status: string) => any;
@@ -160,19 +160,19 @@ declare const __VLS_export: vue.DefineComponent<NotificationCenterProps, Notific
160
160
  navigate: (url: string) => any;
161
161
  }, string, vue.PublicProps, Readonly<NotificationCenterProps> & Readonly<{
162
162
  onDelete?: ((ids: string[]) => any) | undefined;
163
- onItemClick?: ((message: NotificationMessage) => any) | undefined;
164
163
  onRead?: ((ids: string[]) => any) | undefined;
164
+ onItemClick?: ((message: NotificationMessage) => any) | undefined;
165
165
  onAllRead?: ((category?: NotificationCategory | undefined) => any) | undefined;
166
166
  onUnreadChange?: ((count: number) => any) | undefined;
167
167
  onWsStatusChange?: ((status: string) => any) | undefined;
168
168
  onNewMessage?: ((message: NotificationMessage) => any) | undefined;
169
169
  onNavigate?: ((url: string) => any) | undefined;
170
170
  }>, {
171
- pageSize: number;
172
- storageKey: string;
173
171
  desktopNotification: boolean;
174
172
  maxBadgeCount: number;
175
173
  pollingInterval: number;
174
+ pageSize: number;
175
+ storageKey: string;
176
176
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
177
177
  declare const _default: typeof __VLS_export;
178
178
  //#endregion
@@ -217,7 +217,7 @@ declare function useNotificationCore(props: NotificationCenterProps): {
217
217
  actionText?: string | undefined;
218
218
  extra?: Record<string, unknown> | undefined;
219
219
  }[]>;
220
- activeCategory: vue.Ref<"all" | NotificationCategory, "all" | NotificationCategory>;
220
+ activeCategory: vue.Ref<NotificationCategory | "all", NotificationCategory | "all">;
221
221
  loading: vue.Ref<boolean, boolean>;
222
222
  total: vue.Ref<number, number>;
223
223
  page: vue.Ref<number, number>;
@@ -196,17 +196,17 @@ type __VLS_Slots = {} & {
196
196
  area?: (props: typeof __VLS_11) => any;
197
197
  };
198
198
  declare const __VLS_base: vue.DefineComponent<UploadProps, UploadExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
199
- error: (file: UploadFileItem, error: Error) => any;
200
199
  success: (file: UploadFileItem, response: any) => any;
201
200
  change: (fileList: UploadFileItem[]) => any;
201
+ error: (file: UploadFileItem, error: Error) => any;
202
202
  progress: (file: UploadFileItem, percent: number) => any;
203
203
  remove: (file: UploadFileItem) => any;
204
204
  finish: (fileList: UploadFileItem[]) => any;
205
205
  exceed: (files: File[], fileList: UploadFileItem[]) => any;
206
206
  }, string, vue.PublicProps, Readonly<UploadProps> & Readonly<{
207
- onError?: ((file: UploadFileItem, error: Error) => any) | undefined;
208
207
  onSuccess?: ((file: UploadFileItem, response: any) => any) | undefined;
209
208
  onChange?: ((fileList: UploadFileItem[]) => any) | undefined;
209
+ onError?: ((file: UploadFileItem, error: Error) => any) | undefined;
210
210
  onProgress?: ((file: UploadFileItem, percent: number) => any) | undefined;
211
211
  onRemove?: ((file: UploadFileItem) => any) | undefined;
212
212
  onFinish?: ((fileList: UploadFileItem[]) => any) | undefined;
@@ -216,11 +216,11 @@ declare const __VLS_base: vue.DefineComponent<UploadProps, UploadExpose, {}, {},
216
216
  data: Record<string, any>;
217
217
  multiple: boolean;
218
218
  draggable: boolean;
219
- maxSize: number;
220
219
  action: string;
221
220
  headers: Record<string, string>;
222
221
  directory: boolean;
223
222
  accept: string;
223
+ maxSize: number;
224
224
  maxCount: number;
225
225
  pasteable: boolean;
226
226
  chunked: boolean;
@@ -260,8 +260,8 @@ type PlayerInstance = InstanceType<typeof xgplayer.default>;
260
260
  //#region src/components/C_VideoPlayer/index.vue.d.ts
261
261
  declare const __VLS_export: vue.DefineComponent<VideoPlayerProps, VideoPlayerExpose, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
262
262
  error: (error: Error) => any;
263
- ended: () => any;
264
263
  ready: () => any;
264
+ ended: () => any;
265
265
  stateChange: (state: PlayerState) => any;
266
266
  timeUpdate: (currentTime: number, duration: number) => any;
267
267
  qualityChange: (quality: QualityLevel) => any;
@@ -273,8 +273,8 @@ declare const __VLS_export: vue.DefineComponent<VideoPlayerProps, VideoPlayerExp
273
273
  progressUpdate: (data: ProgressData) => any;
274
274
  }, string, vue.PublicProps, Readonly<VideoPlayerProps> & Readonly<{
275
275
  onError?: ((error: Error) => any) | undefined;
276
- onEnded?: (() => any) | undefined;
277
276
  onReady?: (() => any) | undefined;
277
+ onEnded?: (() => any) | undefined;
278
278
  onStateChange?: ((state: PlayerState) => any) | undefined;
279
279
  onTimeUpdate?: ((currentTime: number, duration: number) => any) | undefined;
280
280
  onQualityChange?: ((quality: QualityLevel) => any) | undefined;
package/dist/data.d.ts CHANGED
@@ -23,10 +23,10 @@ declare const __VLS_export: vue.DefineComponent<__VLS_Props, {}, {}, {}, {}, vue
23
23
  onMarkerClick?: ((marker: MapMarker$1, event: any) => any) | undefined;
24
24
  }>, {
25
25
  height: string;
26
- zoom: number;
27
- center: [number, number];
28
26
  markers: MapMarker$1[];
29
27
  amapKey: string;
28
+ center: [number, number];
29
+ zoom: number;
30
30
  mapType: "osm" | "amap";
31
31
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
32
32
  declare const _default: typeof __VLS_export;
@@ -63,10 +63,10 @@ declare const __VLS_base: vue.DefineComponent<TableActionsProps, {}, {}, {}, {},
63
63
  "onDropdown-click"?: ((item: ActionDropdownItem, action: ActionItem) => any) | undefined;
64
64
  "onAction-click"?: ((action: ActionItem) => any) | undefined;
65
65
  }>, {
66
- config: ActionBarConfig;
67
66
  actions: ActionItem[];
68
67
  leftActions: ActionItem[];
69
68
  rightActions: ActionItem[];
69
+ config: ActionBarConfig;
70
70
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
71
71
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
72
72
  declare const _default: typeof __VLS_export;
@@ -41,29 +41,29 @@ declare const __VLS_export: vue.DefineComponent<IconProps, {
41
41
  errorMessage: Readonly<vue.Ref<string, string>>; /** DOM引用 */
42
42
  el: vue.Ref<HTMLElement | undefined, HTMLElement | undefined>;
43
43
  }, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
44
- error: (type: string, error?: any) => any;
45
44
  click: (event: MouseEvent) => any;
45
+ error: (type: string, error?: any) => any;
46
46
  load: () => any;
47
47
  }, string, vue.PublicProps, Readonly<IconProps> & Readonly<{
48
- onError?: ((type: string, error?: any) => any) | undefined;
49
48
  onClick?: ((event: MouseEvent) => any) | undefined;
49
+ onError?: ((type: string, error?: any) => any) | undefined;
50
50
  onLoad?: (() => any) | undefined;
51
51
  }>, {
52
52
  type: "iconify" | "unocss" | "component" | "svg" | "image";
53
53
  name: string | any;
54
- size: number | string;
55
- title: string;
56
54
  color: string;
57
- rotate: number;
58
- flip: "horizontal" | "vertical" | "both";
59
- loading: boolean;
55
+ size: number | string;
60
56
  svgPath: string;
61
57
  viewBox: string;
62
58
  alt: string;
63
59
  clickable: boolean;
60
+ loading: boolean;
64
61
  fallbackIcon: string;
62
+ title: string;
65
63
  ariaLabel: string;
66
64
  customClass: string;
65
+ rotate: number;
66
+ flip: "horizontal" | "vertical" | "both";
67
67
  componentProps: Record<string, any>;
68
68
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
69
69
  declare const _default: typeof __VLS_export;
@@ -58,12 +58,11 @@ declare const __VLS_export: vue.DefineComponent<Props, {
58
58
  "onAuto-save"?: ((text: string) => any) | undefined;
59
59
  "onMax-length-exceeded"?: ((currentLength: number, maxLength: number) => any) | undefined;
60
60
  }>, {
61
- height: string | number;
62
61
  disabled: boolean;
63
- mode: "edit" | "editable" | "preview";
64
- placeholder: string;
65
62
  modelValue: string;
66
- autoSave: boolean;
63
+ height: string | number;
64
+ placeholder: string;
65
+ mode: "edit" | "editable" | "preview";
67
66
  tocNavPosition: "left" | "right";
68
67
  defaultFullscreen: boolean;
69
68
  autofocus: boolean;
@@ -72,6 +71,7 @@ declare const __VLS_export: vue.DefineComponent<Props, {
72
71
  rightToolbar: string;
73
72
  maxLength: number;
74
73
  showWordCount: boolean;
74
+ autoSave: boolean;
75
75
  autoSaveInterval: number;
76
76
  isDark: boolean;
77
77
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
@@ -34,13 +34,13 @@ type __VLS_Slots = {} & {
34
34
  indicator?: (props: typeof __VLS_9) => any;
35
35
  };
36
36
  declare const __VLS_base: vue.DefineComponent<Props, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<Props> & Readonly<{}>, {
37
- strokeWidth: number;
38
- time: number;
39
- status: "default" | "success" | "error" | "warning" | "info";
40
37
  percentage: number | number[];
41
38
  isAnimation: boolean;
39
+ time: number;
42
40
  indicatorPlacement: "inside" | "outside";
43
41
  showIndicator: boolean;
42
+ status: "default" | "success" | "error" | "warning" | "info";
43
+ strokeWidth: number;
44
44
  unit: string;
45
45
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
46
46
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -23,8 +23,8 @@ declare const __VLS_export: vue.DefineComponent<__VLS_Props, {}, {}, {}, {}, vue
23
23
  onChange?: ((args_0: number) => any) | undefined;
24
24
  "onUpdate:current"?: ((args_0: number) => any) | undefined;
25
25
  }>, {
26
- direction: "horizontal" | "vertical";
27
26
  clickable: boolean;
27
+ direction: "horizontal" | "vertical";
28
28
  current: number;
29
29
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
30
30
  declare const _default: typeof __VLS_export;
@@ -76,10 +76,10 @@ declare const __VLS_export: vue.DefineComponent<__VLS_Props, {
76
76
  onClose?: ((fallbackPath: string) => any) | undefined;
77
77
  onCloseAll?: (() => any) | undefined;
78
78
  }>, {
79
+ persistKey: string;
79
80
  homePath: string;
80
81
  homeTitle: string;
81
82
  homeIcon: string;
82
- persistKey: string;
83
83
  contextMenuLabels: ContextMenuLabels;
84
84
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
85
85
  declare const _default: typeof __VLS_export;
@@ -647,12 +647,12 @@ declare const __VLS_export: vue.DefineComponent<Props, {
647
647
  onTaskClick?: ((task: GanttTask, event: Event) => any) | undefined;
648
648
  onTaskChange?: ((task: GanttTask, changes: any) => any) | undefined;
649
649
  }>, {
650
- height: string | number;
651
650
  theme: "light" | "dark";
652
- data: GanttTask[];
653
651
  title: string;
654
- options: GanttOptions;
652
+ height: string | number;
653
+ data: GanttTask[];
655
654
  showToolbar: boolean;
655
+ options: GanttOptions;
656
656
  preset: GanttPreset;
657
657
  showFullscreenButton: boolean;
658
658
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
@@ -20,9 +20,9 @@ declare const __VLS_export: vue.DefineComponent<Props, {}, {}, {}, {}, vue.Compo
20
20
  }, string, vue.PublicProps, Readonly<Props> & Readonly<{
21
21
  onError?: ((error: Error) => any) | undefined;
22
22
  }>, {
23
+ height: number;
23
24
  format: "CODE128" | "CODE39" | "EAN13" | "EAN8" | "UPC" | "ITF14" | "MSI" | "pharmacode";
24
25
  width: number;
25
- height: number;
26
26
  showText: boolean;
27
27
  fontSize: number;
28
28
  textPosition: "bottom" | "top";
@@ -25,20 +25,20 @@ declare const __VLS_export: vue.DefineComponent<Props, {
25
25
  copyCode: typeof copyCode;
26
26
  toggleFullscreen: typeof toggleFullscreen;
27
27
  }, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
28
- copy: (code: string) => any;
29
28
  click: (event: MouseEvent) => any;
29
+ copy: (code: string) => any;
30
30
  fullscreen: (isFullscreen: boolean) => any;
31
31
  }, string, vue.PublicProps, Readonly<Props> & Readonly<{
32
- onCopy?: ((code: string) => any) | undefined;
33
32
  onClick?: ((event: MouseEvent) => any) | undefined;
33
+ onCopy?: ((code: string) => any) | undefined;
34
34
  onFullscreen?: ((isFullscreen: boolean) => any) | undefined;
35
35
  }>, {
36
- wordWrap: boolean;
37
36
  trim: boolean;
38
37
  code: string;
39
38
  language: string;
40
39
  showHeader: boolean;
41
40
  showLineNumbers: boolean;
41
+ wordWrap: boolean;
42
42
  showFullscreen: boolean;
43
43
  autoLoadLanguage: boolean;
44
44
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
@@ -40,8 +40,8 @@ declare const __VLS_export: vue.DefineComponent<Props, {
40
40
  "onUpdate:smartRange"?: ((value: DateRangeValue) => any) | undefined;
41
41
  }>, {
42
42
  disabled: boolean;
43
- mode: DatePickerMode;
44
43
  placeholder: string;
44
+ mode: DatePickerMode;
45
45
  startPlaceholder: string;
46
46
  endPlaceholder: string;
47
47
  disabledBeforeToday: boolean;
@@ -28,11 +28,11 @@ declare const __VLS_export: vue.DefineComponent<Props, {
28
28
  "onEditor-mounted"?: ((editor: any) => any) | undefined;
29
29
  "onEditor-change"?: ((html: string) => any) | undefined;
30
30
  }>, {
31
- height: number;
32
31
  disabled: boolean;
33
32
  theme: "light" | "dark";
34
- placeholder: string;
35
33
  modelValue: string;
34
+ height: number;
35
+ placeholder: string;
36
36
  readonly: boolean;
37
37
  }, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
38
38
  declare const _default: typeof __VLS_export;
@@ -1,2 +1,2 @@
1
- import{h as e}from"vue";import{Icon as t}from"@iconify/vue";const n=e=>e.startsWith(`/`)?e:`/${e}`,r=e=>e.path?n(e.path):``,i=e=>e.meta?.title||e.name||``,a=e=>!e.meta?.hidden,o=n=>{if(n){if(typeof n==`string`)return()=>e(`span`,{class:`n-icon`,style:`display: inline-flex; align-items: center;`},[e(t,{icon:n})]);if(typeof n==`function`)return n}};function s(e,t={}){let{labelFormatter:n=e=>e,getKey:s=r,getLabel:c=i,filter:l=a,renderIcon:u=o,recursive:d=!0}=t,f=e=>e.filter(l).map(e=>{let t=e.meta?.icon||e.icon,r=d&&e.children?.length?f(e.children):void 0;return{key:s(e),label:n(c(e)),disabled:e.disabled||!1,icon:u(t),...e.type&&{type:e.type},...r?.length&&{children:r}}});return f(e)}function c(e,t=a){let n=[],r=e=>{for(let i of e)t(i)&&n.push(i),i.children?.length&&r(i.children)};return r(e),n}export{c as n,s as t};
1
+ import{t as e}from"./C_Icon2.js";import{h as t}from"vue";const n=e=>e.startsWith(`/`)?e:`/${e}`,r=e=>e.path?n(e.path):``,i=e=>e.meta?.title||e.name||``,a=e=>!e.meta?.hidden,o=n=>{if(n){if(typeof n==`string`)return()=>t(e,{name:n,size:18});if(typeof n==`function`)return n}};function s(e,t={}){let{labelFormatter:n=e=>e,getKey:s=r,getLabel:c=i,filter:l=a,renderIcon:u=o,recursive:d=!0}=t,f=e=>e.filter(l).map(e=>{let t=e.meta?.icon||e.icon,r=d&&e.children?.length?f(e.children):void 0;return{key:s(e),label:n(c(e)),disabled:e.disabled||!1,icon:u(t),...e.type&&{type:e.type},...r?.length&&{children:r}}});return f(e)}function c(e,t=a){let n=[],r=e=>{for(let i of e)t(i)&&n.push(i),i.children?.length&&r(i.children)};return r(e),n}export{c as n,s as t};
2
2
  //# sourceMappingURL=menuAdapter.js.map