n20-common-lib 3.3.16 → 3.3.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n20-common-lib",
3
- "version": "3.3.16",
3
+ "version": "3.3.18",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -265,6 +265,7 @@
265
265
  .table-hover-btns {
266
266
  position: absolute;
267
267
  right: 0;
268
+ width: max-content;
268
269
  display: flex;
269
270
  align-items: center;
270
271
  justify-content: flex-end;
@@ -274,6 +275,7 @@
274
275
 
275
276
  .hover-btns-wrapper {
276
277
  display: flex;
278
+ width: max-content;
277
279
  align-items: center;
278
280
  gap: 4px;
279
281
  white-space: nowrap;
@@ -174,7 +174,10 @@ export default {
174
174
  provide() {
175
175
  let bigData = this.bigData
176
176
  return {
177
- bigData
177
+ bigData,
178
+ n20TableContext: {
179
+ getData: () => this.data || []
180
+ }
178
181
  }
179
182
  },
180
183
  watch: {
@@ -1,8 +1,8 @@
1
1
  <template>
2
- <el-table-column v-if="!bigData" v-bind="$attrs">
2
+ <el-table-column v-if="!bigData" v-bind="resolvedColumnAttrs">
3
3
  <OperateBtns slot-scope="{ row, $index }" :btn-list="btnList" :row="row" @command="(c) => $emit(c, row, $index)" />
4
4
  </el-table-column>
5
- <ux-table-column v-else :field="$attrs.prop" :title="$attrs.label" v-bind="$attrs">
5
+ <ux-table-column v-else :field="$attrs.prop" :title="$attrs.label" v-bind="resolvedColumnAttrs">
6
6
  <OperateBtns slot-scope="{ row, $index }" :btn-list="btnList" :row="row" @command="(c) => $emit(c, row, $index)" />
7
7
  </ux-table-column>
8
8
  </template>
@@ -10,17 +10,143 @@
10
10
  <script>
11
11
  // import { $lc } from '../../utils/i18n/index'
12
12
  import OperateBtns from './OperateBtns.vue'
13
+
14
+ const DEFAULT_OPERATE_COLUMN_MIN_WIDTH = 80
15
+
13
16
  export default {
14
17
  name: 'TableOperateColumn',
15
18
  components: {
16
19
  OperateBtns
17
20
  },
18
- inject: { bigData: { default: false } },
21
+ inject: {
22
+ bigData: { default: false },
23
+ n20TableContext: { default: null }
24
+ },
19
25
  props: {
20
26
  btnList: {
21
27
  type: Array,
22
28
  default: () => []
23
29
  }
30
+ },
31
+ computed: {
32
+ resolvedColumnAttrs() {
33
+ const attrs = { ...this.$attrs }
34
+ const hasWidth =
35
+ Object.prototype.hasOwnProperty.call(attrs, 'width') &&
36
+ attrs.width !== null &&
37
+ attrs.width !== undefined &&
38
+ attrs.width !== ''
39
+ if (hasWidth) {
40
+ return attrs
41
+ }
42
+
43
+ const minWidthKey = ['minWidth', 'min-width'].find((key) => {
44
+ const value = attrs[key]
45
+ return Object.prototype.hasOwnProperty.call(attrs, key) && value !== null && value !== undefined && value !== ''
46
+ })
47
+ const calculatedWidth = this.calcOperateColumnWidth()
48
+ if (minWidthKey) {
49
+ const minWidth = this.parsePixelWidth(attrs[minWidthKey])
50
+ if (minWidth !== null) {
51
+ attrs[minWidthKey] = Math.max(calculatedWidth, minWidth)
52
+ }
53
+ } else {
54
+ // 避免 Element/UX Table 将大量剩余空间分配给操作列。
55
+ attrs.width = calculatedWidth
56
+ }
57
+ return attrs
58
+ }
59
+ },
60
+ methods: {
61
+ measureOperateText(text) {
62
+ const normalizedText = text === undefined || text === null ? '' : String(text)
63
+ if (!normalizedText) return 0
64
+
65
+ const fallbackWidth = Array.from(normalizedText).reduce(
66
+ (width, char) => width + (/[⺀-鿿]/.test(char) ? 14 : 8),
67
+ 0
68
+ )
69
+ if (typeof document === 'undefined') return fallbackWidth
70
+
71
+ const canvas = document.createElement('canvas')
72
+ const context = canvas.getContext('2d')
73
+ if (!context) return fallbackWidth
74
+
75
+ context.font = '14px PingFang SC, Microsoft YaHei, sans-serif'
76
+ return Math.max(context.measureText(normalizedText).width, fallbackWidth)
77
+ },
78
+ parsePixelWidth(value) {
79
+ if (typeof value === 'number') {
80
+ return Number.isFinite(value) && value >= 0 ? value : null
81
+ }
82
+ if (typeof value !== 'string') return null
83
+
84
+ const normalizedValue = value.trim()
85
+ if (!/^\d+(\.\d+)?(px)?$/.test(normalizedValue)) return null
86
+ const parsedValue = Number.parseFloat(normalizedValue)
87
+ return Number.isFinite(parsedValue) ? parsedValue : null
88
+ },
89
+ calcOperateColumnWidth() {
90
+ const CELL_HORIZONTAL_PADDING = this.bigData ? 20 : 16
91
+ // OperateBtns 使用行内元素,除 6px margin 外还会产生约 4px 的模板空白。
92
+ const BUTTON_GAP = 10
93
+ const CHILDREN_ARROW_WIDTH = 20
94
+ const MORE_BUTTON_WIDTH = 16
95
+ const buttons = (this.btnList || []).filter((button) => button && button.isHas !== false)
96
+ const getButtonWidth = (button) => {
97
+ let width = this.measureOperateText(button.label)
98
+ if (button.children && button.children.length > 0) {
99
+ width += CHILDREN_ARROW_WIDTH
100
+ }
101
+ return width
102
+ }
103
+ const buttonWidths = buttons.map(getButtonWidth)
104
+
105
+ if (buttonWidths.length === 0) {
106
+ return DEFAULT_OPERATE_COLUMN_MIN_WIDTH
107
+ }
108
+
109
+ const calcLayoutWidth = (inlineWidths, hasMoreButton = false) => {
110
+ const itemCount = inlineWidths.length + (hasMoreButton ? 1 : 0)
111
+ const contentWidth = inlineWidths.reduce((total, width) => total + width, 0)
112
+ const moreButtonWidth = hasMoreButton ? MORE_BUTTON_WIDTH : 0
113
+ const gapWidth = Math.max(itemCount - 1, 0) * BUTTON_GAP
114
+ return contentWidth + moreButtonWidth + gapWidth + CELL_HORIZONTAL_PADDING
115
+ }
116
+ const rows = this.n20TableContext?.getData?.() || []
117
+ if (rows.length > 0) {
118
+ const maxRowWidth = rows.reduce((maxWidth, row) => {
119
+ const visibleButtonWidths = buttons
120
+ .filter((button) => this.hasButton(button.isHas, row))
121
+ .map(getButtonWidth)
122
+ const rowWidth = visibleButtonWidths.length > 3
123
+ ? calcLayoutWidth(visibleButtonWidths.slice(0, 2), true)
124
+ : calcLayoutWidth(visibleButtonWidths)
125
+ return Math.max(maxWidth, rowWidth)
126
+ }, 0)
127
+ return Math.max(DEFAULT_OPERATE_COLUMN_MIN_WIDTH, Math.ceil(maxRowWidth))
128
+ }
129
+
130
+ const sortedButtonWidths = [...buttonWidths].sort((a, b) => b - a)
131
+ const directButtonsWidth = calcLayoutWidth(sortedButtonWidths.slice(0, 3))
132
+ const collapsedButtonsWidth =
133
+ sortedButtonWidths.length > 3 ? calcLayoutWidth(sortedButtonWidths.slice(0, 2), true) : 0
134
+
135
+ return Math.max(
136
+ DEFAULT_OPERATE_COLUMN_MIN_WIDTH,
137
+ Math.ceil(directButtonsWidth),
138
+ Math.ceil(collapsedButtonsWidth)
139
+ )
140
+ },
141
+ hasButton(isHas, row) {
142
+ if (isHas === undefined || isHas === null) return true
143
+ if (typeof isHas === 'boolean') return isHas
144
+ if (typeof isHas === 'function') return isHas(row)
145
+ if (typeof isHas === 'string' || Array.isArray(isHas)) {
146
+ return typeof this.$has === 'function' ? this.$has(isHas) : true
147
+ }
148
+ return false
149
+ }
24
150
  }
25
151
  }
26
152
  </script>
@@ -166,6 +166,13 @@ export default {
166
166
  empty,
167
167
  renderer
168
168
  },
169
+ provide() {
170
+ return {
171
+ n20TableProContext: {
172
+ getData: () => this.data || []
173
+ }
174
+ }
175
+ },
169
176
  props: {
170
177
  scrollY: {
171
178
  type: Object,
@@ -1,19 +1,153 @@
1
1
  <template>
2
- <vxe-column :field="$attrs.prop" :title="$attrs.label" v-bind="$attrs">
2
+ <vxe-column :field="$attrs.prop" :title="$attrs.label" v-bind="resolvedColumnAttrs">
3
3
  <OperateBtns slot-scope="{ row, $index }" :btn-list="btnList" :row="row" @command="(c) => $emit(c, row, $index)" />
4
4
  </vxe-column>
5
5
  </template>
6
6
  <script>
7
7
  import OperateBtns from './OperateBtns.vue'
8
8
 
9
+ const DEFAULT_OPERATE_COLUMN_WIDTH = 180
10
+
9
11
  export default {
10
12
  name: 'TableProOperateColumn',
11
13
  components: { OperateBtns },
14
+ inject: {
15
+ n20TableProContext: {
16
+ default: null
17
+ }
18
+ },
12
19
  props: {
13
20
  btnList: {
14
21
  type: Array,
15
22
  default: () => []
16
23
  }
24
+ },
25
+ computed: {
26
+ resolvedColumnAttrs() {
27
+ const attrs = { ...this.$attrs }
28
+ const hasWidth =
29
+ Object.prototype.hasOwnProperty.call(attrs, 'width') &&
30
+ attrs.width !== null &&
31
+ attrs.width !== undefined &&
32
+ attrs.width !== ''
33
+ if (hasWidth) {
34
+ return attrs
35
+ }
36
+
37
+ const minWidthKey = ['minWidth', 'min-width'].find((key) => {
38
+ const value = attrs[key]
39
+ return Object.prototype.hasOwnProperty.call(attrs, key) && value !== null && value !== undefined && value !== ''
40
+ })
41
+ const calculatedWidth = this.calcOperateColumnWidth()
42
+ if (minWidthKey) {
43
+ const minWidth = this.parsePixelWidth(attrs[minWidthKey])
44
+ if (minWidth !== null) {
45
+ attrs[minWidthKey] = Math.max(calculatedWidth, minWidth)
46
+ }
47
+ } else {
48
+ attrs.width = calculatedWidth
49
+ }
50
+ return attrs
51
+ }
52
+ },
53
+ methods: {
54
+ measureOperateText(text) {
55
+ const normalizedText = text === undefined || text === null ? '' : String(text)
56
+ if (!normalizedText) return 0
57
+
58
+ const fallbackWidth = Array.from(normalizedText).reduce(
59
+ (width, char) => width + (/[⺀-鿿]/.test(char) ? 14 : 8),
60
+ 0
61
+ )
62
+ if (typeof document === 'undefined') return fallbackWidth
63
+
64
+ const canvas = document.createElement('canvas')
65
+ const context = canvas.getContext('2d')
66
+ if (!context) return fallbackWidth
67
+
68
+ context.font = '14px PingFang SC, Microsoft YaHei, sans-serif'
69
+ return Math.max(context.measureText(normalizedText).width, fallbackWidth)
70
+ },
71
+ parsePixelWidth(value) {
72
+ if (typeof value === 'number') {
73
+ return Number.isFinite(value) && value >= 0 ? value : null
74
+ }
75
+ if (typeof value !== 'string') return null
76
+
77
+ const normalizedValue = value.trim()
78
+ if (!/^\d+(\.\d+)?(px)?$/.test(normalizedValue)) return null
79
+ const parsedValue = Number.parseFloat(normalizedValue)
80
+ return Number.isFinite(parsedValue) ? parsedValue : null
81
+ },
82
+ calcOperateColumnWidth() {
83
+ const CELL_HORIZONTAL_PADDING = 14
84
+ const BUTTON_GAP = 6
85
+ const ICON_AND_GAP_WIDTH = 23
86
+ const CHILDREN_ARROW_WIDTH = 20
87
+ const ICON_ONLY_BUTTON_WIDTH = 28
88
+ const MORE_BUTTON_WIDTH = 29
89
+ const buttons = (this.btnList || []).filter((button) => button && button.isHas !== false)
90
+ const getButtonWidth = (button) => {
91
+ if (button.iconOnly && button.icon) {
92
+ return ICON_ONLY_BUTTON_WIDTH
93
+ }
94
+
95
+ let width = this.measureOperateText(button.label)
96
+ if (button.icon) {
97
+ width += ICON_AND_GAP_WIDTH
98
+ }
99
+ if (button.children && button.children.length > 0) {
100
+ width += CHILDREN_ARROW_WIDTH
101
+ }
102
+ return width
103
+ }
104
+ const buttonWidths = buttons.map(getButtonWidth)
105
+
106
+ if (buttonWidths.length === 0) {
107
+ return DEFAULT_OPERATE_COLUMN_WIDTH
108
+ }
109
+
110
+ const calcLayoutWidth = (inlineWidths, hasMoreButton = false) => {
111
+ const itemCount = inlineWidths.length + (hasMoreButton ? 1 : 0)
112
+ const contentWidth = inlineWidths.reduce((total, width) => total + width, 0)
113
+ const moreButtonWidth = hasMoreButton ? MORE_BUTTON_WIDTH : 0
114
+ const gapWidth = Math.max(itemCount - 1, 0) * BUTTON_GAP
115
+ return contentWidth + moreButtonWidth + gapWidth + CELL_HORIZONTAL_PADDING
116
+ }
117
+ const rows = this.n20TableProContext?.getData?.() || []
118
+ if (rows.length > 0) {
119
+ const maxRowWidth = rows.reduce((maxWidth, row) => {
120
+ const visibleButtonWidths = buttons
121
+ .filter((button) => this.hasButton(button.isHas, row))
122
+ .map(getButtonWidth)
123
+ const rowWidth = visibleButtonWidths.length > 3
124
+ ? calcLayoutWidth(visibleButtonWidths.slice(0, 2), true)
125
+ : calcLayoutWidth(visibleButtonWidths)
126
+ return Math.max(maxWidth, rowWidth)
127
+ }, 0)
128
+ return Math.max(DEFAULT_OPERATE_COLUMN_WIDTH, Math.ceil(maxRowWidth))
129
+ }
130
+
131
+ const sortedButtonWidths = [...buttonWidths].sort((a, b) => b - a)
132
+ const directButtonsWidth = calcLayoutWidth(sortedButtonWidths.slice(0, 3))
133
+ const collapsedButtonsWidth =
134
+ sortedButtonWidths.length > 3 ? calcLayoutWidth(sortedButtonWidths.slice(0, 2), true) : 0
135
+
136
+ return Math.max(
137
+ DEFAULT_OPERATE_COLUMN_WIDTH,
138
+ Math.ceil(directButtonsWidth),
139
+ Math.ceil(collapsedButtonsWidth)
140
+ )
141
+ },
142
+ hasButton(isHas, row) {
143
+ if (isHas === undefined || isHas === null) return true
144
+ if (typeof isHas === 'boolean') return isHas
145
+ if (typeof isHas === 'function') return isHas(row)
146
+ if (typeof isHas === 'string' || Array.isArray(isHas)) {
147
+ return typeof this.$has === 'function' ? this.$has(isHas) : true
148
+ }
149
+ return false
150
+ }
17
151
  }
18
152
  }
19
153
  </script>
@@ -287,7 +287,7 @@
287
287
  v-if="isOperateFixed && btnList && btnList.length > 0"
288
288
  :title="$lc('操作')"
289
289
  field="__operate__"
290
- :width="operateColumnWidth"
290
+ :width="computedOperateColumnWidth"
291
291
  fixed="right"
292
292
  align="center"
293
293
  >
@@ -452,8 +452,10 @@ import empty from '../../Empty'
452
452
  import tableShowColumn from '../../ShowColumn/index.vue'
453
453
  import { saveTransform } from '../../ShowColumn/index.vue'
454
454
  import tableOperate from '../../TableOperate/index.vue'
455
- import OperateBtns from '../../TableProOperateColumn/OperateBtns.vue'
456
455
  import { isTableCellInteractiveTarget } from '../../TablePro/cellClick'
456
+ import OperateBtns from '../../TableProOperateColumn/OperateBtns.vue'
457
+
458
+ const DEFAULT_OPERATE_COLUMN_WIDTH = 180
457
459
 
458
460
  const renderer = {
459
461
  name: 'renderer',
@@ -627,10 +629,16 @@ export default {
627
629
  type: Function,
628
630
  default: null
629
631
  },
632
+ // 固定操作列宽度;不传时按各行实际可见按钮的最大宽度自动计算
630
633
  operateColumnWidth: {
631
634
  type: Number,
632
635
  default: 180
633
636
  },
637
+ // 自动计算操作列宽度的下限;显式传入 operateColumnWidth 时不生效
638
+ operateColumnMinWidth: {
639
+ type: [Number, String],
640
+ default: 180
641
+ },
634
642
  // 异步获取操作按钮函数,(row) => Promise<Array<BtnItem>>
635
643
  getOperateBtns: {
636
644
  type: Function,
@@ -722,6 +730,19 @@ export default {
722
730
  const activeCount = [this.showColumn, this.showSetsize, hasExpand].filter(Boolean).length
723
731
  return activeCount === 3 ? 112 : 76
724
732
  },
733
+ // 操作列宽度:显式传入时优先,否则按按钮内容自动计算
734
+ computedOperateColumnWidth() {
735
+ const hasCustomWidth = Object.prototype.hasOwnProperty.call(this.$options.propsData || {}, 'operateColumnWidth')
736
+ const hasCustomWidthValue =
737
+ this.operateColumnWidth !== null && this.operateColumnWidth !== undefined && this.operateColumnWidth !== ''
738
+ const customWidth = hasCustomWidthValue ? Number(this.operateColumnWidth) : NaN
739
+ if (hasCustomWidth && Number.isFinite(customWidth) && customWidth >= 0) {
740
+ return customWidth
741
+ }
742
+ const calculatedWidth = this.calcOperateColumnWidth()
743
+ const minWidth = this.parseOperateColumnPixelWidth(this.operateColumnMinWidth)
744
+ return minWidth === null ? calculatedWidth : Math.max(calculatedWidth, minWidth)
745
+ },
725
746
  // 骨架屏定位样式,根据表头实际高度动态计算
726
747
  skeletonStyle() {
727
748
  return {
@@ -1385,6 +1406,121 @@ export default {
1385
1406
  return checkedSet.has(args.row) ? 'v3-n20-table-pro__row-checked' : ''
1386
1407
  },
1387
1408
 
1409
+ // 测量操作按钮文案宽度,优先使用当前页面字体,服务端或 canvas 不可用时使用保守估算
1410
+ measureOperateText(text) {
1411
+ const normalizedText = text === undefined || text === null ? '' : String(text)
1412
+ if (!normalizedText) return 0
1413
+
1414
+ const fallbackWidth = Array.from(normalizedText).reduce(
1415
+ (width, char) => width + (/[⺀-鿿]/.test(char) ? 14 : 8),
1416
+ 0
1417
+ )
1418
+ if (typeof document === 'undefined') return fallbackWidth
1419
+
1420
+ const canvas = document.createElement('canvas')
1421
+ const context = canvas.getContext('2d')
1422
+ if (!context) return fallbackWidth
1423
+
1424
+ const tableEl = this.$refs.vxeTable?.$el
1425
+ const textEl = tableEl?.querySelector('.table-operate-btns__wrapper .el-link')
1426
+ if (textEl && typeof window !== 'undefined' && window.getComputedStyle) {
1427
+ const style = window.getComputedStyle(textEl)
1428
+ context.font = `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`
1429
+ } else {
1430
+ context.font = '14px PingFang SC, Microsoft YaHei, sans-serif'
1431
+ }
1432
+
1433
+ return Math.max(context.measureText(normalizedText).width, fallbackWidth)
1434
+ },
1435
+
1436
+ parseOperateColumnPixelWidth(value) {
1437
+ if (typeof value === 'number') {
1438
+ return Number.isFinite(value) && value >= 0 ? value : null
1439
+ }
1440
+ if (typeof value !== 'string') return null
1441
+
1442
+ const normalizedValue = value.trim()
1443
+ if (!/^\d+(\.\d+)?(px)?$/.test(normalizedValue)) return null
1444
+ const parsedValue = Number.parseFloat(normalizedValue)
1445
+ return Number.isFinite(parsedValue) ? parsedValue : null
1446
+ },
1447
+
1448
+ // 固定操作列按当前数据中每行实际可见的按钮布局取最大宽度
1449
+ calcOperateColumnWidth() {
1450
+ const CELL_HORIZONTAL_PADDING = 24
1451
+ const BUTTON_GAP = 12
1452
+ const ICON_AND_GAP_WIDTH = 20
1453
+ const CHILDREN_ARROW_WIDTH = 14
1454
+ const ICON_ONLY_BUTTON_WIDTH = 28
1455
+ const MORE_BUTTON_WIDTH = 40
1456
+ const buttons = (this.btnList || []).filter(Boolean)
1457
+ const buttonWidthMap = new Map()
1458
+ buttons.forEach((button) => {
1459
+ if (button.iconOnly && button.icon) {
1460
+ buttonWidthMap.set(button, ICON_ONLY_BUTTON_WIDTH)
1461
+ return
1462
+ }
1463
+
1464
+ let width = this.measureOperateText(button.label)
1465
+ if (button.icon) {
1466
+ width += ICON_AND_GAP_WIDTH
1467
+ }
1468
+ if (button.children && button.children.length > 0) {
1469
+ width += CHILDREN_ARROW_WIDTH
1470
+ }
1471
+ buttonWidthMap.set(button, width)
1472
+ })
1473
+
1474
+ if (buttons.length === 0) {
1475
+ return DEFAULT_OPERATE_COLUMN_WIDTH
1476
+ }
1477
+
1478
+ const calcLayoutWidth = (inlineWidths, hasMoreButton = false) => {
1479
+ const itemCount = inlineWidths.length + (hasMoreButton ? 1 : 0)
1480
+ const buttonWidth = inlineWidths.reduce((total, width) => total + width, 0)
1481
+ const moreButtonWidth = hasMoreButton ? MORE_BUTTON_WIDTH : 0
1482
+ const gapWidth = Math.max(itemCount - 1, 0) * BUTTON_GAP
1483
+ return buttonWidth + moreButtonWidth + gapWidth + CELL_HORIZONTAL_PADDING
1484
+ }
1485
+
1486
+ const calcButtonsWidth = (visibleButtons) => {
1487
+ const hasMoreButton = visibleButtons.length > 3 || !!this.getOperateBtns
1488
+ const inlineButtons = visibleButtons.length > 3 ? visibleButtons.slice(0, 2) : visibleButtons
1489
+ return calcLayoutWidth(
1490
+ inlineButtons.map((button) => buttonWidthMap.get(button) || 0),
1491
+ hasMoreButton
1492
+ )
1493
+ }
1494
+
1495
+ // 直接根据 data 计算所有行,可覆盖 isHas(row) 导致的 1/2/3/更多按钮差异,且不受虚拟滚动影响。
1496
+ const rows = Array.isArray(this.data) ? this.data : []
1497
+ const maxRowWidth = rows.reduce((maxWidth, row) => {
1498
+ const visibleButtons = buttons.filter((button) => this.hasBtn(button.isHas, row))
1499
+ return Math.max(maxWidth, calcButtonsWidth(visibleButtons))
1500
+ }, 0)
1501
+
1502
+ if (maxRowWidth > 0) {
1503
+ return Math.max(DEFAULT_OPERATE_COLUMN_WIDTH, Math.ceil(maxRowWidth))
1504
+ }
1505
+
1506
+ // 数据尚未加载时按所有可能布局保守估算,避免首次渲染回落到过窄列宽。
1507
+ const sortedButtonWidths = buttons
1508
+ .filter((button) => button.isHas !== false)
1509
+ .map((button) => buttonWidthMap.get(button) || 0)
1510
+ .sort((a, b) => b - a)
1511
+ const directButtonsWidth = calcLayoutWidth(sortedButtonWidths.slice(0, 3))
1512
+ const collapsedButtonsWidth =
1513
+ sortedButtonWidths.length > 3 ? calcLayoutWidth(sortedButtonWidths.slice(0, 2), true) : 0
1514
+ const dynamicButtonsWidth = this.getOperateBtns ? calcLayoutWidth(sortedButtonWidths.slice(0, 3), true) : 0
1515
+
1516
+ return Math.max(
1517
+ DEFAULT_OPERATE_COLUMN_WIDTH,
1518
+ Math.ceil(directButtonsWidth),
1519
+ Math.ceil(collapsedButtonsWidth),
1520
+ Math.ceil(dynamicButtonsWidth)
1521
+ )
1522
+ },
1523
+
1388
1524
  calcColumnWidth(columns) {
1389
1525
  // 常量配置
1390
1526
  const CHAR_WIDTH = 20 // 每个字符的平均宽度(像素)