vue2-components-plus 1.0.28 → 1.0.31

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,546 +0,0 @@
1
- <template>
2
- <div class="table-demo">
3
- <el-card shadow="never" class="table-demo__mode-card">
4
- <div class="table-demo__mode-header">
5
- <div>
6
- <div class="table-demo__mode-title">分页模式演示(&lt;script setup&gt; 版)</div>
7
- <div class="table-demo__mode-desc">
8
- {{ paginationMode === 'frontend' ? '一次加载全部筛选结果,再在本地完成翻页。' : '每次切页都会按当前页码重新请求模拟数据。' }}
9
- </div>
10
- </div>
11
- <el-radio-group v-model="paginationMode" size="small" @change="handlePaginationModeChange">
12
- <el-radio-button label="backend">后端分页</el-radio-button>
13
- <el-radio-button label="frontend">前端分页</el-radio-button>
14
- </el-radio-group>
15
- </div>
16
- </el-card>
17
-
18
- <NsTableContainer
19
- ref="containerRef"
20
- class="table-demo__container"
21
- page-number-key="currentPage1"
22
- page-size-key="pageSize1"
23
- page-total-key="total1"
24
- :search-items="searchItems"
25
- :external-search-params="externalSearchParams"
26
- :search-props="searchProps"
27
- :table-data="tableData"
28
- :columns="columns"
29
- :total="total"
30
- :table-props="mergedTableProps"
31
- :load-data="loadData"
32
- @search="handleSearch"
33
- @reset="handleReset"
34
- @add="handleAdd"
35
- @selection-change="handleSelectionChange"
36
- >
37
- <template v-slot:status="{ row }">
38
- <el-tag size="small" :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag>
39
- </template>
40
-
41
- <template v-slot:gender="{ row }">
42
- <el-tag size="small" :type="row.gender === 1 ? 'primary' : 'danger'">
43
- {{ row.gender === 1 ? '男' : '女' }}
44
- </el-tag>
45
- </template>
46
-
47
- <template v-slot:department="{ row }">
48
- <el-tag size="small" effect="plain">{{ getDepartmentText(row.department) }}</el-tag>
49
- </template>
50
-
51
- <template v-slot:delete-action="{ row }">
52
- <el-button
53
- type="text"
54
- style="color: #f56c6c"
55
- :disabled="row.status === 0"
56
- @click="handleDelete(row)"
57
- >
58
- 删除
59
- </el-button>
60
- </template>
61
- </NsTableContainer>
62
-
63
- <el-card shadow="never" class="table-demo__actions">
64
- <template v-slot:header>选择能力演示</template>
65
- <div class="table-demo__action-list">
66
- <el-button @click="getSelectedRows">获取选中行</el-button>
67
- <el-button @click="getSelectedKeys">获取选中 ID</el-button>
68
- <el-button @click="selectRows([3,7])">选中 ID 为 3 / 7 的行</el-button>
69
- <el-button @click="clearSelection">清空选择</el-button>
70
- <el-button @click="selectAll">全选当前页</el-button>
71
- <el-button @click="checkSelection">检查选择状态</el-button>
72
- </div>
73
- </el-card>
74
- </div>
75
- </template>
76
-
77
- <script setup>
78
- import { computed, getCurrentInstance, nextTick, onMounted, ref } from 'vue'
79
- import { departmentOptions, fetchDepartmentOptions, fetchStatusOptions, filterUsers, mockUsers } from './mockData'
80
-
81
- function createSearchItems() {
82
- return [
83
- {
84
- prop: 'month',
85
- label: '归属月',
86
- span: 6,
87
- component: 'ElSelect',
88
- attrs: {
89
- placeholder: '请选择归属月',
90
- clearable: true,
91
- },
92
- children: Array.from({ length: 12 }, function (_, index) {
93
- return {
94
- label: index + 1 + '月',
95
- value: String(index + 1),
96
- }
97
- }),
98
- },
99
- {
100
- prop: 'username',
101
- label: '用户名',
102
- span: 6,
103
- component: 'ElInput',
104
- attrs: {
105
- placeholder: '请输入用户名',
106
- clearable: true,
107
- },
108
- events: {},
109
- },
110
- {
111
- prop: 'realName',
112
- label: '真实姓名',
113
- span: 6,
114
- component: 'ElInput',
115
- attrs: {
116
- placeholder: '请输入真实姓名',
117
- clearable: true,
118
- },
119
- },
120
- {
121
- prop: 'status',
122
- label: '状态',
123
- span: 6,
124
- component: 'ElSelect',
125
- attrs: {
126
- placeholder: '请选择状态',
127
- clearable: true,
128
- },
129
- children: [],
130
- },
131
- {
132
- prop: 'department',
133
- label: '部门',
134
- span: 6,
135
- component: 'ElSelect',
136
- attrs: {
137
- placeholder: '请选择部门',
138
- clearable: true,
139
- filterable: true,
140
- },
141
- children: [],
142
- },
143
- {
144
- prop: 'gender',
145
- label: '性别',
146
- span: 6,
147
- component: 'ElSelect',
148
- attrs: {
149
- placeholder: '请选择性别',
150
- clearable: true,
151
- },
152
- children: [
153
- { label: '全部', value: '' },
154
- { label: '男', value: 1 },
155
- { label: '女', value: 2 },
156
- ],
157
- },
158
- {
159
- prop: 'createTime',
160
- label: '创建时间',
161
- span: 6,
162
- component: 'ElDatePicker',
163
- attrs: {
164
- type: 'daterange',
165
- clearable: true,
166
- rangeSeparator: '至',
167
- startPlaceholder: '开始日期',
168
- endPlaceholder: '结束日期',
169
- valueFormat: 'yyyy-MM-dd',
170
- },
171
- },
172
- {
173
- prop: 'phone',
174
- label: '手机号',
175
- span: 6,
176
- component: 'ElInput',
177
- attrs: {
178
- placeholder: '请输入手机号',
179
- clearable: true,
180
- },
181
- },
182
- {
183
- prop: 'active',
184
- label: '是否激活',
185
- span: 6,
186
- component: 'ElSwitch',
187
- attrs: {
188
- activeText: '是',
189
- inactiveText: '否',
190
- },
191
- defaultValue: true,
192
- },
193
- ]
194
- }
195
-
196
- function createColumns(context) {
197
- return [
198
- {
199
- prop: 'id',
200
- label: 'ID',
201
- sortable: true,
202
- },
203
- {
204
- label: '基本信息',
205
- children: [
206
- {
207
- prop: 'username',
208
- label: '用户名',
209
- width: 130,
210
- formatter: function (row, _column, cellValue) {
211
- return cellValue ? '@' + cellValue : '-'
212
- },
213
- },
214
- {
215
- prop: 'realName',
216
- label: '真实姓名',
217
- width: 120,
218
- },
219
- {
220
- prop: 'gender',
221
- label: '性别',
222
- width: 90,
223
- slot: 'gender',
224
- },
225
- ],
226
- },
227
- {
228
- label: '组织信息',
229
- children: [
230
- {
231
- prop: 'department',
232
- label: '部门',
233
- width: 120,
234
- slot: 'department',
235
- },
236
- {
237
- prop: 'status',
238
- label: '状态',
239
- width: 100,
240
- slot: 'status',
241
- },
242
- ],
243
- },
244
- {
245
- label: '联系方式',
246
- children: [
247
- {
248
- prop: 'phone',
249
- label: '手机号',
250
- width: 140,
251
- },
252
- {
253
- prop: 'email',
254
- label: '邮箱',
255
- minWidth: 220,
256
- },
257
- ],
258
- },
259
- {
260
- prop: 'createTime',
261
- label: '创建时间',
262
- width: 180,
263
- sortable: true,
264
- },
265
- {
266
- type: 'action',
267
- label: '操作',
268
- width: 260,
269
- fixed: 'right',
270
- buttons: [
271
- {
272
- label: '查看',
273
- type: 'text',
274
- icon: 'el-icon-view',
275
- handler: function (row) {
276
- context.handleView(row)
277
- },
278
- },
279
- {
280
- label: '编辑',
281
- type: 'text',
282
- icon: 'el-icon-edit',
283
- handler: function (row) {
284
- context.handleEdit(row)
285
- },
286
- },
287
- {
288
- label: '删除',
289
- type: 'text',
290
- icon: 'el-icon-delete',
291
- slot: 'delete-action',
292
- },
293
- ],
294
- },
295
- ]
296
- }
297
-
298
- const containerRef = ref()
299
- const loading = ref(false)
300
- const total = ref(0)
301
- const tableData = ref([])
302
- const searchParams = ref({})
303
- const paginationMode = ref('backend')
304
- const mockUserCount = mockUsers.length
305
- const externalSearchParams = { source: 'vue2-demo' }
306
- const searchProps = { labelWidth: '90px' }
307
- const searchItems = ref(createSearchItems())
308
- const columns = ref([])
309
- const { proxy } = getCurrentInstance() || {}
310
-
311
- const mergedTableProps = ref({
312
- showSelection: true,
313
- showIndex: true,
314
- loading: loading.value,
315
- rowKey: 'id',
316
- showPagination: true,
317
- pageSizes: [5, 10, 20],
318
- stripe: true,
319
- border: true
320
- })
321
-
322
- function handleKeywordEnter(event) {
323
- if (event && event.key === 'Enter') {
324
- handleSearch(containerRef.value ? containerRef.value.getSearchFormData() : {})
325
- }
326
- }
327
-
328
- function getStatusType(status) {
329
- return status === 1 ? 'success' : 'danger'
330
- }
331
-
332
- function getStatusText(status) {
333
- return status === 1 ? '启用' : '禁用'
334
- }
335
-
336
- function getDepartmentText(value) {
337
- const matched = departmentOptions.find(function (item) {
338
- return item.value === value
339
- })
340
- return matched ? matched.label : value
341
- }
342
-
343
- function getCurrentPagination() {
344
- return containerRef.value && containerRef.value.getPagination
345
- ? containerRef.value.getPagination()
346
- : { currentPage1: 1, pageSize1: 10 }
347
- }
348
-
349
- function paginateList(list, pagination) {
350
- const currentPage = Number(pagination.currentPage1 || 1)
351
- const pageSize = Number(pagination.pageSize1 || 10)
352
- const start = (currentPage - 1) * pageSize
353
- return (list || []).slice(start, start + pageSize)
354
- }
355
-
356
- function resetContainerPage() {
357
- if (containerRef.value && containerRef.value.internalPagination) {
358
- containerRef.value.internalPagination.currentPage = 1
359
- }
360
- }
361
-
362
- function handlePaginationModeChange() {
363
- if (containerRef.value) {
364
- containerRef.value.clearAllSelection()
365
- }
366
- resetContainerPage()
367
- loadData()
368
- proxy.$message.success('已切换为' + (paginationMode.value === 'frontend' ? '前端分页' : '后端分页'))
369
- }
370
-
371
- async function loadData() {
372
- loading.value = true
373
- try {
374
- await new Promise(function (resolve) {
375
- setTimeout(resolve, 300)
376
- })
377
- const pagination = getCurrentPagination()
378
- const pageConfig = {
379
- pageNumberKey: 'currentPage1',
380
- pageSizeKey: 'pageSize1',
381
- }
382
- if (paginationMode.value === 'frontend') {
383
- const result = filterUsers(
384
- mockUsers,
385
- searchParams.value,
386
- { currentPage1: 1, pageSize1: mockUserCount || 10 },
387
- pageConfig,
388
- )
389
- tableData.value = paginateList(result.list, pagination)
390
- total.value = result.total
391
- return
392
- }
393
- const result = filterUsers(mockUsers, searchParams.value, pagination, pageConfig)
394
- tableData.value = result.list
395
- total.value = result.total
396
- } catch (error) {
397
- console.error(error)
398
- proxy.$message.error('加载表格数据失败')
399
- } finally {
400
- loading.value = false
401
- }
402
- }
403
-
404
- function handleSearch(params) {
405
- searchParams.value = Object.assign({}, params)
406
- loadData()
407
- }
408
-
409
- function handleReset() {
410
- proxy.$message.info('搜索条件已重置')
411
- }
412
-
413
- function handleSelectionChange(selection) {
414
- console.log('选中切换', selection)
415
- if (!selection) return
416
- }
417
-
418
- function getSelectedRows() {
419
- const rows = containerRef.value ? containerRef.value.getSelectionRows() : []
420
- proxy.$alert(JSON.stringify(rows, null, 2), '当前选中行', {
421
- confirmButtonText: '知道了',
422
- })
423
- }
424
-
425
- function getSelectedKeys() {
426
- const keys = containerRef.value ? containerRef.value.getSelectionKeys() : []
427
- proxy.$message.success('当前选中 ID:' + (keys.length ? keys.join(', ') : '无'))
428
- }
429
-
430
- function selectRows(ids) {
431
- if (!containerRef.value) return
432
- containerRef.value.setSelectionKeys(ids)
433
- proxy.$message.success('已尝试选中 ID:' + ids.join(', '))
434
- }
435
-
436
- function clearSelection() {
437
- if (!containerRef.value) return
438
- containerRef.value.clearAllSelection()
439
- proxy.$message.success('已清空选中状态')
440
- }
441
-
442
- function selectAll() {
443
- if (!containerRef.value) return
444
- containerRef.value.selectAll()
445
- proxy.$message.success('已全选当前页')
446
- }
447
-
448
- function checkSelection() {
449
- if (!containerRef.value || !tableData.value.length) return
450
- const firstSelected = containerRef.value.isRowSelected(tableData.value[0])
451
- const keySelected = containerRef.value.isKeySelected(3)
452
- proxy.$message.info('第一行选中:' + (firstSelected ? '是' : '否') + ';ID=3 选中:' + (keySelected ? '是' : '否'))
453
- }
454
-
455
- function handleAdd() {
456
- proxy.$message.success('点击了新增按钮')
457
- }
458
-
459
- function handleView(row) {
460
- proxy.$message.info('查看:' + row.username)
461
- }
462
-
463
- function handleEdit(row) {
464
- proxy.$message.success('编辑:' + row.username)
465
- }
466
-
467
- function handleDelete(row) {
468
- if (row.status === 0) {
469
- proxy.$message.warning('禁用状态用户不可删除')
470
- return
471
- }
472
- proxy.$confirm('确认删除用户“' + row.username + '”吗?', '提示', {
473
- type: 'warning',
474
- })
475
- .then(() => {
476
- proxy.$message.success('已模拟删除:' + row.username)
477
- loadData()
478
- })
479
- .catch(function () {})
480
- }
481
-
482
- columns.value = createColumns({ handleView, handleEdit, handleDelete })
483
- searchItems.value[1].events.keyup = handleKeywordEnter
484
-
485
- onMounted(async () => {
486
- const statusOptions = await fetchStatusOptions()
487
- const departmentList = await fetchDepartmentOptions()
488
- searchItems.value[3].children = statusOptions
489
- searchItems.value[4].children = departmentList
490
- await nextTick()
491
- if (containerRef.value) {
492
- containerRef.value.initSearchAndLoad()
493
- }
494
- })
495
- </script>
496
-
497
- <style scoped>
498
- .table-demo {
499
- display: flex;
500
- flex-direction: column;
501
- gap: 20px;
502
- height: 100%;
503
- min-height: 0;
504
- }
505
-
506
- .table-demo__container {
507
- flex: 1;
508
- min-height: 0;
509
- }
510
-
511
- .table-demo__mode-card,
512
- .table-demo__actions {
513
- border-radius: 12px;
514
- }
515
-
516
- .table-demo__mode-header {
517
- display: flex;
518
- align-items: center;
519
- justify-content: space-between;
520
- gap: 16px;
521
- flex-wrap: wrap;
522
- }
523
-
524
- .table-demo__mode-title {
525
- font-size: 16px;
526
- font-weight: 600;
527
- color: #303133;
528
- }
529
-
530
- .table-demo__mode-tip {
531
- margin-top: 6px;
532
- color: #606266;
533
- }
534
-
535
- .table-demo__mode-desc {
536
- margin-top: 4px;
537
- font-size: 13px;
538
- color: #909399;
539
- }
540
-
541
- .table-demo__action-list {
542
- display: flex;
543
- flex-wrap: wrap;
544
- gap: 12px;
545
- }
546
- </style>