n20-common-lib 3.0.91 → 3.0.93

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,462 +0,0 @@
1
- <template>
2
- <div style="height: 100%; position: relative">
3
- <vxe-table
4
- ref="vxeTable"
5
- :key="colsKey"
6
- :align="'center'"
7
- :data="data"
8
- :height="height"
9
- :class="[{ 'cell-default-set--': cellDefault }, 'n20-table-pro']"
10
- :checkbox-config="{
11
- checkField: 'checked',
12
- checkMethod: forbidSelect,
13
- ...$attrs['checkbox-config'],
14
- ...$attrs.checkboxConfig
15
- }"
16
- show-header-overflow
17
- show-overflow
18
- :row-config="{
19
- isHover: true,
20
- useKey: true,
21
- ...$attrs.rowConfig,
22
- ...$attrs['row-config']
23
- }"
24
- :column-config="{
25
- resizable: true,
26
- useKey: true,
27
- ...$attrs.columnConfig,
28
- ...$attrs['column-config']
29
- }"
30
- :scroll-y="scrollY"
31
- :sort-config="{
32
- multiple: false,
33
- remote: true,
34
- trigger: 'cell',
35
- iconAsc: 'n20-icon-daoxu',
36
- iconDesc: 'n20-icon-shunxu',
37
- ...$attrs.sortConfig,
38
- ...$attrs['sort-config']
39
- }"
40
- :filter-config="{
41
- remote: true,
42
- iconNone: 'n20-icon-xiala-moren',
43
- iconMatch: 'n20-icon-xiala-moren'
44
- }"
45
- v-bind="Object.assign({ size: size }, $attrs, sizeBind)"
46
- v-on="$listeners"
47
- @sort-change="(val) => customSortMethod(val)"
48
- @filter-change="filterChange"
49
- @checkbox-change="handleSelectionChange"
50
- @cell-click="handleCellClick"
51
- >
52
- <template v-for="(item, i) in _columns">
53
- <slot v-if="item.slotName" :name="item.slotName" :column="item"></slot>
54
- <vxe-column
55
- v-else-if="item.render"
56
- :key="'vxe-table__render_' + i"
57
- v-bind="item"
58
- :formatter="item.formatter ? item.formatter : 'formatName'"
59
- :filters="item.filters"
60
- :filter-render="item.filters && item.filters.length > 0 ? { name: 'FilterInput' } : null"
61
- :title="item.label"
62
- :field="item.prop"
63
- >
64
- <template slot-scope="scope">
65
- <renderer :render-content="item.render" :scope="scope" />
66
- </template>
67
- </vxe-column>
68
- <vxe-column
69
- v-else-if="item.type === 'checkbox'"
70
- :key="'vxe-table-' + i"
71
- v-bind="item"
72
- :title="item.label"
73
- :field="item.prop"
74
- type="checkbox"
75
- width="50"
76
- :fixed="item.fixed || item.fixed === '' ? item.fixed : 'left'"
77
- >
78
- <template #header="{ $table, checked, indeterminate, disabled }">
79
- <span class="custom-checkbox" @click.stop="toggleAll($table, disabled)">
80
- <el-checkbox v-if="indeterminate" :key="key" :indeterminate="indeterminate" :disabled="disabled" />
81
- <el-checkbox v-else-if="checked" :key="key" :value="checked" :disabled="disabled" />
82
- <el-checkbox v-else :key="key" :value="checked" :disabled="disabled" />
83
- </span>
84
- </template>
85
- <template #checkbox="{ $table, row, checked, indeterminate, disabled }">
86
- <span class="custom-checkbox" @click.stop="toggleChecked($table, row, disabled)">
87
- <el-checkbox v-if="indeterminate" :key="key" :indeterminate="indeterminate" :disabled="disabled" />
88
- <el-checkbox v-else-if="checked" :key="key" :value="checked" :disabled="disabled" />
89
- <el-checkbox v-else :key="key" :value="checked" :disabled="disabled" />
90
- </span>
91
- </template>
92
- </vxe-column>
93
- <vxe-colgroup
94
- v-else-if="item.children && item.children.length > 0"
95
- :key="'vxe-colgroup-' + i"
96
- :title="item.label"
97
- >
98
- <vxe-column
99
- v-for="(subItem, i) in item.children"
100
- :key="'vxe-table-' + i"
101
- :formatter="subItem.formatter ? subItem.formatter : 'formatName'"
102
- :filters="subItem.filters"
103
- :filter-render="subItem.filterRender"
104
- :title="subItem.label"
105
- :field="subItem.prop"
106
- v-bind="subItem"
107
- :class-name="`${subItem.wrap && `vxe-table-custom-wrap`} ${subItem.bold && `font-w600`}`"
108
- />
109
- </vxe-colgroup>
110
- <vxe-column
111
- v-else
112
- :key="'vxe-table-' + i"
113
- :class-name="`${item.wrap && `vxe-table-custom-wrap`} ${item.bold && `font-w600`}`"
114
- :formatter="item.formatter ? item.formatter : 'formatName'"
115
- :filters="item.filters"
116
- :filter-render="item.filters && item.filters.length > 0 ? { name: 'FilterInput' } : null"
117
- :title="item.label"
118
- :field="item.prop"
119
- v-bind="item"
120
- />
121
- </template>
122
- <template #empty>
123
- <slot name="empty">
124
- <empty type="empty" :content="$lc('暂无数据')" :height="200" :width="200" />
125
- </slot>
126
- </template>
127
- </vxe-table>
128
- <tableSetSize v-if="showSetsize" :size="sizeC" v-bind="$attrs" @update:size="sizeUp" @resize="sizeSet" />
129
- </div>
130
- </template>
131
-
132
- <script>
133
- import empty from '../Empty'
134
- import tableSetSize from '../TableSetSize/index.vue'
135
- import { $lc } from '../../utils/i18n/index.js'
136
- import XEUtils from 'xe-utils'
137
- const renderer = {
138
- name: 'renderer',
139
- props: {
140
- renderContent: {
141
- type: Function
142
- },
143
- scope: {
144
- type: Object
145
- }
146
- },
147
- render(h) {
148
- return this.renderContent(h, this.scope.row, this.scope)
149
- }
150
- }
151
- export default {
152
- name: 'TablePro',
153
- components: {
154
- tableSetSize,
155
- empty,
156
- renderer
157
- },
158
- props: {
159
- scrollY: {
160
- type: Object,
161
- default: () => {
162
- return { enabled: true, oSize: 20, gt: 30 }
163
- }
164
- },
165
- data: {
166
- type: Array,
167
- default: undefined
168
- },
169
- columns: {
170
- type: Array,
171
- require: true,
172
- default: () => []
173
- },
174
- height: {
175
- type: [String, Number],
176
- default: undefined
177
- },
178
- size: {
179
- type: String,
180
- default: 'small'
181
- },
182
- showSetsize: {
183
- type: Boolean,
184
- default: true
185
- },
186
- cellDefault: {
187
- type: Boolean,
188
- default: true
189
- },
190
- // 禁止选择
191
- forbidSelect: {
192
- type: Function,
193
- default: () => {
194
- const forbidSelect = function ({ row }) {
195
- return row
196
- }
197
- return forbidSelect
198
- }
199
- },
200
- // 数据更新时是否自动清空已选
201
- clearSelect: {
202
- type: Boolean,
203
- default: true
204
- },
205
- // 筛选条件只输出当前筛选的单个条件,默认为全部条件
206
- isFiliterSingle: {
207
- type: Boolean,
208
- default: false
209
- },
210
- isAutoWidth: {
211
- type: Boolean,
212
- default: true
213
- }
214
- },
215
- data() {
216
- let _this = this
217
- return {
218
- colsKey: 0,
219
- sizeC: localStorage.getItem('table-size') || _this.size,
220
- sizeBind: undefined,
221
- key: 0
222
- }
223
- },
224
- computed: {
225
- _columns() {
226
- if (this.isAutoWidth) {
227
- return this.calcColumnWidth(this.columns)
228
- } else {
229
- return this.columns
230
- }
231
- }
232
- },
233
- watch: {
234
- columns() {
235
- this.colsKey = this.colsKey + 1
236
- },
237
- size(val) {
238
- this.sizeC = val
239
- },
240
- data() {
241
- // 翻页清除选中
242
- if (this.clearSelect) {
243
- this.$refs.vxeTable.clearCheckboxRow()
244
- this.$emit('selection-change-method', [])
245
- }
246
- }
247
- },
248
- activated() {
249
- this.$refs.vxeTable.loadData(this.data)
250
- },
251
- mounted() {},
252
- methods: {
253
- // 全选
254
- toggleAllSelection() {
255
- if (this.$refs.vxeTable) {
256
- this.$refs.vxeTable.setAllCheckboxRow(true)
257
- // 得手动触发
258
- this.handleSelectionChange()
259
- }
260
- },
261
- // 清空选择
262
- clearSelection() {
263
- if (this.$refs.vxeTable) {
264
- this.$refs.vxeTable.setAllCheckboxRow(false)
265
- // 得手动触发
266
- this.handleSelectionChange()
267
- }
268
- },
269
- // 选中某些行
270
- toggleRowSelection(row, state = true) {
271
- this.$refs.vxeTable.setCheckboxRow(row, state)
272
- // 得手动触发
273
- this.handleSelectionChange()
274
- },
275
- toggleAll($table, disabled) {
276
- if (disabled) {
277
- return false
278
- }
279
- $table.toggleAllCheckboxRow()
280
- this.key++
281
- this.handleSelectionChange()
282
- },
283
- toggleChecked($table, row, disabled) {
284
- if (disabled) {
285
- return false
286
- }
287
- $table.toggleCheckboxRow(row)
288
- this.key++
289
- this.handleSelectionChange(row)
290
- },
291
- customSortMethod({ sortList }) {
292
- const orders = sortList.map((item) => {
293
- return {
294
- column: item.field,
295
- asc: item.order === 'asc'
296
- }
297
- })
298
- this.$emit('sort-change-method', orders)
299
- },
300
- filterChange(data) {
301
- const { filterList } = data
302
- // 输出全部条件
303
- const obj = {}
304
- // 复制默认筛选条件为空
305
- this.columns.forEach((item) => {
306
- if (item.filters) {
307
- this.$set(obj, item.prop, undefined)
308
- }
309
- })
310
- filterList.forEach((item) => {
311
- if (item.column.filterMultiple) {
312
- this.$set(obj, item.field, item.values)
313
- } else {
314
- this.$set(obj, item.field, item.values && item.values[0])
315
- }
316
- })
317
- // 输出单个条件
318
- const singleObj = {}
319
- for (let key in obj) {
320
- if (key === data.field) {
321
- singleObj[data.field] = obj[data.field]
322
- }
323
- }
324
- if (this.isFiliterSingle) {
325
- this.$emit('filter-change-method', singleObj)
326
- } else {
327
- this.$emit('filter-change-method', obj)
328
- }
329
- },
330
- // row当前单次勾选的哪一行数据 包含checked字段
331
- handleSelectionChange(row = '') {
332
- const val = this.$refs.vxeTable.getCheckboxRecords()
333
- // 支持跨页勾选
334
- const val1 = this.$refs.vxeTable.getCheckboxReserveRecords()
335
- this.$emit('selection-change-method', [...val, ...val1], row)
336
- },
337
- // 点击行勾选/取消勾选
338
- handleCellClick({ row, column, $event }) {
339
- this.$emit('cell-click', { row, column, $event })
340
- // 如果点击的是 checkbox 列,不处理(由原生的 checkbox 处理)
341
- if (column.type === 'checkbox') {
342
- return
343
- }
344
-
345
- // 检查点击的目标元素是否是按钮或链接
346
- // 需要检测多种按钮类型:
347
- // - button: 原生按钮标签
348
- // - .el-button: Element UI 按钮组件
349
- // - .n20-button: n20 项目按钮组件
350
- // - [class*="button"]: 包含 button 类名的元素
351
- // - [class*="el-link--inner"]: Element UI 链接组件内部元素
352
- // - a[href]: 链接标签
353
- const target = $event.target
354
- const clickedButton = target.closest(
355
- 'button, .el-button, .n20-button, [class*="button"], [class*="el-link--inner"], a[href]'
356
- )
357
-
358
- // 如果点击的是按钮或链接,不触发行勾选
359
- if (clickedButton) {
360
- return
361
- }
362
-
363
- // 如果 closest 没找到,检查父元素的类名是否包含操作相关的关键词
364
- if (!clickedButton && target.parentElement) {
365
- const parentClass = target.parentElement.className || ''
366
- // 检测父元素是否包含:operate(操作)、btn(按钮)、button(按钮) 等关键词
367
- if (parentClass.includes('operate') || parentClass.includes('btn') || parentClass.includes('button')) {
368
- return
369
- }
370
- }
371
-
372
- // 检查该行是否可以被勾选
373
- let canCheck = true
374
- if (typeof this.forbidSelect === 'function') {
375
- const forbidResult = this.forbidSelect({ row })
376
- // 只有当 forbidSelect 明确返回 true 时,才禁止勾选
377
- canCheck = forbidResult !== true
378
- }
379
-
380
- if (canCheck) {
381
- // 切换该行的勾选状态
382
- this.$refs.vxeTable.toggleCheckboxRow(row)
383
- this.key++ // 强制刷新 checkbox 显示
384
- this.handleSelectionChange(row)
385
- }
386
- },
387
- sizeUp(size) {
388
- this.sizeC = size
389
- this.$emit('update:size', size)
390
- },
391
- sizeSet(el) {
392
- this.sizeBind = el
393
- },
394
- // 计算列宽
395
- calcColumnWidth(columns) {
396
- columns = columns.map((item) => {
397
- return {
398
- ...item,
399
- _width_: 0
400
- }
401
- })
402
-
403
- // 优先使用表格容器的宽度,如果没有则使用app容器宽度
404
- let wrapperEl = this.$refs.vxeTable?.$el
405
- if (!wrapperEl) {
406
- wrapperEl = document.querySelector('div#app')
407
- }
408
- if (!wrapperEl) {
409
- return columns
410
- }
411
- const { width: windowWidth } = wrapperEl.getBoundingClientRect()
412
- console.log(windowWidth, 'windowWidth')
413
- // 定义每个字符的平均宽度(像素)
414
- const CHAR_WIDTH = 20 // 根据实际字体大小调整
415
- const PADDING = 20 // 左右padding
416
-
417
- function calc(columns) {
418
- // 计算所有列的基础宽度总和
419
- let totalBaseWidth = 0
420
- columns.forEach((column) => {
421
- if (column.static && column.label === $lc('操作') && !column.width && !column.minWidth) {
422
- column.width = 180
423
- }
424
- if (column.type === 'checkbox') {
425
- column.width = 50
426
- }
427
-
428
- // 如果没有设置宽度,根据字符数计算最小宽度
429
- if (!column.width && !column.minWidth && !column['min-width']) {
430
- const textLength = (column.label && column.label.length) || 10
431
- column.minWidth = Math.ceil(textLength * CHAR_WIDTH + PADDING)
432
- }
433
-
434
- // 计算基础宽度:有width的用width,没有的用minWidth
435
- const widthValue = column.width || column.minWidth || column['min-width'] || 0
436
- // 处理不同格式的宽度:数字、"100"、"100px"
437
- let baseWidth = 0
438
- if (typeof widthValue === 'number') {
439
- baseWidth = widthValue
440
- } else if (typeof widthValue === 'string') {
441
- // 提取字符串中的数字部分
442
- baseWidth = parseInt(widthValue) || 0
443
- }
444
- column['_baseWidth_'] = baseWidth
445
- totalBaseWidth += baseWidth
446
- })
447
- // 如果所有列的基础宽度总和 >= 容器宽度,不做处理
448
- if (totalBaseWidth >= windowWidth) {
449
- return columns
450
- } else {
451
- const seqColumns = columns.filter((item) => item.type !== 'seq' && item.type !== 'checkbox')
452
- if (seqColumns.length > 0) {
453
- seqColumns[0].width = ''
454
- }
455
- return columns
456
- }
457
- }
458
- return calc(columns)
459
- }
460
- }
461
- }
462
- </script>