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 +1 -1
- package/src/App.vue +3 -0
- package/src/components/ElTablePro.vue +16 -4
- package/src/router/index.ts +5 -0
- package/src/views/TableProForView.vue +144 -0
package/package.json
CHANGED
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
|
-
|
|
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
|
|
package/src/router/index.ts
CHANGED
|
@@ -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>
|