verce-vue-test 0.0.0 → 0.0.2

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.2",
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'
@@ -90,6 +91,7 @@ type ColumnOption = {
90
91
  key: string // 列唯一标识
91
92
  label: string // 列显示名称
92
93
  visible: boolean // 是否可见
94
+ disabled: boolean // 是否禁用选择
93
95
  vnode: VNode // 列的 VNode 节点
94
96
  }
95
97
 
@@ -143,10 +145,15 @@ const currentPageSize = computed({
143
145
 
144
146
  // 是否全选(弹窗中的临时状态)
145
147
  const isAllSelected = computed({
146
- get: () => pendingColumnOptions.value.length > 0 && pendingColumnOptions.value.every(col => col.visible),
148
+ get: () => {
149
+ const selectable = pendingColumnOptions.value.filter(col => !col.disabled)
150
+ return selectable.length > 0 && selectable.every(col => col.visible)
151
+ },
147
152
  set: value => {
148
153
  pendingColumnOptions.value.forEach(col => {
149
- col.visible = value
154
+ if (!col.disabled) {
155
+ col.visible = value
156
+ }
150
157
  })
151
158
  },
152
159
  })
@@ -210,6 +217,7 @@ const restoreColumnConfig = () => {
210
217
 
211
218
  // 遍历列选项,更新可见性状态
212
219
  columnOptions.value.forEach(column => {
220
+ if (column.disabled) return
213
221
  const match = cacheColumns.find(item => item.key === column.key)
214
222
  if (match) {
215
223
  column.visible = match.visible
@@ -271,20 +279,33 @@ const cancelColumnConfig = () => {
271
279
  * 初始化列配置
272
280
  */
273
281
  const initColumns = () => {
274
- // 获取默认插槽中的子节点(列定义)
275
- const children = slots.default?.() || []
282
+ const rawChildren = slots.default?.() || []
283
+
284
+ const flattenVNodes = (vnodes: VNode[]): VNode[] => {
285
+ const result: VNode[] = []
286
+ for (const vnode of vnodes) {
287
+ if (vnode.type === Fragment && Array.isArray(vnode.children)) {
288
+ result.push(...flattenVNodes(vnode.children as VNode[]))
289
+ } else {
290
+ result.push(vnode)
291
+ }
292
+ }
293
+ return result
294
+ }
295
+
296
+ const children = flattenVNodes(rawChildren)
276
297
 
277
- // 转换为列选项列表
278
298
  columnOptions.value = children.map((vnode, index) => {
299
+ const columnProps = vnode.props as Record<string, any> | null
279
300
  return {
280
301
  key: getColumnKey(vnode, index),
281
302
  label: getColumnLabel(vnode, index),
282
303
  visible: true,
304
+ disabled: columnProps?.disabled ?? false,
283
305
  vnode,
284
306
  }
285
307
  })
286
308
 
287
- // 从本地存储恢复配置
288
309
  restoreColumnConfig()
289
310
  }
290
311
 
@@ -387,6 +408,7 @@ initColumns()
387
408
  >
388
409
  <el-checkbox
389
410
  v-model="column.visible"
411
+ :disabled="column.disabled"
390
412
  >
391
413
  {{ column.label }}
392
414
  </el-checkbox>
@@ -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>