@robot-admin/naive-ui-components 0.6.31 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +5 -3
- package/dist/C_OrgChart.js.map +1 -1
- package/dist/C_OrgChart2.js.map +1 -1
- package/dist/C_Skeleton.js.map +1 -1
- package/dist/C_Skeleton2.js.map +1 -1
- package/dist/{C_Table-B8hpzOcR.css.map → C_Table-BcM5LqAM.css.map} +1 -1
- package/dist/{C_Table-CGP3n_u0.css.map → C_Table-HATVoq1F.css.map} +1 -1
- package/dist/C_Table.cjs +1 -1
- package/dist/C_Table.css +140 -97
- package/dist/C_Table.d.cts +2 -2
- package/dist/C_Table.d.ts +2 -2
- package/dist/C_Table.js +1 -1
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +3 -1
- package/dist/C_Table2.js.map +1 -1
- package/dist/constants.d.ts +4 -4
- package/dist/constants2.d.ts +3 -3
- package/dist/constants3.d.ts +3 -3
- package/dist/constants4.d.ts +2 -2
- package/dist/constants5.d.ts +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.vue.d.ts +1 -1
- package/dist/index10.vue.d.ts +1 -1
- package/dist/index11.vue.d.ts +2 -2
- package/dist/index13.vue.d.ts +3 -3
- package/dist/index14.vue.d.ts +1 -1
- package/dist/index15.vue.d.ts +4 -4
- package/dist/index16.vue.d.ts +2 -2
- package/dist/index18.vue.d.ts +4 -4
- package/dist/index2.vue.d.ts +6 -6
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index21.vue.d.ts +1 -1
- package/dist/index22.vue.d.ts +2 -2
- package/dist/index23.vue.d.ts +1 -1
- package/dist/index24.vue.d.ts +1 -1
- package/dist/index26.vue.d.ts +4 -4
- package/dist/index27.vue.d.ts +2 -2
- package/dist/index28.vue.d.ts +3 -3
- package/dist/index3.vue.d.ts +3 -3
- package/dist/index4.vue.d.ts +5 -5
- package/dist/index6.vue.d.ts +2 -2
- package/dist/index7.vue.d.ts +2 -2
- package/dist/index9.vue.d.ts +2 -2
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +142 -99
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.ts +5 -5
- package/dist/useCropperCore.d.ts +4 -4
- package/dist/useDraggableLayout.d.ts +5 -5
- package/dist/useDynamicFormState.d.ts +124 -124
- package/dist/useEdgeInteraction.d.ts +1 -1
- package/dist/useGlobalSearch.d.ts +1 -1
- package/dist/useInfiniteScroll.d.ts +4 -4
- package/dist/useModalEdit.d.ts +513 -240
- package/dist/useQRCode.d.ts +3 -3
- package/dist/useSearchState.d.ts +2 -2
- package/dist/useSignatureHistory.d.ts +3 -3
- package/dist/useSplitResize.d.ts +5 -5
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +4 -4
- package/dist/useWorkflowValidation.d.ts +7 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @robot-admin/naive-ui-components
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- C_Table 类型系统清理:移除 6 个废弃类型(TestRecord、SelectedChildGroup、DemoConfig、DataMapping、CommonMappings),集中定义 ColumnWithKey 消除跨文件重复,修复所有 TypeScript 类型错误
|
|
8
|
+
|
|
9
|
+
## 0.7.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- C_Table 新增10项能力:全局配置 provide/inject、列级 formatter 格式化引擎、树形表格、行拖拽排序、跨页多选、CSV/XLSX 导出、列配置持久化、编辑校验、错误状态、批量操作栏
|
|
14
|
+
|
|
3
15
|
## 0.6.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @agile-team/naive-ui-components
|
|
2
2
|
|
|
3
|
-
基于 **Naive UI** 的 Vue 3 企业级组件库,从 Robot Admin 中提炼的
|
|
3
|
+
基于 **Naive UI** 的 Vue 3 企业级组件库,从 Robot Admin 中提炼的 51 个高质量业务组件。
|
|
4
4
|
|
|
5
5
|
支持 **全量注册**、**按需导入(Tree-Shaking)** 和 **子路径独立导入**,配合多入口构建输出 ESM / CJS / DTS,满足不同集成场景。
|
|
6
6
|
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
} from '@agile-team/naive-ui-components'
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
## 📋 组件清单(
|
|
67
|
+
## 📋 组件清单(51 个)
|
|
68
68
|
|
|
69
69
|
> 💡 所有组件均提供 **在线交互演示**,访问 [组件文档](https://www.tzagileteam.com/robot/components/preface) 可直接在页面中体验真实效果(通过 iframe 嵌入 Robot Admin 生产环境)。
|
|
70
70
|
|
|
@@ -90,6 +90,8 @@ import {
|
|
|
90
90
|
| `C_TagsView` | 标签页导航 | - |
|
|
91
91
|
| `C_GlobalSearch` | 全局搜索面板 | - |
|
|
92
92
|
| `C_AvatarGroup` | 头像组合展示 | - |
|
|
93
|
+
| `C_OrgChart` | 组织架构图 | - |
|
|
94
|
+
| `C_Skeleton` | 骨架屏占位组件 | - |
|
|
93
95
|
|
|
94
96
|
### 内容 & 编辑组件
|
|
95
97
|
|
|
@@ -185,7 +187,7 @@ bun run build
|
|
|
185
187
|
|
|
186
188
|
### 技术要点
|
|
187
189
|
|
|
188
|
-
- **构建引擎**:[tsdown](https://github.com/rolldown/tsdown)(基于 Rolldown),
|
|
190
|
+
- **构建引擎**:[tsdown](https://github.com/rolldown/tsdown)(基于 Rolldown),51 个独立入口并行编译
|
|
189
191
|
- **SCSS 处理**:自定义 `scssTransformPlugin` 在 Rolldown 管线内编译 SFC SCSS,独立 Sass CLI 编译全局样式
|
|
190
192
|
- **CSS 合并**:构建后将分散的 per-chunk CSS 与 `global-scss.css` 合并为单一 `style.css`
|
|
191
193
|
- **类型导出**:统一 `export *` barrel 模式,自动生成完整 `.d.ts`
|
package/dist/C_OrgChart.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_OrgChart.js","names":["node","$emit","collapsible","$slots"],"sources":["../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_OrgChart 组织架构图组件\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-orgchart\"\n :class=\"[\n `c-orgchart--${props.direction}`,\n `c-orgchart--line-${props.lineStyle}`,\n ]\"\n :style=\"cssVars\"\n @wheel.prevent=\"handleWheel\"\n @mousedown=\"handlePanStart\"\n @mousemove=\"handlePanMove\"\n @mouseup=\"handlePanEnd\"\n @mouseleave=\"handlePanEnd\"\n >\n <div\n class=\"c-orgchart__viewport\"\n :style=\"viewportStyle\"\n >\n <OrgNode\n :node=\"props.data\"\n :collapsible=\"props.collapsible\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @node-collapse=\"handleNodeCollapse\"\n >\n <template\n v-if=\"$slots.node\"\n #node=\"slotProps\"\n >\n <slot\n name=\"node\"\n v-bind=\"slotProps\"\n />\n </template>\n </OrgNode>\n </div>\n\n <!-- 缩放控制 -->\n <div\n v-if=\"props.zoomable\"\n class=\"c-orgchart__controls\"\n >\n <button\n class=\"c-orgchart__control-btn\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n +\n </button>\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n −\n </button>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"重置\"\n @click=\"resetView\"\n >\n ⟳\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed } from 'vue'\n import OrgNode from './OrgNode.vue'\n import type { OrgChartProps, OrgChartNode } from './types'\n\n defineOptions({ name: 'C_OrgChart' })\n\n const props = withDefaults(defineProps<OrgChartProps>(), {\n direction: 'vertical',\n lineStyle: 'rounded',\n lineColor: '#d1d5db',\n lineWidth: 2,\n nodeSpacing: 24,\n levelSpacing: 48,\n zoomable: true,\n pannable: true,\n initialZoom: 1,\n minZoom: 0.3,\n maxZoom: 2,\n collapsible: true,\n })\n\n const emit = defineEmits<{\n 'node-click': [node: OrgChartNode]\n 'node-expand': [node: OrgChartNode]\n 'node-collapse': [node: OrgChartNode]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n\n // ─── 缩放 & 平移 ───\n const zoom = ref(props.initialZoom)\n const panX = ref(0)\n const panY = ref(0)\n const isPanning = ref(false)\n const panStartX = ref(0)\n const panStartY = ref(0)\n\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\n\n const cssVars = computed(() => ({\n '--c-orgchart-line-color': props.lineColor,\n '--c-orgchart-line-width': `${props.lineWidth}px`,\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\n }))\n\n const viewportStyle = computed(() => ({\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\n transformOrigin: 'center top',\n }))\n\n /**\n * * @description: 鼠标滚轮缩放\n */\n const handleWheel = (e: WheelEvent) => {\n if (!props.zoomable) return\n const delta = e.deltaY > 0 ? -0.1 : 0.1\n const newZoom = Math.max(\n props.minZoom,\n Math.min(props.maxZoom, zoom.value + delta)\n )\n zoom.value = Math.round(newZoom * 100) / 100\n }\n\n const handlePanStart = (e: MouseEvent) => {\n if (!props.pannable) return\n isPanning.value = true\n panStartX.value = e.clientX - panX.value\n panStartY.value = e.clientY - panY.value\n }\n\n const handlePanMove = (e: MouseEvent) => {\n if (!isPanning.value) return\n panX.value = e.clientX - panStartX.value\n panY.value = e.clientY - panStartY.value\n }\n\n const handlePanEnd = () => {\n isPanning.value = false\n }\n\n const zoomIn = () => {\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\n }\n\n const zoomOut = () => {\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\n }\n\n const resetView = () => {\n zoom.value = props.initialZoom\n panX.value = 0\n panY.value = 0\n }\n\n // ─── 事件桥接 ───\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\n\n defineExpose({\n zoomIn,\n zoomOut,\n resetView,\n zoom,\n })\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_OrgChart 组织架构图组件\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-orgchart\"\n :class=\"[\n `c-orgchart--${props.direction}`,\n `c-orgchart--line-${props.lineStyle}`,\n ]\"\n :style=\"cssVars\"\n @wheel.prevent=\"handleWheel\"\n @mousedown=\"handlePanStart\"\n @mousemove=\"handlePanMove\"\n @mouseup=\"handlePanEnd\"\n @mouseleave=\"handlePanEnd\"\n >\n <div\n class=\"c-orgchart__viewport\"\n :style=\"viewportStyle\"\n >\n <OrgNode\n :node=\"props.data\"\n :collapsible=\"props.collapsible\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @node-collapse=\"handleNodeCollapse\"\n >\n <template\n v-if=\"$slots.node\"\n #node=\"slotProps\"\n >\n <slot\n name=\"node\"\n v-bind=\"slotProps\"\n />\n </template>\n </OrgNode>\n </div>\n\n <!-- 缩放控制 -->\n <div\n v-if=\"props.zoomable\"\n class=\"c-orgchart__controls\"\n >\n <button\n class=\"c-orgchart__control-btn\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n +\n </button>\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n −\n </button>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"重置\"\n @click=\"resetView\"\n >\n ⟳\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed } from 'vue'\n import OrgNode from './OrgNode.vue'\n import type { OrgChartProps, OrgChartNode } from './types'\n\n defineOptions({ name: 'C_OrgChart' })\n\n const props = withDefaults(defineProps<OrgChartProps>(), {\n direction: 'vertical',\n lineStyle: 'rounded',\n lineColor: '#d1d5db',\n lineWidth: 2,\n nodeSpacing: 24,\n levelSpacing: 48,\n zoomable: true,\n pannable: true,\n initialZoom: 1,\n minZoom: 0.3,\n maxZoom: 2,\n collapsible: true,\n })\n\n const emit = defineEmits<{\n 'node-click': [node: OrgChartNode]\n 'node-expand': [node: OrgChartNode]\n 'node-collapse': [node: OrgChartNode]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n\n // ─── 缩放 & 平移 ───\n const zoom = ref(props.initialZoom)\n const panX = ref(0)\n const panY = ref(0)\n const isPanning = ref(false)\n const panStartX = ref(0)\n const panStartY = ref(0)\n\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\n\n const cssVars = computed(() => ({\n '--c-orgchart-line-color': props.lineColor,\n '--c-orgchart-line-width': `${props.lineWidth}px`,\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\n }))\n\n const viewportStyle = computed(() => ({\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\n transformOrigin: 'center top',\n }))\n\n /**\n * * @description: 鼠标滚轮缩放\n */\n const handleWheel = (e: WheelEvent) => {\n if (!props.zoomable) return\n const delta = e.deltaY > 0 ? -0.1 : 0.1\n const newZoom = Math.max(\n props.minZoom,\n Math.min(props.maxZoom, zoom.value + delta)\n )\n zoom.value = Math.round(newZoom * 100) / 100\n }\n\n const handlePanStart = (e: MouseEvent) => {\n if (!props.pannable) return\n isPanning.value = true\n panStartX.value = e.clientX - panX.value\n panStartY.value = e.clientY - panY.value\n }\n\n const handlePanMove = (e: MouseEvent) => {\n if (!isPanning.value) return\n panX.value = e.clientX - panStartX.value\n panY.value = e.clientY - panStartY.value\n }\n\n const handlePanEnd = () => {\n isPanning.value = false\n }\n\n const zoomIn = () => {\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\n }\n\n const zoomOut = () => {\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\n }\n\n const resetView = () => {\n zoom.value = props.initialZoom\n panX.value = 0\n panY.value = 0\n }\n\n // ─── 事件桥接 ───\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\n\n defineExpose({\n zoomIn,\n zoomOut,\n resetView,\n zoom,\n })\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_OrgChart 组织架构图组件\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-orgchart\"\n :class=\"[\n `c-orgchart--${props.direction}`,\n `c-orgchart--line-${props.lineStyle}`,\n ]\"\n :style=\"cssVars\"\n @wheel.prevent=\"handleWheel\"\n @mousedown=\"handlePanStart\"\n @mousemove=\"handlePanMove\"\n @mouseup=\"handlePanEnd\"\n @mouseleave=\"handlePanEnd\"\n >\n <div\n class=\"c-orgchart__viewport\"\n :style=\"viewportStyle\"\n >\n <OrgNode\n :node=\"props.data\"\n :collapsible=\"props.collapsible\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @node-collapse=\"handleNodeCollapse\"\n >\n <template\n v-if=\"$slots.node\"\n #node=\"slotProps\"\n >\n <slot\n name=\"node\"\n v-bind=\"slotProps\"\n />\n </template>\n </OrgNode>\n </div>\n\n <!-- 缩放控制 -->\n <div\n v-if=\"props.zoomable\"\n class=\"c-orgchart__controls\"\n >\n <button\n class=\"c-orgchart__control-btn\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n +\n </button>\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n −\n </button>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"重置\"\n @click=\"resetView\"\n >\n ⟳\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed } from 'vue'\n import OrgNode from './OrgNode.vue'\n import type { OrgChartProps, OrgChartNode } from './types'\n\n defineOptions({ name: 'C_OrgChart' })\n\n const props = withDefaults(defineProps<OrgChartProps>(), {\n direction: 'vertical',\n lineStyle: 'rounded',\n lineColor: '#d1d5db',\n lineWidth: 2,\n nodeSpacing: 24,\n levelSpacing: 48,\n zoomable: true,\n pannable: true,\n initialZoom: 1,\n minZoom: 0.3,\n maxZoom: 2,\n collapsible: true,\n })\n\n const emit = defineEmits<{\n 'node-click': [node: OrgChartNode]\n 'node-expand': [node: OrgChartNode]\n 'node-collapse': [node: OrgChartNode]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n\n // ─── 缩放 & 平移 ───\n const zoom = ref(props.initialZoom)\n const panX = ref(0)\n const panY = ref(0)\n const isPanning = ref(false)\n const panStartX = ref(0)\n const panStartY = ref(0)\n\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\n\n const cssVars = computed(() => ({\n '--c-orgchart-line-color': props.lineColor,\n '--c-orgchart-line-width': `${props.lineWidth}px`,\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\n }))\n\n const viewportStyle = computed(() => ({\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\n transformOrigin: 'center top',\n }))\n\n /**\n * * @description: 鼠标滚轮缩放\n */\n const handleWheel = (e: WheelEvent) => {\n if (!props.zoomable) return\n const delta = e.deltaY > 0 ? -0.1 : 0.1\n const newZoom = Math.max(\n props.minZoom,\n Math.min(props.maxZoom, zoom.value + delta)\n )\n zoom.value = Math.round(newZoom * 100) / 100\n }\n\n const handlePanStart = (e: MouseEvent) => {\n if (!props.pannable) return\n isPanning.value = true\n panStartX.value = e.clientX - panX.value\n panStartY.value = e.clientY - panY.value\n }\n\n const handlePanMove = (e: MouseEvent) => {\n if (!isPanning.value) return\n panX.value = e.clientX - panStartX.value\n panY.value = e.clientY - panStartY.value\n }\n\n const handlePanEnd = () => {\n isPanning.value = false\n }\n\n const zoomIn = () => {\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\n }\n\n const zoomOut = () => {\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\n }\n\n const resetView = () => {\n zoom.value = props.initialZoom\n panX.value = 0\n panY.value = 0\n }\n\n // ─── 事件桥接 ───\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\n\n defineExpose({\n zoomIn,\n zoomOut,\n resetView,\n zoom,\n })\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_OrgChart.js","names":["node","$emit","collapsible","$slots"],"sources":["../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 组织架构图组件\r\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\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-orgchart\"\r\n :class=\"[\r\n `c-orgchart--${props.direction}`,\r\n `c-orgchart--line-${props.lineStyle}`,\r\n ]\"\r\n :style=\"cssVars\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown=\"handlePanStart\"\r\n @mousemove=\"handlePanMove\"\r\n @mouseup=\"handlePanEnd\"\r\n @mouseleave=\"handlePanEnd\"\r\n >\r\n <div\r\n class=\"c-orgchart__viewport\"\r\n :style=\"viewportStyle\"\r\n >\r\n <OrgNode\r\n :node=\"props.data\"\r\n :collapsible=\"props.collapsible\"\r\n @node-click=\"handleNodeClick\"\r\n @node-expand=\"handleNodeExpand\"\r\n @node-collapse=\"handleNodeCollapse\"\r\n >\r\n <template\r\n v-if=\"$slots.node\"\r\n #node=\"slotProps\"\r\n >\r\n <slot\r\n name=\"node\"\r\n v-bind=\"slotProps\"\r\n />\r\n </template>\r\n </OrgNode>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div\r\n v-if=\"props.zoomable\"\r\n class=\"c-orgchart__controls\"\r\n >\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"放大\"\r\n @click=\"zoomIn\"\r\n >\r\n +\r\n </button>\r\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"缩小\"\r\n @click=\"zoomOut\"\r\n >\r\n −\r\n </button>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"重置\"\r\n @click=\"resetView\"\r\n >\r\n ⟳\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import OrgNode from './OrgNode.vue'\r\n import type { OrgChartProps, OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'C_OrgChart' })\r\n\r\n const props = withDefaults(defineProps<OrgChartProps>(), {\r\n direction: 'vertical',\r\n lineStyle: 'rounded',\r\n lineColor: '#d1d5db',\r\n lineWidth: 2,\r\n nodeSpacing: 24,\r\n levelSpacing: 48,\r\n zoomable: true,\r\n pannable: true,\r\n initialZoom: 1,\r\n minZoom: 0.3,\r\n maxZoom: 2,\r\n collapsible: true,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n\r\n // ─── 缩放 & 平移 ───\r\n const zoom = ref(props.initialZoom)\r\n const panX = ref(0)\r\n const panY = ref(0)\r\n const isPanning = ref(false)\r\n const panStartX = ref(0)\r\n const panStartY = ref(0)\r\n\r\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\r\n\r\n const cssVars = computed(() => ({\r\n '--c-orgchart-line-color': props.lineColor,\r\n '--c-orgchart-line-width': `${props.lineWidth}px`,\r\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\r\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\r\n }))\r\n\r\n const viewportStyle = computed(() => ({\r\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\r\n transformOrigin: 'center top',\r\n }))\r\n\r\n /**\r\n * * @description: 鼠标滚轮缩放\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable) return\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(\r\n props.minZoom,\r\n Math.min(props.maxZoom, zoom.value + delta)\r\n )\r\n zoom.value = Math.round(newZoom * 100) / 100\r\n }\r\n\r\n const handlePanStart = (e: MouseEvent) => {\r\n if (!props.pannable) return\r\n isPanning.value = true\r\n panStartX.value = e.clientX - panX.value\r\n panStartY.value = e.clientY - panY.value\r\n }\r\n\r\n const handlePanMove = (e: MouseEvent) => {\r\n if (!isPanning.value) return\r\n panX.value = e.clientX - panStartX.value\r\n panY.value = e.clientY - panStartY.value\r\n }\r\n\r\n const handlePanEnd = () => {\r\n isPanning.value = false\r\n }\r\n\r\n const zoomIn = () => {\r\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\r\n }\r\n\r\n const zoomOut = () => {\r\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\r\n }\r\n\r\n const resetView = () => {\r\n zoom.value = props.initialZoom\r\n panX.value = 0\r\n panY.value = 0\r\n }\r\n\r\n // ─── 事件桥接 ───\r\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\r\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\r\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\r\n\r\n defineExpose({\r\n zoomIn,\r\n zoomOut,\r\n resetView,\r\n zoom,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\">\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-03-06\r\n * @Description: C_OrgChart 组织架构图组件\r\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\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-orgchart\"\r\n :class=\"[\r\n `c-orgchart--${props.direction}`,\r\n `c-orgchart--line-${props.lineStyle}`,\r\n ]\"\r\n :style=\"cssVars\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown=\"handlePanStart\"\r\n @mousemove=\"handlePanMove\"\r\n @mouseup=\"handlePanEnd\"\r\n @mouseleave=\"handlePanEnd\"\r\n >\r\n <div\r\n class=\"c-orgchart__viewport\"\r\n :style=\"viewportStyle\"\r\n >\r\n <OrgNode\r\n :node=\"props.data\"\r\n :collapsible=\"props.collapsible\"\r\n @node-click=\"handleNodeClick\"\r\n @node-expand=\"handleNodeExpand\"\r\n @node-collapse=\"handleNodeCollapse\"\r\n >\r\n <template\r\n v-if=\"$slots.node\"\r\n #node=\"slotProps\"\r\n >\r\n <slot\r\n name=\"node\"\r\n v-bind=\"slotProps\"\r\n />\r\n </template>\r\n </OrgNode>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div\r\n v-if=\"props.zoomable\"\r\n class=\"c-orgchart__controls\"\r\n >\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"放大\"\r\n @click=\"zoomIn\"\r\n >\r\n +\r\n </button>\r\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"缩小\"\r\n @click=\"zoomOut\"\r\n >\r\n −\r\n </button>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"重置\"\r\n @click=\"resetView\"\r\n >\r\n ⟳\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import OrgNode from './OrgNode.vue'\r\n import type { OrgChartProps, OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'C_OrgChart' })\r\n\r\n const props = withDefaults(defineProps<OrgChartProps>(), {\r\n direction: 'vertical',\r\n lineStyle: 'rounded',\r\n lineColor: '#d1d5db',\r\n lineWidth: 2,\r\n nodeSpacing: 24,\r\n levelSpacing: 48,\r\n zoomable: true,\r\n pannable: true,\r\n initialZoom: 1,\r\n minZoom: 0.3,\r\n maxZoom: 2,\r\n collapsible: true,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n\r\n // ─── 缩放 & 平移 ───\r\n const zoom = ref(props.initialZoom)\r\n const panX = ref(0)\r\n const panY = ref(0)\r\n const isPanning = ref(false)\r\n const panStartX = ref(0)\r\n const panStartY = ref(0)\r\n\r\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\r\n\r\n const cssVars = computed(() => ({\r\n '--c-orgchart-line-color': props.lineColor,\r\n '--c-orgchart-line-width': `${props.lineWidth}px`,\r\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\r\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\r\n }))\r\n\r\n const viewportStyle = computed(() => ({\r\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\r\n transformOrigin: 'center top',\r\n }))\r\n\r\n /**\r\n * * @description: 鼠标滚轮缩放\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable) return\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(\r\n props.minZoom,\r\n Math.min(props.maxZoom, zoom.value + delta)\r\n )\r\n zoom.value = Math.round(newZoom * 100) / 100\r\n }\r\n\r\n const handlePanStart = (e: MouseEvent) => {\r\n if (!props.pannable) return\r\n isPanning.value = true\r\n panStartX.value = e.clientX - panX.value\r\n panStartY.value = e.clientY - panY.value\r\n }\r\n\r\n const handlePanMove = (e: MouseEvent) => {\r\n if (!isPanning.value) return\r\n panX.value = e.clientX - panStartX.value\r\n panY.value = e.clientY - panStartY.value\r\n }\r\n\r\n const handlePanEnd = () => {\r\n isPanning.value = false\r\n }\r\n\r\n const zoomIn = () => {\r\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\r\n }\r\n\r\n const zoomOut = () => {\r\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\r\n }\r\n\r\n const resetView = () => {\r\n zoom.value = props.initialZoom\r\n panX.value = 0\r\n panY.value = 0\r\n }\r\n\r\n // ─── 事件桥接 ───\r\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\r\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\r\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\r\n\r\n defineExpose({\r\n zoomIn,\r\n zoomOut,\r\n resetView,\r\n zoom,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 组织架构图组件\r\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\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-orgchart\"\r\n :class=\"[\r\n `c-orgchart--${props.direction}`,\r\n `c-orgchart--line-${props.lineStyle}`,\r\n ]\"\r\n :style=\"cssVars\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown=\"handlePanStart\"\r\n @mousemove=\"handlePanMove\"\r\n @mouseup=\"handlePanEnd\"\r\n @mouseleave=\"handlePanEnd\"\r\n >\r\n <div\r\n class=\"c-orgchart__viewport\"\r\n :style=\"viewportStyle\"\r\n >\r\n <OrgNode\r\n :node=\"props.data\"\r\n :collapsible=\"props.collapsible\"\r\n @node-click=\"handleNodeClick\"\r\n @node-expand=\"handleNodeExpand\"\r\n @node-collapse=\"handleNodeCollapse\"\r\n >\r\n <template\r\n v-if=\"$slots.node\"\r\n #node=\"slotProps\"\r\n >\r\n <slot\r\n name=\"node\"\r\n v-bind=\"slotProps\"\r\n />\r\n </template>\r\n </OrgNode>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div\r\n v-if=\"props.zoomable\"\r\n class=\"c-orgchart__controls\"\r\n >\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"放大\"\r\n @click=\"zoomIn\"\r\n >\r\n +\r\n </button>\r\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"缩小\"\r\n @click=\"zoomOut\"\r\n >\r\n −\r\n </button>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"重置\"\r\n @click=\"resetView\"\r\n >\r\n ⟳\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import OrgNode from './OrgNode.vue'\r\n import type { OrgChartProps, OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'C_OrgChart' })\r\n\r\n const props = withDefaults(defineProps<OrgChartProps>(), {\r\n direction: 'vertical',\r\n lineStyle: 'rounded',\r\n lineColor: '#d1d5db',\r\n lineWidth: 2,\r\n nodeSpacing: 24,\r\n levelSpacing: 48,\r\n zoomable: true,\r\n pannable: true,\r\n initialZoom: 1,\r\n minZoom: 0.3,\r\n maxZoom: 2,\r\n collapsible: true,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n\r\n // ─── 缩放 & 平移 ───\r\n const zoom = ref(props.initialZoom)\r\n const panX = ref(0)\r\n const panY = ref(0)\r\n const isPanning = ref(false)\r\n const panStartX = ref(0)\r\n const panStartY = ref(0)\r\n\r\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\r\n\r\n const cssVars = computed(() => ({\r\n '--c-orgchart-line-color': props.lineColor,\r\n '--c-orgchart-line-width': `${props.lineWidth}px`,\r\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\r\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\r\n }))\r\n\r\n const viewportStyle = computed(() => ({\r\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\r\n transformOrigin: 'center top',\r\n }))\r\n\r\n /**\r\n * * @description: 鼠标滚轮缩放\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable) return\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(\r\n props.minZoom,\r\n Math.min(props.maxZoom, zoom.value + delta)\r\n )\r\n zoom.value = Math.round(newZoom * 100) / 100\r\n }\r\n\r\n const handlePanStart = (e: MouseEvent) => {\r\n if (!props.pannable) return\r\n isPanning.value = true\r\n panStartX.value = e.clientX - panX.value\r\n panStartY.value = e.clientY - panY.value\r\n }\r\n\r\n const handlePanMove = (e: MouseEvent) => {\r\n if (!isPanning.value) return\r\n panX.value = e.clientX - panStartX.value\r\n panY.value = e.clientY - panStartY.value\r\n }\r\n\r\n const handlePanEnd = () => {\r\n isPanning.value = false\r\n }\r\n\r\n const zoomIn = () => {\r\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\r\n }\r\n\r\n const zoomOut = () => {\r\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\r\n }\r\n\r\n const resetView = () => {\r\n zoom.value = props.initialZoom\r\n panX.value = 0\r\n panY.value = 0\r\n }\r\n\r\n // ─── 事件桥接 ───\r\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\r\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\r\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\r\n\r\n defineExpose({\r\n zoomIn,\r\n zoomOut,\r\n resetView,\r\n zoom,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
package/dist/C_OrgChart2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_OrgChart2.js","names":["node","$emit","collapsible","$slots"],"sources":["../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_OrgChart 组织架构图组件\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-orgchart\"\n :class=\"[\n `c-orgchart--${props.direction}`,\n `c-orgchart--line-${props.lineStyle}`,\n ]\"\n :style=\"cssVars\"\n @wheel.prevent=\"handleWheel\"\n @mousedown=\"handlePanStart\"\n @mousemove=\"handlePanMove\"\n @mouseup=\"handlePanEnd\"\n @mouseleave=\"handlePanEnd\"\n >\n <div\n class=\"c-orgchart__viewport\"\n :style=\"viewportStyle\"\n >\n <OrgNode\n :node=\"props.data\"\n :collapsible=\"props.collapsible\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @node-collapse=\"handleNodeCollapse\"\n >\n <template\n v-if=\"$slots.node\"\n #node=\"slotProps\"\n >\n <slot\n name=\"node\"\n v-bind=\"slotProps\"\n />\n </template>\n </OrgNode>\n </div>\n\n <!-- 缩放控制 -->\n <div\n v-if=\"props.zoomable\"\n class=\"c-orgchart__controls\"\n >\n <button\n class=\"c-orgchart__control-btn\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n +\n </button>\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n −\n </button>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"重置\"\n @click=\"resetView\"\n >\n ⟳\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed } from 'vue'\n import OrgNode from './OrgNode.vue'\n import type { OrgChartProps, OrgChartNode } from './types'\n\n defineOptions({ name: 'C_OrgChart' })\n\n const props = withDefaults(defineProps<OrgChartProps>(), {\n direction: 'vertical',\n lineStyle: 'rounded',\n lineColor: '#d1d5db',\n lineWidth: 2,\n nodeSpacing: 24,\n levelSpacing: 48,\n zoomable: true,\n pannable: true,\n initialZoom: 1,\n minZoom: 0.3,\n maxZoom: 2,\n collapsible: true,\n })\n\n const emit = defineEmits<{\n 'node-click': [node: OrgChartNode]\n 'node-expand': [node: OrgChartNode]\n 'node-collapse': [node: OrgChartNode]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n\n // ─── 缩放 & 平移 ───\n const zoom = ref(props.initialZoom)\n const panX = ref(0)\n const panY = ref(0)\n const isPanning = ref(false)\n const panStartX = ref(0)\n const panStartY = ref(0)\n\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\n\n const cssVars = computed(() => ({\n '--c-orgchart-line-color': props.lineColor,\n '--c-orgchart-line-width': `${props.lineWidth}px`,\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\n }))\n\n const viewportStyle = computed(() => ({\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\n transformOrigin: 'center top',\n }))\n\n /**\n * * @description: 鼠标滚轮缩放\n */\n const handleWheel = (e: WheelEvent) => {\n if (!props.zoomable) return\n const delta = e.deltaY > 0 ? -0.1 : 0.1\n const newZoom = Math.max(\n props.minZoom,\n Math.min(props.maxZoom, zoom.value + delta)\n )\n zoom.value = Math.round(newZoom * 100) / 100\n }\n\n const handlePanStart = (e: MouseEvent) => {\n if (!props.pannable) return\n isPanning.value = true\n panStartX.value = e.clientX - panX.value\n panStartY.value = e.clientY - panY.value\n }\n\n const handlePanMove = (e: MouseEvent) => {\n if (!isPanning.value) return\n panX.value = e.clientX - panStartX.value\n panY.value = e.clientY - panStartY.value\n }\n\n const handlePanEnd = () => {\n isPanning.value = false\n }\n\n const zoomIn = () => {\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\n }\n\n const zoomOut = () => {\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\n }\n\n const resetView = () => {\n zoom.value = props.initialZoom\n panX.value = 0\n panY.value = 0\n }\n\n // ─── 事件桥接 ───\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\n\n defineExpose({\n zoomIn,\n zoomOut,\n resetView,\n zoom,\n })\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_OrgChart 组织架构图组件\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-orgchart\"\n :class=\"[\n `c-orgchart--${props.direction}`,\n `c-orgchart--line-${props.lineStyle}`,\n ]\"\n :style=\"cssVars\"\n @wheel.prevent=\"handleWheel\"\n @mousedown=\"handlePanStart\"\n @mousemove=\"handlePanMove\"\n @mouseup=\"handlePanEnd\"\n @mouseleave=\"handlePanEnd\"\n >\n <div\n class=\"c-orgchart__viewport\"\n :style=\"viewportStyle\"\n >\n <OrgNode\n :node=\"props.data\"\n :collapsible=\"props.collapsible\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @node-collapse=\"handleNodeCollapse\"\n >\n <template\n v-if=\"$slots.node\"\n #node=\"slotProps\"\n >\n <slot\n name=\"node\"\n v-bind=\"slotProps\"\n />\n </template>\n </OrgNode>\n </div>\n\n <!-- 缩放控制 -->\n <div\n v-if=\"props.zoomable\"\n class=\"c-orgchart__controls\"\n >\n <button\n class=\"c-orgchart__control-btn\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n +\n </button>\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n −\n </button>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"重置\"\n @click=\"resetView\"\n >\n ⟳\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed } from 'vue'\n import OrgNode from './OrgNode.vue'\n import type { OrgChartProps, OrgChartNode } from './types'\n\n defineOptions({ name: 'C_OrgChart' })\n\n const props = withDefaults(defineProps<OrgChartProps>(), {\n direction: 'vertical',\n lineStyle: 'rounded',\n lineColor: '#d1d5db',\n lineWidth: 2,\n nodeSpacing: 24,\n levelSpacing: 48,\n zoomable: true,\n pannable: true,\n initialZoom: 1,\n minZoom: 0.3,\n maxZoom: 2,\n collapsible: true,\n })\n\n const emit = defineEmits<{\n 'node-click': [node: OrgChartNode]\n 'node-expand': [node: OrgChartNode]\n 'node-collapse': [node: OrgChartNode]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n\n // ─── 缩放 & 平移 ───\n const zoom = ref(props.initialZoom)\n const panX = ref(0)\n const panY = ref(0)\n const isPanning = ref(false)\n const panStartX = ref(0)\n const panStartY = ref(0)\n\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\n\n const cssVars = computed(() => ({\n '--c-orgchart-line-color': props.lineColor,\n '--c-orgchart-line-width': `${props.lineWidth}px`,\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\n }))\n\n const viewportStyle = computed(() => ({\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\n transformOrigin: 'center top',\n }))\n\n /**\n * * @description: 鼠标滚轮缩放\n */\n const handleWheel = (e: WheelEvent) => {\n if (!props.zoomable) return\n const delta = e.deltaY > 0 ? -0.1 : 0.1\n const newZoom = Math.max(\n props.minZoom,\n Math.min(props.maxZoom, zoom.value + delta)\n )\n zoom.value = Math.round(newZoom * 100) / 100\n }\n\n const handlePanStart = (e: MouseEvent) => {\n if (!props.pannable) return\n isPanning.value = true\n panStartX.value = e.clientX - panX.value\n panStartY.value = e.clientY - panY.value\n }\n\n const handlePanMove = (e: MouseEvent) => {\n if (!isPanning.value) return\n panX.value = e.clientX - panStartX.value\n panY.value = e.clientY - panStartY.value\n }\n\n const handlePanEnd = () => {\n isPanning.value = false\n }\n\n const zoomIn = () => {\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\n }\n\n const zoomOut = () => {\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\n }\n\n const resetView = () => {\n zoom.value = props.initialZoom\n panX.value = 0\n panY.value = 0\n }\n\n // ─── 事件桥接 ───\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\n\n defineExpose({\n zoomIn,\n zoomOut,\n resetView,\n zoom,\n })\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_OrgChart 组织架构图组件\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-orgchart\"\n :class=\"[\n `c-orgchart--${props.direction}`,\n `c-orgchart--line-${props.lineStyle}`,\n ]\"\n :style=\"cssVars\"\n @wheel.prevent=\"handleWheel\"\n @mousedown=\"handlePanStart\"\n @mousemove=\"handlePanMove\"\n @mouseup=\"handlePanEnd\"\n @mouseleave=\"handlePanEnd\"\n >\n <div\n class=\"c-orgchart__viewport\"\n :style=\"viewportStyle\"\n >\n <OrgNode\n :node=\"props.data\"\n :collapsible=\"props.collapsible\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @node-collapse=\"handleNodeCollapse\"\n >\n <template\n v-if=\"$slots.node\"\n #node=\"slotProps\"\n >\n <slot\n name=\"node\"\n v-bind=\"slotProps\"\n />\n </template>\n </OrgNode>\n </div>\n\n <!-- 缩放控制 -->\n <div\n v-if=\"props.zoomable\"\n class=\"c-orgchart__controls\"\n >\n <button\n class=\"c-orgchart__control-btn\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n +\n </button>\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n −\n </button>\n <button\n class=\"c-orgchart__control-btn\"\n title=\"重置\"\n @click=\"resetView\"\n >\n ⟳\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed } from 'vue'\n import OrgNode from './OrgNode.vue'\n import type { OrgChartProps, OrgChartNode } from './types'\n\n defineOptions({ name: 'C_OrgChart' })\n\n const props = withDefaults(defineProps<OrgChartProps>(), {\n direction: 'vertical',\n lineStyle: 'rounded',\n lineColor: '#d1d5db',\n lineWidth: 2,\n nodeSpacing: 24,\n levelSpacing: 48,\n zoomable: true,\n pannable: true,\n initialZoom: 1,\n minZoom: 0.3,\n maxZoom: 2,\n collapsible: true,\n })\n\n const emit = defineEmits<{\n 'node-click': [node: OrgChartNode]\n 'node-expand': [node: OrgChartNode]\n 'node-collapse': [node: OrgChartNode]\n }>()\n\n const containerRef = ref<HTMLElement | null>(null)\n\n // ─── 缩放 & 平移 ───\n const zoom = ref(props.initialZoom)\n const panX = ref(0)\n const panY = ref(0)\n const isPanning = ref(false)\n const panStartX = ref(0)\n const panStartY = ref(0)\n\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\n\n const cssVars = computed(() => ({\n '--c-orgchart-line-color': props.lineColor,\n '--c-orgchart-line-width': `${props.lineWidth}px`,\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\n }))\n\n const viewportStyle = computed(() => ({\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\n transformOrigin: 'center top',\n }))\n\n /**\n * * @description: 鼠标滚轮缩放\n */\n const handleWheel = (e: WheelEvent) => {\n if (!props.zoomable) return\n const delta = e.deltaY > 0 ? -0.1 : 0.1\n const newZoom = Math.max(\n props.minZoom,\n Math.min(props.maxZoom, zoom.value + delta)\n )\n zoom.value = Math.round(newZoom * 100) / 100\n }\n\n const handlePanStart = (e: MouseEvent) => {\n if (!props.pannable) return\n isPanning.value = true\n panStartX.value = e.clientX - panX.value\n panStartY.value = e.clientY - panY.value\n }\n\n const handlePanMove = (e: MouseEvent) => {\n if (!isPanning.value) return\n panX.value = e.clientX - panStartX.value\n panY.value = e.clientY - panStartY.value\n }\n\n const handlePanEnd = () => {\n isPanning.value = false\n }\n\n const zoomIn = () => {\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\n }\n\n const zoomOut = () => {\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\n }\n\n const resetView = () => {\n zoom.value = props.initialZoom\n panX.value = 0\n panY.value = 0\n }\n\n // ─── 事件桥接 ───\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\n\n defineExpose({\n zoomIn,\n zoomOut,\n resetView,\n zoom,\n })\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_OrgChart2.js","names":["node","$emit","collapsible","$slots"],"sources":["../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/OrgNode.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue","../src/components/C_OrgChart/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 递归节点组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div class=\"c-orgchart__node-wrapper\">\r\n <!-- 节点卡片 -->\r\n <div\r\n class=\"c-orgchart__node\"\r\n :class=\"[node.className, { 'c-orgchart__node--leaf': isLeaf }]\"\r\n @click.stop=\"$emit('node-click', node)\"\r\n >\r\n <slot\r\n name=\"node\"\r\n :node=\"node\"\r\n :is-leaf=\"isLeaf\"\r\n :is-expanded=\"isExpanded\"\r\n >\r\n <!-- 默认节点渲染 -->\r\n <div class=\"c-orgchart__node-default\">\r\n <div\r\n v-if=\"node.avatar\"\r\n class=\"c-orgchart__avatar\"\r\n >\r\n <img\r\n :src=\"node.avatar\"\r\n :alt=\"node.label\"\r\n />\r\n </div>\r\n <div class=\"c-orgchart__info\">\r\n <div class=\"c-orgchart__label\">{{ node.label }}</div>\r\n <div\r\n v-if=\"node.subtitle\"\r\n class=\"c-orgchart__subtitle\"\r\n >\r\n {{ node.subtitle }}\r\n </div>\r\n </div>\r\n </div>\r\n </slot>\r\n\r\n <!-- 折叠/展开按钮 -->\r\n <button\r\n v-if=\"collapsible && !isLeaf\"\r\n class=\"c-orgchart__toggle\"\r\n @click.stop=\"toggleExpand\"\r\n >\r\n {{ isExpanded ? '−' : '+' }}\r\n </button>\r\n </div>\r\n\r\n <!-- 子节点容器 -->\r\n <div\r\n v-if=\"hasChildren && isExpanded\"\r\n class=\"c-orgchart__children\"\r\n >\r\n <OrgNode\r\n v-for=\"child in node.children\"\r\n :key=\"child.id\"\r\n :node=\"child\"\r\n :collapsible=\"collapsible\"\r\n @node-click=\"$emit('node-click', $event)\"\r\n @node-expand=\"$emit('node-expand', $event)\"\r\n @node-collapse=\"$emit('node-collapse', $event)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import type { OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'OrgNode' })\r\n\r\n const props = defineProps<{\r\n node: OrgChartNode\r\n collapsible?: boolean\r\n }>()\r\n\r\n defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const isExpanded = ref(!props.node.collapsed)\r\n\r\n const hasChildren = computed(\r\n () => props.node.children && props.node.children.length > 0\r\n )\r\n\r\n const isLeaf = computed(() => !hasChildren.value)\r\n\r\n const toggleExpand = () => {\r\n isExpanded.value = !isExpanded.value\r\n }\r\n</script>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 组织架构图组件\r\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\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-orgchart\"\r\n :class=\"[\r\n `c-orgchart--${props.direction}`,\r\n `c-orgchart--line-${props.lineStyle}`,\r\n ]\"\r\n :style=\"cssVars\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown=\"handlePanStart\"\r\n @mousemove=\"handlePanMove\"\r\n @mouseup=\"handlePanEnd\"\r\n @mouseleave=\"handlePanEnd\"\r\n >\r\n <div\r\n class=\"c-orgchart__viewport\"\r\n :style=\"viewportStyle\"\r\n >\r\n <OrgNode\r\n :node=\"props.data\"\r\n :collapsible=\"props.collapsible\"\r\n @node-click=\"handleNodeClick\"\r\n @node-expand=\"handleNodeExpand\"\r\n @node-collapse=\"handleNodeCollapse\"\r\n >\r\n <template\r\n v-if=\"$slots.node\"\r\n #node=\"slotProps\"\r\n >\r\n <slot\r\n name=\"node\"\r\n v-bind=\"slotProps\"\r\n />\r\n </template>\r\n </OrgNode>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div\r\n v-if=\"props.zoomable\"\r\n class=\"c-orgchart__controls\"\r\n >\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"放大\"\r\n @click=\"zoomIn\"\r\n >\r\n +\r\n </button>\r\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"缩小\"\r\n @click=\"zoomOut\"\r\n >\r\n −\r\n </button>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"重置\"\r\n @click=\"resetView\"\r\n >\r\n ⟳\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import OrgNode from './OrgNode.vue'\r\n import type { OrgChartProps, OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'C_OrgChart' })\r\n\r\n const props = withDefaults(defineProps<OrgChartProps>(), {\r\n direction: 'vertical',\r\n lineStyle: 'rounded',\r\n lineColor: '#d1d5db',\r\n lineWidth: 2,\r\n nodeSpacing: 24,\r\n levelSpacing: 48,\r\n zoomable: true,\r\n pannable: true,\r\n initialZoom: 1,\r\n minZoom: 0.3,\r\n maxZoom: 2,\r\n collapsible: true,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n\r\n // ─── 缩放 & 平移 ───\r\n const zoom = ref(props.initialZoom)\r\n const panX = ref(0)\r\n const panY = ref(0)\r\n const isPanning = ref(false)\r\n const panStartX = ref(0)\r\n const panStartY = ref(0)\r\n\r\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\r\n\r\n const cssVars = computed(() => ({\r\n '--c-orgchart-line-color': props.lineColor,\r\n '--c-orgchart-line-width': `${props.lineWidth}px`,\r\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\r\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\r\n }))\r\n\r\n const viewportStyle = computed(() => ({\r\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\r\n transformOrigin: 'center top',\r\n }))\r\n\r\n /**\r\n * * @description: 鼠标滚轮缩放\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable) return\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(\r\n props.minZoom,\r\n Math.min(props.maxZoom, zoom.value + delta)\r\n )\r\n zoom.value = Math.round(newZoom * 100) / 100\r\n }\r\n\r\n const handlePanStart = (e: MouseEvent) => {\r\n if (!props.pannable) return\r\n isPanning.value = true\r\n panStartX.value = e.clientX - panX.value\r\n panStartY.value = e.clientY - panY.value\r\n }\r\n\r\n const handlePanMove = (e: MouseEvent) => {\r\n if (!isPanning.value) return\r\n panX.value = e.clientX - panStartX.value\r\n panY.value = e.clientY - panStartY.value\r\n }\r\n\r\n const handlePanEnd = () => {\r\n isPanning.value = false\r\n }\r\n\r\n const zoomIn = () => {\r\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\r\n }\r\n\r\n const zoomOut = () => {\r\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\r\n }\r\n\r\n const resetView = () => {\r\n zoom.value = props.initialZoom\r\n panX.value = 0\r\n panY.value = 0\r\n }\r\n\r\n // ─── 事件桥接 ───\r\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\r\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\r\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\r\n\r\n defineExpose({\r\n zoomIn,\r\n zoomOut,\r\n resetView,\r\n zoom,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\">\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-03-06\r\n * @Description: C_OrgChart 组织架构图组件\r\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\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-orgchart\"\r\n :class=\"[\r\n `c-orgchart--${props.direction}`,\r\n `c-orgchart--line-${props.lineStyle}`,\r\n ]\"\r\n :style=\"cssVars\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown=\"handlePanStart\"\r\n @mousemove=\"handlePanMove\"\r\n @mouseup=\"handlePanEnd\"\r\n @mouseleave=\"handlePanEnd\"\r\n >\r\n <div\r\n class=\"c-orgchart__viewport\"\r\n :style=\"viewportStyle\"\r\n >\r\n <OrgNode\r\n :node=\"props.data\"\r\n :collapsible=\"props.collapsible\"\r\n @node-click=\"handleNodeClick\"\r\n @node-expand=\"handleNodeExpand\"\r\n @node-collapse=\"handleNodeCollapse\"\r\n >\r\n <template\r\n v-if=\"$slots.node\"\r\n #node=\"slotProps\"\r\n >\r\n <slot\r\n name=\"node\"\r\n v-bind=\"slotProps\"\r\n />\r\n </template>\r\n </OrgNode>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div\r\n v-if=\"props.zoomable\"\r\n class=\"c-orgchart__controls\"\r\n >\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"放大\"\r\n @click=\"zoomIn\"\r\n >\r\n +\r\n </button>\r\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"缩小\"\r\n @click=\"zoomOut\"\r\n >\r\n −\r\n </button>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"重置\"\r\n @click=\"resetView\"\r\n >\r\n ⟳\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import OrgNode from './OrgNode.vue'\r\n import type { OrgChartProps, OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'C_OrgChart' })\r\n\r\n const props = withDefaults(defineProps<OrgChartProps>(), {\r\n direction: 'vertical',\r\n lineStyle: 'rounded',\r\n lineColor: '#d1d5db',\r\n lineWidth: 2,\r\n nodeSpacing: 24,\r\n levelSpacing: 48,\r\n zoomable: true,\r\n pannable: true,\r\n initialZoom: 1,\r\n minZoom: 0.3,\r\n maxZoom: 2,\r\n collapsible: true,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n\r\n // ─── 缩放 & 平移 ───\r\n const zoom = ref(props.initialZoom)\r\n const panX = ref(0)\r\n const panY = ref(0)\r\n const isPanning = ref(false)\r\n const panStartX = ref(0)\r\n const panStartY = ref(0)\r\n\r\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\r\n\r\n const cssVars = computed(() => ({\r\n '--c-orgchart-line-color': props.lineColor,\r\n '--c-orgchart-line-width': `${props.lineWidth}px`,\r\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\r\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\r\n }))\r\n\r\n const viewportStyle = computed(() => ({\r\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\r\n transformOrigin: 'center top',\r\n }))\r\n\r\n /**\r\n * * @description: 鼠标滚轮缩放\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable) return\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(\r\n props.minZoom,\r\n Math.min(props.maxZoom, zoom.value + delta)\r\n )\r\n zoom.value = Math.round(newZoom * 100) / 100\r\n }\r\n\r\n const handlePanStart = (e: MouseEvent) => {\r\n if (!props.pannable) return\r\n isPanning.value = true\r\n panStartX.value = e.clientX - panX.value\r\n panStartY.value = e.clientY - panY.value\r\n }\r\n\r\n const handlePanMove = (e: MouseEvent) => {\r\n if (!isPanning.value) return\r\n panX.value = e.clientX - panStartX.value\r\n panY.value = e.clientY - panStartY.value\r\n }\r\n\r\n const handlePanEnd = () => {\r\n isPanning.value = false\r\n }\r\n\r\n const zoomIn = () => {\r\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\r\n }\r\n\r\n const zoomOut = () => {\r\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\r\n }\r\n\r\n const resetView = () => {\r\n zoom.value = props.initialZoom\r\n panX.value = 0\r\n panY.value = 0\r\n }\r\n\r\n // ─── 事件桥接 ───\r\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\r\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\r\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\r\n\r\n defineExpose({\r\n zoomIn,\r\n zoomOut,\r\n resetView,\r\n zoom,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_OrgChart 组织架构图组件\r\n * 纯 CSS + Vue 实现的树形组织架构图,支持缩放/平移/折叠\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-orgchart\"\r\n :class=\"[\r\n `c-orgchart--${props.direction}`,\r\n `c-orgchart--line-${props.lineStyle}`,\r\n ]\"\r\n :style=\"cssVars\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown=\"handlePanStart\"\r\n @mousemove=\"handlePanMove\"\r\n @mouseup=\"handlePanEnd\"\r\n @mouseleave=\"handlePanEnd\"\r\n >\r\n <div\r\n class=\"c-orgchart__viewport\"\r\n :style=\"viewportStyle\"\r\n >\r\n <OrgNode\r\n :node=\"props.data\"\r\n :collapsible=\"props.collapsible\"\r\n @node-click=\"handleNodeClick\"\r\n @node-expand=\"handleNodeExpand\"\r\n @node-collapse=\"handleNodeCollapse\"\r\n >\r\n <template\r\n v-if=\"$slots.node\"\r\n #node=\"slotProps\"\r\n >\r\n <slot\r\n name=\"node\"\r\n v-bind=\"slotProps\"\r\n />\r\n </template>\r\n </OrgNode>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div\r\n v-if=\"props.zoomable\"\r\n class=\"c-orgchart__controls\"\r\n >\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"放大\"\r\n @click=\"zoomIn\"\r\n >\r\n +\r\n </button>\r\n <span class=\"c-orgchart__zoom-level\">{{ zoomPercent }}%</span>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"缩小\"\r\n @click=\"zoomOut\"\r\n >\r\n −\r\n </button>\r\n <button\r\n class=\"c-orgchart__control-btn\"\r\n title=\"重置\"\r\n @click=\"resetView\"\r\n >\r\n ⟳\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, computed } from 'vue'\r\n import OrgNode from './OrgNode.vue'\r\n import type { OrgChartProps, OrgChartNode } from './types'\r\n\r\n defineOptions({ name: 'C_OrgChart' })\r\n\r\n const props = withDefaults(defineProps<OrgChartProps>(), {\r\n direction: 'vertical',\r\n lineStyle: 'rounded',\r\n lineColor: '#d1d5db',\r\n lineWidth: 2,\r\n nodeSpacing: 24,\r\n levelSpacing: 48,\r\n zoomable: true,\r\n pannable: true,\r\n initialZoom: 1,\r\n minZoom: 0.3,\r\n maxZoom: 2,\r\n collapsible: true,\r\n })\r\n\r\n const emit = defineEmits<{\r\n 'node-click': [node: OrgChartNode]\r\n 'node-expand': [node: OrgChartNode]\r\n 'node-collapse': [node: OrgChartNode]\r\n }>()\r\n\r\n const containerRef = ref<HTMLElement | null>(null)\r\n\r\n // ─── 缩放 & 平移 ───\r\n const zoom = ref(props.initialZoom)\r\n const panX = ref(0)\r\n const panY = ref(0)\r\n const isPanning = ref(false)\r\n const panStartX = ref(0)\r\n const panStartY = ref(0)\r\n\r\n const zoomPercent = computed(() => Math.round(zoom.value * 100))\r\n\r\n const cssVars = computed(() => ({\r\n '--c-orgchart-line-color': props.lineColor,\r\n '--c-orgchart-line-width': `${props.lineWidth}px`,\r\n '--c-orgchart-node-spacing': `${props.nodeSpacing}px`,\r\n '--c-orgchart-level-spacing': `${props.levelSpacing}px`,\r\n }))\r\n\r\n const viewportStyle = computed(() => ({\r\n transform: `translate(${panX.value}px, ${panY.value}px) scale(${zoom.value})`,\r\n transformOrigin: 'center top',\r\n }))\r\n\r\n /**\r\n * * @description: 鼠标滚轮缩放\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n if (!props.zoomable) return\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1\r\n const newZoom = Math.max(\r\n props.minZoom,\r\n Math.min(props.maxZoom, zoom.value + delta)\r\n )\r\n zoom.value = Math.round(newZoom * 100) / 100\r\n }\r\n\r\n const handlePanStart = (e: MouseEvent) => {\r\n if (!props.pannable) return\r\n isPanning.value = true\r\n panStartX.value = e.clientX - panX.value\r\n panStartY.value = e.clientY - panY.value\r\n }\r\n\r\n const handlePanMove = (e: MouseEvent) => {\r\n if (!isPanning.value) return\r\n panX.value = e.clientX - panStartX.value\r\n panY.value = e.clientY - panStartY.value\r\n }\r\n\r\n const handlePanEnd = () => {\r\n isPanning.value = false\r\n }\r\n\r\n const zoomIn = () => {\r\n zoom.value = Math.min(props.maxZoom, zoom.value + 0.1)\r\n }\r\n\r\n const zoomOut = () => {\r\n zoom.value = Math.max(props.minZoom, zoom.value - 0.1)\r\n }\r\n\r\n const resetView = () => {\r\n zoom.value = props.initialZoom\r\n panX.value = 0\r\n panY.value = 0\r\n }\r\n\r\n // ─── 事件桥接 ───\r\n const handleNodeClick = (node: OrgChartNode) => emit('node-click', node)\r\n const handleNodeExpand = (node: OrgChartNode) => emit('node-expand', node)\r\n const handleNodeCollapse = (node: OrgChartNode) => emit('node-collapse', node)\r\n\r\n defineExpose({\r\n zoomIn,\r\n zoomOut,\r\n resetView,\r\n zoom,\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
package/dist/C_Skeleton.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Skeleton.js","names":["preset","repeat"],"sources":["../src/components/C_Skeleton/index.vue","../src/components/C_Skeleton/index.vue","../src/components/C_Skeleton/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","/* unplugin-vue-components disabled */<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_Skeleton.js","names":["preset","repeat"],"sources":["../src/components/C_Skeleton/index.vue","../src/components/C_Skeleton/index.vue","../src/components/C_Skeleton/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_Skeleton 业务级骨架屏组件\r\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n v-if=\"props.loading\"\r\n class=\"c-skeleton\"\r\n :class=\"[`c-skeleton--${animationType}`]\"\r\n >\r\n <!-- text 预设 -->\r\n <template v-if=\"preset === 'text'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__text\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- avatar 预设 -->\r\n <template v-else-if=\"preset === 'avatar'\">\r\n <div class=\"c-skeleton__avatar-group\">\r\n <div class=\"c-skeleton__circle c-skeleton__item\" />\r\n <div class=\"c-skeleton__avatar-text\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 40%\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 60%\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- image 预设 -->\r\n <template v-else-if=\"preset === 'image'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__image c-skeleton__item\"\r\n >\r\n <div class=\"c-skeleton__image-icon\">\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"32\"\r\n height=\"32\"\r\n >\r\n <path\r\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\r\n />\r\n </svg>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- card 预设 -->\r\n <template v-else-if=\"preset === 'card'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__card\"\r\n >\r\n <div\r\n v-if=\"cardConfig.showCover\"\r\n class=\"c-skeleton__card-cover c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__card-body\">\r\n <div\r\n v-for=\"t in cardConfig.titleLines\"\r\n :key=\"`t-${t}`\"\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\r\n />\r\n <div class=\"c-skeleton__card-desc\">\r\n <div\r\n v-for=\"d in cardConfig.descLines\"\r\n :key=\"`d-${d}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: d === cardConfig.descLines ? '70%' : '100%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"cardConfig.showFooter\"\r\n class=\"c-skeleton__card-footer\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- table 预设 -->\r\n <template v-else-if=\"preset === 'table'\">\r\n <div class=\"c-skeleton__table\">\r\n <div\r\n v-if=\"tableConfig.showHeader\"\r\n class=\"c-skeleton__table-header\"\r\n >\r\n <div\r\n v-for=\"c in tableConfig.cols\"\r\n :key=\"`h-${c}`\"\r\n class=\"c-skeleton__table-cell\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"tableConfig.showActions\"\r\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 60%\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n v-for=\"r in tableConfig.rows\"\r\n :key=\"`r-${r}`\"\r\n class=\"c-skeleton__table-row\"\r\n >\r\n <div\r\n v-for=\"c in tableConfig.cols\"\r\n :key=\"`c-${c}`\"\r\n class=\"c-skeleton__table-cell\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\r\n }\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"tableConfig.showActions\"\r\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\r\n >\r\n <div class=\"c-skeleton__action-btns\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\r\n style=\"width: 40px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\r\n style=\"width: 40px\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- form 预设 -->\r\n <template v-else-if=\"preset === 'form'\">\r\n <div\r\n class=\"c-skeleton__form\"\r\n :style=\"{ '--form-cols': formConfig.cols }\"\r\n >\r\n <div\r\n v-for=\"f in formConfig.fields\"\r\n :key=\"f\"\r\n class=\"c-skeleton__form-field\"\r\n >\r\n <div\r\n v-if=\"formConfig.showLabel\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\r\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"formConfig.showActions\"\r\n class=\"c-skeleton__form-actions\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 100px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- list 预设 -->\r\n <template v-else-if=\"preset === 'list'\">\r\n <div\r\n v-for=\"i in listConfig.items\"\r\n :key=\"i\"\r\n class=\"c-skeleton__list-item\"\r\n >\r\n <div\r\n v-if=\"listConfig.showAvatar\"\r\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__list-content\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 30%\"\r\n />\r\n <div\r\n v-for=\"d in listConfig.descLines\"\r\n :key=\"`d-${d}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: d === listConfig.descLines ? '50%' : '90%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- detail 预设 -->\r\n <template v-else-if=\"preset === 'detail'\">\r\n <div class=\"c-skeleton__detail\">\r\n <div\r\n v-if=\"detailConfig.showAvatar\"\r\n class=\"c-skeleton__detail-header\"\r\n >\r\n <div\r\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__detail-title\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 120px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 200px\"\r\n />\r\n </div>\r\n </div>\r\n <div class=\"c-skeleton__detail-body\">\r\n <div\r\n v-for=\"f in detailConfig.fields\"\r\n :key=\"f\"\r\n class=\"c-skeleton__detail-field\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\r\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\r\n />\r\n <div class=\"c-skeleton__detail-value\">\r\n <div\r\n v-for=\"v in detailConfig.valueLines\"\r\n :key=\"`v-${v}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: v === detailConfig.valueLines ? '60%' : '100%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n\r\n <!-- 加载完成后显示插槽内容 -->\r\n <slot v-else />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import type {\r\n SkeletonProps,\r\n SkeletonTableConfig,\r\n SkeletonFormConfig,\r\n SkeletonListConfig,\r\n SkeletonCardConfig,\r\n SkeletonDetailConfig,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_Skeleton' })\r\n\r\n const props = withDefaults(defineProps<SkeletonProps>(), {\r\n preset: 'text',\r\n loading: true,\r\n animation: 'wave',\r\n repeat: 3,\r\n borderRadius: '4px',\r\n })\r\n\r\n const animationType = computed(() =>\r\n props.animation === false ? 'none' : props.animation\r\n )\r\n\r\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\r\n rows: props.table?.rows ?? 5,\r\n cols: props.table?.cols ?? 4,\r\n showHeader: props.table?.showHeader ?? true,\r\n showActions: props.table?.showActions ?? true,\r\n }))\r\n\r\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\r\n fields: props.form?.fields ?? 6,\r\n cols: props.form?.cols ?? 2,\r\n showLabel: props.form?.showLabel ?? true,\r\n showActions: props.form?.showActions ?? true,\r\n }))\r\n\r\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\r\n items: props.list?.items ?? 5,\r\n showAvatar: props.list?.showAvatar ?? true,\r\n descLines: props.list?.descLines ?? 2,\r\n }))\r\n\r\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\r\n showCover: props.card?.showCover ?? true,\r\n titleLines: props.card?.titleLines ?? 1,\r\n descLines: props.card?.descLines ?? 2,\r\n showFooter: props.card?.showFooter ?? true,\r\n }))\r\n\r\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\r\n fields: props.detail?.fields ?? 6,\r\n valueLines: props.detail?.valueLines ?? 1,\r\n showAvatar: props.detail?.showAvatar ?? true,\r\n }))\r\n</script>\r\n\r\n<style lang=\"scss\">\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-03-06\r\n * @Description: C_Skeleton 业务级骨架屏组件\r\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n v-if=\"props.loading\"\r\n class=\"c-skeleton\"\r\n :class=\"[`c-skeleton--${animationType}`]\"\r\n >\r\n <!-- text 预设 -->\r\n <template v-if=\"preset === 'text'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__text\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- avatar 预设 -->\r\n <template v-else-if=\"preset === 'avatar'\">\r\n <div class=\"c-skeleton__avatar-group\">\r\n <div class=\"c-skeleton__circle c-skeleton__item\" />\r\n <div class=\"c-skeleton__avatar-text\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 40%\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 60%\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- image 预设 -->\r\n <template v-else-if=\"preset === 'image'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__image c-skeleton__item\"\r\n >\r\n <div class=\"c-skeleton__image-icon\">\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"32\"\r\n height=\"32\"\r\n >\r\n <path\r\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\r\n />\r\n </svg>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- card 预设 -->\r\n <template v-else-if=\"preset === 'card'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__card\"\r\n >\r\n <div\r\n v-if=\"cardConfig.showCover\"\r\n class=\"c-skeleton__card-cover c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__card-body\">\r\n <div\r\n v-for=\"t in cardConfig.titleLines\"\r\n :key=\"`t-${t}`\"\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\r\n />\r\n <div class=\"c-skeleton__card-desc\">\r\n <div\r\n v-for=\"d in cardConfig.descLines\"\r\n :key=\"`d-${d}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: d === cardConfig.descLines ? '70%' : '100%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"cardConfig.showFooter\"\r\n class=\"c-skeleton__card-footer\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- table 预设 -->\r\n <template v-else-if=\"preset === 'table'\">\r\n <div class=\"c-skeleton__table\">\r\n <div\r\n v-if=\"tableConfig.showHeader\"\r\n class=\"c-skeleton__table-header\"\r\n >\r\n <div\r\n v-for=\"c in tableConfig.cols\"\r\n :key=\"`h-${c}`\"\r\n class=\"c-skeleton__table-cell\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"tableConfig.showActions\"\r\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 60%\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n v-for=\"r in tableConfig.rows\"\r\n :key=\"`r-${r}`\"\r\n class=\"c-skeleton__table-row\"\r\n >\r\n <div\r\n v-for=\"c in tableConfig.cols\"\r\n :key=\"`c-${c}`\"\r\n class=\"c-skeleton__table-cell\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\r\n }\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"tableConfig.showActions\"\r\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\r\n >\r\n <div class=\"c-skeleton__action-btns\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\r\n style=\"width: 40px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\r\n style=\"width: 40px\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- form 预设 -->\r\n <template v-else-if=\"preset === 'form'\">\r\n <div\r\n class=\"c-skeleton__form\"\r\n :style=\"{ '--form-cols': formConfig.cols }\"\r\n >\r\n <div\r\n v-for=\"f in formConfig.fields\"\r\n :key=\"f\"\r\n class=\"c-skeleton__form-field\"\r\n >\r\n <div\r\n v-if=\"formConfig.showLabel\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\r\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"formConfig.showActions\"\r\n class=\"c-skeleton__form-actions\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 100px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- list 预设 -->\r\n <template v-else-if=\"preset === 'list'\">\r\n <div\r\n v-for=\"i in listConfig.items\"\r\n :key=\"i\"\r\n class=\"c-skeleton__list-item\"\r\n >\r\n <div\r\n v-if=\"listConfig.showAvatar\"\r\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__list-content\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 30%\"\r\n />\r\n <div\r\n v-for=\"d in listConfig.descLines\"\r\n :key=\"`d-${d}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: d === listConfig.descLines ? '50%' : '90%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- detail 预设 -->\r\n <template v-else-if=\"preset === 'detail'\">\r\n <div class=\"c-skeleton__detail\">\r\n <div\r\n v-if=\"detailConfig.showAvatar\"\r\n class=\"c-skeleton__detail-header\"\r\n >\r\n <div\r\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__detail-title\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 120px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 200px\"\r\n />\r\n </div>\r\n </div>\r\n <div class=\"c-skeleton__detail-body\">\r\n <div\r\n v-for=\"f in detailConfig.fields\"\r\n :key=\"f\"\r\n class=\"c-skeleton__detail-field\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\r\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\r\n />\r\n <div class=\"c-skeleton__detail-value\">\r\n <div\r\n v-for=\"v in detailConfig.valueLines\"\r\n :key=\"`v-${v}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: v === detailConfig.valueLines ? '60%' : '100%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n\r\n <!-- 加载完成后显示插槽内容 -->\r\n <slot v-else />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import type {\r\n SkeletonProps,\r\n SkeletonTableConfig,\r\n SkeletonFormConfig,\r\n SkeletonListConfig,\r\n SkeletonCardConfig,\r\n SkeletonDetailConfig,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_Skeleton' })\r\n\r\n const props = withDefaults(defineProps<SkeletonProps>(), {\r\n preset: 'text',\r\n loading: true,\r\n animation: 'wave',\r\n repeat: 3,\r\n borderRadius: '4px',\r\n })\r\n\r\n const animationType = computed(() =>\r\n props.animation === false ? 'none' : props.animation\r\n )\r\n\r\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\r\n rows: props.table?.rows ?? 5,\r\n cols: props.table?.cols ?? 4,\r\n showHeader: props.table?.showHeader ?? true,\r\n showActions: props.table?.showActions ?? true,\r\n }))\r\n\r\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\r\n fields: props.form?.fields ?? 6,\r\n cols: props.form?.cols ?? 2,\r\n showLabel: props.form?.showLabel ?? true,\r\n showActions: props.form?.showActions ?? true,\r\n }))\r\n\r\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\r\n items: props.list?.items ?? 5,\r\n showAvatar: props.list?.showAvatar ?? true,\r\n descLines: props.list?.descLines ?? 2,\r\n }))\r\n\r\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\r\n showCover: props.card?.showCover ?? true,\r\n titleLines: props.card?.titleLines ?? 1,\r\n descLines: props.card?.descLines ?? 2,\r\n showFooter: props.card?.showFooter ?? true,\r\n }))\r\n\r\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\r\n fields: props.detail?.fields ?? 6,\r\n valueLines: props.detail?.valueLines ?? 1,\r\n showAvatar: props.detail?.showAvatar ?? true,\r\n }))\r\n</script>\r\n\r\n<style lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-03-06\r\n * @Description: C_Skeleton 业务级骨架屏组件\r\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n v-if=\"props.loading\"\r\n class=\"c-skeleton\"\r\n :class=\"[`c-skeleton--${animationType}`]\"\r\n >\r\n <!-- text 预设 -->\r\n <template v-if=\"preset === 'text'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__text\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- avatar 预设 -->\r\n <template v-else-if=\"preset === 'avatar'\">\r\n <div class=\"c-skeleton__avatar-group\">\r\n <div class=\"c-skeleton__circle c-skeleton__item\" />\r\n <div class=\"c-skeleton__avatar-text\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 40%\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 60%\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- image 预设 -->\r\n <template v-else-if=\"preset === 'image'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__image c-skeleton__item\"\r\n >\r\n <div class=\"c-skeleton__image-icon\">\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"currentColor\"\r\n width=\"32\"\r\n height=\"32\"\r\n >\r\n <path\r\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\r\n />\r\n </svg>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- card 预设 -->\r\n <template v-else-if=\"preset === 'card'\">\r\n <div\r\n v-for=\"i in repeat\"\r\n :key=\"i\"\r\n class=\"c-skeleton__card\"\r\n >\r\n <div\r\n v-if=\"cardConfig.showCover\"\r\n class=\"c-skeleton__card-cover c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__card-body\">\r\n <div\r\n v-for=\"t in cardConfig.titleLines\"\r\n :key=\"`t-${t}`\"\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\r\n />\r\n <div class=\"c-skeleton__card-desc\">\r\n <div\r\n v-for=\"d in cardConfig.descLines\"\r\n :key=\"`d-${d}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: d === cardConfig.descLines ? '70%' : '100%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"cardConfig.showFooter\"\r\n class=\"c-skeleton__card-footer\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- table 预设 -->\r\n <template v-else-if=\"preset === 'table'\">\r\n <div class=\"c-skeleton__table\">\r\n <div\r\n v-if=\"tableConfig.showHeader\"\r\n class=\"c-skeleton__table-header\"\r\n >\r\n <div\r\n v-for=\"c in tableConfig.cols\"\r\n :key=\"`h-${c}`\"\r\n class=\"c-skeleton__table-cell\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"tableConfig.showActions\"\r\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 60%\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n v-for=\"r in tableConfig.rows\"\r\n :key=\"`r-${r}`\"\r\n class=\"c-skeleton__table-row\"\r\n >\r\n <div\r\n v-for=\"c in tableConfig.cols\"\r\n :key=\"`c-${c}`\"\r\n class=\"c-skeleton__table-cell\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\r\n }\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"tableConfig.showActions\"\r\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\r\n >\r\n <div class=\"c-skeleton__action-btns\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\r\n style=\"width: 40px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\r\n style=\"width: 40px\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- form 预设 -->\r\n <template v-else-if=\"preset === 'form'\">\r\n <div\r\n class=\"c-skeleton__form\"\r\n :style=\"{ '--form-cols': formConfig.cols }\"\r\n >\r\n <div\r\n v-for=\"f in formConfig.fields\"\r\n :key=\"f\"\r\n class=\"c-skeleton__form-field\"\r\n >\r\n <div\r\n v-if=\"formConfig.showLabel\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\r\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\r\n />\r\n </div>\r\n <div\r\n v-if=\"formConfig.showActions\"\r\n class=\"c-skeleton__form-actions\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 100px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- list 预设 -->\r\n <template v-else-if=\"preset === 'list'\">\r\n <div\r\n v-for=\"i in listConfig.items\"\r\n :key=\"i\"\r\n class=\"c-skeleton__list-item\"\r\n >\r\n <div\r\n v-if=\"listConfig.showAvatar\"\r\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__list-content\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 30%\"\r\n />\r\n <div\r\n v-for=\"d in listConfig.descLines\"\r\n :key=\"`d-${d}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: d === listConfig.descLines ? '50%' : '90%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- detail 预设 -->\r\n <template v-else-if=\"preset === 'detail'\">\r\n <div class=\"c-skeleton__detail\">\r\n <div\r\n v-if=\"detailConfig.showAvatar\"\r\n class=\"c-skeleton__detail-header\"\r\n >\r\n <div\r\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\r\n />\r\n <div class=\"c-skeleton__detail-title\">\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item\"\r\n style=\"width: 120px\"\r\n />\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n style=\"width: 200px\"\r\n />\r\n </div>\r\n </div>\r\n <div class=\"c-skeleton__detail-body\">\r\n <div\r\n v-for=\"f in detailConfig.fields\"\r\n :key=\"f\"\r\n class=\"c-skeleton__detail-field\"\r\n >\r\n <div\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\r\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\r\n />\r\n <div class=\"c-skeleton__detail-value\">\r\n <div\r\n v-for=\"v in detailConfig.valueLines\"\r\n :key=\"`v-${v}`\"\r\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\r\n :style=\"{\r\n width: v === detailConfig.valueLines ? '60%' : '100%',\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </template>\r\n </div>\r\n\r\n <!-- 加载完成后显示插槽内容 -->\r\n <slot v-else />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import type {\r\n SkeletonProps,\r\n SkeletonTableConfig,\r\n SkeletonFormConfig,\r\n SkeletonListConfig,\r\n SkeletonCardConfig,\r\n SkeletonDetailConfig,\r\n } from './types'\r\n\r\n defineOptions({ name: 'C_Skeleton' })\r\n\r\n const props = withDefaults(defineProps<SkeletonProps>(), {\r\n preset: 'text',\r\n loading: true,\r\n animation: 'wave',\r\n repeat: 3,\r\n borderRadius: '4px',\r\n })\r\n\r\n const animationType = computed(() =>\r\n props.animation === false ? 'none' : props.animation\r\n )\r\n\r\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\r\n rows: props.table?.rows ?? 5,\r\n cols: props.table?.cols ?? 4,\r\n showHeader: props.table?.showHeader ?? true,\r\n showActions: props.table?.showActions ?? true,\r\n }))\r\n\r\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\r\n fields: props.form?.fields ?? 6,\r\n cols: props.form?.cols ?? 2,\r\n showLabel: props.form?.showLabel ?? true,\r\n showActions: props.form?.showActions ?? true,\r\n }))\r\n\r\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\r\n items: props.list?.items ?? 5,\r\n showAvatar: props.list?.showAvatar ?? true,\r\n descLines: props.list?.descLines ?? 2,\r\n }))\r\n\r\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\r\n showCover: props.card?.showCover ?? true,\r\n titleLines: props.card?.titleLines ?? 1,\r\n descLines: props.card?.descLines ?? 2,\r\n showFooter: props.card?.showFooter ?? true,\r\n }))\r\n\r\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\r\n fields: props.detail?.fields ?? 6,\r\n valueLines: props.detail?.valueLines ?? 1,\r\n showAvatar: props.detail?.showAvatar ?? true,\r\n }))\r\n</script>\r\n\r\n<style lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|