vue3-components-plus 3.0.16 → 3.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,564 +1,570 @@
1
- <template>
2
- <div class="demo-page">
3
- <!-- 使用 NsTableContainer 组件 -->
4
- <NsTableContainer
5
- ref="containerRef"
6
- :search-items="searchItems"
7
- :external-search-params="externalSearchParams"
8
- :search-props="{
9
- labelWidth: '100px',
10
- }"
11
- :table-data="tableData"
12
- :columns="columns"
13
- :total="total"
14
- :table-props="{
15
- showSelection: true,
16
- showIndex: true,
17
- loading: loading,
18
- rowKey: 'id',
19
- showPagination: true,
20
- }"
21
- :load-data="loadData"
22
- @search="handleSearch"
23
- @reset="handleReset"
24
- @add="handleAdd"
25
- @selection-change="handleSelectionChange"
26
- >
27
- <!-- 自定义状态列 -->
28
- <template #status="{ row }">
29
- <el-tag :type="getStatusType(row.status)">
30
- {{ getStatusText(row.status) }}
31
- </el-tag>
32
- </template>
33
-
34
- <!-- 自定义性别列 -->
35
- <template #gender="{ row }">
36
- <el-tag :type="row.gender === 1 ? 'primary' : 'danger'" size="small">
37
- {{ row.gender === 1 ? '男' : '女' }}
38
- </el-tag>
39
- </template>
40
-
41
- <!-- 自定义部门列 -->
42
- <template #department="{ row }">
43
- <el-tag effect="plain">{{ getDepartmentText(row.department) }}</el-tag>
44
- </template>
45
- </NsTableContainer>
46
- <!-- 选择操作区域 -->
47
- <div class="selection-actions">
48
- <el-button @click="getSelectedRows">获取选中行</el-button>
49
- <el-button @click="getSelectedKeys">获取选中ID</el-button>
50
- <el-button @click="selectRows([1, 5, 21])">选中ID为1, 5, 21的行</el-button>
51
- <el-button @click="clearSelection">清空选择</el-button>
52
- <el-button @click="selectAll">全选</el-button>
53
- <el-button @click="checkSelection">检查选择状态</el-button>
54
- </div>
55
- </div>
56
- </template>
57
-
58
- <script setup lang="ts">
59
- import { Delete, Edit, View } from '@element-plus/icons-vue'
60
- import { ElDatePicker, ElInput, ElMessage, ElMessageBox, ElSelect, ElSwitch } from 'element-plus'
61
- import { onMounted, ref } from 'vue'
62
- import { fetchDepartmentOptions, fetchStatusOptions, filterUsers, mockUsers } from './mockData.js'
63
-
64
- // ==================== 组件引用 ====================
65
- const containerRef = ref(null)
66
-
67
- // ==================== 搜索配置 ====================
68
- // 当前搜索参数(从 PageSearch 获取)
69
- const searchParams = ref({})
70
-
71
- // 外部注入的搜索参数(用于特殊情况传参)
72
- const externalSearchParams = ref({ test: 'aaa' })
73
-
74
- // ==================== 数据状态 ====================
75
- const loading = ref(false)
76
- const tableData = ref([])
77
- const total = ref(0)
78
-
79
- const searchItems = ref([
80
- {
81
- prop: "mounth",
82
- label: "归属月",
83
- span: 6,
84
- component: ElSelect,
85
- attrs: {
86
- placeholder: "请选择归属月",
87
- clearable: true,
88
- options: [
89
- {
90
- value: "Option1",
91
- label: "Option1"
92
- },
93
- {
94
- value: "Option2",
95
- label: "Option2",
96
- },
97
- {
98
- value: "Option3",
99
- label: "Option3"
100
- },
101
- {
102
- value: "Option4",
103
- label: "Option4",
104
- },
105
- {
106
- value: "Option5",
107
- label: "Option5"
108
- }
109
- ]
110
- }
111
- },
112
- {
113
- prop: 'username',
114
- label: '用户名',
115
- span: 6,
116
- component: ElInput,
117
- attrs: {
118
- placeholder: '请输入用户名',
119
- clearable: true,
120
- maxlength: 20,
121
- },
122
- events: {
123
- keyup: (e) => {
124
- if (e.key === 'Enter') {
125
- handleSearch()
126
- }
127
- },
128
- },
129
- },
130
- {
131
- prop: 'realName',
132
- label: '真实姓名',
133
- span: 6,
134
- component: ElInput,
135
- attrs: {
136
- placeholder: '请输入真实姓名',
137
- clearable: true,
138
- },
139
- },
140
- {
141
- prop: 'status',
142
- label: '状态',
143
- span: 6,
144
- component: ElSelect,
145
- attrs: {
146
- placeholder: '请选择状态',
147
- clearable: true,
148
- },
149
- children: [],
150
- events: {
151
- change: (_) => {
152
- ElMessage.success('下拉选择变化')
153
- },
154
- },
155
- },
156
- {
157
- prop: 'department',
158
- label: '部门',
159
- span: 6,
160
- component: ElSelect,
161
- attrs: {
162
- placeholder: '请选择部门',
163
- clearable: true,
164
- filterable: true,
165
- },
166
- children: [],
167
- },
168
- {
169
- prop: 'gender',
170
- label: '性别',
171
- span: 6,
172
- component: ElSelect,
173
- attrs: {
174
- placeholder: '请选择性别',
175
- clearable: true,
176
- },
177
- children: [
178
- { label: '全部', value: '' },
179
- { label: '男', value: 1 },
180
- { label: '女', value: 2 },
181
- ],
182
- },
183
- {
184
- prop: 'createTime',
185
- label: '创建时间',
186
- span: 6,
187
- component: ElDatePicker,
188
- attrs: {
189
- type: 'daterange',
190
- rangeSeparator: '至',
191
- startPlaceholder: '开始日期',
192
- endPlaceholder: '结束日期',
193
- clearable: true,
194
- format: 'YYYY-MM-DD',
195
- valueFormat: 'YYYY-MM-DD',
196
- },
197
- },
198
- {
199
- prop: 'phone',
200
- label: '手机号',
201
- span: 6,
202
- component: ElInput,
203
- attrs: {
204
- placeholder: '请输入手机号',
205
- clearable: true,
206
- maxlength: 11,
207
- },
208
- },
209
- {
210
- prop: 'active',
211
- label: '是否激活',
212
- span: 6,
213
- component: ElSwitch,
214
- attrs: {
215
- activeText: '是',
216
- inactiveText: '否',
217
- },
218
- defaultValue: true,
219
- },
220
- ])
221
-
222
- // ==================== 表格配置 ====================
223
- const columns = ref([
224
- {
225
- prop: 'id',
226
- label: 'ID',
227
- width: 80,
228
- sortable: true,
229
- // el-table-column 属性透传示例
230
- 'class-name': 'id-column', // 自定义列样式类名
231
- resizable: false, // 禁止拖拽调整宽度
232
- },
233
- // 多级表头示例:基本信息
234
- {
235
- label: '基本信息',
236
- children: [
237
- { prop: 'avatar', label: '头像', slot: 'avatar', width: 80 },
238
- {
239
- prop: 'username',
240
- label: '用户名',
241
- width: 120,
242
- // 透传属性
243
- 'show-overflow-tooltip': true, // 内容过长时显示 tooltip
244
- formatter: (row, column, cellValue) => {
245
- return cellValue ? `@${cellValue}` : '-'
246
- },
247
- },
248
- {
249
- prop: 'realName',
250
- label: '真实姓名',
251
- width: 120,
252
- 'min-width': 100, // 最小宽度
253
- },
254
- { prop: 'gender', label: '性别', slot: 'gender', width: 80 },
255
- ]
256
- },
257
- // 多级表头示例:组织信息
258
- {
259
- label: '组织信息',
260
- children: [
261
- { prop: 'department', label: '部门', slot: 'department', width: 120 },
262
- { prop: 'status', label: '状态', slot: 'status', width: 100 },
263
- ]
264
- },
265
- // 多级表头示例:联系方式
266
- {
267
- label: '联系方式',
268
- children: [
269
- {
270
- prop: 'phone',
271
- label: '手机号',
272
- width: 130,
273
- 'show-overflow-tooltip': true,
274
- },
275
- {
276
- prop: 'email',
277
- label: '邮箱',
278
- minWidth: 180,
279
- 'show-overflow-tooltip': true,
280
- filters: [
281
- // 筛选配置
282
- { text: 'Gmail', value: '@gmail.com' },
283
- { text: 'QQ邮箱', value: '@qq.com' },
284
- ],
285
- 'filter-method': (value, row) => {
286
- return row.email.includes(value)
287
- },
288
- },
289
- ]
290
- },
291
- {
292
- prop: 'createTime',
293
- label: '创建时间',
294
- width: 180,
295
- sortable: true,
296
- 'sort-orders': ['descending', 'ascending'], // 排序顺序
297
- },
298
- // 操作列
299
- {
300
- type: 'action',
301
- label: '操作',
302
- width: 300,
303
- fixed: 'right',
304
- align: 'center',
305
- headerAlign: 'center',
306
- buttons: [
307
- {
308
- label: '查看',
309
- type: 'primary',
310
- link: true,
311
- icon: View,
312
- handler: (row) => handleView(row),
313
- },
314
- {
315
- label: '编辑',
316
- type: 'warning',
317
- link: true,
318
- icon: Edit,
319
- handler: (row) => handleEdit(row),
320
- },
321
- {
322
- label: '删除',
323
- type: 'danger',
324
- link: true,
325
- icon: Delete,
326
- show: true,
327
- disabled: (row) => row.status === 0, // 业务时不展示
328
- handler: (row) => handleDelete(row),
329
- },
330
- ],
331
- },
332
- ])
333
-
334
- // ==================== 工具方法 ====================
335
- const getStatusType = (status) => {
336
- return status === 1 ? 'success' : 'danger'
337
- }
338
-
339
- const getStatusText = (status) => {
340
- return status === 1 ? '启用' : '禁用'
341
- }
342
-
343
- const getDepartmentText = (department) => {
344
- const departmentOptions = [
345
- { label: '技术部', value: 'tech' },
346
- { label: '产品部', value: 'product' },
347
- { label: '运营部', value: 'operation' },
348
- { label: '人力资源部', value: 'hr' },
349
- { label: '财务部', value: 'finance' },
350
- ]
351
- const dept = departmentOptions.find((d) => d.value === department)
352
- return dept ? dept.label : department
353
- }
354
-
355
- // ==================== 数据加载 ====================
356
- const loadData = async () => {
357
- loading.value = true
358
- try {
359
- // 模拟网络延迟
360
- await new Promise((resolve) => setTimeout(resolve, 500))
361
-
362
- // 从组件获取分页信息
363
- const pagination = containerRef.value?.getPagination() || {
364
- currentPage: 1,
365
- pageSize: 10,
366
- }
367
-
368
- // 使用 filterUsers 进行过滤和分页
369
- const result = filterUsers(mockUsers, searchParams.value, {
370
- currentPage: pagination.currentPage,
371
- pageSize: pagination.pageSize,
372
- })
373
-
374
- // 更新数据
375
- tableData.value = result.list
376
- total.value = result.total
377
- } catch (error) {
378
- console.error('加载数据失败:', error)
379
- ElMessage.error('加载数据失败')
380
- } finally {
381
- loading.value = false
382
- }
383
- }
384
-
385
- // ==================== 事件处理 ====================
386
- // 搜索
387
- const handleSearch = (params) => {
388
- // 更新搜索参数
389
- searchParams.value = { ...params }
390
- loadData()
391
- }
392
-
393
- // 重置
394
- const handleReset = () => {
395
- // 重置搜索参数
396
- // searchParams.value = {};
397
- console.log('表单已重置,数据已刷新')
398
- }
399
-
400
- // 选择变化
401
- const handleSelectionChange = (selection) => {
402
- console.log('选中的数据:', selection)
403
- }
404
-
405
- // ==================== 选择列操作方法 ====================
406
- const getSelectedRows = () => {
407
- if (!containerRef.value) return
408
- const selectedRows = containerRef.value.getSelectionRows()
409
- ElMessage.success(
410
- `选中了 ${selectedRows.length} 行数据:${selectedRows.map((r) => r.username).join(', ')}`,
411
- )
412
- console.log('选中的行数据:', selectedRows)
413
- }
414
-
415
- const getSelectedKeys = () => {
416
- if (!containerRef.value) return
417
- const selectedKeys = containerRef.value.getSelectionKeys()
418
- ElMessage.success(`选中了 ${selectedKeys.length} 个ID:${selectedKeys.join(', ')}`)
419
- console.log('选中的ID:', selectedKeys)
420
- }
421
-
422
- const selectRows = (ids) => {
423
- if (!containerRef.value) return
424
-
425
- try {
426
- // 设置选择
427
- containerRef.value.setSelectionKeys(ids)
428
-
429
- // 延迟检查选择结果
430
- const selectedRows = containerRef.value.getSelectionRows()
431
- const selectedKeys = containerRef.value.getSelectionKeys()
432
-
433
- if (selectedRows.length > 0) {
434
- ElMessage.success(`已选中ID为 ${ids.join(', ')} 的行,实际选中:${selectedKeys.join(', ')}`)
435
- } else {
436
- ElMessage.warning(`未选中任何行,请检查数据是否正确`)
437
- }
438
- } catch (error) {
439
- console.error('选择出错:', error)
440
- ElMessage.error(`选择失败:${error.message}`)
441
- }
442
- }
443
-
444
- const clearSelection = () => {
445
- if (!containerRef.value) return
446
- containerRef.value.clearAllSelection()
447
- ElMessage.success('已清空所有选择')
448
- }
449
-
450
- const selectAll = () => {
451
- if (!containerRef.value) return
452
- containerRef.value.selectAll()
453
- ElMessage.success('已全选所有行')
454
- }
455
-
456
- const checkSelection = () => {
457
- if (!containerRef.value) return
458
-
459
- // 检查特定行是否被选中
460
- const isRow1Selected = containerRef.value.isRowSelected(tableData.value[0])
461
- const isKey3Selected = containerRef.value.isKeySelected(3)
462
-
463
- ElMessage.info(
464
- `第一行是否选中:${isRow1Selected ? '是' : '否'},ID为3是否选中:${
465
- isKey3Selected ? '是' : '否'
466
- }`,
467
- )
468
- }
469
-
470
- // 新增
471
- const handleAdd = () => {
472
- ElMessage.success('新增')
473
- }
474
-
475
- // 查看
476
- const handleView = (row) => {
477
- ElMessage.success(`查看:${row.username}`)
478
- }
479
-
480
- // 编辑
481
- const handleEdit = (row) => {
482
- ElMessage.success(`编辑:${row.username}`)
483
- }
484
-
485
- // 删除
486
- const handleDelete = (row) => {
487
- ElMessageBox.confirm(`确定要删除用户 "${row.username}" 吗?`, '删除确认', {
488
- confirmButtonText: '确定',
489
- cancelButtonText: '取消',
490
- type: 'warning',
491
- }).then(() => {
492
- // 模拟删除
493
- ElMessage.success('删除成功')
494
- loadData()
495
- })
496
- }
497
-
498
- // ==================== 生命周期 ====================
499
- onMounted(async () => {
500
- // 异步获取状态选项(模拟接口请求,延迟2秒)
501
- const options = await fetchStatusOptions()
502
- searchItems.value[2].children = options
503
-
504
- // 异步获取部门选项(模拟接口请求,延迟2秒)
505
- const departmentOptions = await fetchDepartmentOptions()
506
- searchItems.value[3].children = departmentOptions
507
-
508
- // 搜索条件准备好后,调用 initSearchAndLoad 初始化搜索参数并加载数据
509
- // 这会自动获取 PageSearch 的初始表单数据(包含默认值和外部参数)
510
- containerRef.value?.initSearchAndLoad()
511
- })
512
- </script>
513
-
514
- <style scoped>
515
- .demo-page {
516
- height: 100%;
517
- padding: 20px;
518
- background: #f5f7fa;
519
- display: flex;
520
- flex-direction: column;
521
- }
522
-
523
- :deep(.el-dialog__body) {
524
- padding: 20px;
525
- }
526
-
527
- .selection-actions {
528
- margin-top: 20px;
529
- padding: 20px;
530
- background: #f5f7fa;
531
- border-radius: 4px;
532
- display: flex;
533
- gap: 10px;
534
- flex-wrap: wrap;
535
- }
536
-
537
- .debug-content {
538
- padding: 0 20px;
539
- }
540
-
541
- .debug-item {
542
- margin-bottom: 24px;
543
- }
544
-
545
- .debug-label {
546
- display: block;
547
- font-weight: 600;
548
- color: #303133;
549
- margin-bottom: 8px;
550
- font-size: 14px;
551
- }
552
-
553
- .debug-value {
554
- background: #f5f7fa;
555
- padding: 12px;
556
- border-radius: 4px;
557
- font-size: 13px;
558
- color: #606266;
559
- margin: 0;
560
- white-space: pre-wrap;
561
- word-wrap: break-word;
562
- border: 1px solid #e4e7ed;
563
- }
564
- </style>
1
+ <template>
2
+ <div class="demo-page">
3
+ <!-- 使用 NsTableContainer 组件 -->
4
+ <NsTableContainer
5
+ ref="containerRef"
6
+ page-number-key="currentPage1"
7
+ page-size-key="pageSize1"
8
+ page-total-key="total1"
9
+ :search-items="searchItems"
10
+ :external-search-params="externalSearchParams"
11
+ :search-props="{
12
+ labelWidth: '100px',
13
+ }"
14
+ :table-data="tableData"
15
+ :columns="columns"
16
+ :total="total"
17
+ :table-props="{
18
+ showSelection: true,
19
+ showIndex: true,
20
+ loading: loading,
21
+ rowKey: 'id',
22
+ showPagination: true,
23
+ }"
24
+ :load-data="loadData"
25
+ @search="handleSearch"
26
+ @reset="handleReset"
27
+ @add="handleAdd"
28
+ @selection-change="handleSelectionChange"
29
+ >
30
+ <!-- 自定义状态列 -->
31
+ <template #status="{ row }">
32
+ <el-tag :type="getStatusType(row.status)">
33
+ {{ getStatusText(row.status) }}
34
+ </el-tag>
35
+ </template>
36
+
37
+ <!-- 自定义性别列 -->
38
+ <template #gender="{ row }">
39
+ <el-tag :type="row.gender === 1 ? 'primary' : 'danger'" size="small">
40
+ {{ row.gender === 1 ? '男' : '女' }}
41
+ </el-tag>
42
+ </template>
43
+
44
+ <!-- 自定义部门列 -->
45
+ <template #department="{ row }">
46
+ <el-tag effect="plain">{{ getDepartmentText(row.department) }}</el-tag>
47
+ </template>
48
+ </NsTableContainer>
49
+ <!-- 选择操作区域 -->
50
+ <div class="selection-actions">
51
+ <el-button @click="getSelectedRows">获取选中行</el-button>
52
+ <el-button @click="getSelectedKeys">获取选中ID</el-button>
53
+ <el-button @click="selectRows([1, 5, 21])">选中ID为1, 5, 21的行</el-button>
54
+ <el-button @click="clearSelection">清空选择</el-button>
55
+ <el-button @click="selectAll">全选</el-button>
56
+ <el-button @click="checkSelection">检查选择状态</el-button>
57
+ </div>
58
+ </div>
59
+ </template>
60
+
61
+ <script setup lang="ts">
62
+ import { Delete, Edit, View } from '@element-plus/icons-vue'
63
+ import { ElDatePicker, ElInput, ElMessage, ElMessageBox, ElSelect, ElSwitch } from 'element-plus'
64
+ import { onMounted, ref } from 'vue'
65
+ import { fetchDepartmentOptions, fetchStatusOptions, filterUsers, mockUsers } from './mockData.js'
66
+
67
+ // ==================== 组件引用 ====================
68
+ const containerRef = ref(null)
69
+
70
+ // ==================== 搜索配置 ====================
71
+ // 当前搜索参数(从 PageSearch 获取)
72
+ const searchParams = ref({})
73
+
74
+ // 外部注入的搜索参数(用于特殊情况传参)
75
+ const externalSearchParams = ref({ test: 'aaa' })
76
+
77
+ // ==================== 数据状态 ====================
78
+ const loading = ref(false)
79
+ const tableData = ref([])
80
+ const total = ref(0)
81
+
82
+ const searchItems = ref([
83
+ {
84
+ prop: "mounth",
85
+ label: "归属月",
86
+ span: 6,
87
+ component: ElSelect,
88
+ attrs: {
89
+ placeholder: "请选择归属月",
90
+ clearable: true,
91
+ options: [
92
+ {
93
+ value: "Option1",
94
+ label: "Option1"
95
+ },
96
+ {
97
+ value: "Option2",
98
+ label: "Option2",
99
+ },
100
+ {
101
+ value: "Option3",
102
+ label: "Option3"
103
+ },
104
+ {
105
+ value: "Option4",
106
+ label: "Option4",
107
+ },
108
+ {
109
+ value: "Option5",
110
+ label: "Option5"
111
+ }
112
+ ]
113
+ }
114
+ },
115
+ {
116
+ prop: 'username',
117
+ label: '用户名',
118
+ span: 6,
119
+ component: ElInput,
120
+ attrs: {
121
+ placeholder: '请输入用户名',
122
+ clearable: true,
123
+ maxlength: 20,
124
+ },
125
+ events: {
126
+ keyup: (e) => {
127
+ if (e.key === 'Enter') {
128
+ handleSearch()
129
+ }
130
+ },
131
+ },
132
+ },
133
+ {
134
+ prop: 'realName',
135
+ label: '真实姓名',
136
+ span: 6,
137
+ component: ElInput,
138
+ attrs: {
139
+ placeholder: '请输入真实姓名',
140
+ clearable: true,
141
+ },
142
+ },
143
+ {
144
+ prop: 'status',
145
+ label: '状态',
146
+ span: 6,
147
+ component: ElSelect,
148
+ attrs: {
149
+ placeholder: '请选择状态',
150
+ clearable: true,
151
+ },
152
+ children: [],
153
+ events: {
154
+ change: (_) => {
155
+ ElMessage.success('下拉选择变化')
156
+ },
157
+ },
158
+ },
159
+ {
160
+ prop: 'department',
161
+ label: '部门',
162
+ span: 6,
163
+ component: ElSelect,
164
+ attrs: {
165
+ placeholder: '请选择部门',
166
+ clearable: true,
167
+ filterable: true,
168
+ },
169
+ children: [],
170
+ },
171
+ {
172
+ prop: 'gender',
173
+ label: '性别',
174
+ span: 6,
175
+ component: ElSelect,
176
+ attrs: {
177
+ placeholder: '请选择性别',
178
+ clearable: true,
179
+ },
180
+ children: [
181
+ { label: '全部', value: '' },
182
+ { label: '男', value: 1 },
183
+ { label: '女', value: 2 },
184
+ ],
185
+ },
186
+ {
187
+ prop: 'createTime',
188
+ label: '创建时间',
189
+ span: 6,
190
+ component: ElDatePicker,
191
+ attrs: {
192
+ type: 'daterange',
193
+ rangeSeparator: '至',
194
+ startPlaceholder: '开始日期',
195
+ endPlaceholder: '结束日期',
196
+ clearable: true,
197
+ format: 'YYYY-MM-DD',
198
+ valueFormat: 'YYYY-MM-DD',
199
+ },
200
+ },
201
+ {
202
+ prop: 'phone',
203
+ label: '手机号',
204
+ span: 6,
205
+ component: ElInput,
206
+ attrs: {
207
+ placeholder: '请输入手机号',
208
+ clearable: true,
209
+ maxlength: 11,
210
+ },
211
+ },
212
+ {
213
+ prop: 'active',
214
+ label: '是否激活',
215
+ span: 6,
216
+ component: ElSwitch,
217
+ attrs: {
218
+ activeText: '是',
219
+ inactiveText: '否',
220
+ },
221
+ defaultValue: true,
222
+ },
223
+ ])
224
+
225
+ // ==================== 表格配置 ====================
226
+ const columns = ref([
227
+ {
228
+ prop: 'id',
229
+ label: 'ID',
230
+ width: 80,
231
+ sortable: true,
232
+ // el-table-column 属性透传示例
233
+ 'class-name': 'id-column', // 自定义列样式类名
234
+ resizable: false, // 禁止拖拽调整宽度
235
+ },
236
+ // 多级表头示例:基本信息
237
+ {
238
+ label: '基本信息',
239
+ children: [
240
+ { prop: 'avatar', label: '头像', slot: 'avatar', width: 80 },
241
+ {
242
+ prop: 'username',
243
+ label: '用户名',
244
+ width: 120,
245
+ // 透传属性
246
+ 'show-overflow-tooltip': true, // 内容过长时显示 tooltip
247
+ formatter: (row, column, cellValue) => {
248
+ return cellValue ? `@${cellValue}` : '-'
249
+ },
250
+ },
251
+ {
252
+ prop: 'realName',
253
+ label: '真实姓名',
254
+ width: 120,
255
+ 'min-width': 100, // 最小宽度
256
+ },
257
+ { prop: 'gender', label: '性别', slot: 'gender', width: 80 },
258
+ ]
259
+ },
260
+ // 多级表头示例:组织信息
261
+ {
262
+ label: '组织信息',
263
+ children: [
264
+ { prop: 'department', label: '部门', slot: 'department', width: 120 },
265
+ { prop: 'status', label: '状态', slot: 'status', width: 100 },
266
+ ]
267
+ },
268
+ // 多级表头示例:联系方式
269
+ {
270
+ label: '联系方式',
271
+ children: [
272
+ {
273
+ prop: 'phone',
274
+ label: '手机号',
275
+ width: 130,
276
+ 'show-overflow-tooltip': true,
277
+ },
278
+ {
279
+ prop: 'email',
280
+ label: '邮箱',
281
+ minWidth: 180,
282
+ 'show-overflow-tooltip': true,
283
+ filters: [
284
+ // 筛选配置
285
+ { text: 'Gmail', value: '@gmail.com' },
286
+ { text: 'QQ邮箱', value: '@qq.com' },
287
+ ],
288
+ 'filter-method': (value, row) => {
289
+ return row.email.includes(value)
290
+ },
291
+ },
292
+ ]
293
+ },
294
+ {
295
+ prop: 'createTime',
296
+ label: '创建时间',
297
+ width: 180,
298
+ sortable: true,
299
+ 'sort-orders': ['descending', 'ascending'], // 排序顺序
300
+ },
301
+ // 操作列
302
+ {
303
+ type: 'action',
304
+ label: '操作',
305
+ width: 300,
306
+ fixed: 'right',
307
+ align: 'center',
308
+ headerAlign: 'center',
309
+ buttons: [
310
+ {
311
+ label: '查看',
312
+ type: 'primary',
313
+ link: true,
314
+ icon: View,
315
+ handler: (row) => handleView(row),
316
+ },
317
+ {
318
+ label: '编辑',
319
+ type: 'warning',
320
+ link: true,
321
+ icon: Edit,
322
+ handler: (row) => handleEdit(row),
323
+ },
324
+ {
325
+ label: '删除',
326
+ type: 'danger',
327
+ link: true,
328
+ icon: Delete,
329
+ show: true,
330
+ disabled: (row) => row.status === 0, // 业务时不展示
331
+ handler: (row) => handleDelete(row),
332
+ },
333
+ ],
334
+ },
335
+ ])
336
+
337
+ // ==================== 工具方法 ====================
338
+ const getStatusType = (status) => {
339
+ return status === 1 ? 'success' : 'danger'
340
+ }
341
+
342
+ const getStatusText = (status) => {
343
+ return status === 1 ? '启用' : '禁用'
344
+ }
345
+
346
+ const getDepartmentText = (department) => {
347
+ const departmentOptions = [
348
+ { label: '技术部', value: 'tech' },
349
+ { label: '产品部', value: 'product' },
350
+ { label: '运营部', value: 'operation' },
351
+ { label: '人力资源部', value: 'hr' },
352
+ { label: '财务部', value: 'finance' },
353
+ ]
354
+ const dept = departmentOptions.find((d) => d.value === department)
355
+ return dept ? dept.label : department
356
+ }
357
+
358
+ // ==================== 数据加载 ====================
359
+ const loadData = async () => {
360
+ loading.value = true
361
+ try {
362
+ // 模拟网络延迟
363
+ await new Promise((resolve) => setTimeout(resolve, 500))
364
+
365
+ // 从组件获取分页信息(使用自定义 key)
366
+ // getPagination() 返回的对象会根据 page-number-key 和 page-size-key 配置使用对应的 key
367
+ // 例如:{ total1: 0, currentPage1: 1, pageSize1: 10 }
368
+ const pagination = containerRef.value?.getPagination() || {
369
+ currentPage1: 1,
370
+ pageSize1: 10,
371
+ }
372
+
373
+ // 使用 filterUsers 进行过滤和分页
374
+ // 直接传入 pagination 对象,filterUsers 会根据 keyConfig 解析对应的值
375
+ const result = filterUsers(mockUsers, searchParams.value, pagination, {
376
+ pageNumberKey: 'currentPage1',
377
+ pageSizeKey: 'pageSize1',
378
+ })
379
+
380
+ // 更新数据
381
+ tableData.value = result.list
382
+ total.value = result.total
383
+ } catch (error) {
384
+ console.error('加载数据失败:', error)
385
+ ElMessage.error('加载数据失败')
386
+ } finally {
387
+ loading.value = false
388
+ }
389
+ }
390
+
391
+ // ==================== 事件处理 ====================
392
+ // 搜索
393
+ const handleSearch = (params) => {
394
+ // 更新搜索参数
395
+ searchParams.value = { ...params }
396
+ loadData()
397
+ }
398
+
399
+ // 重置
400
+ const handleReset = () => {
401
+ // 重置搜索参数
402
+ // searchParams.value = {};
403
+ console.log('表单已重置,数据已刷新')
404
+ }
405
+
406
+ // 选择变化
407
+ const handleSelectionChange = (selection) => {
408
+ console.log('选中的数据:', selection)
409
+ }
410
+
411
+ // ==================== 选择列操作方法 ====================
412
+ const getSelectedRows = () => {
413
+ if (!containerRef.value) return
414
+ const selectedRows = containerRef.value.getSelectionRows()
415
+ ElMessage.success(
416
+ `选中了 ${selectedRows.length} 行数据:${selectedRows.map((r) => r.username).join(', ')}`,
417
+ )
418
+ console.log('选中的行数据:', selectedRows)
419
+ }
420
+
421
+ const getSelectedKeys = () => {
422
+ if (!containerRef.value) return
423
+ const selectedKeys = containerRef.value.getSelectionKeys()
424
+ ElMessage.success(`选中了 ${selectedKeys.length} 个ID:${selectedKeys.join(', ')}`)
425
+ console.log('选中的ID:', selectedKeys)
426
+ }
427
+
428
+ const selectRows = (ids) => {
429
+ if (!containerRef.value) return
430
+
431
+ try {
432
+ // 设置选择
433
+ containerRef.value.setSelectionKeys(ids)
434
+
435
+ // 延迟检查选择结果
436
+ const selectedRows = containerRef.value.getSelectionRows()
437
+ const selectedKeys = containerRef.value.getSelectionKeys()
438
+
439
+ if (selectedRows.length > 0) {
440
+ ElMessage.success(`已选中ID为 ${ids.join(', ')} 的行,实际选中:${selectedKeys.join(', ')}`)
441
+ } else {
442
+ ElMessage.warning(`未选中任何行,请检查数据是否正确`)
443
+ }
444
+ } catch (error) {
445
+ console.error('选择出错:', error)
446
+ ElMessage.error(`选择失败:${error.message}`)
447
+ }
448
+ }
449
+
450
+ const clearSelection = () => {
451
+ if (!containerRef.value) return
452
+ containerRef.value.clearAllSelection()
453
+ ElMessage.success('已清空所有选择')
454
+ }
455
+
456
+ const selectAll = () => {
457
+ if (!containerRef.value) return
458
+ containerRef.value.selectAll()
459
+ ElMessage.success('已全选所有行')
460
+ }
461
+
462
+ const checkSelection = () => {
463
+ if (!containerRef.value) return
464
+
465
+ // 检查特定行是否被选中
466
+ const isRow1Selected = containerRef.value.isRowSelected(tableData.value[0])
467
+ const isKey3Selected = containerRef.value.isKeySelected(3)
468
+
469
+ ElMessage.info(
470
+ `第一行是否选中:${isRow1Selected ? '是' : '否'},ID为3是否选中:${
471
+ isKey3Selected ? '是' : '否'
472
+ }`,
473
+ )
474
+ }
475
+
476
+ // 新增
477
+ const handleAdd = () => {
478
+ ElMessage.success('新增')
479
+ }
480
+
481
+ // 查看
482
+ const handleView = (row) => {
483
+ ElMessage.success(`查看:${row.username}`)
484
+ }
485
+
486
+ // 编辑
487
+ const handleEdit = (row) => {
488
+ ElMessage.success(`编辑:${row.username}`)
489
+ }
490
+
491
+ // 删除
492
+ const handleDelete = (row) => {
493
+ ElMessageBox.confirm(`确定要删除用户 "${row.username}" 吗?`, '删除确认', {
494
+ confirmButtonText: '确定',
495
+ cancelButtonText: '取消',
496
+ type: 'warning',
497
+ }).then(() => {
498
+ // 模拟删除
499
+ ElMessage.success('删除成功')
500
+ loadData()
501
+ })
502
+ }
503
+
504
+ // ==================== 生命周期 ====================
505
+ onMounted(async () => {
506
+ // 异步获取状态选项(模拟接口请求,延迟2秒)
507
+ const options = await fetchStatusOptions()
508
+ searchItems.value[2].children = options
509
+
510
+ // 异步获取部门选项(模拟接口请求,延迟2秒)
511
+ const departmentOptions = await fetchDepartmentOptions()
512
+ searchItems.value[3].children = departmentOptions
513
+
514
+ // 搜索条件准备好后,调用 initSearchAndLoad 初始化搜索参数并加载数据
515
+ // 这会自动获取 PageSearch 的初始表单数据(包含默认值和外部参数)
516
+ containerRef.value?.initSearchAndLoad()
517
+ })
518
+ </script>
519
+
520
+ <style scoped>
521
+ .demo-page {
522
+ height: 100%;
523
+ padding: 20px;
524
+ background: #f5f7fa;
525
+ display: flex;
526
+ flex-direction: column;
527
+ }
528
+
529
+ :deep(.el-dialog__body) {
530
+ padding: 20px;
531
+ }
532
+
533
+ .selection-actions {
534
+ margin-top: 20px;
535
+ padding: 20px;
536
+ background: #f5f7fa;
537
+ border-radius: 4px;
538
+ display: flex;
539
+ gap: 10px;
540
+ flex-wrap: wrap;
541
+ }
542
+
543
+ .debug-content {
544
+ padding: 0 20px;
545
+ }
546
+
547
+ .debug-item {
548
+ margin-bottom: 24px;
549
+ }
550
+
551
+ .debug-label {
552
+ display: block;
553
+ font-weight: 600;
554
+ color: #303133;
555
+ margin-bottom: 8px;
556
+ font-size: 14px;
557
+ }
558
+
559
+ .debug-value {
560
+ background: #f5f7fa;
561
+ padding: 12px;
562
+ border-radius: 4px;
563
+ font-size: 13px;
564
+ color: #606266;
565
+ margin: 0;
566
+ white-space: pre-wrap;
567
+ word-wrap: break-word;
568
+ border: 1px solid #e4e7ed;
569
+ }
570
+ </style>