verce-vue-test 0.0.0 → 0.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verce-vue-test",
3
- "version": "0.0.0",
3
+ "version": "0.0.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "scripts": {
package/src/App.vue CHANGED
@@ -27,6 +27,9 @@ import { RouterView } from 'vue-router'
27
27
  <el-menu-item index="/table-pro">
28
28
  <span>高级表格</span>
29
29
  </el-menu-item>
30
+ <el-menu-item index="/table-pro-for">
31
+ <span>循环表格</span>
32
+ </el-menu-item>
30
33
  <el-menu-item index="/about">
31
34
  <span>关于</span>
32
35
  </el-menu-item>
@@ -9,6 +9,7 @@ import {
9
9
  useAttrs,
10
10
  useSlots,
11
11
  cloneVNode,
12
+ Fragment,
12
13
  type VNode,
13
14
  } from 'vue'
14
15
  import { useRoute } from 'vue-router'
@@ -271,10 +272,22 @@ const cancelColumnConfig = () => {
271
272
  * 初始化列配置
272
273
  */
273
274
  const initColumns = () => {
274
- // 获取默认插槽中的子节点(列定义)
275
- const children = slots.default?.() || []
275
+ const rawChildren = slots.default?.() || []
276
+
277
+ const flattenVNodes = (vnodes: VNode[]): VNode[] => {
278
+ const result: VNode[] = []
279
+ for (const vnode of vnodes) {
280
+ if (vnode.type === Fragment && Array.isArray(vnode.children)) {
281
+ result.push(...flattenVNodes(vnode.children as VNode[]))
282
+ } else {
283
+ result.push(vnode)
284
+ }
285
+ }
286
+ return result
287
+ }
288
+
289
+ const children = flattenVNodes(rawChildren)
276
290
 
277
- // 转换为列选项列表
278
291
  columnOptions.value = children.map((vnode, index) => {
279
292
  return {
280
293
  key: getColumnKey(vnode, index),
@@ -284,7 +297,6 @@ const initColumns = () => {
284
297
  }
285
298
  })
286
299
 
287
- // 从本地存储恢复配置
288
300
  restoreColumnConfig()
289
301
  }
290
302
 
@@ -34,6 +34,11 @@ const router = createRouter({
34
34
  name: 'tablePro',
35
35
  component: () => import('../views/TableProView.vue'),
36
36
  },
37
+ {
38
+ path: '/table-pro-for',
39
+ name: 'tableProFor',
40
+ component: () => import('../views/TableProForView.vue'),
41
+ },
37
42
  ],
38
43
  })
39
44
 
@@ -0,0 +1,144 @@
1
+ <template>
2
+ <ElTablePro
3
+ :data="tableData"
4
+ :total="total"
5
+ v-model:page="query.page"
6
+ v-model:page-size="query.pageSize"
7
+ table-key="product"
8
+ row-key="id"
9
+ border
10
+ stripe
11
+ v-loading="loading"
12
+ @pagination-change="handlePaginationChange"
13
+ >
14
+ <template #toolbar>
15
+ <el-button type="primary" @click="handleAdd">新增</el-button>
16
+ </template>
17
+
18
+ <el-table-column
19
+ v-for="col in visibleColumns"
20
+ :key="col.prop"
21
+ :prop="col.prop"
22
+ :label="col.label"
23
+ :width="col.width"
24
+ :min-width="col.minWidth"
25
+ >
26
+ <template v-if="col.slot" #default="{ row }">
27
+ <el-tag
28
+ v-if="col.prop === 'status'"
29
+ :type="row.status ? 'success' : 'danger'"
30
+ >
31
+ {{ row.status ? '启用' : '禁用' }}
32
+ </el-tag>
33
+ <el-tag
34
+ v-else-if="col.prop === 'category'"
35
+ :type="categoryTagType(row.category)"
36
+ >
37
+ {{ row.category }}
38
+ </el-tag>
39
+ <template v-else-if="col.prop === 'action'">
40
+ <el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
41
+ <el-button link type="danger" @click="handleDelete(row)">删除</el-button>
42
+ </template>
43
+ </template>
44
+ </el-table-column>
45
+ </ElTablePro>
46
+ </template>
47
+
48
+ <script setup lang="ts">
49
+ import { ref, reactive, onMounted } from 'vue'
50
+ import { ElMessage, ElMessageBox } from 'element-plus'
51
+ import ElTablePro from '@/components/ElTablePro.vue'
52
+
53
+ interface ColumnConfig {
54
+ prop: string
55
+ label: string
56
+ width?: number | string
57
+ minWidth?: number | string
58
+ slot?: boolean
59
+ }
60
+
61
+ const columns: ColumnConfig[] = [
62
+ { prop: 'id', label: 'ID', width: 80 },
63
+ { prop: 'name', label: '商品名称', minWidth: 150 },
64
+ { prop: 'category', label: '分类', width: 120, slot: true },
65
+ { prop: 'price', label: '价格', width: 100 },
66
+ { prop: 'stock', label: '库存', width: 80 },
67
+ { prop: 'status', label: '状态', width: 100, slot: true },
68
+ { prop: 'action', label: '操作', width: 180, slot: true },
69
+ ]
70
+
71
+ const visibleColumns = columns
72
+
73
+ const loading = ref(false)
74
+ const total = ref(0)
75
+
76
+ const query = reactive({
77
+ page: 1,
78
+ pageSize: 10,
79
+ })
80
+
81
+ const allData = [
82
+ { id: 1, name: 'MacBook Pro 16"', category: '电子产品', price: 18999, stock: 50, status: true },
83
+ { id: 2, name: 'iPhone 17 Pro', category: '电子产品', price: 8999, stock: 120, status: true },
84
+ { id: 3, name: 'AirPods Max', category: '电子产品', price: 4399, stock: 80, status: false },
85
+ { id: 4, name: '耐克运动鞋', category: '服装鞋帽', price: 899, stock: 200, status: true },
86
+ { id: 5, name: '优衣库羽绒服', category: '服装鞋帽', price: 599, stock: 150, status: true },
87
+ { id: 6, name: '三只松鼠坚果礼盒', category: '食品饮料', price: 128, stock: 300, status: true },
88
+ { id: 7, name: '飞利浦电动牙刷', category: '家居用品', price: 399, stock: 90, status: true },
89
+ { id: 8, name: '小米空气净化器', category: '家居用品', price: 1299, stock: 60, status: false },
90
+ { id: 9, name: '星巴克咖啡豆', category: '食品饮料', price: 158, stock: 250, status: true },
91
+ { id: 10, name: '华为 MatePad Pro', category: '电子产品', price: 3699, stock: 70, status: true },
92
+ { id: 11, name: '阿迪达斯跑步鞋', category: '服装鞋帽', price: 799, stock: 180, status: true },
93
+ { id: 12, name: '戴森吹风机', category: '家居用品', price: 3199, stock: 40, status: true },
94
+ ]
95
+
96
+ const tableData = ref<any[]>([])
97
+
98
+ const categoryTagType = (category: string) => {
99
+ const map: Record<string, string> = {
100
+ '电子产品': 'primary',
101
+ '服装鞋帽': 'warning',
102
+ '食品饮料': 'success',
103
+ '家居用品': 'info',
104
+ }
105
+ return map[category] || 'info'
106
+ }
107
+
108
+ const getList = () => {
109
+ loading.value = true
110
+ setTimeout(() => {
111
+ const start = (query.page - 1) * query.pageSize
112
+ const end = start + query.pageSize
113
+ tableData.value = allData.slice(start, end)
114
+ total.value = allData.length
115
+ loading.value = false
116
+ }, 300)
117
+ }
118
+
119
+ const handlePaginationChange = (_value: { page: number; pageSize: number }) => {
120
+ getList()
121
+ }
122
+
123
+ const handleAdd = () => {
124
+ ElMessage.info('新增商品')
125
+ }
126
+
127
+ const handleEdit = (row: any) => {
128
+ ElMessage.info(`编辑商品: ${row.name}`)
129
+ }
130
+
131
+ const handleDelete = (row: any) => {
132
+ ElMessageBox.confirm(`确认删除商品 ${row.name}?`, '提示', {
133
+ confirmButtonText: '确认',
134
+ cancelButtonText: '取消',
135
+ type: 'warning',
136
+ }).then(() => {
137
+ ElMessage.success('删除成功')
138
+ }).catch(() => {})
139
+ }
140
+
141
+ onMounted(() => {
142
+ getList()
143
+ })
144
+ </script>