vue2-client 1.17.29 → 1.17.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,665 +1,674 @@
1
- <template>
2
- <!-- 当expandedGrid存在时渲染带有expandedRowRender的表格 -->
3
- <s-table
4
- v-if="tableContext.expandedGrid"
5
- ref="expandableTable"
6
- :id="tableContext.uniqueId"
7
- :alert="true"
8
- :columns="realTableColumns"
9
- :data="loadData()"
10
- :rowKey="tableContext.rowKey"
11
- :showSummary="tableContext.showSummary"
12
- :rowSelection="tableContext.rowSelection"
13
- :scroll="{ x: tableContext.scrollXWidth, y: tableContext.scrollYHeight }"
14
- :showPagination="tableContext.showPagination"
15
- :hidePagination="tableContext.simpleMode"
16
- :customPagination="tableContext.customPagination"
17
- :showSelected="!tableContext.simpleMode"
18
- :pageSize="tableContext.simpleMode ? 1000 : undefined"
19
- :pageMaxSize="tableContext.pageMaxSize"
20
- :setScrollYHeight="tableContext.setScrollYHeight"
21
- :selectRowMode="tableContext.selectRowMode"
22
- :size="tableContext.tableSize"
23
- :components="components"
24
- :rowStyleFunction="tableContext.rowStyleFunction"
25
- @beforeDataChange="beforeDataChange"
26
- @expand="onExpand"
27
- @rowClick="handleRowClick"
28
- >
29
- <template
30
- v-for="(item, c_index) in realTableColumns"
31
- :slot="item.dataIndex"
32
- slot-scope="text, record, index">
33
- <template v-if="tableContext.isEditMode && getFromItem(item.dataIndex,text, record, index)">
34
- <x-form-item
35
- class="innerTable"
36
- :style="{ paddingTop: 0, paddingBottom: 0, paddingLeft: 0, paddingRight: 0 }"
37
- :form="record"
38
- :attr="getFromItem(item.dataIndex,text, record, index)"
39
- :service-name="tableContext.serviceName"
40
- mode="新增/修改"
41
- :env="tableContext.env"
42
- :setForm="(obj)=>tableContext.setForm(record,obj)"
43
- @rowChoose="(row, attr, callback) => tableContext.rowChoose(row, attr, callback, record)"
44
- :showLabel="false"
45
- :key="'editRow-' + c_index"
46
- />
47
- </template>
48
- <span v-else-if="item.slotType === 'rate'" :key="'rate-' + c_index">
49
- <x-rate
50
- :value="text"
51
- :disabled="true"
52
- :allow-half="item.allowHalf"
53
- :icon="item.rateIcon"
54
- :max-count="item.maxCount"
55
- style="zoom:0.9"/>
56
- </span>
57
- <span v-else-if="item.slotType === 'index'" :key="'index-' + c_index">
58
- {{ index + 1 }}
59
- </span>
60
- <CustomFuncCel
61
- :text="text"
62
- :record="text"
63
- :index="index"
64
- :item="item"
65
- :localDataSource="activeTable?.localDataSource"
66
- v-else-if="item.slotCustomFunction"
67
- :key="'customJs-' + c_index"></CustomFuncCel>
68
- <span v-else-if="item.slotType === 'link'" :key="'link-' + c_index">
69
- <a @click="tableContext.columnClick(item.dataIndex,text,record)">{{ text }}</a>
70
- </span>
71
- <span v-else-if="item.slotType === 'gotoUserDetail'" :key="'gotoUserDetail-' + c_index">
72
- <a @click="tableContext.gotoUserDetail(item.dataIndex,text,record)">{{ text }}</a>
73
- </span>
74
- <span v-else-if="['ellipsis','fixed'].includes(item.slotType)" :key="'ellipsis-' + c_index">
75
- <span>{{ text === '' ? '--' : text }}</span>
76
- </span>
77
- <span v-else-if="item.slotType === 'badge'" :key="'badge-' + c_index">
78
- <x-badge
79
- :service-name="tableContext.serviceName"
80
- :env="tableContext.env"
81
- v-if="text !== null && text !== undefined"
82
- :badge-key="item.slotKeyMap"
83
- :value="text"/>
84
- </span>
85
- <span v-else-if="item.slotType === 'date'" :key="'date-' + c_index">
86
- {{ format(text, 'yyyy-MM-dd') }}
87
- </span>
88
- <span v-else-if="item.slotType === 'dateTime'" :key="'dateTime-' + c_index">
89
- {{ format(text, 'yyyy-MM-dd hh:mm:ss') }}
90
- </span>
91
- <span v-else-if="item.slotType === 'towDecimal'" :key="'towDecimal-' + c_index">
92
- {{ numberFormat(text, 2) }}
93
- </span>
94
- <span v-else-if="item.slotType === 'fourDecimal'" :key="'fourDecimal-' + c_index">
95
- {{ numberFormat(text, 4) }}
96
- </span>
97
- <span v-else-if="item.slotType === 'int'" :key="'int-' + c_index">
98
- {{ numberFormat(text, 0) }}
99
- </span>
100
- <span v-else-if="item.slotType === 'action'" :key="'action-' + c_index">
101
- <template v-if="item.actionArr && item.actionArr.length > 0">
102
- <a-dropdown placement="bottomCenter" :getPopupContainer=" triggerNode => { return triggerNode.parentNode } ">
103
- <a class="ant-dropdown-link" @click="e => e.preventDefault()">
104
- {{ item.scopedSlots?.customRender || item.slotValue }} <a-icon type="down"/>
105
- </a>
106
- <a-menu slot="overlay" style="min-width: 60px">
107
- <a-menu-item
108
- v-for="(action_item, actionIndex) in item.actionArr"
109
- :key="actionIndex"
110
- v-show="!action_item.customFunction || tableContext.customFunctionShow(action_item.customFunction,record,c_index)">
111
- <a
112
- style="text-align: center"
113
- @click="tableContext.action(record, item.dataIndex, action_item.func)"
114
- >{{ action_item.text }}</a>
115
- </a-menu-item>
116
- </a-menu>
117
- </a-dropdown>
118
- </template>
119
- <template v-if="!item.actionArr || item.actionArr.length === 0">
120
- <a @click="tableContext.action(record, item.dataIndex,'action', index)">{{ item.slotValue }}</a>
121
- </template>
122
- </span>
123
- </template>
124
- <template slot="expandedRowRender" slot-scope="record">
125
- <slot
126
- name="expandedRowRender"
127
- :selectedRowKeys="tableContext.selectedRowKeys"
128
- :selectedRows="tableContext.selectedRows"
129
- :record="record"
130
- ></slot>
131
- </template>
132
- <template slot="footer">
133
- <slot
134
- name="footer"
135
- :selectedRowKeys="tableContext.selectedRowKeys"
136
- :selectedRows="tableContext.selectedRows"></slot>
137
- </template>
138
- </s-table>
139
-
140
- <!-- 当expandedGrid不存在时渲染不带expandedRowRender的表格 -->
141
- <s-table
142
- v-else
143
- ref="simpleTable"
144
- :id="tableContext.uniqueId"
145
- :alert="true"
146
- :columns="realTableColumns"
147
- :data="loadData()"
148
- :rowKey="tableContext.rowKey"
149
- :showSummary="tableContext.showSummary"
150
- :rowSelection="tableContext.rowSelection"
151
- :scroll="{ x: tableContext.scrollXWidth, y: tableContext.scrollYHeight }"
152
- :showPagination="tableContext.showPagination"
153
- :hidePagination="tableContext.simpleMode"
154
- :customPagination="tableContext.customPagination"
155
- :showSelected="!tableContext.simpleMode"
156
- :pageSize="tableContext.simpleMode ? 1000 : undefined"
157
- :pageMaxSize="tableContext.pageMaxSize"
158
- :setScrollYHeight="tableContext.setScrollYHeight"
159
- :selectRowMode="tableContext.selectRowMode"
160
- :size="tableContext.tableSize"
161
- :components="components"
162
- :rowStyleFunction="tableContext.rowStyleFunction"
163
- @rowClick="handleRowClick"
164
- @beforeDataChange="beforeDataChange"
165
- >
166
- <template
167
- v-for="(item, c_index) in realTableColumns"
168
- :slot="item.dataIndex"
169
- slot-scope="text, record, index">
170
- <template v-if="tableContext.isEditMode && getFromItem(item.dataIndex,text, record, index)">
171
- <x-form-item
172
- class="innerTable"
173
- :style="{ paddingTop: 0, paddingBottom: 0, paddingLeft: 0, paddingRight: 0 }"
174
- :form="record"
175
- :attr="getFromItem(item.dataIndex,text, record, index)"
176
- :service-name="tableContext.serviceName"
177
- mode="新增/修改"
178
- :env="tableContext.env"
179
- :setForm="(obj)=>tableContext.setForm(record,obj)"
180
- @rowChoose="(row, attr, callback) => tableContext.rowChoose(row, attr, callback, record)"
181
- :showLabel="false"
182
- :key="'editRow-' + c_index"
183
- />
184
- </template>
185
- <span v-else-if="item.slotType === 'rate'" :key="'rate-' + c_index">
186
- <x-rate
187
- :value="text"
188
- :disabled="true"
189
- :allow-half="item.allowHalf"
190
- :icon="item.rateIcon"
191
- :max-count="item.maxCount"
192
- style="zoom:0.9"/>
193
- </span>
194
- <span v-else-if="item.slotType === 'index'" :key="'index-' + c_index">
195
- {{ index + 1 }}
196
- </span>
197
- <CustomFuncCel
198
- :text="text"
199
- :record="text"
200
- :index="index"
201
- :item="item"
202
- :localDataSource="activeTable?.localDataSource"
203
- v-else-if="item.slotCustomFunction"
204
- :key="'customJs-' + c_index"></CustomFuncCel>
205
- <span v-else-if="item.slotType === 'link'" :key="'link-' + c_index">
206
- <a @click="tableContext.columnClick(item.dataIndex,text,record)">{{ text }}</a>
207
- </span>
208
- <span v-else-if="item.slotType === 'gotoUserDetail'" :key="'gotoUserDetail-' + c_index">
209
- <a @click="tableContext.gotoUserDetail(item.dataIndex,text,record)">{{ text }}</a>
210
- </span>
211
- <span v-else-if="['ellipsis','fixed'].includes(item.slotType)" :key="'ellipsis-' + c_index">
212
- <!-- <ellipsis :length="item.slotValue" tooltip>{{ text === '' ? '--' : text }}</ellipsis> -->
213
- <span>{{ text === '' ? '--' : text }}</span>
214
- </span>
215
- <span v-else-if="item.slotType === 'progress'" :key="'progress-' + c_index">
216
- <!-- websocket-id (配置名称-字段名称-用户id-数据行id) -->
217
- <x-web-socket-progress
218
- v-if="item.webSocket"
219
- :key="`${tableContext.requestParameters?.pageNo || 1}-${item.dataIndex}-${record[tableContext.rowKey] || index}`"
220
- :websocket-id="`${queryParamsName}-${item.dataIndex}-${currUser.id}-${record[tableContext.rowKey] || index}`"
221
- :initial-value="text || 0"
222
- @progress-updated="(data) => handleProgressUpdated(data, record, item.dataIndex)"
223
- />
224
- <!-- 表格进度组件 -->
225
- <a-progress v-else :percent="text" status="active" style="padding-right: 20px;" />
226
- </span>
227
- <span v-else-if="item.slotType === 'badge'" :key="'badge-' + c_index">
228
- <x-badge
229
- :service-name="tableContext.serviceName"
230
- :env="tableContext.env"
231
- v-if="text !== null && text !== undefined"
232
- :badge-key="item.slotKeyMap"
233
- :value="text"/>
234
- </span>
235
- <span v-else-if="item.slotType === 'date'" :key="'date-' + c_index">
236
- {{ format(text, 'yyyy-MM-dd') }}
237
- </span>
238
- <span v-else-if="item.slotType === 'dateTime'" :key="'dateTime-' + c_index">
239
- {{ format(text, 'yyyy-MM-dd hh:mm:ss') }}
240
- </span>
241
- <span v-else-if="item.slotType === 'towDecimal'" :key="'towDecimal-' + c_index">
242
- {{ numberFormat(text, 2) }}
243
- </span>
244
- <span v-else-if="item.slotType === 'fourDecimal'" :key="'fourDecimal-' + c_index">
245
- {{ numberFormat(text, 4) }}
246
- </span>
247
- <span v-else-if="item.slotType === 'int'" :key="'int-' + c_index">
248
- {{ numberFormat(text, 0) }}
249
- </span>
250
- <span v-else-if="item.slotType === 'action'" :key="'action-' + c_index">
251
- <template v-if="item.actionArr && item.actionArr.length > 0">
252
- <a-dropdown placement="bottomCenter" :getPopupContainer=" triggerNode => { return triggerNode.parentNode } ">
253
- <a class="ant-dropdown-link" @click="e => e.preventDefault()">
254
- {{ item.scopedSlots?.customRender || item.slotValue }} <a-icon type="down"/>
255
- </a>
256
- <a-menu slot="overlay" style="min-width: 60px">
257
- <a-menu-item
258
- v-for="(action_item, actionIndex) in item.actionArr"
259
- :key="actionIndex"
260
- v-show="!action_item.customFunction || tableContext.customFunctionShow(action_item.customFunction,record,c_index)">
261
- <a
262
- style="text-align: center"
263
- @click="tableContext.action(record, item.dataIndex, action_item.func)"
264
- >{{ action_item.text }}</a>
265
- </a-menu-item>
266
- </a-menu>
267
- </a-dropdown>
268
- </template>
269
- <template v-if="!item.actionArr || item.actionArr.length === 0">
270
- <a @click="tableContext.action(record, item.dataIndex,'action', index)">{{ item.slotValue }}</a>
271
- </template>
272
- </span>
273
- </template>
274
- <template slot="footer">
275
- <slot
276
- name="footer"
277
- :selectedRowKeys="tableContext.selectedRowKeys"
278
- :selectedRows="tableContext.selectedRows"></slot>
279
- </template>
280
- </s-table>
281
- </template>
282
-
283
- <script>
284
- import { Ellipsis, STable } from '@vue2-client/components'
285
- import { formatDate } from '@vue2-client/utils/util'
286
- import XBadge from '@vue2-client/base-client/components/common/XBadge'
287
- import XFormItem from '@vue2-client/base-client/components/common/XForm/XFormItem'
288
- import CustomFuncCel from '@vue2-client/base-client/components/common/XTable/CustomFuncCel.vue'
289
- import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
290
- import XRate from '@vue2-client/base-client/components/common/XRate/index.vue'
291
- import XWebSocketProgress from '@vue2-client/base-client/components/common/XWebSocketProgress'
292
- import VueDraggableResizable from 'vue-draggable-resizable'
293
- import { mapState } from 'vuex'
294
-
295
- export default {
296
- name: 'XTableWrapper',
297
- components: {
298
- Ellipsis,
299
- STable,
300
- XBadge,
301
- XFormItem,
302
- XRate,
303
- CustomFuncCel,
304
- XWebSocketProgress,
305
- VueDraggableResizable
306
- },
307
- data () {
308
- return {
309
- isDragging: false, // 添加拖拽状态标记
310
- // eslint-disable-next-line vue/no-reserved-keys
311
- _rafId: null // 添加requestAnimationFrame ID标记
312
- }
313
- },
314
- computed: {
315
- ...mapState('account', { currUser: 'user' }),
316
- localDataSource () {
317
- return this.activeTable?.localDataSource
318
- },
319
- // 获取当前活动的表格实例
320
- activeTable () {
321
- return this.tableContext.expandedGrid ? this.$refs.expandableTable : this.$refs.simpleTable
322
- },
323
- realTableColumns () {
324
- console.warn('====', this.tableContext.tableColumns)
325
- return this.tableContext.tableColumns.filter(item => item.slotType !== 'action' || !this.disableAction).map((item) => {
326
- // todo delete 后台现在也是200 不过要清楚配置缓存 这里是为了让不清缓存也能达到争取的效果
327
- // if (item.slotType === 'date' || item.slotType === 'dateTime') {
328
- // item.width = 200
329
- // }
330
- if (['ellipsis', 'badge', 'towDecimal', 'date', 'dateTime', 'fourDecimal', 'int'].includes(item.slotType)) {
331
- item.ellipsis = true
332
- }
333
- return item
334
- })
335
- },
336
- components () {
337
- return {
338
- header: {
339
- cell: (h, props, children) => {
340
- const { key, ...restProps } = props
341
- // 此处的this.realTableColumns 是定义的table的表头属性变量
342
- const col = this.realTableColumns.find((col) => {
343
- const k = col.dataIndex || col.key
344
- return k === key
345
- })
346
- if (!col || !col.width || col.slotType === 'action') {
347
- if (children) {
348
- return h('th', { ...restProps }, [...children])
349
- } else {
350
- return h('th', { ...restProps })
351
- }
352
- }
353
-
354
- // 创建一个防止点击排序的容器
355
- const preventSortProps = {
356
- style: {
357
- position: 'absolute',
358
- right: 0,
359
- top: 0,
360
- width: '20px',
361
- height: '100%',
362
- zIndex: 10
363
- },
364
- on: {
365
- mousedown: (e) => {
366
- e.stopPropagation()
367
- e.preventDefault()
368
- this.isDragging = true
369
- }
370
- }
371
- }
372
-
373
- const dragProps = {
374
- key: col.dataIndex || col.key,
375
- class: 'table-draggable-handle',
376
- attrs: {
377
- w: 10,
378
- x: col.width,
379
- z: 1,
380
- axis: 'x',
381
- draggable: true,
382
- resizable: false,
383
- },
384
- on: {
385
- dragging: (x, y) => {
386
- // 使用requestAnimationFrame优化性能,减少卡顿
387
- if (!this._rafId) {
388
- this._rafId = requestAnimationFrame(() => {
389
- col.width = Math.max(x, 50) // 设置最小列宽为50px
390
- this.isDragging = true // 设置拖拽状态
391
- this._rafId = null
392
- })
393
- }
394
- },
395
- mousedown: (e) => {
396
- // 阻止事件冒泡,防止触发排序
397
- e.stopPropagation()
398
- e.preventDefault()
399
- this.isDragging = true // 设置拖拽状态
400
- },
401
- dragstop: () => {
402
- // 清除可能存在的动画帧请求
403
- if (this._rafId) {
404
- cancelAnimationFrame(this._rafId)
405
- this._rafId = null
406
- }
407
-
408
- // 拖拽结束时,延迟重置拖拽状态,以防止排序被触发
409
- setTimeout(() => {
410
- this.isDragging = false
411
- }, 100)
412
- }
413
- },
414
- nativeOn: {
415
- mousedown: (e) => {
416
- e.stopPropagation()
417
- e.preventDefault()
418
- this.isDragging = true // 设置拖拽状态
419
- }
420
- }
421
- }
422
-
423
- const preventSort = h('div', preventSortProps)
424
- const drag = h('vue-draggable-resizable', { ...dragProps })
425
-
426
- // 修改th的点击事件,在拖拽状态下阻止排序
427
- const newRestProps = { ...restProps }
428
- const originalClick = newRestProps.on && newRestProps.on.click
429
- if (originalClick) {
430
- newRestProps.on = {
431
- ...newRestProps.on,
432
- click: (e) => {
433
- if (this.isDragging) {
434
- e.stopPropagation()
435
- e.preventDefault()
436
- return
437
- }
438
- originalClick(e)
439
- }
440
- }
441
- }
442
-
443
- if (children) {
444
- return h('th', { ...newRestProps, class: 'resize-table-th' }, [...children, preventSort, drag])
445
- } else {
446
- return h('th', { ...newRestProps, class: 'resize-table-th' }, [preventSort, drag])
447
- }
448
- },
449
- }
450
- }
451
- }
452
- },
453
- props: {
454
- // 查询配置文件名
455
- queryParamsName: {
456
- type: String,
457
- default: () => {
458
- return ''
459
- }
460
- },
461
- loadSelectedData: {
462
- type: Boolean,
463
- required: false,
464
- default: false
465
- },
466
- disableAction: {
467
- type: Boolean,
468
- default: false
469
- }
470
- },
471
- inject: ['tableContext'],
472
- methods: {
473
- handleRowClick (record) {
474
- this.$emit('rowClick', record)
475
- },
476
- beforeDataChange (record) {
477
- this.$emit('beforeDataChange', record)
478
- },
479
- onExpand (expanded, record) {
480
- this.$emit('expand', expanded, record)
481
- },
482
- setLocalDataSource (data) {
483
- this.activeTable?.setLocalDataSource(data)
484
- },
485
- loadData () {
486
- if (this.loadSelectedData) {
487
- return this.loadSelectedDataGen
488
- } else {
489
- return this.tableContext.loadData
490
- }
491
- },
492
- loadSelectedDataGen (requestParameters) {
493
- console.log('loadSelectedDataGen', {
494
- pageNo: requestParameters?.pageNo,
495
- pageSize: requestParameters?.pageSize
496
- })
497
-
498
- const { pageNo = 1, pageSize = 10 } = requestParameters || {}
499
- const startIndex = (pageNo - 1) * pageSize
500
- const endIndex = startIndex + pageSize
501
- const paginatedData = this.tableContext.selectedRows.slice(startIndex, endIndex)
502
-
503
- return new Promise((resolve) => {
504
- resolve({
505
- data: paginatedData,
506
- pageNo,
507
- pageSize,
508
- totalPage: Math.ceil(this.tableContext.selectedRows.length / pageSize),
509
- totalCount: this.tableContext.selectedRows.length
510
- })
511
- })
512
- },
513
- updateSelect (selectedRowKeys, selectedRows) {
514
- this.activeTable?.updateSelect(selectedRowKeys, selectedRows)
515
- },
516
- clearSelected () {
517
- this.activeTable?.clearSelected()
518
- },
519
- refresh (bool) {
520
- this.activeTable?.refresh(bool)
521
- },
522
-
523
- /**
524
- * 格式化日期
525
- * @param date 日期字符串
526
- * @param format 格式化方式
527
- */
528
- format (date, format) {
529
- return formatDate(date, format)
530
- },
531
- /**
532
- * 格式化数字
533
- * @param number string 或者 number
534
- * @param decimalPlaces 小数位数
535
- */
536
- numberFormat (number, decimalPlaces = 2) {
537
- const value = parseFloat(number)
538
- if (!isNaN(value)) {
539
- return value.toFixed(decimalPlaces)
540
- } else {
541
- return ''
542
- }
543
- },
544
- getFromItem (model, text, record, index) {
545
- const aa = this.tableContext.formItems.reduce((acc, item) => {
546
- if (item.type === 'group') {
547
- const foundItem = item.groupItems.find(_item => _item.model === model && _item.editRow)
548
- if (foundItem) {
549
- acc = foundItem
550
- }
551
- } else if (item.model === model && item.editRow) {
552
- acc = item
553
- }
554
- return acc
555
- }, null)
556
- if (aa) {
557
- const tempConfig = JSON.parse(JSON.stringify(aa))
558
- // 如果找到了字段
559
- const ColumnIndex = this.realTableColumns.findIndex(item => item.dataIndex === model)
560
- // 并且表单项是日期框
561
- if (ColumnIndex !== -1 && ['yearPicker', 'monthPicker', 'datePicker', 'rangePicker'].includes(tempConfig.type)) {
562
- // 修改他的列宽
563
- this.realTableColumns[ColumnIndex].width = 220
564
- }
565
- // 如果有检验规则检验是数字
566
- if (ColumnIndex !== -1 && ['number', 'integer', 'float'].includes(tempConfig?.rule?.type)) {
567
- // 修改他的列宽
568
- tempConfig.numberInput = true
569
- }
570
- if (tempConfig.editRowShowFunc) {
571
- if (executeStrFunctionByContext(this.tableContext, tempConfig.editRowShowFunc, [text, record, index, tempConfig])) {
572
- return tempConfig
573
- }
574
- } else {
575
- return tempConfig
576
- }
577
- }
578
- return false
579
- },
580
- handleResizeColumn (w, col) {
581
- col.width = w
582
- },
583
-
584
- /**
585
- * 处理进度更新事件
586
- * @param {Object} data 进度数据
587
- * @param {Object} record 行数据
588
- * @param {String} dataIndex 列字段名
589
- */
590
- handleProgressUpdated (data, record, dataIndex) {
591
- // 更新行数据中的进度值
592
- if (record && dataIndex) {
593
- this.$set(record, dataIndex, data.value)
594
- }
595
- },
596
- }
597
- }
598
- </script>
599
-
600
- <style scoped lang="less">
601
- // 修复滚动条容器不影响表头高度
602
- :deep(.ant-table-hide-scrollbar) {
603
- scrollbar-color: auto !important;
604
- }
605
-
606
- // 修复表头间距
607
- :deep(.ant-table-fixed-header .ant-table-scroll .ant-table-header) {
608
- margin-bottom: -6px !important;
609
- }
610
-
611
- // 关键修复:让表头单元格可以超出边界显示
612
- :deep(.ant-table-thead > tr > th) {
613
- overflow: visible !important;
614
- }
615
- </style>
616
- <style>
617
- /* vue-draggable-resizable 拖动手柄样式 */
618
- .table-draggable-handle {
619
- height: 100% !important;
620
- left: auto !important;
621
- right: 0;
622
- cursor: col-resize;
623
- touch-action: none;
624
- border: none;
625
- position: absolute;
626
- transform: none !important;
627
- bottom: 0;
628
- width: 10px !important; /* 减小到10px */
629
- z-index: 99 !important; /* 提高z-index */
630
- }
631
-
632
- /* 拖动手柄的分隔线 */
633
- .table-draggable-handle::after {
634
- content: "";
635
- position: absolute;
636
- top: 50%;
637
- height: 20px;
638
- width: 2px;
639
- background-color: #e8e8e8;
640
- transition: background-color 0.2s;
641
- transform: translateY(-50%);
642
- right: 0;
643
- }
644
-
645
- /* 悬停效果 - 只改变颜色 */
646
- .table-draggable-handle:hover::after {
647
- background-color: #1890ff;
648
- }
649
-
650
- /* 拖动时的效果 */
651
- .table-draggable-handle:active::after {
652
- background-color: #096dd9;
653
- }
654
-
655
- /* 表头单元格样式 */
656
- .resize-table-th {
657
- position: relative;
658
- overflow: visible !important; /* 确保内容不被裁剪 */
659
- }
660
-
661
- /* 表头单元格悬停时的手柄高亮 */
662
- .resize-table-th:hover .table-draggable-handle::after {
663
- background-color: rgba(24, 144, 255, 0.6);
664
- }
665
- </style>
1
+ <template>
2
+ <!-- 当expandedGrid存在时渲染带有expandedRowRender的表格 -->
3
+ <s-table
4
+ v-if="tableContext.expandedGrid"
5
+ ref="expandableTable"
6
+ :id="tableContext.uniqueId"
7
+ :alert="true"
8
+ :columns="realTableColumns"
9
+ :data="loadData()"
10
+ :rowKey="tableContext.rowKey"
11
+ :showSummary="tableContext.showSummary"
12
+ :rowSelection="tableContext.rowSelection"
13
+ :scroll="{ x: tableContext.scrollXWidth, y: tableContext.scrollYHeight }"
14
+ :showPagination="tableContext.showPagination"
15
+ :hidePagination="tableContext.simpleMode"
16
+ :customPagination="tableContext.customPagination"
17
+ :showSelected="!tableContext.simpleMode"
18
+ :pageSize="tableContext.simpleMode ? 1000 : undefined"
19
+ :pageMaxSize="tableContext.pageMaxSize"
20
+ :setScrollYHeight="tableContext.setScrollYHeight"
21
+ :selectRowMode="tableContext.selectRowMode"
22
+ :size="tableContext.tableSize"
23
+ :components="components"
24
+ :rowStyleFunction="tableContext.rowStyleFunction"
25
+ @beforeDataChange="beforeDataChange"
26
+ @expand="onExpand"
27
+ @rowClick="handleRowClick"
28
+ >
29
+ <template
30
+ v-for="(item, c_index) in realTableColumns"
31
+ :slot="item.dataIndex"
32
+ slot-scope="text, record, index">
33
+ <template v-if="tableContext.isEditMode && getFromItem(item.dataIndex,text, record, index)">
34
+ <x-form-item
35
+ class="innerTable"
36
+ :style="{ paddingTop: 0, paddingBottom: 0, paddingLeft: 0, paddingRight: 0 }"
37
+ :form="record"
38
+ :attr="getFromItem(item.dataIndex,text, record, index)"
39
+ :service-name="tableContext.serviceName"
40
+ mode="新增/修改"
41
+ :env="tableContext.env"
42
+ :setForm="(obj)=>tableContext.setForm(record,obj)"
43
+ @rowChoose="(row, attr, callback) => tableContext.rowChoose(row, attr, callback, record)"
44
+ :showLabel="false"
45
+ :key="'editRow-' + c_index"
46
+ />
47
+ </template>
48
+ <span v-else-if="item.slotType === 'rate'" :key="'rate-' + c_index">
49
+ <x-rate
50
+ :value="text"
51
+ :disabled="true"
52
+ :allow-half="item.allowHalf"
53
+ :icon="item.rateIcon"
54
+ :max-count="item.maxCount"
55
+ style="zoom:0.9"/>
56
+ </span>
57
+ <span v-else-if="item.slotType === 'index'" :key="'index-' + c_index">
58
+ {{ index + 1 }}
59
+ </span>
60
+ <CustomFuncCel
61
+ :text="text"
62
+ :record="text"
63
+ :index="index"
64
+ :item="item"
65
+ :localDataSource="activeTable?.localDataSource"
66
+ v-else-if="item.slotCustomFunction"
67
+ :key="'customJs-' + c_index"></CustomFuncCel>
68
+ <span v-else-if="item.slotType === 'link'" :key="'link-' + c_index">
69
+ <a @click="tableContext.columnClick(item.dataIndex,text,record)">{{ text }}</a>
70
+ </span>
71
+ <span v-else-if="item.slotType === 'gotoUserDetail'" :key="'gotoUserDetail-' + c_index">
72
+ <a @click="tableContext.gotoUserDetail(item.dataIndex,text,record)">{{ text }}</a>
73
+ </span>
74
+ <span v-else-if="['ellipsis','fixed'].includes(item.slotType)" :key="'ellipsis-' + c_index">
75
+ <span>{{ text === '' ? '--' : text }}</span>
76
+ </span>
77
+ <span v-else-if="item.slotType === 'badge'" :key="'badge-' + c_index">
78
+ <x-badge
79
+ :service-name="tableContext.serviceName"
80
+ :env="tableContext.env"
81
+ v-if="text !== null && text !== undefined"
82
+ :badge-key="item.slotKeyMap"
83
+ :value="text"/>
84
+ </span>
85
+ <span v-else-if="item.slotType === 'date'" :key="'date-' + c_index">
86
+ {{ format(text, 'yyyy-MM-dd') }}
87
+ </span>
88
+ <span v-else-if="item.slotType === 'dateTime'" :key="'dateTime-' + c_index">
89
+ {{ format(text, 'yyyy-MM-dd hh:mm:ss') }}
90
+ </span>
91
+ <span v-else-if="item.slotType === 'towDecimal'" :key="'towDecimal-' + c_index">
92
+ {{ numberFormat(text, 2) }}
93
+ </span>
94
+ <span v-else-if="item.slotType === 'fourDecimal'" :key="'fourDecimal-' + c_index">
95
+ {{ numberFormat(text, 4) }}
96
+ </span>
97
+ <span v-else-if="item.slotType === 'int'" :key="'int-' + c_index">
98
+ {{ numberFormat(text, 0) }}
99
+ </span>
100
+ <span v-else-if="item.slotType === 'action'" :key="'action-' + c_index">
101
+ <template v-if="item.actionArr && item.actionArr.length > 0">
102
+ <a-dropdown placement="bottomCenter" :getPopupContainer=" triggerNode => { return triggerNode.parentNode } ">
103
+ <a class="ant-dropdown-link" @click="e => e.preventDefault()">
104
+ {{ item.scopedSlots?.customRender || item.slotValue }} <a-icon type="down"/>
105
+ </a>
106
+ <a-menu slot="overlay" style="min-width: 60px">
107
+ <a-menu-item
108
+ v-for="(action_item, actionIndex) in item.actionArr"
109
+ :key="actionIndex"
110
+ v-show="!action_item.customFunction || tableContext.customFunctionShow(action_item.customFunction,record,c_index)">
111
+ <a
112
+ style="text-align: center"
113
+ @click="tableContext.action(record, item.dataIndex, action_item.func)"
114
+ >{{ action_item.text }}</a>
115
+ </a-menu-item>
116
+ </a-menu>
117
+ </a-dropdown>
118
+ </template>
119
+ <template v-if="!item.actionArr || item.actionArr.length === 0">
120
+ <a @click="tableContext.action(record, item.dataIndex,'action', index)">{{ item.slotValue }}</a>
121
+ </template>
122
+ </span>
123
+ </template>
124
+ <template slot="expandedRowRender" slot-scope="record">
125
+ <slot
126
+ name="expandedRowRender"
127
+ :selectedRowKeys="tableContext.selectedRowKeys"
128
+ :selectedRows="tableContext.selectedRows"
129
+ :record="record"
130
+ ></slot>
131
+ </template>
132
+ <template slot="footer">
133
+ <slot
134
+ name="footer"
135
+ :selectedRowKeys="tableContext.selectedRowKeys"
136
+ :selectedRows="tableContext.selectedRows"></slot>
137
+ </template>
138
+ </s-table>
139
+
140
+ <!-- 当expandedGrid不存在时渲染不带expandedRowRender的表格 -->
141
+ <s-table
142
+ v-else
143
+ ref="simpleTable"
144
+ :id="tableContext.uniqueId"
145
+ :alert="true"
146
+ :columns="realTableColumns"
147
+ :data="loadData()"
148
+ :rowKey="tableContext.rowKey"
149
+ :showSummary="tableContext.showSummary"
150
+ :rowSelection="tableContext.rowSelection"
151
+ :scroll="{ x: tableContext.scrollXWidth, y: tableContext.scrollYHeight }"
152
+ :showPagination="tableContext.showPagination"
153
+ :hidePagination="tableContext.simpleMode"
154
+ :customPagination="tableContext.customPagination"
155
+ :showSelected="!tableContext.simpleMode"
156
+ :pageSize="tableContext.simpleMode ? 1000 : undefined"
157
+ :pageMaxSize="tableContext.pageMaxSize"
158
+ :setScrollYHeight="tableContext.setScrollYHeight"
159
+ :selectRowMode="tableContext.selectRowMode"
160
+ :size="tableContext.tableSize"
161
+ :components="components"
162
+ :rowStyleFunction="tableContext.rowStyleFunction"
163
+ @rowClick="handleRowClick"
164
+ @beforeDataChange="beforeDataChange"
165
+ >
166
+ <template
167
+ v-for="(item, c_index) in realTableColumns"
168
+ :slot="item.dataIndex"
169
+ slot-scope="text, record, index">
170
+ <template v-if="tableContext.isEditMode && getFromItem(item.dataIndex,text, record, index)">
171
+ <x-form-item
172
+ class="innerTable"
173
+ :style="{ paddingTop: 0, paddingBottom: 0, paddingLeft: 0, paddingRight: 0 }"
174
+ :form="record"
175
+ :attr="getFromItem(item.dataIndex,text, record, index)"
176
+ :service-name="tableContext.serviceName"
177
+ mode="新增/修改"
178
+ :env="tableContext.env"
179
+ :setForm="(obj)=>tableContext.setForm(record,obj)"
180
+ @rowChoose="(row, attr, callback) => tableContext.rowChoose(row, attr, callback, record)"
181
+ :showLabel="false"
182
+ :key="'editRow-' + c_index"
183
+ />
184
+ </template>
185
+ <span v-else-if="item.slotType === 'rate'" :key="'rate-' + c_index">
186
+ <x-rate
187
+ :value="text"
188
+ :disabled="true"
189
+ :allow-half="item.allowHalf"
190
+ :icon="item.rateIcon"
191
+ :max-count="item.maxCount"
192
+ style="zoom:0.9"/>
193
+ </span>
194
+ <span v-else-if="item.slotType === 'index'" :key="'index-' + c_index">
195
+ {{ index + 1 }}
196
+ </span>
197
+ <CustomFuncCel
198
+ :text="text"
199
+ :record="text"
200
+ :index="index"
201
+ :item="item"
202
+ :localDataSource="activeTable?.localDataSource"
203
+ v-else-if="item.slotCustomFunction"
204
+ :key="'customJs-' + c_index"></CustomFuncCel>
205
+ <span v-else-if="item.slotType === 'link'" :key="'link-' + c_index">
206
+ <a @click="tableContext.columnClick(item.dataIndex,text,record)">{{ text }}</a>
207
+ </span>
208
+ <span v-else-if="item.slotType === 'gotoUserDetail'" :key="'gotoUserDetail-' + c_index">
209
+ <a @click="tableContext.gotoUserDetail(item.dataIndex,text,record)">{{ text }}</a>
210
+ </span>
211
+ <span v-else-if="['ellipsis','fixed'].includes(item.slotType)" :key="'ellipsis-' + c_index">
212
+ <!-- <ellipsis :length="item.slotValue" tooltip>{{ text === '' ? '--' : text }}</ellipsis> -->
213
+ <span>{{ text === '' ? '--' : text }}</span>
214
+ </span>
215
+ <span v-else-if="item.slotType === 'progress'" :key="'progress-' + c_index">
216
+ <!-- websocket-id (配置名称-字段名称-用户id-数据行id) -->
217
+ <x-web-socket-progress
218
+ v-if="item.webSocket"
219
+ :key="`${tableContext.requestParameters?.pageNo || 1}-${item.dataIndex}-${record[tableContext.rowKey] || index}`"
220
+ :websocket-id="`${queryParamsName}-${item.dataIndex}-${currUser.id}-${record[tableContext.rowKey] || index}`"
221
+ :initial-value="text || 0"
222
+ @progress-updated="(data) => handleProgressUpdated(data, record, item.dataIndex)"
223
+ />
224
+ <!-- 表格进度组件 -->
225
+ <a-progress v-else :percent="text" status="active" style="padding-right: 20px;" />
226
+ </span>
227
+ <span v-else-if="item.slotType === 'badge'" :key="'badge-' + c_index">
228
+ <x-badge
229
+ :service-name="tableContext.serviceName"
230
+ :env="tableContext.env"
231
+ v-if="text !== null && text !== undefined"
232
+ :badge-key="item.slotKeyMap"
233
+ :value="text"/>
234
+ </span>
235
+ <span v-else-if="item.slotType === 'date'" :key="'date-' + c_index">
236
+ {{ format(text, 'yyyy-MM-dd') }}
237
+ </span>
238
+ <span v-else-if="item.slotType === 'dateTime'" :key="'dateTime-' + c_index">
239
+ {{ format(text, 'yyyy-MM-dd hh:mm:ss') }}
240
+ </span>
241
+ <span v-else-if="item.slotType === 'towDecimal'" :key="'towDecimal-' + c_index">
242
+ {{ numberFormat(text, 2) }}
243
+ </span>
244
+ <span v-else-if="item.slotType === 'fourDecimal'" :key="'fourDecimal-' + c_index">
245
+ {{ numberFormat(text, 4) }}
246
+ </span>
247
+ <span v-else-if="item.slotType === 'int'" :key="'int-' + c_index">
248
+ {{ numberFormat(text, 0) }}
249
+ </span>
250
+ <span v-else-if="item.slotType === 'action'" :key="'action-' + c_index">
251
+ <template v-if="item.actionArr && item.actionArr.length > 0">
252
+ <a-dropdown
253
+ placement="bottomRight"
254
+ :overlayStyle="{
255
+ whiteSpace: 'nowrap',
256
+ maxWidth: '250px',
257
+ overflow: 'hidden',
258
+ textOverflow: 'ellipsis'
259
+ }"
260
+ >
261
+ <a class="ant-dropdown-link" @click="e => e.preventDefault()">
262
+ {{ item.scopedSlots?.customRender || item.slotValue }} <a-icon type="down"/>
263
+ </a>
264
+ <a-menu slot="overlay" style="min-width: 60px">
265
+ <a-menu-item
266
+ v-for="(action_item, actionIndex) in item.actionArr"
267
+ :key="actionIndex"
268
+ v-show="!action_item.customFunction || tableContext.customFunctionShow(action_item.customFunction,record,c_index)">
269
+ <a
270
+ style="text-align: center"
271
+ @click="tableContext.action(record, item.dataIndex, action_item.func)"
272
+ >{{ action_item.text }}</a>
273
+ </a-menu-item>
274
+ </a-menu>
275
+ </a-dropdown>
276
+ </template>
277
+ <template v-if="!item.actionArr || item.actionArr.length === 0">
278
+ <a @click="tableContext.action(record, item.dataIndex,'action', index)">{{ item.slotValue }}</a>
279
+ </template>
280
+ </span>
281
+ </template>
282
+ <template slot="footer">
283
+ <slot
284
+ name="footer"
285
+ :selectedRowKeys="tableContext.selectedRowKeys"
286
+ :selectedRows="tableContext.selectedRows"></slot>
287
+ </template>
288
+ </s-table>
289
+ </template>
290
+
291
+ <script>
292
+ import { Ellipsis, STable } from '@vue2-client/components'
293
+ import { formatDate } from '@vue2-client/utils/util'
294
+ import XBadge from '@vue2-client/base-client/components/common/XBadge'
295
+ import XFormItem from '@vue2-client/base-client/components/common/XForm/XFormItem'
296
+ import CustomFuncCel from '@vue2-client/base-client/components/common/XTable/CustomFuncCel.vue'
297
+ import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
298
+ import XRate from '@vue2-client/base-client/components/common/XRate/index.vue'
299
+ import XWebSocketProgress from '@vue2-client/base-client/components/common/XWebSocketProgress'
300
+ import VueDraggableResizable from 'vue-draggable-resizable'
301
+ import { mapState } from 'vuex'
302
+
303
+ export default {
304
+ name: 'XTableWrapper',
305
+ components: {
306
+ Ellipsis,
307
+ STable,
308
+ XBadge,
309
+ XFormItem,
310
+ XRate,
311
+ CustomFuncCel,
312
+ XWebSocketProgress,
313
+ VueDraggableResizable
314
+ },
315
+ data () {
316
+ return {
317
+ isDragging: false, // 添加拖拽状态标记
318
+ // eslint-disable-next-line vue/no-reserved-keys
319
+ _rafId: null // 添加requestAnimationFrame ID标记
320
+ }
321
+ },
322
+ computed: {
323
+ ...mapState('account', { currUser: 'user' }),
324
+ localDataSource () {
325
+ return this.activeTable?.localDataSource
326
+ },
327
+ // 获取当前活动的表格实例
328
+ activeTable () {
329
+ return this.tableContext.expandedGrid ? this.$refs.expandableTable : this.$refs.simpleTable
330
+ },
331
+ realTableColumns () {
332
+ console.warn('====', this.tableContext.tableColumns)
333
+ return this.tableContext.tableColumns.filter(item => item.slotType !== 'action' || !this.disableAction).map((item) => {
334
+ // todo delete 后台现在也是200 不过要清楚配置缓存 这里是为了让不清缓存也能达到争取的效果
335
+ // if (item.slotType === 'date' || item.slotType === 'dateTime') {
336
+ // item.width = 200
337
+ // }
338
+ if (['ellipsis', 'badge', 'towDecimal', 'date', 'dateTime', 'fourDecimal', 'int'].includes(item.slotType)) {
339
+ item.ellipsis = true
340
+ }
341
+ return item
342
+ })
343
+ },
344
+ components () {
345
+ return {
346
+ header: {
347
+ cell: (h, props, children) => {
348
+ const { key, ...restProps } = props
349
+ // 此处的this.realTableColumns 是定义的table的表头属性变量
350
+ const col = this.realTableColumns.find((col) => {
351
+ const k = col.dataIndex || col.key
352
+ return k === key
353
+ })
354
+ if (!col || !col.width || col.slotType === 'action') {
355
+ if (children) {
356
+ return h('th', { ...restProps }, [...children])
357
+ } else {
358
+ return h('th', { ...restProps })
359
+ }
360
+ }
361
+
362
+ // 创建一个防止点击排序的容器
363
+ const preventSortProps = {
364
+ style: {
365
+ position: 'absolute',
366
+ right: 0,
367
+ top: 0,
368
+ width: '20px',
369
+ height: '100%',
370
+ zIndex: 10
371
+ },
372
+ on: {
373
+ mousedown: (e) => {
374
+ e.stopPropagation()
375
+ e.preventDefault()
376
+ this.isDragging = true
377
+ }
378
+ }
379
+ }
380
+
381
+ const dragProps = {
382
+ key: col.dataIndex || col.key,
383
+ class: 'table-draggable-handle',
384
+ attrs: {
385
+ w: 10,
386
+ x: col.width,
387
+ z: 1,
388
+ axis: 'x',
389
+ draggable: true,
390
+ resizable: false,
391
+ },
392
+ on: {
393
+ dragging: (x, y) => {
394
+ // 使用requestAnimationFrame优化性能,减少卡顿
395
+ if (!this._rafId) {
396
+ this._rafId = requestAnimationFrame(() => {
397
+ col.width = Math.max(x, 50) // 设置最小列宽为50px
398
+ this.isDragging = true // 设置拖拽状态
399
+ this._rafId = null
400
+ })
401
+ }
402
+ },
403
+ mousedown: (e) => {
404
+ // 阻止事件冒泡,防止触发排序
405
+ e.stopPropagation()
406
+ e.preventDefault()
407
+ this.isDragging = true // 设置拖拽状态
408
+ },
409
+ dragstop: () => {
410
+ // 清除可能存在的动画帧请求
411
+ if (this._rafId) {
412
+ cancelAnimationFrame(this._rafId)
413
+ this._rafId = null
414
+ }
415
+
416
+ // 拖拽结束时,延迟重置拖拽状态,以防止排序被触发
417
+ setTimeout(() => {
418
+ this.isDragging = false
419
+ }, 100)
420
+ }
421
+ },
422
+ nativeOn: {
423
+ mousedown: (e) => {
424
+ e.stopPropagation()
425
+ e.preventDefault()
426
+ this.isDragging = true // 设置拖拽状态
427
+ }
428
+ }
429
+ }
430
+
431
+ const preventSort = h('div', preventSortProps)
432
+ const drag = h('vue-draggable-resizable', { ...dragProps })
433
+
434
+ // 修改th的点击事件,在拖拽状态下阻止排序
435
+ const newRestProps = { ...restProps }
436
+ const originalClick = newRestProps.on && newRestProps.on.click
437
+ if (originalClick) {
438
+ newRestProps.on = {
439
+ ...newRestProps.on,
440
+ click: (e) => {
441
+ if (this.isDragging) {
442
+ e.stopPropagation()
443
+ e.preventDefault()
444
+ return
445
+ }
446
+ originalClick(e)
447
+ }
448
+ }
449
+ }
450
+
451
+ if (children) {
452
+ return h('th', { ...newRestProps, class: 'resize-table-th' }, [...children, preventSort, drag])
453
+ } else {
454
+ return h('th', { ...newRestProps, class: 'resize-table-th' }, [preventSort, drag])
455
+ }
456
+ },
457
+ }
458
+ }
459
+ }
460
+ },
461
+ props: {
462
+ // 查询配置文件名
463
+ queryParamsName: {
464
+ type: String,
465
+ default: () => {
466
+ return ''
467
+ }
468
+ },
469
+ loadSelectedData: {
470
+ type: Boolean,
471
+ required: false,
472
+ default: false
473
+ },
474
+ disableAction: {
475
+ type: Boolean,
476
+ default: false
477
+ }
478
+ },
479
+ inject: ['tableContext'],
480
+ methods: {
481
+ handleRowClick (record) {
482
+ this.$emit('rowClick', record)
483
+ },
484
+ beforeDataChange (record) {
485
+ this.$emit('beforeDataChange', record)
486
+ },
487
+ onExpand (expanded, record) {
488
+ this.$emit('expand', expanded, record)
489
+ },
490
+ setLocalDataSource (data) {
491
+ this.activeTable?.setLocalDataSource(data)
492
+ },
493
+ loadData () {
494
+ if (this.loadSelectedData) {
495
+ return this.loadSelectedDataGen
496
+ } else {
497
+ return this.tableContext.loadData
498
+ }
499
+ },
500
+ loadSelectedDataGen (requestParameters) {
501
+ console.log('loadSelectedDataGen', {
502
+ pageNo: requestParameters?.pageNo,
503
+ pageSize: requestParameters?.pageSize
504
+ })
505
+
506
+ const { pageNo = 1, pageSize = 10 } = requestParameters || {}
507
+ const startIndex = (pageNo - 1) * pageSize
508
+ const endIndex = startIndex + pageSize
509
+ const paginatedData = this.tableContext.selectedRows.slice(startIndex, endIndex)
510
+
511
+ return new Promise((resolve) => {
512
+ resolve({
513
+ data: paginatedData,
514
+ pageNo,
515
+ pageSize,
516
+ totalPage: Math.ceil(this.tableContext.selectedRows.length / pageSize),
517
+ totalCount: this.tableContext.selectedRows.length
518
+ })
519
+ })
520
+ },
521
+ updateSelect (selectedRowKeys, selectedRows) {
522
+ this.activeTable?.updateSelect(selectedRowKeys, selectedRows)
523
+ },
524
+ clearSelected () {
525
+ this.activeTable?.clearSelected()
526
+ },
527
+ refresh (bool) {
528
+ this.activeTable?.refresh(bool)
529
+ },
530
+
531
+ /**
532
+ * 格式化日期
533
+ * @param date 日期字符串
534
+ * @param format 格式化方式
535
+ */
536
+ format (date, format) {
537
+ return formatDate(date, format)
538
+ },
539
+ /**
540
+ * 格式化数字
541
+ * @param number string 或者 number
542
+ * @param decimalPlaces 小数位数
543
+ */
544
+ numberFormat (number, decimalPlaces = 2) {
545
+ const value = parseFloat(number)
546
+ if (!isNaN(value)) {
547
+ return value.toFixed(decimalPlaces)
548
+ } else {
549
+ return ''
550
+ }
551
+ },
552
+ getFromItem (model, text, record, index) {
553
+ const aa = this.tableContext.formItems.reduce((acc, item) => {
554
+ if (item.type === 'group') {
555
+ const foundItem = item.groupItems.find(_item => _item.model === model && _item.editRow)
556
+ if (foundItem) {
557
+ acc = foundItem
558
+ }
559
+ } else if (item.model === model && item.editRow) {
560
+ acc = item
561
+ }
562
+ return acc
563
+ }, null)
564
+ if (aa) {
565
+ const tempConfig = JSON.parse(JSON.stringify(aa))
566
+ // 如果找到了字段
567
+ const ColumnIndex = this.realTableColumns.findIndex(item => item.dataIndex === model)
568
+ // 并且表单项是日期框
569
+ if (ColumnIndex !== -1 && ['yearPicker', 'monthPicker', 'datePicker', 'rangePicker'].includes(tempConfig.type)) {
570
+ // 修改他的列宽
571
+ this.realTableColumns[ColumnIndex].width = 220
572
+ }
573
+ // 如果有检验规则检验是数字
574
+ if (ColumnIndex !== -1 && ['number', 'integer', 'float'].includes(tempConfig?.rule?.type)) {
575
+ // 修改他的列宽
576
+ tempConfig.numberInput = true
577
+ }
578
+ if (tempConfig.editRowShowFunc) {
579
+ if (executeStrFunctionByContext(this.tableContext, tempConfig.editRowShowFunc, [text, record, index, tempConfig])) {
580
+ return tempConfig
581
+ }
582
+ } else {
583
+ return tempConfig
584
+ }
585
+ }
586
+ return false
587
+ },
588
+ handleResizeColumn (w, col) {
589
+ col.width = w
590
+ },
591
+
592
+ /**
593
+ * 处理进度更新事件
594
+ * @param {Object} data 进度数据
595
+ * @param {Object} record 行数据
596
+ * @param {String} dataIndex 列字段名
597
+ */
598
+ handleProgressUpdated (data, record, dataIndex) {
599
+ // 更新行数据中的进度值
600
+ if (record && dataIndex) {
601
+ this.$set(record, dataIndex, data.value)
602
+ }
603
+ },
604
+ }
605
+ }
606
+ </script>
607
+
608
+ <style scoped lang="less">
609
+ /* 精确修复表头空白问题 */
610
+ :deep(.ant-table-fixed-header .ant-table-scroll .ant-table-header) {
611
+ margin-bottom: 0 !important;
612
+ overflow-x: hidden !important;
613
+ }
614
+ /* 统一表头行高和垂直对齐 */
615
+ :deep(.ant-table-thead > tr) {
616
+ height: 54px !important;
617
+ line-height: 54px !important;
618
+ }
619
+ :deep(.ant-table-thead > tr > th) {
620
+ padding: 0 16px !important;
621
+ vertical-align: middle !important;
622
+ border-bottom: 1px solid #f0f0f0;
623
+ }
624
+ </style>
625
+ <style>
626
+ /* vue-draggable-resizable 拖动手柄样式 */
627
+ .table-draggable-handle {
628
+ height: 100% !important;
629
+ left: auto !important;
630
+ right: 0;
631
+ cursor: col-resize;
632
+ touch-action: none;
633
+ border: none;
634
+ position: absolute;
635
+ transform: none !important;
636
+ bottom: 0;
637
+ width: 10px !important; /* 减小到10px */
638
+ z-index: 99 !important; /* 提高z-index */
639
+ }
640
+
641
+ /* 拖动手柄的分隔线 */
642
+ .table-draggable-handle::after {
643
+ content: "";
644
+ position: absolute;
645
+ top: 50%;
646
+ height: 20px;
647
+ width: 2px;
648
+ background-color: #e8e8e8;
649
+ transition: background-color 0.2s;
650
+ transform: translateY(-50%);
651
+ right: 0;
652
+ }
653
+
654
+ /* 悬停效果 - 只改变颜色 */
655
+ .table-draggable-handle:hover::after {
656
+ background-color: #1890ff;
657
+ }
658
+
659
+ /* 拖动时的效果 */
660
+ .table-draggable-handle:active::after {
661
+ background-color: #096dd9;
662
+ }
663
+
664
+ /* 表头单元格样式 */
665
+ .resize-table-th {
666
+ position: relative;
667
+ overflow: visible !important; /* 确保内容不被裁剪 */
668
+ }
669
+
670
+ /* 表头单元格悬停时的手柄高亮 */
671
+ .resize-table-th:hover .table-draggable-handle::after {
672
+ background-color: rgba(24, 144, 255, 0.6);
673
+ }
674
+ </style>