@robot-admin/naive-ui-components 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/C_ActionBar-nnfbZCea.css.map +1 -0
- package/dist/C_ActionBar2.js +2 -2
- package/dist/C_ActionBar2.js.map +1 -1
- package/dist/C_AntV-DGjscTWa.css.map +1 -0
- package/dist/C_AntV2.js +6 -6
- package/dist/C_AntV2.js.map +1 -1
- package/dist/C_Barcode-DjTmDkbQ.css.map +1 -0
- package/dist/C_Barcode2.js +1 -1
- package/dist/C_Barcode2.js.map +1 -1
- package/dist/C_Captcha-Ccq3DMrR.css.map +1 -0
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Captcha2.js.map +1 -1
- package/dist/C_Cascade-IUUHIh7r.css.map +1 -0
- package/dist/C_Cascade2.js +2 -2
- package/dist/C_Cascade2.js.map +1 -1
- package/dist/C_City-Cv5BESaN.css.map +1 -0
- package/dist/C_City2.js +2 -2
- package/dist/C_City2.js.map +1 -1
- package/dist/C_Code-DPZlNSxL.css.map +1 -0
- package/dist/C_Code2.js +8 -7
- package/dist/C_Code2.js.map +1 -1
- package/dist/C_CollapsePanel-Fap-lv_5.css.map +1 -0
- package/dist/C_CollapsePanel2.js +1 -1
- package/dist/C_CollapsePanel2.js.map +1 -1
- package/dist/C_Cron-C0-8b5af.css.map +1 -0
- package/dist/C_Cron2.js +15 -14
- package/dist/C_Cron2.js.map +1 -1
- package/dist/C_Date2.js +1 -1
- package/dist/C_Date2.js.map +1 -1
- package/dist/C_Draggable-Bq6o0qXn.css.map +1 -0
- package/dist/C_Draggable2.js +1 -1
- package/dist/C_Draggable2.js.map +1 -1
- package/dist/C_Editor-OlxIF9-5.css.map +1 -0
- package/dist/C_Editor2.js +1 -1
- package/dist/C_Editor2.js.map +1 -1
- package/dist/C_FilePreview-B4XgTv-h.css.map +1 -0
- package/dist/C_FilePreview.cjs +1 -0
- package/dist/C_FilePreview.js +1 -0
- package/dist/C_FilePreview2.js +10 -9
- package/dist/C_FilePreview2.js.map +1 -1
- package/dist/C_Form-Cr9oX037.css.map +1 -0
- package/dist/C_Form2.js +48 -48
- package/dist/C_Form2.js.map +1 -1
- package/dist/C_FormSearch-DlIEoh7X.css.map +1 -0
- package/dist/C_FormSearch2.js +2 -2
- package/dist/C_FormSearch2.js.map +1 -1
- package/dist/C_FormulaEditor-Cm0CokN5.css.map +1 -0
- package/dist/C_FormulaEditor2.js +6 -6
- package/dist/C_FormulaEditor2.js.map +1 -1
- package/dist/C_FullCalendar-BULCIlVK.css.map +1 -0
- package/dist/C_FullCalendar2.js +2 -2
- package/dist/C_FullCalendar2.js.map +1 -1
- package/dist/C_Guide2.js +1 -1
- package/dist/C_Guide2.js.map +1 -1
- package/dist/C_Icon2.js.map +1 -1
- package/dist/C_ImageCropper-DrmUlaLi.css.map +1 -0
- package/dist/C_ImageCropper2.js +4 -4
- package/dist/C_ImageCropper2.js.map +1 -1
- package/dist/C_Language2.js +1 -1
- package/dist/C_Language2.js.map +1 -1
- package/dist/C_Map-WUMXSAfy.css.map +1 -0
- package/dist/C_Map2.js +2 -2
- package/dist/C_Map2.js.map +1 -1
- package/dist/C_Markdown-Dmv8yaM4.css.map +1 -0
- package/dist/C_Markdown2.js +4 -4
- package/dist/C_Markdown2.js.map +1 -1
- package/dist/C_NotificationCenter-DbgBiyqB.css.map +1 -0
- package/dist/C_NotificationCenter2.js +21 -20
- package/dist/C_NotificationCenter2.js.map +1 -1
- package/dist/C_Progress2.js +1 -1
- package/dist/C_Progress2.js.map +1 -1
- package/dist/C_QRCode-G7fiAkm4.css.map +1 -0
- package/dist/C_QRCode2.js +1 -1
- package/dist/C_QRCode2.js.map +1 -1
- package/dist/C_Signature-es-ZNPzr.css.map +1 -0
- package/dist/C_Signature2.js +2 -2
- package/dist/C_Signature2.js.map +1 -1
- package/dist/C_SplitPane-Br2eK8IG.css.map +1 -0
- package/dist/C_SplitPane2.js +1 -1
- package/dist/C_SplitPane2.js.map +1 -1
- package/dist/C_Steps-P9Qj9iDd.css.map +1 -0
- package/dist/C_Steps2.js +1 -1
- package/dist/C_Steps2.js.map +1 -1
- package/dist/C_Table-DAwAxr72.css.map +1 -0
- package/dist/C_Table2.js +3 -3
- package/dist/C_Table2.js.map +1 -1
- package/dist/C_Theme2.js +1 -1
- package/dist/C_Theme2.js.map +1 -1
- package/dist/C_Time-Bd_e1YDN.css.map +1 -0
- package/dist/C_Time2.js +2 -2
- package/dist/C_Time2.js.map +1 -1
- package/dist/C_Tree-DnGc_MPb.css.map +1 -0
- package/dist/C_Tree2.js +2 -2
- package/dist/C_Tree2.js.map +1 -1
- package/dist/C_Upload-i8LB_29U.css.map +1 -0
- package/dist/C_Upload2.js +5 -5
- package/dist/C_Upload2.js.map +1 -1
- package/dist/C_VideoPlayer-rm0MODUv.css.map +1 -0
- package/dist/C_VideoPlayer2.js +21 -20
- package/dist/C_VideoPlayer2.js.map +1 -1
- package/dist/C_VtableGantt-BpY-Rng3.css.map +1 -0
- package/dist/C_VtableGantt2.js +2 -2
- package/dist/C_VtableGantt2.js.map +1 -1
- package/dist/C_WaterFall-HWB-gPON.css.map +1 -0
- package/dist/C_WaterFall2.js +2 -2
- package/dist/C_WaterFall2.js.map +1 -1
- package/dist/C_WorkFlow-CSO86Cuc.css.map +1 -0
- package/dist/C_WorkFlow2.js +6 -6
- package/dist/C_WorkFlow2.js.map +1 -1
- package/dist/constants2.d.ts +2 -2
- package/dist/constants3.d.ts +2 -2
- package/dist/constants4.d.ts +5 -5
- package/dist/constants5.d.ts +2 -2
- package/dist/data.d.ts +1 -1
- package/dist/index.vue.d.ts +1 -1
- package/dist/index10.vue.d.ts +5 -5
- package/dist/index12.vue.d.ts +1 -1
- package/dist/index12.vue.d.ts.map +1 -1
- package/dist/index13.vue.d.ts +1 -1
- package/dist/index16.vue.d.ts +3 -3
- package/dist/index16.vue.d.ts.map +1 -1
- package/dist/index2.vue.d.ts +5 -5
- package/dist/index3.vue.d.ts +4 -4
- package/dist/index6.vue.d.ts +3 -3
- package/dist/index8.vue.d.ts +2 -2
- package/dist/style.css +1555 -1555
- package/dist/useCropperCore.d.ts +7 -7
- package/dist/useDraggableLayout.d.ts +9 -9
- package/dist/useDynamicFormState.d.ts +9 -9
- package/dist/useDynamicFormState.d.ts.map +1 -1
- package/dist/useEdgeInteraction.d.ts +2 -2
- package/dist/useInfiniteScroll.d.ts +2 -2
- package/dist/useModalEdit.d.ts +2 -2
- package/dist/useModalEdit.d.ts.map +1 -1
- package/dist/useQRCode.d.ts +2 -2
- package/dist/useSearchState.d.ts +2 -2
- package/dist/useSignatureHistory.d.ts +3 -3
- package/dist/useSplitResize.d.ts +6 -6
- package/dist/useSplitResize.d.ts.map +1 -1
- package/dist/useTimeSelection.d.ts +1 -1
- package/dist/useTreeOperations.d.ts +3 -3
- package/dist/useWorkflowValidation.d.ts +1 -1
- package/package.json +2 -1
- package/dist/C_ActionBar-DWN-woTc.css.map +0 -1
- package/dist/C_AntV-AFKyK6hH.css.map +0 -1
- package/dist/C_Barcode-P_EFj8dC.css.map +0 -1
- package/dist/C_Captcha-C-ef41xw.css.map +0 -1
- package/dist/C_Cascade-D9kNsjsV.css.map +0 -1
- package/dist/C_City-BCQ4ipiK.css.map +0 -1
- package/dist/C_Code-C9kvvEmO.css.map +0 -1
- package/dist/C_CollapsePanel-BUJHuYcU.css.map +0 -1
- package/dist/C_Cron-yx2Ob4Jl.css.map +0 -1
- package/dist/C_Draggable-C483syRC.css.map +0 -1
- package/dist/C_Editor-Bp0SyIEw.css.map +0 -1
- package/dist/C_FilePreview-CPqvhoCy.css.map +0 -1
- package/dist/C_Form-Jx7PY3sT.css.map +0 -1
- package/dist/C_FormSearch-DvRgxlRn.css.map +0 -1
- package/dist/C_FormulaEditor-DtGkt4T_.css.map +0 -1
- package/dist/C_FullCalendar-BF7H0YIx.css.map +0 -1
- package/dist/C_ImageCropper-BVJfUufl.css.map +0 -1
- package/dist/C_Map-DpzeuWdX.css.map +0 -1
- package/dist/C_Markdown-BEjxknqd.css.map +0 -1
- package/dist/C_NotificationCenter-0l3TY2Gn.css.map +0 -1
- package/dist/C_QRCode-DbdiAIPg.css.map +0 -1
- package/dist/C_Signature-zhHCbra9.css.map +0 -1
- package/dist/C_SplitPane-C6sBsfKY.css.map +0 -1
- package/dist/C_Steps-CODHN5Hs.css.map +0 -1
- package/dist/C_Table-DSNsntmT.css.map +0 -1
- package/dist/C_Time-BvZLYraL.css.map +0 -1
- package/dist/C_Tree-0GDv--jX.css.map +0 -1
- package/dist/C_Upload-BXd3YYLx.css.map +0 -1
- package/dist/C_VideoPlayer-DYG3RL0Q.css.map +0 -1
- package/dist/C_VtableGantt-fhItIiHE.css.map +0 -1
- package/dist/C_WaterFall-8sQDFXKg.css.map +0 -1
- package/dist/C_WorkFlow-J-dyIuh9.css.map +0 -1
package/dist/C_Code2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Code2.js","names":["showHeader","title","language","showFullscreen","code","showLineNumbers","wordWrap","trim"],"sources":["../src/components/C_Code/index.vue","../src/components/C_Code/index.vue","../src/components/C_Code/index.vue"],"sourcesContent":["<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_Code2.js","names":["showHeader","title","language","showFullscreen","code","showLineNumbers","wordWrap","trim"],"sources":["../src/components/C_Code/index.vue","../src/components/C_Code/index.vue","../src/components/C_Code/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"C_CollapsePanel-Fap-lv_5.css","names":[],"sources":["../src/components/C_CollapsePanel/index.vue?vue&type=style&index=0&scoped=0ab400c1&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* ─── 变量 ───────────────────────────────────────── */\n/* ─── 容器 ───────────────────────────────────────── */\n.c-collapse-panel[data-v-0ab400c1] {\n width: 100%;\n /* ── default 变体 ────────────────────────────── */\n /* ── card 变体 ───────────────────────────────── */\n /* ── ghost 变体(无边框极简) ──────────────────── */\n /* ── bordered 修饰符 ─────────────────────────── */\n /* ── 图标右侧模式 ────────────────────────────── */\n}\n.c-collapse-panel--default .collapse-item[data-v-0ab400c1] {\n border-bottom: 1px solid var(--c-border, #e1e4e8);\n}\n.c-collapse-panel--default .collapse-item[data-v-0ab400c1]:last-child {\n border-bottom: none;\n}\n.c-collapse-panel--card[data-v-0ab400c1] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.c-collapse-panel--card .collapse-item[data-v-0ab400c1] {\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: 8px;\n background: var(--c-bg-card, #fff);\n transition: box-shadow 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.c-collapse-panel--card .collapse-item--active[data-v-0ab400c1] {\n box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);\n}\n.c-collapse-panel--card .collapse-item[data-v-0ab400c1]:hover:not(.collapse-item--disabled) {\n border-color: var(--c-primary, #409eff);\n}\n.c-collapse-panel--ghost .collapse-item__header[data-v-0ab400c1] {\n background: transparent;\n}\n.c-collapse-panel--ghost .collapse-item__header[data-v-0ab400c1]:hover {\n background: var(--c-bg-card, #fff);\n}\n.c-collapse-panel--ghost .collapse-item__content[data-v-0ab400c1] {\n padding-left: 28px;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default[data-v-0ab400c1] {\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: 8px;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default .collapse-item:first-child .collapse-item__header[data-v-0ab400c1] {\n border-radius: 8px 8px 0 0;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default .collapse-item[data-v-0ab400c1]:last-child {\n border-bottom: none;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default .collapse-item:last-child .collapse-item__header[data-v-0ab400c1] {\n border-radius: 0 0 8px 8px;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default .collapse-item:last-child.collapse-item--active .collapse-item__header[data-v-0ab400c1] {\n border-radius: 0;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default .collapse-item:only-child .collapse-item__header[data-v-0ab400c1] {\n border-radius: 8px;\n}\n.c-collapse-panel--bordered.c-collapse-panel--default .collapse-item:only-child.collapse-item--active .collapse-item__header[data-v-0ab400c1] {\n border-radius: 8px 8px 0 0;\n}\n.c-collapse-panel--icon-right .collapse-item__header[data-v-0ab400c1] {\n flex-direction: row-reverse;\n}\n.c-collapse-panel--icon-right .collapse-item__arrow[data-v-0ab400c1] {\n margin-left: auto;\n margin-right: 0;\n}\n.c-collapse-panel--icon-right .collapse-item__title-area[data-v-0ab400c1] {\n margin-left: 0;\n}\n\n/* ─── 面板项 ─────────────────────────────────────── */\n.collapse-item--disabled .collapse-item__header[data-v-0ab400c1] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* ─── 面板头部 ───────────────────────────────────── */\n.collapse-item__header[data-v-0ab400c1] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n cursor: pointer;\n user-select: none;\n background: transparent;\n transition: background-color 0.15s ease;\n outline: none;\n}\n.collapse-item__header[data-v-0ab400c1]:hover:not([aria-disabled=true]) {\n background: var(--c-bg-hover, rgba(0, 0, 0, 0.04));\n}\n.collapse-item__header[data-v-0ab400c1]:focus-visible {\n outline: 2px solid var(--c-primary, #409eff);\n outline-offset: -2px;\n border-radius: 4px;\n}\n\n/* ─── 展开箭头 ───────────────────────────────────── */\n.collapse-item__arrow[data-v-0ab400c1] {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n font-size: 16px;\n color: var(--c-text-3, #999);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.collapse-item__arrow--expanded[data-v-0ab400c1] {\n transform: rotate(90deg);\n}\n\n/* ─── 标题区域 ───────────────────────────────────── */\n.collapse-item__title-area[data-v-0ab400c1] {\n flex: 1;\n min-width: 0;\n}\n.collapse-item__title-group[data-v-0ab400c1] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.collapse-item__icon[data-v-0ab400c1] {\n flex-shrink: 0;\n font-size: 18px;\n color: var(--c-primary, #409eff);\n}\n.collapse-item__title[data-v-0ab400c1] {\n font-size: 14px;\n font-weight: 600;\n color: var(--c-text-1, #333);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.collapse-item__subtitle[data-v-0ab400c1] {\n font-size: 12px;\n color: var(--c-text-4, #ccc);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* ─── 头部右侧操作区 ────────────────────────────── */\n.collapse-item__extra[data-v-0ab400c1] {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n/* ─── 内容区域 ───────────────────────────────────── */\n.collapse-item__content-wrapper[data-v-0ab400c1] {\n transition: height 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n will-change: height;\n}\n.collapse-item__content[data-v-0ab400c1] {\n padding: 0 16px 16px;\n font-size: 14px;\n line-height: 1.6;\n color: var(--c-text-2, #666);\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_CollapsePanel2.js
CHANGED
|
@@ -312,7 +312,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
|
|
|
312
312
|
|
|
313
313
|
//#endregion
|
|
314
314
|
//#region src/components/C_CollapsePanel/index.vue
|
|
315
|
-
var C_CollapsePanel_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
315
|
+
var C_CollapsePanel_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-0ab400c1"]]);
|
|
316
316
|
|
|
317
317
|
//#endregion
|
|
318
318
|
export { useCollapsePanel as n, C_CollapsePanel_default as t };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_CollapsePanel2.js","names":["variant","bordered","expandIconPosition","items","$slots"],"sources":["../src/components/C_CollapsePanel/composables/useCollapsePanel.ts","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue"],"sourcesContent":["import { ref, computed, watch } from 'vue'\r\nimport type { Ref } from 'vue'\r\nimport type { CollapsePanelItem } from '../types'\r\n\r\ninterface UseCollapsePanelOptions {\r\n /** 面板项配置 */\r\n items: Ref<CollapsePanelItem[]>\r\n /** 外部 v-model activeKeys */\r\n activeKeys: Ref<string[] | undefined>\r\n /** 非受控时的默认激活 key */\r\n defaultActiveKeys: string[]\r\n /** 是否手风琴模式 */\r\n accordion: Ref<boolean>\r\n /** localStorage 持久化 key */\r\n persistKey: Ref<string | undefined>\r\n /** activeKeys 变化回调 */\r\n onChange?: (keys: string[]) => void\r\n /** 单面板展开回调 */\r\n onExpand?: (key: string) => void\r\n /** 单面板折叠回调 */\r\n onCollapse?: (key: string) => void\r\n}\r\n\r\n/**\r\n * 折叠面板展开/折叠核心逻辑\r\n */\r\nexport function useCollapsePanel(options: UseCollapsePanelOptions) {\r\n const {\r\n items,\r\n activeKeys: externalKeys,\r\n defaultActiveKeys,\r\n accordion,\r\n persistKey,\r\n onChange,\r\n onExpand,\r\n onCollapse,\r\n } = options\r\n\r\n /* ─── 持久化读取 ──────────────────────────────── */\r\n const loadPersistedKeys = (): string[] | null => {\r\n if (!persistKey.value) return null\r\n try {\r\n const raw = localStorage.getItem(`collapse-panel:${persistKey.value}`)\r\n return raw ? JSON.parse(raw) : null\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const savePersistedKeys = (keys: string[]) => {\r\n if (!persistKey.value) return\r\n try {\r\n localStorage.setItem(\r\n `collapse-panel:${persistKey.value}`,\r\n JSON.stringify(keys),\r\n )\r\n } catch {\r\n /* 静默失败 */\r\n }\r\n }\r\n\r\n /* ─── 内部状态 ────────────────────────────────── */\r\n const resolveInitialKeys = (): string[] => {\r\n /* 优先级:外部 v-model > 持久化 > 默认值 */\r\n if (externalKeys.value !== undefined) return [...externalKeys.value]\r\n const persisted = loadPersistedKeys()\r\n if (persisted) return persisted\r\n return [...defaultActiveKeys]\r\n }\r\n\r\n const internalKeys = ref<string[]>(resolveInitialKeys())\r\n\r\n /** 懒渲染追踪:记录哪些面板曾被展开过 */\r\n const renderedOnce = ref<Set<string>>(new Set(internalKeys.value))\r\n\r\n /* ─── 计算属性 ────────────────────────────────── */\r\n /** 当前激活的 key 数组(兼容受控 / 非受控) */\r\n const currentKeys = computed<string[]>({\r\n get: () =>\r\n externalKeys.value !== undefined\r\n ? externalKeys.value\r\n : internalKeys.value,\r\n set: (val) => {\r\n internalKeys.value = val\r\n },\r\n })\r\n\r\n /**\r\n * 判断面板是否展开\r\n */\r\n const isExpanded = (key: string): boolean => {\r\n return currentKeys.value.includes(key)\r\n }\r\n\r\n /**\r\n * 判断面板是否应该渲染内容\r\n * - lazy 面板只有被展开过至少一次后才渲染\r\n * - destroyOnCollapse 面板在折叠后销毁 DOM\r\n */\r\n const shouldRender = (item: CollapsePanelItem): boolean => {\r\n const expanded = isExpanded(item.key)\r\n\r\n if (item.destroyOnCollapse) return expanded\r\n if (item.lazy) return renderedOnce.value.has(item.key)\r\n return true\r\n }\r\n\r\n /* ─── 操作方法 ────────────────────────────────── */\r\n const updateKeys = (newKeys: string[]) => {\r\n currentKeys.value = newKeys\r\n onChange?.(newKeys)\r\n savePersistedKeys(newKeys)\r\n }\r\n\r\n const toggle = (key: string) => {\r\n const item = items.value.find((i) => i.key === key)\r\n if (!item || item.disabled) return\r\n\r\n const expanded = isExpanded(key)\r\n\r\n if (expanded) {\r\n /* 折叠 */\r\n updateKeys(currentKeys.value.filter((k) => k !== key))\r\n onCollapse?.(key)\r\n } else {\r\n /* 展开 */\r\n renderedOnce.value.add(key)\r\n\r\n if (accordion.value) {\r\n /* 手风琴模式:关闭其他面板 */\r\n const prevKeys = currentKeys.value\r\n updateKeys([key])\r\n /* 通知被折叠的面板 */\r\n prevKeys.forEach((k) => {\r\n if (k !== key) onCollapse?.(k)\r\n })\r\n } else {\r\n updateKeys([...currentKeys.value, key])\r\n }\r\n onExpand?.(key)\r\n }\r\n }\r\n\r\n const expandAll = () => {\r\n if (accordion.value) return /* 手风琴模式不支持全展开 */\r\n\r\n const allKeys = items.value.filter((i) => !i.disabled).map((i) => i.key)\r\n\r\n allKeys.forEach((k) => renderedOnce.value.add(k))\r\n updateKeys(allKeys)\r\n }\r\n\r\n const collapseAll = () => {\r\n updateKeys([])\r\n }\r\n\r\n const getActiveKeys = (): string[] => {\r\n return [...currentKeys.value]\r\n }\r\n\r\n /* ─── 键盘导航 ────────────────────────────────── */\r\n const handleKeyDown = (e: KeyboardEvent, key: string) => {\r\n if (['Enter', ' '].includes(e.key)) {\r\n e.preventDefault()\r\n toggle(key)\r\n }\r\n }\r\n\r\n /* ─── 同步外部 v-model 变化 ───────────────────── */\r\n watch(\r\n () => externalKeys.value,\r\n (newVal) => {\r\n if (newVal !== undefined) {\r\n internalKeys.value = [...newVal]\r\n newVal.forEach((k) => renderedOnce.value.add(k))\r\n savePersistedKeys(newVal)\r\n }\r\n },\r\n )\r\n\r\n return {\r\n currentKeys,\r\n renderedOnce,\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n }\r\n}\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"(el) => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" :size=\"16\" color=\"currentColor\" />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span v-if=\"item.subtitle\" class=\"collapse-item__subtitle\">\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div v-if=\"shouldRender(item)\" class=\"collapse-item__content\">\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, toRef } from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useCollapsePanel } from \"./composables/useCollapsePanel\";\r\nimport type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_CollapsePanel\" });\r\n\r\ninterface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[];\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[];\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[];\r\n /** 是否手风琴模式 */\r\n accordion?: boolean;\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant;\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition;\r\n /** 是否显示边框 */\r\n bordered?: boolean;\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: \"default\",\r\n expandIconPosition: \"left\",\r\n bordered: true,\r\n persistKey: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:activeKeys\": [keys: string[]];\r\n expand: [key: string];\r\n collapse: [key: string];\r\n change: [activeKeys: string[]];\r\n}>();\r\n\r\nconst containerRef = ref<HTMLElement | null>(null);\r\nconst panelRefs = ref<Map<string, HTMLElement>>(new Map());\r\n\r\nconst setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el);\r\n } else {\r\n panelRefs.value.delete(key);\r\n }\r\n};\r\n\r\nconst {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n} = useCollapsePanel({\r\n items: toRef(props, \"items\"),\r\n activeKeys: toRef(props, \"activeKeys\"),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, \"accordion\"),\r\n persistKey: toRef(props, \"persistKey\"),\r\n onChange: (keys) => {\r\n emit(\"update:activeKeys\", keys);\r\n emit(\"change\", keys);\r\n },\r\n onExpand: (key) => emit(\"expand\", key),\r\n onCollapse: (key) => emit(\"collapse\", key),\r\n});\r\n\r\n/* ─── 展开/折叠动画 ──────────────────────────── */\r\nconst onEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"0\";\r\n element.style.overflow = \"hidden\";\r\n /* 强制 reflow */\r\n void element.offsetHeight;\r\n element.style.height = `${element.scrollHeight}px`;\r\n};\r\n\r\nconst onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\nconst onLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = `${element.scrollHeight}px`;\r\n element.style.overflow = \"hidden\";\r\n void element.offsetHeight;\r\n element.style.height = \"0\";\r\n};\r\n\r\nconst onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\n/* ─── 滚动到指定面板 ─────────────────────────── */\r\nconst scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key);\r\n if (el) {\r\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n\r\n/* ─── 暴露方法 ──────────────────────────────── */\r\ndefineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"(el) => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" :size=\"16\" color=\"currentColor\" />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span v-if=\"item.subtitle\" class=\"collapse-item__subtitle\">\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div v-if=\"shouldRender(item)\" class=\"collapse-item__content\">\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, toRef } from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useCollapsePanel } from \"./composables/useCollapsePanel\";\r\nimport type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_CollapsePanel\" });\r\n\r\ninterface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[];\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[];\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[];\r\n /** 是否手风琴模式 */\r\n accordion?: boolean;\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant;\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition;\r\n /** 是否显示边框 */\r\n bordered?: boolean;\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: \"default\",\r\n expandIconPosition: \"left\",\r\n bordered: true,\r\n persistKey: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:activeKeys\": [keys: string[]];\r\n expand: [key: string];\r\n collapse: [key: string];\r\n change: [activeKeys: string[]];\r\n}>();\r\n\r\nconst containerRef = ref<HTMLElement | null>(null);\r\nconst panelRefs = ref<Map<string, HTMLElement>>(new Map());\r\n\r\nconst setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el);\r\n } else {\r\n panelRefs.value.delete(key);\r\n }\r\n};\r\n\r\nconst {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n} = useCollapsePanel({\r\n items: toRef(props, \"items\"),\r\n activeKeys: toRef(props, \"activeKeys\"),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, \"accordion\"),\r\n persistKey: toRef(props, \"persistKey\"),\r\n onChange: (keys) => {\r\n emit(\"update:activeKeys\", keys);\r\n emit(\"change\", keys);\r\n },\r\n onExpand: (key) => emit(\"expand\", key),\r\n onCollapse: (key) => emit(\"collapse\", key),\r\n});\r\n\r\n/* ─── 展开/折叠动画 ──────────────────────────── */\r\nconst onEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"0\";\r\n element.style.overflow = \"hidden\";\r\n /* 强制 reflow */\r\n void element.offsetHeight;\r\n element.style.height = `${element.scrollHeight}px`;\r\n};\r\n\r\nconst onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\nconst onLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = `${element.scrollHeight}px`;\r\n element.style.overflow = \"hidden\";\r\n void element.offsetHeight;\r\n element.style.height = \"0\";\r\n};\r\n\r\nconst onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\n/* ─── 滚动到指定面板 ─────────────────────────── */\r\nconst scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key);\r\n if (el) {\r\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n\r\n/* ─── 暴露方法 ──────────────────────────────── */\r\ndefineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"(el) => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" :size=\"16\" color=\"currentColor\" />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span v-if=\"item.subtitle\" class=\"collapse-item__subtitle\">\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div v-if=\"shouldRender(item)\" class=\"collapse-item__content\">\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, toRef } from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useCollapsePanel } from \"./composables/useCollapsePanel\";\r\nimport type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_CollapsePanel\" });\r\n\r\ninterface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[];\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[];\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[];\r\n /** 是否手风琴模式 */\r\n accordion?: boolean;\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant;\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition;\r\n /** 是否显示边框 */\r\n bordered?: boolean;\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: \"default\",\r\n expandIconPosition: \"left\",\r\n bordered: true,\r\n persistKey: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:activeKeys\": [keys: string[]];\r\n expand: [key: string];\r\n collapse: [key: string];\r\n change: [activeKeys: string[]];\r\n}>();\r\n\r\nconst containerRef = ref<HTMLElement | null>(null);\r\nconst panelRefs = ref<Map<string, HTMLElement>>(new Map());\r\n\r\nconst setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el);\r\n } else {\r\n panelRefs.value.delete(key);\r\n }\r\n};\r\n\r\nconst {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n} = useCollapsePanel({\r\n items: toRef(props, \"items\"),\r\n activeKeys: toRef(props, \"activeKeys\"),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, \"accordion\"),\r\n persistKey: toRef(props, \"persistKey\"),\r\n onChange: (keys) => {\r\n emit(\"update:activeKeys\", keys);\r\n emit(\"change\", keys);\r\n },\r\n onExpand: (key) => emit(\"expand\", key),\r\n onCollapse: (key) => emit(\"collapse\", key),\r\n});\r\n\r\n/* ─── 展开/折叠动画 ──────────────────────────── */\r\nconst onEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"0\";\r\n element.style.overflow = \"hidden\";\r\n /* 强制 reflow */\r\n void element.offsetHeight;\r\n element.style.height = `${element.scrollHeight}px`;\r\n};\r\n\r\nconst onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\nconst onLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = `${element.scrollHeight}px`;\r\n element.style.overflow = \"hidden\";\r\n void element.offsetHeight;\r\n element.style.height = \"0\";\r\n};\r\n\r\nconst onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\n/* ─── 滚动到指定面板 ─────────────────────────── */\r\nconst scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key);\r\n if (el) {\r\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n\r\n/* ─── 暴露方法 ──────────────────────────────── */\r\ndefineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":";;;;;;;;AA0BA,SAAgB,iBAAiB,SAAkC;CACjE,MAAM,EACJ,OACA,YAAY,cACZ,mBACA,WACA,YACA,UACA,UACA,eACE;CAGJ,MAAM,0BAA2C;AAC/C,MAAI,CAAC,WAAW,MAAO,QAAO;AAC9B,MAAI;GACF,MAAM,MAAM,aAAa,QAAQ,kBAAkB,WAAW,QAAQ;AACtE,UAAO,MAAM,KAAK,MAAM,IAAI,GAAG;UACzB;AACN,UAAO;;;CAIX,MAAM,qBAAqB,SAAmB;AAC5C,MAAI,CAAC,WAAW,MAAO;AACvB,MAAI;AACF,gBAAa,QACX,kBAAkB,WAAW,SAC7B,KAAK,UAAU,KAAK,CACrB;UACK;;CAMV,MAAM,2BAAqC;AAEzC,MAAI,aAAa,UAAU,OAAW,QAAO,CAAC,GAAG,aAAa,MAAM;EACpE,MAAM,YAAY,mBAAmB;AACrC,MAAI,UAAW,QAAO;AACtB,SAAO,CAAC,GAAG,kBAAkB;;CAG/B,MAAM,eAAe,IAAc,oBAAoB,CAAC;;CAGxD,MAAM,eAAe,IAAiB,IAAI,IAAI,aAAa,MAAM,CAAC;;CAIlE,MAAM,cAAc,SAAmB;EACrC,WACE,aAAa,UAAU,SACnB,aAAa,QACb,aAAa;EACnB,MAAM,QAAQ;AACZ,gBAAa,QAAQ;;EAExB,CAAC;;;;CAKF,MAAM,cAAc,QAAyB;AAC3C,SAAO,YAAY,MAAM,SAAS,IAAI;;;;;;;CAQxC,MAAM,gBAAgB,SAAqC;EACzD,MAAM,WAAW,WAAW,KAAK,IAAI;AAErC,MAAI,KAAK,kBAAmB,QAAO;AACnC,MAAI,KAAK,KAAM,QAAO,aAAa,MAAM,IAAI,KAAK,IAAI;AACtD,SAAO;;CAIT,MAAM,cAAc,YAAsB;AACxC,cAAY,QAAQ;AACpB,aAAW,QAAQ;AACnB,oBAAkB,QAAQ;;CAG5B,MAAM,UAAU,QAAgB;EAC9B,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,QAAQ,IAAI;AACnD,MAAI,CAAC,QAAQ,KAAK,SAAU;AAI5B,MAFiB,WAAW,IAAI,EAElB;AAEZ,cAAW,YAAY,MAAM,QAAQ,MAAM,MAAM,IAAI,CAAC;AACtD,gBAAa,IAAI;SACZ;AAEL,gBAAa,MAAM,IAAI,IAAI;AAE3B,OAAI,UAAU,OAAO;IAEnB,MAAM,WAAW,YAAY;AAC7B,eAAW,CAAC,IAAI,CAAC;AAEjB,aAAS,SAAS,MAAM;AACtB,SAAI,MAAM,IAAK,cAAa,EAAE;MAC9B;SAEF,YAAW,CAAC,GAAG,YAAY,OAAO,IAAI,CAAC;AAEzC,cAAW,IAAI;;;CAInB,MAAM,kBAAkB;AACtB,MAAI,UAAU,MAAO;EAErB,MAAM,UAAU,MAAM,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,MAAM,EAAE,IAAI;AAExE,UAAQ,SAAS,MAAM,aAAa,MAAM,IAAI,EAAE,CAAC;AACjD,aAAW,QAAQ;;CAGrB,MAAM,oBAAoB;AACxB,aAAW,EAAE,CAAC;;CAGhB,MAAM,sBAAgC;AACpC,SAAO,CAAC,GAAG,YAAY,MAAM;;CAI/B,MAAM,iBAAiB,GAAkB,QAAgB;AACvD,MAAI,CAAC,SAAS,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE;AAClC,KAAE,gBAAgB;AAClB,UAAO,IAAI;;;AAKf,aACQ,aAAa,QAClB,WAAW;AACV,MAAI,WAAW,QAAW;AACxB,gBAAa,QAAQ,CAAC,GAAG,OAAO;AAChC,UAAO,SAAS,MAAM,aAAa,MAAM,IAAI,EAAE,CAAC;AAChD,qBAAkB,OAAO;;GAG9B;AAED,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EE7CH,MAAM,QAAQ;EAUd,MAAM,OAAO;EAOb,MAAM,eAAe,IAAwB,KAAK;EAClD,MAAM,YAAY,oBAA8B,IAAI,KAAK,CAAC;EAE1D,MAAM,eAAe,KAAa,OAA2B;AAC3D,OAAI,GACF,WAAU,MAAM,IAAI,KAAK,GAAG;OAE5B,WAAU,MAAM,OAAO,IAAI;;EAI/B,MAAM,EACJ,YACA,cACA,QACA,WACA,aACA,eACA,kBACE,iBAAiB;GACnB,OAAO,MAAM,OAAO,QAAQ;GAC5B,YAAY,MAAM,OAAO,aAAa;GACtC,mBAAmB,MAAM;GACzB,WAAW,MAAM,OAAO,YAAY;GACpC,YAAY,MAAM,OAAO,aAAa;GACtC,WAAW,SAAS;AAClB,SAAK,qBAAqB,KAAK;AAC/B,SAAK,UAAU,KAAK;;GAEtB,WAAW,QAAQ,KAAK,UAAU,IAAI;GACtC,aAAa,QAAQ,KAAK,YAAY,IAAI;GAC3C,CAAC;EAGF,MAAM,WAAW,OAAgB;GAC/B,MAAM,UAAU;AAChB,WAAQ,MAAM,SAAS;AACvB,WAAQ,MAAM,WAAW;AAEzB,GAAK,QAAQ;AACb,WAAQ,MAAM,SAAS,GAAG,QAAQ,aAAa;;EAGjD,MAAM,gBAAgB,OAAgB;GACpC,MAAM,UAAU;AAChB,WAAQ,MAAM,SAAS;AACvB,WAAQ,MAAM,WAAW;;EAG3B,MAAM,WAAW,OAAgB;GAC/B,MAAM,UAAU;AAChB,WAAQ,MAAM,SAAS,GAAG,QAAQ,aAAa;AAC/C,WAAQ,MAAM,WAAW;AACzB,GAAK,QAAQ;AACb,WAAQ,MAAM,SAAS;;EAGzB,MAAM,gBAAgB,OAAgB;GACpC,MAAM,UAAU;AAChB,WAAQ,MAAM,SAAS;AACvB,WAAQ,MAAM,WAAW;;EAI3B,MAAM,iBAAiB,QAAgB;GACrC,MAAM,KAAK,UAAU,MAAM,IAAI,IAAI;AACnC,OAAI,GACF,IAAG,eAAe;IAAE,UAAU;IAAU,OAAO;IAAS,CAAC;;AAK7D,WAAkC;GAChC;GACA;GACA;GACA;GACA;GACD,CAAC;;uBAxOA,mBAsGM,OAAA;aArGA;IAAJ,KAAI;IACJ,OAAK,eAAA,CAAC,oBAAkB,sBACcA,KAAAA;mCAA2DC,KAAAA;qCAAmDC,KAAAA,uBAAkB;;yBAQtK,mBA0FM,UAAA,MAAA,WAzFWC,KAAAA,QAAR,SAAI;wBADb,mBA0FM,OAAA;KAxFH,KAAK,KAAK;;KACV,MAAM,OAAO,YAAY,KAAK,KAAK,GAAE;KACtC,OAAK,eAAA,CAAC,iBAAe;+BACuB,MAAA,WAAU,CAAC,KAAK,IAAG;iCAAuC,KAAK;;;KAK3G,mBAAA,SAAa;KACb,mBAqDM,OAAA;MApDJ,OAAM;MACN,MAAK;MACJ,iBAAe,MAAA,WAAU,CAAC,KAAK,IAAG;MAClC,iBAAa,oBAAsB,KAAK;MACxC,iBAAe,KAAK;MACpB,UAAU,KAAK,WAAQ,KAAA;MACvB,UAAK,WAAA,CAAG,KAAK,YAAY,MAAA,OAAM,CAAC,KAAK,IAAG;MACxC,YAAO,WAAE,MAAA,cAAa,CAAC,QAAQ,KAAK,IAAG;;MAExC,mBAAA,SAAa;MACb,mBAKO,QAAA,EAJL,OAAK,eAAA,CAAC,wBAAsB,EAAA,kCACgB,MAAA,WAAU,CAAC,KAAK,IAAG,EAAA,CAAA,CAAA,KAE/D,YAAmE,gBAAA;OAA3D,MAAK;OAAqB,MAAM;OAAI,OAAM;;MAGpD,mBAAA,SAAa;MACb,mBAoBM,OApBN,YAoBM,CAnBJ,WAkBO,KAAA,QAAA,UAjBY,KAAK,OAAG;OAClB;OACN,UAAU,MAAA,WAAU,CAAC,KAAK,IAAG;eAezB,CAbL,mBAYM,OAZN,YAYM;OAVI,KAAK,qBADb,YAME,gBAAA;;QAJC,MAAM,KAAK;QACX,MAAM;QACP,OAAM;QACN,OAAM;;OAER,mBAA0D,QAA1D,YAA0D,gBAApB,KAAK,MAAK,EAAA,EAAA;OACpC,KAAK,yBAAjB,mBAEO,QAFP,YAEO,gBADF,KAAK,SAAQ,EAAA,EAAA;;MAMxB,mBAAA,YAAgB;MAERC,KAAAA,OAAM,SAAU,KAAK,uBAD7B,mBAUM,OAAA;;OARJ,OAAM;OACL,SAAK,OAAA,OAAA,OAAA,KAAA,oBAAN,IAAW,CAAA,OAAA,CAAA;UAEX,WAIE,KAAA,QAAA,SAHgB,KAAK,OAAG;OACjB;OACN,UAAU,MAAA,WAAU,CAAC,KAAK,IAAG;;;KAKpC,mBAAA,SAAa;KACb,YAsBa,YAAA;MArBX,MAAK;MACG;MACM;MACN;MACM;MALhB,WAAA;;6BAqBQ,gBAdN,mBAcM,OAAA;OAZH,IAAE,oBAAsB,KAAK;OAC9B,OAAM;OACN,MAAK;OACJ,mBAAe,mBAAqB,KAAK;UAE/B,MAAA,aAAY,CAAC,KAAI,iBAA5B,mBAMM,OANN,YAMM,CALJ,WAIE,KAAA,QAAA,SAHgB,KAAK,OAAG;OACjB;OACN,UAAU,MAAA,WAAU,CAAC,KAAK,IAAG;wFAV1B,MAAA,WAAU,CAAC,KAAK,IAAG,CAAA"}
|
|
1
|
+
{"version":3,"file":"C_CollapsePanel2.js","names":["variant","bordered","expandIconPosition","items","$slots"],"sources":["../src/components/C_CollapsePanel/composables/useCollapsePanel.ts","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue","../src/components/C_CollapsePanel/index.vue"],"sourcesContent":["import { ref, computed, watch } from 'vue'\r\nimport type { Ref } from 'vue'\r\nimport type { CollapsePanelItem } from '../types'\r\n\r\ninterface UseCollapsePanelOptions {\r\n /** 面板项配置 */\r\n items: Ref<CollapsePanelItem[]>\r\n /** 外部 v-model activeKeys */\r\n activeKeys: Ref<string[] | undefined>\r\n /** 非受控时的默认激活 key */\r\n defaultActiveKeys: string[]\r\n /** 是否手风琴模式 */\r\n accordion: Ref<boolean>\r\n /** localStorage 持久化 key */\r\n persistKey: Ref<string | undefined>\r\n /** activeKeys 变化回调 */\r\n onChange?: (keys: string[]) => void\r\n /** 单面板展开回调 */\r\n onExpand?: (key: string) => void\r\n /** 单面板折叠回调 */\r\n onCollapse?: (key: string) => void\r\n}\r\n\r\n/**\r\n * 折叠面板展开/折叠核心逻辑\r\n */\r\nexport function useCollapsePanel(options: UseCollapsePanelOptions) {\r\n const {\r\n items,\r\n activeKeys: externalKeys,\r\n defaultActiveKeys,\r\n accordion,\r\n persistKey,\r\n onChange,\r\n onExpand,\r\n onCollapse,\r\n } = options\r\n\r\n /* ─── 持久化读取 ──────────────────────────────── */\r\n const loadPersistedKeys = (): string[] | null => {\r\n if (!persistKey.value) return null\r\n try {\r\n const raw = localStorage.getItem(`collapse-panel:${persistKey.value}`)\r\n return raw ? JSON.parse(raw) : null\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n const savePersistedKeys = (keys: string[]) => {\r\n if (!persistKey.value) return\r\n try {\r\n localStorage.setItem(\r\n `collapse-panel:${persistKey.value}`,\r\n JSON.stringify(keys),\r\n )\r\n } catch {\r\n /* 静默失败 */\r\n }\r\n }\r\n\r\n /* ─── 内部状态 ────────────────────────────────── */\r\n const resolveInitialKeys = (): string[] => {\r\n /* 优先级:外部 v-model > 持久化 > 默认值 */\r\n if (externalKeys.value !== undefined) return [...externalKeys.value]\r\n const persisted = loadPersistedKeys()\r\n if (persisted) return persisted\r\n return [...defaultActiveKeys]\r\n }\r\n\r\n const internalKeys = ref<string[]>(resolveInitialKeys())\r\n\r\n /** 懒渲染追踪:记录哪些面板曾被展开过 */\r\n const renderedOnce = ref<Set<string>>(new Set(internalKeys.value))\r\n\r\n /* ─── 计算属性 ────────────────────────────────── */\r\n /** 当前激活的 key 数组(兼容受控 / 非受控) */\r\n const currentKeys = computed<string[]>({\r\n get: () =>\r\n externalKeys.value !== undefined\r\n ? externalKeys.value\r\n : internalKeys.value,\r\n set: (val) => {\r\n internalKeys.value = val\r\n },\r\n })\r\n\r\n /**\r\n * 判断面板是否展开\r\n */\r\n const isExpanded = (key: string): boolean => {\r\n return currentKeys.value.includes(key)\r\n }\r\n\r\n /**\r\n * 判断面板是否应该渲染内容\r\n * - lazy 面板只有被展开过至少一次后才渲染\r\n * - destroyOnCollapse 面板在折叠后销毁 DOM\r\n */\r\n const shouldRender = (item: CollapsePanelItem): boolean => {\r\n const expanded = isExpanded(item.key)\r\n\r\n if (item.destroyOnCollapse) return expanded\r\n if (item.lazy) return renderedOnce.value.has(item.key)\r\n return true\r\n }\r\n\r\n /* ─── 操作方法 ────────────────────────────────── */\r\n const updateKeys = (newKeys: string[]) => {\r\n currentKeys.value = newKeys\r\n onChange?.(newKeys)\r\n savePersistedKeys(newKeys)\r\n }\r\n\r\n const toggle = (key: string) => {\r\n const item = items.value.find((i) => i.key === key)\r\n if (!item || item.disabled) return\r\n\r\n const expanded = isExpanded(key)\r\n\r\n if (expanded) {\r\n /* 折叠 */\r\n updateKeys(currentKeys.value.filter((k) => k !== key))\r\n onCollapse?.(key)\r\n } else {\r\n /* 展开 */\r\n renderedOnce.value.add(key)\r\n\r\n if (accordion.value) {\r\n /* 手风琴模式:关闭其他面板 */\r\n const prevKeys = currentKeys.value\r\n updateKeys([key])\r\n /* 通知被折叠的面板 */\r\n prevKeys.forEach((k) => {\r\n if (k !== key) onCollapse?.(k)\r\n })\r\n } else {\r\n updateKeys([...currentKeys.value, key])\r\n }\r\n onExpand?.(key)\r\n }\r\n }\r\n\r\n const expandAll = () => {\r\n if (accordion.value) return /* 手风琴模式不支持全展开 */\r\n\r\n const allKeys = items.value.filter((i) => !i.disabled).map((i) => i.key)\r\n\r\n allKeys.forEach((k) => renderedOnce.value.add(k))\r\n updateKeys(allKeys)\r\n }\r\n\r\n const collapseAll = () => {\r\n updateKeys([])\r\n }\r\n\r\n const getActiveKeys = (): string[] => {\r\n return [...currentKeys.value]\r\n }\r\n\r\n /* ─── 键盘导航 ────────────────────────────────── */\r\n const handleKeyDown = (e: KeyboardEvent, key: string) => {\r\n if (['Enter', ' '].includes(e.key)) {\r\n e.preventDefault()\r\n toggle(key)\r\n }\r\n }\r\n\r\n /* ─── 同步外部 v-model 变化 ───────────────────── */\r\n watch(\r\n () => externalKeys.value,\r\n (newVal) => {\r\n if (newVal !== undefined) {\r\n internalKeys.value = [...newVal]\r\n newVal.forEach((k) => renderedOnce.value.add(k))\r\n savePersistedKeys(newVal)\r\n }\r\n },\r\n )\r\n\r\n return {\r\n currentKeys,\r\n renderedOnce,\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n }\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"(el) => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" :size=\"16\" color=\"currentColor\" />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span v-if=\"item.subtitle\" class=\"collapse-item__subtitle\">\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div v-if=\"shouldRender(item)\" class=\"collapse-item__content\">\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, toRef } from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useCollapsePanel } from \"./composables/useCollapsePanel\";\r\nimport type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_CollapsePanel\" });\r\n\r\ninterface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[];\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[];\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[];\r\n /** 是否手风琴模式 */\r\n accordion?: boolean;\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant;\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition;\r\n /** 是否显示边框 */\r\n bordered?: boolean;\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: \"default\",\r\n expandIconPosition: \"left\",\r\n bordered: true,\r\n persistKey: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:activeKeys\": [keys: string[]];\r\n expand: [key: string];\r\n collapse: [key: string];\r\n change: [activeKeys: string[]];\r\n}>();\r\n\r\nconst containerRef = ref<HTMLElement | null>(null);\r\nconst panelRefs = ref<Map<string, HTMLElement>>(new Map());\r\n\r\nconst setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el);\r\n } else {\r\n panelRefs.value.delete(key);\r\n }\r\n};\r\n\r\nconst {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n} = useCollapsePanel({\r\n items: toRef(props, \"items\"),\r\n activeKeys: toRef(props, \"activeKeys\"),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, \"accordion\"),\r\n persistKey: toRef(props, \"persistKey\"),\r\n onChange: (keys) => {\r\n emit(\"update:activeKeys\", keys);\r\n emit(\"change\", keys);\r\n },\r\n onExpand: (key) => emit(\"expand\", key),\r\n onCollapse: (key) => emit(\"collapse\", key),\r\n});\r\n\r\n/* ─── 展开/折叠动画 ──────────────────────────── */\r\nconst onEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"0\";\r\n element.style.overflow = \"hidden\";\r\n /* 强制 reflow */\r\n void element.offsetHeight;\r\n element.style.height = `${element.scrollHeight}px`;\r\n};\r\n\r\nconst onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\nconst onLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = `${element.scrollHeight}px`;\r\n element.style.overflow = \"hidden\";\r\n void element.offsetHeight;\r\n element.style.height = \"0\";\r\n};\r\n\r\nconst onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\n/* ─── 滚动到指定面板 ─────────────────────────── */\r\nconst scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key);\r\n if (el) {\r\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n\r\n/* ─── 暴露方法 ──────────────────────────────── */\r\ndefineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"(el) => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" :size=\"16\" color=\"currentColor\" />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span v-if=\"item.subtitle\" class=\"collapse-item__subtitle\">\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div v-if=\"shouldRender(item)\" class=\"collapse-item__content\">\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, toRef } from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useCollapsePanel } from \"./composables/useCollapsePanel\";\r\nimport type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_CollapsePanel\" });\r\n\r\ninterface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[];\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[];\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[];\r\n /** 是否手风琴模式 */\r\n accordion?: boolean;\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant;\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition;\r\n /** 是否显示边框 */\r\n bordered?: boolean;\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: \"default\",\r\n expandIconPosition: \"left\",\r\n bordered: true,\r\n persistKey: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:activeKeys\": [keys: string[]];\r\n expand: [key: string];\r\n collapse: [key: string];\r\n change: [activeKeys: string[]];\r\n}>();\r\n\r\nconst containerRef = ref<HTMLElement | null>(null);\r\nconst panelRefs = ref<Map<string, HTMLElement>>(new Map());\r\n\r\nconst setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el);\r\n } else {\r\n panelRefs.value.delete(key);\r\n }\r\n};\r\n\r\nconst {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n} = useCollapsePanel({\r\n items: toRef(props, \"items\"),\r\n activeKeys: toRef(props, \"activeKeys\"),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, \"accordion\"),\r\n persistKey: toRef(props, \"persistKey\"),\r\n onChange: (keys) => {\r\n emit(\"update:activeKeys\", keys);\r\n emit(\"change\", keys);\r\n },\r\n onExpand: (key) => emit(\"expand\", key),\r\n onCollapse: (key) => emit(\"collapse\", key),\r\n});\r\n\r\n/* ─── 展开/折叠动画 ──────────────────────────── */\r\nconst onEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"0\";\r\n element.style.overflow = \"hidden\";\r\n /* 强制 reflow */\r\n void element.offsetHeight;\r\n element.style.height = `${element.scrollHeight}px`;\r\n};\r\n\r\nconst onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\nconst onLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = `${element.scrollHeight}px`;\r\n element.style.overflow = \"hidden\";\r\n void element.offsetHeight;\r\n element.style.height = \"0\";\r\n};\r\n\r\nconst onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\n/* ─── 滚动到指定面板 ─────────────────────────── */\r\nconst scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key);\r\n if (el) {\r\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n\r\n/* ─── 暴露方法 ──────────────────────────────── */\r\ndefineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 折叠面板组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div\r\n ref=\"containerRef\"\r\n class=\"c-collapse-panel\"\r\n :class=\"[\r\n `c-collapse-panel--${variant}`,\r\n {\r\n 'c-collapse-panel--bordered': bordered,\r\n 'c-collapse-panel--icon-right': expandIconPosition === 'right',\r\n },\r\n ]\"\r\n >\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item.key\"\r\n :ref=\"(el) => setPanelRef(item.key, el as HTMLElement)\"\r\n class=\"collapse-item\"\r\n :class=\"{\r\n 'collapse-item--active': isExpanded(item.key),\r\n 'collapse-item--disabled': item.disabled,\r\n }\"\r\n >\r\n <!-- 面板头部 -->\r\n <div\r\n class=\"collapse-item__header\"\r\n role=\"button\"\r\n :aria-expanded=\"isExpanded(item.key)\"\r\n :aria-controls=\"`collapse-content-${item.key}`\"\r\n :aria-disabled=\"item.disabled\"\r\n :tabindex=\"item.disabled ? -1 : 0\"\r\n @click=\"!item.disabled && toggle(item.key)\"\r\n @keydown=\"handleKeyDown($event, item.key)\"\r\n >\r\n <!-- 展开图标 -->\r\n <span\r\n class=\"collapse-item__arrow\"\r\n :class=\"{ 'collapse-item__arrow--expanded': isExpanded(item.key) }\"\r\n >\r\n <C_Icon name=\"mdi:chevron-right\" :size=\"16\" color=\"currentColor\" />\r\n </span>\r\n\r\n <!-- 标题区域 -->\r\n <div class=\"collapse-item__title-area\">\r\n <slot\r\n :name=\"`header-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n >\r\n <div class=\"collapse-item__title-group\">\r\n <C_Icon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"18\"\r\n color=\"currentColor\"\r\n class=\"collapse-item__icon\"\r\n />\r\n <span class=\"collapse-item__title\">{{ item.title }}</span>\r\n <span v-if=\"item.subtitle\" class=\"collapse-item__subtitle\">\r\n {{ item.subtitle }}\r\n </span>\r\n </div>\r\n </slot>\r\n </div>\r\n\r\n <!-- 头部右侧操作区 -->\r\n <div\r\n v-if=\"$slots[`extra-${item.key}`]\"\r\n class=\"collapse-item__extra\"\r\n @click.stop\r\n >\r\n <slot\r\n :name=\"`extra-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 面板内容 -->\r\n <Transition\r\n name=\"collapse-slide\"\r\n @enter=\"onEnter\"\r\n @after-enter=\"onAfterEnter\"\r\n @leave=\"onLeave\"\r\n @after-leave=\"onAfterLeave\"\r\n >\r\n <div\r\n v-show=\"isExpanded(item.key)\"\r\n :id=\"`collapse-content-${item.key}`\"\r\n class=\"collapse-item__content-wrapper\"\r\n role=\"region\"\r\n :aria-labelledby=\"`collapse-header-${item.key}`\"\r\n >\r\n <div v-if=\"shouldRender(item)\" class=\"collapse-item__content\">\r\n <slot\r\n :name=\"`panel-${item.key}`\"\r\n :item=\"item\"\r\n :expanded=\"isExpanded(item.key)\"\r\n />\r\n </div>\r\n </div>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, toRef } from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useCollapsePanel } from \"./composables/useCollapsePanel\";\r\nimport type {\r\n CollapsePanelExpose,\r\n CollapsePanelItem,\r\n CollapsePanelVariant,\r\n ExpandIconPosition,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_CollapsePanel\" });\r\n\r\ninterface Props {\r\n /** 面板项配置数组 */\r\n items: CollapsePanelItem[];\r\n /** 当前激活面板的 key 数组(v-model) */\r\n activeKeys?: string[];\r\n /** 默认展开的面板 key 数组 */\r\n defaultActiveKeys?: string[];\r\n /** 是否手风琴模式 */\r\n accordion?: boolean;\r\n /** 面板样式变体 */\r\n variant?: CollapsePanelVariant;\r\n /** 展开图标位置 */\r\n expandIconPosition?: ExpandIconPosition;\r\n /** 是否显示边框 */\r\n bordered?: boolean;\r\n /** 展开状态 localStorage 持久化 key */\r\n persistKey?: string;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n activeKeys: undefined,\r\n defaultActiveKeys: () => [],\r\n accordion: false,\r\n variant: \"default\",\r\n expandIconPosition: \"left\",\r\n bordered: true,\r\n persistKey: undefined,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"update:activeKeys\": [keys: string[]];\r\n expand: [key: string];\r\n collapse: [key: string];\r\n change: [activeKeys: string[]];\r\n}>();\r\n\r\nconst containerRef = ref<HTMLElement | null>(null);\r\nconst panelRefs = ref<Map<string, HTMLElement>>(new Map());\r\n\r\nconst setPanelRef = (key: string, el: HTMLElement | null) => {\r\n if (el) {\r\n panelRefs.value.set(key, el);\r\n } else {\r\n panelRefs.value.delete(key);\r\n }\r\n};\r\n\r\nconst {\r\n isExpanded,\r\n shouldRender,\r\n toggle,\r\n expandAll,\r\n collapseAll,\r\n getActiveKeys,\r\n handleKeyDown,\r\n} = useCollapsePanel({\r\n items: toRef(props, \"items\"),\r\n activeKeys: toRef(props, \"activeKeys\"),\r\n defaultActiveKeys: props.defaultActiveKeys,\r\n accordion: toRef(props, \"accordion\"),\r\n persistKey: toRef(props, \"persistKey\"),\r\n onChange: (keys) => {\r\n emit(\"update:activeKeys\", keys);\r\n emit(\"change\", keys);\r\n },\r\n onExpand: (key) => emit(\"expand\", key),\r\n onCollapse: (key) => emit(\"collapse\", key),\r\n});\r\n\r\n/* ─── 展开/折叠动画 ──────────────────────────── */\r\nconst onEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"0\";\r\n element.style.overflow = \"hidden\";\r\n /* 强制 reflow */\r\n void element.offsetHeight;\r\n element.style.height = `${element.scrollHeight}px`;\r\n};\r\n\r\nconst onAfterEnter = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\nconst onLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = `${element.scrollHeight}px`;\r\n element.style.overflow = \"hidden\";\r\n void element.offsetHeight;\r\n element.style.height = \"0\";\r\n};\r\n\r\nconst onAfterLeave = (el: Element) => {\r\n const element = el as HTMLElement;\r\n element.style.height = \"\";\r\n element.style.overflow = \"\";\r\n};\r\n\r\n/* ─── 滚动到指定面板 ─────────────────────────── */\r\nconst scrollToPanel = (key: string) => {\r\n const el = panelRefs.value.get(key);\r\n if (el) {\r\n el.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n\r\n/* ─── 暴露方法 ──────────────────────────────── */\r\ndefineExpose<CollapsePanelExpose>({\r\n expandAll,\r\n collapseAll,\r\n toggle,\r\n getActiveKeys,\r\n scrollToPanel,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"C_Cron-C0-8b5af.css","names":[],"sources":["../src/components/C_Cron/components/CronFieldEditor.vue?vue&type=style&index=0&scoped=769c51fe&lang.scss","../src/components/C_Cron/components/CronPreview.vue?vue&type=style&index=0&scoped=570ad3fb&lang.scss","../src/components/C_Cron/components/CronTemplates.vue?vue&type=style&index=0&scoped=5190cefc&lang.scss","../src/components/C_Cron/index.vue?vue&type=style&index=0&scoped=b3efef0a&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.cron-field-editor__grid[data-v-769c51fe] {\n display: grid;\n grid-template-columns: repeat(var(--cols, 10), 1fr);\n gap: 4px;\n}\n.cron-field-editor__cell[data-v-769c51fe] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 34px;\n border-radius: 6px;\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n transition: all var(--c-transition, 0.2s ease);\n user-select: none;\n color: var(--c-text-2);\n /* 非交互高亮(every / range / step 的视觉反馈) */\n /* 可交互模式(specific) */\n}\n.cron-field-editor__cell--on[data-v-769c51fe]:not(.cron-field-editor__cell--pick) {\n background: color-mix(in srgb, var(--c-primary) 12%, transparent);\n color: var(--c-primary);\n}\n.cron-field-editor__cell--pick[data-v-769c51fe] {\n cursor: pointer;\n}\n.cron-field-editor__cell--pick[data-v-769c51fe]:hover:not(.cron-field-editor__cell--on) {\n background: var(--c-bg-card);\n}\n.cron-field-editor__cell--pick.cron-field-editor__cell--on[data-v-769c51fe] {\n background: var(--c-primary);\n color: #fff;\n font-weight: 600;\n}","/* unplugin-vue-components disabled */.cron-preview__header[data-v-570ad3fb] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n font-size: 13px;\n margin-bottom: 6px;\n color: var(--c-text-1);\n}\n.cron-preview__list[data-v-570ad3fb] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.cron-preview__item[data-v-570ad3fb] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 3px 4px;\n border-radius: 4px;\n font-size: 12px;\n transition: background var(--c-transition, 0.2s ease);\n}\n.cron-preview__item[data-v-570ad3fb]:hover {\n background: var(--c-bg-card);\n}\n.cron-preview__idx[data-v-570ad3fb] {\n width: 16px;\n text-align: center;\n color: var(--c-text-4);\n flex-shrink: 0;\n font-size: 11px;\n}\n.cron-preview__date[data-v-570ad3fb] {\n font-family: \"Courier New\", Courier, monospace;\n flex: 1;\n font-size: 12px;\n}\n.cron-preview__week[data-v-570ad3fb] {\n color: var(--c-text-4);\n font-size: 12px;\n flex-shrink: 0;\n}","/* unplugin-vue-components disabled */.cron-templates__header[data-v-5190cefc] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n font-size: 13px;\n margin-bottom: 10px;\n color: var(--c-text-1);\n}\n.cron-templates__cards[data-v-5190cefc] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n gap: 8px;\n}\n.cron-templates__card[data-v-5190cefc] {\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--c-border);\n cursor: pointer;\n transition: all var(--c-transition, 0.2s ease);\n}\n.cron-templates__card[data-v-5190cefc]:hover {\n border-color: var(--c-primary);\n background: color-mix(in srgb, var(--c-primary) 4%, transparent);\n}\n.cron-templates__card--active[data-v-5190cefc] {\n border-color: var(--c-primary);\n background: color-mix(in srgb, var(--c-primary) 8%, transparent);\n}\n.cron-templates__card-name[data-v-5190cefc] {\n font-size: 13px;\n font-weight: 500;\n line-height: 1.4;\n}\n.cron-templates__card-expr[data-v-5190cefc] {\n font-family: \"Courier New\", Courier, monospace;\n font-size: 11px;\n color: var(--c-text-4);\n margin-top: 2px;\n}","/* unplugin-vue-components disabled *//* Cron 表达式编辑器 - 组件级全局样式 */\n.c-cron[data-v-b3efef0a] {\n padding: 20px;\n border-radius: 10px;\n border: 1px solid var(--c-border);\n background: var(--c-bg-card);\n /* ═══════ 顶部 ═══════ */\n /* ─── 分段式字段选择器 ──────────────────── */\n /* ─── 表达式行 ─────────────────────────── */\n /* ═══════ 主内容 ═══════ */\n /* ─── 右侧控制面板 ────────────────────── */\n /* ═══════ 底部模板 ═══════ */\n}\n.c-cron__header[data-v-b3efef0a] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--c-border);\n margin-bottom: 16px;\n}\n.c-cron__title-row[data-v-b3efef0a] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n.c-cron__title[data-v-b3efef0a] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n font-size: 15px;\n}\n.c-cron__segments[data-v-b3efef0a] {\n display: flex;\n gap: 2px;\n padding: 3px;\n border-radius: 10px;\n background: var(--c-bg);\n}\n.c-cron__segment[data-v-b3efef0a] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 8px 6px 5px;\n border-radius: 8px;\n cursor: pointer;\n transition: all var(--c-transition, 0.2s ease);\n user-select: none;\n min-width: 0;\n}\n.c-cron__segment[data-v-b3efef0a]:not(.c-cron__segment--active):hover {\n background: color-mix(in srgb, var(--c-bg-card) 60%, transparent);\n}\n.c-cron__segment--active[data-v-b3efef0a] {\n background: var(--c-bg-card);\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);\n}\n.c-cron__segment--active .c-cron__segment-value[data-v-b3efef0a] {\n color: var(--c-primary);\n}\n.c-cron__segment--wildcard:not(.c-cron__segment--active) .c-cron__segment-value[data-v-b3efef0a] {\n opacity: 0.35;\n}\n.c-cron__segment-value[data-v-b3efef0a] {\n font-family: \"Courier New\", Courier, monospace;\n font-size: 15px;\n font-weight: 700;\n line-height: 1.3;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: center;\n}\n.c-cron__segment-label[data-v-b3efef0a] {\n font-size: 11px;\n color: var(--c-text-4);\n margin-top: 2px;\n}\n.c-cron__expr-row[data-v-b3efef0a] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.c-cron__expr-input[data-v-b3efef0a] {\n width: 240px;\n flex-shrink: 0;\n}\n.c-cron__expr-desc[data-v-b3efef0a] {\n flex: 1;\n font-size: 13px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.c-cron__description[data-v-b3efef0a] {\n color: var(--c-text-2);\n}\n.c-cron__error[data-v-b3efef0a] {\n color: var(--error-color);\n}\n.c-cron__body[data-v-b3efef0a] {\n display: flex;\n gap: 24px;\n}\n.c-cron__main[data-v-b3efef0a] {\n flex: 1;\n min-width: 0;\n}\n.c-cron__panel[data-v-b3efef0a] {\n width: 260px;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.c-cron__config[data-v-b3efef0a] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.c-cron__config-row[data-v-b3efef0a] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--c-text-2);\n flex-wrap: wrap;\n}\n.c-cron__config-num[data-v-b3efef0a] {\n width: 68px;\n}\n.c-cron__quick[data-v-b3efef0a] {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n}\n.c-cron__quick a[data-v-b3efef0a] {\n color: var(--c-primary);\n cursor: pointer;\n user-select: none;\n}\n.c-cron__quick a[data-v-b3efef0a]:hover {\n text-decoration: underline;\n}\n.c-cron__quick-sep[data-v-b3efef0a] {\n color: var(--c-text-4);\n}\n.c-cron__quick-count[data-v-b3efef0a] {\n margin-left: 4px;\n font-size: 12px;\n color: var(--c-text-4);\n}\n.c-cron__panel-line[data-v-b3efef0a] {\n height: 1px;\n background: var(--c-border);\n}\n.c-cron__footer[data-v-b3efef0a] {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid var(--c-border);\n}\n\n/* ─── 响应式 ────────────────────────────────── */\n@media (max-width: 768px) {\n.c-cron__body[data-v-b3efef0a] {\n flex-direction: column;\n}\n.c-cron__panel[data-v-b3efef0a] {\n width: 100%;\n}\n.c-cron__segments[data-v-b3efef0a] {\n flex-wrap: wrap;\n}\n.c-cron__segment[data-v-b3efef0a] {\n min-width: calc(33% - 4px);\n}\n.c-cron__expr-row[data-v-b3efef0a] {\n flex-wrap: wrap;\n}\n.c-cron__expr-input[data-v-b3efef0a] {\n width: 100%;\n}\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC1CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_Cron2.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t as C_Icon_default } from "./C_Icon2.js";
|
|
2
2
|
import { t as export_helper_default } from "./export-helper.js";
|
|
3
|
-
import {
|
|
3
|
+
import { NButton, NEmpty, NInput, NInputNumber, NRadioButton, NRadioGroup, NScrollbar, NSpin, NTag } from "naive-ui";
|
|
4
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, onMounted, openBlock, ref, renderList, toDisplayString, unref, vShow, watch, withCtx, withDirectives, withKeys } from "vue";
|
|
4
5
|
|
|
5
6
|
//#region src/components/C_Cron/constants.ts
|
|
6
7
|
const CRON_FIELD_META = [
|
|
@@ -685,7 +686,7 @@ var CronFieldEditor_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
|
|
|
685
686
|
|
|
686
687
|
//#endregion
|
|
687
688
|
//#region src/components/C_Cron/components/CronFieldEditor.vue
|
|
688
|
-
var CronFieldEditor_default = /* @__PURE__ */ export_helper_default(CronFieldEditor_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
689
|
+
var CronFieldEditor_default = /* @__PURE__ */ export_helper_default(CronFieldEditor_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-769c51fe"]]);
|
|
689
690
|
|
|
690
691
|
//#endregion
|
|
691
692
|
//#region src/components/C_Cron/components/CronPreview.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -709,9 +710,9 @@ var CronPreview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
|
|
|
709
710
|
},
|
|
710
711
|
setup(__props) {
|
|
711
712
|
return (_ctx, _cache) => {
|
|
712
|
-
const _component_NSpin =
|
|
713
|
-
const _component_NEmpty =
|
|
714
|
-
const _component_NScrollbar =
|
|
713
|
+
const _component_NSpin = NSpin;
|
|
714
|
+
const _component_NEmpty = NEmpty;
|
|
715
|
+
const _component_NScrollbar = NScrollbar;
|
|
715
716
|
return openBlock(), createElementBlock("div", _hoisted_1$2, [createElementVNode("div", _hoisted_2$2, [
|
|
716
717
|
createVNode(C_Icon_default, {
|
|
717
718
|
name: "mdi:calendar-clock",
|
|
@@ -745,7 +746,7 @@ var CronPreview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
|
|
|
745
746
|
|
|
746
747
|
//#endregion
|
|
747
748
|
//#region src/components/C_Cron/components/CronPreview.vue
|
|
748
|
-
var CronPreview_default = /* @__PURE__ */ export_helper_default(CronPreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
749
|
+
var CronPreview_default = /* @__PURE__ */ export_helper_default(CronPreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-570ad3fb"]]);
|
|
749
750
|
|
|
750
751
|
//#endregion
|
|
751
752
|
//#region src/components/C_Cron/components/CronTemplates.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -780,7 +781,7 @@ var CronTemplates_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */
|
|
|
780
781
|
|
|
781
782
|
//#endregion
|
|
782
783
|
//#region src/components/C_Cron/components/CronTemplates.vue
|
|
783
|
-
var CronTemplates_default = /* @__PURE__ */ export_helper_default(CronTemplates_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
784
|
+
var CronTemplates_default = /* @__PURE__ */ export_helper_default(CronTemplates_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-5190cefc"]]);
|
|
784
785
|
|
|
785
786
|
//#endregion
|
|
786
787
|
//#region src/components/C_Cron/index.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -980,12 +981,12 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
|
|
|
980
981
|
validate: () => validate()
|
|
981
982
|
});
|
|
982
983
|
return (_ctx, _cache) => {
|
|
983
|
-
const _component_NTag =
|
|
984
|
-
const _component_NInput =
|
|
985
|
-
const _component_NButton =
|
|
986
|
-
const _component_NRadioButton =
|
|
987
|
-
const _component_NRadioGroup =
|
|
988
|
-
const _component_NInputNumber =
|
|
984
|
+
const _component_NTag = NTag;
|
|
985
|
+
const _component_NInput = NInput;
|
|
986
|
+
const _component_NButton = NButton;
|
|
987
|
+
const _component_NRadioButton = NRadioButton;
|
|
988
|
+
const _component_NRadioGroup = NRadioGroup;
|
|
989
|
+
const _component_NInputNumber = NInputNumber;
|
|
989
990
|
return openBlock(), createElementBlock("div", {
|
|
990
991
|
class: "c-cron",
|
|
991
992
|
style: normalizeStyle({ height: containerHeight.value })
|
|
@@ -1202,7 +1203,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
|
|
|
1202
1203
|
|
|
1203
1204
|
//#endregion
|
|
1204
1205
|
//#region src/components/C_Cron/index.vue
|
|
1205
|
-
var C_Cron_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
1206
|
+
var C_Cron_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b3efef0a"]]);
|
|
1206
1207
|
|
|
1207
1208
|
//#endregion
|
|
1208
1209
|
export { CRON_FIELD_META as a, DEFAULT_CRON_VALUE as c, WEEK_LABELS as d, useCronParser as i, DEFAULT_FIELD_VALUE as l, useCronDescription as n, CRON_TEMPLATES as o, useCronPreview as r, DEFAULT_CRON_EXPRESSION as s, C_Cron_default as t, MONTH_LABELS as u };
|