@robot-admin/layout 3.0.0 → 3.2.0
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.
- package/CHANGELOG.md +164 -144
- package/README.md +519 -410
- package/dist/core/index.cjs +8 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +6 -1
- package/dist/core/index.d.ts +6 -1
- package/dist/core/index.js +7 -1
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +1 -39
- package/dist/index.css +1 -1
- package/dist/index.d.cts +1537 -360
- package/dist/index.d.ts +1537 -360
- package/dist/index.js +3 -2296
- package/dist/naive/index.cjs +1 -0
- package/dist/naive/index.d.cts +2927 -0
- package/dist/naive/index.d.ts +2927 -0
- package/dist/naive/index.js +3 -0
- package/dist/naive-Bd8pxcrF.js +1635 -0
- package/dist/naive-Bd8pxcrF.js.map +1 -0
- package/dist/naive-BfZUS_c8.cjs +28 -0
- package/dist/naive-BfZUS_c8.cjs.map +1 -0
- package/dist/vue/index.cjs +1 -0
- package/dist/vue/index.d.cts +1181 -0
- package/dist/vue/index.d.ts +1181 -0
- package/dist/vue/index.js +2 -0
- package/dist/vue-BRQ1Fg0b.js +739 -0
- package/dist/vue-BRQ1Fg0b.js.map +1 -0
- package/dist/vue-DhbxgFgz.cjs +2 -0
- package/dist/vue-DhbxgFgz.cjs.map +1 -0
- package/package.json +128 -100
- package/src/styles/layouts.scss +137 -82
- package/src/styles/settings.scss +421 -391
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naive-BfZUS_c8.cjs","names":["$slots"],"sources":["../src/components/LayoutRouterView/index.vue","../src/components/LayoutRouterView/index.vue","../src/components/layouts/SideLayout/index.vue","../src/components/layouts/SideLayout/index.vue","../src/components/ResponsiveMenu/index.vue","../src/components/ResponsiveMenu/index.vue","../src/components/layouts/TopLayout/index.vue","../src/components/layouts/TopLayout/index.vue","../src/components/layouts/MixLayout/index.vue","../src/components/layouts/MixLayout/index.vue","../src/components/layouts/MixTopLayout/index.vue","../src/components/layouts/MixTopLayout/index.vue","../src/components/layouts/ReverseHorizontalMixLayout/index.vue","../src/components/layouts/ReverseHorizontalMixLayout/index.vue","../src/components/layouts/CardLayout/index.vue","../src/components/layouts/CardLayout/index.vue","../src/components/C_LayoutContainer/index.vue","../src/components/C_LayoutContainer/index.vue","../src/components/SettingsDrawer/data.ts","../src/components/SettingsDrawer/index.vue","../src/components/SettingsDrawer/index.vue","../src/components/BrandLogo/index.vue","../src/components/BrandLogo/index.vue","../src/components/IconMenu/index.vue","../src/components/IconMenu/index.vue","../src/components/FloatingMenu/index.vue","../src/components/FloatingMenu/index.vue","../src/components/SideMenu/index.vue","../src/components/SideMenu/index.vue","../src/components/DrawerMenu/index.vue","../src/components/DrawerMenu/index.vue","../src/components/MenuTrigger/index.vue","../src/components/MenuTrigger/index.vue","../src/naive/index.ts"],"sourcesContent":["<!-- UI 框架无关的路由内容、过渡与 KeepAlive 统一边界。 -->\r\n<template>\r\n <RouterView v-slot=\"{ Component, route }\">\r\n <Transition :name=\"ctx.transitionName.value\" mode=\"out-in\">\r\n <KeepAlive :include=\"cachedViews\" :max=\"maxCacheCount\">\r\n <component :is=\"Component\" :key=\"route.path\" />\r\n </KeepAlive>\r\n </Transition>\r\n </RouterView>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { useLayoutCache } from \"../../composables/useLayoutCache\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"LayoutRouterView\" });\r\n\r\nconst ctx = useLayoutContext();\r\nconst { cachedViews, maxCacheCount } = useLayoutCache();\r\n</script>\r\n","<!-- UI 框架无关的路由内容、过渡与 KeepAlive 统一边界。 -->\r\n<template>\r\n <RouterView v-slot=\"{ Component, route }\">\r\n <Transition :name=\"ctx.transitionName.value\" mode=\"out-in\">\r\n <KeepAlive :include=\"cachedViews\" :max=\"maxCacheCount\">\r\n <component :is=\"Component\" :key=\"route.path\" />\r\n </KeepAlive>\r\n </Transition>\r\n </RouterView>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { useLayoutCache } from \"../../composables/useLayoutCache\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"LayoutRouterView\" });\r\n\r\nconst ctx = useLayoutContext();\r\nconst { cachedViews, maxCacheCount } = useLayoutCache();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_SideLayout\n *\r\n * 左侧菜单布局骨架\r\n * 经典的左侧导航 + 右侧内容布局,使用 NLayout/NLayoutSider 实现\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域(侧边栏顶部)\r\n * #menu - 垂直菜单区域(侧边栏)\r\n * #header - 头部区域(含面包屑、导航栏右侧操作等)\r\n * #default - 页面内容(自动包含 RouterView + KeepAlive + Transition)\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <NLayout has-sider>\r\n <NLayoutSider\r\n bordered\r\n collapse-mode=\"width\"\r\n :collapsed-width=\"ctx.sidebarCollapsedWidth.value\"\r\n :width=\"ctx.sidebarWidth.value\"\r\n :native-scrollbar=\"false\"\r\n :collapsed=\"collapsed\"\r\n @update:collapsed=\"handleCollapsedUpdate\"\r\n :class=\"[\r\n 'layout-sider',\r\n 'no-horizontal-scroll',\r\n ctx.isDark.value ? 'dark-theme' : 'light-theme',\r\n ]\"\r\n >\r\n <slot name=\"logo\" />\r\n <slot name=\"menu\" :collapsed=\"collapsed\" />\r\n </NLayoutSider>\r\n\r\n <NLayout>\r\n <slot name=\"header\" />\r\n\r\n <NLayoutContent class=\"content-with-header p16px app-content\">\r\n <LayoutRouterView />\r\n </NLayoutContent>\r\n\r\n <slot name=\"footer\" />\r\n </NLayout>\r\n </NLayout>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, watch } from \"vue\";\r\nimport { NLayout, NLayoutSider, NLayoutContent } from \"naive-ui\";\r\nimport { useLayoutContext } from \"../../../composables/useLayoutContext\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\n\r\ndefineOptions({ name: \"C_SideLayout\" });\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 控制侧边栏折叠状态 (支持 v-model:collapsed) */\r\n collapsed?: boolean;\r\n }>(),\r\n { collapsed: false },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:collapsed\": [value: boolean];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\n\r\n// 内部折叠状态,与 prop 双向同步\r\nconst _collapsed = ref(props.collapsed);\r\nwatch(\r\n () => props.collapsed,\r\n (v) => {\r\n _collapsed.value = v;\r\n },\r\n);\r\n\r\nconst collapsed = computed(() => _collapsed.value);\r\n\r\nconst handleCollapsedUpdate = (val: boolean) => {\r\n _collapsed.value = val;\r\n emit(\"update:collapsed\", val);\r\n};\r\n\r\n// 折叠切换\r\nconst toggleCollapse = () => {\r\n const next = !_collapsed.value;\r\n _collapsed.value = next;\r\n emit(\"update:collapsed\", next);\r\n};\r\n\r\ndefineExpose({\r\n collapsed,\r\n toggleCollapse,\r\n});\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_SideLayout\n *\r\n * 左侧菜单布局骨架\r\n * 经典的左侧导航 + 右侧内容布局,使用 NLayout/NLayoutSider 实现\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域(侧边栏顶部)\r\n * #menu - 垂直菜单区域(侧边栏)\r\n * #header - 头部区域(含面包屑、导航栏右侧操作等)\r\n * #default - 页面内容(自动包含 RouterView + KeepAlive + Transition)\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <NLayout has-sider>\r\n <NLayoutSider\r\n bordered\r\n collapse-mode=\"width\"\r\n :collapsed-width=\"ctx.sidebarCollapsedWidth.value\"\r\n :width=\"ctx.sidebarWidth.value\"\r\n :native-scrollbar=\"false\"\r\n :collapsed=\"collapsed\"\r\n @update:collapsed=\"handleCollapsedUpdate\"\r\n :class=\"[\r\n 'layout-sider',\r\n 'no-horizontal-scroll',\r\n ctx.isDark.value ? 'dark-theme' : 'light-theme',\r\n ]\"\r\n >\r\n <slot name=\"logo\" />\r\n <slot name=\"menu\" :collapsed=\"collapsed\" />\r\n </NLayoutSider>\r\n\r\n <NLayout>\r\n <slot name=\"header\" />\r\n\r\n <NLayoutContent class=\"content-with-header p16px app-content\">\r\n <LayoutRouterView />\r\n </NLayoutContent>\r\n\r\n <slot name=\"footer\" />\r\n </NLayout>\r\n </NLayout>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, watch } from \"vue\";\r\nimport { NLayout, NLayoutSider, NLayoutContent } from \"naive-ui\";\r\nimport { useLayoutContext } from \"../../../composables/useLayoutContext\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\n\r\ndefineOptions({ name: \"C_SideLayout\" });\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 控制侧边栏折叠状态 (支持 v-model:collapsed) */\r\n collapsed?: boolean;\r\n }>(),\r\n { collapsed: false },\r\n);\r\n\r\nconst emit = defineEmits<{\r\n \"update:collapsed\": [value: boolean];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\n\r\n// 内部折叠状态,与 prop 双向同步\r\nconst _collapsed = ref(props.collapsed);\r\nwatch(\r\n () => props.collapsed,\r\n (v) => {\r\n _collapsed.value = v;\r\n },\r\n);\r\n\r\nconst collapsed = computed(() => _collapsed.value);\r\n\r\nconst handleCollapsedUpdate = (val: boolean) => {\r\n _collapsed.value = val;\r\n emit(\"update:collapsed\", val);\r\n};\r\n\r\n// 折叠切换\r\nconst toggleCollapse = () => {\r\n const next = !_collapsed.value;\r\n _collapsed.value = next;\r\n emit(\"update:collapsed\", next);\r\n};\r\n\r\ndefineExpose({\r\n collapsed,\r\n toggleCollapse,\r\n});\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - ResponsiveMenu\r\n *\r\n * 响应式水平菜单\r\n * 用于 C_TopLayout / C_MixTopLayout / C_ReverseHorizontalMixLayout 的水平菜单\n * 自动检测容器宽度,溢出项放入“更多”下拉菜单,使用 NMenu (naive-ui) 渲染\r\n -->\r\n<template>\r\n <div :ref=\"setContainerRef\" class=\"responsive-menu\">\r\n <div class=\"responsive-menu__visible\">\r\n <NMenu\r\n v-if=\"visibleOptions.length > 0\"\r\n mode=\"horizontal\"\r\n :value=\"activeKey\"\r\n :options=\"visibleOptions\"\r\n :theme-overrides=\"menuThemeOverrides\"\r\n @update:value=\"handleSelect\"\r\n />\r\n </div>\r\n\r\n <NDropdown\r\n v-if=\"hiddenItems.length > 0\"\r\n :options=\"dropdownOptions\"\r\n placement=\"bottom-end\"\r\n trigger=\"hover\"\r\n @select=\"handleSelect\"\r\n >\r\n <div class=\"responsive-menu__more\">\r\n <NButton text class=\"responsive-menu__more-btn\">\r\n <!-- 纯 CSS 三个点图标 -->\r\n <span class=\"dots-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n </NButton>\r\n </div>\r\n </NDropdown>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, h } from \"vue\";\r\nimport { useRoute, useRouter } from \"vue-router\";\r\nimport { NMenu, NDropdown, NButton } from \"naive-ui\";\r\nimport type { MenuOption, DropdownOption } from \"naive-ui\";\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\nimport { useResponsiveMenu } from \"../../composables/useResponsiveMenu\";\r\n\r\ndefineOptions({ name: \"ResponsiveMenu\" });\r\n\r\nconst props = defineProps<{\r\n /** 菜单数据 */\r\n data: MenuOptions[];\r\n}>();\r\n\r\nconst route = useRoute();\r\nconst router = useRouter();\r\nconst ctx = useLayoutContext();\r\n\r\nconst activeKey = computed(() => route.path);\r\nconst { containerRef, visibleItems, hiddenItems } = useResponsiveMenu({\r\n data: () => props.data || [],\r\n});\r\nconst setContainerRef = (element: unknown) => {\r\n containerRef.value = element instanceof HTMLElement ? element : undefined;\r\n};\r\n\r\n// 根据主题选择菜单样式\r\nconst isDarkMode = ctx.isDark;\r\n\r\nconst lightTheme = {\r\n itemTextColor: \"rgba(51, 65, 85, 0.85)\",\r\n itemTextColorHover: \"rgba(30, 64, 175, 0.95)\",\r\n itemTextColorActive: \"rgba(30, 64, 175, 1)\",\r\n itemTextColorActiveHover: \"rgba(30, 64, 175, 1)\",\r\n itemTextColorChildActive: \"rgba(30, 64, 175, 1)\",\r\n itemIconColor: \"rgba(51, 65, 85, 0.7)\",\r\n itemIconColorHover: \"rgba(30, 64, 175, 0.85)\",\r\n itemIconColorActive: \"rgba(30, 64, 175, 1)\",\r\n itemIconColorActiveHover: \"rgba(30, 64, 175, 1)\",\r\n itemIconColorChildActive: \"rgba(30, 64, 175, 1)\",\r\n itemColorHover: \"rgba(30, 64, 175, 0.06)\",\r\n itemColorActive: \"rgba(30, 64, 175, 0.1)\",\r\n itemColorActiveHover: \"rgba(30, 64, 175, 0.12)\",\r\n itemColorActiveCollapsed: \"rgba(30, 64, 175, 0.1)\",\r\n arrowColor: \"rgba(51, 65, 85, 0.6)\",\r\n arrowColorHover: \"rgba(30, 64, 175, 0.8)\",\r\n arrowColorActive: \"rgba(30, 64, 175, 1)\",\r\n arrowColorChildActive: \"rgba(30, 64, 175, 1)\",\r\n itemHeight: \"42px\",\r\n itemPadding: \"0 18px\",\r\n itemBorderRadius: \"10px\",\r\n groupTextColor: \"rgba(51, 65, 85, 0.65)\",\r\n};\r\n\r\nconst darkTheme = {\r\n itemTextColor: \"rgba(226, 232, 240, 0.85)\",\r\n itemTextColorHover: \"rgba(255, 255, 255, 0.95)\",\r\n itemTextColorActive: \"rgba(147, 197, 253, 1)\",\r\n itemTextColorActiveHover: \"rgba(147, 197, 253, 1)\",\r\n itemTextColorChildActive: \"rgba(147, 197, 253, 1)\",\r\n itemIconColor: \"rgba(226, 232, 240, 0.7)\",\r\n itemIconColorHover: \"rgba(255, 255, 255, 0.85)\",\r\n itemIconColorActive: \"rgba(147, 197, 253, 1)\",\r\n itemIconColorActiveHover: \"rgba(147, 197, 253, 1)\",\r\n itemIconColorChildActive: \"rgba(147, 197, 253, 1)\",\r\n itemColorHover: \"rgba(59, 130, 246, 0.1)\",\r\n itemColorActive: \"rgba(59, 130, 246, 0.15)\",\r\n itemColorActiveHover: \"rgba(59, 130, 246, 0.18)\",\r\n itemColorActiveCollapsed: \"rgba(59, 130, 246, 0.15)\",\r\n arrowColor: \"rgba(226, 232, 240, 0.5)\",\r\n arrowColorHover: \"rgba(255, 255, 255, 0.7)\",\r\n arrowColorActive: \"rgba(147, 197, 253, 1)\",\r\n arrowColorChildActive: \"rgba(147, 197, 253, 1)\",\r\n itemHeight: \"42px\",\r\n itemPadding: \"0 18px\",\r\n itemBorderRadius: \"10px\",\r\n groupTextColor: \"rgba(226, 232, 240, 0.6)\",\r\n};\r\n\r\nconst menuThemeOverrides = computed(() =>\r\n isDarkMode.value ? darkTheme : lightTheme,\r\n);\r\n\r\n// ============ 图标渲染 ============\r\n\r\nconst renderIcon = (icon: string, size = 18) => {\r\n if (ctx.iconComponent) {\r\n return () => h(ctx.iconComponent!, { name: icon, size });\r\n }\r\n return () =>\r\n h(\"i\", {\r\n class: icon,\r\n style: {\r\n fontSize: `${size}px`,\r\n display: \"inline-flex\",\r\n alignItems: \"center\",\r\n },\r\n });\r\n};\r\n\r\n// ============ 菜单转换 ============\r\n\r\nconst getStringIcon = (item: MenuOptions) =>\r\n item.meta?.icon ?? (typeof item.icon === \"string\" ? item.icon : undefined);\r\n\r\nconst convertToMenuOption = (item: MenuOptions): MenuOption => {\r\n const icon = getStringIcon(item);\r\n return {\r\n key: item.path || item.key || \"\",\r\n label: item.meta?.title || item.label || item.name || \"\",\r\n icon: icon ? renderIcon(icon, 18) : undefined,\r\n children: item.children?.length\r\n ? item.children.map(convertToMenuOption)\r\n : undefined,\r\n };\r\n};\r\n\r\nconst visibleOptions = computed<MenuOption[]>(() =>\r\n visibleItems.value.map(convertToMenuOption),\r\n);\r\n\r\nconst dropdownOptions = computed<DropdownOption[]>(() =>\r\n hiddenItems.value.map((item) => {\r\n const icon = getStringIcon(item);\r\n return {\r\n key: item.path || item.key || \"\",\r\n label: item.meta?.title || item.label || item.name || \"\",\r\n icon: icon ? renderIcon(icon, 16) : undefined,\r\n children: item.children?.length\r\n ? item.children.map((child) => {\r\n const childIcon = getStringIcon(child);\r\n return {\r\n key: child.path || child.key || \"\",\r\n label: child.meta?.title || child.label || child.name || \"\",\r\n icon: childIcon ? renderIcon(childIcon, 16) : undefined,\r\n };\r\n })\r\n : undefined,\r\n };\r\n }),\r\n);\r\n\r\nconst handleSelect = (key: string) => {\r\n if (key) void router.push(key);\r\n};\r\n</script>\r\n\r\n<style scoped>\r\n.responsive-menu {\r\n display: flex;\r\n align-items: center;\r\n width: 100%;\r\n gap: 0;\r\n}\r\n\r\n.responsive-menu__visible {\r\n flex: 0 1 auto;\r\n min-width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu) {\r\n background-color: transparent !important;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item) {\r\n position: relative;\r\n font-weight: 500;\r\n letter-spacing: 0.01em;\r\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n/* 防止 NMenu 内部截断菜单项文字 */\r\n.responsive-menu__visible :deep(.n-menu-item-content-header) {\r\n overflow: visible !important;\r\n text-overflow: clip !important;\r\n white-space: nowrap !important;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item-content) {\r\n overflow: visible !important;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item::after) {\r\n content: \"\";\r\n position: absolute;\r\n bottom: 0;\r\n left: 50%;\r\n transform: translateX(-50%) scaleX(0);\r\n width: 60%;\r\n height: 2px;\r\n background: linear-gradient(90deg, transparent, currentColor, transparent);\r\n opacity: 0;\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item.n-menu-item--selected::after) {\r\n transform: translateX(-50%) scaleX(1);\r\n opacity: 0.5;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item:hover) {\r\n transform: translateY(-1px);\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item.n-menu-item--selected) {\r\n box-shadow:\r\n 0 2px 8px -2px rgba(30, 64, 175, 0.15),\r\n 0 1px 3px rgba(30, 64, 175, 0.1);\r\n}\r\n\r\n.responsive-menu__more {\r\n flex-shrink: 0;\r\n margin-left: 4px;\r\n}\r\n\r\n.responsive-menu__more-btn {\r\n min-width: 42px;\r\n height: 42px;\r\n padding: 0 18px !important;\r\n border-radius: 10px !important;\r\n background-color: transparent !important;\r\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.responsive-menu__more-btn::before,\r\n.responsive-menu__more-btn :deep(.n-button__border),\r\n.responsive-menu__more-btn :deep(.n-button__state-border) {\r\n display: none !important;\r\n}\r\n\r\n.responsive-menu__more-btn:hover {\r\n background-color: rgba(30, 64, 175, 0.06) !important;\r\n transform: translateY(-1px);\r\n}\r\n\r\n/* 纯 CSS 三个点图标 */\r\n.dots-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 3px;\r\n width: 20px;\r\n height: 20px;\r\n}\r\n\r\n.dots-icon span {\r\n width: 4px;\r\n height: 4px;\r\n border-radius: 50%;\r\n background-color: currentColor;\r\n opacity: 0.85;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - ResponsiveMenu\r\n *\r\n * 响应式水平菜单\r\n * 用于 C_TopLayout / C_MixTopLayout / C_ReverseHorizontalMixLayout 的水平菜单\n * 自动检测容器宽度,溢出项放入“更多”下拉菜单,使用 NMenu (naive-ui) 渲染\r\n -->\r\n<template>\r\n <div :ref=\"setContainerRef\" class=\"responsive-menu\">\r\n <div class=\"responsive-menu__visible\">\r\n <NMenu\r\n v-if=\"visibleOptions.length > 0\"\r\n mode=\"horizontal\"\r\n :value=\"activeKey\"\r\n :options=\"visibleOptions\"\r\n :theme-overrides=\"menuThemeOverrides\"\r\n @update:value=\"handleSelect\"\r\n />\r\n </div>\r\n\r\n <NDropdown\r\n v-if=\"hiddenItems.length > 0\"\r\n :options=\"dropdownOptions\"\r\n placement=\"bottom-end\"\r\n trigger=\"hover\"\r\n @select=\"handleSelect\"\r\n >\r\n <div class=\"responsive-menu__more\">\r\n <NButton text class=\"responsive-menu__more-btn\">\r\n <!-- 纯 CSS 三个点图标 -->\r\n <span class=\"dots-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n </NButton>\r\n </div>\r\n </NDropdown>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, h } from \"vue\";\r\nimport { useRoute, useRouter } from \"vue-router\";\r\nimport { NMenu, NDropdown, NButton } from \"naive-ui\";\r\nimport type { MenuOption, DropdownOption } from \"naive-ui\";\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\nimport { useResponsiveMenu } from \"../../composables/useResponsiveMenu\";\r\n\r\ndefineOptions({ name: \"ResponsiveMenu\" });\r\n\r\nconst props = defineProps<{\r\n /** 菜单数据 */\r\n data: MenuOptions[];\r\n}>();\r\n\r\nconst route = useRoute();\r\nconst router = useRouter();\r\nconst ctx = useLayoutContext();\r\n\r\nconst activeKey = computed(() => route.path);\r\nconst { containerRef, visibleItems, hiddenItems } = useResponsiveMenu({\r\n data: () => props.data || [],\r\n});\r\nconst setContainerRef = (element: unknown) => {\r\n containerRef.value = element instanceof HTMLElement ? element : undefined;\r\n};\r\n\r\n// 根据主题选择菜单样式\r\nconst isDarkMode = ctx.isDark;\r\n\r\nconst lightTheme = {\r\n itemTextColor: \"rgba(51, 65, 85, 0.85)\",\r\n itemTextColorHover: \"rgba(30, 64, 175, 0.95)\",\r\n itemTextColorActive: \"rgba(30, 64, 175, 1)\",\r\n itemTextColorActiveHover: \"rgba(30, 64, 175, 1)\",\r\n itemTextColorChildActive: \"rgba(30, 64, 175, 1)\",\r\n itemIconColor: \"rgba(51, 65, 85, 0.7)\",\r\n itemIconColorHover: \"rgba(30, 64, 175, 0.85)\",\r\n itemIconColorActive: \"rgba(30, 64, 175, 1)\",\r\n itemIconColorActiveHover: \"rgba(30, 64, 175, 1)\",\r\n itemIconColorChildActive: \"rgba(30, 64, 175, 1)\",\r\n itemColorHover: \"rgba(30, 64, 175, 0.06)\",\r\n itemColorActive: \"rgba(30, 64, 175, 0.1)\",\r\n itemColorActiveHover: \"rgba(30, 64, 175, 0.12)\",\r\n itemColorActiveCollapsed: \"rgba(30, 64, 175, 0.1)\",\r\n arrowColor: \"rgba(51, 65, 85, 0.6)\",\r\n arrowColorHover: \"rgba(30, 64, 175, 0.8)\",\r\n arrowColorActive: \"rgba(30, 64, 175, 1)\",\r\n arrowColorChildActive: \"rgba(30, 64, 175, 1)\",\r\n itemHeight: \"42px\",\r\n itemPadding: \"0 18px\",\r\n itemBorderRadius: \"10px\",\r\n groupTextColor: \"rgba(51, 65, 85, 0.65)\",\r\n};\r\n\r\nconst darkTheme = {\r\n itemTextColor: \"rgba(226, 232, 240, 0.85)\",\r\n itemTextColorHover: \"rgba(255, 255, 255, 0.95)\",\r\n itemTextColorActive: \"rgba(147, 197, 253, 1)\",\r\n itemTextColorActiveHover: \"rgba(147, 197, 253, 1)\",\r\n itemTextColorChildActive: \"rgba(147, 197, 253, 1)\",\r\n itemIconColor: \"rgba(226, 232, 240, 0.7)\",\r\n itemIconColorHover: \"rgba(255, 255, 255, 0.85)\",\r\n itemIconColorActive: \"rgba(147, 197, 253, 1)\",\r\n itemIconColorActiveHover: \"rgba(147, 197, 253, 1)\",\r\n itemIconColorChildActive: \"rgba(147, 197, 253, 1)\",\r\n itemColorHover: \"rgba(59, 130, 246, 0.1)\",\r\n itemColorActive: \"rgba(59, 130, 246, 0.15)\",\r\n itemColorActiveHover: \"rgba(59, 130, 246, 0.18)\",\r\n itemColorActiveCollapsed: \"rgba(59, 130, 246, 0.15)\",\r\n arrowColor: \"rgba(226, 232, 240, 0.5)\",\r\n arrowColorHover: \"rgba(255, 255, 255, 0.7)\",\r\n arrowColorActive: \"rgba(147, 197, 253, 1)\",\r\n arrowColorChildActive: \"rgba(147, 197, 253, 1)\",\r\n itemHeight: \"42px\",\r\n itemPadding: \"0 18px\",\r\n itemBorderRadius: \"10px\",\r\n groupTextColor: \"rgba(226, 232, 240, 0.6)\",\r\n};\r\n\r\nconst menuThemeOverrides = computed(() =>\r\n isDarkMode.value ? darkTheme : lightTheme,\r\n);\r\n\r\n// ============ 图标渲染 ============\r\n\r\nconst renderIcon = (icon: string, size = 18) => {\r\n if (ctx.iconComponent) {\r\n return () => h(ctx.iconComponent!, { name: icon, size });\r\n }\r\n return () =>\r\n h(\"i\", {\r\n class: icon,\r\n style: {\r\n fontSize: `${size}px`,\r\n display: \"inline-flex\",\r\n alignItems: \"center\",\r\n },\r\n });\r\n};\r\n\r\n// ============ 菜单转换 ============\r\n\r\nconst getStringIcon = (item: MenuOptions) =>\r\n item.meta?.icon ?? (typeof item.icon === \"string\" ? item.icon : undefined);\r\n\r\nconst convertToMenuOption = (item: MenuOptions): MenuOption => {\r\n const icon = getStringIcon(item);\r\n return {\r\n key: item.path || item.key || \"\",\r\n label: item.meta?.title || item.label || item.name || \"\",\r\n icon: icon ? renderIcon(icon, 18) : undefined,\r\n children: item.children?.length\r\n ? item.children.map(convertToMenuOption)\r\n : undefined,\r\n };\r\n};\r\n\r\nconst visibleOptions = computed<MenuOption[]>(() =>\r\n visibleItems.value.map(convertToMenuOption),\r\n);\r\n\r\nconst dropdownOptions = computed<DropdownOption[]>(() =>\r\n hiddenItems.value.map((item) => {\r\n const icon = getStringIcon(item);\r\n return {\r\n key: item.path || item.key || \"\",\r\n label: item.meta?.title || item.label || item.name || \"\",\r\n icon: icon ? renderIcon(icon, 16) : undefined,\r\n children: item.children?.length\r\n ? item.children.map((child) => {\r\n const childIcon = getStringIcon(child);\r\n return {\r\n key: child.path || child.key || \"\",\r\n label: child.meta?.title || child.label || child.name || \"\",\r\n icon: childIcon ? renderIcon(childIcon, 16) : undefined,\r\n };\r\n })\r\n : undefined,\r\n };\r\n }),\r\n);\r\n\r\nconst handleSelect = (key: string) => {\r\n if (key) void router.push(key);\r\n};\r\n</script>\r\n\r\n<style scoped>\r\n.responsive-menu {\r\n display: flex;\r\n align-items: center;\r\n width: 100%;\r\n gap: 0;\r\n}\r\n\r\n.responsive-menu__visible {\r\n flex: 0 1 auto;\r\n min-width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu) {\r\n background-color: transparent !important;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item) {\r\n position: relative;\r\n font-weight: 500;\r\n letter-spacing: 0.01em;\r\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n/* 防止 NMenu 内部截断菜单项文字 */\r\n.responsive-menu__visible :deep(.n-menu-item-content-header) {\r\n overflow: visible !important;\r\n text-overflow: clip !important;\r\n white-space: nowrap !important;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item-content) {\r\n overflow: visible !important;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item::after) {\r\n content: \"\";\r\n position: absolute;\r\n bottom: 0;\r\n left: 50%;\r\n transform: translateX(-50%) scaleX(0);\r\n width: 60%;\r\n height: 2px;\r\n background: linear-gradient(90deg, transparent, currentColor, transparent);\r\n opacity: 0;\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item.n-menu-item--selected::after) {\r\n transform: translateX(-50%) scaleX(1);\r\n opacity: 0.5;\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item:hover) {\r\n transform: translateY(-1px);\r\n}\r\n\r\n.responsive-menu__visible :deep(.n-menu-item.n-menu-item--selected) {\r\n box-shadow:\r\n 0 2px 8px -2px rgba(30, 64, 175, 0.15),\r\n 0 1px 3px rgba(30, 64, 175, 0.1);\r\n}\r\n\r\n.responsive-menu__more {\r\n flex-shrink: 0;\r\n margin-left: 4px;\r\n}\r\n\r\n.responsive-menu__more-btn {\r\n min-width: 42px;\r\n height: 42px;\r\n padding: 0 18px !important;\r\n border-radius: 10px !important;\r\n background-color: transparent !important;\r\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.responsive-menu__more-btn::before,\r\n.responsive-menu__more-btn :deep(.n-button__border),\r\n.responsive-menu__more-btn :deep(.n-button__state-border) {\r\n display: none !important;\r\n}\r\n\r\n.responsive-menu__more-btn:hover {\r\n background-color: rgba(30, 64, 175, 0.06) !important;\r\n transform: translateY(-1px);\r\n}\r\n\r\n/* 纯 CSS 三个点图标 */\r\n.dots-icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 3px;\r\n width: 20px;\r\n height: 20px;\r\n}\r\n\r\n.dots-icon span {\r\n width: 4px;\r\n height: 4px;\r\n border-radius: 50%;\r\n background-color: currentColor;\r\n opacity: 0.85;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - C_TopLayout\n *\r\n * 顶部导航布局骨架\r\n * Logo+品牌 | 水平菜单 | 操作区 → 标签页 → 内容区 → 页脚\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域\r\n * #menu - 水平菜单(默认使用 ResponsiveMenu)\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"top-layout-container\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 左侧:Logo 和品牌 -->\r\n <div class=\"navbar-left\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-container\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </div>\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 中间:水平菜单 -->\r\n <div class=\"navbar-center\">\r\n <slot name=\"menu\">\r\n <ResponsiveMenu :data=\"menus\" />\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 主内容区域 -->\r\n <NLayout>\r\n <NLayoutContent class=\"main-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <!-- 页脚 -->\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport ResponsiveMenu from \"../../ResponsiveMenu/index.vue\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\n\r\ndefineOptions({ name: \"C_TopLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_TopLayout\n *\r\n * 顶部导航布局骨架\r\n * Logo+品牌 | 水平菜单 | 操作区 → 标签页 → 内容区 → 页脚\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域\r\n * #menu - 水平菜单(默认使用 ResponsiveMenu)\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"top-layout-container\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 左侧:Logo 和品牌 -->\r\n <div class=\"navbar-left\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-container\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </div>\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 中间:水平菜单 -->\r\n <div class=\"navbar-center\">\r\n <slot name=\"menu\">\r\n <ResponsiveMenu :data=\"menus\" />\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 主内容区域 -->\r\n <NLayout>\r\n <NLayoutContent class=\"main-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <!-- 页脚 -->\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport ResponsiveMenu from \"../../ResponsiveMenu/index.vue\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\n\r\ndefineOptions({ name: \"C_TopLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_MixLayout\n *\r\n * 混合布局骨架\r\n * 左侧一级菜单图标栏 + 悬浮二级菜单弹出面板 + 右侧内容区\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域(侧边栏顶部)\r\n * #header - 头部区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"mix-layout-container\">\r\n <!-- 左侧一级菜单 -->\r\n <div\r\n class=\"first-level-menu\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- Logo -->\r\n <div class=\"logo-container\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </slot>\r\n </div>\r\n\r\n <!-- 一级菜单列表 -->\r\n <div class=\"first-menu-list\">\r\n <div\r\n v-for=\"item in menus\"\r\n :key=\"item.path\"\r\n class=\"first-menu-item\"\r\n :class=\"{\r\n active: menuSplit.activeFirstMenu.value === item.path,\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n :aria-disabled=\"item.disabled || undefined\"\r\n @click=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.enter=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.space.prevent=\"menuSplit.handleFirstMenuClick(item)\"\r\n >\r\n <div class=\"menu-item-content\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"22\"\r\n />\r\n <span v-else class=\"menu-item-text\">{{\r\n (item.meta?.title || \"\")[0]\r\n }}</span>\r\n </div>\r\n <span class=\"menu-item-label\">{{ item.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 悬浮二级菜单 -->\r\n <Transition name=\"slide-fade\">\r\n <div\r\n v-if=\"menuSplit.showSecondMenu.value\"\r\n class=\"second-level-menu-popup\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <div class=\"second-menu-header\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"menuSplit.displayMenuItem.value?.meta?.icon\"\r\n :name=\"menuSplit.displayMenuItem.value.meta.icon\"\r\n :size=\"20\"\r\n />\r\n <span class=\"menu-title\">{{\r\n menuSplit.displayMenuItem.value?.meta?.title\r\n }}</span>\r\n </div>\r\n <div class=\"second-menu-list\">\r\n <div\r\n v-for=\"child in menuSplit.displayMenuItem.value?.children || []\"\r\n :key=\"child.path\"\r\n class=\"second-menu-item\"\r\n :class=\"{ active: menuSplit.isMenuItemActive(child.path) }\"\r\n role=\"link\"\r\n :tabindex=\"child.disabled ? -1 : 0\"\r\n :aria-disabled=\"child.disabled || undefined\"\r\n @click=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.enter=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.space.prevent=\"menuSplit.handleSecondMenuClick(child)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"menu-item-label\">{{ child.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </Transition>\r\n\r\n <!-- 右侧主内容区 -->\r\n <div class=\"main-layout\">\r\n <slot name=\"header\" />\r\n\r\n <NLayout>\r\n <NLayoutContent class=\"content-with-header p16px app-content\">\r\n <LayoutRouterView />\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport { useMenuSplit } from \"../../../composables/useMenuSplit\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_MixLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\nconst menuSplit = useMenuSplit({\r\n menus: ctx.menus,\r\n floatingSecondMenu: computed(() => true),\r\n});\r\n\r\n// 图标组件:优先使用消费方提供的,否则用 CSS class 渲染\r\nconst LayoutIcon = useLayoutIcon();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_MixLayout\n *\r\n * 混合布局骨架\r\n * 左侧一级菜单图标栏 + 悬浮二级菜单弹出面板 + 右侧内容区\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域(侧边栏顶部)\r\n * #header - 头部区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"mix-layout-container\">\r\n <!-- 左侧一级菜单 -->\r\n <div\r\n class=\"first-level-menu\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- Logo -->\r\n <div class=\"logo-container\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </slot>\r\n </div>\r\n\r\n <!-- 一级菜单列表 -->\r\n <div class=\"first-menu-list\">\r\n <div\r\n v-for=\"item in menus\"\r\n :key=\"item.path\"\r\n class=\"first-menu-item\"\r\n :class=\"{\r\n active: menuSplit.activeFirstMenu.value === item.path,\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n :aria-disabled=\"item.disabled || undefined\"\r\n @click=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.enter=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.space.prevent=\"menuSplit.handleFirstMenuClick(item)\"\r\n >\r\n <div class=\"menu-item-content\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"22\"\r\n />\r\n <span v-else class=\"menu-item-text\">{{\r\n (item.meta?.title || \"\")[0]\r\n }}</span>\r\n </div>\r\n <span class=\"menu-item-label\">{{ item.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 悬浮二级菜单 -->\r\n <Transition name=\"slide-fade\">\r\n <div\r\n v-if=\"menuSplit.showSecondMenu.value\"\r\n class=\"second-level-menu-popup\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <div class=\"second-menu-header\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"menuSplit.displayMenuItem.value?.meta?.icon\"\r\n :name=\"menuSplit.displayMenuItem.value.meta.icon\"\r\n :size=\"20\"\r\n />\r\n <span class=\"menu-title\">{{\r\n menuSplit.displayMenuItem.value?.meta?.title\r\n }}</span>\r\n </div>\r\n <div class=\"second-menu-list\">\r\n <div\r\n v-for=\"child in menuSplit.displayMenuItem.value?.children || []\"\r\n :key=\"child.path\"\r\n class=\"second-menu-item\"\r\n :class=\"{ active: menuSplit.isMenuItemActive(child.path) }\"\r\n role=\"link\"\r\n :tabindex=\"child.disabled ? -1 : 0\"\r\n :aria-disabled=\"child.disabled || undefined\"\r\n @click=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.enter=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.space.prevent=\"menuSplit.handleSecondMenuClick(child)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"menu-item-label\">{{ child.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </Transition>\r\n\r\n <!-- 右侧主内容区 -->\r\n <div class=\"main-layout\">\r\n <slot name=\"header\" />\r\n\r\n <NLayout>\r\n <NLayoutContent class=\"content-with-header p16px app-content\">\r\n <LayoutRouterView />\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport { useMenuSplit } from \"../../../composables/useMenuSplit\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_MixLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\nconst menuSplit = useMenuSplit({\r\n menus: ctx.menus,\r\n floatingSecondMenu: computed(() => true),\r\n});\r\n\r\n// 图标组件:优先使用消费方提供的,否则用 CSS class 渲染\r\nconst LayoutIcon = useLayoutIcon();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_MixTopLayout\n *\r\n * 顶部混合布局骨架\r\n * 左侧一级菜单 + 顶部二级水平菜单 + 内容区\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域(侧边栏顶部)\r\n * #brand - 顶部导航品牌区\r\n * #top-menu - 二级水平菜单(默认使用 ResponsiveMenu)\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"mix-top-layout-container\">\r\n <!-- 左侧一级菜单 -->\r\n <div\r\n class=\"first-level-sidebar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- Logo -->\r\n <div class=\"logo-container\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </slot>\r\n </div>\r\n\r\n <!-- 一级菜单列表 -->\r\n <div class=\"first-menu-list\">\r\n <div\r\n v-for=\"item in menus\"\r\n :key=\"item.path\"\r\n class=\"first-menu-item\"\r\n :class=\"{\r\n active: menuSplit.activeFirstMenu.value === item.path,\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n :aria-disabled=\"item.disabled || undefined\"\r\n :aria-current=\"\r\n menuSplit.activeFirstMenu.value === item.path ? 'page' : undefined\r\n \"\r\n @click=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.enter=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.space.prevent=\"menuSplit.handleFirstMenuClick(item)\"\r\n >\r\n <div class=\"menu-item-content\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"22\"\r\n />\r\n <span v-else class=\"menu-item-text\">{{\r\n (item.meta?.title || \"\")[0]\r\n }}</span>\r\n </div>\r\n <span class=\"menu-item-label\">{{ item.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 右侧主区域 -->\r\n <div class=\"main-area\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 左侧:品牌 -->\r\n <div class=\"navbar-left\">\r\n <slot name=\"brand\">\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 中间:二级水平菜单 -->\r\n <div class=\"navbar-center\">\r\n <slot name=\"top-menu\">\r\n <ResponsiveMenu\r\n v-if=\"menuSplit.currentSecondMenus.value.length > 0\"\r\n :data=\"menuSplit.currentSecondMenus.value\"\r\n />\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 内容区 -->\r\n <NLayout class=\"content-layout\">\r\n <NLayoutContent class=\"main-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport { useMenuSplit } from \"../../../composables/useMenuSplit\";\r\nimport ResponsiveMenu from \"../../ResponsiveMenu/index.vue\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_MixTopLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\nconst menuSplit = useMenuSplit({\r\n menus: ctx.menus,\r\n floatingSecondMenu: computed(() => false),\r\n});\r\n\r\nconst LayoutIcon = useLayoutIcon();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_MixTopLayout\n *\r\n * 顶部混合布局骨架\r\n * 左侧一级菜单 + 顶部二级水平菜单 + 内容区\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域(侧边栏顶部)\r\n * #brand - 顶部导航品牌区\r\n * #top-menu - 二级水平菜单(默认使用 ResponsiveMenu)\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"mix-top-layout-container\">\r\n <!-- 左侧一级菜单 -->\r\n <div\r\n class=\"first-level-sidebar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- Logo -->\r\n <div class=\"logo-container\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 40\"\r\n :height=\"brand.logoSize || 40\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </slot>\r\n </div>\r\n\r\n <!-- 一级菜单列表 -->\r\n <div class=\"first-menu-list\">\r\n <div\r\n v-for=\"item in menus\"\r\n :key=\"item.path\"\r\n class=\"first-menu-item\"\r\n :class=\"{\r\n active: menuSplit.activeFirstMenu.value === item.path,\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n :aria-disabled=\"item.disabled || undefined\"\r\n :aria-current=\"\r\n menuSplit.activeFirstMenu.value === item.path ? 'page' : undefined\r\n \"\r\n @click=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.enter=\"menuSplit.handleFirstMenuClick(item)\"\r\n @keydown.space.prevent=\"menuSplit.handleFirstMenuClick(item)\"\r\n >\r\n <div class=\"menu-item-content\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"22\"\r\n />\r\n <span v-else class=\"menu-item-text\">{{\r\n (item.meta?.title || \"\")[0]\r\n }}</span>\r\n </div>\r\n <span class=\"menu-item-label\">{{ item.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 右侧主区域 -->\r\n <div class=\"main-area\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 左侧:品牌 -->\r\n <div class=\"navbar-left\">\r\n <slot name=\"brand\">\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 中间:二级水平菜单 -->\r\n <div class=\"navbar-center\">\r\n <slot name=\"top-menu\">\r\n <ResponsiveMenu\r\n v-if=\"menuSplit.currentSecondMenus.value.length > 0\"\r\n :data=\"menuSplit.currentSecondMenus.value\"\r\n />\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 内容区 -->\r\n <NLayout class=\"content-layout\">\r\n <NLayoutContent class=\"main-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport { useMenuSplit } from \"../../../composables/useMenuSplit\";\r\nimport ResponsiveMenu from \"../../ResponsiveMenu/index.vue\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_MixTopLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\nconst menuSplit = useMenuSplit({\r\n menus: ctx.menus,\r\n floatingSecondMenu: computed(() => false),\r\n});\r\n\r\nconst LayoutIcon = useLayoutIcon();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_ReverseHorizontalMixLayout\n *\r\n * 反转混合布局骨架\r\n * 顶部一级菜单 + 右侧二级菜单侧边栏 + 左侧内容区\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域\r\n * #top-menu - 一级水平菜单(默认使用 ResponsiveMenu)\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"reverse-horizontal-mix-layout-container\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 左侧:Logo 和品牌 -->\r\n <div class=\"navbar-left\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-container\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </div>\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 中间:一级水平菜单 -->\r\n <div class=\"navbar-center\">\r\n <slot name=\"top-menu\">\r\n <ResponsiveMenu :data=\"menus\" />\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 主区域:左侧内容 + 右侧菜单 -->\r\n <div class=\"main-area\">\r\n <!-- 左侧:主内容区 -->\r\n <NLayout class=\"content-layout\">\r\n <NLayoutContent class=\"main-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n\r\n <!-- 右侧折叠/展开按钮 - 始终可见 -->\r\n <div\r\n v-if=\"menuSplit.currentSecondMenus.value.length > 0\"\r\n class=\"sidebar-toggle\"\r\n :class=\"[\r\n isDarkMode ? 'dark-theme' : 'light-theme',\r\n { active: !isCollapsed },\r\n ]\"\r\n @click=\"toggleCollapse\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n :aria-expanded=\"!isCollapsed\"\r\n @keydown.enter=\"toggleCollapse\"\r\n @keydown.space.prevent=\"toggleCollapse\"\r\n >\r\n <span\r\n :class=\"[\r\n 'collapse-arrow',\r\n 'toggle-icon',\r\n isCollapsed ? 'collapsed' : 'expanded',\r\n ]\"\r\n >\r\n <span class=\"arrow-line\"></span>\r\n <span class=\"arrow-line\"></span>\r\n </span>\r\n </div>\r\n\r\n <!-- 右侧:二级菜单侧边栏 -->\r\n <div\r\n v-if=\"menuSplit.currentSecondMenus.value.length > 0\"\r\n class=\"right-sidebar-wrapper\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n >\r\n <div\r\n class=\"right-sidebar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 侧边栏标题 -->\r\n <div\r\n class=\"sidebar-header\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <div class=\"header-icon\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"menuSplit.activeFirstMenuItem.value?.meta?.icon\"\r\n :name=\"menuSplit.activeFirstMenuItem.value.meta.icon\"\r\n :size=\"20\"\r\n />\r\n </div>\r\n <span class=\"header-title\">{{\r\n menuSplit.activeFirstMenuItem.value?.meta?.title || \"菜单\"\r\n }}</span>\r\n </div>\r\n\r\n <!-- 二级菜单列表 -->\r\n <div class=\"sidebar-menu-list\">\r\n <template\r\n v-for=\"child in menuSplit.currentSecondMenus.value\"\r\n :key=\"child.path\"\r\n >\r\n <!-- 有子菜单的项 -->\r\n <div\r\n v-if=\"child.children && child.children.length > 0\"\r\n class=\"menu-group\"\r\n >\r\n <div class=\"group-title\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span>{{ child.meta?.title }}</span>\r\n </div>\r\n <div\r\n v-for=\"subChild in child.children\"\r\n :key=\"subChild.path\"\r\n class=\"menu-item sub-item\"\r\n :class=\"{\r\n active: menuSplit.isMenuItemActive(subChild.path),\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"subChild.disabled ? -1 : 0\"\r\n :aria-disabled=\"subChild.disabled || undefined\"\r\n :aria-current=\"\r\n menuSplit.isMenuItemActive(subChild.path)\r\n ? 'page'\r\n : undefined\r\n \"\r\n @click=\"menuSplit.handleSecondMenuClick(subChild)\"\r\n @keydown.enter=\"menuSplit.handleSecondMenuClick(subChild)\"\r\n @keydown.space.prevent=\"\r\n menuSplit.handleSecondMenuClick(subChild)\r\n \"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"subChild.meta?.icon\"\r\n :name=\"subChild.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"item-title\">{{ subChild.meta?.title }}</span>\r\n </div>\r\n </div>\r\n <!-- 没有子菜单的项 -->\r\n <div\r\n v-else\r\n class=\"menu-item\"\r\n :class=\"{\r\n active: menuSplit.isMenuItemActive(child.path),\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"child.disabled ? -1 : 0\"\r\n :aria-disabled=\"child.disabled || undefined\"\r\n :aria-current=\"\r\n menuSplit.isMenuItemActive(child.path) ? 'page' : undefined\r\n \"\r\n @click=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.enter=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.space.prevent=\"menuSplit.handleSecondMenuClick(child)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span class=\"item-title\">{{ child.meta?.title }}</span>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { ref, computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport { useMenuSplit } from \"../../../composables/useMenuSplit\";\r\nimport ResponsiveMenu from \"../../ResponsiveMenu/index.vue\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_ReverseHorizontalMixLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\nconst menuSplit = useMenuSplit({\r\n menus: ctx.menus,\r\n floatingSecondMenu: computed(() => false),\r\n});\r\n\r\n// 右侧边栏折叠状态\r\nconst isCollapsed = ref(false);\r\nconst toggleCollapse = () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n};\r\n\r\nconst LayoutIcon = useLayoutIcon();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_ReverseHorizontalMixLayout\n *\r\n * 反转混合布局骨架\r\n * 顶部一级菜单 + 右侧二级菜单侧边栏 + 左侧内容区\r\n *\r\n * Slots:\r\n * #logo - Logo/品牌区域\r\n * #top-menu - 一级水平菜单(默认使用 ResponsiveMenu)\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"reverse-horizontal-mix-layout-container\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 左侧:Logo 和品牌 -->\r\n <div class=\"navbar-left\">\r\n <slot name=\"logo\">\r\n <div class=\"logo-container\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </div>\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 中间:一级水平菜单 -->\r\n <div class=\"navbar-center\">\r\n <slot name=\"top-menu\">\r\n <ResponsiveMenu :data=\"menus\" />\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 主区域:左侧内容 + 右侧菜单 -->\r\n <div class=\"main-area\">\r\n <!-- 左侧:主内容区 -->\r\n <NLayout class=\"content-layout\">\r\n <NLayoutContent class=\"main-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n\r\n <!-- 右侧折叠/展开按钮 - 始终可见 -->\r\n <div\r\n v-if=\"menuSplit.currentSecondMenus.value.length > 0\"\r\n class=\"sidebar-toggle\"\r\n :class=\"[\r\n isDarkMode ? 'dark-theme' : 'light-theme',\r\n { active: !isCollapsed },\r\n ]\"\r\n @click=\"toggleCollapse\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n :aria-expanded=\"!isCollapsed\"\r\n @keydown.enter=\"toggleCollapse\"\r\n @keydown.space.prevent=\"toggleCollapse\"\r\n >\r\n <span\r\n :class=\"[\r\n 'collapse-arrow',\r\n 'toggle-icon',\r\n isCollapsed ? 'collapsed' : 'expanded',\r\n ]\"\r\n >\r\n <span class=\"arrow-line\"></span>\r\n <span class=\"arrow-line\"></span>\r\n </span>\r\n </div>\r\n\r\n <!-- 右侧:二级菜单侧边栏 -->\r\n <div\r\n v-if=\"menuSplit.currentSecondMenus.value.length > 0\"\r\n class=\"right-sidebar-wrapper\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n >\r\n <div\r\n class=\"right-sidebar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 侧边栏标题 -->\r\n <div\r\n class=\"sidebar-header\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <div class=\"header-icon\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"menuSplit.activeFirstMenuItem.value?.meta?.icon\"\r\n :name=\"menuSplit.activeFirstMenuItem.value.meta.icon\"\r\n :size=\"20\"\r\n />\r\n </div>\r\n <span class=\"header-title\">{{\r\n menuSplit.activeFirstMenuItem.value?.meta?.title || \"菜单\"\r\n }}</span>\r\n </div>\r\n\r\n <!-- 二级菜单列表 -->\r\n <div class=\"sidebar-menu-list\">\r\n <template\r\n v-for=\"child in menuSplit.currentSecondMenus.value\"\r\n :key=\"child.path\"\r\n >\r\n <!-- 有子菜单的项 -->\r\n <div\r\n v-if=\"child.children && child.children.length > 0\"\r\n class=\"menu-group\"\r\n >\r\n <div class=\"group-title\">\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span>{{ child.meta?.title }}</span>\r\n </div>\r\n <div\r\n v-for=\"subChild in child.children\"\r\n :key=\"subChild.path\"\r\n class=\"menu-item sub-item\"\r\n :class=\"{\r\n active: menuSplit.isMenuItemActive(subChild.path),\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"subChild.disabled ? -1 : 0\"\r\n :aria-disabled=\"subChild.disabled || undefined\"\r\n :aria-current=\"\r\n menuSplit.isMenuItemActive(subChild.path)\r\n ? 'page'\r\n : undefined\r\n \"\r\n @click=\"menuSplit.handleSecondMenuClick(subChild)\"\r\n @keydown.enter=\"menuSplit.handleSecondMenuClick(subChild)\"\r\n @keydown.space.prevent=\"\r\n menuSplit.handleSecondMenuClick(subChild)\r\n \"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"subChild.meta?.icon\"\r\n :name=\"subChild.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"item-title\">{{ subChild.meta?.title }}</span>\r\n </div>\r\n </div>\r\n <!-- 没有子菜单的项 -->\r\n <div\r\n v-else\r\n class=\"menu-item\"\r\n :class=\"{\r\n active: menuSplit.isMenuItemActive(child.path),\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"child.disabled ? -1 : 0\"\r\n :aria-disabled=\"child.disabled || undefined\"\r\n :aria-current=\"\r\n menuSplit.isMenuItemActive(child.path) ? 'page' : undefined\r\n \"\r\n @click=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.enter=\"menuSplit.handleSecondMenuClick(child)\"\r\n @keydown.space.prevent=\"menuSplit.handleSecondMenuClick(child)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span class=\"item-title\">{{ child.meta?.title }}</span>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { ref, computed } from \"vue\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport { useMenuSplit } from \"../../../composables/useMenuSplit\";\r\nimport ResponsiveMenu from \"../../ResponsiveMenu/index.vue\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_ReverseHorizontalMixLayout\" });\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\nconst menuSplit = useMenuSplit({\r\n menus: ctx.menus,\r\n floatingSecondMenu: computed(() => false),\r\n});\r\n\r\n// 右侧边栏折叠状态\r\nconst isCollapsed = ref(false);\r\nconst toggleCollapse = () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n};\r\n\r\nconst LayoutIcon = useLayoutIcon();\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_CardLayout\n *\r\n * 卡片式布局骨架\r\n * 顶部导航 + hover 触发抽屉式菜单 + 内容区\r\n *\r\n * Slots:\r\n * #menu-trigger - 菜单触发区域(hover 弹出抽屉)\r\n * #logo - Logo/品牌区域\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #drawer-menu - 抽屉式菜单内容\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"card-layout-container\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <div class=\"navbar-left\">\r\n <!-- 悬停触发区域 -->\r\n <div\r\n class=\"hover-trigger-area\"\r\n @mouseenter=\"cancelHideTimer\"\r\n @mouseleave=\"hideDrawerMenu\"\r\n >\r\n <slot name=\"menu-trigger\">\r\n <div class=\"menu-indicator\">\r\n <!-- 纯 CSS 三横线菜单图标 -->\r\n <span class=\"hamburger-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <slot name=\"logo\">\r\n <div class=\"logo-container\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </div>\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 抽屉式菜单 -->\r\n <div\r\n class=\"drawer-menu\"\r\n :class=\"[\r\n isDarkMode ? 'dark-theme' : 'light-theme',\r\n { visible: showDrawerMenu },\r\n ]\"\r\n @mouseenter=\"cancelHideTimer\"\r\n @mouseleave=\"hideDrawerMenu\"\r\n >\r\n <slot name=\"drawer-menu\">\r\n <!-- 菜单头部 -->\r\n <div class=\"drawer-header\">\r\n <div class=\"drawer-title\">\r\n <!-- 纯 CSS 网格图标 -->\r\n <span class=\"grid-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n <span>功能导航</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 菜单内容 - 阿里云风格铺开布局 -->\r\n <div class=\"drawer-content\">\r\n <div class=\"menu-grid\">\r\n <div\r\n v-for=\"category in menus\"\r\n :key=\"category.path\"\r\n class=\"menu-category\"\r\n >\r\n <!-- 分类标题 -->\r\n <div\r\n class=\"category-header\"\r\n role=\"link\"\r\n :tabindex=\"category.disabled ? -1 : 0\"\r\n :aria-disabled=\"category.disabled || undefined\"\r\n @click=\"navigateToPage(category)\"\r\n @keydown.enter=\"navigateToPage(category)\"\r\n @keydown.space.prevent=\"navigateToPage(category)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"category.meta?.icon\"\r\n :name=\"category.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span>{{ category.meta?.title }}</span>\r\n </div>\r\n\r\n <!-- 分类下的菜单项 -->\r\n <div\r\n class=\"category-items\"\r\n v-if=\"category.children && category.children.length > 0\"\r\n >\r\n <div\r\n v-for=\"item in category.children\"\r\n :key=\"item.path\"\r\n class=\"menu-item\"\r\n role=\"link\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n :aria-disabled=\"item.disabled || undefined\"\r\n @click=\"navigateToPage(item)\"\r\n @keydown.enter=\"navigateToPage(item)\"\r\n @keydown.space.prevent=\"navigateToPage(item)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"item-title\">{{ item.meta?.title }}</span>\r\n </div>\r\n\r\n <!-- 3级菜单项 -->\r\n <template\r\n v-for=\"item in category.children\"\r\n :key=\"'sub-' + item.path\"\r\n >\r\n <div\r\n v-if=\"item.children && item.children.length > 0\"\r\n class=\"submenu-items\"\r\n >\r\n <div class=\"submenu-title\">{{ item.meta?.title }}</div>\r\n <div\r\n v-for=\"subItem in item.children\"\r\n :key=\"subItem.path\"\r\n class=\"menu-item submenu-item\"\r\n role=\"link\"\r\n :tabindex=\"subItem.disabled ? -1 : 0\"\r\n :aria-disabled=\"subItem.disabled || undefined\"\r\n @click=\"navigateToPage(subItem)\"\r\n @keydown.enter=\"navigateToPage(subItem)\"\r\n @keydown.space.prevent=\"navigateToPage(subItem)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"subItem.meta?.icon\"\r\n :name=\"subItem.meta.icon\"\r\n :size=\"14\"\r\n />\r\n <span class=\"item-title\">{{ subItem.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 主内容区域 -->\r\n <div class=\"main-content-area\">\r\n <NLayout class=\"content-layout\">\r\n <NLayoutContent class=\"main-content p16px app-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { ref, computed, onUnmounted } from \"vue\";\r\nimport { useRouter } from \"vue-router\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport type { MenuOptions } from \"../../../types/menu\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_CardLayout\" });\n\r\nconst ctx = useLayoutContext();\r\nconst router = useRouter();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\n// 抽屉菜单状态\r\nconst showDrawerMenu = ref(false);\r\nconst hideTimer = ref<ReturnType<typeof setTimeout> | null>(null);\r\n\r\nconst hideDrawerMenu = () => {\r\n if (hideTimer.value) clearTimeout(hideTimer.value);\r\n hideTimer.value = setTimeout(() => {\r\n showDrawerMenu.value = false;\r\n }, 300);\r\n};\r\n\r\nconst cancelHideTimer = () => {\r\n if (hideTimer.value) {\r\n clearTimeout(hideTimer.value);\r\n hideTimer.value = null;\r\n }\r\n showDrawerMenu.value = true;\r\n};\r\n\r\nconst navigateToPage = (item: MenuOptions) => {\r\n if (!item.disabled && item.path) {\r\n void router.push(item.path);\r\n showDrawerMenu.value = false;\r\n }\r\n};\r\n\r\nconst LayoutIcon = useLayoutIcon();\r\n\r\nonUnmounted(() => {\r\n if (hideTimer.value) clearTimeout(hideTimer.value);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n/* 纯 CSS 网格图标 (2x2) */\r\n.grid-icon {\r\n display: inline-grid;\r\n grid-template-columns: repeat(2, 1fr);\r\n gap: 2.5px;\r\n width: 18px;\r\n height: 18px;\r\n padding: 1px;\r\n}\r\n\r\n.grid-icon span {\r\n background-color: currentColor;\r\n border-radius: 2px;\r\n opacity: 0.85;\r\n}\r\n\r\n/* 纯 CSS 三横线汉堡菜单图标 */\r\n.hamburger-icon {\r\n display: inline-flex;\r\n flex-direction: column;\r\n justify-content: space-between;\r\n width: 20px;\r\n height: 16px;\r\n padding: 2px 0;\r\n}\r\n\r\n.hamburger-icon span {\r\n display: block;\r\n width: 100%;\r\n height: 2px;\r\n background-color: currentColor;\r\n border-radius: 1px;\r\n opacity: 0.85;\r\n transition: all 0.2s ease;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - C_CardLayout\n *\r\n * 卡片式布局骨架\r\n * 顶部导航 + hover 触发抽屉式菜单 + 内容区\r\n *\r\n * Slots:\r\n * #menu-trigger - 菜单触发区域(hover 弹出抽屉)\r\n * #logo - Logo/品牌区域\r\n * #header-extra - 头部右侧操作区\r\n * #tags-view - 标签页区域\r\n * #drawer-menu - 抽屉式菜单内容\r\n * #footer - 页脚区域\r\n -->\r\n<template>\r\n <div class=\"card-layout-container\">\r\n <!-- 顶部导航栏 -->\r\n <div\r\n class=\"top-navbar\"\r\n :class=\"[isDarkMode ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <div class=\"navbar-left\">\r\n <!-- 悬停触发区域 -->\r\n <div\r\n class=\"hover-trigger-area\"\r\n @mouseenter=\"cancelHideTimer\"\r\n @mouseleave=\"hideDrawerMenu\"\r\n >\r\n <slot name=\"menu-trigger\">\r\n <div class=\"menu-indicator\">\r\n <!-- 纯 CSS 三横线菜单图标 -->\r\n <span class=\"hamburger-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <slot name=\"logo\">\r\n <div class=\"logo-container\">\r\n <div class=\"logo-glow\"></div>\r\n <video\r\n v-if=\"brand.logoType === 'video' && brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"logo-video\"\r\n >\r\n 您的浏览器不支持 video 标签。\r\n </video>\r\n <img\r\n v-else-if=\"brand.logoSrc\"\r\n :src=\"brand.logoSrc\"\r\n :width=\"brand.logoSize || 36\"\r\n :height=\"brand.logoSize || 36\"\r\n class=\"logo-video\"\r\n :alt=\"brand.name || 'Logo'\"\r\n />\r\n </div>\r\n <div class=\"brand-name\">\r\n <span class=\"brand-title\">{{ brand.name }}</span>\r\n <span class=\"brand-subtitle\">{{ brand.subtitle }}</span>\r\n </div>\r\n <div class=\"navbar-divider\"></div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 右侧:操作区 -->\r\n <slot name=\"header-extra\" />\r\n </div>\r\n\r\n <!-- 标签页区域 -->\r\n <div\r\n v-if=\"showTagsView\"\r\n class=\"tags-view-container\"\r\n :style=\"{ height: `${tagsViewHeight}px` }\"\r\n >\r\n <slot name=\"tags-view\" />\r\n </div>\r\n\r\n <!-- 抽屉式菜单 -->\r\n <div\r\n class=\"drawer-menu\"\r\n :class=\"[\r\n isDarkMode ? 'dark-theme' : 'light-theme',\r\n { visible: showDrawerMenu },\r\n ]\"\r\n @mouseenter=\"cancelHideTimer\"\r\n @mouseleave=\"hideDrawerMenu\"\r\n >\r\n <slot name=\"drawer-menu\">\r\n <!-- 菜单头部 -->\r\n <div class=\"drawer-header\">\r\n <div class=\"drawer-title\">\r\n <!-- 纯 CSS 网格图标 -->\r\n <span class=\"grid-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n <span>功能导航</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 菜单内容 - 阿里云风格铺开布局 -->\r\n <div class=\"drawer-content\">\r\n <div class=\"menu-grid\">\r\n <div\r\n v-for=\"category in menus\"\r\n :key=\"category.path\"\r\n class=\"menu-category\"\r\n >\r\n <!-- 分类标题 -->\r\n <div\r\n class=\"category-header\"\r\n role=\"link\"\r\n :tabindex=\"category.disabled ? -1 : 0\"\r\n :aria-disabled=\"category.disabled || undefined\"\r\n @click=\"navigateToPage(category)\"\r\n @keydown.enter=\"navigateToPage(category)\"\r\n @keydown.space.prevent=\"navigateToPage(category)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"category.meta?.icon\"\r\n :name=\"category.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span>{{ category.meta?.title }}</span>\r\n </div>\r\n\r\n <!-- 分类下的菜单项 -->\r\n <div\r\n class=\"category-items\"\r\n v-if=\"category.children && category.children.length > 0\"\r\n >\r\n <div\r\n v-for=\"item in category.children\"\r\n :key=\"item.path\"\r\n class=\"menu-item\"\r\n role=\"link\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n :aria-disabled=\"item.disabled || undefined\"\r\n @click=\"navigateToPage(item)\"\r\n @keydown.enter=\"navigateToPage(item)\"\r\n @keydown.space.prevent=\"navigateToPage(item)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"item-title\">{{ item.meta?.title }}</span>\r\n </div>\r\n\r\n <!-- 3级菜单项 -->\r\n <template\r\n v-for=\"item in category.children\"\r\n :key=\"'sub-' + item.path\"\r\n >\r\n <div\r\n v-if=\"item.children && item.children.length > 0\"\r\n class=\"submenu-items\"\r\n >\r\n <div class=\"submenu-title\">{{ item.meta?.title }}</div>\r\n <div\r\n v-for=\"subItem in item.children\"\r\n :key=\"subItem.path\"\r\n class=\"menu-item submenu-item\"\r\n role=\"link\"\r\n :tabindex=\"subItem.disabled ? -1 : 0\"\r\n :aria-disabled=\"subItem.disabled || undefined\"\r\n @click=\"navigateToPage(subItem)\"\r\n @keydown.enter=\"navigateToPage(subItem)\"\r\n @keydown.space.prevent=\"navigateToPage(subItem)\"\r\n >\r\n <component\r\n :is=\"LayoutIcon\"\r\n v-if=\"subItem.meta?.icon\"\r\n :name=\"subItem.meta.icon\"\r\n :size=\"14\"\r\n />\r\n <span class=\"item-title\">{{ subItem.meta?.title }}</span>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 主内容区域 -->\r\n <div class=\"main-content-area\">\r\n <NLayout class=\"content-layout\">\r\n <NLayoutContent class=\"main-content p16px app-content\">\r\n <div class=\"page-content\">\r\n <LayoutRouterView />\r\n </div>\r\n </NLayoutContent>\r\n\r\n <template v-if=\"showFooter\">\r\n <slot name=\"footer\" />\r\n </template>\r\n </NLayout>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport \"./index.scss\";\r\nimport { ref, computed, onUnmounted } from \"vue\";\r\nimport { useRouter } from \"vue-router\";\r\nimport { NLayout, NLayoutContent } from \"naive-ui\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../../composables/useLayoutContext\";\r\nimport type { MenuOptions } from \"../../../types/menu\";\r\nimport LayoutRouterView from \"../../LayoutRouterView/index.vue\";\r\nimport { useLayoutIcon } from \"../../../composables/useLayoutIcon\";\r\n\r\ndefineOptions({ name: \"C_CardLayout\" });\n\r\nconst ctx = useLayoutContext();\r\nconst router = useRouter();\r\n\r\nconst isDarkMode = ctx.isDark;\r\nconst menus = computed(() => ctx.menus.value);\r\nconst showTagsView = computed(() => ctx.showTagsView.value);\r\nconst tagsViewHeight = computed(() => ctx.tagsViewHeight.value);\r\nconst showFooter = computed(() => ctx.showFooter.value);\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n\r\n// 抽屉菜单状态\r\nconst showDrawerMenu = ref(false);\r\nconst hideTimer = ref<ReturnType<typeof setTimeout> | null>(null);\r\n\r\nconst hideDrawerMenu = () => {\r\n if (hideTimer.value) clearTimeout(hideTimer.value);\r\n hideTimer.value = setTimeout(() => {\r\n showDrawerMenu.value = false;\r\n }, 300);\r\n};\r\n\r\nconst cancelHideTimer = () => {\r\n if (hideTimer.value) {\r\n clearTimeout(hideTimer.value);\r\n hideTimer.value = null;\r\n }\r\n showDrawerMenu.value = true;\r\n};\r\n\r\nconst navigateToPage = (item: MenuOptions) => {\r\n if (!item.disabled && item.path) {\r\n void router.push(item.path);\r\n showDrawerMenu.value = false;\r\n }\r\n};\r\n\r\nconst LayoutIcon = useLayoutIcon();\r\n\r\nonUnmounted(() => {\r\n if (hideTimer.value) clearTimeout(hideTimer.value);\r\n});\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n/* 纯 CSS 网格图标 (2x2) */\r\n.grid-icon {\r\n display: inline-grid;\r\n grid-template-columns: repeat(2, 1fr);\r\n gap: 2.5px;\r\n width: 18px;\r\n height: 18px;\r\n padding: 1px;\r\n}\r\n\r\n.grid-icon span {\r\n background-color: currentColor;\r\n border-radius: 2px;\r\n opacity: 0.85;\r\n}\r\n\r\n/* 纯 CSS 三横线汉堡菜单图标 */\r\n.hamburger-icon {\r\n display: inline-flex;\r\n flex-direction: column;\r\n justify-content: space-between;\r\n width: 20px;\r\n height: 16px;\r\n padding: 2px 0;\r\n}\r\n\r\n.hamburger-icon span {\r\n display: block;\r\n width: 100%;\r\n height: 2px;\r\n background-color: currentColor;\r\n border-radius: 1px;\r\n opacity: 0.85;\r\n transition: all 0.2s ease;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - C_LayoutContainer\r\n *\r\n * 智能布局容器\r\n * 根据 layoutMode 自动切换 6 种布局骨架,消费方仅需提供业务组件\r\n *\r\n * Slots:\r\n * #logo - 品牌 Logo 区域(各骨架有内置默认实现)\r\n * #menu - Side 布局的垂直菜单(需消费方提供)\r\n * #header - Side/Mix 布局的完整头部(需消费方提供)\r\n * #header-extra - Top/MixTop/Reverse/Card 头部右侧操作区\r\n * #tags-view - 标签页区域(需消费方提供)\r\n * #footer - 页脚区域(需消费方提供)\r\n * #top-menu - Top/MixTop/Reverse 水平菜单(骨架有默认)\r\n * #brand - MixTop 顶部导航品牌区(骨架有默认)\r\n * #menu-trigger - Card 菜单触发区域(骨架有默认)\r\n * #drawer-menu - Card 抽屉式菜单(骨架有默认)\r\n -->\r\n<template>\r\n <div\r\n data-ra-layout\r\n :class=\"['layout-container', isDark ? 'dark-mode' : 'light-mode']\"\r\n >\r\n <!-- ═══════ Side 左侧菜单布局 ═══════ -->\r\n <C_SideLayout\n v-if=\"layoutMode === 'side'\"\n v-model:collapsed=\"sideCollapsed\"\n >\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template #menu>\r\n <slot name=\"menu\" :collapsed=\"sideCollapsed\" />\r\n </template>\r\n <template #header><slot name=\"header\" /></template>\r\n <template #footer><slot name=\"footer\" /></template>\r\n </C_SideLayout>\n\r\n <!-- ═══════ Top 顶部菜单布局 ═══════ -->\r\n <C_TopLayout v-else-if=\"layoutMode === 'top'\">\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots['top-menu']\" #menu\r\n ><slot name=\"top-menu\"\r\n /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_TopLayout>\n\r\n <!-- ═══════ Mix 混合布局 ═══════ -->\r\n <C_MixLayout v-else-if=\"layoutMode === 'mix'\">\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template #header><slot name=\"header\" /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_MixLayout>\n\r\n <!-- ═══════ MixTop 顶部混合布局 ═══════ -->\r\n <C_MixTopLayout v-else-if=\"layoutMode === 'mix-top'\">\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots.brand\" #brand><slot name=\"brand\" /></template>\r\n <template v-if=\"$slots['top-menu']\" #top-menu\r\n ><slot name=\"top-menu\"\r\n /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_MixTopLayout>\n\r\n <!-- ═══════ ReverseHorizontalMix 反转混合布局 ═══════ -->\r\n <C_ReverseHorizontalMixLayout\n v-else-if=\"layoutMode === 'reverse-horizontal-mix'\"\r\n >\r\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots['top-menu']\" #top-menu\r\n ><slot name=\"top-menu\"\r\n /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_ReverseHorizontalMixLayout>\n\r\n <!-- ═══════ C_CardLayout 卡片布局 ═══════ -->\n <C_CardLayout v-else-if=\"layoutMode === 'card-layout'\">\n <template v-if=\"$slots['menu-trigger']\" #menu-trigger\r\n ><slot name=\"menu-trigger\"\r\n /></template>\r\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots['drawer-menu']\" #drawer-menu\r\n ><slot name=\"drawer-menu\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_CardLayout>\n\r\n <!-- ═══════ Fallback ═══════ -->\r\n <div v-else class=\"layout-coming-soon\">\r\n <div class=\"coming-soon-content\">\r\n <div class=\"coming-soon-icon\">🚧</div>\r\n <div class=\"coming-soon-title\">布局开发中</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, provide } from \"vue\";\r\nimport {\r\n MENU_COLLAPSE_KEY,\r\n useLayoutContext,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\n// 骨架布局全局样式\r\nimport \"../../styles/layouts.scss\";\r\n\r\n// 骨架组件\r\nimport C_SideLayout from \"../layouts/SideLayout/index.vue\";\nimport C_TopLayout from \"../layouts/TopLayout/index.vue\";\nimport C_MixLayout from \"../layouts/MixLayout/index.vue\";\nimport C_MixTopLayout from \"../layouts/MixTopLayout/index.vue\";\nimport C_ReverseHorizontalMixLayout from \"../layouts/ReverseHorizontalMixLayout/index.vue\";\nimport C_CardLayout from \"../layouts/CardLayout/index.vue\";\n\r\ndefineOptions({ name: \"C_LayoutContainer\" });\r\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst layoutMode = ctx.layoutMode;\r\nconst isDark = ctx.isDark;\r\n\r\n// 上下文提供 collapsed 时与宿主共享;否则保留内部状态以兼容旧接入。\r\nconst internalCollapsed = ref(false);\r\nconst sideCollapsed = computed({\r\n get: () => ctx.collapsed?.value ?? internalCollapsed.value,\r\n set: (value: boolean) => {\r\n if (ctx.collapsed) ctx.collapsed.value = value;\r\n else internalCollapsed.value = value;\r\n },\r\n});\r\n\r\n// 提供折叠状态给子组件(如 C_Header 的汉堡按钮)\r\nconst collapseHandlers = {\r\n isCollapsed: sideCollapsed,\r\n handleCollapsedChange: (collapsed: boolean) => {\r\n sideCollapsed.value = collapsed;\r\n },\r\n};\r\nprovide(MENU_COLLAPSE_KEY, collapseHandlers);\r\n// 3.x 兼容层:旧消费方仍可使用字符串 key,计划在 4.0 移除。\r\nprovide(\"menuCollapse\", collapseHandlers);\r\n</script>\r\n","<!--\r\n * @robot-admin/layout - C_LayoutContainer\r\n *\r\n * 智能布局容器\r\n * 根据 layoutMode 自动切换 6 种布局骨架,消费方仅需提供业务组件\r\n *\r\n * Slots:\r\n * #logo - 品牌 Logo 区域(各骨架有内置默认实现)\r\n * #menu - Side 布局的垂直菜单(需消费方提供)\r\n * #header - Side/Mix 布局的完整头部(需消费方提供)\r\n * #header-extra - Top/MixTop/Reverse/Card 头部右侧操作区\r\n * #tags-view - 标签页区域(需消费方提供)\r\n * #footer - 页脚区域(需消费方提供)\r\n * #top-menu - Top/MixTop/Reverse 水平菜单(骨架有默认)\r\n * #brand - MixTop 顶部导航品牌区(骨架有默认)\r\n * #menu-trigger - Card 菜单触发区域(骨架有默认)\r\n * #drawer-menu - Card 抽屉式菜单(骨架有默认)\r\n -->\r\n<template>\r\n <div\r\n data-ra-layout\r\n :class=\"['layout-container', isDark ? 'dark-mode' : 'light-mode']\"\r\n >\r\n <!-- ═══════ Side 左侧菜单布局 ═══════ -->\r\n <C_SideLayout\n v-if=\"layoutMode === 'side'\"\n v-model:collapsed=\"sideCollapsed\"\n >\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template #menu>\r\n <slot name=\"menu\" :collapsed=\"sideCollapsed\" />\r\n </template>\r\n <template #header><slot name=\"header\" /></template>\r\n <template #footer><slot name=\"footer\" /></template>\r\n </C_SideLayout>\n\r\n <!-- ═══════ Top 顶部菜单布局 ═══════ -->\r\n <C_TopLayout v-else-if=\"layoutMode === 'top'\">\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots['top-menu']\" #menu\r\n ><slot name=\"top-menu\"\r\n /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_TopLayout>\n\r\n <!-- ═══════ Mix 混合布局 ═══════ -->\r\n <C_MixLayout v-else-if=\"layoutMode === 'mix'\">\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template #header><slot name=\"header\" /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_MixLayout>\n\r\n <!-- ═══════ MixTop 顶部混合布局 ═══════ -->\r\n <C_MixTopLayout v-else-if=\"layoutMode === 'mix-top'\">\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots.brand\" #brand><slot name=\"brand\" /></template>\r\n <template v-if=\"$slots['top-menu']\" #top-menu\r\n ><slot name=\"top-menu\"\r\n /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_MixTopLayout>\n\r\n <!-- ═══════ ReverseHorizontalMix 反转混合布局 ═══════ -->\r\n <C_ReverseHorizontalMixLayout\n v-else-if=\"layoutMode === 'reverse-horizontal-mix'\"\r\n >\r\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots['top-menu']\" #top-menu\r\n ><slot name=\"top-menu\"\r\n /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_ReverseHorizontalMixLayout>\n\r\n <!-- ═══════ C_CardLayout 卡片布局 ═══════ -->\n <C_CardLayout v-else-if=\"layoutMode === 'card-layout'\">\n <template v-if=\"$slots['menu-trigger']\" #menu-trigger\r\n ><slot name=\"menu-trigger\"\r\n /></template>\r\n <template v-if=\"$slots.logo\" #logo><slot name=\"logo\" /></template>\r\n <template v-if=\"$slots['header-extra']\" #header-extra\r\n ><slot name=\"header-extra\"\r\n /></template>\r\n <template v-if=\"$slots['tags-view']\" #tags-view\r\n ><slot name=\"tags-view\"\r\n /></template>\r\n <template v-if=\"$slots['drawer-menu']\" #drawer-menu\r\n ><slot name=\"drawer-menu\"\r\n /></template>\r\n <template v-if=\"$slots.footer\" #footer><slot name=\"footer\" /></template>\r\n </C_CardLayout>\n\r\n <!-- ═══════ Fallback ═══════ -->\r\n <div v-else class=\"layout-coming-soon\">\r\n <div class=\"coming-soon-content\">\r\n <div class=\"coming-soon-icon\">🚧</div>\r\n <div class=\"coming-soon-title\">布局开发中</div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, provide } from \"vue\";\r\nimport {\r\n MENU_COLLAPSE_KEY,\r\n useLayoutContext,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\n// 骨架布局全局样式\r\nimport \"../../styles/layouts.scss\";\r\n\r\n// 骨架组件\r\nimport C_SideLayout from \"../layouts/SideLayout/index.vue\";\nimport C_TopLayout from \"../layouts/TopLayout/index.vue\";\nimport C_MixLayout from \"../layouts/MixLayout/index.vue\";\nimport C_MixTopLayout from \"../layouts/MixTopLayout/index.vue\";\nimport C_ReverseHorizontalMixLayout from \"../layouts/ReverseHorizontalMixLayout/index.vue\";\nimport C_CardLayout from \"../layouts/CardLayout/index.vue\";\n\r\ndefineOptions({ name: \"C_LayoutContainer\" });\r\n\r\nconst ctx = useLayoutContext();\r\n\r\nconst layoutMode = ctx.layoutMode;\r\nconst isDark = ctx.isDark;\r\n\r\n// 上下文提供 collapsed 时与宿主共享;否则保留内部状态以兼容旧接入。\r\nconst internalCollapsed = ref(false);\r\nconst sideCollapsed = computed({\r\n get: () => ctx.collapsed?.value ?? internalCollapsed.value,\r\n set: (value: boolean) => {\r\n if (ctx.collapsed) ctx.collapsed.value = value;\r\n else internalCollapsed.value = value;\r\n },\r\n});\r\n\r\n// 提供折叠状态给子组件(如 C_Header 的汉堡按钮)\r\nconst collapseHandlers = {\r\n isCollapsed: sideCollapsed,\r\n handleCollapsedChange: (collapsed: boolean) => {\r\n sideCollapsed.value = collapsed;\r\n },\r\n};\r\nprovide(MENU_COLLAPSE_KEY, collapseHandlers);\r\n// 3.x 兼容层:旧消费方仍可使用字符串 key,计划在 4.0 移除。\r\nprovide(\"menuCollapse\", collapseHandlers);\r\n</script>\r\n","/**\n * SettingsDrawer - 常量数据\n */\n\nimport { THEME_PRESETS, COLOR_SWATCHES } from \"../../constants\";\nimport type { LayoutMode, ThemePreset } from \"../../types\";\n\n// 重新导出(内部使用)\nexport { COLOR_SWATCHES, THEME_PRESETS };\nexport type { ThemePreset };\n\n// 布局模式选项 - 完整的 6 种布局(含 SVG 图标,仅 UI 内部使用)\nexport const LAYOUT_MODE_OPTIONS = [\n {\n label: \"左侧菜单(默认)\",\n value: \"side\",\n disabled: false,\n svg: `\n <rect x=\"0\" y=\"0\" width=\"16\" height=\"48\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.9\"/>\n <rect x=\"18\" y=\"0\" width=\"38\" height=\"10\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.7\"/>\n <rect x=\"18\" y=\"12\" width=\"38\" height=\"34\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.4\"/>\n `,\n },\n {\n label: \"顶部菜单(清爽)\",\n value: \"top\",\n disabled: false,\n svg: `\n <rect x=\"0\" y=\"0\" width=\"56\" height=\"10\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.9\"/>\n <rect x=\"0\" y=\"12\" width=\"56\" height=\"8\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.7\"/>\n <rect x=\"0\" y=\"22\" width=\"56\" height=\"24\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.4\"/>\n `,\n },\n {\n label: \"左侧混合(灵巧)\",\n value: \"mix\",\n disabled: false,\n svg: `\n <rect x=\"0\" y=\"0\" width=\"8\" height=\"48\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.9\"/>\n <rect x=\"10\" y=\"0\" width=\"14\" height=\"48\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.7\"/>\n <rect x=\"26\" y=\"0\" width=\"30\" height=\"10\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.6\"/>\n <rect x=\"26\" y=\"12\" width=\"30\" height=\"34\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.4\"/>\n `,\n },\n {\n label: \"顶部混合(侧优)\",\n value: \"mix-top\",\n disabled: false,\n svg: `\n <rect x=\"0\" y=\"0\" width=\"8\" height=\"48\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.9\"/>\n <rect x=\"10\" y=\"0\" width=\"46\" height=\"10\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.7\"/>\n <rect x=\"10\" y=\"12\" width=\"46\" height=\"34\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.4\"/>\n `,\n },\n {\n label: \"反转混合(另类)\",\n value: \"reverse-horizontal-mix\",\n disabled: false,\n svg: `\n <rect x=\"0\" y=\"0\" width=\"56\" height=\"10\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.9\"/>\n <rect x=\"44\" y=\"12\" width=\"12\" height=\"34\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.7\"/>\n <rect x=\"0\" y=\"12\" width=\"42\" height=\"34\" rx=\"1\" fill=\"currentColor\" fill-opacity=\"0.4\"/>\n `,\n },\n {\n label: \"卡片网格(新颖)\",\n value: \"card-layout\",\n disabled: false,\n svg: `\n <rect x=\"0\" y=\"0\" width=\"24\" height=\"20\" rx=\"2\" fill=\"currentColor\" fill-opacity=\"0.9\"/>\n <rect x=\"32\" y=\"0\" width=\"24\" height=\"20\" rx=\"2\" fill=\"currentColor\" fill-opacity=\"0.7\"/>\n <rect x=\"0\" y=\"24\" width=\"24\" height=\"20\" rx=\"2\" fill=\"currentColor\" fill-opacity=\"0.6\"/>\n <rect x=\"32\" y=\"24\" width=\"24\" height=\"20\" rx=\"2\" fill=\"currentColor\" fill-opacity=\"0.4\"/>\n `,\n },\n] satisfies Array<{\n label: string;\n value: LayoutMode;\n disabled: boolean;\n svg: string;\n}>;\n","<!--\r\n * @robot-admin/layout - SettingsDrawer\r\n *\r\n * 布局配置抽屉\r\n * 包含外观/布局/功能三大模块,支持主题预设、布局切换、配置导入导出等\r\n -->\r\n<template>\r\n <NDrawer\r\n v-model:show=\"visible\"\r\n :width=\"width\"\r\n placement=\"right\"\r\n :trap-focus=\"true\"\r\n :block-scroll=\"true\"\r\n >\r\n <NDrawerContent title=\"⚙️ 布局配置\" closable>\r\n <NTabs v-model:value=\"activeTab\" animated class=\"settings-tabs\">\r\n <!-- 外观 Tab -->\r\n <NTabPane name=\"appearance\" tab=\"🎨 外观\">\r\n <slot name=\"appearance-prepend\" :settings=\"settingsStore\" />\r\n <!-- 预设方案网格 -->\r\n <div class=\"settings-section\">\r\n <div class=\"preset-grid\">\r\n <div\r\n v-for=\"preset in THEME_PRESETS\"\r\n :key=\"preset.name\"\r\n class=\"preset-card\"\r\n :class=\"{ active: isCurrentPreset(preset) }\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n :aria-pressed=\"isCurrentPreset(preset)\"\r\n @click=\"handleApplyPreset(preset)\"\r\n @keydown.enter=\"handleApplyPreset(preset)\"\r\n @keydown.space.prevent=\"handleApplyPreset(preset)\"\r\n >\r\n <div class=\"preset-icon\">{{ preset.icon }}</div>\r\n <div class=\"preset-name\">{{ preset.name }}</div>\r\n <div class=\"preset-color\">\r\n <span\r\n class=\"color-dot\"\r\n :style=\"{ backgroundColor: preset.primaryColor }\"\r\n ></span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主题模式 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">主题模式</div>\r\n <NRadioGroup\r\n :value=\"settingsStore.themeMode\"\r\n class=\"mode-group\"\r\n @update:value=\"handleThemeModeChange\"\r\n >\r\n <NRadioButton value=\"light\">\r\n <span class=\"i-mdi:white-balance-sunny mr-1\"></span>\r\n 浅色\r\n </NRadioButton>\r\n <NRadioButton value=\"dark\">\r\n <span class=\"i-mdi:moon-waning-crescent mr-1\"></span>\r\n 深色\r\n </NRadioButton>\r\n <NRadioButton value=\"system\">\r\n <span class=\"i-mdi:theme-light-dark mr-1\"></span>\r\n 自动\r\n </NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 主题色 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">主题色</div>\r\n <div class=\"color-picker-wrapper\">\r\n <NColorPicker\r\n v-model:value=\"settingsStore.primaryColor\"\r\n :show-alpha=\"false\"\r\n :swatches=\"COLOR_SWATCHES\"\r\n :actions=\"['confirm']\"\r\n />\r\n <span class=\"color-value\">{{ settingsStore.primaryColor }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 圆角大小 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">圆角大小</div>\r\n <NRadioGroup\r\n v-model:value=\"settingsStore.borderRadius\"\r\n class=\"radius-group\"\r\n >\r\n <NRadioButton value=\"small\">小 (4px)</NRadioButton>\r\n <NRadioButton value=\"medium\">中 (6px)</NRadioButton>\r\n <NRadioButton value=\"large\">大 (8px)</NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 页面动画 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">页面动画</div>\r\n <div class=\"flex items-center justify-between mb-2\">\r\n <span class=\"text-sm\">启用动画</span>\r\n <NSwitch v-model:value=\"settingsStore.enableTransition\" />\r\n </div>\r\n <NRadioGroup\r\n v-model:value=\"settingsStore.transitionType\"\r\n :disabled=\"!settingsStore.enableTransition\"\r\n class=\"transition-group\"\r\n >\r\n <NRadioButton value=\"fade\">淡入</NRadioButton>\r\n <NRadioButton value=\"slide\">滑动</NRadioButton>\r\n <NRadioButton value=\"zoom\">缩放</NRadioButton>\r\n <NRadioButton value=\"none\">无</NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 恢复默认 -->\r\n <div class=\"settings-section\">\r\n <NButton block secondary @click=\"handleResetAppearance\">\r\n <template #icon>\r\n <span class=\"i-mdi:restore\"></span>\r\n </template>\r\n 恢复外观默认设置\r\n </NButton>\r\n </div>\r\n <slot name=\"appearance-append\" :settings=\"settingsStore\" />\r\n </NTabPane>\r\n\r\n <!-- 布局 Tab -->\r\n <NTabPane name=\"layout\" tab=\"📐 布局\">\r\n <slot name=\"layout-prepend\" :settings=\"settingsStore\" />\r\n <!-- 布局模式 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">布局模式</div>\r\n <div class=\"layout-grid\">\r\n <div\r\n v-for=\"mode in LAYOUT_MODE_OPTIONS\"\r\n :key=\"mode.value\"\r\n class=\"layout-item\"\r\n :class=\"{\r\n active: settingsStore.layoutMode === mode.value,\r\n disabled: mode.disabled,\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"mode.disabled ? -1 : 0\"\r\n :aria-disabled=\"mode.disabled\"\r\n :aria-pressed=\"settingsStore.layoutMode === mode.value\"\r\n @click.stop=\"handleLayoutChange(mode.value, mode.disabled)\"\r\n @keydown.enter.stop=\"\r\n handleLayoutChange(mode.value, mode.disabled)\r\n \"\r\n @keydown.space.stop.prevent=\"\r\n handleLayoutChange(mode.value, mode.disabled)\r\n \"\r\n >\r\n <div class=\"layout-screenshot\">\r\n <svg\r\n class=\"layout-svg\"\r\n viewBox=\"0 0 56 48\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <g v-html=\"mode.svg\"></g>\r\n </svg>\r\n </div>\r\n <div class=\"layout-label\">\r\n {{ mode.label }}\r\n <span v-if=\"mode.disabled\" class=\"badge-soon\">敬请期待</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <slot name=\"layout-after-mode\" :settings=\"settingsStore\" />\r\n\r\n <div\r\n class=\"settings-section menu-expand-section\"\r\n data-menu-expand-mode=\"built-in\"\r\n >\r\n <div class=\"section-title\">菜单展开方式</div>\r\n <NRadioGroup\r\n v-model:value=\"settingsStore.menuExpandMode\"\r\n class=\"menu-expand-group\"\r\n >\r\n <NRadioButton value=\"inline\">传统展开</NRadioButton>\r\n <NRadioButton value=\"panel\">右侧面板</NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 界面元素 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">界面元素</div>\r\n <div class=\"setting-item\">\r\n <span>显示面包屑</span>\r\n <NSwitch v-model:value=\"settingsStore.showBreadcrumb\" />\r\n </div>\r\n <div class=\"setting-item\">\r\n <span>显示面包屑图标</span>\r\n <NSwitch\r\n v-model:value=\"settingsStore.showBreadcrumbIcon\"\r\n :disabled=\"!settingsStore.showBreadcrumb\"\r\n />\r\n </div>\r\n <div class=\"setting-item\">\r\n <span>显示标签页</span>\r\n <NSwitch v-model:value=\"settingsStore.showTagsView\" />\r\n </div>\r\n <div class=\"setting-item\">\r\n <span>显示页脚</span>\r\n <NSwitch v-model:value=\"settingsStore.showFooter\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 尺寸调整 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">尺寸调整</div>\r\n <div class=\"slider-item\">\r\n <div class=\"slider-label\">\r\n <span>侧边栏宽度</span>\r\n <span class=\"slider-value\"\r\n >{{ settingsStore.sidebarWidth }}px</span\r\n >\r\n </div>\r\n <NSlider\r\n v-model:value=\"settingsStore.sidebarWidth\"\r\n :min=\"180\"\r\n :max=\"280\"\r\n :step=\"10\"\r\n :marks=\"{ 180: '180', 220: '220', 280: '280' }\"\r\n />\r\n </div>\r\n <div class=\"slider-item\">\r\n <div class=\"slider-label\">\r\n <span>头部高度</span>\r\n <span class=\"slider-value\"\r\n >{{ settingsStore.headerHeight }}px</span\r\n >\r\n </div>\r\n <NSlider\r\n v-model:value=\"settingsStore.headerHeight\"\r\n :min=\"48\"\r\n :max=\"64\"\r\n :step=\"4\"\r\n :marks=\"{ 48: '48', 56: '56', 64: '64' }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 恢复默认 -->\r\n <div class=\"settings-section\">\r\n <NButton block secondary @click=\"handleResetLayout\">\r\n <template #icon>\r\n <span class=\"i-mdi:restore\"></span>\r\n </template>\r\n 恢复布局默认设置\r\n </NButton>\r\n </div>\r\n <slot name=\"layout-append\" :settings=\"settingsStore\" />\r\n </NTabPane>\r\n\r\n <!-- 功能 Tab -->\r\n <NTabPane name=\"features\" tab=\"🔧 功能\">\r\n <slot name=\"features-prepend\" :settings=\"settingsStore\" />\r\n <!-- 缓存管理 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">缓存管理</div>\r\n <div class=\"action-buttons-grid\">\r\n <NButton secondary @click=\"handleClearCache\">\r\n <template #icon>\r\n <span class=\"i-mdi:delete-sweep\"></span>\r\n </template>\r\n 清除缓存\r\n </NButton>\r\n <NButton secondary @click=\"handleReload\">\r\n <template #icon>\r\n <span class=\"i-mdi:refresh\"></span>\r\n </template>\r\n 重新加载\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <!-- 配置管理 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">配置管理</div>\r\n <div class=\"action-buttons-grid\">\r\n <NButton secondary @click=\"handleExportConfig\">\r\n <template #icon>\r\n <span class=\"i-mdi:download\"></span>\r\n </template>\r\n 导出配置\r\n </NButton>\r\n <NButton secondary @click=\"handleImportConfig\">\r\n <template #icon>\r\n <span class=\"i-mdi:upload\"></span>\r\n </template>\r\n 导入配置\r\n </NButton>\r\n </div>\r\n <NButton\r\n block\r\n type=\"error\"\r\n secondary\r\n class=\"mt-2\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <span class=\"i-mdi:restore\"></span>\r\n </template>\r\n 重置所有配置\r\n </NButton>\r\n </div>\r\n\r\n <!-- 系统模式 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">系统模式</div>\r\n <div class=\"setting-item\">\r\n <div class=\"setting-label\">\r\n <span>灰色模式</span>\r\n <span class=\"setting-desc\">用于哀悼日场景</span>\r\n </div>\r\n <NSwitch v-model:value=\"grayMode\" />\r\n </div>\r\n <div class=\"setting-item\">\r\n <div class=\"setting-label\">\r\n <span>色弱模式</span>\r\n <span class=\"setting-desc\">提供无障碍访问支持</span>\r\n </div>\r\n <NSwitch v-model:value=\"colorWeakMode\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 水印设置 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">水印设置</div>\r\n <div class=\"setting-item\">\r\n <span>启用水印</span>\r\n <NSwitch v-model:value=\"watermarkEnabled\" />\r\n </div>\r\n <div v-if=\"watermarkEnabled\" class=\"mt-2\">\r\n <NInput\r\n v-model:value=\"watermarkText\"\r\n placeholder=\"请输入水印内容\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 系统信息 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">系统信息</div>\r\n <div class=\"system-info\">\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">浏览器</span>\r\n <span class=\"info-value\">{{ systemInfo.browser }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">操作系统</span>\r\n <span class=\"info-value\">{{ systemInfo.os }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">屏幕分辨率</span>\r\n <span class=\"info-value\">{{ systemInfo.resolution }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">设备像素比</span>\r\n <span class=\"info-value\">{{ systemInfo.pixelRatio }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">语言</span>\r\n <span class=\"info-value\">{{ systemInfo.language }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">时区</span>\r\n <span class=\"info-value\">{{ systemInfo.timezone }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <slot name=\"features-append\" :settings=\"settingsStore\" />\r\n </NTabPane>\r\n </NTabs>\r\n </NDrawerContent>\r\n </NDrawer>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, inject } from \"vue\";\r\nimport {\r\n NDrawer,\r\n NDrawerContent,\r\n NTabs,\r\n NTabPane,\r\n NRadioGroup,\r\n NRadioButton,\r\n NColorPicker,\r\n NSwitch,\r\n NButton,\r\n NSlider,\r\n NInput,\r\n useMessage,\r\n useDialog,\r\n} from \"naive-ui\";\r\nimport {\r\n useSettingsStore,\r\n type SettingsStoreInstance,\r\n} from \"../../stores/settings\";\r\nimport {\r\n LayoutActionUnavailableError,\r\n useSettingsController,\r\n} from \"../../composables/useSettingsController\";\r\nimport { LAYOUT_SETTINGS_KEY } from \"../../composables/useLayoutContext\";\r\nimport { COLOR_SWATCHES, LAYOUT_MODE_OPTIONS, THEME_PRESETS } from \"./data\";\r\nimport type {\r\n SettingsDrawerActions,\r\n LayoutMode,\r\n ThemeMode,\r\n ThemePreset,\r\n} from \"../../types\";\r\n\r\n// ============ 数据定义 ============\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 抽屉宽度,默认 380px */\r\n width?: number;\r\n /** 显式设置 Store;优先级高于 setupLayout 注入和默认 Store */\r\n store?: SettingsStoreInstance;\r\n /** 由宿主实现的缓存清理、页面刷新等高副作用操作 */\r\n actions?: SettingsDrawerActions;\r\n /** 导入文件最大字节数,默认 1 MiB */\r\n maxImportBytes?: number;\r\n }>(),\r\n {\r\n width: 380,\r\n maxImportBytes: 1024 * 1024,\r\n },\r\n);\r\n\r\nconst message = useMessage();\r\nconst dialog = useDialog();\r\nconst injectedSettingsStore = inject(LAYOUT_SETTINGS_KEY, null);\r\nconst settingsStore =\r\n props.store ?? injectedSettingsStore ?? useSettingsStore();\r\nconst visible = defineModel<boolean>(\"show\", { default: false });\r\nconst activeTab = ref(\"appearance\");\r\nconst settingsController = useSettingsController({\r\n store: settingsStore,\r\n actions: props.actions,\r\n maxImportBytes: props.maxImportBytes,\r\n onVisualEffectError: (text) => message.error(text),\r\n});\r\nconst { colorWeakMode, grayMode, systemInfo, watermarkEnabled, watermarkText } =\r\n settingsController;\r\n\r\n// 处理布局切换 - 阻止抽屉关闭\r\nconst handleLayoutChange = (value: LayoutMode, disabled?: boolean) => {\r\n if (disabled) return;\r\n settingsStore.layoutMode = value;\r\n};\r\n\r\n// ============ 方法 ============\r\n\r\n/**\r\n * 判断是否是当前预设\r\n */\r\nconst isCurrentPreset = (preset: ThemePreset) => {\r\n return settingsStore.primaryColor === preset.primaryColor;\r\n};\r\n\r\n/**\r\n * 应用预设方案\r\n */\r\nconst handleApplyPreset = (preset: ThemePreset) => {\r\n void settingsController.applyPreset(preset);\r\n message.success(`已应用「${preset.name}」主题方案`);\r\n};\r\n\r\nconst handleThemeModeChange = async (mode: ThemeMode) => {\r\n try {\r\n await settingsController.updateThemeMode(mode);\r\n } catch {\r\n message.error(\"主题模式切换失败\");\r\n }\r\n};\r\n\r\n/**\r\n * 恢复外观默认设置\r\n */\r\nconst handleResetAppearance = async () => {\r\n try {\r\n await settingsController.resetAppearance();\r\n message.success(\"已恢复外观默认设置\");\r\n } catch {\r\n message.error(\"恢复外观默认设置失败\");\r\n }\r\n};\r\n\r\n/**\r\n * 恢复布局默认设置\r\n */\r\nconst handleResetLayout = () => {\r\n settingsController.resetLayout();\r\n message.success(\"已恢复布局默认设置\");\r\n};\r\n\r\n/**\r\n * 重置配置\r\n */\r\nconst handleReset = () => {\r\n dialog.warning({\r\n title: \"确认重置\",\r\n content: \"确定要恢复默认配置吗?此操作不可撤销。\",\r\n positiveText: \"确认\",\r\n negativeText: \"取消\",\r\n onPositiveClick: async () => {\r\n try {\r\n await settingsController.resetAll();\r\n message.success(\"已恢复默认配置\");\r\n } catch {\r\n message.error(\"恢复默认配置失败\");\r\n }\r\n },\r\n });\r\n};\r\n\r\n/**\r\n * 清除缓存\r\n */\r\nconst handleClearCache = () => {\r\n dialog.warning({\r\n title: \"确认清除\",\r\n content: \"确定要清除浏览器缓存吗?\",\r\n positiveText: \"确认\",\r\n negativeText: \"取消\",\r\n onPositiveClick: async () => {\r\n try {\r\n await settingsController.clearCache();\r\n message.success(\"缓存已清除\");\r\n } catch (error) {\r\n if (error instanceof LayoutActionUnavailableError) {\r\n message.warning(\"宿主应用未配置可安全清理的缓存\");\r\n return;\r\n }\r\n message.error(\"缓存清除失败\");\r\n }\r\n },\r\n });\r\n};\r\n\r\n/**\r\n * 重新加载页面\r\n */\r\nconst handleReload = () => {\r\n settingsController.reloadPage();\r\n};\r\n\r\n/**\r\n * 导出配置\r\n */\r\nconst handleExportConfig = () => {\r\n if (settingsController.downloadConfig()) message.success(\"配置已导出\");\r\n else message.error(\"当前环境不支持配置导出\");\r\n};\r\n\r\n/**\r\n * 导入配置\r\n */\r\nconst handleImportConfig = () => {\r\n if (typeof document === \"undefined\") return;\r\n const input = document.createElement(\"input\");\r\n input.type = \"file\";\r\n input.accept = \"application/json\";\r\n input.onchange = async (e: Event) => {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (!file) return;\r\n\r\n try {\r\n await settingsController.importFile(file);\r\n message.success(\"配置已导入\");\r\n } catch (error) {\r\n message.error(\"配置文件格式错误\");\r\n }\r\n };\r\n input.click();\r\n};\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"../../styles/settings.scss\" as *;\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - SettingsDrawer\r\n *\r\n * 布局配置抽屉\r\n * 包含外观/布局/功能三大模块,支持主题预设、布局切换、配置导入导出等\r\n -->\r\n<template>\r\n <NDrawer\r\n v-model:show=\"visible\"\r\n :width=\"width\"\r\n placement=\"right\"\r\n :trap-focus=\"true\"\r\n :block-scroll=\"true\"\r\n >\r\n <NDrawerContent title=\"⚙️ 布局配置\" closable>\r\n <NTabs v-model:value=\"activeTab\" animated class=\"settings-tabs\">\r\n <!-- 外观 Tab -->\r\n <NTabPane name=\"appearance\" tab=\"🎨 外观\">\r\n <slot name=\"appearance-prepend\" :settings=\"settingsStore\" />\r\n <!-- 预设方案网格 -->\r\n <div class=\"settings-section\">\r\n <div class=\"preset-grid\">\r\n <div\r\n v-for=\"preset in THEME_PRESETS\"\r\n :key=\"preset.name\"\r\n class=\"preset-card\"\r\n :class=\"{ active: isCurrentPreset(preset) }\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n :aria-pressed=\"isCurrentPreset(preset)\"\r\n @click=\"handleApplyPreset(preset)\"\r\n @keydown.enter=\"handleApplyPreset(preset)\"\r\n @keydown.space.prevent=\"handleApplyPreset(preset)\"\r\n >\r\n <div class=\"preset-icon\">{{ preset.icon }}</div>\r\n <div class=\"preset-name\">{{ preset.name }}</div>\r\n <div class=\"preset-color\">\r\n <span\r\n class=\"color-dot\"\r\n :style=\"{ backgroundColor: preset.primaryColor }\"\r\n ></span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主题模式 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">主题模式</div>\r\n <NRadioGroup\r\n :value=\"settingsStore.themeMode\"\r\n class=\"mode-group\"\r\n @update:value=\"handleThemeModeChange\"\r\n >\r\n <NRadioButton value=\"light\">\r\n <span class=\"i-mdi:white-balance-sunny mr-1\"></span>\r\n 浅色\r\n </NRadioButton>\r\n <NRadioButton value=\"dark\">\r\n <span class=\"i-mdi:moon-waning-crescent mr-1\"></span>\r\n 深色\r\n </NRadioButton>\r\n <NRadioButton value=\"system\">\r\n <span class=\"i-mdi:theme-light-dark mr-1\"></span>\r\n 自动\r\n </NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 主题色 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">主题色</div>\r\n <div class=\"color-picker-wrapper\">\r\n <NColorPicker\r\n v-model:value=\"settingsStore.primaryColor\"\r\n :show-alpha=\"false\"\r\n :swatches=\"COLOR_SWATCHES\"\r\n :actions=\"['confirm']\"\r\n />\r\n <span class=\"color-value\">{{ settingsStore.primaryColor }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 圆角大小 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">圆角大小</div>\r\n <NRadioGroup\r\n v-model:value=\"settingsStore.borderRadius\"\r\n class=\"radius-group\"\r\n >\r\n <NRadioButton value=\"small\">小 (4px)</NRadioButton>\r\n <NRadioButton value=\"medium\">中 (6px)</NRadioButton>\r\n <NRadioButton value=\"large\">大 (8px)</NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 页面动画 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">页面动画</div>\r\n <div class=\"flex items-center justify-between mb-2\">\r\n <span class=\"text-sm\">启用动画</span>\r\n <NSwitch v-model:value=\"settingsStore.enableTransition\" />\r\n </div>\r\n <NRadioGroup\r\n v-model:value=\"settingsStore.transitionType\"\r\n :disabled=\"!settingsStore.enableTransition\"\r\n class=\"transition-group\"\r\n >\r\n <NRadioButton value=\"fade\">淡入</NRadioButton>\r\n <NRadioButton value=\"slide\">滑动</NRadioButton>\r\n <NRadioButton value=\"zoom\">缩放</NRadioButton>\r\n <NRadioButton value=\"none\">无</NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 恢复默认 -->\r\n <div class=\"settings-section\">\r\n <NButton block secondary @click=\"handleResetAppearance\">\r\n <template #icon>\r\n <span class=\"i-mdi:restore\"></span>\r\n </template>\r\n 恢复外观默认设置\r\n </NButton>\r\n </div>\r\n <slot name=\"appearance-append\" :settings=\"settingsStore\" />\r\n </NTabPane>\r\n\r\n <!-- 布局 Tab -->\r\n <NTabPane name=\"layout\" tab=\"📐 布局\">\r\n <slot name=\"layout-prepend\" :settings=\"settingsStore\" />\r\n <!-- 布局模式 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">布局模式</div>\r\n <div class=\"layout-grid\">\r\n <div\r\n v-for=\"mode in LAYOUT_MODE_OPTIONS\"\r\n :key=\"mode.value\"\r\n class=\"layout-item\"\r\n :class=\"{\r\n active: settingsStore.layoutMode === mode.value,\r\n disabled: mode.disabled,\r\n }\"\r\n role=\"button\"\r\n :tabindex=\"mode.disabled ? -1 : 0\"\r\n :aria-disabled=\"mode.disabled\"\r\n :aria-pressed=\"settingsStore.layoutMode === mode.value\"\r\n @click.stop=\"handleLayoutChange(mode.value, mode.disabled)\"\r\n @keydown.enter.stop=\"\r\n handleLayoutChange(mode.value, mode.disabled)\r\n \"\r\n @keydown.space.stop.prevent=\"\r\n handleLayoutChange(mode.value, mode.disabled)\r\n \"\r\n >\r\n <div class=\"layout-screenshot\">\r\n <svg\r\n class=\"layout-svg\"\r\n viewBox=\"0 0 56 48\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <g v-html=\"mode.svg\"></g>\r\n </svg>\r\n </div>\r\n <div class=\"layout-label\">\r\n {{ mode.label }}\r\n <span v-if=\"mode.disabled\" class=\"badge-soon\">敬请期待</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <slot name=\"layout-after-mode\" :settings=\"settingsStore\" />\r\n\r\n <div\r\n class=\"settings-section menu-expand-section\"\r\n data-menu-expand-mode=\"built-in\"\r\n >\r\n <div class=\"section-title\">菜单展开方式</div>\r\n <NRadioGroup\r\n v-model:value=\"settingsStore.menuExpandMode\"\r\n class=\"menu-expand-group\"\r\n >\r\n <NRadioButton value=\"inline\">传统展开</NRadioButton>\r\n <NRadioButton value=\"panel\">右侧面板</NRadioButton>\r\n </NRadioGroup>\r\n </div>\r\n\r\n <!-- 界面元素 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">界面元素</div>\r\n <div class=\"setting-item\">\r\n <span>显示面包屑</span>\r\n <NSwitch v-model:value=\"settingsStore.showBreadcrumb\" />\r\n </div>\r\n <div class=\"setting-item\">\r\n <span>显示面包屑图标</span>\r\n <NSwitch\r\n v-model:value=\"settingsStore.showBreadcrumbIcon\"\r\n :disabled=\"!settingsStore.showBreadcrumb\"\r\n />\r\n </div>\r\n <div class=\"setting-item\">\r\n <span>显示标签页</span>\r\n <NSwitch v-model:value=\"settingsStore.showTagsView\" />\r\n </div>\r\n <div class=\"setting-item\">\r\n <span>显示页脚</span>\r\n <NSwitch v-model:value=\"settingsStore.showFooter\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 尺寸调整 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">尺寸调整</div>\r\n <div class=\"slider-item\">\r\n <div class=\"slider-label\">\r\n <span>侧边栏宽度</span>\r\n <span class=\"slider-value\"\r\n >{{ settingsStore.sidebarWidth }}px</span\r\n >\r\n </div>\r\n <NSlider\r\n v-model:value=\"settingsStore.sidebarWidth\"\r\n :min=\"180\"\r\n :max=\"280\"\r\n :step=\"10\"\r\n :marks=\"{ 180: '180', 220: '220', 280: '280' }\"\r\n />\r\n </div>\r\n <div class=\"slider-item\">\r\n <div class=\"slider-label\">\r\n <span>头部高度</span>\r\n <span class=\"slider-value\"\r\n >{{ settingsStore.headerHeight }}px</span\r\n >\r\n </div>\r\n <NSlider\r\n v-model:value=\"settingsStore.headerHeight\"\r\n :min=\"48\"\r\n :max=\"64\"\r\n :step=\"4\"\r\n :marks=\"{ 48: '48', 56: '56', 64: '64' }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 恢复默认 -->\r\n <div class=\"settings-section\">\r\n <NButton block secondary @click=\"handleResetLayout\">\r\n <template #icon>\r\n <span class=\"i-mdi:restore\"></span>\r\n </template>\r\n 恢复布局默认设置\r\n </NButton>\r\n </div>\r\n <slot name=\"layout-append\" :settings=\"settingsStore\" />\r\n </NTabPane>\r\n\r\n <!-- 功能 Tab -->\r\n <NTabPane name=\"features\" tab=\"🔧 功能\">\r\n <slot name=\"features-prepend\" :settings=\"settingsStore\" />\r\n <!-- 缓存管理 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">缓存管理</div>\r\n <div class=\"action-buttons-grid\">\r\n <NButton secondary @click=\"handleClearCache\">\r\n <template #icon>\r\n <span class=\"i-mdi:delete-sweep\"></span>\r\n </template>\r\n 清除缓存\r\n </NButton>\r\n <NButton secondary @click=\"handleReload\">\r\n <template #icon>\r\n <span class=\"i-mdi:refresh\"></span>\r\n </template>\r\n 重新加载\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <!-- 配置管理 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">配置管理</div>\r\n <div class=\"action-buttons-grid\">\r\n <NButton secondary @click=\"handleExportConfig\">\r\n <template #icon>\r\n <span class=\"i-mdi:download\"></span>\r\n </template>\r\n 导出配置\r\n </NButton>\r\n <NButton secondary @click=\"handleImportConfig\">\r\n <template #icon>\r\n <span class=\"i-mdi:upload\"></span>\r\n </template>\r\n 导入配置\r\n </NButton>\r\n </div>\r\n <NButton\r\n block\r\n type=\"error\"\r\n secondary\r\n class=\"mt-2\"\r\n @click=\"handleReset\"\r\n >\r\n <template #icon>\r\n <span class=\"i-mdi:restore\"></span>\r\n </template>\r\n 重置所有配置\r\n </NButton>\r\n </div>\r\n\r\n <!-- 系统模式 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">系统模式</div>\r\n <div class=\"setting-item\">\r\n <div class=\"setting-label\">\r\n <span>灰色模式</span>\r\n <span class=\"setting-desc\">用于哀悼日场景</span>\r\n </div>\r\n <NSwitch v-model:value=\"grayMode\" />\r\n </div>\r\n <div class=\"setting-item\">\r\n <div class=\"setting-label\">\r\n <span>色弱模式</span>\r\n <span class=\"setting-desc\">提供无障碍访问支持</span>\r\n </div>\r\n <NSwitch v-model:value=\"colorWeakMode\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 水印设置 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">水印设置</div>\r\n <div class=\"setting-item\">\r\n <span>启用水印</span>\r\n <NSwitch v-model:value=\"watermarkEnabled\" />\r\n </div>\r\n <div v-if=\"watermarkEnabled\" class=\"mt-2\">\r\n <NInput\r\n v-model:value=\"watermarkText\"\r\n placeholder=\"请输入水印内容\"\r\n size=\"small\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 系统信息 -->\r\n <div class=\"settings-section\">\r\n <div class=\"section-title\">系统信息</div>\r\n <div class=\"system-info\">\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">浏览器</span>\r\n <span class=\"info-value\">{{ systemInfo.browser }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">操作系统</span>\r\n <span class=\"info-value\">{{ systemInfo.os }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">屏幕分辨率</span>\r\n <span class=\"info-value\">{{ systemInfo.resolution }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">设备像素比</span>\r\n <span class=\"info-value\">{{ systemInfo.pixelRatio }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">语言</span>\r\n <span class=\"info-value\">{{ systemInfo.language }}</span>\r\n </div>\r\n <div class=\"info-item\">\r\n <span class=\"info-label\">时区</span>\r\n <span class=\"info-value\">{{ systemInfo.timezone }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <slot name=\"features-append\" :settings=\"settingsStore\" />\r\n </NTabPane>\r\n </NTabs>\r\n </NDrawerContent>\r\n </NDrawer>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, inject } from \"vue\";\r\nimport {\r\n NDrawer,\r\n NDrawerContent,\r\n NTabs,\r\n NTabPane,\r\n NRadioGroup,\r\n NRadioButton,\r\n NColorPicker,\r\n NSwitch,\r\n NButton,\r\n NSlider,\r\n NInput,\r\n useMessage,\r\n useDialog,\r\n} from \"naive-ui\";\r\nimport {\r\n useSettingsStore,\r\n type SettingsStoreInstance,\r\n} from \"../../stores/settings\";\r\nimport {\r\n LayoutActionUnavailableError,\r\n useSettingsController,\r\n} from \"../../composables/useSettingsController\";\r\nimport { LAYOUT_SETTINGS_KEY } from \"../../composables/useLayoutContext\";\r\nimport { COLOR_SWATCHES, LAYOUT_MODE_OPTIONS, THEME_PRESETS } from \"./data\";\r\nimport type {\r\n SettingsDrawerActions,\r\n LayoutMode,\r\n ThemeMode,\r\n ThemePreset,\r\n} from \"../../types\";\r\n\r\n// ============ 数据定义 ============\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 抽屉宽度,默认 380px */\r\n width?: number;\r\n /** 显式设置 Store;优先级高于 setupLayout 注入和默认 Store */\r\n store?: SettingsStoreInstance;\r\n /** 由宿主实现的缓存清理、页面刷新等高副作用操作 */\r\n actions?: SettingsDrawerActions;\r\n /** 导入文件最大字节数,默认 1 MiB */\r\n maxImportBytes?: number;\r\n }>(),\r\n {\r\n width: 380,\r\n maxImportBytes: 1024 * 1024,\r\n },\r\n);\r\n\r\nconst message = useMessage();\r\nconst dialog = useDialog();\r\nconst injectedSettingsStore = inject(LAYOUT_SETTINGS_KEY, null);\r\nconst settingsStore =\r\n props.store ?? injectedSettingsStore ?? useSettingsStore();\r\nconst visible = defineModel<boolean>(\"show\", { default: false });\r\nconst activeTab = ref(\"appearance\");\r\nconst settingsController = useSettingsController({\r\n store: settingsStore,\r\n actions: props.actions,\r\n maxImportBytes: props.maxImportBytes,\r\n onVisualEffectError: (text) => message.error(text),\r\n});\r\nconst { colorWeakMode, grayMode, systemInfo, watermarkEnabled, watermarkText } =\r\n settingsController;\r\n\r\n// 处理布局切换 - 阻止抽屉关闭\r\nconst handleLayoutChange = (value: LayoutMode, disabled?: boolean) => {\r\n if (disabled) return;\r\n settingsStore.layoutMode = value;\r\n};\r\n\r\n// ============ 方法 ============\r\n\r\n/**\r\n * 判断是否是当前预设\r\n */\r\nconst isCurrentPreset = (preset: ThemePreset) => {\r\n return settingsStore.primaryColor === preset.primaryColor;\r\n};\r\n\r\n/**\r\n * 应用预设方案\r\n */\r\nconst handleApplyPreset = (preset: ThemePreset) => {\r\n void settingsController.applyPreset(preset);\r\n message.success(`已应用「${preset.name}」主题方案`);\r\n};\r\n\r\nconst handleThemeModeChange = async (mode: ThemeMode) => {\r\n try {\r\n await settingsController.updateThemeMode(mode);\r\n } catch {\r\n message.error(\"主题模式切换失败\");\r\n }\r\n};\r\n\r\n/**\r\n * 恢复外观默认设置\r\n */\r\nconst handleResetAppearance = async () => {\r\n try {\r\n await settingsController.resetAppearance();\r\n message.success(\"已恢复外观默认设置\");\r\n } catch {\r\n message.error(\"恢复外观默认设置失败\");\r\n }\r\n};\r\n\r\n/**\r\n * 恢复布局默认设置\r\n */\r\nconst handleResetLayout = () => {\r\n settingsController.resetLayout();\r\n message.success(\"已恢复布局默认设置\");\r\n};\r\n\r\n/**\r\n * 重置配置\r\n */\r\nconst handleReset = () => {\r\n dialog.warning({\r\n title: \"确认重置\",\r\n content: \"确定要恢复默认配置吗?此操作不可撤销。\",\r\n positiveText: \"确认\",\r\n negativeText: \"取消\",\r\n onPositiveClick: async () => {\r\n try {\r\n await settingsController.resetAll();\r\n message.success(\"已恢复默认配置\");\r\n } catch {\r\n message.error(\"恢复默认配置失败\");\r\n }\r\n },\r\n });\r\n};\r\n\r\n/**\r\n * 清除缓存\r\n */\r\nconst handleClearCache = () => {\r\n dialog.warning({\r\n title: \"确认清除\",\r\n content: \"确定要清除浏览器缓存吗?\",\r\n positiveText: \"确认\",\r\n negativeText: \"取消\",\r\n onPositiveClick: async () => {\r\n try {\r\n await settingsController.clearCache();\r\n message.success(\"缓存已清除\");\r\n } catch (error) {\r\n if (error instanceof LayoutActionUnavailableError) {\r\n message.warning(\"宿主应用未配置可安全清理的缓存\");\r\n return;\r\n }\r\n message.error(\"缓存清除失败\");\r\n }\r\n },\r\n });\r\n};\r\n\r\n/**\r\n * 重新加载页面\r\n */\r\nconst handleReload = () => {\r\n settingsController.reloadPage();\r\n};\r\n\r\n/**\r\n * 导出配置\r\n */\r\nconst handleExportConfig = () => {\r\n if (settingsController.downloadConfig()) message.success(\"配置已导出\");\r\n else message.error(\"当前环境不支持配置导出\");\r\n};\r\n\r\n/**\r\n * 导入配置\r\n */\r\nconst handleImportConfig = () => {\r\n if (typeof document === \"undefined\") return;\r\n const input = document.createElement(\"input\");\r\n input.type = \"file\";\r\n input.accept = \"application/json\";\r\n input.onchange = async (e: Event) => {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (!file) return;\r\n\r\n try {\r\n await settingsController.importFile(file);\r\n message.success(\"配置已导入\");\r\n } catch (error) {\r\n message.error(\"配置文件格式错误\");\r\n }\r\n };\r\n input.click();\r\n};\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n@use \"../../styles/settings.scss\" as *;\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - BrandLogo\r\n *\r\n * 品牌 Logo 组件\r\n * 从 LayoutContext.brand 读取配置,自动渲染 Logo + 品牌名\r\n * 支持折叠状态、横向/纵向布局\r\n -->\r\n<template>\r\n <div\r\n class=\"brand-logo\"\r\n :class=\"{\r\n 'brand-logo--collapsed': collapsed,\r\n 'brand-logo--horizontal': variant === 'horizontal',\r\n }\"\r\n >\r\n <div class=\"brand-logo__icon\">\r\n <div class=\"brand-logo__glow\"></div>\r\n <video\r\n v-if=\"brandConfig.logoType === 'video' && brandConfig.logoSrc\"\r\n :src=\"brandConfig.logoSrc\"\r\n :width=\"size\"\r\n :height=\"size\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"brand-logo__media\"\r\n />\r\n <img\r\n v-else-if=\"brandConfig.logoSrc\"\r\n :src=\"brandConfig.logoSrc\"\r\n :width=\"size\"\r\n :height=\"size\"\r\n class=\"brand-logo__media\"\r\n alt=\"Logo\"\r\n />\r\n </div>\r\n <template v-if=\"showName && !collapsed\">\r\n <div class=\"brand-logo__name\">\r\n <span class=\"brand-logo__title\">{{ brandConfig.name }}</span>\r\n <span v-if=\"brandConfig.subtitle\" class=\"brand-logo__subtitle\">{{\r\n brandConfig.subtitle\r\n }}</span>\r\n </div>\r\n <div v-if=\"showDivider\" class=\"brand-logo__divider\"></div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"BrandLogo\" });\r\n\r\nwithDefaults(\r\n defineProps<{\r\n /** 是否显示品牌名称 */\r\n showName?: boolean;\r\n /** 是否显示分隔线 */\r\n showDivider?: boolean;\r\n /** Logo 尺寸 */\r\n size?: number;\r\n /** 是否折叠状态 */\r\n collapsed?: boolean;\r\n /** 布局方向 */\r\n variant?: \"vertical\" | \"horizontal\";\r\n }>(),\r\n {\r\n showName: false,\r\n showDivider: false,\r\n size: 36,\r\n collapsed: false,\r\n variant: \"horizontal\",\r\n },\r\n);\r\n\r\nconst ctx = useLayoutContext();\r\nconst brandConfig = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n</script>\r\n\r\n<style scoped>\r\n.brand-logo {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n cursor: pointer;\r\n user-select: none;\r\n}\r\n\r\n.brand-logo--collapsed {\r\n justify-content: center;\r\n}\r\n\r\n.brand-logo__icon {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n}\r\n\r\n.brand-logo__glow {\r\n position: absolute;\r\n inset: -4px;\r\n border-radius: 50%;\r\n background: radial-gradient(\r\n circle,\r\n rgba(99, 102, 241, 0.15) 0%,\r\n transparent 70%\r\n );\r\n pointer-events: none;\r\n}\r\n\r\n.brand-logo__media {\r\n border-radius: 8px;\r\n object-fit: contain;\r\n}\r\n\r\n.brand-logo__name {\r\n display: flex;\r\n flex-direction: column;\r\n line-height: 1.2;\r\n white-space: nowrap;\r\n}\r\n\r\n.brand-logo__title {\r\n font-size: 15px;\r\n font-weight: 700;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n background-clip: text;\r\n -webkit-background-clip: text;\r\n -webkit-text-fill-color: transparent;\r\n}\r\n\r\n.brand-logo__subtitle {\r\n font-size: 10px;\r\n opacity: 0.6;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.brand-logo__divider {\r\n width: 1px;\r\n height: 24px;\r\n margin: 0 6px;\r\n background: linear-gradient(\r\n 180deg,\r\n transparent 0%,\r\n rgba(128, 128, 128, 0.3) 50%,\r\n transparent 100%\r\n );\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - BrandLogo\r\n *\r\n * 品牌 Logo 组件\r\n * 从 LayoutContext.brand 读取配置,自动渲染 Logo + 品牌名\r\n * 支持折叠状态、横向/纵向布局\r\n -->\r\n<template>\r\n <div\r\n class=\"brand-logo\"\r\n :class=\"{\r\n 'brand-logo--collapsed': collapsed,\r\n 'brand-logo--horizontal': variant === 'horizontal',\r\n }\"\r\n >\r\n <div class=\"brand-logo__icon\">\r\n <div class=\"brand-logo__glow\"></div>\r\n <video\r\n v-if=\"brandConfig.logoType === 'video' && brandConfig.logoSrc\"\r\n :src=\"brandConfig.logoSrc\"\r\n :width=\"size\"\r\n :height=\"size\"\r\n autoplay\r\n loop\r\n muted\r\n playsinline\r\n class=\"brand-logo__media\"\r\n />\r\n <img\r\n v-else-if=\"brandConfig.logoSrc\"\r\n :src=\"brandConfig.logoSrc\"\r\n :width=\"size\"\r\n :height=\"size\"\r\n class=\"brand-logo__media\"\r\n alt=\"Logo\"\r\n />\r\n </div>\r\n <template v-if=\"showName && !collapsed\">\r\n <div class=\"brand-logo__name\">\r\n <span class=\"brand-logo__title\">{{ brandConfig.name }}</span>\r\n <span v-if=\"brandConfig.subtitle\" class=\"brand-logo__subtitle\">{{\r\n brandConfig.subtitle\r\n }}</span>\r\n </div>\r\n <div v-if=\"showDivider\" class=\"brand-logo__divider\"></div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"BrandLogo\" });\r\n\r\nwithDefaults(\r\n defineProps<{\r\n /** 是否显示品牌名称 */\r\n showName?: boolean;\r\n /** 是否显示分隔线 */\r\n showDivider?: boolean;\r\n /** Logo 尺寸 */\r\n size?: number;\r\n /** 是否折叠状态 */\r\n collapsed?: boolean;\r\n /** 布局方向 */\r\n variant?: \"vertical\" | \"horizontal\";\r\n }>(),\r\n {\r\n showName: false,\r\n showDivider: false,\r\n size: 36,\r\n collapsed: false,\r\n variant: \"horizontal\",\r\n },\r\n);\r\n\r\nconst ctx = useLayoutContext();\r\nconst brandConfig = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n</script>\r\n\r\n<style scoped>\r\n.brand-logo {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n cursor: pointer;\r\n user-select: none;\r\n}\r\n\r\n.brand-logo--collapsed {\r\n justify-content: center;\r\n}\r\n\r\n.brand-logo__icon {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n}\r\n\r\n.brand-logo__glow {\r\n position: absolute;\r\n inset: -4px;\r\n border-radius: 50%;\r\n background: radial-gradient(\r\n circle,\r\n rgba(99, 102, 241, 0.15) 0%,\r\n transparent 70%\r\n );\r\n pointer-events: none;\r\n}\r\n\r\n.brand-logo__media {\r\n border-radius: 8px;\r\n object-fit: contain;\r\n}\r\n\r\n.brand-logo__name {\r\n display: flex;\r\n flex-direction: column;\r\n line-height: 1.2;\r\n white-space: nowrap;\r\n}\r\n\r\n.brand-logo__title {\r\n font-size: 15px;\r\n font-weight: 700;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n background-clip: text;\r\n -webkit-background-clip: text;\r\n -webkit-text-fill-color: transparent;\r\n}\r\n\r\n.brand-logo__subtitle {\r\n font-size: 10px;\r\n opacity: 0.6;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.brand-logo__divider {\r\n width: 1px;\r\n height: 24px;\r\n margin: 0 6px;\r\n background: linear-gradient(\r\n 180deg,\r\n transparent 0%,\r\n rgba(128, 128, 128, 0.3) 50%,\r\n transparent 100%\r\n );\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - IconMenu\r\n *\r\n * 一级图标菜单\r\n * 用于 Mix / MixTop 布局的左侧一级菜单栏\r\n * 显示图标 + 标签,支持激活状态\r\n -->\r\n<template>\r\n <div class=\"icon-menu\">\r\n <div\r\n v-for=\"item in menus\"\r\n :key=\"item.path\"\r\n class=\"icon-menu__item\"\r\n :class=\"{ 'icon-menu__item--active': active === item.path }\"\r\n @click=\"emit('click', item)\"\r\n >\r\n <div class=\"icon-menu__icon\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"20\"\r\n />\r\n <span v-else class=\"icon-menu__fallback\">\r\n {{ item.meta?.title?.charAt(0) || \"?\" }}\r\n </span>\r\n </div>\r\n <div class=\"icon-menu__label\">\r\n {{ item.meta?.title }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"IconMenu\" });\r\n\r\ndefineProps<{\r\n /** 菜单数据 */\r\n menus: MenuOptions[];\r\n /** 当前激活的菜单路径 */\r\n active?: string;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n click: [item: MenuOptions];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\n</script>\r\n\r\n<style scoped>\r\n.icon-menu {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 4px 0;\r\n width: 100%;\r\n}\r\n\r\n.icon-menu__item {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n width: calc(100% - 12px);\r\n padding: 10px 4px 8px;\r\n margin: 0 6px;\r\n border-radius: 10px;\r\n cursor: pointer;\r\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n position: relative;\r\n opacity: 0.7;\r\n}\r\n\r\n.icon-menu__item:hover {\r\n opacity: 1;\r\n background: rgba(99, 102, 241, 0.08);\r\n transform: translateY(-1px);\r\n}\r\n\r\n.icon-menu__item--active {\r\n opacity: 1;\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.15) 0%,\r\n rgba(139, 92, 246, 0.1) 100%\r\n );\r\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.2);\r\n}\r\n\r\n.icon-menu__item--active::before {\r\n content: \"\";\r\n position: absolute;\r\n left: 0;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n width: 3px;\r\n height: 60%;\r\n border-radius: 0 3px 3px 0;\r\n background: linear-gradient(180deg, #667eea, #764ba2);\r\n}\r\n\r\n.icon-menu__icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n font-size: 20px;\r\n}\r\n\r\n.icon-menu__fallback {\r\n font-size: 14px;\r\n font-weight: 600;\r\n width: 28px;\r\n height: 28px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 8px;\r\n background: rgba(128, 128, 128, 0.1);\r\n}\r\n\r\n.icon-menu__label {\r\n font-size: 11px;\r\n font-weight: 500;\r\n line-height: 1.2;\r\n text-align: center;\r\n max-width: 100%;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - IconMenu\r\n *\r\n * 一级图标菜单\r\n * 用于 Mix / MixTop 布局的左侧一级菜单栏\r\n * 显示图标 + 标签,支持激活状态\r\n -->\r\n<template>\r\n <div class=\"icon-menu\">\r\n <div\r\n v-for=\"item in menus\"\r\n :key=\"item.path\"\r\n class=\"icon-menu__item\"\r\n :class=\"{ 'icon-menu__item--active': active === item.path }\"\r\n @click=\"emit('click', item)\"\r\n >\r\n <div class=\"icon-menu__icon\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"20\"\r\n />\r\n <span v-else class=\"icon-menu__fallback\">\r\n {{ item.meta?.title?.charAt(0) || \"?\" }}\r\n </span>\r\n </div>\r\n <div class=\"icon-menu__label\">\r\n {{ item.meta?.title }}\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"IconMenu\" });\r\n\r\ndefineProps<{\r\n /** 菜单数据 */\r\n menus: MenuOptions[];\r\n /** 当前激活的菜单路径 */\r\n active?: string;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n click: [item: MenuOptions];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\n</script>\r\n\r\n<style scoped>\r\n.icon-menu {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 4px 0;\r\n width: 100%;\r\n}\r\n\r\n.icon-menu__item {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n width: calc(100% - 12px);\r\n padding: 10px 4px 8px;\r\n margin: 0 6px;\r\n border-radius: 10px;\r\n cursor: pointer;\r\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n position: relative;\r\n opacity: 0.7;\r\n}\r\n\r\n.icon-menu__item:hover {\r\n opacity: 1;\r\n background: rgba(99, 102, 241, 0.08);\r\n transform: translateY(-1px);\r\n}\r\n\r\n.icon-menu__item--active {\r\n opacity: 1;\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.15) 0%,\r\n rgba(139, 92, 246, 0.1) 100%\r\n );\r\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.2);\r\n}\r\n\r\n.icon-menu__item--active::before {\r\n content: \"\";\r\n position: absolute;\r\n left: 0;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n width: 3px;\r\n height: 60%;\r\n border-radius: 0 3px 3px 0;\r\n background: linear-gradient(180deg, #667eea, #764ba2);\r\n}\r\n\r\n.icon-menu__icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n font-size: 20px;\r\n}\r\n\r\n.icon-menu__fallback {\r\n font-size: 14px;\r\n font-weight: 600;\r\n width: 28px;\r\n height: 28px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 8px;\r\n background: rgba(128, 128, 128, 0.1);\r\n}\r\n\r\n.icon-menu__label {\r\n font-size: 11px;\r\n font-weight: 500;\r\n line-height: 1.2;\r\n text-align: center;\r\n max-width: 100%;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - FloatingMenu\r\n *\r\n * 悬浮二级菜单面板\r\n * 用于 C_MixLayout 的悬浮二级菜单(点击一级菜单后展开)\n -->\r\n<template>\r\n <Transition name=\"slide-fade\">\r\n <div\r\n v-if=\"show && menuItem\"\r\n class=\"floating-menu\"\n :class=\"[ctx.isDark.value ? 'dark-theme' : 'light-theme']\"\n role=\"navigation\"\n aria-label=\"二级功能导航\"\n >\r\n <!-- 标题 -->\r\n <div class=\"floating-menu__header\">\r\n <div class=\"floating-menu__brand\">\r\n <span class=\"floating-menu__brand-title\">{{ brand.name }}</span>\r\n <span class=\"floating-menu__brand-subtitle\">{{\r\n brand.subtitle\r\n }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 菜单列表 -->\r\n <div class=\"floating-menu__list\">\r\n <template v-for=\"child in menuItem.children\" :key=\"child.path\">\r\n <!-- 有子菜单的项 -->\r\n <div\r\n v-if=\"child.children && child.children.length > 0\"\r\n class=\"floating-menu__group\"\r\n >\r\n <div class=\"floating-menu__group-title\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span>{{ child.meta?.title }}</span>\r\n </div>\r\n <div\r\n v-for=\"subChild in child.children\"\r\n :key=\"subChild.path\"\r\n class=\"floating-menu__item floating-menu__item--sub\"\n :class=\"{ active: isActive?.(subChild.path) }\"\n role=\"link\"\n tabindex=\"0\"\n @click=\"emit('click', subChild)\"\n @keydown.enter=\"emit('click', subChild)\"\n @keydown.space.prevent=\"emit('click', subChild)\"\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && subChild.meta?.icon\"\r\n :name=\"subChild.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"floating-menu__item-text\">{{\r\n subChild.meta?.title\r\n }}</span>\r\n </div>\r\n </div>\r\n <!-- 无子菜单的项 -->\r\n <div\r\n v-else\r\n class=\"floating-menu__item\"\n :class=\"{ active: isActive?.(child.path) }\"\n role=\"link\"\n tabindex=\"0\"\n @click=\"emit('click', child)\"\n @keydown.enter=\"emit('click', child)\"\n @keydown.space.prevent=\"emit('click', child)\"\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span class=\"floating-menu__item-text\">{{\r\n child.meta?.title\r\n }}</span>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </Transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"FloatingMenu\" });\r\n\r\ndefineProps<{\r\n /** 是否显示 */\r\n show: boolean;\r\n /** 当前悬浮的一级菜单项(包含 children) */\r\n menuItem: MenuOptions | null;\r\n /** 判断菜单项是否激活 */\r\n isActive?: (path: string | undefined) => boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n click: [item: MenuOptions];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n</script>\r\n\r\n<style scoped>\r\n.floating-menu {\r\n position: absolute;\r\n top: 0;\r\n left: 100%;\r\n width: 240px;\r\n height: 100%;\r\n z-index: 100;\r\n overflow-y: auto;\r\n border-right: 1px solid rgba(128, 128, 128, 0.1);\r\n backdrop-filter: blur(20px);\r\n -webkit-backdrop-filter: blur(20px);\r\n}\r\n\r\n.floating-menu.light-theme {\r\n background: rgba(255, 255, 255, 0.95);\r\n box-shadow: 4px 0 24px rgba(0, 0, 0, 0.08);\r\n}\r\n\r\n.floating-menu.dark-theme {\r\n background: rgba(30, 30, 36, 0.95);\r\n box-shadow: 4px 0 24px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.floating-menu__header {\r\n padding: 16px 20px 12px;\r\n border-bottom: 1px solid rgba(128, 128, 128, 0.1);\r\n}\r\n\r\n.floating-menu__brand-title {\r\n font-size: 14px;\r\n font-weight: 700;\r\n background: linear-gradient(135deg, #667eea, #764ba2);\r\n background-clip: text;\r\n -webkit-background-clip: text;\r\n -webkit-text-fill-color: transparent;\r\n}\r\n\r\n.floating-menu__brand-subtitle {\r\n display: block;\r\n font-size: 11px;\r\n opacity: 0.5;\r\n margin-top: 2px;\r\n}\r\n\r\n.floating-menu__list {\r\n padding: 8px 12px;\r\n}\r\n\r\n.floating-menu__group {\r\n margin-bottom: 8px;\r\n}\r\n\r\n.floating-menu__group-title {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 8px 4px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n opacity: 0.5;\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.floating-menu__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 10px 12px;\r\n margin: 2px 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n font-size: 14px;\r\n}\r\n\r\n.floating-menu__item:hover {\n background: rgba(99, 102, 241, 0.08);\r\n}\n\n.floating-menu__item:focus-visible {\n outline: 2px solid #667eea;\n outline-offset: 2px;\n}\n\r\n.floating-menu__item.active {\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.12),\r\n rgba(139, 92, 246, 0.08)\r\n );\r\n color: #667eea;\r\n}\r\n\r\n.floating-menu__item--sub {\r\n padding-left: 20px;\r\n font-size: 13px;\r\n}\r\n\r\n.floating-menu__item-text {\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* Transition */\r\n.slide-fade-enter-active,\r\n.slide-fade-leave-active {\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.slide-fade-enter-from {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n\r\n.slide-fade-leave-to {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - FloatingMenu\r\n *\r\n * 悬浮二级菜单面板\r\n * 用于 C_MixLayout 的悬浮二级菜单(点击一级菜单后展开)\n -->\r\n<template>\r\n <Transition name=\"slide-fade\">\r\n <div\r\n v-if=\"show && menuItem\"\r\n class=\"floating-menu\"\n :class=\"[ctx.isDark.value ? 'dark-theme' : 'light-theme']\"\n role=\"navigation\"\n aria-label=\"二级功能导航\"\n >\r\n <!-- 标题 -->\r\n <div class=\"floating-menu__header\">\r\n <div class=\"floating-menu__brand\">\r\n <span class=\"floating-menu__brand-title\">{{ brand.name }}</span>\r\n <span class=\"floating-menu__brand-subtitle\">{{\r\n brand.subtitle\r\n }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 菜单列表 -->\r\n <div class=\"floating-menu__list\">\r\n <template v-for=\"child in menuItem.children\" :key=\"child.path\">\r\n <!-- 有子菜单的项 -->\r\n <div\r\n v-if=\"child.children && child.children.length > 0\"\r\n class=\"floating-menu__group\"\r\n >\r\n <div class=\"floating-menu__group-title\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span>{{ child.meta?.title }}</span>\r\n </div>\r\n <div\r\n v-for=\"subChild in child.children\"\r\n :key=\"subChild.path\"\r\n class=\"floating-menu__item floating-menu__item--sub\"\n :class=\"{ active: isActive?.(subChild.path) }\"\n role=\"link\"\n tabindex=\"0\"\n @click=\"emit('click', subChild)\"\n @keydown.enter=\"emit('click', subChild)\"\n @keydown.space.prevent=\"emit('click', subChild)\"\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && subChild.meta?.icon\"\r\n :name=\"subChild.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"floating-menu__item-text\">{{\r\n subChild.meta?.title\r\n }}</span>\r\n </div>\r\n </div>\r\n <!-- 无子菜单的项 -->\r\n <div\r\n v-else\r\n class=\"floating-menu__item\"\n :class=\"{ active: isActive?.(child.path) }\"\n role=\"link\"\n tabindex=\"0\"\n @click=\"emit('click', child)\"\n @keydown.enter=\"emit('click', child)\"\n @keydown.space.prevent=\"emit('click', child)\"\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span class=\"floating-menu__item-text\">{{\r\n child.meta?.title\r\n }}</span>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </Transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport {\r\n useLayoutContext,\r\n DEFAULT_BRAND_CONFIG,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"FloatingMenu\" });\r\n\r\ndefineProps<{\r\n /** 是否显示 */\r\n show: boolean;\r\n /** 当前悬浮的一级菜单项(包含 children) */\r\n menuItem: MenuOptions | null;\r\n /** 判断菜单项是否激活 */\r\n isActive?: (path: string | undefined) => boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n click: [item: MenuOptions];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\nconst brand = { ...DEFAULT_BRAND_CONFIG, ...ctx.brand };\r\n</script>\r\n\r\n<style scoped>\r\n.floating-menu {\r\n position: absolute;\r\n top: 0;\r\n left: 100%;\r\n width: 240px;\r\n height: 100%;\r\n z-index: 100;\r\n overflow-y: auto;\r\n border-right: 1px solid rgba(128, 128, 128, 0.1);\r\n backdrop-filter: blur(20px);\r\n -webkit-backdrop-filter: blur(20px);\r\n}\r\n\r\n.floating-menu.light-theme {\r\n background: rgba(255, 255, 255, 0.95);\r\n box-shadow: 4px 0 24px rgba(0, 0, 0, 0.08);\r\n}\r\n\r\n.floating-menu.dark-theme {\r\n background: rgba(30, 30, 36, 0.95);\r\n box-shadow: 4px 0 24px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.floating-menu__header {\r\n padding: 16px 20px 12px;\r\n border-bottom: 1px solid rgba(128, 128, 128, 0.1);\r\n}\r\n\r\n.floating-menu__brand-title {\r\n font-size: 14px;\r\n font-weight: 700;\r\n background: linear-gradient(135deg, #667eea, #764ba2);\r\n background-clip: text;\r\n -webkit-background-clip: text;\r\n -webkit-text-fill-color: transparent;\r\n}\r\n\r\n.floating-menu__brand-subtitle {\r\n display: block;\r\n font-size: 11px;\r\n opacity: 0.5;\r\n margin-top: 2px;\r\n}\r\n\r\n.floating-menu__list {\r\n padding: 8px 12px;\r\n}\r\n\r\n.floating-menu__group {\r\n margin-bottom: 8px;\r\n}\r\n\r\n.floating-menu__group-title {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 8px 4px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n opacity: 0.5;\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.floating-menu__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 10px 12px;\r\n margin: 2px 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n font-size: 14px;\r\n}\r\n\r\n.floating-menu__item:hover {\n background: rgba(99, 102, 241, 0.08);\r\n}\n\n.floating-menu__item:focus-visible {\n outline: 2px solid #667eea;\n outline-offset: 2px;\n}\n\r\n.floating-menu__item.active {\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.12),\r\n rgba(139, 92, 246, 0.08)\r\n );\r\n color: #667eea;\r\n}\r\n\r\n.floating-menu__item--sub {\r\n padding-left: 20px;\r\n font-size: 13px;\r\n}\r\n\r\n.floating-menu__item-text {\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* Transition */\r\n.slide-fade-enter-active,\r\n.slide-fade-leave-active {\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.slide-fade-enter-from {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n\r\n.slide-fade-leave-to {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - SideMenu\r\n *\r\n * 右侧二级菜单侧边栏\r\n * 用于 C_ReverseHorizontalMixLayout 的右侧二级菜单\n -->\r\n<template>\r\n <template v-if=\"menus.length > 0\">\r\n <!-- 折叠/展开按钮 -->\r\n <div\r\n class=\"side-menu-toggle\"\r\n :class=\"[\r\n ctx.isDark.value ? 'dark-theme' : 'light-theme',\r\n { active: !isCollapsed },\r\n ]\"\r\n @click=\"isCollapsed = !isCollapsed\"\r\n >\r\n <i\r\n :class=\"[\r\n 'toggle-icon',\r\n isCollapsed ? 'i-ri:side-bar-line' : 'i-ri:arrow-right-s-line',\r\n ]\"\r\n ></i>\r\n </div>\r\n\r\n <!-- 侧边栏内容 -->\r\n <Transition name=\"glass-slide\">\r\n <div\r\n v-if=\"!isCollapsed\"\r\n class=\"side-menu\"\r\n :class=\"[ctx.isDark.value ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 标题 -->\r\n <div class=\"side-menu__header\">\r\n <div class=\"side-menu__header-icon\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && activeItem?.meta?.icon\"\r\n :name=\"activeItem.meta.icon\"\r\n :size=\"17\"\r\n />\r\n </div>\r\n <span class=\"side-menu__header-title\">{{\r\n activeItem?.meta?.title || \"菜单\"\r\n }}</span>\r\n </div>\r\n\r\n <!-- 菜单列表 -->\r\n <div class=\"side-menu__list\">\r\n <template v-for=\"child in menus\" :key=\"child.path\">\r\n <!-- 有子菜单 -->\r\n <div\r\n v-if=\"child.children && child.children.length > 0\"\r\n class=\"side-menu__group\"\r\n >\r\n <div class=\"side-menu__group-label\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"14\"\r\n />\r\n <span>{{ child.meta?.title }}</span>\r\n </div>\r\n <div\r\n v-for=\"subChild in child.children\"\r\n :key=\"subChild.path\"\r\n class=\"side-menu__item\"\r\n :class=\"{ active: isActive?.(subChild.path) }\"\r\n @click=\"emit('click', subChild)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && subChild.meta?.icon\"\r\n :name=\"subChild.meta.icon\"\r\n :size=\"15\"\r\n />\r\n <span class=\"side-menu__item-text\">{{\r\n subChild.meta?.title\r\n }}</span>\r\n </div>\r\n </div>\r\n <!-- 无子菜单 -->\r\n <div\r\n v-else\r\n class=\"side-menu__item\"\r\n :class=\"{ active: isActive?.(child.path) }\"\r\n @click=\"emit('click', child)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"side-menu__item-text\">{{ child.meta?.title }}</span>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </Transition>\r\n </template>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"SideMenu\" });\r\n\r\ndefineProps<{\r\n /** 二级菜单列表 */\r\n menus: MenuOptions[];\r\n /** 当前一级菜单项(显示标题和图标) */\r\n activeItem?: MenuOptions;\r\n /** 判断菜单项是否激活 */\r\n isActive?: (path: string | undefined) => boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n click: [item: MenuOptions];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\nconst isCollapsed = ref(false);\r\n</script>\r\n\r\n<style scoped>\r\n.side-menu-toggle {\r\n position: absolute;\r\n right: 0;\r\n top: 50%;\r\n transform: translateY(-50%) translateX(50%);\r\n width: 24px;\r\n height: 48px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 12px;\r\n cursor: pointer;\r\n z-index: 10;\r\n transition: all 0.25s ease;\r\n font-size: 14px;\r\n}\r\n\r\n.side-menu-toggle.light-theme {\r\n background: rgba(255, 255, 255, 0.9);\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n.side-menu-toggle.dark-theme {\r\n background: rgba(40, 40, 46, 0.9);\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.side-menu-toggle:hover {\r\n transform: translateY(-50%) translateX(50%) scale(1.1);\r\n}\r\n\r\n.side-menu {\r\n width: 100%;\r\n height: 100%;\r\n overflow-y: auto;\r\n padding: 0 8px;\r\n}\r\n\r\n.side-menu.light-theme {\r\n background: rgba(255, 255, 255, 0.95);\r\n border-left: 1px solid rgba(0, 0, 0, 0.06);\r\n}\r\n\r\n.side-menu.dark-theme {\r\n background: rgba(30, 30, 36, 0.95);\r\n border-left: 1px solid rgba(255, 255, 255, 0.06);\r\n}\r\n\r\n.side-menu__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 16px 12px 12px;\r\n border-bottom: 1px solid rgba(128, 128, 128, 0.1);\r\n margin-bottom: 8px;\r\n}\r\n\r\n.side-menu__header-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n border-radius: 8px;\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.12),\r\n rgba(139, 92, 246, 0.08)\r\n );\r\n}\r\n\r\n.side-menu__header-title {\r\n font-size: 14px;\r\n font-weight: 600;\r\n}\r\n\r\n.side-menu__list {\r\n padding: 4px 0;\r\n}\r\n\r\n.side-menu__group {\r\n margin-bottom: 8px;\r\n}\r\n\r\n.side-menu__group-label {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 6px 12px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n opacity: 0.5;\r\n}\r\n\r\n.side-menu__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 9px 12px;\r\n margin: 2px 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.side-menu__item:hover {\r\n background: rgba(99, 102, 241, 0.06);\r\n}\r\n\r\n.side-menu__item.active {\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.1),\r\n rgba(139, 92, 246, 0.06)\r\n );\r\n color: #667eea;\r\n font-weight: 500;\r\n}\r\n\r\n.side-menu__item-text {\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* Transition */\r\n.glass-slide-enter-active,\r\n.glass-slide-leave-active {\r\n transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.glass-slide-enter-from,\r\n.glass-slide-leave-to {\r\n opacity: 0;\r\n transform: translateX(20px);\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - SideMenu\r\n *\r\n * 右侧二级菜单侧边栏\r\n * 用于 C_ReverseHorizontalMixLayout 的右侧二级菜单\n -->\r\n<template>\r\n <template v-if=\"menus.length > 0\">\r\n <!-- 折叠/展开按钮 -->\r\n <div\r\n class=\"side-menu-toggle\"\r\n :class=\"[\r\n ctx.isDark.value ? 'dark-theme' : 'light-theme',\r\n { active: !isCollapsed },\r\n ]\"\r\n @click=\"isCollapsed = !isCollapsed\"\r\n >\r\n <i\r\n :class=\"[\r\n 'toggle-icon',\r\n isCollapsed ? 'i-ri:side-bar-line' : 'i-ri:arrow-right-s-line',\r\n ]\"\r\n ></i>\r\n </div>\r\n\r\n <!-- 侧边栏内容 -->\r\n <Transition name=\"glass-slide\">\r\n <div\r\n v-if=\"!isCollapsed\"\r\n class=\"side-menu\"\r\n :class=\"[ctx.isDark.value ? 'dark-theme' : 'light-theme']\"\r\n >\r\n <!-- 标题 -->\r\n <div class=\"side-menu__header\">\r\n <div class=\"side-menu__header-icon\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && activeItem?.meta?.icon\"\r\n :name=\"activeItem.meta.icon\"\r\n :size=\"17\"\r\n />\r\n </div>\r\n <span class=\"side-menu__header-title\">{{\r\n activeItem?.meta?.title || \"菜单\"\r\n }}</span>\r\n </div>\r\n\r\n <!-- 菜单列表 -->\r\n <div class=\"side-menu__list\">\r\n <template v-for=\"child in menus\" :key=\"child.path\">\r\n <!-- 有子菜单 -->\r\n <div\r\n v-if=\"child.children && child.children.length > 0\"\r\n class=\"side-menu__group\"\r\n >\r\n <div class=\"side-menu__group-label\">\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"14\"\r\n />\r\n <span>{{ child.meta?.title }}</span>\r\n </div>\r\n <div\r\n v-for=\"subChild in child.children\"\r\n :key=\"subChild.path\"\r\n class=\"side-menu__item\"\r\n :class=\"{ active: isActive?.(subChild.path) }\"\r\n @click=\"emit('click', subChild)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && subChild.meta?.icon\"\r\n :name=\"subChild.meta.icon\"\r\n :size=\"15\"\r\n />\r\n <span class=\"side-menu__item-text\">{{\r\n subChild.meta?.title\r\n }}</span>\r\n </div>\r\n </div>\r\n <!-- 无子菜单 -->\r\n <div\r\n v-else\r\n class=\"side-menu__item\"\r\n :class=\"{ active: isActive?.(child.path) }\"\r\n @click=\"emit('click', child)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && child.meta?.icon\"\r\n :name=\"child.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"side-menu__item-text\">{{ child.meta?.title }}</span>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </Transition>\r\n </template>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"SideMenu\" });\r\n\r\ndefineProps<{\r\n /** 二级菜单列表 */\r\n menus: MenuOptions[];\r\n /** 当前一级菜单项(显示标题和图标) */\r\n activeItem?: MenuOptions;\r\n /** 判断菜单项是否激活 */\r\n isActive?: (path: string | undefined) => boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n click: [item: MenuOptions];\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\nconst isCollapsed = ref(false);\r\n</script>\r\n\r\n<style scoped>\r\n.side-menu-toggle {\r\n position: absolute;\r\n right: 0;\r\n top: 50%;\r\n transform: translateY(-50%) translateX(50%);\r\n width: 24px;\r\n height: 48px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 12px;\r\n cursor: pointer;\r\n z-index: 10;\r\n transition: all 0.25s ease;\r\n font-size: 14px;\r\n}\r\n\r\n.side-menu-toggle.light-theme {\r\n background: rgba(255, 255, 255, 0.9);\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n.side-menu-toggle.dark-theme {\r\n background: rgba(40, 40, 46, 0.9);\r\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.side-menu-toggle:hover {\r\n transform: translateY(-50%) translateX(50%) scale(1.1);\r\n}\r\n\r\n.side-menu {\r\n width: 100%;\r\n height: 100%;\r\n overflow-y: auto;\r\n padding: 0 8px;\r\n}\r\n\r\n.side-menu.light-theme {\r\n background: rgba(255, 255, 255, 0.95);\r\n border-left: 1px solid rgba(0, 0, 0, 0.06);\r\n}\r\n\r\n.side-menu.dark-theme {\r\n background: rgba(30, 30, 36, 0.95);\r\n border-left: 1px solid rgba(255, 255, 255, 0.06);\r\n}\r\n\r\n.side-menu__header {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 16px 12px 12px;\r\n border-bottom: 1px solid rgba(128, 128, 128, 0.1);\r\n margin-bottom: 8px;\r\n}\r\n\r\n.side-menu__header-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n border-radius: 8px;\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.12),\r\n rgba(139, 92, 246, 0.08)\r\n );\r\n}\r\n\r\n.side-menu__header-title {\r\n font-size: 14px;\r\n font-weight: 600;\r\n}\r\n\r\n.side-menu__list {\r\n padding: 4px 0;\r\n}\r\n\r\n.side-menu__group {\r\n margin-bottom: 8px;\r\n}\r\n\r\n.side-menu__group-label {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 6px 12px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n opacity: 0.5;\r\n}\r\n\r\n.side-menu__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 9px 12px;\r\n margin: 2px 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.side-menu__item:hover {\r\n background: rgba(99, 102, 241, 0.06);\r\n}\r\n\r\n.side-menu__item.active {\r\n background: linear-gradient(\r\n 135deg,\r\n rgba(99, 102, 241, 0.1),\r\n rgba(139, 92, 246, 0.06)\r\n );\r\n color: #667eea;\r\n font-weight: 500;\r\n}\r\n\r\n.side-menu__item-text {\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* Transition */\r\n.glass-slide-enter-active,\r\n.glass-slide-leave-active {\r\n transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);\r\n}\r\n\r\n.glass-slide-enter-from,\r\n.glass-slide-leave-to {\r\n opacity: 0;\r\n transform: translateX(20px);\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - DrawerMenu\r\n *\r\n * 抽屉式网格菜单\r\n * 用于 C_CardLayout 的 hover 触发的抽屉式功能导航\n -->\r\n<template>\r\n <div\r\n class=\"drawer-menu\"\r\n :class=\"[\r\n ctx.isDark.value ? 'dark-theme' : 'light-theme',\r\n { visible: show },\r\n ]\"\r\n role=\"navigation\"\r\n aria-label=\"功能导航\"\r\n :aria-hidden=\"!show\"\r\n @mouseenter=\"handlers.show()\"\r\n @mouseleave=\"handlers.startHide()\"\r\n >\r\n <div class=\"drawer-menu__header\">\r\n <div class=\"drawer-menu__title\">\r\n <!-- 纯 CSS 网格图标 -->\r\n <span class=\"grid-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n <span>功能导航</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"drawer-menu__content\">\r\n <div class=\"drawer-menu__grid\">\r\n <div\r\n v-for=\"category in menus\"\r\n :key=\"category.path\"\r\n class=\"drawer-menu__category\"\r\n >\r\n <div\r\n class=\"drawer-menu__category-header\"\r\n role=\"link\"\r\n tabindex=\"0\"\r\n @click=\"navigate(category)\"\r\n @keydown.enter=\"navigate(category)\"\r\n @keydown.space.prevent=\"navigate(category)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && category.meta?.icon\"\r\n :name=\"category.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span>{{ category.meta?.title }}</span>\r\n </div>\r\n\r\n <div\r\n v-if=\"category.children && category.children.length > 0\"\r\n class=\"drawer-menu__items\"\r\n >\r\n <div\r\n v-for=\"item in category.children\"\r\n :key=\"item.path\"\r\n class=\"drawer-menu__item\"\r\n role=\"link\"\r\n tabindex=\"0\"\r\n @click=\"navigate(item)\"\r\n @keydown.enter=\"navigate(item)\"\r\n @keydown.space.prevent=\"navigate(item)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"drawer-menu__item-text\">{{ item.meta?.title }}</span>\r\n </div>\r\n\r\n <template v-for=\"item in category.children\" :key=\"item.path\">\r\n <div\r\n v-if=\"item.children && item.children.length > 0\"\r\n class=\"drawer-menu__sub-items\"\r\n >\r\n <div class=\"drawer-menu__sub-title\">\r\n {{ item.meta?.title }}\r\n </div>\r\n <div\r\n v-for=\"subItem in item.children\"\r\n :key=\"subItem.path\"\r\n class=\"drawer-menu__item drawer-menu__item--sub\"\r\n role=\"link\"\r\n tabindex=\"0\"\r\n @click=\"navigate(subItem)\"\r\n @keydown.enter=\"navigate(subItem)\"\r\n @keydown.space.prevent=\"navigate(subItem)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && subItem.meta?.icon\"\r\n :name=\"subItem.meta.icon\"\r\n :size=\"14\"\r\n />\r\n <span class=\"drawer-menu__item-text\">{{\r\n subItem.meta?.title\r\n }}</span>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue\";\r\nimport { useRouter } from \"vue-router\";\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\nimport {\r\n DRAWER_HANDLER_KEY,\r\n type DrawerHandlers,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"DrawerMenu\" });\r\n\r\ndefineProps<{\r\n /** 菜单数据 */\r\n menus: MenuOptions[];\r\n /** 是否显示 */\r\n show: boolean;\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\nconst router = useRouter();\r\n\r\n// 使用共享的 drawer 控制器(由 C_LayoutContainer provide)\r\nconst handlers = inject<DrawerHandlers>(DRAWER_HANDLER_KEY, {\r\n show: () => {},\r\n startHide: () => {},\r\n hide: () => {},\r\n});\r\n\r\nconst navigate = (item: MenuOptions) => {\r\n if (item.path) {\r\n void router.push(item.path);\r\n handlers.hide();\r\n }\r\n};\r\n</script>\r\n\r\n<style scoped>\r\n.drawer-menu {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n right: 0;\r\n z-index: 100;\r\n max-height: 60vh;\r\n overflow-y: auto;\r\n opacity: 0;\r\n visibility: hidden;\r\n transform: translateY(-8px);\r\n pointer-events: none;\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n backdrop-filter: blur(20px);\r\n -webkit-backdrop-filter: blur(20px);\r\n border-bottom-left-radius: 16px;\r\n border-bottom-right-radius: 16px;\r\n}\r\n\r\n.drawer-menu.visible {\r\n opacity: 1;\r\n visibility: visible;\r\n transform: translateY(0);\r\n pointer-events: all;\r\n}\r\n\r\n.drawer-menu.light-theme {\r\n background: rgba(255, 255, 255, 0.96);\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\r\n border: 1px solid rgba(0, 0, 0, 0.06);\r\n border-top: none;\r\n}\r\n\r\n.drawer-menu.dark-theme {\r\n background: rgba(30, 30, 36, 0.96);\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\r\n border: 1px solid rgba(255, 255, 255, 0.06);\r\n border-top: none;\r\n}\r\n\r\n.drawer-menu__header {\r\n padding: 16px 24px 8px;\r\n}\r\n\r\n.drawer-menu__title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n font-size: 15px;\r\n font-weight: 600;\r\n}\r\n\r\n.drawer-menu__content {\r\n padding: 8px 24px 20px;\r\n}\r\n\r\n.drawer-menu__grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\r\n gap: 16px;\r\n}\r\n\r\n.drawer-menu__category {\r\n padding: 0;\r\n}\r\n\r\n.drawer-menu__category-header {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n font-size: 14px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n border-radius: 8px;\r\n transition: background 0.2s ease;\r\n}\r\n\r\n.drawer-menu__category-header:hover {\r\n background: rgba(99, 102, 241, 0.06);\r\n}\r\n\r\n.drawer-menu__category-header:focus-visible,\r\n.drawer-menu__item:focus-visible {\r\n outline: 2px solid #667eea;\r\n outline-offset: 2px;\r\n}\r\n\r\n.drawer-menu__items {\r\n padding-left: 8px;\r\n}\r\n\r\n.drawer-menu__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 7px 12px;\r\n margin: 1px 0;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.drawer-menu__item:hover {\r\n background: rgba(99, 102, 241, 0.08);\r\n color: #667eea;\r\n}\r\n\r\n.drawer-menu__item--sub {\r\n padding-left: 16px;\r\n font-size: 12px;\r\n}\r\n\r\n.drawer-menu__item-text {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.drawer-menu__sub-items {\r\n padding: 4px 0;\r\n}\r\n\r\n.drawer-menu__sub-title {\r\n padding: 4px 12px;\r\n font-size: 11px;\r\n font-weight: 600;\r\n opacity: 0.4;\r\n}\r\n\r\n/* 纯 CSS 网格图标 (2x2) */\r\n.grid-icon {\r\n display: inline-grid;\r\n grid-template-columns: repeat(2, 1fr);\r\n gap: 2.5px;\r\n width: 18px;\r\n height: 18px;\r\n padding: 1px;\r\n}\r\n\r\n.grid-icon span {\r\n background-color: currentColor;\r\n border-radius: 2px;\r\n opacity: 0.85;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - DrawerMenu\r\n *\r\n * 抽屉式网格菜单\r\n * 用于 C_CardLayout 的 hover 触发的抽屉式功能导航\n -->\r\n<template>\r\n <div\r\n class=\"drawer-menu\"\r\n :class=\"[\r\n ctx.isDark.value ? 'dark-theme' : 'light-theme',\r\n { visible: show },\r\n ]\"\r\n role=\"navigation\"\r\n aria-label=\"功能导航\"\r\n :aria-hidden=\"!show\"\r\n @mouseenter=\"handlers.show()\"\r\n @mouseleave=\"handlers.startHide()\"\r\n >\r\n <div class=\"drawer-menu__header\">\r\n <div class=\"drawer-menu__title\">\r\n <!-- 纯 CSS 网格图标 -->\r\n <span class=\"grid-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n <span>功能导航</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"drawer-menu__content\">\r\n <div class=\"drawer-menu__grid\">\r\n <div\r\n v-for=\"category in menus\"\r\n :key=\"category.path\"\r\n class=\"drawer-menu__category\"\r\n >\r\n <div\r\n class=\"drawer-menu__category-header\"\r\n role=\"link\"\r\n tabindex=\"0\"\r\n @click=\"navigate(category)\"\r\n @keydown.enter=\"navigate(category)\"\r\n @keydown.space.prevent=\"navigate(category)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && category.meta?.icon\"\r\n :name=\"category.meta.icon\"\r\n :size=\"18\"\r\n />\r\n <span>{{ category.meta?.title }}</span>\r\n </div>\r\n\r\n <div\r\n v-if=\"category.children && category.children.length > 0\"\r\n class=\"drawer-menu__items\"\r\n >\r\n <div\r\n v-for=\"item in category.children\"\r\n :key=\"item.path\"\r\n class=\"drawer-menu__item\"\r\n role=\"link\"\r\n tabindex=\"0\"\r\n @click=\"navigate(item)\"\r\n @keydown.enter=\"navigate(item)\"\r\n @keydown.space.prevent=\"navigate(item)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && item.meta?.icon\"\r\n :name=\"item.meta.icon\"\r\n :size=\"16\"\r\n />\r\n <span class=\"drawer-menu__item-text\">{{ item.meta?.title }}</span>\r\n </div>\r\n\r\n <template v-for=\"item in category.children\" :key=\"item.path\">\r\n <div\r\n v-if=\"item.children && item.children.length > 0\"\r\n class=\"drawer-menu__sub-items\"\r\n >\r\n <div class=\"drawer-menu__sub-title\">\r\n {{ item.meta?.title }}\r\n </div>\r\n <div\r\n v-for=\"subItem in item.children\"\r\n :key=\"subItem.path\"\r\n class=\"drawer-menu__item drawer-menu__item--sub\"\r\n role=\"link\"\r\n tabindex=\"0\"\r\n @click=\"navigate(subItem)\"\r\n @keydown.enter=\"navigate(subItem)\"\r\n @keydown.space.prevent=\"navigate(subItem)\"\r\n >\r\n <component\r\n :is=\"ctx.iconComponent\"\r\n v-if=\"ctx.iconComponent && subItem.meta?.icon\"\r\n :name=\"subItem.meta.icon\"\r\n :size=\"14\"\r\n />\r\n <span class=\"drawer-menu__item-text\">{{\r\n subItem.meta?.title\r\n }}</span>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue\";\r\nimport { useRouter } from \"vue-router\";\r\nimport type { MenuOptions } from \"../../types/menu\";\r\nimport { useLayoutContext } from \"../../composables/useLayoutContext\";\r\nimport {\r\n DRAWER_HANDLER_KEY,\r\n type DrawerHandlers,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"DrawerMenu\" });\r\n\r\ndefineProps<{\r\n /** 菜单数据 */\r\n menus: MenuOptions[];\r\n /** 是否显示 */\r\n show: boolean;\r\n}>();\r\n\r\nconst ctx = useLayoutContext();\r\nconst router = useRouter();\r\n\r\n// 使用共享的 drawer 控制器(由 C_LayoutContainer provide)\r\nconst handlers = inject<DrawerHandlers>(DRAWER_HANDLER_KEY, {\r\n show: () => {},\r\n startHide: () => {},\r\n hide: () => {},\r\n});\r\n\r\nconst navigate = (item: MenuOptions) => {\r\n if (item.path) {\r\n void router.push(item.path);\r\n handlers.hide();\r\n }\r\n};\r\n</script>\r\n\r\n<style scoped>\r\n.drawer-menu {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n right: 0;\r\n z-index: 100;\r\n max-height: 60vh;\r\n overflow-y: auto;\r\n opacity: 0;\r\n visibility: hidden;\r\n transform: translateY(-8px);\r\n pointer-events: none;\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n backdrop-filter: blur(20px);\r\n -webkit-backdrop-filter: blur(20px);\r\n border-bottom-left-radius: 16px;\r\n border-bottom-right-radius: 16px;\r\n}\r\n\r\n.drawer-menu.visible {\r\n opacity: 1;\r\n visibility: visible;\r\n transform: translateY(0);\r\n pointer-events: all;\r\n}\r\n\r\n.drawer-menu.light-theme {\r\n background: rgba(255, 255, 255, 0.96);\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\r\n border: 1px solid rgba(0, 0, 0, 0.06);\r\n border-top: none;\r\n}\r\n\r\n.drawer-menu.dark-theme {\r\n background: rgba(30, 30, 36, 0.96);\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\r\n border: 1px solid rgba(255, 255, 255, 0.06);\r\n border-top: none;\r\n}\r\n\r\n.drawer-menu__header {\r\n padding: 16px 24px 8px;\r\n}\r\n\r\n.drawer-menu__title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n font-size: 15px;\r\n font-weight: 600;\r\n}\r\n\r\n.drawer-menu__content {\r\n padding: 8px 24px 20px;\r\n}\r\n\r\n.drawer-menu__grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\r\n gap: 16px;\r\n}\r\n\r\n.drawer-menu__category {\r\n padding: 0;\r\n}\r\n\r\n.drawer-menu__category-header {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n font-size: 14px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n border-radius: 8px;\r\n transition: background 0.2s ease;\r\n}\r\n\r\n.drawer-menu__category-header:hover {\r\n background: rgba(99, 102, 241, 0.06);\r\n}\r\n\r\n.drawer-menu__category-header:focus-visible,\r\n.drawer-menu__item:focus-visible {\r\n outline: 2px solid #667eea;\r\n outline-offset: 2px;\r\n}\r\n\r\n.drawer-menu__items {\r\n padding-left: 8px;\r\n}\r\n\r\n.drawer-menu__item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 7px 12px;\r\n margin: 1px 0;\r\n border-radius: 6px;\r\n font-size: 13px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.drawer-menu__item:hover {\r\n background: rgba(99, 102, 241, 0.08);\r\n color: #667eea;\r\n}\r\n\r\n.drawer-menu__item--sub {\r\n padding-left: 16px;\r\n font-size: 12px;\r\n}\r\n\r\n.drawer-menu__item-text {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.drawer-menu__sub-items {\r\n padding: 4px 0;\r\n}\r\n\r\n.drawer-menu__sub-title {\r\n padding: 4px 12px;\r\n font-size: 11px;\r\n font-weight: 600;\r\n opacity: 0.4;\r\n}\r\n\r\n/* 纯 CSS 网格图标 (2x2) */\r\n.grid-icon {\r\n display: inline-grid;\r\n grid-template-columns: repeat(2, 1fr);\r\n gap: 2.5px;\r\n width: 18px;\r\n height: 18px;\r\n padding: 1px;\r\n}\r\n\r\n.grid-icon span {\r\n background-color: currentColor;\r\n border-radius: 2px;\r\n opacity: 0.85;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - MenuTrigger\r\n *\r\n * 菜单触发区域\r\n * 用于 C_CardLayout 的 hover 触发抽屉式菜单\n * 使用共享的 drawer 控制器避免与 DrawerMenu 定时器竞争\r\n -->\r\n<template>\r\n <div\r\n class=\"menu-trigger\"\r\n @mouseenter=\"handlers.show()\"\r\n @mouseleave=\"handlers.startHide()\"\r\n >\r\n <div class=\"menu-trigger__indicator\">\r\n <!-- 纯 CSS 三横线菜单图标 -->\r\n <span class=\"hamburger-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue\";\r\nimport {\r\n DRAWER_HANDLER_KEY,\r\n type DrawerHandlers,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"MenuTrigger\" });\r\n\r\ndefineProps<{\r\n show?: boolean;\r\n}>();\r\n\r\n// 使用共享控制器(由 C_LayoutContainer provide)\r\nconst handlers = inject<DrawerHandlers>(DRAWER_HANDLER_KEY, {\r\n show: () => {},\r\n startHide: () => {},\r\n hide: () => {},\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.menu-trigger {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 0 8px;\r\n height: 100%;\r\n cursor: pointer;\r\n}\r\n\r\n.menu-trigger__indicator {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 36px;\r\n height: 36px;\r\n border-radius: 8px;\r\n font-size: 18px;\r\n transition: all 0.25s ease;\r\n opacity: 0.6;\r\n}\r\n\r\n.menu-trigger__indicator:hover {\r\n opacity: 1;\r\n background: rgba(99, 102, 241, 0.08);\r\n}\r\n\r\n/* 纯 CSS 三横线汉堡菜单图标 */\r\n.hamburger-icon {\r\n display: inline-flex;\r\n flex-direction: column;\r\n justify-content: space-between;\r\n width: 20px;\r\n height: 16px;\r\n padding: 2px 0;\r\n}\r\n\r\n.hamburger-icon span {\r\n display: block;\r\n width: 100%;\r\n height: 2px;\r\n background-color: currentColor;\r\n border-radius: 1px;\r\n opacity: 0.85;\r\n transition: all 0.2s ease;\r\n}\r\n</style>\r\n","<!--\r\n * @robot-admin/layout - MenuTrigger\r\n *\r\n * 菜单触发区域\r\n * 用于 C_CardLayout 的 hover 触发抽屉式菜单\n * 使用共享的 drawer 控制器避免与 DrawerMenu 定时器竞争\r\n -->\r\n<template>\r\n <div\r\n class=\"menu-trigger\"\r\n @mouseenter=\"handlers.show()\"\r\n @mouseleave=\"handlers.startHide()\"\r\n >\r\n <div class=\"menu-trigger__indicator\">\r\n <!-- 纯 CSS 三横线菜单图标 -->\r\n <span class=\"hamburger-icon\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </span>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue\";\r\nimport {\r\n DRAWER_HANDLER_KEY,\r\n type DrawerHandlers,\r\n} from \"../../composables/useLayoutContext\";\r\n\r\ndefineOptions({ name: \"MenuTrigger\" });\r\n\r\ndefineProps<{\r\n show?: boolean;\r\n}>();\r\n\r\n// 使用共享控制器(由 C_LayoutContainer provide)\r\nconst handlers = inject<DrawerHandlers>(DRAWER_HANDLER_KEY, {\r\n show: () => {},\r\n startHide: () => {},\r\n hide: () => {},\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.menu-trigger {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 0 8px;\r\n height: 100%;\r\n cursor: pointer;\r\n}\r\n\r\n.menu-trigger__indicator {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 36px;\r\n height: 36px;\r\n border-radius: 8px;\r\n font-size: 18px;\r\n transition: all 0.25s ease;\r\n opacity: 0.6;\r\n}\r\n\r\n.menu-trigger__indicator:hover {\r\n opacity: 1;\r\n background: rgba(99, 102, 241, 0.08);\r\n}\r\n\r\n/* 纯 CSS 三横线汉堡菜单图标 */\r\n.hamburger-icon {\r\n display: inline-flex;\r\n flex-direction: column;\r\n justify-content: space-between;\r\n width: 20px;\r\n height: 16px;\r\n padding: 2px 0;\r\n}\r\n\r\n.hamburger-icon span {\r\n display: block;\r\n width: 100%;\r\n height: 2px;\r\n background-color: currentColor;\r\n border-radius: 1px;\r\n opacity: 0.85;\r\n transition: all 0.2s ease;\r\n}\r\n</style>\r\n","import C_SideLayoutComponent from \"../components/layouts/SideLayout/index.vue\";\nimport C_TopLayoutComponent from \"../components/layouts/TopLayout/index.vue\";\nimport C_MixLayoutComponent from \"../components/layouts/MixLayout/index.vue\";\nimport C_MixTopLayoutComponent from \"../components/layouts/MixTopLayout/index.vue\";\nimport C_ReverseHorizontalMixLayoutComponent from \"../components/layouts/ReverseHorizontalMixLayout/index.vue\";\nimport C_CardLayoutComponent from \"../components/layouts/CardLayout/index.vue\";\n\n/** Naive UI 完整适配入口:聚合 Vue Headless 能力与 Naive 视图。 */\nexport * from \"../vue\";\n\nexport { default as C_LayoutContainer } from \"../components/C_LayoutContainer/index.vue\";\nexport { default as SettingsDrawer } from \"../components/SettingsDrawer/index.vue\";\n\nexport { default as BrandLogo } from \"../components/BrandLogo/index.vue\";\nexport { default as IconMenu } from \"../components/IconMenu/index.vue\";\nexport { default as FloatingMenu } from \"../components/FloatingMenu/index.vue\";\nexport { default as SideMenu } from \"../components/SideMenu/index.vue\";\nexport { default as DrawerMenu } from \"../components/DrawerMenu/index.vue\";\nexport { default as MenuTrigger } from \"../components/MenuTrigger/index.vue\";\nexport { default as ResponsiveMenu } from \"../components/ResponsiveMenu/index.vue\";\n\nexport const C_SideLayout = C_SideLayoutComponent;\nexport const C_TopLayout = C_TopLayoutComponent;\nexport const C_MixLayout = C_MixLayoutComponent;\nexport const C_MixTopLayout = C_MixTopLayoutComponent;\nexport const C_ReverseHorizontalMixLayout =\n C_ReverseHorizontalMixLayoutComponent;\nexport const C_CardLayout = C_CardLayoutComponent;\n\n/** @deprecated 请使用 C_SideLayout;计划在 4.0 移除。 */\nexport const SideLayout = C_SideLayout;\n/** @deprecated 请使用 C_TopLayout;计划在 4.0 移除。 */\nexport const TopLayout = C_TopLayout;\n/** @deprecated 请使用 C_MixLayout;计划在 4.0 移除。 */\nexport const MixLayout = C_MixLayout;\n/** @deprecated 请使用 C_MixTopLayout;计划在 4.0 移除。 */\nexport const MixTopLayout = C_MixTopLayout;\n/** @deprecated 请使用 C_ReverseHorizontalMixLayout;计划在 4.0 移除。 */\nexport const ReverseHorizontalMixLayout = C_ReverseHorizontalMixLayout;\n/** @deprecated 请使用 C_CardLayout;计划在 4.0 移除。 */\nexport const CardLayout = C_CardLayout;\n"],"mappings":"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"}
|