Table 表格
表格整体设计
基础用法
配置columns表头和table-data
表格数据。
名称 | 状态 | 标签 | 时间 |
---|
0namenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamename | 未解决 | danger | 2025-06-16 03:07:54 |
1name | 已解决 | success | 2025-06-16 03:07:54 |
2name | 解决中 | warning | 2025-06-16 03:07:54 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" />
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index === 0 ? index + 'name'.repeat(100) : index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
disabledHeaderFilter: true,
tooltip: '名称',
tableColumnProps: {
align: 'center',
showOverflowTooltip: true
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker',
tableColumnProps: {
align: 'center',
sortable: true
}
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
自适应内容区高度
v0.1.17表格配置 adaptive
可实现自适应内容区高度,adaptive
的默认值是 false
,adaptive
的类型是
boolean | {
/** 表格距离页面底部的偏移量,默认值为 `20` */
offsetBottom?: number
/** 页面 `resize` 时的防抖时间,默认值为 `60` ms */
timeout?: number
}
2
3
4
5
6
注意
表格设置height
属性后, adaptive
属性将不在生效。
名称 | 状态 | 评分 | 标签 | 开关 | 日期 |
---|
未解决 | 3.5 | true | |||
已解决 | 3.5 | success | false | ||
2name | 解决中 | 3.5 | warning | true | 2025-06-16 |
3name | 未解决 | 3.5 | info | false | 2025-06-16 |
4name | 已解决 | 2 | true | 2025-06-16 | |
5name | 解决中 | 2 | false | 2025-06-16 | |
6name | 未解决 | 2 | true | 2025-06-16 | |
7name | 已解决 | 2 | false | 2025-06-16 | |
8name | 解决中 | 2 | true | 2025-06-16 | |
9name | 未解决 | 2 | false | 2025-06-16 |
- 1
<template>
<div class="adaptive-table-wrapper">
<PlusTable
ref="plusTableInstance"
:columns="tableConfig"
:table-data="tableData"
:pagination="{
total: 10,
pageSizeList: [10, 20, 50]
}"
adaptive
/>
</div>
</template>
<script lang="ts" setup>
import type { PlusColumn, PlusTableInstance } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ref } from 'vue'
interface TableRow {
id: number
name: string
status: string
rate: number
switch: boolean
time: string
tag: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 10 }).map((item, index) => {
return {
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date(),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : ''
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const plusTableInstance = ref<PlusTableInstance | null>(null)
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 120,
formProps: {
// 添加校验
rules: {
name: [
{
required: true,
message: '请输入名称'
}
]
}
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
],
formProps: {
// 添加校验
rules: {
status: [
{
required: true,
trigger: 'change',
message: '请选择状态'
}
]
}
}
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '标签',
width: 200,
prop: 'tag',
valueType: 'tag'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 250,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
},
formProps: {
// 添加校验
rules: {
time: [
{
required: true,
message: '请选择日期'
}
]
}
}
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
</script>
<style scoped>
.adaptive-table-wrapper {
:deep(.el-table--default) {
max-height: 640px;
}
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
数据多级显示
columns中的 prop
支持 x.y.z
形式的 多(无限)级数据形式。
注意
数据级不宜过多,可能会影响性能。
多级显示 | 多级显示 | 数组形式 | 数组形式 | 状态 |
---|
提示0 | list0 | 未解决 | ||
提示1 | list0 | 已解决 | ||
提示2 | list0 | 未解决 | ||
提示3 | list0 | 已解决 | ||
提示4 | list0 | 未解决 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" @form-change="handleChange" />
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
import { set } from 'lodash-es'
const TestServe = {
getList: async () => {
const data = Array.from({ length: 5 }).map((_, index) => {
return {
status: { data: { value: String(index % 2) } },
level: { message: { tip: '提示' + index } },
list: ['list0', 'list1', 'list2']
}
})
return { data }
}
}
const { tableData } = useTable()
const tableConfig: PlusColumn[] = [
{
label: '多级显示',
prop: 'level.message.tip',
editable: true
},
{
label: '多级显示',
prop: 'level.message.tip'
},
{
label: '数组形式',
editable: true,
prop: 'list[0]'
},
{
label: '数组形式',
prop: 'list[0]'
},
{
label: '状态',
prop: 'status.data.value',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
type: 'primary'
},
{
label: '已解决',
value: '1',
type: 'success'
}
]
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
const handleChange = ({ index, prop, value }: any) => {
set(tableData.value[index], prop, value)
console.log(tableData.value)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
自定义状态
配置项中valueType
为select
、radio
或checkbox
时, 配置columns中的options,表格会自动显示 value
对应的状态
和 label
。
默认的逻辑是 表格的tableData
中的实际值
和 options
中 value
对比 严格相等的话,会取当前项的 label
显示在表格中,想自定义显示逻辑的话,只需配置columns 中 customGetStatus
即可。
名称 | 状态 | 状态1 | 状态2 |
---|
0name | 未解决 | 未解决 | 未解决 |
1name | 已解决 | 已解决 | |
2name | 解决中 | 解决中 | |
3name | 失败 | 失败 | |
4name | 审核中 | 审核中 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" />
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 5 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 5),
status1: String(index % 5),
status2: String(index % 5),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
type: 'primary'
},
{
label: '已解决',
value: '1',
type: 'success'
},
{
label: '解决中',
value: '2',
type: 'info'
},
{
label: '失败',
value: '3',
type: 'danger'
},
{
label: '审核中',
value: '4',
type: 'warning'
}
],
customGetStatus: ({ options, value, row }) => {
const data = options?.find(item => item.value === value && row.id === 0)
return data
}
},
{
label: '状态1',
prop: 'status1',
valueType: 'radio',
options: [
{
label: '未解决',
value: '0',
color: '#68228B'
},
{
label: '已解决',
value: '1',
color: '#00ff66'
},
{
label: '解决中',
value: '2',
color: '#C2C2C2'
},
{
label: '失败',
value: '3',
color: '#ff3366'
},
{
label: '审核中',
value: '4',
color: '#ffff99'
}
]
},
{
label: '状态2',
prop: 'status2',
valueType: 'checkbox',
options: [
{
label: '未解决',
value: '0',
type: 'primary',
color: '#68228B'
},
{
label: '已解决',
value: '1',
type: 'success',
color: '#00ff66'
},
{
label: '解决中',
value: '2',
type: 'info',
color: '#C2C2C2'
},
{
label: '失败',
value: '3',
type: 'danger',
color: '#ff3366'
},
{
label: '审核中',
value: '4',
type: 'warning',
color: '#ffff99'
}
]
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
表格列样式简单修改
配置columns中的 fieldProps
,不仅会作用于表单单项,也会作用于表格单项。使用 fieldProps
可以做简单的样式修改,更强大的自定义样式,请使用自定义表格项。
名称 | 标签 | 时间 |
---|
0name | danger | 2025-06-16 03:07:54 |
1name | success | 2025-06-16 03:07:54 |
2name | warning | 2025-06-16 03:07:54 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" />
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
disabledHeaderFilter: true,
fieldProps: {
style: {
color: 'red',
fontSize: '20px'
}
}
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string, { index }) => {
return {
type: value,
style: {
fontSize: index * 2 + 13 + 'px'
}
}
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker',
fieldProps: (_, { index }) => {
return {
style: {
color: 'green',
fontSize: index * 2 + 13 + 'px'
}
}
}
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
操作栏
默认不显示。配置actionBar 即可,actionBar
配置参考 ActionBarProps。
actionBar
中的type
支持 button
,icon
和 link
,对应element plus
的 ElButton,ElIcon 和 ElLink 组件。
操作栏actionBar
中buttons
配置参考 ActionBarButtonsRow, buttons
中每项配置 confirm
即可实现二次确认,配置 show
即可实现权限和动态显示。
<template>
<el-row>
<el-text style="margin-right: 10px">操作按钮类型 </el-text>
<el-radio-group v-model="type">
<el-radio value="link">link </el-radio>
<el-radio value="icon">icon</el-radio>
<el-radio value="button">button</el-radio>
</el-radio-group>
</el-row>
<div>
<PlusTable
key="1"
:columns="tableConfig"
:table-data="tableData"
:action-bar="{
buttons: buttons,
type: type,
width: type === 'button' ? 260 : type === 'icon' ? 160 : 200
}"
@clickAction="handleClickButton"
/>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn, ButtonsCallBackParams } from 'plus-pro-components'
import { View, Edit, Delete, DocumentCopy } from '@element-plus/icons-vue'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const type = ref('link')
const { tableData, buttons } = useTable<TableRow[]>()
buttons.value = [
{
// v0.0.8开始支持 text支持函数类型
text: row => (row.status === '1' ? '开启' : '关闭'),
code: 'status',
icon: View,
props: {
type: 'primary'
}
},
{
// 查看
text: '查看',
code: 'view',
props: (row: any) => ({
type: 'info',
disabled: row.status === '1'
}),
show: (row: any) => row.status === '1',
icon: View
},
{
// 修改
text: '修改',
code: 'edit',
// props v0.1.16 版本新增函数类型
props: (row: any) => ({
type: 'primary',
disabled: row.status === '1'
}),
show: computed(() => true),
icon: Edit
},
{
// 删除
text: '删除',
code: 'delete',
// props v0.1.16 版本新增计算属性支持
props: computed(() => ({ type: 'danger' })),
confirm: {
options: { draggable: true }
},
icon: Delete
},
{
text: '复制',
code: 'copy',
props: {
type: 'success'
},
icon: DocumentCopy
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
const handleClickButton = (data: ButtonsCallBackParams) => {
console.log(data.buttonRow.text)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
操作栏事件
操作栏除了支持PlusTable Event中的clickAction
和clickActionConfirmCancel
外,v0.1.8版本开始支持自身的事件。
ActionBarButtonsRow支持以下事件。
事件名 | 类型 | 触发说明 |
---|---|---|
onClick v0.1.8 | ActionBarButtonsRow['onClick'] | 点击当前按钮的时触发,可与 PlusTable 的事件 clickAction 同时触发;操作需要二次确认时:PlusTable 的事件 clickAction 会在确认时触发,而当前的 onClick 是在点击时触发; |
onConfirm v0.1.8 | ActionBarButtonsRow['onConfirm'] | 操作需要二次确认时,点击确认时触发 |
onCancel v0.1.8 | ActionBarButtonsRow['onCancel'] | 操作需要二次确认时,点击取消时触发, 可与 PlusTable 的事件 clickActionConfirmCancel 同时触发 |
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:action-bar="{ buttons, width: '100px' }"
@clickAction="handleClickButton"
@clickActionConfirmCancel="handleClickCancel"
/>
</div>
</template>
<script lang="ts" setup>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { computed } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn, ButtonsCallBackParams } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData, buttons } = useTable<TableRow[]>()
buttons.value = [
{
// 修改
text: '修改',
code: 'edit',
props: {
type: 'primary'
},
show: computed(() => true),
onClick(params: ButtonsCallBackParams) {
if (params?.formRefs) {
// isEdit v0.1.8 新增
const isEdit = params.formRefs[0].isEdit.value
isEdit ? params.formRefs[0]?.stopCellEdit() : params.formRefs[0]?.startCellEdit()
}
}
},
{
// 删除
text: '删除',
code: 'delete',
props: {
type: 'danger'
},
confirm: {
options: { draggable: true }
},
onClick(params: ButtonsCallBackParams) {
console.log(params, 'onClick')
},
onConfirm(params: ButtonsCallBackParams) {
console.log(params, 'onConfirm')
},
onCancel(params: ButtonsCallBackParams) {
console.log(params, 'onCancel')
}
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
const handleClickButton = (params: ButtonsCallBackParams) => {
console.log(params, 'handleClickButton')
}
const handleClickCancel = (params: ButtonsCallBackParams) => {
console.log(params, 'handleClickCancel')
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
操作栏权限控制
小于v0.1.7版本
可使用 ActionBarButtonsRow 中的 show
字段控制。
大于等于v0.1.7版本
可使用 ActionBarButtonsRow 中的 show
和 directives
指令字段控制。参考 vue 渲染函数自定义指令
<template>
<div>
<PlusTable
key="1"
:columns="tableConfig"
:table-data="tableData"
:action-bar="{ buttons, showNumber: 4 }"
@clickAction="handleClickButton"
/>
</div>
</template>
<script lang="ts" setup>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { resolveDirective } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn, ButtonsCallBackParams } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData, buttons } = useTable<TableRow[]>()
const permissionList = ['sys.view', 'sys.edit', 'sys.copy']
/**
* 正常可引用(导入)写法
*/
const permission = {
mounted(el: HTMLElement, binding) {
const { value } = binding
const hasButtonPermission = permissionList.includes(value)
!hasButtonPermission && el.parentElement?.removeChild(el)
}
}
/**
* 如果 指令已经在全局注册,app.directive('copy',.....),则需要使用resolveDirective解析出指令
*
* copy 指令已经在全局注册
*/
const copy = resolveDirective('copy')
buttons.value = [
{
// 查看
text: '查看',
code: 'view',
props: {
type: 'info'
},
// show 字段控制权限
show: () => permissionList.includes('sys.view')
},
{
// 修改
text: '修改',
code: 'edit',
props: {
type: 'primary'
},
directives: [
// 相当于 v-permission="'sys.edit'"
[permission, 'sys.edit']
]
},
{
// 删除
text: '删除',
code: 'delete',
props: {
type: 'danger'
},
confirm: {
options: { draggable: true }
},
directives: [
// 相当于 v-permission="'sys.del'"
[permission, 'sys.del']
]
},
{
text: '复制',
code: 'copy',
props: {
type: 'success'
},
directives: [
// 相当于 v-permission="'sys.del'"
[permission, 'sys.copy'],
// 相当于 v-copy="'v-copy 复制的值'"
[copy, 'v-copy 复制的值']
]
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
const handleClickButton = (data: ButtonsCallBackParams) => {
console.log(data.buttonRow.text)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
操作栏二次确认类型
v0.1.17 版本新增气泡确认框 ElPopconfirm设置表格属性 actionBar.confirmType
为 popconfirm
即可生效,示例: <PlusTable :action-bar="{ confirmType: 'popconfirm'}" />
操作栏二次确认类型配置confirmType
默认值为messageBox
即 ElMessageBox.confirm
<template>
<div>
<el-row>
<el-text style="margin-right: 10px">操作按钮二次确认类型 </el-text>
<el-radio-group v-model="confirmType">
<el-radio value="popconfirm">popconfirm </el-radio>
<el-radio value="messageBox">messageBox</el-radio>
</el-radio-group>
</el-row>
<el-row>
<el-text style="margin-right: 10px">操作按钮类型 </el-text>
<el-radio-group v-model="type">
<el-radio value="link">link </el-radio>
<el-radio value="icon">icon</el-radio>
<el-radio value="button">button</el-radio>
</el-radio-group>
</el-row>
<PlusTable
key="3"
:columns="tableConfig"
:table-data="tableData"
:action-bar="{
buttons: buttons2,
type: type,
confirmType: confirmType,
width: type === 'button' ? 260 : type === 'icon' ? 160 : 200
}"
@clickAction="handleClickButton"
/>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn, ButtonsCallBackParams } from 'plus-pro-components'
import {
View,
Edit,
Delete,
DocumentCopy,
WarnTriangleFilled,
Operation
} from '@element-plus/icons-vue'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const type = ref('link')
const confirmType = ref('popconfirm')
const { buttons: buttons2, tableData } = useTable<TableRow[]>()
buttons2.value = [
{
// 打开
text: '打开',
code: 'open',
props: {
type: 'warning'
},
icon: Operation,
confirm: {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
popconfirmProps: { width: 150, icon: WarnTriangleFilled, iconColor: 'red' },
message: data => `确定打开id为${data.row.id}的数据吗?`
}
},
{
// 查看
text: '查看',
code: 'view',
icon: View,
props: {
type: 'info'
},
show: (row: any) => row.status === '1'
},
{
// 修改
text: '修改',
code: 'edit',
icon: Edit,
// props v0.1.16 版本新增函数类型
props: (row: any) => ({
type: 'primary',
color: row.status === '1' ? 'red' : '#333'
}),
show: computed(() => true)
},
{
// 删除
text: '删除',
code: 'delete',
icon: Delete,
// props v0.1.16 版本新增计算属性支持
props: computed(() => ({ type: 'danger' })),
confirm: {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
popconfirmProps: { width: 200, icon: WarnTriangleFilled, iconColor: 'red' },
message: data => `确定删除id为${data.row.id}且行数为${data.index}的数据吗?`
}
},
{
text: '复制',
code: 'copy',
icon: DocumentCopy,
props: {
type: 'success'
}
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
const handleClickButton = (data: ButtonsCallBackParams) => {
console.log(data)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
操作栏显示的按钮数量
配置actionBar showNumber
属性,showNumber
在v0.1.23 版本中新增了函数支持。
<template>
<div>
<PlusTable
key="1"
:columns="tableConfig"
:table-data="tableData"
:action-bar="{
showNumber: 3,
buttons
}"
@clickAction="handleClickButton"
/>
<PlusTable
key="2"
:columns="tableConfig"
:table-data="tableData"
:action-bar="{
showNumber,
buttons,
width: 230
}"
@clickAction="handleClickButton"
/>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useTable } from 'plus-pro-components'
import type { ButtonsCallBackParams, PlusColumn } from 'plus-pro-components'
import { View, Edit, Delete, DocumentCopy } from '@element-plus/icons-vue'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData, buttons } = useTable<TableRow[]>()
buttons.value = [
{
// v0.0.8开始支持 text支持函数类型
text: row => (row.status === '1' ? '开启' : '关闭'),
code: 'status',
icon: View,
props: {
type: 'primary'
}
},
{
// 查看
text: '查看',
code: 'view',
props: (row: any) => ({
type: 'info',
disabled: row.status === '1'
}),
icon: View
},
{
// 修改
text: '修改',
code: 'edit',
// props v0.1.16 版本新增函数类型
props: (row: any) => ({
type: 'primary',
disabled: row.status === '1'
}),
show: computed(() => true),
icon: Edit
},
{
// 删除
text: '删除',
code: 'delete',
// props v0.1.16 版本新增计算属性支持
props: computed(() => ({ type: 'danger' })),
confirm: {
options: { draggable: true }
},
icon: Delete
},
{
text: '复制',
code: 'copy',
props: {
type: 'success'
},
icon: DocumentCopy
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
// v0.1.23版本新增函数类型
const showNumber = (row: any, index: number) => {
return index + 1
}
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
const handleClickButton = (data: ButtonsCallBackParams) => {
console.log(data.buttonRow.text)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
标题栏
标题栏默认显示右侧工具栏, 可以使用title
,toolbar
插槽定制。不需要的的话配置 <PlusTable :title-bar="false" />
即可。
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 |
1name | 已解决 | success | 2025-06-16 03:07:55 |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 |
1name | 已解决 | success | 2025-06-16 03:07:55 |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:title-bar="{ title: '表格标题' }"
:has-toolbar="true"
>
<template #toolbar>
<el-button plain size="small">查看日志</el-button>
<el-button plain size="small">导出数据</el-button>
<el-button type="primary" size="small">创建应用</el-button>
</template>
</PlusTable>
<br />
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:title-bar="{ title: '表格标题' }"
:has-toolbar="true"
>
<template #title>
<el-button type="primary" size="small">新增</el-button>
<el-button type="danger" size="small">批量删除</el-button>
</template>
<template #toolbar>
<el-button plain size="small">查看日志</el-button>
<el-button plain size="small">导出数据</el-button>
<el-button type="primary" size="small">创建应用</el-button>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
拖动排序行
注意
拖动排序行对应的 el-table-column 的 props,使用dragSortableTableColumnProps 属性配置。
配置drag-sortable
,同时配合dragSortEnd
使用。
排序 | 名称 | 状态 | 标签 | 时间 |
---|
☷ | 0name | 未解决 | danger | 2025-06-16 03:07:55 |
☷ | 1name | 已解决 | success | 2025-06-16 03:07:55 |
☷ | 2name | 解决中 | warning | 2025-06-16 03:07:55 |
<template>
<div>
<PlusTable
drag-sortable
:columns="tableConfig"
:table-data="tableData"
@dragSortEnd="handleSortEnd"
/>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
valueType: 'copy'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
const handleSortEnd = (newIndex: number, oldIndex: number) => {
const currRow = tableData.value.splice(oldIndex, 1)[0]
tableData.value.splice(newIndex, 0, currRow)
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
列设置拖拽排序列
配置 TitleBar中的columnSetting
中的dragSort
属性,默认为 true
可拖拽。
不需要可以给 false
: <PlusTable :title-bar="{ columnSetting: { dragSort: false } }" />
。
如下示例, 点击 表格右上角列设置 图标,即可通过列设置拖拽排序列。
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 |
1name | 已解决 | success | 2025-06-16 03:07:55 |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 |
1name | 已解决 | success | 2025-06-16 03:07:55 |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
<template>
<el-divider style="margin-top: 10px"> 可通过列设置拖拽排序列</el-divider>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:title-bar="{
columnSetting: {
dragSort: {
animation: 180,
delay: 0
}
}
}"
/>
<el-divider style="margin: 24px 0 10px"> 去除了列设置拖拽排序列</el-divider>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:title-bar="{
columnSetting: {
dragSort: false
}
}"
/>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
disabledHeaderFilter: true,
tooltip: '名称',
tableColumnProps: {
align: 'center',
showOverflowTooltip: true
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
列设置信息保存
v0.1.22 新增使用columns[headerIsChecked
] 字段,配合事件filterTableHeader使用。
状态 | 评分 | 标签 | 开关 | 日期 |
---|
<template>
<div>
<PlusTable
ref="plusTableInstance"
editable
:columns="tableConfig"
:table-data="tableData"
@filterTableHeader="filterTableHeader"
/>
</div>
</template>
<script lang="ts" setup>
import type { PlusColumn, PlusTableInstance } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ref, onMounted } from 'vue'
interface TableRow {
id: number
name: string
status: string
rate: number
switch: boolean
time: string
tag: string
}
const localKey = 'filter-table-header'
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date(),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : ''
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const plusTableInstance = ref<PlusTableInstance | null>(null)
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 120,
// 列设置中此列不选中
headerIsChecked: false
},
{
label: '状态',
prop: 'status',
disabledHeaderFilter: true,
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '标签',
width: 200,
prop: 'tag',
valueType: 'tag'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 250
}
])
onMounted(() => {
// 此方法适应于简单数据,如果tableConfig有复杂数据,如计算属性函数等,可以考虑只保存关键字段 prop、label、headerIsChecked 、disabledHeaderFilter等
const data = localStorage.getItem(localKey)
? JSON.parse(localStorage.getItem(localKey) as string)
: null
if (data) {
tableConfig.value = data
}
})
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
const filterTableHeader = (columns: PlusColumn[]) => {
// 此方法适应于简单数据,如果tableConfig有复杂数据,如计算属性函数等,可以考虑只保存关键字段 prop、label、headerIsChecked 、disabledHeaderFilter等
localStorage.setItem(localKey, JSON.stringify(columns))
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
分页栏
默认不显示,配置pagination
属性即可。
# | 名称 | 状态 | 标签 | 时间 |
---|
1 | 0name | 未解决 | danger | 2025-06-16 03:07:55 |
2 | 1name | 已解决 | success | 2025-06-16 03:07:55 |
3 | 2name | 解决中 | warning | 2025-06-16 03:07:55 |
4 | 3name | 未解决 | info | 2025-06-16 03:07:55 |
5 | 4name | 已解决 | danger | 2025-06-16 03:07:55 |
- 1
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
has-index-column
:pagination="{
total,
modelValue: pageInfo,
pageSizeList: [10, 20, 50],
align: 'right'
}"
@paginationChange="handlePaginationChange"
/>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PageInfo, PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 5 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[],
total: data.length
}
}
}
const { tableData, total, pageInfo } = useTable<TableRow[]>()
pageInfo.value.pageSize = 5
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data, total: dataTotal } = await TestServe.getList()
tableData.value = data
total.value = dataTotal
} catch (error) {}
}
const handlePaginationChange = (_pageInfo: PageInfo): void => {
pageInfo.value = _pageInfo
getList()
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
序号栏
注意
序号栏对应的 el-table-column 的 props,使用indexTableColumnProps 属性配置。
默认不显示。配置hasIndexColumn
为 true
即可。 配置indexContentStyle
可定制序号栏样式。使用indexTableColumnProps
为序号栏配置el-table-column属性。
# | 名称 | 状态 | 标签 | 时间 |
---|
1 | 0name | 未解决 | danger | 2025-06-16 03:07:55 |
2 | 1name | 已解决 | success | 2025-06-16 03:07:55 |
3 | 2name | 解决中 | warning | 2025-06-16 03:07:55 |
4 | 3name | 未解决 | info | 2025-06-16 03:07:55 |
5 | 4name | 已解决 | danger | 2025-06-16 03:07:55 |
序号栏 | 名称 | 状态 | 标签 | 时间 |
---|
1 | 0name | 未解决 | danger | 2025-06-16 03:07:55 |
2 | 1name | 已解决 | success | 2025-06-16 03:07:55 |
3 | 2name | 解决中 | warning | 2025-06-16 03:07:55 |
4 | 3name | 未解决 | info | 2025-06-16 03:07:55 |
5 | 4name | 已解决 | danger | 2025-06-16 03:07:55 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" has-index-column />
</div>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
has-index-column
:index-content-style="indexContentStyle"
:index-table-column-props="{
label: '序号栏',
width: 80
}"
/>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 5 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[],
total: data.length
}
}
}
const { tableData, total, pageInfo } = useTable<TableRow[]>()
pageInfo.value.pageSize = 5
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data, total: dataTotal } = await TestServe.getList()
tableData.value = data
total.value = dataTotal
} catch (error) {}
}
const indexContentStyle = (row: any, index: number) => {
const style = {
width: '30px',
height: '30px',
color: '#fff',
borderRadius: '50%'
}
return index < 3
? {
...style,
backgroundColor: '#314659'
}
: {
...style,
backgroundColor: '#979797'
}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
多选
注意
多选栏对应的 el-table-column 的 props,使用selectionTableColumnProps 属性配置。
配置is-selection
属性为true
,即可显示表格多选框。默认值false
。配合 el-table selection-change
事件使用。
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 | |
1name | 已解决 | success | 2025-06-16 03:07:55 | |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:is-selection="true"
@selection-change="handleSelectionChange"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const multipleSelection = ref<TableRow[]>([])
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const handleSelectionChange = (val: TableRow[]) => {
multipleSelection.value = val
}
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
单选
v0.1.23注意
单选栏对应的 el-table-column 的 props,使用radioTableColumnProps 属性配置。
配置is-radio
属性为true
,即可显示表格单选框。默认值false
名称 | 状态 | 评分 | 标签 | 开关 | 日期 |
---|
未解决 | 3.5 | true | ||||
已解决 | 3.5 | success | false | |||
2name | 解决中 | 3.5 | warning | true | 2025-06-16 | |
3name | 未解决 | 3.5 | info | false | 2025-06-16 |
<template>
<div>
<PlusTable
ref="plusTableInstance"
is-radio
:columns="tableConfig"
:table-data="tableData"
:default-selected-radio-row="defaultSelectedRadioRow"
@radioChange="handleRadioChange"
/>
</div>
</template>
<script lang="ts" setup>
import type { PlusColumn, PlusTableInstance } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ref } from 'vue'
interface TableRow {
id: number
name: string
status: string
rate: number
switch: boolean
time: string
tag: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date(),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : ''
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const plusTableInstance = ref<PlusTableInstance | null>(null)
const defaultSelectedRadioRow = ref()
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 120,
formProps: {
// 添加校验
rules: {
name: [
{
required: true,
message: '请输入名称'
}
]
}
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
],
formProps: {
// 添加校验
rules: {
status: [
{
required: true,
trigger: 'change',
message: '请选择状态'
}
]
}
}
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '标签',
width: 200,
prop: 'tag',
valueType: 'tag'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 250,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
},
formProps: {
// 添加校验
rules: {
time: [
{
required: true,
message: '请选择日期'
}
]
}
}
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
defaultSelectedRadioRow.value = tableData.value[0]
} catch (error) {}
}
getList()
const handleRadioChange = (row: any, index: number) => {
console.log(row, index, 'handleRadioChange')
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
展开行
注意
展开行栏对应的el-table-column 的 props,使用expandTableColumnProps 属性配置。
配置has-expand
属性 true
可显示展开行,默认值 false
。配合插槽 expand
使用。
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 | |
1name | 已解决 | success | 2025-06-16 03:07:55 | |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" :has-expand="true">
<template #expand="{ row }">
<div m="4">
<p m="t-0 b-2">名称: {{ row.name }}</p>
<p m="t-0 b-2">状态: {{ row.status }}</p>
<p m="t-0 b-2">标签: {{ row.tag }}</p>
<p m="t-0 b-2">时间: {{ row.time }}</p>
</div>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number
name: string
status: string
tag: string
time: Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
树形结构
配置tree-props
树形为children: 'children'
,数据结构中有 children 即可。 树形懒加载表格还需设置lazy
,load
。
注意
数据中 children
中的id
和表格id
不能重复。row-key
默认为id
。
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 |
小明0-0 | 未解决 | danger | 2025-06-16 03:07:55 |
小明1-1 | 已解决 | success | 2025-06-16 03:07:55 |
小明2-2 | 解决中 | warning | 2025-06-16 03:07:55 |
小明3-3 | 未解决 | info | 2025-06-16 03:07:55 |
小明4-4 | 已解决 | danger | 2025-06-16 03:07:55 |
小明5-5 | 解决中 | danger | 2025-06-16 03:07:55 |
小明6-6 | 未解决 | danger | 2025-06-16 03:07:55 |
小明7-7 | 已解决 | danger | 2025-06-16 03:07:55 |
小明8-8 | 解决中 | danger | 2025-06-16 03:07:55 |
小明9-9 | 未解决 | danger | 2025-06-16 03:07:55 |
1name | 已解决 | success | 2025-06-16 03:07:55 |
小明0-0 | 未解决 | danger | 2025-06-16 03:07:55 |
小明1-1 | 已解决 | success | 2025-06-16 03:07:55 |
小明2-2 | 解决中 | warning | 2025-06-16 03:07:55 |
小明3-3 | 未解决 | info | 2025-06-16 03:07:55 |
小明4-4 | 已解决 | danger | 2025-06-16 03:07:55 |
小明5-5 | 解决中 | danger | 2025-06-16 03:07:55 |
小明6-6 | 未解决 | danger | 2025-06-16 03:07:55 |
小明7-7 | 已解决 | danger | 2025-06-16 03:07:55 |
小明8-8 | 解决中 | danger | 2025-06-16 03:07:55 |
小明9-9 | 未解决 | danger | 2025-06-16 03:07:55 |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
小明0-0 | 未解决 | danger | 2025-06-16 03:07:55 |
小明1-1 | 已解决 | success | 2025-06-16 03:07:55 |
小明2-2 | 解决中 | warning | 2025-06-16 03:07:55 |
小明3-3 | 未解决 | info | 2025-06-16 03:07:55 |
小明4-4 | 已解决 | danger | 2025-06-16 03:07:55 |
小明5-5 | 解决中 | danger | 2025-06-16 03:07:55 |
小明6-6 | 未解决 | danger | 2025-06-16 03:07:55 |
小明7-7 | 已解决 | danger | 2025-06-16 03:07:55 |
小明8-8 | 解决中 | danger | 2025-06-16 03:07:55 |
小明9-9 | 未解决 | danger | 2025-06-16 03:07:55 |
名称 | 状态 | 标签 | 时间 |
---|
0name | 未解决 | danger | 2025-06-16 03:07:55 |
1name | 已解决 | success | 2025-06-16 03:07:55 |
2name | 解决中 | warning | 2025-06-16 03:07:55 |
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
title="树形表格"
:tree-props="{ children: 'children' }"
/>
<PlusTable
:columns="tableConfig"
:table-data="tableDataLazy"
title="树形懒加载表格"
lazy
:load="load"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
/>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
interface TableRow {
id: number | string
name: string
status: string
tag: string
time: Date
hasChildren?: boolean
children?: TableRow[]
}
const TestServe = {
getList: async () => {
const dataLazy = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date(),
hasChildren: true,
children: []
}
})
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date(),
children: Array.from({ length: 10 }).map((item, i) => ({
id: index + '' + i,
name: '小明' + i + '-' + i,
status: String(i % 3),
tag: i === 1 ? 'success' : i === 2 ? 'warning' : i === 3 ? 'info' : 'danger',
time: new Date()
}))
}
})
return {
data: data as TableRow[],
dataLazy: dataLazy as TableRow[]
}
}
}
const load = (row: TableRow, treeNode: unknown, resolve: (date: TableRow[]) => void) => {
setTimeout(() => {
resolve(
Array.from({ length: 10 }).map((item, i) => ({
id: 10 + i,
name: '小明' + i + '-' + i,
status: String(i % 3),
tag: i === 1 ? 'success' : i === 2 ? 'warning' : i === 3 ? 'info' : 'danger',
time: new Date()
}))
)
}, 1000)
}
const { tableData } = useTable<TableRow[]>()
const { tableData: tableDataLazy } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name'
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '标签',
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker'
}
]
const getList = async () => {
try {
const { data, dataLazy } = await TestServe.getList()
tableData.value = data
tableDataLazy.value = dataLazy
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
多级表头
v0.1.7数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。
只需要将 el-table-column 放置于el-table-column 中,就可以实现组头。
Date | Delivery Info | ||||
---|---|---|---|---|---|
Name | Address Info | ||||
State | City | Address | Zip |
2016-05-03 | Tom | California | Los Angeles | No. 189, Grove St, Los Angeles | CA 90036 |
2016-05-02 | Tom | California | Los Angeles | No. 189, Grove St, Los Angeles | CA 90036 |
2016-05-04 | Tom | California | Los Angeles | No. 189, Grove St, Los Angeles | CA 90036 |
<template>
<PlusTable :table-data="tableData">
<el-table-column prop="date" label="Date" width="150" />
<el-table-column label="Delivery Info">
<el-table-column prop="name" label="Name" width="120" />
<el-table-column label="Address Info">
<el-table-column prop="state" label="State" width="120" />
<el-table-column prop="city" label="City" width="120" />
<el-table-column prop="address" label="Address" />
<el-table-column prop="zip" label="Zip" width="120" />
</el-table-column>
</el-table-column>
</PlusTable>
</template>
<script lang="ts" setup>
const tableData = [
{
date: '2016-05-03',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-02',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
},
{
date: '2016-05-04',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036'
}
]
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
在 columns 配置添加 children 属性, 即可实现无限极表头。
名称 | 状态 | 日期 | 总结 | ||
---|---|---|---|---|---|
评分 | 结果 | ||||
大众评分 | 专家评分 |
name-0 | 未解决 | 2025-06-16 03:07 | 晋级 | ||
name-1 | 已解决 | 2025-06-16 03:07 | 淘汰 | ||
name-2 | 解决中 | 2025-06-16 03:07 | 晋级 |
<template>
<div>
<PlusTable
ref="plusTableInstance"
:columns="tableConfig"
:table-data="tableData"
:title-bar="false"
>
<template #plus-header-summarize="scoped">
<span style="color: red"> {{ scoped.label }}</span>
</template>
<template #plus-header-expertRating="scoped">
<span style="color: red"> {{ scoped.label }}</span>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import type { PlusColumn, PlusTableInstance } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ref } from 'vue'
interface TableRow {
id: number
name: string
status: string
popularRating: number
expertRating: number
switch: boolean
time: Date
result: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: 'name-' + index,
status: String(index % 3),
popularRating: Math.ceil(Math.random() * 5),
expertRating: Math.ceil(Math.random() * 5),
switch: index % 2 === 0 ? true : false,
time: new Date(),
result: ['晋级', '淘汰'][index % 2]
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const plusTableInstance = ref<PlusTableInstance | null>(null)
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 120,
tableColumnProps: { align: 'center' }
},
{
label: '状态',
prop: 'status',
valueType: 'select',
tableColumnProps: { align: 'center' },
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
fieldProps: {
format: 'YYYY-MM-DD HH:mm'
}
},
{
label: '总结',
prop: 'summarize',
tableColumnProps: { align: 'center' },
children: [
{
label: '评分',
width: 200,
prop: 'rate',
tableColumnProps: { align: 'center' },
children: [
{
label: '大众评分',
width: 200,
prop: 'popularRating',
editable: true,
valueType: 'rate'
},
{
label: '专家评分',
width: 200,
prop: 'expertRating',
editable: true,
valueType: 'rate'
}
]
},
{
label: '结果',
width: 200,
prop: 'result',
valueType: 'tag',
tableColumnProps: { align: 'center' },
fieldProps: (value: string) => {
return { type: value === '晋级' ? 'primary' : 'danger' }
}
}
]
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
表格显示单项插槽配置
组件提供 fieldSlots
对象可以简易配置表格显示单项插槽, fieldSlots
的插槽配置是根据表格的 valueType 自动进行匹配的, 如:
valueType
是img
,fieldSlots
的插槽就是给 ElImage的。valueType
是link
时,fieldSlots
的插槽就是给 ElLink的。valueType
是tag
时,fieldSlots
的插槽就是给 ElTag的。- 其他以此类推
要实现更强大的自定义,请使用自定义表格项。
注意
valueType 的值对应的组件不是 element-plus 组件时,fieldSlots
不生效,或者组件本身没有插槽时也不生效。
<template>
<el-card>
<PlusTable :table-data="tableData" :columns="columns" />
</el-card>
</template>
<script lang="ts" setup>
import { h } from 'vue'
import { ElEmpty, ElIcon } from 'element-plus'
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
import { Link } from '@element-plus/icons-vue'
interface TableRow {
id: number
img: string
link: string
progress: number
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
img:
index === 0
? 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
: '',
link: String(index % 3),
progress: (index + 1) * 30,
tag: index
}
})
return {
data: data as TableRow[]
}
}
}
const { tableData } = useTable<TableRow[]>()
const columns: PlusColumn[] = [
{
label: '图片',
prop: 'img',
valueType: 'img',
fieldProps: {
style: {
width: '100%'
}
},
fieldSlots: {
error: () => h(ElEmpty, { description: '图片坏了' })
}
},
{
label: 'link',
prop: 'link',
valueType: 'link',
fieldSlots: {
default: () => '按钮',
icon: () => h(ElIcon, null, () => h(Link))
}
},
{
label: 'tag',
prop: 'tag',
valueType: 'tag',
fieldProps: value => ({
type: value === 0 ? 'success' : 'info'
}),
fieldSlots: {
default: ({ value }) => (value === 0 ? '开启' : '关闭')
}
},
{
label: 'progress',
prop: 'progress',
valueType: 'progress',
fieldProps: value => ({
status: value === 30 ? 'success' : 'warning'
}),
fieldSlots: {
default: ({ value }) => (value > 30 ? '高' : '低')
}
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
可编辑表格 (整体)
注意
表格中表单数据不会主动和表格数据同步,需要结合 formChange 事件手动同步。
表格配置editable
为true
即可实现整体可编辑, columns中的 editable
优先级会更高。
名称 | 状态 | 评分 | 开关 | 时间 |
---|
<template>
<div>
<el-button type="primary" @click="handleAdd">新增数据</el-button>
<el-button type="danger" @click="handleDelete">移除数据</el-button>
<PlusTable
:columns="tableConfig"
:editable="editable"
:table-data="tableData"
@formChange="formChange"
>
<template #plus-extra-name> 自定义下一行内容 </template>
<template #toolbar>
<el-button plain size="small" @click="editTable(false)">取消编辑</el-button>
<el-button type="primary" size="small" @click="editTable(true)">开启编辑</el-button>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
import { ref } from 'vue'
import { set } from 'lodash-es'
interface TableRow {
id: number
name: string
status: string
rate: number
switch: boolean
time: Date | string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
id: index,
name: index === 0 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: new Date()
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const editable = ref(true)
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 200
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate',
editable: true,
fieldProps: {
disabled: false,
allowHalf: true
}
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch',
editable: true,
fieldProps: {
disabled: false
}
},
{
label: '时间',
prop: 'time',
valueType: 'date-picker',
width: 250
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data
} catch (error) {}
}
getList()
const handleAdd = () => {
const index = ((tableData.value.at(-1)?.id as number) || 0) + 1
tableData.value.push({
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date()
})
}
const handleDelete = () => {
tableData.value.pop()
}
const formChange = ({ value, prop, index }) => {
// 同步表单数据到表格
set(tableData.value[index], prop, value)
console.log(tableData.value, 'tableData.value')
}
const editTable = (isEdit: boolean) => {
editable.value = isEdit
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
可编辑表格 (单行)
注意
表格中表单数据不会主动和表格数据同步,需要结合 formChange 事件手动同步。
可编辑和校验单行,也可以控制单行的每一个单元格的编辑状态和校验。核心方法是 调用 formRefs
里的startCellEdit()
方法。
<template>
<div>
<el-button type="primary" @click="handleAdd">新增数据</el-button>
<el-button type="danger" @click="handleDelete">移除数据</el-button>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:action-bar="{ buttons, width: 140 }"
@formChange="formChange"
@clickAction="handleClickButton"
/>
</div>
</template>
<script lang="ts" setup>
import type { ButtonsCallBackParams, TableFormRefRow, PlusColumn } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ElMessage } from 'element-plus'
import { ref } from 'vue'
import { set } from 'lodash-es'
interface TableRow {
id: number
name: {
name: string
}
status: string
rate: number
switch: boolean
time: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: {
name: index < 2 ? '' : index + 'name'
},
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date()
}
})
return { data: data as TableRow[] }
}
}
const { tableData, buttons } = useTable<TableRow[]>()
const show = ref<boolean[]>([])
buttons.value = [
{
text: '取消编辑',
code: 'cancel',
props: {
type: 'warning'
},
show: (_, index) => !!show.value[index]
},
{
// 保存
text: '保存',
code: 'save',
props: {
type: 'primary'
},
show: (_, index) => !!show.value[index]
},
{
text: '编辑',
code: 'edit',
props: {
type: 'primary'
},
show: (_, index) => !show.value[index]
},
{
text: '删除',
code: 'delete',
props: {
type: 'danger'
},
confirm: {},
show: (_, index) => !show.value[index]
}
]
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name.name',
width: 120,
formProps: {
// 添加校验
rules: {
'name.name': [
{
required: true,
message: '请输入名称'
}
]
}
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
],
formProps: {
// 添加校验
rules: {
status: [
{
required: true,
trigger: 'change',
message: '请选择状态'
}
]
}
}
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 250,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
},
formProps: {
// 添加校验
rules: {
time: [
{
required: true,
message: '请选择日期'
}
]
}
}
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
const handleAdd = () => {
const index = ((tableData.value.at(-1)?.id as number) || 0) + 1
tableData.value.push({
id: index,
name: {
name: index < 2 ? '' : index + 'name'
},
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date().toString()
})
}
const handleDelete = () => {
tableData.value.pop()
}
const formChange = ({ value, prop, index }) => {
// 同步表单数据到表格
set(tableData.value[index], prop, value)
console.log(tableData.value, 'tableData.value')
}
const handleSave = async (data: ButtonsCallBackParams) => {
try {
if (data.formRefs) {
const da = await Promise.all(
data.formRefs?.map((item: TableFormRefRow) => item.formInstance.value?.validate())
)
console.log(da, 'da')
}
} catch (errors: any) {
console.log(errors, 'errors')
ElMessage.closeAll()
const values: any[] = Object.values(errors)
ElMessage.warning(values[0]?.[0]?.message || '请完整填写表单并再次提交!')
}
}
const handleClickButton = async (data: ButtonsCallBackParams) => {
if (data.buttonRow.code === 'edit') {
tableData.value.forEach(item => {
if (item.id === data.row.id) {
show.value[data.index] = true
}
})
data.formRefs?.forEach((item: TableFormRefRow) => {
item.startCellEdit()
})
} else if (data.buttonRow.code === 'cancel') {
tableData.value.forEach(item => {
if (item.id === data.row.id) {
show.value[data.index] = false
}
})
data.formRefs?.forEach((item: TableFormRefRow) => {
item.stopCellEdit()
})
} else if (data.buttonRow.code === 'save') {
handleSave(data)
} else {
ElMessage.success('删除成功')
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
可编辑表格 (单元格)
注意
表格中表单数据不会主动和表格数据同步,需要结合 formChange 事件手动同步。
可编辑和校验单元格。核心方法是 调用 formRefs
里的startCellEdit()
方法。
<template>
<div>
<el-button type="primary" @click="handleAdd">新增数据</el-button>
<el-button type="danger" @click="handleDelete">移除数据</el-button>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
:action-bar="{ buttons, width: 140 }"
@formChange="formChange"
@clickAction="handleClickButton"
/>
</div>
</template>
<script lang="ts" setup>
import type { ButtonsCallBackParams, TableFormRefRow, PlusColumn } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ElMessage } from 'element-plus'
import { ref } from 'vue'
import { set } from 'lodash-es'
interface TableRow {
id: number
name: {
name: string
}
status: string
rate: number
switch: boolean
time: string | Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: {
name: index < 2 ? '' : index + 'name'
},
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date()
}
})
return { data: data as TableRow[] }
}
}
const { tableData, buttons } = useTable<TableRow[]>()
const show = ref<boolean[]>([])
buttons.value = [
{
text: '取消编辑',
code: 'cancel',
props: {
type: 'warning'
},
show: (_, index) => !!show.value[index]
},
{
// 保存
text: '保存',
code: 'save',
props: {
type: 'primary'
},
show: (_, index) => !!show.value[index]
},
{
text: '编辑',
code: 'edit',
props: {
type: 'primary'
},
show: (_, index) => !show.value[index]
},
{
text: '删除',
code: 'delete',
props: {
type: 'danger'
},
confirm: {},
show: (_, index) => !show.value[index]
}
]
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name.name',
width: 120,
formProps: {
// 添加校验
rules: {
'name.name': [
{
required: true,
message: '请输入名称'
}
]
}
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
]
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 250,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
},
formProps: {
// 添加校验
rules: {
time: [
{
required: true,
message: '请选择日期'
}
]
}
}
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
const handleAdd = () => {
const index = ((tableData.value.at(-1)?.id as number) || 0) + 1
tableData.value.push({
id: index,
name: {
name: index < 2 ? '' : index + 'name'
},
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date()
})
}
const handleDelete = () => {
tableData.value.pop()
}
const formChange = ({ value, prop, index }) => {
// 同步表单数据到表格
set(tableData.value[index], prop, value)
console.log(tableData.value, 'tableData.value')
}
const handleSave = async (data: ButtonsCallBackParams) => {
try {
if (data.formRefs) {
const formItem = data.formRefs?.find((item: TableFormRefRow) => item.prop === 'name.name')
await (formItem?.formInstance.value as any)?.validate()
}
} catch (errors: any) {
ElMessage.closeAll()
console.log(errors, 'errors')
const values: any[] = Object.values(errors)
ElMessage.warning(values[0]?.[0]?.message || '请完整填写表单并再次提交!')
}
}
const handleClickButton = async (data: ButtonsCallBackParams) => {
if (data.buttonRow.code === 'edit') {
tableData.value.forEach(item => {
if (item.id === data.row.id) {
show.value[data.index] = true
}
})
data.formRefs?.forEach((item: TableFormRefRow) => {
if (item.prop === 'name.name') {
item.startCellEdit()
}
})
} else if (data.buttonRow.code === 'cancel') {
tableData.value.forEach(item => {
if (item.id === data.row.id) {
show.value[data.index] = false
}
})
data.formRefs?.forEach((item: TableFormRefRow) => {
item.stopCellEdit()
})
} else if (data.buttonRow.code === 'save') {
handleSave(data)
} else {
ElMessage.success('删除成功')
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
可编辑表格 (手动控制)
注意
表格中表单数据不会主动和表格数据同步,需要结合 formChange 事件手动同步。
手动控制表格编辑
名称 | 状态 | 评分 | 开关 | 日期 |
---|
未解决 | 3.5 | true | ||
已解决 | 3.5 | false | ||
2name | 解决中 | 3.5 | true | 2025-06-16 |
3name | 未解决 | 3.5 | false | 2025-06-16 |
<template>
<div>
<PlusTable
ref="plusTableInstance"
:columns="tableConfig"
:table-data="tableData"
@formChange="formChange"
/>
<el-row class="mgt-10">
<el-button type="primary" @click="handleAdd">新增数据</el-button>
<el-button type="danger" @click="handleDelete">移除数据</el-button>
<el-button class="mgb-10" @click="handleStart(0)"> 开启第一行编辑 </el-button>
<el-button class="mgb-10" @click="handleStop(0)"> 关闭第一行编辑 </el-button>
<el-button class="mgb-10" @click="handleStart(2)"> 开启第三行编辑 </el-button>
<el-button class="mgb-10" @click="handleStop(2)"> 关闭第三行编辑 </el-button>
<el-button class="mgb-10" @click="handleStart(1, 'status')"> 开启第二行第二列编辑 </el-button>
<el-button class="mgb-10" @click="handleStop(1, 'status')"> 关闭第二行第二列编辑 </el-button>
</el-row>
</div>
</template>
<script lang="ts" setup>
import type { PlusColumn, PlusTableInstance, TableFormRefRow } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ref } from 'vue'
import { set } from 'lodash-es'
interface TableRow {
id: number
name: string
status: string
rate: number
switch: boolean
time: string | Date
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date()
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const plusTableInstance = ref<PlusTableInstance | null>(null)
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 120,
formProps: {
// 添加校验
rules: {
name: [
{
required: true,
message: '请输入名称'
}
]
}
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
],
formProps: {
// 添加校验
rules: {
status: [
{
required: true,
trigger: 'change',
message: '请选择状态'
}
]
}
}
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
minWidth: 150,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
},
formProps: {
// 添加校验
rules: {
time: [
{
required: true,
message: '请选择日期'
}
]
}
}
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
const handleAdd = () => {
const index = ((tableData.value.at(-1)?.id as number) || 0) + 1
tableData.value.push({
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date()
})
}
const handleDelete = () => {
tableData.value.pop()
}
const handleStart = (index: number, prop?: string) => {
if (plusTableInstance.value?.formRefs) {
let cell = Reflect.get(plusTableInstance.value?.formRefs, index) as TableFormRefRow[]
if (prop) {
cell = cell.filter(item => item.prop === prop)
}
cell?.forEach(item => {
item.startCellEdit()
})
}
}
const handleStop = (index: number, prop?: string) => {
if (plusTableInstance.value?.formRefs) {
let cell = Reflect.get(plusTableInstance.value?.formRefs, index) as TableFormRefRow[]
if (prop) {
cell = cell.filter(item => item.prop === prop)
}
cell?.forEach(item => {
item.stopCellEdit()
})
}
}
const formChange = ({ value, prop, index }) => {
// 同步表单数据到表格
set(tableData.value[index], prop, value)
console.log(tableData.value, 'tableData.value')
}
</script>
<style lang="scss" scoped>
.mgb-10 {
margin-bottom: 10px;
}
.mgt-10 {
margin-top: 10px;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
可编辑表格 (点击单元格)
注意
表格中表单数据不会主动和表格数据同步,需要结合 formChange 事件手动同步。
表格属性editable
支持 boolean
,'click'
, 'dblclick'
:
- 当值为
true
时:表格都是编辑状态, - 当值为
false
(默认) 时 :表格都是显示状态, - 当值为
'click'
(点击) 或'dblclick'
(双击) 时 :全部表格都是显示状态,同时携带编辑 icon,需要点击或双击才能打开编辑状态,当点击表格外
退出编辑状态,同时触发edited
事件,当点击其他单元格
时会退出当前单元格的编辑状态,不会触发edited
事件。
提示
PlusColumn 配置中的 editable
仅支持 boolean
,优先级高于表格整体的editable
配置。
表格第一列和第二列有自己的 editable
配置,优先级高于整体的 editable
,表格整体的配置改变后对于单个的配置无效。
名称 | 状态 | 评分 | 标签 | 开关 | 日期 |
---|
3.5 | true | ||||
3.5 | success | false | |||
2name | 3.5 | warning | true | 2025-06-16 | |
3name | 3.5 | info | false | 2025-06-16 |
<template>
<div>
<el-row style="margin-bottom: 10px">
<el-button type="primary" @click="handleAdd">新增数据</el-button>
<el-button type="danger" @click="handleDelete">移除数据</el-button>
<el-button plain @click="handleEditable(true)">开启编辑</el-button>
<el-button plain @click="handleEditable(false)">关闭编辑</el-button>
<el-button @click="handleEditable('click')"> 切换点击(click)单元格开启编辑 </el-button>
<el-button @click="handleEditable('dblclick')">
切换双击(dblclick)单元格开启编辑
</el-button>
</el-row>
<el-row style="margin-bottom: 10px">
<el-alert type="warning" :closable="false">
表格第一列和第二列有自己的 <code> editable</code>配置,优先级高于整体的
<code> editable</code>,表格整体的配置改变后对于单个的配置无效。
</el-alert>
</el-row>
<PlusTable
ref="plusTableInstance"
:columns="tableConfig"
:table-data="tableData"
:editable="editable"
:title-bar="false"
@formChange="formChange"
@edited="handleEdited"
/>
</div>
</template>
<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import type { PlusColumn, PlusTableInstance } from 'plus-pro-components'
import { useTable } from 'plus-pro-components'
import { ref } from 'vue'
import { set } from 'lodash-es'
interface TableRow {
id: number
name: string
status: string
rate: number
switch: boolean
time: string | Date
tag: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date(),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : ''
}
})
return { data: data as TableRow[] }
}
}
const { tableData } = useTable<TableRow[]>()
const plusTableInstance = ref<PlusTableInstance | null>(null)
const editable = ref<string | boolean>(false)
const tableConfig = ref<PlusColumn[]>([
{
label: '名称',
prop: 'name',
width: 120,
tableColumnProps: {
align: 'right'
},
formProps: {
// 添加校验
rules: {
name: [
{
required: true,
message: '请输入名称'
}
]
}
},
// 优先级高于表格整体配置
editable: false
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
},
{
label: '解决中',
value: '2',
color: 'yellow'
},
{
label: '失败',
value: '3',
color: 'red'
}
],
// 优先级高于表格整体配置
editable: true
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate'
},
{
label: '标签',
width: 200,
prop: 'tag',
valueType: 'tag'
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch'
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 250,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
}
}
])
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
const handleAdd = () => {
const index = ((tableData.value.at(-1)?.id as number) || 0) + 1
tableData.value.push({
id: index,
name: index < 2 ? '' : index + 'name',
status: String(index % 3),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
time: index < 2 ? '' : new Date(),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : ''
})
}
const handleDelete = () => {
tableData.value.pop()
}
const formChange = ({ value, prop, index }) => {
// 同步表单数据到表格
set(tableData.value[index], prop, value)
console.log(tableData.value, 'tableData.value')
}
const handleEditable = (_editable: boolean | 'click' | 'dblclick') => {
editable.value = _editable
}
// 当表格的editable值为'click'或'dblclick'退出编辑状态时触发
const handleEdited = () => {
ElMessage.success('退出编辑了')
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
自定义表格项和表单项 ( 插槽 )
注意
插槽 的优先级低于 render,高于数据。
自定义表格项
PlusTable
组件会自动根据配置项的prop
生成对应的插槽,例如下面的配置项,则会自动生成两个名称叫做 [ plus-cell-name
]和 [ plus-cell-status
] 的两个插槽,插槽的生成规则就是 固定 key 值 [ plus-cell- ] 然后加上 配置项的prop
。tsimport { PlusColumn } from 'plus-pro-components' const tableConfig: PlusColumn[] = [ { label: '名称', // 自动生成对应的插槽 'plus-cell-name' prop: 'name' }, { label: '状态', // 自动生成对应的插槽 'plus-cell-status' prop: 'status' } ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14插槽作用域中会返回
scoped
参数,scoped
中 包含prop
、label
、valueType
和column
等参数可供使用。自定义表单项
参考自定义表单项(插槽) ( 表格中需要开启
editable
)
名称 | 状态 |
---|
render 0name | 插槽- 0 |
render 1name | 插槽- 1 |
render 2name | 插槽- 2 |
render 3name | 插槽- 3 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData">
<!--这里的plus-cell-name 插槽没有生效,因为它的优先级低于render函数 -->
<template #plus-cell-name="scoped">
<span style="color: blue"> {{ scoped.value }} </span>
</template>
<template #plus-cell-status="scoped">
<span style="color: green">插槽- {{ scoped.value }} </span>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { h } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
name: index + 'name',
status: String(index % 4),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data
}
}
}
const { tableData } = useTable()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
// render 的优先级比 插槽plus-cell-name 的高
render(value) {
return h(
'div',
{
style: {
color: 'green'
}
},
`render ${value}`
)
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
type: 'primary'
},
{
label: '已解决',
value: '1',
type: 'success'
}
]
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
自定义表格项和表单项 (render)
提示
render 的优先级高于插槽。
自定义表格项 (格式化表格显示)
使用 render 函数自定义表格项。
render
方法需要返回一个 VNode 或string
,返回一个string
时可以用来格式化表格显示。自定义表格项还支持
renderHTML
方法,需要返回一个 HTML 字符串。谨慎使用,确保 HTML 字符串可信。自定义表单项
参考自定义表单项-renderField ( 表格中需要开启
editable
)
格式化显示 | 自定义组件div | 自定义组件ElResult | 自定义组件ElAlert | 自定义组件 | 自定义html | 自定义html | 自定义表单ElUpload | 自定义操作栏 |
---|
开启 | 0name | Tip0 | 待审核 | 返回 0 层 | custom0 | |||
关闭 | 1name | Tip1 | 进行中 | 返回 1 层 | custom1 | |||
开启 | 2name | Tip2 | 已结束 | 返回 2 层 | custom2 |
- 1
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
table-title="表格"
:pagination="{ total, modelValue: pageInfo }"
@paginationChange="handlePaginationChange"
/>
</div>
</template>
<script lang="ts" setup>
import type { Component } from 'vue'
import { h, Fragment } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PageInfo, PlusColumn } from 'plus-pro-components'
import { ElAlert, ElButton, ElMessage, ElUpload, ElResult } from 'element-plus'
import CustomPageHeader from './components/page-header.vue'
defineOptions({
name: 'CustomCell'
})
interface TableRow {
index: number
id: number
name: string
status: string
custom: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
index,
id: index,
name: index + 'name',
tag: index % 2 === 0 ? '0' : '1',
status: String(index % 3),
status0: String(index % 3),
status1: String(index % 3),
status2: String(index % 3),
custom: 'custom' + index,
custom0: 'custom' + index,
custom1: 'custom' + index
}
})
return {
data: data as TableRow[],
total: data.length
}
}
}
const { tableData, pageInfo, total, loadingStatus } = useTable<TableRow[]>()
const statusOptions = [
{
label: '待审核',
value: '0',
type: 'info'
},
{
label: '进行中',
value: '1',
type: 'success'
},
{
label: '已结束',
value: '2',
type: 'warning'
}
]
const typeList = ['success', 'warning', 'info']
const tableConfig: PlusColumn[] = [
{
label: '格式化显示',
width: 140,
prop: 'tag',
// 返回一个字符串
render: value => (value === '0' ? '开启' : '关闭')
},
{
label: '自定义组件div',
tooltip: '名称最多显示6个字符',
width: 140,
prop: 'name',
// 返回一个标签
render: value => h('div', null, `${value}`),
// 传递给 'div' props
fieldProps: value => {
return { value: value }
}
},
{
label: '自定义组件ElResult',
width: 150,
prop: 'status',
// 返回一个组件
render: (value, { index }) =>
h(
ElResult,
{},
// 插槽
{
extra: () => {
return h(ElButton, { type: typeList[index % 4] as any }, () => `按钮${value}`)
}
}
),
// 传递给 ElResult 组件的props
fieldProps: (value, { index }) => {
return { icon: typeList[index % 4] as any, title: `Tip${value}` }
}
},
{
label: '自定义组件ElAlert',
width: 150,
prop: 'status0',
// 返回一个组件
render: value => {
const item = statusOptions.find(item => item.value === value)
return h(ElAlert as unknown as Component, { type: item?.type }, () => item?.label)
}
},
{
label: '自定义组件',
width: 100,
prop: 'status1',
// 返回一个组件
render: () => h(CustomPageHeader),
// 传递给CustomPageHeader 组件的props
fieldProps: (value, { index }) => ({
content: index
})
},
// renderHTML 返回一个 HTML 字符串
{
label: '自定义html',
width: 100,
prop: 'custom',
renderHTML: (value: any) => {
return `<div style='color:red;'>${value}</div>`
}
},
// renderHTML 返回一个 HTML 字符串
{
label: '自定义html',
width: 110,
prop: 'custom0',
renderHTML: (value: any) => {
return `<input style="border:1px solid #ccc;width:80px;padding:0 10px;" value=${value} />`
}
},
{
label: '自定义表单ElUpload',
width: 160,
prop: 'custom1',
// editable 为true renderField才生效
editable: true,
// 返回一个VNode
renderField(_, onChange) {
// 自定义上传
const handleHttpRequest = async ({ file, onError, onSuccess }: any) => {
try {
onSuccess(file)
} catch (error: any) {
onError(error)
}
return file
}
return h(
ElUpload,
{
action: '',
drag: true,
httpRequest: handleHttpRequest,
onChange: (file: any) => {
onChange(file.raw.name)
}
},
() => '你可以将文件拖拽到特定区域以进行上传。'
)
}
},
{
label: '自定义操作栏',
width: 200,
prop: 'status2',
render: (value, { index, row }) => {
const buttons = index > 1 ? ['编辑', '删除'] : ['保存', '删除']
const CustomButton = buttons.map(item =>
h(
ElButton,
{
type: index > 1 ? 'warning' : 'primary',
onClick: e => handleClickButton(e, value, index, row, item)
},
() => item
)
)
return h(Fragment, CustomButton)
}
}
]
const handleClickButton = (
e: MouseEvent,
value: any,
index: number,
row: any,
buttonText: string
) => {
console.log(e, value, index, row)
ElMessage.success(buttonText)
}
const getList = async () => {
try {
loadingStatus.value = true
const { data, total: dataTotal } = await TestServe.getList()
tableData.value = data || []
total.value = dataTotal
} catch (error) {}
loadingStatus.value = false
}
getList()
const handlePaginationChange = (_pageInfo: PageInfo): void => {
pageInfo.value = _pageInfo
getList()
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
自定义表格项和表单项 (jsx/tsx)
注意
jsx/tsx 的使用需要将 vue 单文件组件的script
的属性 lang
设置为jsx
或者tsx
,jsx
中值使用单花括号{}
绑定。
<script lang="tsx" setup></script>
自定义表格项
jsx/tsx
的支持本质是jsx/tsx
解析出来是VNode
, 使用 render 函数自定义表格项。自定义表单项
参考自定义表单项-jsx-tsx ( 表格中需要开启
editable
)
名称 | 状态 | 按钮 |
---|
0name | 0 | |
1name | 1 | |
2name | 2 | |
3name | 3 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" />
</div>
</template>
<script lang="tsx" setup>
// `lang ` 设置为 `jsx`或者`tsx`
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
import { ElButton } from 'element-plus'
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
name: index + 'name',
status: String(index % 4),
data: 'data' + String(index % 4)
}
})
return {
data
}
}
}
const { tableData } = useTable()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
// jsx 中值使用单花括号
render(value) {
return <div> {value}</div>
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
// jsx 中style使用单花括号,里面还有一个花括号表示对象
render(value) {
return <p style={{ padding: 10, color: 'red' }}> {value}</p>
}
},
{
label: '按钮',
prop: 'data',
valueType: 'select',
render(value) {
return <ElButton type="primary"> {value}</ElButton>
}
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
自定义表格表头 (插槽)
注意
插槽 的优先级低于 renderHeader,高于 label。
PlusTable
组件会自动根据配置项的 prop
生成对应的插槽,例如下面的配置项,则会自动生成两个名称叫做 [ plus-header-name
]和 [ plus-header-status
] 的两个插槽,插槽的生成规则就是 固定 key 值 [ plus-header- ] 然后加上 配置项的 prop
。
import { PlusColumn } from 'plus-pro-components'
const tableConfig: PlusColumn[] = [
{
label: '名称',
// 自动生成对应的插槽 'plus-header-name'
prop: 'name'
},
{
label: '状态',
// 自动生成对应的插槽 'plus-header-status'
prop: 'status'
}
]
2
3
4
5
6
7
8
9
10
11
12
13
14
插槽作用域中会返回 scoped
参数,scoped
中 包含 prop
、label
、valueType
和column
等参数可供使用。
render 名称 | 插槽- 状态 |
---|
0name | 未解决 |
1name | 已解决 |
2name | 未解决 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData">
<!--这里的plus-header-name 插槽没有生效,因为它的优先级低于renderHeader函数 -->
<template #plus-header-name="scoped">
<span style="color: yellow">{{ scoped.label }}</span>
</template>
<template #plus-header-status="scoped">
<span style="color: red">插槽- {{ scoped.label }}</span>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { h } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
name: index + 'name',
status: String(index % 2),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
time: new Date()
}
})
return {
data
}
}
}
const { tableData } = useTable()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
// renderHeader 的优先级比 插槽 plus-header-name 的高
renderHeader(label) {
return h(
'div',
{
style: {
color: 'red'
}
},
`render ${label}`
)
}
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
type: 'primary'
},
{
label: '已解决',
value: '1',
type: 'success'
}
]
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
自定义表格表头 (renderHeader)
注意
renderHeader 的优先级高于插槽。
- 使用 renderHeader 函数自定义表格项。
renderHeader
方法需要返回一个 VNode 或String
。
自定义表头 div | 自定义组件ElAlert |
---|
0name | 0 | custom0 |
1name | 1 | custom1 |
2name | 2 | custom2 |
- 1
<template>
<div>
<PlusTable
:columns="tableConfig"
:table-data="tableData"
table-title="表格"
:pagination="{ total, modelValue: pageInfo }"
@paginationChange="handlePaginationChange"
/>
</div>
</template>
<script lang="ts" setup>
import type { Component } from 'vue'
import { h } from 'vue'
import { useTable } from 'plus-pro-components'
import type { PageInfo, PlusColumn } from 'plus-pro-components'
import { ElButton, ElAlert } from 'element-plus'
defineOptions({
name: 'CustomCell'
})
interface TableRow {
index: number
id: number
name: string
status: string
custom: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
index,
id: index,
name: index + 'name',
status: String(index % 3),
custom: 'custom' + index
}
})
return {
data: data as TableRow[],
total: data.length
}
}
}
const { tableData, pageInfo, total, loadingStatus } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '自定义表头 div',
tooltip: '名称最多显示6个字符',
width: 200,
prop: 'name',
// 返回一个标签字符串
renderHeader: label => h('div', null, label)
},
{
label: '自定义表头 ElButton',
width: 200,
prop: 'status',
// 返回一个组件
renderHeader: label => h(ElButton, null, () => label)
},
{
label: '自定义组件ElAlert',
prop: 'custom',
// 返回一个VNode
renderHeader: label => {
return h(ElAlert as unknown as Component, null, () => label)
}
}
]
const getList = async () => {
try {
loadingStatus.value = true
const { data, total: dataTotal } = await TestServe.getList()
tableData.value = data || []
total.value = dataTotal
} catch (error) {}
loadingStatus.value = false
}
getList()
const handlePaginationChange = (_pageInfo: PageInfo): void => {
pageInfo.value = _pageInfo
getList()
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
自定义表格表头 (jsx/tsx)
注意
jsx/tsx 的使用需要将 vue 单文件组件的script
的属性 lang
设置为jsx
或者tsx
,jsx
中值使用单花括号{}
绑定。
<script lang="tsx" setup></script>
jsx/tsx
的支持本质是jsx/tsx
解析出来是VNode
, 使用 renderHeader 函数自定义表格表头。
名称 | 状态 |
---|
0name | 0 | 0 |
1name | 1 | 1 |
2name | 2 | 2 |
3name | 3 | 3 |
<template>
<div>
<PlusTable :columns="tableConfig" :table-data="tableData" />
</div>
</template>
<script lang="tsx" setup>
// `lang ` 设置为 `jsx`或者`tsx`
import { useTable } from 'plus-pro-components'
import type { PlusColumn } from 'plus-pro-components'
import { ElButton } from 'element-plus'
const TestServe = {
getList: async () => {
const data = Array.from({ length: 4 }).map((item, index) => {
return {
name: index + 'name',
status: String(index % 4),
data: String(index % 4)
}
})
return {
data
}
}
}
const { tableData } = useTable()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
// jsx 中值使用单花括号
renderHeader(label) {
return <div style={{ color: 'green' }}> {label}</div>
}
},
{
label: '按钮',
prop: 'data',
renderHeader(label) {
return <ElButton type="primary"> {label}</ElButton>
}
},
{
label: '状态',
prop: 'status',
// jsx 中style使用单花括号,里面还有一个花括号表示对象
renderHeader(label) {
return <p style={{ padding: 10, color: 'red' }}> {label}</p>
}
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data || []
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
自定义 icon
v0.0.3组件提供了以下插槽可以自定义 icon
插槽名 | 说明 |
---|---|
action-bar-more-icon | 操作栏更多旁边的 icon |
tooltip-icon | 表格表头 tooltip icon |
drag-sort-icon | 表格拖拽行 和 列设置里拖拽 icon |
column-settings-icon | 表格表头 列设置 icon |
density-icon | 表格表头 密度 icon |
<template>
<div>
<PlusTable
ref="plusTable"
row-key="id"
size="small"
:loading-status="loadingStatus"
:columns="tableConfig"
:table-data="tableData"
has-index-column
:drag-sortable="true"
table-title="表格"
:pagination="{ total, modelValue: pageInfo }"
:action-bar="{
buttons,
type: 'link',
showNumber: 3,
width: 200
}"
@paginationChange="handlePaginationChange"
@clickAction="handleClickButton"
@dragSortEnd="handleSortEnd"
>
<!-- 操作栏更多旁边的icon -->
<template #action-bar-more-icon>
<el-icon :size="12" style="margin-top: 1px"><ArrowRightBold /></el-icon>
</template>
<!-- 表格表头 tooltip icon -->
<template #tooltip-icon>
<el-icon :size="16" class="plus-table-column__header__icon"><Warning /></el-icon>
</template>
<!-- 表格拖拽行 和 列设置里拖拽 icon -->
<template #drag-sort-icon>
<el-icon><Sort /></el-icon>
</template>
<!--表格表头 列设置icon -->
<template #column-settings-icon>
<el-icon style="margin-left: 10px; cursor: pointer"><Orange /></el-icon>
</template>
<!--表格表头 密度icon -->
<template #density-icon>
<el-icon style="cursor: pointer"><Grid /></el-icon>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useTable } from 'plus-pro-components'
import type {
PlusTableInstance,
ButtonsCallBackParams,
PageInfo,
PlusColumn
} from 'plus-pro-components'
import { ArrowRightBold, Warning, Sort, Orange, Grid } from '@element-plus/icons-vue'
defineOptions({
name: 'PlusTableAdvancedTest'
})
interface TableRow {
index: number
id: number
name: string
status: string
tag: string
progress: number
rate: number
switch: boolean
img: string
code: string
time: Date
custom: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
index,
id: index,
name: index === 0 ? 'name'.repeat(20) : index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
progress: Math.ceil(Math.random() * index * 10),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
img: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
time: new Date(),
code: `
const getData = async params => {
const data = await getData(params)
return { list: data.data, ...data }
}`,
custom: 'custom' + index,
level: {
state: {
value: 'level' + index
}
}
}
})
return {
data: data as TableRow[],
total: data.length
}
}
}
const plusTable = ref<PlusTableInstance>()
const { tableData, pageInfo, total, buttons, loadingStatus } = useTable<TableRow[]>()
buttons.value = [
{
// 查看
text: '查看',
props: {
type: 'primary'
}
},
{
// 修改
text: '修改',
props: {
type: 'success'
}
},
{
// 删除
text: '删除',
props: {
type: 'warning'
},
confirm: {}
},
{
text: '复制',
props: {
type: 'primary'
},
confirm: {}
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
tooltip: '名称最多显示6个字符',
width: 120,
prop: 'name',
tableColumnProps: {
showOverflowTooltip: true
}
},
{
label: '多级数据',
width: 120,
prop: 'level.state.value'
},
{
label: '状态',
width: 120,
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
type: 'warning'
},
{
label: '已解决',
value: '1',
type: 'success'
},
{
label: '解决中',
value: '2',
type: 'primary'
},
{
label: '失败',
value: '3',
type: 'danger'
}
]
},
{
label: '标签',
width: 120,
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate',
editable: true
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch',
editable: true
},
{
label: '图片',
prop: 'img',
width: 100,
valueType: 'img'
}
]
const getList = async () => {
try {
loadingStatus.value = true
const { data, total: dataTotal } = await TestServe.getList()
tableData.value = data || []
total.value = dataTotal
} catch (error) {}
loadingStatus.value = false
}
getList()
const handlePaginationChange = (_pageInfo: PageInfo): void => {
pageInfo.value = _pageInfo
getList()
}
const handleClickButton = (data: ButtonsCallBackParams) => {
console.log(data.buttonRow.text)
}
const handleSortEnd = (newIndex: number, oldIndex: number) => {
const currRow = tableData.value.splice(oldIndex, 1)[0]
tableData.value.splice(newIndex, 0, currRow)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
表格显示格式化
表格显示可通过以下三种方式格式化
方式 | 说明 | PlusColumn[valueType ]是否生效 | 版本支持 | 示例 |
---|---|---|---|---|
PlusColumn[render ]返回一个字符串时 | 完全自定义表格行 | 否 | v0.0.1 | 示例 |
PlusColumn[fieldSlots ] | 定义PlusColumn[valueType ]对应的组件的插槽 | 是 | v0.0.1 | 示例 |
PlusColumn[formatter ] | 仅仅格式化显示的值 | 是 | v0.1.13 | 见下文 |
以下是PlusColumn[formatter
] 的示例 v0.1.13
名称 | 状态 | 状态1 | 状态2 | 评分 | 标签 | 日期 | 日期 | 图片 | 头像 | 链接 | 金钱 | 进度 | 代码 | 文本 |
---|
未解决-自定义 | 未解决-自定义 | 未解决 | 1 低 | 开启 | 加载失败 | https://dummyimage.com/200x200 | $0.00 | 15 | const { tableData } = useTable<TableRow[]>()【结束】 | text-文本 | ||||
已解决-自定义 | 已解决-自定义 | 已解决 | 1 低 | 开启 | 加载失败 | https://dummyimage.com/200x200 | $1.00 | 25 | const { tableData } = useTable<TableRow[]>()【结束】 | text-文本 | ||||
name... | 未解决-自定义 | 未解决-自定义 | 未解决 | 1 低 | 开启 | 2025-06-16 | 2025-06-16 | 加载失败 | https://dummyimage.com/200x200 | $2.00 | 35 | const { tableData } = useTable<TableRow[]>()【结束】 | text-文本 | |
name... | 已解决-自定义 | 已解决-自定义 | 已解决 | 4 高 | 开启 | 2025-06-16 | 2025-06-16 | 加载失败 | https://dummyimage.com/200x200 | $3.00 | 45 | const { tableData } = useTable<TableRow[]>()【结束】 | text-文本 | |
name... | 未解决-自定义 | 未解决-自定义 | 未解决 | 4 高 | 关闭 | 2025-06-16 | 2025-06-16 | 加载失败 | https://dummyimage.com/200x200 | $4.00 | 55 | const { tableData } = useTable<TableRow[]>()【结束】 | text-文本 | |
name... | 已解决-自定义 | 已解决-自定义 | 已解决 | 4 高 | 关闭 | 2025-06-16 | 2025-06-16 | 加载失败 | https://dummyimage.com/200x200 | $5.00 | 65 | const { tableData } = useTable<TableRow[]>()【结束】 | text-文本 |
<template>
<div>
<el-button type="primary" @click="editable = true"> 开启编辑状态 </el-button>
<el-button type="danger" @click="editable = false"> 关闭编辑状态 </el-button>
<el-divider />
<PlusTable
:editable="editable"
:columns="tableConfig"
:table-data="tableData"
:title-bar="false"
/>
</div>
</template>
<script lang="ts" setup>
import { useTable } from 'plus-pro-components'
import type { PlusColumn, OptionsRow } from 'plus-pro-components'
import { ref } from 'vue'
interface TableRow {
id: number
name: string
status: string
checkbox: string[]
rate: number
time: string | Date
tag: number
img: string
link: string
money: number
progress: number
text: string
}
const editable = ref(false)
const TestServe = {
getList: async () => {
const data: TableRow[] = Array.from({ length: 6 }).map((item, index) => {
return {
id: index,
name: index < 2 ? '' : 'name'.padEnd(50, index + ''),
status: String(index % 2),
checkbox: [String(index % 2)],
rate: index > 2 ? 4 : 1,
time: index < 2 ? '' : new Date(),
tag: index > 3 ? 0 : 1,
img: 'https://dummyimage.com/',
link: '链接',
money: index,
progress: index * 10,
code: `const { tableData } = useTable<TableRow[]>()`,
text: 'text'
}
})
return { data }
}
}
const { tableData } = useTable<TableRow[]>()
const tableConfig: PlusColumn[] = [
{
label: '名称',
prop: 'name',
width: 120,
valueType: 'copy',
formatter: (value: string) => (value ? value.slice(0, 4) + '...' : '')
},
{
label: '状态',
prop: 'status',
width: 140,
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
}
],
formatter: (value, { column }) =>
(column.options as OptionsRow[])?.find(item => item.value === value)?.label + '-自定义' || ''
},
{
label: '状态1',
prop: 'status',
width: 140,
valueType: 'radio',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
}
],
formatter: (value, { column }) =>
(column.options as OptionsRow[])?.find(item => item.value === value)?.label + '-自定义' || ''
},
{
label: '状态2',
prop: 'checkbox',
width: 120,
valueType: 'checkbox',
options: [
{
label: '未解决',
value: '0',
color: 'red'
},
{
label: '已解决',
value: '1',
color: 'blue'
}
],
formatter: (value: string[], { column }) =>
(column.options as OptionsRow[])
?.filter(item => value.includes(item.value as string))
.map(item => item.label)
.toString()
},
{
label: '评分',
width: 60,
prop: 'rate',
valueType: 'rate',
formatter: value => (value >= 4 ? `${value} 高` : `${value} 低`)
},
{
label: '标签',
width: 80,
prop: 'tag',
valueType: 'tag',
fieldProps: value => {
return { type: value === 1 ? 'primary' : 'danger' }
},
formatter: value => (value ? '开启' : '关闭')
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 120,
fieldProps: {
type: 'date',
placeholder: '请选择日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
}
},
{
label: '日期',
prop: 'time',
valueType: 'date-picker',
width: 120,
formatter: value => (value ? new Date().toJSON().slice(0, 10) : ''),
// valueType=== 'date-picker' 时, formatter 存在时,fieldProps的format和valueFormat不再生效。
fieldProps: {
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD'
}
},
{
label: '图片',
prop: 'img',
valueType: 'img',
width: 60,
formatter: value => value + '60x60'
},
{
label: '头像',
prop: 'img',
valueType: 'avatar',
width: 100,
formatter: value => value + '200x200'
},
{
label: '链接',
prop: 'link',
valueType: 'link',
width: 100,
formatter: value => `${value}->`
},
{
label: '金钱',
prop: 'money',
valueType: 'money',
width: 100,
formatter: (value: number) => `$${value.toFixed(2)} `
},
{
label: '进度',
prop: 'progress',
valueType: 'progress',
width: 100,
formatter: value => value + 15
},
{
label: '代码',
prop: 'code',
valueType: 'code',
width: 200,
formatter: value => value + '【结束】'
},
{
label: '文本',
prop: 'text',
valueType: 'text',
width: 200,
formatter: value => value + '-文本'
}
]
const getList = async () => {
try {
const { data } = await TestServe.getList()
tableData.value = data.map(item => ({ ...item }))
} catch (error) {}
}
getList()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
综合表格
# | 名称 | 多级数据 | 状态 | 标签 | 执行进度 | 代码块 | 评分 | 开关 | 图片 | 时间 | 自定义组件 | 自定义html | 操作 |
---|
1 | namenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamename | level0 | 未解决 | danger | 0 |
const getData = async params => {
const data = await getData(params)
return { list: data.data, ...data }
} | 加载失败 | 2025-06-16 03:07:56 | 待审核 | custom0 | |||
2 | 1name | level1 | 已解决 | success | 1 |
const getData = async params => {
const data = await getData(params)
return { list: data.data, ...data }
} | 加载失败 | 2025-06-16 03:07:56 | 进行中 | custom1 | |||
3 | 2name | level2 | 解决中 | warning | 8 |
const getData = async params => {
const data = await getData(params)
return { list: data.data, ...data }
} | 加载失败 | 2025-06-16 03:07:56 | 已结束 | custom2 |
- 1
<template>
<div>
<PlusTable
ref="plusTable"
row-key="id"
size="small"
:loading-status="loadingStatus"
:columns="tableConfig"
:table-data="tableData"
has-index-column
:drag-sort="true"
table-title="表格"
:pagination="{ total, modelValue: pageInfo }"
:action-bar="{
buttons,
type: 'link',
showNumber: 3,
width: 200
}"
@paginationChange="handlePaginationChange"
@clickAction="handleClickButton"
@dragSortEnd="handleSortEnd"
@formChange="handleChange"
>
<template #toolbar>
<el-button plain size="small">查看日志</el-button>
<el-button plain size="small">导出数据</el-button>
<el-button type="primary" size="small">创建应用</el-button>
</template>
</PlusTable>
</div>
</template>
<script lang="ts" setup>
import { ref, h } from 'vue'
import { useTable } from 'plus-pro-components'
import type {
PlusTableInstance,
ButtonsCallBackParams,
PageInfo,
PlusColumn
} from 'plus-pro-components'
import { ElAlert } from 'element-plus'
defineOptions({
name: 'PlusTableAdvancedTest'
})
interface TableRow {
index: number
id: number
name: string
status: string
tag: string
progress: number
rate: number
switch: boolean
img: string
code: string
time: Date
custom: string
}
const TestServe = {
getList: async () => {
const data = Array.from({ length: 3 }).map((item, index) => {
return {
index,
id: index,
name: index === 0 ? 'name'.repeat(20) : index + 'name',
status: String(index % 3),
tag: index === 1 ? 'success' : index === 2 ? 'warning' : index === 3 ? 'info' : 'danger',
progress: Math.ceil(Math.random() * index * 10),
rate: index > 3 ? 2 : 3.5,
switch: index % 2 === 0 ? true : false,
img: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
time: new Date(),
code: `
const getData = async params => {
const data = await getData(params)
return { list: data.data, ...data }
}`,
custom: 'custom' + index,
level: {
state: {
value: 'level' + index
}
}
}
})
return {
data: data as TableRow[],
total: data.length
}
}
}
const plusTable = ref<PlusTableInstance>()
const { tableData, pageInfo, total, buttons, loadingStatus } = useTable<TableRow[]>()
buttons.value = [
{
// 查看
text: '查看',
props: {
type: 'primary'
}
},
{
// 修改
text: '修改',
props: {
type: 'success'
}
},
{
// 删除
text: '删除',
props: {
type: 'warning'
},
confirm: {}
},
{
text: '复制',
props: {
type: 'primary'
},
confirm: {}
}
]
const statusOptions = [
{
label: '待审核',
value: '0',
type: 'info'
},
{
label: '进行中',
value: '1',
type: 'success'
},
{
label: '已结束',
value: '2',
type: 'warning'
}
]
const tableConfig: PlusColumn[] = [
{
label: '名称',
tooltip: '名称最多显示6个字符',
width: 120,
prop: 'name',
tableColumnProps: {
showOverflowTooltip: true
}
},
{
label: '多级数据',
width: 120,
prop: 'level.state.value'
},
{
label: '状态',
width: 120,
prop: 'status',
valueType: 'select',
options: [
{
label: '未解决',
value: '0',
type: 'warning'
},
{
label: '已解决',
value: '1',
type: 'success'
},
{
label: '解决中',
value: '2',
type: 'primary'
},
{
label: '失败',
value: '3',
type: 'danger'
}
]
},
{
label: '标签',
width: 120,
prop: 'tag',
valueType: 'tag',
fieldProps: (value: string) => {
return { type: value }
}
},
{
label: '执行进度',
width: 200,
prop: 'progress',
valueType: 'progress',
fieldProps: (value: number) => {
const data =
value === 0
? { status: 'exception' }
: value > 5
? { status: 'warning' }
: value > 3
? { status: 'success' }
: { status: 'exception' }
return data
}
},
{
label: '代码块',
width: 250,
prop: 'code',
valueType: 'code'
},
{
label: '评分',
width: 200,
prop: 'rate',
valueType: 'rate',
editable: true
},
{
label: '开关',
width: 100,
prop: 'switch',
valueType: 'switch',
editable: true
},
{
label: '图片',
prop: 'img',
width: 100,
valueType: 'img'
},
{
label: '时间',
prop: 'time',
width: 180,
valueType: 'date-picker',
renderHeader: (label, props) => {
return h('h1' as any, { style: { color: 'red' } }, props.label)
}
},
{
label: '自定义组件',
width: 200,
prop: 'status',
render: value => {
const item = statusOptions.find(item => item.value === value)
return h(ElAlert as any, { type: item?.type }, () => item?.label)
}
},
{
label: '自定义html',
width: 100,
prop: 'custom',
renderHTML: (value: any) => {
return `<div style='color:red;'>${value}</div>`
}
}
]
const getList = async () => {
try {
loadingStatus.value = true
const { data, total: dataTotal } = await TestServe.getList()
tableData.value = data || []
total.value = dataTotal
} catch (error) {}
loadingStatus.value = false
}
getList()
const handlePaginationChange = (_pageInfo: PageInfo): void => {
pageInfo.value = _pageInfo
getList()
}
const handleClickButton = (data: ButtonsCallBackParams) => {
console.log(data.buttonRow.text)
}
const handleSortEnd = (newIndex: number, oldIndex: number) => {
const currRow = tableData.value.splice(oldIndex, 1)[0]
tableData.value.splice(newIndex, 0, currRow)
}
const handleChange = (data: {
value: any
prop: string
row: TableRow
index: number
column: any
}) => {
console.log(data)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
Table API
Table Attributes
名称 | 说明 | 类型 | 默认值 | 是否必须 |
---|---|---|---|---|
columns | 表格配置信息 | array PlusColumn[] | [] | 是 |
tableData | 表格数据 | array | [] | 是 |
defaultSize | 默认密度(size) | string | 'default' | 否 |
pagination | 分页参数 (默认 false 给参数就显示) | false / (object PlusPaginationProps ) | false | 否 |
actionBar | 操作栏参数 (默认 false 给参数就显示) | false / (object ActionBarProps ) | false | 否 |
titleBar | 标题栏 | boolean / (object TitleBar) | true | 否 |
hasIndexColumn | 是否需要序号 | boolean | false | 否 |
isSelection | 是否是多选表格 | boolean | false | 否 |
isRadio `v0.1.23 | 是否是单选表格 | boolean | false | 否 |
dragSortable | 表格拖拽配置 (默认 false 给参数就显示) | false / (object SortableOptions ) | false | 否 |
hasExpand | 是否需要展开行 | boolean | false | 否 |
loadingStatus | 加载状态 | boolean | false | 否 |
height | 表格高度 | string | 否 | |
editable v0.1.4 | 表格整体可编辑 | boolean / string | false | 否 |
headerCellStyle | 表格表头样式 | object CSSProperties | {'background-color': 'var(--el-fill-color-light)'} | 否 |
indexContentStyle | 序号栏样式 | (object CSSProperties ) / function | {} | 否 |
dragSortableTableColumnProps | 拖拽栏 el-table-column 的 props | object ElTableColumnProps | {} | 否 |
indexTableColumnProps | 序号栏 el-table-column 的 props | object ElTableColumnProps | {} | 否 |
selectionTableColumnProps | 选择栏 el-table-column 的 props | object ElTableColumnProps | {width: 40} | 否 |
expandTableColumnProps | 展开栏 el-table-column 的 props | object ElTableColumnProps | {} | 否 |
radioTableColumnProps v0.1.23 | 单选栏 el-table-column 的 props | object ElTableColumnProps | ` | 否 |
radioProps v0.1.23 | 单选栏 plus-radio 的 props | object PlusRadioProps | ` | 否 |
defaultSelectedRadioRow v0.1.23 | 单选栏默认选择的表格行数据 | object | ComputedRef | 否 | |
adaptive v0.1.17 | 表格高度自适应内容区域配置 | boolean |object | false | 否 |
... | ... | ... | ... | ... |
...
表示同时支持所有ElTable Attributes
提示
el-table 的其他属性写法示例 如 stripe
,border
,fit
等
示例:
<PlusTable :stripe="true" :border="true" :fit="false" />
Table Events
名称 | 说明 | 类型 |
---|---|---|
paginationChange | 分页改变触发 | function |
clickAction | 点击操作栏触发(需要二次确认的,点击确认时触发) | function ButtonsCallBackParams |
clickActionConfirmCancel | 点击操作栏需要二次确认的取消时触发 | function ButtonsCallBackParams |
dragSortEnd | 拖拽排序行触发 | function |
formChange | 表格中有可以编辑的表单项目改变时触发 | function FormChangeCallBackParams |
edited v0.1.4 | 表格中点击编辑单元格退出时触发 | function |
filterTableHeader v0.1.22 | 表格表头列设置改变时触发,eventType 参数解释: check:表头单个 check; allCheck:全选/取消全选 check; drag:拖拽; reset:重置; | function |
radioChange v0.1.23 | 单选栏改变时触发 | function |
... | ... | ... |
...
表示同时支持所有ElTable 事件
提示
el-table 的其他事件写法示例 如 select
,select-all
,row-click
等,如下示例
示例:
模板中
<PlusTable @select="handleSelect" @select-all="handleSelectAll" />
setup 中
const handleSelect = (selection: any[], row: any) => {
console.log(selection, row)
}
const handleSelectAll = (selection: any[]) => {
console.log(selection)
}
2
3
4
5
6
Table Slots
插槽名 | 说明 | 作用域插槽参数 |
---|---|---|
title | 表格标题 | |
toolbar | 工具栏左侧 | |
expand | 展开行 | |
pagination-left v0.0.2 | 分页器左侧内容 (默认生效,align 属性默认是 right ) | |
pagination-right v0.0.2 | 分页器右侧内容 (align 属性是 left 时生效) | |
action-bar-more-icon v0.0.3 | 操作栏更多旁边的 icon | |
tooltip-icon v0.0.3 | 表格表头 tooltip icon | |
drag-sort-icon v0.0.3 | 表格拖拽行 和 列设置里拖拽 icon | |
column-settings-icon v0.0.3 | 表格表头 列设置 icon | |
density-icon v0.0.3 | 表格表头 密度 icon | |
edit-icon v0.1.4 | 表格处于编辑状态时的 icon | |
plus-cell-* | 自定义表格项,组件会自动根据配置项的 prop 生成对应的插槽 | object |
plus-header-* | 自定义表格项 header,组件会自动根据配置项的 prop 生成对应的插槽 | object |
plus-field-* | PlusForm 的自定义表单项,组件会自动根据配置项的 prop 生成对应的插槽 ,需要开启属性 PlusColumn['editable'] | object |
plus-extra-* | PlusForm的自定义渲染 el-form-item 下一行额外的内容,组件会自动根据配置项的 prop 生成对应的插槽,需要开启属性 PlusColumn['editable'] | {column,row} |
... | ... | ... |
...
表示同时支持所有ElTable 插槽
提示
el-table 的其他插槽 如 append
,empty
。 v0.1.7 开始支持 default
插槽。
Table Exposes
名称 | 说明 | 类型 |
---|---|---|
tableInstance | el-table 的实例 | object import('element-plus')['TableInstance'] |
formRefs | 表格中所有 form 的实例,可以用来控制表格是否可编辑,以及表格表单检验等 | object |
拿到 tableInstance 后支持所有ElTable 方法
提示
如 clearSelection
,getSelectionRows
等