el-plus-crud 0.0.78 → 0.0.80

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,807 +1,744 @@
1
- <template>
2
- <div class="el-plus-table-content">
3
- <!-- <div class="select-items" v-if="type === 'selection' && selectRowList && selectRowList.length > 0">
4
- <span class="title">已选择({{ selectRowList.length }}个): </span>
5
- <el-tag v-for="(item, i) in selectRowList" :key="item.id" class="select-item" size="small" closable @close="() => handelRemoveSelect(i, item)">
6
- {{ item[tableConfig.showSelectNameKey || 'name'] }}
7
- </el-tag>
8
- </div> -->
9
- <EleTabletHeader ref="tableHeaderRef" v-if="Object.keys(tableConfig?.toolbar || {}).length || tableConfig.tbName" v-model="toolFormData" :tbName="tableConfig.tbName" :column="tableConfig.column" :size="size" :isShowRefresh="isShowRefresh" :loading="loading" :toolbar="tableConfig.toolbar" :isDialog="isDialog" @query="handelTopQuery" />
10
-
11
- <!-- 中部的Tabs -->
12
- <div class="table-tabs-panel" v-if="tableConfig.tabConf">
13
- <el-radio-group v-model="tableTabVal" size="default" @change="handelTabChange">
14
- <el-radio-button v-for="(item, i) in tableConfig.tabConf?.tabs" :key="i" :label="item.value" :loading="true">
15
- {{ item.label }}
16
- <template v-if="loadingTab">
17
- <el-icon class="is-loading"><Loading /></el-icon>
18
- </template>
19
- <template v-else>
20
- {{ getTabLabel(item) }}
21
- </template>
22
- </el-radio-button>
23
- </el-radio-group>
24
- </div>
25
-
26
- <!-- 中间列表 -->
27
- <div class="el-plus-table-main" v-loading="loading">
28
- <template v-if="isDIYMain">
29
- <slot name="main" :tableData="tableData"></slot>
30
- </template>
31
- <!-- 这里开始是表格内容 -->
32
- <el-table ref="elPlusTableRef" v-else style="width: 100%" height="100%" :maxHeight="tableConfig.maxHeight || 'auto'" v-bind="tableConfig.tableAttr" :class="{ 'big-h-bar': tableConfig?.tableAttr?.bigHBar, 'big-v-bar': tableConfig.tableAttr?.bigVBar }" :data="tableData" :row-key="rowKey" lazy :load="loadExpandData" :size="size" :row-class-name="initRowClassName" @select="handelTableSelect" @select-all="handelTableSelectAll" @expand-change="handelTableExpandChange" :treeProps="treeProps">
33
- <!-- 复选框 -->
34
- <el-table-column v-if="type === 'selection'" type="selection" width="55px" :selectable="selectable" header-align="center" align="center" />
35
- <!-- 下标 -->
36
- <el-table-column v-if="isIndex" type="index" width="60" label="序号" />
37
- <!-- 首列 -->
38
- <template v-if="useSlots().firstColumn">
39
- <slot name="firstColumn" />
40
- </template>
41
- <template v-for="(item, i) in headerColumns" :key="item.prop + item.label + i">
42
- <!-- 二级表头 -->
43
- <template v-if="item.children && item.children.length > 0">
44
- <el-table-column v-if="columnShowList[i]?.some((t: boolean) => t)" :prop="item.label" :label="item.label" header-align="center">
45
- <template v-for="(item2, j) in item.children" :key="item2.label + i + j">
46
- <el-table-column :prop="item2.prop" v-if="columnShowList[i][j]" v-bind="item2">
47
- <template #header>
48
- <div :class="{ 'th-required': item2.required }">
49
- {{ item2.label }}
50
- </div>
51
- </template>
52
- <template #default="scope: any">
53
- <slot name="default"></slot>
54
- <ColumnItem v-if="scope.$index >= 0" :field="item2.prop" :desc="item2" :scope="scope" :size="size" v-model="scope.row[item2.prop]" />
55
- </template>
56
- </el-table-column>
57
- </template>
58
- </el-table-column>
59
- </template>
60
- <!-- 单级表头 -->
61
- <template v-else>
62
- <el-table-column v-if="columnShowList[i]" :prop="item.prop" v-bind="item">
63
- <template #header="{ column }: any">
64
- <div :class="{ 'th-required': item.required }" :style="item.hstyle">
65
- {{ column.label }}
66
- </div>
67
- </template>
68
- <template #default="scope: any">
69
- <ColumnItem v-if="scope.$index >= 0" :field="item.prop" :desc="item" :scope="scope" :size="size" v-model="scope.row[item.prop]" />
70
- </template>
71
- </el-table-column>
72
- </template>
73
- </template>
74
- <template v-if="!loading && loadingStatus === 2" #empty>
75
- <el-empty v-if="isEmptyImg" :description="nullText" />
76
- <span v-else>{{ nullText }}</span>
77
- </template>
78
- <!-- 合计行 -->
79
- <template v-if="tableConfig.summaryConf?.prop" #append>
80
- <div :style="tableConfig.summaryConf?.hstyle" class="summary-row" v-if="summaryList && summaryList.length > 0">
81
- <div class="summary-item" v-for="(item, i) in summaryList" :key="i">
82
- <span>{{ item.label || '合计' }}:</span>
83
- <p>{{ item.value || 0 }}</p>
84
- </div>
85
- </div>
86
- </template>
87
- </el-table>
88
- </div>
89
- <div class="bottom-page-static-info" v-if="isPager || tableConfig.statistic">
90
- <el-pagination class="page-info" small @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="+pageInfo.current" :page-sizes="[5, 10, 20, 50, 100]" :page-size="pageInfo.size" layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total" />
91
- </div>
92
- <slot name="bottom"></slot>
93
- </div>
94
- </template>
95
- <script lang="ts">
96
- export default {
97
- name: 'ElPlusTable',
98
- inheritAttrs: false,
99
- customOptions: {}
100
- }
101
- </script>
102
- <script lang="ts" setup>
103
- import { ref, reactive, onMounted, computed, watch, nextTick, useSlots, inject } from 'vue'
104
- import EleTabletHeader from './components/header.vue'
105
- import ColumnItem from './components/columnItem.vue'
106
- import { handelListColumn } from './util'
107
- import { cloneDeep } from 'lodash'
108
- import { Loading } from '@element-plus/icons-vue'
109
- import { ICRUDConfig, ITableConfig, ITableTabItem, ITreeProps } from 'types'
110
-
111
- const defaultConf = inject('defaultConf') as ICRUDConfig
112
- const format = inject('format') as any
113
-
114
- const emits = defineEmits(['getUrlConsumerIds', 'selection', 'select', 'selectAll', 'update:modelValue', 'tabChange', 'expandChange'])
115
- const props = withDefaults(
116
- defineProps<{
117
- tableConfig: ITableConfig
118
- // 外部数据
119
- modelValue?: Array<any> | null
120
- // 列表类型 默认为index
121
- type?: string
122
- // 是否显示第一列的Index下标
123
- isIndex?: boolean
124
- // 是否分页
125
- isPager?: boolean
126
- // 每页显示条数
127
- pageSize?: number
128
- // 是否在弹框中
129
- isDialog?: boolean
130
- // 空占位文本
131
- nullText?: string
132
- // 是否显示暂无数据的图片
133
- isEmptyImg?: boolean
134
- // 是否显示刷新文本
135
- isShowRefresh?: boolean
136
- // rowKey默认为id
137
- rowKey?: string
138
- // 自定义table主体
139
- isDIYMain?: boolean
140
- // 默认选中项
141
- selectList?: Array<any> | []
142
- // 默认列宽
143
- colMinWidth?: string
144
- }>(),
145
- {
146
- modelValue: null,
147
- type: 'index',
148
- isIndex: true,
149
- isPager: true,
150
- pageSize: 10,
151
- isDialog: false,
152
- nullText: '暂无数据',
153
- isShowRefresh: true,
154
- rowKey: 'id',
155
- isEmptyImg: true,
156
- isDIYMain: false,
157
- selectList: () => [],
158
- colMinWidth: 'auto'
159
- }
160
- )
161
-
162
- const elPlusTableRef = ref()
163
-
164
- // 顶部Tab数据
165
- const tableTabVal = ref(props.tableConfig?.tabConf?.tabs[props.tableConfig?.tabConf?.default || 0].value ?? '')
166
- const tabStatic = ref({} as any)
167
- const getTabLabel = computed(() => (item: ITableTabItem) => {
168
- if (item.key) {
169
- return tabStatic.value[item.key] || 0
170
- }
171
- return ''
172
- })
173
-
174
- const selectable = computed(() => (row: any, index: number) => {
175
- if (typeof props.tableConfig?.tableAttr?.selectable === 'function') {
176
- return props.tableConfig?.tableAttr?.selectable(row, index)
177
- }
178
- return true
179
- })
180
-
181
- const tableHeaderRef = ref()
182
-
183
- // 加载
184
- const loading = ref(false)
185
- const loadingTab = ref(!!props.tableConfig?.tabConf?.fetch)
186
- const listLoading = ref(false)
187
- const size = defaultConf.size || 'small'
188
-
189
- // 顶部查询条件数据缓存
190
- const topQueryData = ref({} as any)
191
-
192
- // 数据
193
- let toolFormData = reactive({} as any)
194
- const tableData = reactive((props.modelValue || []) as any[])
195
- const haveClassRowList = reactive([])
196
-
197
- // 初始化表头
198
- const headerColumns = reactive(handelListColumn(props.tableConfig?.column, props.isDialog ? 'auto' : props.colMinWidth))
199
-
200
- // 0:未加载; 1:加载中;2:加载完成
201
- const loadingStatus = ref(0)
202
-
203
- // 保存所有的选中行
204
- const allSelectRowList = reactive((cloneDeep(props.selectList) || []) as any[])
205
- // 记录树形展开的数组的下标
206
- const treeIndexList = reactive([] as any[][])
207
-
208
- // 分页信息
209
- const pageInfo = reactive({
210
- current: !props.isDialog && toolFormData.current ? parseInt(toolFormData.current as any) : 1,
211
- total: 0,
212
- size: !props.isDialog && toolFormData.size ? parseInt(toolFormData.size as any) : props.pageSize
213
- })
214
- // 数型解析
215
- const treeProps = (props.tableConfig?.explan?.treeProps || { children: 'children', hasChildren: 'hasChildren' }) as ITreeProps
216
-
217
- // 列的显示
218
- const columnShowList = computed(() => {
219
- return handelVIfList(handelListColumn(props.tableConfig?.column, props.isDialog ? 'auto' : props.colMinWidth))
220
- })
221
-
222
- // 合计行数据
223
- const summaryList = computed(() => {
224
- const tempList = [] as any[]
225
- if (props.tableConfig.summaryConf?.vif) {
226
- if (typeof props.tableConfig.summaryConf?.vif === 'boolean') {
227
- if (!props.tableConfig.summaryConf?.vif) {
228
- return tempList
229
- }
230
- } else {
231
- if (!props.tableConfig.summaryConf?.vif()) {
232
- return tempList
233
- }
234
- }
235
- }
236
- if (props.tableConfig.summaryConf?.prop) {
237
- const propList = props.tableConfig.summaryConf.prop.split(',')
238
- const labelList = props.tableConfig.summaryConf?.label?.split(',') || []
239
- // 遍历
240
- propList.map((prop, i: number) => {
241
- let value = ''
242
- if (props.tableConfig.summaryConf?.sumFn) {
243
- value = props.tableConfig.summaryConf?.sumFn(tableData, allSelectRowList)
244
- } else {
245
- value = format.yuan(tableData.reduce((total: number, current) => (total += current[prop]), 0))
246
- }
247
- tempList.push({ label: labelList[i], value })
248
- })
249
- }
250
- return tempList
251
- })
252
-
253
- /**
254
- * 处理列表的vif
255
- * @param list
256
- */
257
- function handelVIfList(list: any[]): any[] {
258
- return list.map((item) => {
259
- if (item.children) {
260
- return handelVIfList(item.children)
261
- }
262
- if (props.tableConfig.tbName) {
263
- return item._vif && item.scShow
264
- } else {
265
- // 这里初始化一下vif
266
- if (item.vif !== undefined && item.vif !== null) {
267
- if (typeof item.vif === 'function') {
268
- item._vif = item.vif(item)
269
- } else {
270
- item._vif = !!item.vif
271
- }
272
- } else {
273
- item._vif = true
274
- }
275
- // 这里最终处理一下auth权限问题
276
- if (item.auth) {
277
- if (!defaultConf.auth) {
278
- console.warn('使用auth属性,请在crud注册时传入auth校验方法~')
279
- } else {
280
- item._vif = defaultConf.auth(item.auth)
281
- }
282
- }
283
- return item._vif
284
- }
285
- })
286
- }
287
-
288
- /**
289
- * Tab切换
290
- * @param val
291
- */
292
- async function handelTabChange(val: string | number | boolean) {
293
- // 这里直接重新查询
294
- reload(true)
295
-
296
- // 通知父类 第二个参数是回调
297
- await emits('tabChange', val, initCol)
298
-
299
- // 这里触发下initCol
300
- nextTick(() => {
301
- initCol()
302
- })
303
- }
304
-
305
- /**
306
- * 加载自身展开的数据
307
- * @param row
308
- * @param treeNode
309
- * @param resolve
310
- */
311
- function loadExpandData(row: any, treeNode: any, resolve: any) {
312
- const postData = getListQueryData()
313
- postData[props.tableConfig?.explan?.idName || 'parentId'] = row.id
314
- props.tableConfig.fetch &&
315
- props.tableConfig.fetch(postData).then((pageInfo) => {
316
- resolve(pageInfo?.records)
317
- })
318
- }
319
-
320
- /**
321
- * 初始化每行的颜色
322
- * @param data
323
- */
324
- function initRowClassName(data: any) {
325
- if (haveClassRowList.length > data.rowIndex) {
326
- return haveClassRowList[data.rowIndex * 1]
327
- }
328
- return ''
329
- }
330
-
331
- /**
332
- * 处理单个选中的情况
333
- * @param selection
334
- * @param row
335
- */
336
- function handelTableSelect(selection: any[], item: any) {
337
- checkAndRemove(item, !selection.some((i) => i[props.rowKey] === item[props.rowKey]))
338
- // 通知父类
339
- emits('select', selection, item)
340
- emits('selection', cloneDeep(allSelectRowList))
341
- }
342
-
343
- /**
344
- * 处理全选
345
- * @param selection
346
- * @param row
347
- */
348
- function handelTableSelectAll(selection: any[]) {
349
- const isRemove = !(selection && selection.length > 0)
350
- ;(isRemove ? tableData : selection).map((item) => {
351
- checkAndRemove(item, isRemove)
352
- })
353
- // 通知父类
354
- emits('selectAll', selection, isRemove)
355
- emits('selection', cloneDeep(allSelectRowList))
356
- }
357
-
358
- /**
359
- * 处理行展开
360
- * @param row
361
- * @param expanded
362
- */
363
- function handelTableExpandChange(row: any, expanded: boolean) {
364
- // console.log('row: ', row, expanded)
365
- emits('expandChange', row, expanded)
366
- }
367
-
368
- /**
369
- * 选中或者取消
370
- * @param item
371
- */
372
- function checkAndRemove(item: any, isRemove: boolean = false) {
373
- // 校验是否已经有了
374
- const index = allSelectRowList.findIndex((i) => i[props.rowKey] === item[props.rowKey])
375
- if (isRemove) {
376
- if (index >= 0) {
377
- allSelectRowList.splice(index, 1)
378
- }
379
- } else {
380
- if (index < 0) {
381
- allSelectRowList.push(item)
382
- }
383
- }
384
- }
385
-
386
- /**
387
- * 外部修改选中项
388
- * @param item
389
- */
390
- function changeSelect(itemList: any[], isSelect: boolean = false) {
391
- if (itemList && itemList.length) {
392
- itemList.map((item) => {
393
- checkAndRemove(
394
- allSelectRowList.find((i) => i[props.rowKey] === item[props.rowKey]),
395
- !isSelect
396
- )
397
- })
398
- }
399
- // 这里要刷新一下tab的选中
400
- refreshTableSelect()
401
- }
402
-
403
- /**
404
- * 重置选中
405
- */
406
- function resetSelect() {
407
- allSelectRowList.splice(0, allSelectRowList.length, ...props.selectList)
408
- }
409
-
410
- /**
411
- * 封装分页查询条件
412
- */
413
- async function getListQueryData() {
414
- let queryMap = {
415
- // 封装查询条件
416
- // ...route.query,
417
- // ...tableHeaderRef.value.getData(),
418
- ...topQueryData.value,
419
- ...(typeof props.tableConfig.queryMap === 'function' ? await props.tableConfig.queryMap() : props.tableConfig.queryMap),
420
- t_: new Date().getTime()
421
- } as any
422
- if (props.isPager) {
423
- // 封装分页信息
424
- queryMap.current = pageInfo.current
425
- queryMap.size = pageInfo.size
426
- }
427
- // 这里处理一下列表Tab的查询条件
428
- if (props.tableConfig?.tabConf && props.tableConfig?.tabConf.prop) {
429
- queryMap[props.tableConfig?.tabConf.prop] = tableTabVal.value
430
- }
431
-
432
- queryMap = handelQueryData(queryMap)
433
- if (!props.isDialog) {
434
- // setQuery(route.path, queryMap)
435
- }
436
- // 这里是导出的权限判定-增加登陆信息
437
- if (props.tableConfig?.toolbar?.export?.isAuth) {
438
- // TODO GET Auth
439
- }
440
- return queryMap
441
- }
442
-
443
- /**
444
- * 处理下请求参数
445
- * @param queryMap
446
- */
447
- function handelQueryData(queryMap: object) {
448
- if (!queryMap) return {}
449
- const tempMap = {}
450
- Object.keys(queryMap).map((key) => {
451
- if (queryMap[key] !== undefined && queryMap[key] !== null && queryMap[key] !== '') {
452
- tempMap[key] = queryMap[key]
453
- }
454
- })
455
- return tempMap
456
- }
457
-
458
- /**
459
- * 处理显示
460
- * @param rowInfo
461
- */
462
- // function handelHeaderVIf(rowInfo: any) {
463
- // let vif = false
464
- // if (rowInfo.children && rowInfo.children.length > 0) {
465
- // vif = rowInfo.children.some((item: any) => {
466
- // return !(item.vif === false)
467
- // })
468
- // }
469
- // return vif
470
- // }
471
-
472
- /**
473
- * 处理列的显示
474
- * @param item
475
- */
476
- // function handelColumnVIf(item: any) {
477
- // if (item.vif !== undefined && item.vif !== null && item.vif !== '') {
478
- // if (typeof item.vif === 'boolean') return item.vif
479
- // if (typeof item.vif === 'function') return item.vif(item)
480
- // return !!item.vif
481
- // }
482
- // return true
483
- // }
484
-
485
- /**
486
- * 处理分页工具中pageSize变化
487
- * @param val
488
- */
489
- function handleSizeChange(val: number) {
490
- // 回到第一页
491
- pageInfo.current = 1
492
- pageInfo.size = val
493
- loadData(true)
494
- }
495
-
496
- /**
497
- * 处理分页工具中current变化
498
- * @param val
499
- */
500
- function handleCurrentChange(val: number) {
501
- if (pageInfo.current !== val) {
502
- pageInfo.current = val
503
- loadData(false)
504
- }
505
- }
506
-
507
- /**
508
- * 处理行展开
509
- * @param list
510
- * @param pIndexList
511
- */
512
- function handelTreeIndex(list: any[], pIndexList: number[]) {
513
- let tempList = []
514
- if (list && list.length > 0) {
515
- list.map((item, i) => {
516
- treeIndexList.push([...pIndexList, i])
517
- tempList = item[treeProps.children] as any[]
518
- if (tempList && tempList.length > 0) {
519
- handelTreeIndex(tempList, [i])
520
- }
521
- })
522
- }
523
- }
524
-
525
- /**
526
- * 真正调用查询的接口
527
- * @param isInit
528
- */
529
- async function loadData(isInit: Boolean) {
530
- if (!props.tableConfig.fetch) {
531
- loadingStatus.value = 2
532
- // if (props.modelValue) {
533
- // tableData.splice(0, tableData.length, ...props.modelValue)
534
- // }
535
- return false
536
- }
537
- if (loadingStatus.value === 1 || loading.value) return false
538
- loadingStatus.value = 1
539
- loading.value = true
540
- tableData.splice(0, tableData.length)
541
- if (isInit) {
542
- pageInfo.current = 1
543
- }
544
- let postData = await getListQueryData()
545
- // 这里处理一下外部数据格式化
546
- if (props.tableConfig?.toolbar?.formConfig?.beforeRequest) {
547
- postData = props.tableConfig?.toolbar?.formConfig?.beforeRequest(JSON.parse(JSON.stringify(postData))) || postData
548
- }
549
- const dataPage = (await props.tableConfig.fetch(postData)) as any
550
- try {
551
- if (props.isPager) {
552
- pageInfo.total = dataPage?.total * 1 || 0
553
- pageInfo.current = dataPage?.current || 1
554
- tableData.push(...(dataPage?.records || null))
555
- } else {
556
- tableData.push(...(dataPage?.records || dataPage || null))
557
- }
558
- if (isInit) {
559
- // 初始化完毕后,调用一次父类更新
560
- // emits('update:modelValue', tableData)
561
- }
562
- // 如果是树形结构
563
- if (props.type === 'expand') {
564
- treeIndexList.splice(0, treeIndexList.length)
565
- handelTreeIndex(tableData, [])
566
- }
567
- listLoading.value = false
568
- nextTick(() => {
569
- // 遍历以及选中当前页面数据
570
- refreshTableSelect()
571
- })
572
- } catch (e) {
573
- // eslint-disable-next-line no-console
574
- console.log('error: ', e)
575
- }
576
- loadingStatus.value = 2
577
- loading.value = false
578
- }
579
-
580
- /**
581
- * 渲染列表的选中项
582
- */
583
- function refreshTableSelect() {
584
- if (tableData && tableData.length > 0 && props.type === 'selection') {
585
- tableData.map((item: any) => {
586
- elPlusTableRef.value!.toggleRowSelection(
587
- item,
588
- allSelectRowList.some((i) => i[props.rowKey] === item[props.rowKey])
589
- )
590
- })
591
- }
592
- }
593
-
594
- /**
595
- * 重新加载
596
- */
597
- async function reload(isTab: boolean = false) {
598
- await loadData(true)
599
- // 这里判断一下Tab
600
- if (!isTab && props.tableConfig?.tabConf && props.tableConfig?.tabConf.fetch) {
601
- tabStatic.value = await props.tableConfig?.tabConf.fetch(Object.assign({}, await getListQueryData(), props.tableConfig?.tabConf.queryMap))
602
- loadingTab.value = false
603
- }
604
- return tableData
605
- }
606
-
607
- /**
608
- * 处理顶部条件表单筛选
609
- */
610
- function handelTopQuery() {
611
- topQueryData.value = cloneDeep(tableHeaderRef.value.getData())
612
- reload()
613
- }
614
-
615
- /**
616
- * 初始化列
617
- */
618
- function initCol() {
619
- tableHeaderRef.value?.initCol()
620
- }
621
-
622
- // 监听父类数据变更
623
- watch(
624
- () => props.modelValue,
625
- (data) => {
626
- // console.log('data: ', JSON.parse(JSON.stringify(data)))
627
- if (!props.tableConfig.fetch) {
628
- if (JSON.parse(JSON.stringify(data)) !== JSON.parse(JSON.stringify(tableData))) {
629
- loadingStatus.value = 2
630
- tableData.splice(0, tableData.length, ...(data || []))
631
- }
632
- }
633
- },
634
- { deep: true }
635
- )
636
-
637
- watch(
638
- () => props.selectList,
639
- (val: any[]) => {
640
- allSelectRowList.splice(0, allSelectRowList.length, ...val)
641
- // 遍历以及选中当前页面数据
642
- refreshTableSelect()
643
- },
644
- { deep: true }
645
- )
646
-
647
- onMounted(() => {
648
- reload()
649
- })
650
-
651
- defineExpose({ reload, tableData, changeSelect, resetSelect, initCol })
652
- </script>
653
- <style lang="scss">
654
- .el-plus-table-content {
655
- background-color: #ffffff;
656
- border-radius: 5px;
657
- padding: 10px;
658
- width: 100%;
659
- max-height: 100%;
660
- overflow: hidden;
661
- display: flex;
662
- flex-direction: column;
663
- position: relative;
664
- .th-required {
665
- position: relative;
666
- &::before {
667
- content: '*';
668
- position: absolute;
669
- left: -10px;
670
- font-size: 16px;
671
- top: 2px;
672
- color: #ff3b30;
673
- font-weight: bold;
674
- }
675
- }
676
- .select-items {
677
- display: flex;
678
- flex-wrap: wrap;
679
- align-items: center;
680
-
681
- .title {
682
- font-size: 18px;
683
- font-weight: bold;
684
- margin-right: 20px;
685
- }
686
-
687
- .select-item {
688
- margin: 5px 10px 5px 0;
689
-
690
- &:last-child {
691
- margin-right: 0;
692
- }
693
- }
694
- }
695
-
696
- .table-tabs-panel {
697
- margin-bottom: 16px;
698
- }
699
- .summary-row {
700
- width: 100%;
701
- background-color: var(--el-table-row-hover-bg-color);
702
- color: var(--el-table-text-color);
703
- padding: 16px 20px;
704
- line-height: 24px;
705
- height: 40px;
706
- display: flex;
707
- position: relative;
708
- .summary-item {
709
- display: flex;
710
- align-items: center;
711
- margin-right: 30px;
712
- & > span {
713
- margin-right: 20px;
714
- }
715
- }
716
- }
717
-
718
- .el-plus-table-main {
719
- width: 100%;
720
- flex: 1;
721
- max-height: 100%;
722
- display: flex;
723
- flex-direction: column;
724
- .el-table {
725
- .cell {
726
- display: flex;
727
- }
728
- .is-center {
729
- .cell {
730
- align-items: center;
731
- justify-content: center;
732
- }
733
- }
734
- }
735
- .big-h-bar {
736
- .el-scrollbar {
737
- .is-horizontal {
738
- height: 12px !important;
739
- }
740
- .el-table__body {
741
- padding-bottom: 16px;
742
- }
743
- }
744
- }
745
- .big-v-bar {
746
- .el-scrollbar {
747
- .is-vertical {
748
- width: 12px !important;
749
- }
750
- }
751
- }
752
- }
753
-
754
- .pager-statistic {
755
- width: 100%;
756
- position: fixed;
757
- height: 32px;
758
- line-height: 32px;
759
- bottom: 0;
760
- text-align: right;
761
- min-width: 900px;
762
-
763
- .statistic-item {
764
- display: inline-block;
765
- }
766
- }
767
-
768
- .el-cascader__label {
769
- width: 300px !important;
770
- }
771
-
772
- .bottom-page-static-info {
773
- display: flex;
774
- flex-wrap: wrap;
775
- justify-content: center;
776
- align-items: center;
777
- min-height: 41px;
778
- margin-top: 10px;
779
-
780
- .page-info {
781
- margin-right: 30px;
782
- }
783
- }
784
-
785
- .common-list-export-excel {
786
- background: #20a0ff;
787
- text-decoration: none;
788
- color: #ffffff;
789
- font-size: 12px;
790
- height: 29px;
791
- line-height: 30px;
792
- display: block;
793
- margin-top: 5px;
794
- border-radius: 3px;
795
- padding: 0 10px;
796
- }
797
-
798
- .common-list-export-excel:hover {
799
- background: #58b6ff;
800
- }
801
-
802
- .el-table__empty-block {
803
- height: auto !important;
804
- }
805
- }
806
- </style>
807
- types
1
+ <template>
2
+ <div class="el-plus-table-content">
3
+ <!-- <div class="select-items" v-if="type === 'selection' && selectRowList && selectRowList.length > 0">
4
+ <span class="title">已选择({{ selectRowList.length }}个): </span>
5
+ <el-tag v-for="(item, i) in selectRowList" :key="item.id" class="select-item" size="small" closable @close="() => handelRemoveSelect(i, item)">
6
+ {{ item[tableConfig.showSelectNameKey || 'name'] }}
7
+ </el-tag>
8
+ </div> -->
9
+ <EleTabletHeader ref="tableHeaderRef" v-if="Object.keys(tableConfig?.toolbar || {}).length || tableConfig.tbName" v-model="toolFormData" :tbName="tableConfig.tbName" :column="tableConfig.column" :size="size" :isShowRefresh="isShowRefresh" :loading="loading" :toolbar="tableConfig.toolbar" :isDialog="isDialog" @query="handelTopQuery" />
10
+
11
+ <!-- 中部的Tabs -->
12
+ <div class="table-tabs-panel" v-if="tableConfig.tabConf">
13
+ <el-radio-group v-model="tableTabVal" size="default" @change="handelTabChange">
14
+ <el-radio-button v-for="(item, i) in tableConfig.tabConf?.tabs" :key="i" :label="item.value" :loading="true">
15
+ {{ item.label }}
16
+ <template v-if="loadingTab">
17
+ <el-icon class="is-loading"><Loading /></el-icon>
18
+ </template>
19
+ <template v-else>
20
+ {{ getTabLabel(item) }}
21
+ </template>
22
+ </el-radio-button>
23
+ </el-radio-group>
24
+ </div>
25
+
26
+ <!-- 中间列表 -->
27
+ <div class="el-plus-table-main" v-loading="loading">
28
+ <template v-if="isDIYMain">
29
+ <slot name="main" :tableData="tableData"></slot>
30
+ </template>
31
+ <!-- 这里开始是表格内容 -->
32
+ <el-table ref="elPlusTableRef" v-else style="width: 100%" height="100%" :maxHeight="tableConfig.maxHeight || 'auto'" v-bind="tableConfig.tableAttr" :class="{ 'big-h-bar': tableConfig?.tableAttr?.bigHBar, 'big-v-bar': tableConfig.tableAttr?.bigVBar }" :data="tableData" :row-key="rowKey" lazy :load="loadExpandData" :size="size" :row-class-name="initRowClassName" @select="handelTableSelect" @select-all="handelTableSelectAll" @expand-change="handelTableExpandChange" :treeProps="treeProps">
33
+ <!-- 复选框 -->
34
+ <el-table-column v-if="type === 'selection'" type="selection" width="55px" :selectable="selectable" header-align="center" align="center" />
35
+ <!-- 下标 -->
36
+ <el-table-column v-if="isIndex" type="index" width="60" label="序号" :headerAlign="headerAlign" />
37
+ <!-- 首列 -->
38
+ <template v-if="useSlots().firstColumn">
39
+ <slot name="firstColumn" />
40
+ </template>
41
+ <!-- 一级或多级列 -->
42
+ <ElPlusTableColumn v-for="(item, i) in headerColumns" :key="i" :item="item" :size="size"></ElPlusTableColumn>
43
+
44
+ <!-- -->
45
+ <template v-if="!loading && loadingStatus === 2" #empty>
46
+ <el-empty v-if="isEmptyImg" :description="nullText" />
47
+ <span v-else>{{ nullText }}</span>
48
+ </template>
49
+ <!-- 合计行 -->
50
+ <template v-if="tableConfig.summaryConf?.prop" #append>
51
+ <div :style="tableConfig.summaryConf?.hstyle" class="summary-row" v-if="summaryList && summaryList.length > 0">
52
+ <div class="summary-item" v-for="(item, i) in summaryList" :key="i">
53
+ <span>{{ item.label || '合计' }}:</span>
54
+ <p>{{ item.value || 0 }}</p>
55
+ </div>
56
+ </div>
57
+ </template>
58
+ </el-table>
59
+ </div>
60
+ <div class="bottom-page-static-info" v-if="isPager || tableConfig.statistic">
61
+ <el-pagination class="page-info" small @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="+pageInfo.current" :page-sizes="[5, 10, 20, 50, 100]" :page-size="pageInfo.size" layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total" />
62
+ </div>
63
+ <slot name="bottom"></slot>
64
+ </div>
65
+ </template>
66
+ <script lang="ts">
67
+ export default {
68
+ name: 'ElPlusTable',
69
+ inheritAttrs: false,
70
+ customOptions: {}
71
+ }
72
+ </script>
73
+ <script lang="ts" setup>
74
+ import { ref, reactive, onMounted, computed, watch, nextTick, useSlots, inject } from 'vue'
75
+ import EleTabletHeader from './components/header.vue'
76
+ import ElPlusTableColumn from './ElPlusTableColumn.vue'
77
+ import { handelListColumn } from './util'
78
+ import { cloneDeep } from 'lodash'
79
+ import { Loading } from '@element-plus/icons-vue'
80
+ import { ICRUDConfig, ITableConfig, ITableTabItem, ITreeProps } from 'types'
81
+
82
+ const defaultConf = inject('defaultConf') as ICRUDConfig
83
+ const format = inject('format') as any
84
+
85
+ const emits = defineEmits(['getUrlConsumerIds', 'selection', 'select', 'selectAll', 'update:modelValue', 'tabChange', 'expandChange'])
86
+ const props = withDefaults(
87
+ defineProps<{
88
+ tableConfig: ITableConfig
89
+ // 外部数据
90
+ modelValue?: Array<any> | null
91
+ // 列表类型 默认为index
92
+ type?: string
93
+ // 是否显示第一列的Index下标
94
+ isIndex?: boolean
95
+ // 是否分页
96
+ isPager?: boolean
97
+ // 每页显示条数
98
+ pageSize?: number
99
+ // 是否在弹框中
100
+ isDialog?: boolean
101
+ // 空占位文本
102
+ nullText?: string
103
+ // 是否显示暂无数据的图片
104
+ isEmptyImg?: boolean
105
+ // 是否显示刷新文本
106
+ isShowRefresh?: boolean
107
+ // rowKey默认为id
108
+ rowKey?: string
109
+ // 自定义table主体
110
+ isDIYMain?: boolean
111
+ // 默认选中项
112
+ selectList?: Array<any> | []
113
+ // 默认列宽
114
+ colMinWidth?: string
115
+ // 表头文本排列方式
116
+ headerAlign?: 'left' | 'right' | 'center'
117
+ }>(),
118
+ {
119
+ modelValue: null,
120
+ type: 'index',
121
+ isIndex: true,
122
+ isPager: true,
123
+ pageSize: 10,
124
+ isDialog: false,
125
+ nullText: '暂无数据',
126
+ isShowRefresh: true,
127
+ rowKey: 'id',
128
+ isEmptyImg: true,
129
+ isDIYMain: false,
130
+ selectList: () => [],
131
+ colMinWidth: 'auto',
132
+ headerAlign: 'left'
133
+ }
134
+ )
135
+
136
+ const elPlusTableRef = ref()
137
+
138
+ // 顶部Tab数据
139
+ const tableTabVal = ref(props.tableConfig?.tabConf?.tabs[props.tableConfig?.tabConf?.default || 0].value ?? '')
140
+ const tabStatic = ref({} as any)
141
+ const getTabLabel = computed(() => (item: ITableTabItem) => {
142
+ if (item.key) {
143
+ return tabStatic.value[item.key] || 0
144
+ }
145
+ return ''
146
+ })
147
+
148
+ const selectable = computed(() => (row: any, index: number) => {
149
+ if (typeof props.tableConfig?.tableAttr?.selectable === 'function') {
150
+ return props.tableConfig?.tableAttr?.selectable(row, index)
151
+ }
152
+ return true
153
+ })
154
+
155
+ const tableHeaderRef = ref()
156
+
157
+ // 加载
158
+ const loading = ref(false)
159
+ const loadingTab = ref(!!props.tableConfig?.tabConf?.fetch)
160
+ const listLoading = ref(false)
161
+ const size = defaultConf.size || 'small'
162
+
163
+ // 顶部查询条件数据缓存
164
+ const topQueryData = ref({} as any)
165
+
166
+ // 数据
167
+ let toolFormData = reactive({} as any)
168
+ const tableData = reactive((props.modelValue || []) as any[])
169
+ const haveClassRowList = reactive([])
170
+
171
+ // 0:未加载; 1:加载中;2:加载完成
172
+ const loadingStatus = ref(0)
173
+
174
+ // 保存所有的选中行
175
+ const allSelectRowList = reactive((cloneDeep(props.selectList) || []) as any[])
176
+ // 记录树形展开的数组的下标
177
+ const treeIndexList = reactive([] as any[][])
178
+
179
+ // 分页信息
180
+ const pageInfo = reactive({
181
+ current: !props.isDialog && toolFormData.current ? parseInt(toolFormData.current as any) : 1,
182
+ total: 0,
183
+ size: !props.isDialog && toolFormData.size ? parseInt(toolFormData.size as any) : props.pageSize
184
+ })
185
+ // 数型解析
186
+ const treeProps = (props.tableConfig?.explan?.treeProps || { children: 'children', hasChildren: 'hasChildren' }) as ITreeProps
187
+
188
+ // 处理后的列显示
189
+ const headerColumns = computed(() => {
190
+ const tempList = handelListColumn(props.tableConfig?.column, defaultConf, props.tableConfig?.tbName || '', props.headerAlign, props.isDialog ? 'auto' : props.colMinWidth)
191
+ return tempList
192
+ })
193
+
194
+ // 合计行数据
195
+ const summaryList = computed(() => {
196
+ const tempList = [] as any[]
197
+ if (props.tableConfig.summaryConf?.vif) {
198
+ if (typeof props.tableConfig.summaryConf?.vif === 'boolean') {
199
+ if (!props.tableConfig.summaryConf?.vif) {
200
+ return tempList
201
+ }
202
+ } else {
203
+ if (!props.tableConfig.summaryConf?.vif()) {
204
+ return tempList
205
+ }
206
+ }
207
+ }
208
+ if (props.tableConfig.summaryConf?.prop) {
209
+ const propList = props.tableConfig.summaryConf.prop.split(',')
210
+ const labelList = props.tableConfig.summaryConf?.label?.split(',') || []
211
+ // 遍历
212
+ propList.map((prop, i: number) => {
213
+ let value = ''
214
+ if (props.tableConfig.summaryConf?.sumFn) {
215
+ value = props.tableConfig.summaryConf?.sumFn(tableData, allSelectRowList)
216
+ } else {
217
+ value = format.yuan(tableData.reduce((total: number, current) => (total += current[prop]), 0))
218
+ }
219
+ tempList.push({ label: labelList[i], value })
220
+ })
221
+ }
222
+ return tempList
223
+ })
224
+
225
+ /**
226
+ * Tab切换
227
+ * @param val
228
+ */
229
+ async function handelTabChange(val: string | number | boolean) {
230
+ // 这里直接重新查询
231
+ reload(true)
232
+
233
+ // 通知父类 第二个参数是回调
234
+ await emits('tabChange', val, initCol)
235
+
236
+ // 这里触发下initCol
237
+ nextTick(() => {
238
+ initCol()
239
+ })
240
+ }
241
+
242
+ /**
243
+ * 加载自身展开的数据
244
+ * @param row
245
+ * @param treeNode
246
+ * @param resolve
247
+ */
248
+ function loadExpandData(row: any, treeNode: any, resolve: any) {
249
+ const postData = getListQueryData()
250
+ postData[props.tableConfig?.explan?.idName || 'parentId'] = row.id
251
+ props.tableConfig.fetch &&
252
+ props.tableConfig.fetch(postData).then((pageInfo) => {
253
+ resolve(pageInfo?.records)
254
+ })
255
+ }
256
+
257
+ /**
258
+ * 初始化每行的颜色
259
+ * @param data
260
+ */
261
+ function initRowClassName(data: any) {
262
+ if (haveClassRowList.length > data.rowIndex) {
263
+ return haveClassRowList[data.rowIndex * 1]
264
+ }
265
+ return ''
266
+ }
267
+
268
+ /**
269
+ * 处理单个选中的情况
270
+ * @param selection
271
+ * @param row
272
+ */
273
+ function handelTableSelect(selection: any[], item: any) {
274
+ checkAndRemove(item, !selection.some((i) => i[props.rowKey] === item[props.rowKey]))
275
+ // 通知父类
276
+ emits('select', selection, item)
277
+ emits('selection', cloneDeep(allSelectRowList))
278
+ }
279
+
280
+ /**
281
+ * 处理全选
282
+ * @param selection
283
+ * @param row
284
+ */
285
+ function handelTableSelectAll(selection: any[]) {
286
+ const isRemove = !(selection && selection.length > 0)
287
+ ;(isRemove ? tableData : selection).map((item) => {
288
+ checkAndRemove(item, isRemove)
289
+ })
290
+ // 通知父类
291
+ emits('selectAll', selection, isRemove)
292
+ emits('selection', cloneDeep(allSelectRowList))
293
+ }
294
+
295
+ /**
296
+ * 处理行展开
297
+ * @param row
298
+ * @param expanded
299
+ */
300
+ function handelTableExpandChange(row: any, expanded: boolean) {
301
+ // console.log('row: ', row, expanded)
302
+ emits('expandChange', row, expanded)
303
+ }
304
+
305
+ /**
306
+ * 选中或者取消
307
+ * @param item
308
+ */
309
+ function checkAndRemove(item: any, isRemove: boolean = false) {
310
+ // 校验是否已经有了
311
+ const index = allSelectRowList.findIndex((i) => i[props.rowKey] === item[props.rowKey])
312
+ if (isRemove) {
313
+ if (index >= 0) {
314
+ allSelectRowList.splice(index, 1)
315
+ }
316
+ } else {
317
+ if (index < 0) {
318
+ allSelectRowList.push(item)
319
+ }
320
+ }
321
+ }
322
+
323
+ /**
324
+ * 外部修改选中项
325
+ * @param item
326
+ */
327
+ function changeSelect(itemList: any[], isSelect: boolean = false) {
328
+ if (itemList && itemList.length) {
329
+ itemList.map((item) => {
330
+ checkAndRemove(
331
+ allSelectRowList.find((i) => i[props.rowKey] === item[props.rowKey]),
332
+ !isSelect
333
+ )
334
+ })
335
+ }
336
+ // 这里要刷新一下tab的选中
337
+ refreshTableSelect()
338
+ }
339
+
340
+ /**
341
+ * 重置选中
342
+ */
343
+ function resetSelect() {
344
+ allSelectRowList.splice(0, allSelectRowList.length, ...props.selectList)
345
+ }
346
+
347
+ /**
348
+ * 封装分页查询条件
349
+ */
350
+ async function getListQueryData() {
351
+ let queryMap = {
352
+ // 封装查询条件
353
+ // ...route.query,
354
+ // ...tableHeaderRef.value.getData(),
355
+ ...topQueryData.value,
356
+ ...(typeof props.tableConfig.queryMap === 'function' ? await props.tableConfig.queryMap() : props.tableConfig.queryMap),
357
+ t_: new Date().getTime()
358
+ } as any
359
+ if (props.isPager) {
360
+ // 封装分页信息
361
+ queryMap.current = pageInfo.current
362
+ queryMap.size = pageInfo.size
363
+ }
364
+ // 这里处理一下列表Tab的查询条件
365
+ if (props.tableConfig?.tabConf && props.tableConfig?.tabConf.prop) {
366
+ queryMap[props.tableConfig?.tabConf.prop] = tableTabVal.value
367
+ }
368
+
369
+ queryMap = handelQueryData(queryMap)
370
+ if (!props.isDialog) {
371
+ // setQuery(route.path, queryMap)
372
+ }
373
+ // 这里是导出的权限判定-增加登陆信息
374
+ if (props.tableConfig?.toolbar?.export?.isAuth) {
375
+ // TODO GET Auth
376
+ }
377
+ return queryMap
378
+ }
379
+
380
+ /**
381
+ * 处理下请求参数
382
+ * @param queryMap
383
+ */
384
+ function handelQueryData(queryMap: object) {
385
+ if (!queryMap) return {}
386
+ const tempMap = {}
387
+ Object.keys(queryMap).map((key) => {
388
+ if (queryMap[key] !== undefined && queryMap[key] !== null && queryMap[key] !== '') {
389
+ tempMap[key] = queryMap[key]
390
+ }
391
+ })
392
+ return tempMap
393
+ }
394
+
395
+ /**
396
+ * 处理显示
397
+ * @param rowInfo
398
+ */
399
+ // function handelHeaderVIf(rowInfo: any) {
400
+ // let vif = false
401
+ // if (rowInfo.children && rowInfo.children.length > 0) {
402
+ // vif = rowInfo.children.some((item: any) => {
403
+ // return !(item.vif === false)
404
+ // })
405
+ // }
406
+ // return vif
407
+ // }
408
+
409
+ /**
410
+ * 处理列的显示
411
+ * @param item
412
+ */
413
+ // function handelColumnVIf(item: any) {
414
+ // if (item.vif !== undefined && item.vif !== null && item.vif !== '') {
415
+ // if (typeof item.vif === 'boolean') return item.vif
416
+ // if (typeof item.vif === 'function') return item.vif(item)
417
+ // return !!item.vif
418
+ // }
419
+ // return true
420
+ // }
421
+
422
+ /**
423
+ * 处理分页工具中pageSize变化
424
+ * @param val
425
+ */
426
+ function handleSizeChange(val: number) {
427
+ // 回到第一页
428
+ pageInfo.current = 1
429
+ pageInfo.size = val
430
+ loadData(true)
431
+ }
432
+
433
+ /**
434
+ * 处理分页工具中current变化
435
+ * @param val
436
+ */
437
+ function handleCurrentChange(val: number) {
438
+ if (pageInfo.current !== val) {
439
+ pageInfo.current = val
440
+ loadData(false)
441
+ }
442
+ }
443
+
444
+ /**
445
+ * 处理行展开
446
+ * @param list
447
+ * @param pIndexList
448
+ */
449
+ function handelTreeIndex(list: any[], pIndexList: number[]) {
450
+ let tempList = []
451
+ if (list && list.length > 0) {
452
+ list.map((item, i) => {
453
+ treeIndexList.push([...pIndexList, i])
454
+ tempList = item[treeProps.children] as any[]
455
+ if (tempList && tempList.length > 0) {
456
+ handelTreeIndex(tempList, [i])
457
+ }
458
+ })
459
+ }
460
+ }
461
+
462
+ /**
463
+ * 真正调用查询的接口
464
+ * @param isInit
465
+ */
466
+ async function loadData(isInit: Boolean) {
467
+ if (!props.tableConfig.fetch) {
468
+ loadingStatus.value = 2
469
+ // if (props.modelValue) {
470
+ // tableData.splice(0, tableData.length, ...props.modelValue)
471
+ // }
472
+ return false
473
+ }
474
+ if (loadingStatus.value === 1 || loading.value) return false
475
+ loadingStatus.value = 1
476
+ loading.value = true
477
+ tableData.splice(0, tableData.length)
478
+ if (isInit) {
479
+ pageInfo.current = 1
480
+ }
481
+ let postData = await getListQueryData()
482
+ // 这里处理一下外部数据格式化
483
+ if (props.tableConfig?.toolbar?.formConfig?.beforeRequest) {
484
+ postData = props.tableConfig?.toolbar?.formConfig?.beforeRequest(JSON.parse(JSON.stringify(postData))) || postData
485
+ }
486
+ const dataPage = (await props.tableConfig.fetch(postData)) as any
487
+ try {
488
+ if (props.isPager) {
489
+ pageInfo.total = dataPage?.total * 1 || 0
490
+ pageInfo.current = dataPage?.current || 1
491
+ tableData.push(...(dataPage?.records || null))
492
+ } else {
493
+ tableData.push(...(dataPage?.records || dataPage || null))
494
+ }
495
+ if (isInit) {
496
+ // 初始化完毕后,调用一次父类更新
497
+ // emits('update:modelValue', tableData)
498
+ }
499
+ // 如果是树形结构
500
+ if (props.type === 'expand') {
501
+ treeIndexList.splice(0, treeIndexList.length)
502
+ handelTreeIndex(tableData, [])
503
+ }
504
+ listLoading.value = false
505
+ nextTick(() => {
506
+ // 遍历以及选中当前页面数据
507
+ refreshTableSelect()
508
+ })
509
+ } catch (e) {
510
+ // eslint-disable-next-line no-console
511
+ console.log('error: ', e)
512
+ }
513
+ loadingStatus.value = 2
514
+ loading.value = false
515
+ }
516
+
517
+ /**
518
+ * 渲染列表的选中项
519
+ */
520
+ function refreshTableSelect() {
521
+ if (tableData && tableData.length > 0 && props.type === 'selection') {
522
+ tableData.map((item: any) => {
523
+ elPlusTableRef.value!.toggleRowSelection(
524
+ item,
525
+ allSelectRowList.some((i) => i[props.rowKey] === item[props.rowKey])
526
+ )
527
+ })
528
+ }
529
+ }
530
+
531
+ /**
532
+ * 重新加载
533
+ */
534
+ async function reload(isTab: boolean = false) {
535
+ await loadData(true)
536
+ // 这里判断一下Tab
537
+ if (!isTab && props.tableConfig?.tabConf && props.tableConfig?.tabConf.fetch) {
538
+ tabStatic.value = await props.tableConfig?.tabConf.fetch(Object.assign({}, await getListQueryData(), props.tableConfig?.tabConf.queryMap))
539
+ loadingTab.value = false
540
+ }
541
+ return tableData
542
+ }
543
+
544
+ /**
545
+ * 处理顶部条件表单筛选
546
+ */
547
+ function handelTopQuery() {
548
+ topQueryData.value = cloneDeep(tableHeaderRef.value.getData())
549
+ reload()
550
+ }
551
+
552
+ /**
553
+ * 初始化列
554
+ */
555
+ function initCol() {
556
+ tableHeaderRef.value?.initCol()
557
+ }
558
+
559
+ // 监听父类数据变更
560
+ watch(
561
+ () => props.modelValue,
562
+ (data) => {
563
+ // console.log('data: ', JSON.parse(JSON.stringify(data)))
564
+ if (!props.tableConfig.fetch) {
565
+ if (JSON.parse(JSON.stringify(data)) !== JSON.parse(JSON.stringify(tableData))) {
566
+ loadingStatus.value = 2
567
+ tableData.splice(0, tableData.length, ...(data || []))
568
+ }
569
+ }
570
+ },
571
+ { deep: true }
572
+ )
573
+
574
+ watch(
575
+ () => props.selectList,
576
+ (val: any[]) => {
577
+ allSelectRowList.splice(0, allSelectRowList.length, ...val)
578
+ // 遍历以及选中当前页面数据
579
+ refreshTableSelect()
580
+ },
581
+ { deep: true }
582
+ )
583
+
584
+ onMounted(() => {
585
+ reload()
586
+ })
587
+
588
+ defineExpose({ reload, tableData, changeSelect, resetSelect, initCol })
589
+ </script>
590
+ <style lang="scss">
591
+ .el-plus-table-content {
592
+ background-color: #ffffff;
593
+ border-radius: 5px;
594
+ padding: 10px;
595
+ width: 100%;
596
+ max-height: 100%;
597
+ overflow: hidden;
598
+ display: flex;
599
+ flex-direction: column;
600
+ position: relative;
601
+ .th-required {
602
+ position: relative;
603
+ &::before {
604
+ content: '*';
605
+ position: absolute;
606
+ left: -10px;
607
+ font-size: 16px;
608
+ top: 2px;
609
+ color: #ff3b30;
610
+ font-weight: bold;
611
+ }
612
+ }
613
+ .select-items {
614
+ display: flex;
615
+ flex-wrap: wrap;
616
+ align-items: center;
617
+
618
+ .title {
619
+ font-size: 18px;
620
+ font-weight: bold;
621
+ margin-right: 20px;
622
+ }
623
+
624
+ .select-item {
625
+ margin: 5px 10px 5px 0;
626
+
627
+ &:last-child {
628
+ margin-right: 0;
629
+ }
630
+ }
631
+ }
632
+
633
+ .table-tabs-panel {
634
+ margin-bottom: 16px;
635
+ }
636
+ .summary-row {
637
+ width: 100%;
638
+ background-color: var(--el-table-row-hover-bg-color);
639
+ color: var(--el-table-text-color);
640
+ padding: 16px 20px;
641
+ line-height: 24px;
642
+ height: 40px;
643
+ display: flex;
644
+ position: relative;
645
+ .summary-item {
646
+ display: flex;
647
+ align-items: center;
648
+ margin-right: 30px;
649
+ & > span {
650
+ margin-right: 20px;
651
+ }
652
+ }
653
+ }
654
+
655
+ .el-plus-table-main {
656
+ width: 100%;
657
+ flex: 1;
658
+ max-height: 100%;
659
+ display: flex;
660
+ flex-direction: column;
661
+ .el-table {
662
+ .cell {
663
+ display: flex;
664
+ }
665
+ .is-center {
666
+ .cell {
667
+ align-items: center;
668
+ justify-content: center;
669
+ }
670
+ }
671
+ }
672
+ .big-h-bar {
673
+ .el-scrollbar {
674
+ .is-horizontal {
675
+ height: 12px !important;
676
+ }
677
+ .el-table__body {
678
+ padding-bottom: 16px;
679
+ }
680
+ }
681
+ }
682
+ .big-v-bar {
683
+ .el-scrollbar {
684
+ .is-vertical {
685
+ width: 12px !important;
686
+ }
687
+ }
688
+ }
689
+ }
690
+
691
+ .pager-statistic {
692
+ width: 100%;
693
+ position: fixed;
694
+ height: 32px;
695
+ line-height: 32px;
696
+ bottom: 0;
697
+ text-align: right;
698
+ min-width: 900px;
699
+
700
+ .statistic-item {
701
+ display: inline-block;
702
+ }
703
+ }
704
+
705
+ .el-cascader__label {
706
+ width: 300px !important;
707
+ }
708
+
709
+ .bottom-page-static-info {
710
+ display: flex;
711
+ flex-wrap: wrap;
712
+ justify-content: center;
713
+ align-items: center;
714
+ min-height: 41px;
715
+ margin-top: 10px;
716
+
717
+ .page-info {
718
+ margin-right: 30px;
719
+ }
720
+ }
721
+
722
+ .common-list-export-excel {
723
+ background: #20a0ff;
724
+ text-decoration: none;
725
+ color: #ffffff;
726
+ font-size: 12px;
727
+ height: 29px;
728
+ line-height: 30px;
729
+ display: block;
730
+ margin-top: 5px;
731
+ border-radius: 3px;
732
+ padding: 0 10px;
733
+ }
734
+
735
+ .common-list-export-excel:hover {
736
+ background: #58b6ff;
737
+ }
738
+
739
+ .el-table__empty-block {
740
+ height: auto !important;
741
+ }
742
+ }
743
+ </style>
744
+ types