vue2-client 1.18.36 → 1.18.37

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