vxe-table 4.23.8 → 4.23.10

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 (126) hide show
  1. package/dist/all.esm.js +5683 -3798
  2. package/es/components.d.ts +1 -0
  3. package/es/components.js +2 -7
  4. package/es/grid/src/emits.js +1 -15
  5. package/es/grid/src/grid.js +397 -120
  6. package/es/index.esm.js +5 -3
  7. package/es/index.js +5 -3
  8. package/es/table/module/custom/hook.js +49 -42
  9. package/es/table/module/custom/panel.js +777 -527
  10. package/es/table/module/edit/hook.js +140 -62
  11. package/es/table/module/export/export-panel.js +399 -316
  12. package/es/table/module/export/hook.js +395 -337
  13. package/es/table/module/export/import-panel.js +152 -123
  14. package/es/table/module/filter/hook.js +16 -2
  15. package/es/table/module/filter/panel.js +146 -84
  16. package/es/table/module/keyboard/hook.js +8 -4
  17. package/es/table/module/menu/panel.js +197 -126
  18. package/es/table/render/index.js +151 -98
  19. package/es/table/src/body.js +355 -233
  20. package/es/table/src/cell.js +426 -269
  21. package/es/table/src/columnInfo.js +1 -0
  22. package/es/table/src/footer.js +144 -99
  23. package/es/table/src/group.js +7 -3
  24. package/es/table/src/header.js +229 -172
  25. package/es/table/src/table.js +1503 -1030
  26. package/es/table/src/util.js +15 -19
  27. package/es/toolbar/src/toolbar.js +132 -75
  28. package/es/ui/index.js +1 -1
  29. package/es/ui/src/dom.js +9 -6
  30. package/es/ui/src/log.js +1 -1
  31. package/es/ui/src/utils.d.ts +1 -1
  32. package/lib/components.js +2 -7
  33. package/lib/grid/src/emits.js +1 -15
  34. package/lib/grid/src/grid.js +397 -120
  35. package/lib/index.common.js +5 -3
  36. package/lib/index.js +5 -3
  37. package/lib/index.umd.js +5652 -3797
  38. package/lib/index.umd.min.js +3 -3
  39. package/lib/table/module/custom/hook.js +49 -42
  40. package/lib/table/module/custom/panel.js +777 -527
  41. package/lib/table/module/edit/hook.js +140 -62
  42. package/lib/table/module/export/export-panel.js +399 -316
  43. package/lib/table/module/export/hook.js +395 -337
  44. package/lib/table/module/export/import-panel.js +152 -123
  45. package/lib/table/module/filter/hook.js +16 -2
  46. package/lib/table/module/filter/panel.js +146 -84
  47. package/lib/table/module/keyboard/hook.js +8 -4
  48. package/lib/table/module/menu/panel.js +197 -126
  49. package/lib/table/render/index.js +151 -98
  50. package/lib/table/src/body.js +355 -233
  51. package/lib/table/src/cell.js +426 -269
  52. package/lib/table/src/columnInfo.js +1 -0
  53. package/lib/table/src/footer.js +144 -99
  54. package/lib/table/src/group.js +7 -3
  55. package/lib/table/src/header.js +229 -172
  56. package/lib/table/src/table.js +1471 -1029
  57. package/lib/table/src/util.js +15 -19
  58. package/lib/toolbar/src/toolbar.js +132 -75
  59. package/lib/ui/index.js +1 -1
  60. package/lib/ui/src/dom.js +9 -6
  61. package/lib/ui/src/log.js +1 -1
  62. package/package.json +2 -2
  63. package/packages/colgroup/index.ts +22 -22
  64. package/packages/column/index.ts +22 -22
  65. package/packages/components.ts +42 -44
  66. package/packages/grid/index.ts +18 -18
  67. package/packages/grid/src/emits.ts +5 -19
  68. package/packages/grid/src/grid.ts +2229 -1925
  69. package/packages/grid/src/props.ts +22 -23
  70. package/packages/index.ts +13 -11
  71. package/packages/locale/lang/fr-FR.ts +15 -15
  72. package/packages/locale/lang/it-IT.ts +4 -4
  73. package/packages/locale/lang/uk-UA.ts +1 -1
  74. package/packages/locale/lang/uz-UZ.ts +13 -13
  75. package/packages/locale/lang/zh-CN.ts +907 -907
  76. package/packages/table/index.ts +26 -26
  77. package/packages/table/module/custom/hook.ts +510 -503
  78. package/packages/table/module/custom/panel.ts +2002 -1743
  79. package/packages/table/module/edit/hook.ts +1224 -1131
  80. package/packages/table/module/export/export-panel.ts +697 -611
  81. package/packages/table/module/export/hook.ts +2160 -2059
  82. package/packages/table/module/export/import-panel.ts +319 -279
  83. package/packages/table/module/export/util.ts +25 -24
  84. package/packages/table/module/filter/hook.ts +519 -501
  85. package/packages/table/module/filter/panel.ts +368 -304
  86. package/packages/table/module/keyboard/hook.ts +498 -494
  87. package/packages/table/module/menu/hook.ts +330 -330
  88. package/packages/table/module/menu/panel.ts +272 -201
  89. package/packages/table/module/validator/hook.ts +653 -635
  90. package/packages/table/render/index.ts +1819 -1744
  91. package/packages/table/src/body.ts +1078 -955
  92. package/packages/table/src/cell.ts +1524 -1359
  93. package/packages/table/src/column.ts +192 -192
  94. package/packages/table/src/columnInfo.ts +232 -232
  95. package/packages/table/src/emits.ts +134 -134
  96. package/packages/table/src/footer.ts +425 -380
  97. package/packages/table/src/group.ts +67 -63
  98. package/packages/table/src/header.ts +642 -581
  99. package/packages/table/src/props.ts +336 -336
  100. package/packages/table/src/store.ts +14 -14
  101. package/packages/table/src/table.ts +16011 -15454
  102. package/packages/table/src/use/cell-view.ts +41 -44
  103. package/packages/table/src/use/index.ts +1 -1
  104. package/packages/table/src/util.ts +1206 -1216
  105. package/packages/toolbar/index.ts +18 -18
  106. package/packages/toolbar/src/toolbar.ts +768 -706
  107. package/packages/ui/index.ts +519 -520
  108. package/packages/ui/src/anime.ts +51 -52
  109. package/packages/ui/src/comp.ts +3 -3
  110. package/packages/ui/src/dom.ts +466 -463
  111. package/packages/ui/src/log.ts +19 -19
  112. package/packages/ui/src/utils.ts +66 -66
  113. package/packages/ui/src/vn.ts +55 -55
  114. package/packages/v-x-e-table/index.d.ts +3 -3
  115. package/packages/v-x-e-table/index.ts +3 -3
  116. package/types/all.d.ts +76 -76
  117. package/types/index.d.ts +4 -4
  118. /package/dist/{iconfont.1793007753347.ttf → iconfont.1793015256719.ttf} +0 -0
  119. /package/dist/{iconfont.1793007753347.woff → iconfont.1793015256719.woff} +0 -0
  120. /package/dist/{iconfont.1793007753347.woff2 → iconfont.1793015256719.woff2} +0 -0
  121. /package/es/{iconfont.1793007753347.ttf → iconfont.1793015256719.ttf} +0 -0
  122. /package/es/{iconfont.1793007753347.woff → iconfont.1793015256719.woff} +0 -0
  123. /package/es/{iconfont.1793007753347.woff2 → iconfont.1793015256719.woff2} +0 -0
  124. /package/lib/{iconfont.1793007753347.ttf → iconfont.1793015256719.ttf} +0 -0
  125. /package/lib/{iconfont.1793007753347.woff → iconfont.1793015256719.woff} +0 -0
  126. /package/lib/{iconfont.1793007753347.woff2 → iconfont.1793015256719.woff2} +0 -0
@@ -1,2059 +1,2160 @@
1
- import { nextTick } from 'vue'
2
- import XEUtils from 'xe-utils'
3
- import { VxeUI } from '@vxe-ui/core'
4
- import { isColumnInfo, getCellValue, createHandleGetRowId } from '../../src/util'
5
- import { parseFile, formatText, eqEmptyValue, hasEnableConf } from '../../../ui/src/utils'
6
- import { hasClass, toCssUnit } from '../../../ui/src/dom'
7
- import { createHtmlPage, getExportBlobByContent } from './util'
8
- import { createComponentLog } from '../../../ui/src/log'
9
-
10
- import type { VxeTablePropTypes, VxeColumnPropTypes, TableExportMethods, VxeGridPropTypes, VxeTableDefines, VxeTableConstructor, VxeTablePrivateMethods } from '../../../../types'
11
-
12
- const { warnLog, errLog } = createComponentLog('table')
13
-
14
- const { getI18n, hooks, renderer } = VxeUI
15
-
16
- let htmlCellElem: any
17
-
18
- const csvBOM = '\ufeff'
19
- const enterSymbol = '\r\n'
20
-
21
- function defaultFilterExportColumn (column: VxeTableDefines.ColumnInfo) {
22
- return !!column.field || ['seq', 'checkbox', 'radio'].indexOf(column.type || '') === -1
23
- }
24
-
25
- const getConvertColumns = (columns: any) => {
26
- const result: any = []
27
- columns.forEach((column: any) => {
28
- if (column.childNodes && column.childNodes.length) {
29
- result.push(column)
30
- result.push(...getConvertColumns(column.childNodes))
31
- } else {
32
- result.push(column)
33
- }
34
- })
35
- return result
36
- }
37
-
38
- const convertToRows = (originColumns: any): any[][] => {
39
- let maxLevel = 1
40
- const traverse = (column: any, parent?: any) => {
41
- if (parent) {
42
- column._level = parent._level + 1
43
- if (maxLevel < column._level) {
44
- maxLevel = column._level
45
- }
46
- }
47
- if (column.childNodes && column.childNodes.length) {
48
- let colSpan = 0
49
- column.childNodes.forEach((subColumn: any) => {
50
- traverse(subColumn, column)
51
- colSpan += subColumn._colSpan
52
- })
53
- column._colSpan = colSpan
54
- } else {
55
- column._colSpan = 1
56
- }
57
- }
58
-
59
- originColumns.forEach((column: any) => {
60
- column._level = 1
61
- traverse(column)
62
- })
63
-
64
- const rows: any = []
65
- for (let i = 0; i < maxLevel; i++) {
66
- rows.push([])
67
- }
68
-
69
- const allColumns = getConvertColumns(originColumns)
70
-
71
- allColumns.forEach((column: any) => {
72
- if (column.childNodes && column.childNodes.length) {
73
- column._rowSpan = 1
74
- } else {
75
- column._rowSpan = maxLevel - column._level + 1
76
- }
77
- rows[column._level - 1].push(column)
78
- })
79
-
80
- return rows
81
- }
82
-
83
- function toTableBorder (border: VxeTablePropTypes.Border | undefined) {
84
- if (border === true) {
85
- return 'full'
86
- }
87
- if (border) {
88
- return border
89
- }
90
- return 'default'
91
- }
92
-
93
- function getBooleanValue (cellValue: any) {
94
- return cellValue === 'TRUE' || cellValue === 'true' || cellValue === true
95
- }
96
-
97
- function getFooterData ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, footerTableData: any[]) {
98
- const $xeGrid = $xeTable.xeGrid
99
- const $xeGantt = $xeTable.xeGantt
100
-
101
- const { footerFilterMethod } = opts
102
- return footerFilterMethod ? footerTableData.filter((items, index) => footerFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, items, $rowIndex: index })) : footerTableData
103
- }
104
-
105
- function getCsvCellTypeLabel (column: any, cellValue: any) {
106
- if (cellValue) {
107
- if (column.type === 'seq') {
108
- return `\t${cellValue}`
109
- }
110
- switch (column.cellType) {
111
- case 'string':
112
- if (!isNaN(cellValue)) {
113
- return `\t${cellValue}`
114
- }
115
- break
116
- case 'number':
117
- break
118
- default:
119
- if (cellValue.length >= 12 && !isNaN(cellValue)) {
120
- return `\t${cellValue}`
121
- }
122
- break
123
- }
124
- }
125
- return cellValue
126
- }
127
-
128
- function toTxtCellLabel (val: any) {
129
- if (/[",\s\n]/.test(val)) {
130
- return `"${val.replace(/"/g, '""')}"`
131
- }
132
- return XEUtils.eqNull(val) ? '' : val
133
- }
134
-
135
- function getElementsByTagName (elem: any, qualifiedName: any) {
136
- return elem.getElementsByTagName(qualifiedName) as HTMLElement[]
137
- }
138
-
139
- function getTxtCellKey (now: number) {
140
- return `#${now}@${XEUtils.uniqueId()}`
141
- }
142
-
143
- function replaceTxtCell (cell: any, vMaps: any) {
144
- return cell.replace(/#\d+@\d+/g, (key: any) => XEUtils.hasOwnProp(vMaps, key) ? vMaps[key] : key)
145
- }
146
-
147
- function getTxtCellValue (val: any, vMaps: any) {
148
- const rest = replaceTxtCell(val, vMaps)
149
- return rest.replace(/^"+$/g, (qVal: any) => '"'.repeat(Math.ceil(qVal.length / 2)))
150
- }
151
-
152
- function toExportField (tableConf: {
153
- fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
154
- titleMaps: Record<string, VxeTableDefines.ColumnInfo>
155
- }, field: string) {
156
- const { fieldMaps, titleMaps } = tableConf
157
- // title 转 field
158
- if (!fieldMaps[field]) {
159
- const teCol = titleMaps[field]
160
- if (teCol && teCol.field) {
161
- field = teCol.field
162
- }
163
- }
164
- return field
165
- }
166
-
167
- function parseCsvAndTxt (tableConf: {
168
- fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
169
- titleMaps: Record<string, VxeTableDefines.ColumnInfo>
170
- }, content: string, cellSeparator: string) {
171
- const list = content.split(enterSymbol)
172
- const rows: any[] = []
173
- let fields: string[] = []
174
- if (list.length) {
175
- const vMaps: any = {}
176
- const now = Date.now()
177
- list.forEach((rVal) => {
178
- if (rVal) {
179
- const item: any = {}
180
- rVal = rVal.replace(/("")|(\n)/g, (text: string, dVal: string) => {
181
- const key = getTxtCellKey(now)
182
- vMaps[key] = dVal ? '"' : '\n'
183
- return key
184
- }).replace(/"(.*?)"/g, (text: string, cVal: string) => {
185
- const key = getTxtCellKey(now)
186
- vMaps[key] = replaceTxtCell(cVal, vMaps)
187
- return key
188
- })
189
- const cells: string[] = rVal.split(cellSeparator)
190
- if (!fields.length) {
191
- fields = cells.map((val: string) => toExportField(tableConf, getTxtCellValue(val.trim(), vMaps)))
192
- } else {
193
- cells.forEach((val, colIndex) => {
194
- if (colIndex < fields.length) {
195
- item[fields[colIndex]] = getTxtCellValue(val.trim(), vMaps)
196
- }
197
- })
198
- rows.push(item)
199
- }
200
- }
201
- })
202
- }
203
- return { fields, rows }
204
- }
205
-
206
- function parseCsv (tableConf: {
207
- fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
208
- titleMaps: Record<string, VxeTableDefines.ColumnInfo>
209
- }, content: string) {
210
- return parseCsvAndTxt(tableConf, content, ',')
211
- }
212
-
213
- function parseTxt (tableConf: {
214
- fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
215
- titleMaps: Record<string, VxeTableDefines.ColumnInfo>
216
- }, content: string) {
217
- return parseCsvAndTxt(tableConf, content, '\t')
218
- }
219
-
220
- function parseHTML (tableConf: {
221
- fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
222
- titleMaps: Record<string, VxeTableDefines.ColumnInfo>
223
- }, content: string) {
224
- const domParser = new DOMParser()
225
- const xmlDoc = domParser.parseFromString(content, 'text/html')
226
- const bodyNodes = getElementsByTagName(xmlDoc, 'body')
227
- const rows: any[] = []
228
- const fields: string[] = []
229
- if (bodyNodes.length) {
230
- const tableNodes = getElementsByTagName(bodyNodes[0], 'table')
231
- if (tableNodes.length) {
232
- const theadNodes = getElementsByTagName(tableNodes[0], 'thead')
233
- if (theadNodes.length) {
234
- XEUtils.arrayEach(getElementsByTagName(theadNodes[0], 'tr'), rowNode => {
235
- XEUtils.arrayEach(getElementsByTagName(rowNode, 'th'), cellNode => {
236
- fields.push(toExportField(tableConf, cellNode.textContent || ''))
237
- })
238
- })
239
- const tbodyNodes = getElementsByTagName(tableNodes[0], 'tbody')
240
- if (tbodyNodes.length) {
241
- XEUtils.arrayEach(getElementsByTagName(tbodyNodes[0], 'tr'), rowNode => {
242
- const item: any = {}
243
- XEUtils.arrayEach(getElementsByTagName(rowNode, 'td'), (cellNode, colIndex) => {
244
- if (fields[colIndex]) {
245
- item[fields[colIndex]] = cellNode.textContent || ''
246
- }
247
- })
248
- rows.push(item)
249
- })
250
- }
251
- }
252
- }
253
- }
254
- return { fields, rows }
255
- }
256
-
257
- function parseXML (tableConf: {
258
- fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
259
- titleMaps: Record<string, VxeTableDefines.ColumnInfo>
260
- }, content: string) {
261
- const domParser = new DOMParser()
262
- const xmlDoc = domParser.parseFromString(content, 'application/xml')
263
- const sheetNodes = getElementsByTagName(xmlDoc, 'Worksheet')
264
- const rows: any[] = []
265
- const fields: string[] = []
266
- if (sheetNodes.length) {
267
- const tableNodes = getElementsByTagName(sheetNodes[0], 'Table')
268
- if (tableNodes.length) {
269
- const rowNodes = getElementsByTagName(tableNodes[0], 'Row')
270
- if (rowNodes.length) {
271
- XEUtils.arrayEach(getElementsByTagName(rowNodes[0], 'Cell'), cellNode => {
272
- fields.push(toExportField(tableConf, cellNode.textContent || ''))
273
- })
274
- XEUtils.arrayEach(rowNodes, (rowNode, index) => {
275
- if (index) {
276
- const item: any = {}
277
- const cellNodes = getElementsByTagName(rowNode, 'Cell')
278
- XEUtils.arrayEach(cellNodes, (cellNode, colIndex) => {
279
- if (fields[colIndex]) {
280
- item[fields[colIndex]] = cellNode.textContent
281
- }
282
- })
283
- rows.push(item)
284
- }
285
- })
286
- }
287
- }
288
- }
289
- return { fields, rows }
290
- }
291
-
292
- function clearColumnConvert (columns: any) {
293
- XEUtils.eachTree(columns, (column: any) => {
294
- delete column._level
295
- delete column._colSpan
296
- delete column._rowSpan
297
- delete column._children
298
- delete column.childNodes
299
- }, { children: 'children' })
300
- }
301
-
302
- const tableExportMethodKeys: (keyof TableExportMethods)[] = ['exportData', 'importByFile', 'importData', 'saveFile', 'readFile', 'print', 'getPrintHtml', 'openImport', 'closeImport', 'openExport', 'closeExport', 'openPrint', 'closePrint']
303
-
304
- hooks.add('tableExportModule', {
305
- setupTable ($xeTable) {
306
- const { props, reactData, internalData } = $xeTable
307
- const { computeTreeOpts, computePrintOpts, computeExportOpts, computeImportOpts, computeSeqOpts, computeRadioOpts, computeCheckboxOpts, computeColumnOpts, computeAggregateOpts, computeRendererOpts } = $xeTable.getComputeMaps()
308
-
309
- const getSeq = (cellValue: any, row: any, $rowIndex: number, column: VxeTableDefines.ColumnInfo, $columnIndex: number) => {
310
- const seqOpts = computeSeqOpts.value
311
- const seqMd = seqOpts.seqMethod || (column as any).seqMethod
312
- if (seqMd) {
313
- return seqMd({
314
- $table: $xeTable,
315
- row,
316
- rowIndex: $xeTable.getRowIndex(row),
317
- _rowIndex: $xeTable.getVTRowIndex(row),
318
- $rowIndex,
319
- column,
320
- columnIndex: $xeTable.getColumnIndex(column),
321
- _columnIndex: $xeTable.getVTColumnIndex(column),
322
- $columnIndex
323
- })
324
- }
325
- return cellValue
326
- }
327
-
328
- function getHeaderTitle (opts: VxeTablePropTypes.ExportHandleOptions, column: VxeTableDefines.ColumnInfo) {
329
- const columnOpts = computeColumnOpts.value
330
- const headExportMethod = column.headerExportMethod || columnOpts.headerExportMethod
331
- return headExportMethod ? headExportMethod({ column, options: opts, $table: $xeTable }) : ((opts.isTitle ? $xeTable.getHeaderCellLabel(column) : column.field) || '')
332
- }
333
-
334
- const toBooleanValue = (cellValue: any) => {
335
- return XEUtils.isBoolean(cellValue) ? (cellValue ? 'TRUE' : 'FALSE') : cellValue
336
- }
337
-
338
- const toStringValue = (cellValue: any) => {
339
- return eqEmptyValue(cellValue) ? '' : `${cellValue}`
340
- }
341
-
342
- const getBodyLabelData = (opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
343
- const { isTreeAllExpanded, isRowGroupAllExpanded, mode: expMode } = opts
344
- const { treeConfig } = props
345
- const { isRowGroupStatus } = reactData
346
- const { fullColumnFieldData, fullAllDataRowIdData } = internalData
347
- const radioOpts = computeRadioOpts.value
348
- const checkboxOpts = computeCheckboxOpts.value
349
- const treeOpts = computeTreeOpts.value
350
- const columnOpts = computeColumnOpts.value
351
- const aggregateOpts = computeAggregateOpts.value
352
- const rendererOpts = computeRendererOpts.value
353
- if (!htmlCellElem) {
354
- htmlCellElem = document.createElement('div')
355
- }
356
- const { handleGetRowId } = createHandleGetRowId($xeTable)
357
- if (isRowGroupStatus) {
358
- // 如果是数据分组
359
- const { mode: aggMode, showTotal, totalMethod, countFields, contentMethod, formatValuesMethod, mapChildrenField } = aggregateOpts
360
- const rest: any[] = []
361
- const expandMaps: Record<string, boolean> = {}
362
- const useMaps: Record<string, boolean> = {}
363
- XEUtils.eachTree(datas, (item, $rowIndex, items, path, parentItem, nodes) => {
364
- const row = item._row || item
365
- const rowid = handleGetRowId(row)
366
- if (useMaps[rowid]) {
367
- return
368
- }
369
- const parentRow = parentItem && parentItem._row ? parentItem._row : parentItem
370
- const pRowid = parentRow ? handleGetRowId(parentRow) : ''
371
- if ((isRowGroupAllExpanded || !parentRow || (expandMaps[pRowid] && $xeTable.isRowExpandByRow(parentRow)))) {
372
- const hasRowChild = mapChildrenField && row[mapChildrenField] && row[mapChildrenField].length
373
- const item: any = {
374
- _row: row,
375
- _level: nodes.length - 1,
376
- _hasChild: hasRowChild,
377
- _expand: hasRowChild && $xeTable.isRowExpandByRow(row)
378
- }
379
- columns.forEach((column, $columnIndex) => {
380
- const { field, editRender, cellRender, aggFunc, rowGroupNode } = column
381
- let cellValue: string | number | boolean | null = ''
382
- const renderOpts = editRender || cellRender
383
- let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
384
- if (!bodyExportMethod && renderOpts && renderOpts.name) {
385
- const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
386
- if (compConf) {
387
- bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
388
- }
389
- }
390
- if (!bodyExportMethod) {
391
- bodyExportMethod = columnOpts.exportMethod
392
- }
393
- if (bodyExportMethod) {
394
- cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
395
- } else {
396
- switch (column.type) {
397
- case 'seq': {
398
- const seqVal = path.map((num, i) => i % 2 === 0 ? (Number(num) + 1) : '.').join('')
399
- cellValue = expMode === 'all' ? seqVal : getSeq(seqVal, row, $rowIndex, column, $columnIndex)
400
- break
401
- }
402
- case 'checkbox': {
403
- cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
404
- item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
405
- item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
406
- break
407
- }
408
- case 'radio': {
409
- cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
410
- item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
411
- item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
412
- break
413
- }
414
- default: {
415
- if (field && row.isAggregate) {
416
- const aggRow: VxeTableDefines.AggregateRowInfo = row
417
- const aggData = aggRow.aggData
418
- const currAggData = aggData ? aggData[field] : null
419
- const groupField = aggRow.groupField
420
- const groupContent = aggRow.groupContent
421
- const childList = mapChildrenField ? (aggRow[mapChildrenField] || []) : []
422
- const childCount = aggRow.childCount
423
- const colRest = fullColumnFieldData[groupField] || {}
424
- const ctParams = {
425
- $table: $xeTable,
426
- groupField,
427
- groupColumn: (colRest ? colRest.column : null) as VxeTableDefines.ColumnInfo,
428
- column,
429
- groupValue: groupContent,
430
- childList,
431
- childCount,
432
- aggValue: null as any,
433
-
434
- /**
435
- * 已废弃
436
- * @deprecated
437
- */
438
- children: childList,
439
- /**
440
- * 已废弃
441
- * @deprecated
442
- */
443
- totalValue: childCount
444
- }
445
- if (aggMode === 'column' ? field === aggRow.groupField : rowGroupNode) {
446
- cellValue = groupContent
447
- if (contentMethod) {
448
- cellValue = `${contentMethod(ctParams)}`
449
- }
450
- if (showTotal) {
451
- cellValue = getI18n('vxe.table.rowGroupContentTotal', [cellValue, totalMethod ? totalMethod(ctParams) : childCount, childCount])
452
- }
453
- } else if ($xeTable.getPivotTableAggregateCellAggValue) {
454
- const aggParams = {
455
- $table: $xeTable,
456
- row,
457
- column
458
- }
459
- cellValue = $xeTable.getPivotTableAggregateCellAggValue(aggParams)
460
- } else if (aggFunc === true || (countFields && countFields.includes(field))) {
461
- cellValue = currAggData ? currAggData.value : childCount
462
- ctParams.aggValue = cellValue
463
- if (formatValuesMethod) {
464
- cellValue = formatValuesMethod(ctParams)
465
- }
466
- }
467
- } else if (opts.original) {
468
- cellValue = getCellValue(row, column)
469
- } else {
470
- cellValue = $xeTable.getCellLabel(row, column)
471
- if (column.type === 'html') {
472
- htmlCellElem.innerHTML = cellValue
473
- cellValue = htmlCellElem.innerText.trim()
474
- } else {
475
- const cell = $xeTable.getCellElement(row, column)
476
- if (cell && !hasClass(cell, 'is--progress')) {
477
- cellValue = cell.innerText.trim()
478
- }
479
- }
480
- }
481
- break
482
- }
483
- }
484
- }
485
- item[column.id] = toStringValue(cellValue)
486
- })
487
- useMaps[rowid] = true
488
- if (pRowid) {
489
- expandMaps[pRowid] = true
490
- }
491
- rest.push(Object.assign(item, row))
492
- }
493
- }, { children: mapChildrenField })
494
- return rest
495
- }
496
- if (treeConfig) {
497
- // 如果是树结构
498
- const { seqMode } = treeOpts
499
- const childrenField = treeOpts.children || treeOpts.childrenField
500
- const rest: any[] = []
501
- const expandMaps: Record<string, boolean> = {}
502
- const useMaps: Record<string, boolean> = {}
503
- XEUtils.eachTree(datas, (item, $rowIndex, items, path, parentItem, nodes) => {
504
- const row = item._row || item
505
- const rowid = handleGetRowId(row)
506
- if (useMaps[rowid]) {
507
- return
508
- }
509
- const parentRow = parentItem && parentItem._row ? parentItem._row : parentItem
510
- const pRowid = parentRow ? handleGetRowId(parentRow) : ''
511
- if ((isTreeAllExpanded || !parentRow || (expandMaps[pRowid] && $xeTable.isTreeExpandByRow(parentRow)))) {
512
- const hasRowChild = row[childrenField] && row[childrenField].length
513
- const item: any = {
514
- _row: row,
515
- _level: nodes.length - 1,
516
- _hasChild: hasRowChild,
517
- _expand: hasRowChild && $xeTable.isTreeExpandByRow(row)
518
- }
519
- const rowRest = fullAllDataRowIdData[rowid] || {}
520
- columns.forEach((column, $columnIndex) => {
521
- let cellValue: string | number | boolean | null = ''
522
- const renderOpts = column.editRender || column.cellRender
523
- let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
524
- if (!bodyExportMethod && renderOpts && renderOpts.name) {
525
- const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
526
- if (compConf) {
527
- bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
528
- }
529
- }
530
- if (!bodyExportMethod) {
531
- bodyExportMethod = columnOpts.exportMethod
532
- }
533
- if (bodyExportMethod) {
534
- cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
535
- } else {
536
- switch (column.type) {
537
- case 'seq': {
538
- let seqVal: number | string = path.map((num, i) => i % 2 === 0 ? (Number(num) + 1) : '.').join('')
539
- if (seqMode === 'increasing') {
540
- seqVal = rowRest ? (rowRest._index + 1) : -1
541
- }
542
- cellValue = expMode === 'all' ? seqVal : getSeq(seqVal, row, $rowIndex, column, $columnIndex)
543
- break
544
- }
545
- case 'checkbox':
546
- cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
547
- item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
548
- item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
549
- break
550
- case 'radio':
551
- cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
552
- item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
553
- item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
554
- break
555
- default:
556
- if (opts.original) {
557
- cellValue = getCellValue(row, column)
558
- } else {
559
- cellValue = $xeTable.getCellLabel(row, column)
560
- if (column.type === 'html') {
561
- htmlCellElem.innerHTML = cellValue
562
- cellValue = htmlCellElem.innerText.trim()
563
- } else {
564
- const cell = $xeTable.getCellElement(row, column)
565
- if (cell && !hasClass(cell, 'is--progress')) {
566
- cellValue = cell.innerText.trim()
567
- }
568
- }
569
- }
570
- }
571
- }
572
- item[column.id] = toStringValue(cellValue)
573
- })
574
- useMaps[rowid] = true
575
- if (pRowid) {
576
- expandMaps[pRowid] = true
577
- }
578
- rest.push(Object.assign(item, row))
579
- }
580
- }, { children: childrenField })
581
- return rest
582
- }
583
- return datas.map((row, $rowIndex) => {
584
- const item: any = {
585
- _row: row
586
- }
587
- columns.forEach((column, $columnIndex) => {
588
- let cellValue: string | number | boolean | null = ''
589
- const renderOpts = column.editRender || column.cellRender
590
- let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
591
- if (!bodyExportMethod && renderOpts && renderOpts.name) {
592
- const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
593
- if (compConf) {
594
- bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
595
- }
596
- }
597
- if (bodyExportMethod) {
598
- cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
599
- } else {
600
- switch (column.type) {
601
- case 'seq': {
602
- const seqValue = $rowIndex + 1
603
- cellValue = expMode === 'all' ? seqValue : getSeq(seqValue, row, $rowIndex, column, $columnIndex)
604
- break
605
- }
606
- case 'checkbox':
607
- cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
608
- item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
609
- item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
610
- break
611
- case 'radio':
612
- cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
613
- item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
614
- item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
615
- break
616
- default:
617
- if (opts.original) {
618
- cellValue = getCellValue(row, column)
619
- } else {
620
- cellValue = $xeTable.getCellLabel(row, column)
621
- if (column.type === 'html') {
622
- htmlCellElem.innerHTML = cellValue
623
- cellValue = htmlCellElem.innerText.trim()
624
- } else {
625
- const cell = $xeTable.getCellElement(row, column)
626
- if (cell && !hasClass(cell, 'is--progress')) {
627
- cellValue = cell.innerText.trim()
628
- }
629
- }
630
- }
631
- }
632
- }
633
- item[column.id] = toStringValue(cellValue)
634
- })
635
- return item
636
- })
637
- }
638
-
639
- const getExportData = (opts: VxeTablePropTypes.ExportHandleOptions) => {
640
- const $xeGrid = $xeTable.xeGrid
641
- const $xeGantt = $xeTable.xeGantt
642
-
643
- const { columns, dataFilterMethod } = opts
644
- let datas = opts.data
645
- if (dataFilterMethod) {
646
- datas = datas.filter((row, index) => dataFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, row, $rowIndex: index }))
647
- }
648
- return getBodyLabelData(opts, columns, datas)
649
- }
650
-
651
- const getFooterCellValue = (opts: VxeTablePropTypes.ExportHandleOptions, row: any, column: VxeTableDefines.ColumnInfo) => {
652
- const columnOpts = computeColumnOpts.value
653
- const rendererOpts = computeRendererOpts.value
654
- const renderOpts = column.editRender || column.cellRender
655
- let footLabelMethod: VxeColumnPropTypes.FooterExportMethod | undefined = column.footerExportMethod
656
- if (!footLabelMethod && renderOpts && renderOpts.name) {
657
- const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
658
- if (compConf) {
659
- footLabelMethod = compConf.tableFooterExportMethod || compConf.footerExportMethod
660
- }
661
- }
662
- if (!footLabelMethod) {
663
- footLabelMethod = columnOpts.footerExportMethod
664
- }
665
- if (footLabelMethod) {
666
- const _columnIndex = $xeTable.getVTColumnIndex(column)
667
- return footLabelMethod({ $table: $xeTable, items: row, itemIndex: _columnIndex, row, _columnIndex, column, options: opts })
668
- }
669
- const cellValue = $xeTable.getFooterCellLabel(row, column)
670
- return cellValue
671
- }
672
-
673
- const toCsv = ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
674
- let content = csvBOM
675
- if (opts.isHeader) {
676
- content += columns.map((column) => toTxtCellLabel(getHeaderTitle(opts, column))).join(',') + enterSymbol
677
- }
678
- datas.forEach((row) => {
679
- content += columns.map((column) => toTxtCellLabel(getCsvCellTypeLabel(column, row[column.id]))).join(',') + enterSymbol
680
- })
681
- if (opts.isFooter) {
682
- const { footerTableData } = reactData
683
- const footers = getFooterData($xeTable, opts, footerTableData)
684
- footers.forEach((row) => {
685
- content += columns.map((column: any) => toTxtCellLabel(getFooterCellValue(opts, row, column))).join(',') + enterSymbol
686
- })
687
- }
688
- return content
689
- }
690
-
691
- const toTxt = ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
692
- let content = ''
693
- if (opts.isHeader) {
694
- content += columns.map((column) => toTxtCellLabel(getHeaderTitle(opts, column))).join('\t') + enterSymbol
695
- }
696
- datas.forEach((row) => {
697
- content += columns.map((column) => toTxtCellLabel(row[column.id])).join('\t') + enterSymbol
698
- })
699
- if (opts.isFooter) {
700
- const { footerTableData } = reactData
701
- const footers = getFooterData($xeTable, opts, footerTableData)
702
- footers.forEach((row) => {
703
- content += columns.map((column: any) => toTxtCellLabel(getFooterCellValue(opts, row, column))).join('\t') + enterSymbol
704
- })
705
- }
706
- return content
707
- }
708
-
709
- const hasEllipsis = (column: VxeTableDefines.ColumnInfo, property: 'showOverflow' | 'showHeaderOverflow', allColumnOverflow: VxeTablePropTypes.ShowOverflow | undefined) => {
710
- const columnOverflow = column[property]
711
- const headOverflow = XEUtils.isUndefined(columnOverflow) || XEUtils.isNull(columnOverflow) ? allColumnOverflow : columnOverflow
712
- const showEllipsis = headOverflow === 'ellipsis'
713
- const showTitle = headOverflow === 'title'
714
- const showTooltip = headOverflow === true || headOverflow === 'tooltip'
715
- let isEllipsis = showTitle || showTooltip || showEllipsis
716
- // 虚拟滚动不支持动态高度
717
- const { scrollXLoad, scrollYLoad } = reactData
718
- if ((scrollXLoad || scrollYLoad) && !isEllipsis) {
719
- isEllipsis = true
720
- }
721
- return isEllipsis
722
- }
723
-
724
- const getCustomColKey = (conf: VxeTableDefines.ColumnInfo<any> | VxeTablePropTypes.ExportOrPrintColumnOption) => {
725
- return `${conf.field || ''}:${conf.type || ''}`
726
- }
727
-
728
- const toHtml = (opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
729
- const { id, border, treeConfig, headerAlign: allHeaderAlign, align: allAlign, footerAlign: allFooterAlign, showOverflow: allColumnOverflow, showHeaderOverflow: allColumnHeaderOverflow } = props
730
- const { isAllSelected, isIndeterminate } = reactData
731
- const { mergeBodyCellMaps, mergeFooterCellMaps } = internalData
732
- const treeOpts = computeTreeOpts.value
733
- const { print: isPrint, widthMode, isHeader, isFooter, isColgroup, isMerge, colgroups, _columnConfs, original } = opts
734
- const isAutoWidth = widthMode === 'auto'
735
- const isScaleWidth = widthMode === 'scale'
736
- const isDefaultWidth = !isAutoWidth && !isScaleWidth
737
-
738
- const customWidthMaps: Record<string, number | string> = {}
739
- if (_columnConfs) {
740
- _columnConfs.forEach(conf => {
741
- if (!isColumnInfo(conf)) {
742
- if ((conf.field || conf.type) && conf.width) {
743
- customWidthMaps[getCustomColKey(conf)] = conf.width
744
- }
745
- }
746
- })
747
- }
748
-
749
- // 计算宽度
750
- const colWidthMaps: Record<string, number> = {}
751
- const printWidthMaps: Record<string, number> = {}
752
- if (isPrint) {
753
- let tableWidth = 0
754
- columns.forEach(column => {
755
- tableWidth += column.renderWidth
756
- })
757
- if (colgroups) {
758
- colgroups.forEach((cols) => {
759
- cols.forEach((column: any) => {
760
- if (!column.childNodes || !column.childNodes.length) {
761
- return
762
- }
763
- let childWidth = 0
764
- let countChild = 0
765
- XEUtils.eachTree([column], item => {
766
- if (!item.childNodes || !column.childNodes.length) {
767
- countChild++
768
- }
769
- const ptWidth = printWidthMaps[item.id]
770
- childWidth += ptWidth || 0
771
- }, { children: 'childNodes' })
772
- const colWidth = childWidth - countChild
773
- colWidthMaps[column.id] = colWidth
774
- printWidthMaps[column.id] = XEUtils.floor(colWidth / tableWidth * 180, 2)
775
- })
776
- })
777
- }
778
- columns.forEach(column => {
779
- const colWidth = column.renderWidth
780
- if (column.width) {
781
- colWidthMaps[column.id] = colWidth
782
- }
783
- printWidthMaps[column.id] = XEUtils.floor(colWidth / tableWidth * 180, 2)
784
- })
785
- }
786
-
787
- const getHeaderWidthStyle = (column: VxeTableDefines.ColumnInfo) => {
788
- const cmColKey = getCustomColKey(column)
789
- const cmWidthMaps = customWidthMaps[cmColKey]
790
- if (cmWidthMaps) {
791
- return 'width:' + toCssUnit(cmWidthMaps)
792
- }
793
- if (isAutoWidth) {
794
- return ''
795
- }
796
- if (isScaleWidth) {
797
- return printWidthMaps[column.id] ? ('width:' + printWidthMaps[column.id] + 'mm') : ''
798
- }
799
- return colWidthMaps[column.id] ? ('width:' + toCssUnit(colWidthMaps[column.id])) : ''
800
- }
801
-
802
- const getCellWidthStyle = (column: VxeTableDefines.ColumnInfo) => {
803
- const cmColKey = getCustomColKey(column)
804
- const cmWidthMaps = customWidthMaps[cmColKey]
805
- if (cmWidthMaps) {
806
- return 'width:' + toCssUnit(cmWidthMaps)
807
- }
808
- if (isAutoWidth || isDefaultWidth) {
809
- return ''
810
- }
811
- if (isScaleWidth) {
812
- return printWidthMaps[column.id] ? ('width:' + printWidthMaps[column.id] + 'mm') : ''
813
- }
814
- return colWidthMaps[column.id] ? ('width:' + toCssUnit(colWidthMaps[column.id])) : ''
815
- }
816
-
817
- const allCls = 'check-all'
818
- const clss = [
819
- 'vxe-table',
820
- `border--${toTableBorder(border)}`,
821
- isPrint ? 'is--print' : '',
822
- isAutoWidth ? 'is--auto-width' : '',
823
- isScaleWidth ? 'is--scale-width' : '',
824
- isDefaultWidth ? 'is--default-width' : '',
825
- isHeader ? 'is--header' : ''
826
- ].filter(cls => cls)
827
- const tables = [
828
- `<table class="${clss.join(' ')}" border="0" cellspacing="0" cellpadding="0">`,
829
- `<colgroup>${columns.map((column) => `<col style="${getHeaderWidthStyle(column)}">`).join('')}</colgroup>`
830
- ]
831
- if (isHeader) {
832
- tables.push('<thead>')
833
- if (isColgroup && !original) {
834
- colgroups.forEach((cols) => {
835
- tables.push(
836
- `<tr>${cols.map((column: any) => {
837
- const headAlign = column.headerAlign || column.align || allHeaderAlign || allAlign
838
- const classNames = hasEllipsis(column, 'showHeaderOverflow', allColumnHeaderOverflow) ? ['col--ellipsis'] : []
839
- const cellTitle = getHeaderTitle(opts, column)
840
- if (headAlign) {
841
- classNames.push(`col--${headAlign}`)
842
- }
843
- if (column.type === 'checkbox') {
844
- return `<th class="${classNames.join(' ')}" colspan="${column._colSpan}" rowspan="${column._rowSpan}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" class="${allCls}" ${isAllSelected ? 'checked' : ''}><span>${cellTitle}</span></div></th>`
845
- }
846
- return `<th class="${classNames.join(' ')}" colspan="${column._colSpan}" rowspan="${column._rowSpan}" title="${cellTitle}"><div style="${getCellWidthStyle(column)}"><span>${formatText(cellTitle, true)}</span></div></th>`
847
- }).join('')}</tr>`
848
- )
849
- })
850
- } else {
851
- tables.push(
852
- `<tr>${columns.map((column: any) => {
853
- const headAlign = column.headerAlign || column.align || allHeaderAlign || allAlign
854
- const classNames = hasEllipsis(column, 'showHeaderOverflow', allColumnHeaderOverflow) ? ['col--ellipsis'] : []
855
- const cellTitle = getHeaderTitle(opts, column)
856
- if (headAlign) {
857
- classNames.push(`col--${headAlign}`)
858
- }
859
- if (column.type === 'checkbox') {
860
- return `<th class="${classNames.join(' ')}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" class="${allCls}" ${isAllSelected ? 'checked' : ''}><span>${cellTitle}</span></div></th>`
861
- }
862
- return `<th class="${classNames.join(' ')}" title="${cellTitle}"><div style="${getCellWidthStyle(column)}"><span>${formatText(cellTitle, true)}</span></div></th>`
863
- }).join('')}</tr>`
864
- )
865
- }
866
- tables.push('</thead>')
867
- }
868
- if (datas.length) {
869
- tables.push('<tbody>')
870
- if (treeConfig) {
871
- datas.forEach((item: any) => {
872
- tables.push(
873
- '<tr>' + columns.map((column: any) => {
874
- const colid = column.id
875
- const cellAlign = column.align || allAlign
876
- const classNames = hasEllipsis(column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
877
- const cellValue = item[colid]
878
- if (cellAlign) {
879
- classNames.push(`col--${cellAlign}`)
880
- }
881
- if (column.treeNode) {
882
- let treeIcon = ''
883
- if (item._hasChild) {
884
- treeIcon = `<i class="${item._expand ? 'vxe-table--tree-fold-icon' : 'vxe-table--tree-unfold-icon'}"></i>`
885
- }
886
- classNames.push('vxe-table--tree-node')
887
- if (column.type === 'radio') {
888
- return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}"><div class="vxe-table--tree-node-wrapper" style="padding-left: ${item._level * treeOpts.indent}px"><div class="vxe-table--tree-icon-wrapper">${treeIcon}</div><div class="vxe-table--tree-cell"><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></div></div></td>`
889
- } else if (column.type === 'checkbox') {
890
- return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}"><div class="vxe-table--tree-node-wrapper" style="padding-left: ${item._level * treeOpts.indent}px"><div class="vxe-table--tree-icon-wrapper">${treeIcon}</div><div class="vxe-table--tree-cell"><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></div></div></td>`
891
- }
892
- return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}"><div class="vxe-table--tree-node-wrapper" style="padding-left: ${item._level * treeOpts.indent}px"><div class="vxe-table--tree-icon-wrapper">${treeIcon}</div><div class="vxe-table--tree-cell">${cellValue}</div></div></div></td>`
893
- }
894
- if (column.type === 'radio') {
895
- return `<td class="${classNames.join(' ')}"><div style="${getCellWidthStyle(column)}"><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></td>`
896
- } else if (column.type === 'checkbox') {
897
- return `<td class="${classNames.join(' ')}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></td>`
898
- }
899
- return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}">${formatText(cellValue, true)}</div></td>`
900
- }).join('') + '</tr>'
901
- )
902
- })
903
- } else {
904
- datas.forEach((item) => {
905
- tables.push(
906
- '<tr>' + columns.map((column) => {
907
- const cellAlign = column.align || allAlign
908
- const classNames = hasEllipsis(column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
909
- const cellValue = item[column.id]
910
- let rowSpan = 1
911
- let colSpan = 1
912
- if (isMerge) {
913
- const _rowIndex = $xeTable.getVTRowIndex(item._row)
914
- const _columnIndex = $xeTable.getVTColumnIndex(column)
915
- const spanRest = mergeBodyCellMaps[`${_rowIndex}:${_columnIndex}`]
916
- if (spanRest) {
917
- const { rowspan, colspan } = spanRest
918
- if (!rowspan || !colspan) {
919
- return ''
920
- }
921
- if (rowspan > 1) {
922
- rowSpan = rowspan
923
- }
924
- if (colspan > 1) {
925
- colSpan = colspan
926
- }
927
- }
928
- }
929
- if (cellAlign) {
930
- classNames.push(`col--${cellAlign}`)
931
- }
932
- if (column.type === 'radio') {
933
- return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}"><div style="${getCellWidthStyle(column)}"><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></td>`
934
- } else if (column.type === 'checkbox') {
935
- return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></td>`
936
- }
937
- return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}" title="${cellValue}"><div style="${getCellWidthStyle(column)}">${formatText(cellValue, true)}</div></td>`
938
- }).join('') + '</tr>'
939
- )
940
- })
941
- }
942
- tables.push('</tbody>')
943
- }
944
- if (isFooter) {
945
- const { footerTableData } = reactData
946
- const footers = getFooterData($xeTable, opts, footerTableData)
947
- if (footers.length) {
948
- tables.push('<tfoot>')
949
- footers.forEach((row, rIndex) => {
950
- tables.push(
951
- `<tr>${columns.map((column) => {
952
- const footAlign = column.footerAlign || column.align || allFooterAlign || allAlign
953
- const classNames = hasEllipsis(column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
954
- const cellValue = getFooterCellValue(opts, row, column)
955
- let rowSpan = 1
956
- let colSpan = 1
957
- if (isMerge) {
958
- const _rowIndex = rIndex
959
- const _columnIndex = $xeTable.getVTColumnIndex(column)
960
- const spanRest = mergeFooterCellMaps[`${_rowIndex}:${_columnIndex}`]
961
- if (spanRest) {
962
- const { rowspan, colspan } = spanRest
963
- if (!rowspan || !colspan) {
964
- return ''
965
- }
966
- if (rowspan > 1) {
967
- rowSpan = rowspan
968
- }
969
- if (colspan > 1) {
970
- colSpan = colspan
971
- }
972
- }
973
- }
974
- if (footAlign) {
975
- classNames.push(`col--${footAlign}`)
976
- }
977
- return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}" title="${cellValue}"><div style="${getCellWidthStyle(column)}">${formatText(cellValue, true)}</div></td>`
978
- }).join('')}</tr>`
979
- )
980
- })
981
- tables.push('</tfoot>')
982
- }
983
- }
984
- // 是否半选状态
985
- const script = !isAllSelected && isIndeterminate ? `<script>(function(){var a=document.querySelector(".${allCls}");if(a){a.indeterminate=true}})()</script>` : ''
986
- tables.push('</table>', script)
987
- return isPrint ? tables.join('') : createHtmlPage(opts, tables.join(''))
988
- }
989
-
990
- const toXML = (opts: any, columns: any, datas: any) => {
991
- let xml = [
992
- '<?xml version="1.0"?>',
993
- '<?mso-application progid="Excel.Sheet"?>',
994
- '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">',
995
- '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">',
996
- '<Version>16.00</Version>',
997
- '</DocumentProperties>',
998
- '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">',
999
- '<WindowHeight>7920</WindowHeight>',
1000
- '<WindowWidth>21570</WindowWidth>',
1001
- '<WindowTopX>32767</WindowTopX>',
1002
- '<WindowTopY>32767</WindowTopY>',
1003
- '<ProtectStructure>False</ProtectStructure>',
1004
- '<ProtectWindows>False</ProtectWindows>',
1005
- '</ExcelWorkbook>',
1006
- `<Worksheet ss:Name="${opts.sheetName}">`,
1007
- '<Table>',
1008
- columns.map((column: any) => `<Column ss:Width="${column.renderWidth}"/>`).join('')
1009
- ].join('')
1010
- if (opts.isHeader) {
1011
- xml += `<Row>${columns.map((column: any) => `<Cell><Data ss:Type="String">${getHeaderTitle(opts, column)}</Data></Cell>`).join('')}</Row>`
1012
- }
1013
- datas.forEach((row: any) => {
1014
- xml += '<Row>' + columns.map((column: any) => `<Cell><Data ss:Type="String">${row[column.id]}</Data></Cell>`).join('') + '</Row>'
1015
- })
1016
- if (opts.isFooter) {
1017
- const { footerTableData } = reactData
1018
- const footers = getFooterData($xeTable, opts, footerTableData)
1019
- footers.forEach((row: any) => {
1020
- xml += `<Row>${columns.map((column: any) => `<Cell><Data ss:Type="String">${getFooterCellValue(opts, row, column)}</Data></Cell>`).join('')}</Row>`
1021
- })
1022
- }
1023
- return `${xml}</Table></Worksheet></Workbook>`
1024
- }
1025
-
1026
- const getContent = ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
1027
- if (columns.length) {
1028
- switch (opts.type) {
1029
- case 'csv':
1030
- return toCsv($xeTable, opts, columns, datas)
1031
- case 'txt':
1032
- return toTxt($xeTable, opts, columns, datas)
1033
- case 'html':
1034
- return toHtml(opts, columns, datas)
1035
- case 'xml':
1036
- return toXML(opts, columns, datas)
1037
- }
1038
- }
1039
- return ''
1040
- }
1041
-
1042
- const downloadFile = (opts: any, content: any) => {
1043
- const { filename, type, download } = opts
1044
- if (!download) {
1045
- const blob = getExportBlobByContent(content, opts)
1046
- return Promise.resolve({ type, content, blob })
1047
- }
1048
- if (VxeUI.saveFile) {
1049
- VxeUI.saveFile({ filename, type, content }).then(() => {
1050
- if (opts.message !== false) {
1051
- if (VxeUI.modal) {
1052
- VxeUI.modal.message({ content: getI18n('vxe.table.expSuccess'), status: 'success' })
1053
- }
1054
- }
1055
- })
1056
- }
1057
- }
1058
-
1059
- const handleExport = (opts: VxeTablePropTypes.ExportHandleOptions) => {
1060
- const $xeGrid = $xeTable.xeGrid
1061
- const $xeGantt = $xeTable.xeGantt
1062
-
1063
- const { remote, columns, colgroups, exportMethod, afterExportMethod } = opts
1064
- return new Promise(resolve => {
1065
- if (remote) {
1066
- const params = { options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt }
1067
- resolve(exportMethod ? exportMethod(params) : params)
1068
- } else {
1069
- const datas = getExportData(opts)
1070
- resolve(
1071
- $xeTable.preventEvent(null, 'event.export', { options: opts, columns, colgroups, datas }, () => {
1072
- return downloadFile(opts, getContent($xeTable, opts, columns, datas))
1073
- })
1074
- )
1075
- }
1076
- }).then((params: any) => {
1077
- clearColumnConvert(columns)
1078
- if (!opts.print) {
1079
- if (afterExportMethod) {
1080
- afterExportMethod({ status: true, options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1081
- }
1082
- }
1083
- return Object.assign({ status: true }, params)
1084
- }).catch(() => {
1085
- clearColumnConvert(columns)
1086
- if (!opts.print) {
1087
- if (afterExportMethod) {
1088
- afterExportMethod({ status: false, options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1089
- }
1090
- }
1091
- const params = { status: false }
1092
- return Promise.reject(params)
1093
- })
1094
- }
1095
-
1096
- const handleImport = (content: any, opts: any) => {
1097
- const { tableFullColumn, _importResolve, _importReject } = internalData
1098
- let rest: {
1099
- fields: string[];
1100
- rows: any[];
1101
- } = { fields: [], rows: [] }
1102
- const tableFieldMaps: Record<string, VxeTableDefines.ColumnInfo> = {}
1103
- const tableTitleMaps: Record<string, VxeTableDefines.ColumnInfo> = {}
1104
- tableFullColumn.forEach((column) => {
1105
- const field = column.field
1106
- const title = $xeTable.getHeaderCellLabel(column)
1107
- if (field) {
1108
- tableFieldMaps[field] = column
1109
- }
1110
- if (title) {
1111
- tableTitleMaps[title] = column
1112
- }
1113
- })
1114
- const tableConf = {
1115
- fieldMaps: tableFieldMaps,
1116
- titleMaps: tableTitleMaps
1117
- }
1118
- switch (opts.type) {
1119
- case 'csv':
1120
- rest = parseCsv(tableConf, content)
1121
- break
1122
- case 'txt':
1123
- rest = parseTxt(tableConf, content)
1124
- break
1125
- case 'html':
1126
- rest = parseHTML(tableConf, content)
1127
- break
1128
- case 'xml':
1129
- rest = parseXML(tableConf, content)
1130
- break
1131
- }
1132
- const { fields, rows } = rest
1133
- const status = fields.some(field => tableFieldMaps[field] || tableTitleMaps[field])
1134
- if (status) {
1135
- $xeTable.createData(rows)
1136
- .then((data: any) => {
1137
- let loadRest
1138
- if (opts.mode === 'insert' || opts.mode === 'insertBottom') {
1139
- loadRest = $xeTable.insertAt(data, -1)
1140
- } else if (opts.mode === 'insertTop') {
1141
- loadRest = $xeTable.insert(data)
1142
- } else {
1143
- loadRest = $xeTable.reloadData(data)
1144
- }
1145
- if (opts.message !== false) {
1146
- if (VxeUI.modal) {
1147
- VxeUI.modal.message({ content: getI18n('vxe.table.impSuccess', [rows.length]), status: 'success' })
1148
- }
1149
- }
1150
- return loadRest.then(() => {
1151
- if (_importResolve) {
1152
- _importResolve({ status: true })
1153
- }
1154
- })
1155
- })
1156
- } else if (opts.message !== false) {
1157
- if (VxeUI.modal) {
1158
- VxeUI.modal.message({ content: getI18n('vxe.error.impFields'), status: 'error' })
1159
- }
1160
- if (_importReject) {
1161
- _importReject({ status: false, msg: 'field mismatching' })
1162
- }
1163
- }
1164
- }
1165
-
1166
- const handleFileImport = (file: File, opts: any) => {
1167
- const { importMethod, afterImportMethod } = opts
1168
- const { type, filename } = parseFile(file)
1169
- const importOpts = computeImportOpts.value
1170
-
1171
- // 检查类型,如果为自定义导出,则不需要校验类型
1172
- if (!importMethod && !XEUtils.includes(XEUtils.keys(importOpts._typeMaps), type)) {
1173
- if (opts.message !== false) {
1174
- if (VxeUI.modal) {
1175
- VxeUI.modal.message({ content: getI18n('vxe.error.notType', [type]), status: 'error' })
1176
- }
1177
- }
1178
- const params = { status: false, msg: 'type error' }
1179
- return Promise.reject(params)
1180
- }
1181
-
1182
- const rest = new Promise((resolve, reject) => {
1183
- const _importResolve = (params?: any) => {
1184
- resolve(params)
1185
- internalData._importResolve = null
1186
- internalData._importReject = null
1187
- }
1188
- const _importReject = (params?: any) => {
1189
- reject(params)
1190
- internalData._importResolve = null
1191
- internalData._importReject = null
1192
- }
1193
- internalData._importResolve = _importResolve
1194
- internalData._importReject = _importReject
1195
- if (window.FileReader) {
1196
- const options = Object.assign({ mode: 'insertTop' }, opts, { type, filename })
1197
- if (options.remote) {
1198
- if (importMethod) {
1199
- Promise.resolve(importMethod({ file, options, $table: $xeTable })).then(() => {
1200
- _importResolve({ status: true })
1201
- }).catch(() => {
1202
- _importResolve({ status: true })
1203
- })
1204
- } else {
1205
- _importResolve({ status: true })
1206
- }
1207
- } else {
1208
- const { tableFullColumn } = internalData
1209
- $xeTable.preventEvent(null, 'event.import', { file, options, columns: tableFullColumn }, () => {
1210
- const reader = new FileReader()
1211
- reader.onerror = () => {
1212
- errLog('vxe.error.notType', [type])
1213
- _importReject({ status: false, msg: 'reading file error' })
1214
- }
1215
- reader.onload = (e: any) => {
1216
- handleImport(e.target.result, options)
1217
- }
1218
- reader.readAsText(file, options.encoding || 'UTF-8')
1219
- })
1220
- }
1221
- } else {
1222
- // 不支持的浏览器
1223
- errLog('vxe.error.notExp')
1224
- _importResolve({ status: false, msg: 'unsupported browser' })
1225
- }
1226
- })
1227
-
1228
- return rest.then(() => {
1229
- if (afterImportMethod) {
1230
- afterImportMethod({ status: true, options: opts, $table: $xeTable })
1231
- }
1232
- }).catch((e) => {
1233
- if (afterImportMethod) {
1234
- afterImportMethod({ status: false, options: opts, $table: $xeTable })
1235
- }
1236
- return Promise.reject(e)
1237
- })
1238
- }
1239
-
1240
- const handleFilterColumns = (exportOpts: VxeTablePropTypes.ExportConfig, column: VxeTableDefines.ColumnInfo, columns: VxeTableDefines.ColumnInfo[] | VxeTablePropTypes.ExportOrPrintColumnOption[]) => {
1241
- return columns.some((item: any) => {
1242
- if (isColumnInfo(item)) {
1243
- return column.id === (item as any).id
1244
- } else if (XEUtils.isString(item)) {
1245
- return column.field === item
1246
- } else {
1247
- const colid = item.id || item.colId
1248
- const type = item.type
1249
- const field = item.field
1250
- if (colid) {
1251
- return column.id === colid
1252
- } else if (field && type) {
1253
- return column.field === field && column.type === type
1254
- } else if (field) {
1255
- return column.field === field
1256
- } else if (type) {
1257
- return column.type === type
1258
- }
1259
- }
1260
- return false
1261
- })
1262
- }
1263
-
1264
- const handleFilterFields = (exportOpts: VxeTablePropTypes.ExportConfig, column: VxeTableDefines.ColumnInfo, includeFields: string[] | undefined, includeFdMaps: Record<string, number>, excludeFdMaps: Record<string, number>, extraFdMaps: Record<string, number>) => {
1265
- const { field } = column
1266
- if (excludeFdMaps[field]) {
1267
- return false
1268
- }
1269
- if (includeFields) {
1270
- if (includeFdMaps[field]) {
1271
- return true
1272
- }
1273
- return false
1274
- }
1275
- if (extraFdMaps[field]) {
1276
- return true
1277
- }
1278
- return exportOpts.original ? !!field : defaultFilterExportColumn(column)
1279
- }
1280
-
1281
- const handleExportAndPrint = (options: VxeTablePropTypes.ExportOpts | VxeTablePropTypes.ExportConfig, isPrint?: boolean) => {
1282
- const $xeGrid = $xeTable.xeGrid
1283
- const $xeGantt = $xeTable.xeGantt
1284
- const $xeGGWrapper = $xeGrid || $xeGantt
1285
-
1286
- const { treeConfig, showHeader, showFooter } = props
1287
- const { initStore, isGroup, rowGroupList, footerTableData, exportStore, exportParams } = reactData
1288
- const { collectColumn, mergeBodyList, mergeFooterList } = internalData
1289
- const exportOpts = computeExportOpts.value
1290
- const printOpts = computePrintOpts.value
1291
- const hasTree = !!treeConfig
1292
- const hasRowGroup = rowGroupList.length > 0
1293
- const selectRecords = $xeTable.getCheckboxRecords()
1294
- const proxyOpts = $xeGGWrapper ? $xeGGWrapper.getComputeMaps().computeProxyOpts.value : {} as VxeGridPropTypes.ProxyOpts
1295
- const hasFooter = !!footerTableData.length
1296
- const hasMerge = !!(mergeBodyList.length || mergeFooterList.length)
1297
- const defOpts = Object.assign({
1298
- message: true,
1299
- isHeader: showHeader,
1300
- isTitle: showHeader,
1301
- isFooter: showFooter,
1302
- isColgroup: isGroup,
1303
- isMerge: hasMerge,
1304
- useStyle: true,
1305
- current: 'current',
1306
- modes: (proxyOpts.ajax && proxyOpts.ajax.queryAll ? ['all'] : []).concat(['current', 'selected', 'empty'])
1307
- }, options)
1308
-
1309
- // 已废弃,参数 isAllExpand
1310
- if (XEUtils.isBoolean((defOpts as any).isAllExpand)) {
1311
- warnLog('vxe.error.delProp', ['isAllExpand', 'isTreeAllExpanded'])
1312
- defOpts.isTreeAllExpanded = (defOpts as any).isAllExpand
1313
- }
1314
-
1315
- const types: string[] = isPrint ? [] : (defOpts.types || XEUtils.keys(exportOpts._typeMaps))
1316
- const modes: string[] = defOpts.modes || []
1317
- const checkMethod = (isPrint ? printOpts : exportOpts).checkMethod
1318
- const exportColumns = collectColumn.slice(0)
1319
- const { columns, excludeFields, includeFields, extraFields } = defOpts
1320
- // 处理类型
1321
- const typeList = types.map((value) => {
1322
- return {
1323
- value,
1324
- label: getI18n(`vxe.export.types.${value}`)
1325
- }
1326
- })
1327
- const modeList = modes.map((item: any) => {
1328
- if (item && item.value) {
1329
- return {
1330
- value: item.value,
1331
- label: item.label || item.value
1332
- }
1333
- }
1334
- return {
1335
- value: item,
1336
- label: getI18n(`vxe.export.modes.${item}`)
1337
- }
1338
- })
1339
-
1340
- const excludeFdMaps: Record<string, number> = {}
1341
- if (excludeFields && excludeFields.length) {
1342
- excludeFields.forEach(field => {
1343
- excludeFdMaps[field] = 1
1344
- })
1345
- }
1346
- const includeFdMaps: Record<string, number> = {}
1347
- if (includeFields && includeFields.length) {
1348
- includeFields.forEach(field => {
1349
- includeFdMaps[field] = 1
1350
- })
1351
- }
1352
- const extraFdMaps: Record<string, number> = {}
1353
- if (extraFields) {
1354
- extraFields.forEach(field => {
1355
- extraFdMaps[field] = 1
1356
- })
1357
- }
1358
-
1359
- // 默认选中
1360
- // 优先级 columns > excludeFields > (includeFields || extraFields)
1361
- XEUtils.eachTree(exportColumns, (column, index, items, path, parentColumn) => {
1362
- const isColGroup = column.children && column.children.length > 0
1363
- let isChecked = false
1364
- const isExtraChecked = extraFdMaps[column.field]
1365
- if (columns) {
1366
- isChecked = handleFilterColumns(defOpts, column, columns)
1367
- } else if (excludeFields || includeFields) {
1368
- isChecked = handleFilterFields(defOpts, column, includeFields, includeFdMaps, excludeFdMaps, extraFdMaps)
1369
- } else {
1370
- if (isExtraChecked) {
1371
- isChecked = true
1372
- } else {
1373
- isChecked = column.visible && (isColGroup || defaultFilterExportColumn(column))
1374
- }
1375
- }
1376
- column.checked = isChecked
1377
- column.halfChecked = false
1378
- column.disabled = (parentColumn && parentColumn.disabled) || (checkMethod ? !checkMethod({ $table: $xeTable, column }) : false)
1379
- })
1380
- // 更新条件
1381
- exportStore.columns = exportColumns
1382
- exportStore.typeList = typeList
1383
- exportStore.modeList = modeList
1384
- exportStore.hasFooter = hasFooter
1385
- exportStore.hasMerge = hasMerge
1386
- exportStore.hasTree = hasTree
1387
- exportStore.hasRowGroup = hasRowGroup
1388
- exportStore.isPrint = !!isPrint
1389
- exportStore.hasColgroup = isGroup
1390
- exportStore.visible = true
1391
- // 默认参数
1392
- Object.assign(exportParams, {
1393
- mode: selectRecords.length ? 'selected' : 'current'
1394
- }, defOpts)
1395
- const { filename, sheetName, mode, type } = exportParams
1396
- if (filename) {
1397
- if (XEUtils.isFunction(filename)) {
1398
- exportParams.filename = filename({
1399
- options: defOpts,
1400
- $table: $xeTable,
1401
- $grid: $xeGrid,
1402
- $gantt: $xeGantt
1403
- })
1404
- } else {
1405
- exportParams.filename = `${filename}`
1406
- }
1407
- }
1408
- if (sheetName) {
1409
- if (XEUtils.isFunction(sheetName)) {
1410
- exportParams.sheetName = sheetName({
1411
- options: defOpts,
1412
- $table: $xeTable,
1413
- $grid: $xeGrid,
1414
- $gantt: $xeGantt
1415
- })
1416
- } else {
1417
- exportParams.sheetName = `${sheetName}`
1418
- }
1419
- }
1420
- if (!modeList.some(item => item.value === mode)) {
1421
- exportParams.mode = modeList.length ? modeList[0].value : ''
1422
- }
1423
- if (!typeList.some(item => item.value === type)) {
1424
- exportParams.type = typeList.length ? typeList[0].value : ''
1425
- }
1426
- if (!exportParams.widthMode) {
1427
- exportParams.widthMode = ''
1428
- }
1429
- initStore.export = true
1430
- return nextTick()
1431
- }
1432
-
1433
- const handleCloseExport = () => {
1434
- if (VxeUI.modal) {
1435
- return VxeUI.modal.close('VXE_EXPORT_MODAL')
1436
- }
1437
- return Promise.resolve()
1438
- }
1439
-
1440
- const exportMethods: TableExportMethods = {
1441
- /**
1442
- * 导出文件,支持 csv/html/xml/txt
1443
- * 如果是树表格,则默认是导出所有节点
1444
- * 如果是启用了虚拟滚动,则只能导出数据源,可以配合 dataFilterMethod 函数转换数据
1445
- * @param {Object} options 参数
1446
- */
1447
- exportData (options) {
1448
- const $xeGrid = $xeTable.xeGrid
1449
- const $xeGantt = $xeTable.xeGantt
1450
- const $xeGGWrapper = $xeGrid || $xeGantt
1451
-
1452
- const { treeConfig, showHeader, showFooter } = props
1453
- const { isGroup } = reactData
1454
- const { tableFullColumn, afterFullData, afterTreeFullData, collectColumn, mergeBodyList, mergeFooterList } = internalData
1455
- const exportOpts = computeExportOpts.value
1456
- const treeOpts = computeTreeOpts.value
1457
- const proxyOpts = $xeGGWrapper ? $xeGGWrapper.getComputeMaps().computeProxyOpts.value : {} as VxeGridPropTypes.ProxyOpts
1458
- const hasMerge = !!(mergeBodyList.length || mergeFooterList.length)
1459
- const opts = Object.assign({
1460
- message: true,
1461
- isHeader: showHeader,
1462
- isTitle: showHeader,
1463
- isFooter: showFooter,
1464
- isColgroup: isGroup,
1465
- isMerge: hasMerge,
1466
- useStyle: true,
1467
- current: 'current',
1468
- modes: (proxyOpts.ajax && proxyOpts.ajax.queryAll ? ['all'] : []).concat(['current', 'selected', 'empty']),
1469
- download: true,
1470
- type: 'csv'
1471
- // filename: '',
1472
- // sheetName: '',
1473
- // original: false,
1474
- // isTreeAllExpanded: false,
1475
- // isRowGroupAllExpanded: false,
1476
- // data: null,
1477
- // remote: false,
1478
- // dataFilterMethod: null,
1479
- // footerFilterMethod: null,
1480
- // exportMethod: null,
1481
- // columnFilterMethod: null,
1482
- // beforeExportMethod: null,
1483
- // afterExportMethod: null
1484
- }, exportOpts, options)
1485
-
1486
- // 已废弃,参数 isAllExpand
1487
- if (XEUtils.isBoolean((opts as any).isAllExpand)) {
1488
- warnLog('vxe.error.delProp', ['isAllExpand', 'isTreeAllExpanded'])
1489
- opts.isTreeAllExpanded = (opts as any).isAllExpand
1490
- }
1491
-
1492
- let { filename, sheetName, type, mode, columns, columnFilterMethod, beforeExportMethod, includeFields, excludeFields, extraFields } = opts
1493
- let groups: any[] = []
1494
- const selectRecords = $xeTable.getCheckboxRecords()
1495
- if (!mode) {
1496
- mode = selectRecords.length ? 'selected' : 'current'
1497
- }
1498
-
1499
- const excludeFdMaps: Record<string, number> = {}
1500
- if (excludeFields && excludeFields.length) {
1501
- excludeFields.forEach(field => {
1502
- excludeFdMaps[field] = 1
1503
- })
1504
- }
1505
- const includeFdMaps: Record<string, number> = {}
1506
- if (includeFields && includeFields.length) {
1507
- includeFields.forEach(field => {
1508
- includeFdMaps[field] = 1
1509
- })
1510
- }
1511
- const extraFdMaps: Record<string, number> = {}
1512
- if (extraFields) {
1513
- extraFields.forEach(field => {
1514
- extraFdMaps[field] = 1
1515
- })
1516
- }
1517
-
1518
- let isCustomCol = false
1519
- let customCols = []
1520
- const _columns = (opts as any)._columns
1521
- if (_columns) {
1522
- // 内部导出使用 _columns -> _children 为自定义子集
1523
- isCustomCol = true
1524
- customCols = XEUtils.searchTree(_columns, () => true, { children: '_children', mapChildren: 'childNodes', original: true })
1525
- } else if (columns) {
1526
- isCustomCol = true
1527
- customCols = XEUtils.searchTree(columns, () => true, { children: 'children', mapChildren: 'childNodes', original: true })
1528
- } else {
1529
- customCols = XEUtils.searchTree(collectColumn, column => {
1530
- const isColGroup = column.children && column.children.length > 0
1531
- let isChecked = false
1532
- const isExtraChecked = extraFdMaps[column.field]
1533
- if (columns) {
1534
- isChecked = handleFilterColumns(opts, column, columns)
1535
- } else if (excludeFields || includeFields) {
1536
- isChecked = handleFilterFields(opts, column, includeFields, includeFdMaps, excludeFdMaps, extraFdMaps)
1537
- } else {
1538
- if (isExtraChecked) {
1539
- isChecked = true
1540
- } else {
1541
- isChecked = column.visible && (isColGroup || defaultFilterExportColumn(column))
1542
- }
1543
- }
1544
- return isChecked
1545
- }, { children: 'children', mapChildren: 'childNodes', original: true })
1546
- }
1547
- const handleOptions: VxeTablePropTypes.ExportHandleOptions = Object.assign({ } as { data: any[], colgroups: any[], columns: any[] }, opts, { filename: '', sheetName: '', _columnConfs: columns })
1548
- // 如果设置源数据,则默认导出设置了字段的列
1549
- if (!isCustomCol && !columnFilterMethod) {
1550
- columnFilterMethod = ({ column }) => handleFilterFields(handleOptions, column, includeFields, includeFdMaps, excludeFdMaps, extraFdMaps)
1551
- handleOptions.columnFilterMethod = columnFilterMethod
1552
- }
1553
- if (customCols) {
1554
- handleOptions._isCustomColumn = true
1555
- groups = XEUtils.searchTree(
1556
- XEUtils.mapTree(customCols, (item) => {
1557
- let targetColumn
1558
- if (item) {
1559
- if (isColumnInfo(item)) {
1560
- targetColumn = item
1561
- } else if (XEUtils.isString(item)) {
1562
- targetColumn = $xeTable.getColumnByField(item)
1563
- } else {
1564
- const colid = item.id || item.colId
1565
- const type = item.type
1566
- const field = item.field
1567
- if (colid) {
1568
- targetColumn = $xeTable.getColumnById(colid)
1569
- } else if (field && type) {
1570
- targetColumn = tableFullColumn.find((column) => column.field === field && column.type === type)
1571
- } else if (field) {
1572
- targetColumn = $xeTable.getColumnByField(field)
1573
- } else if (type) {
1574
- targetColumn = tableFullColumn.find((column) => column.type === type)
1575
- }
1576
- }
1577
- return targetColumn || {}
1578
- }
1579
- }, {
1580
- children: 'childNodes',
1581
- mapChildren: '_children'
1582
- }),
1583
- (column, index) => isColumnInfo(column) && (!columnFilterMethod || columnFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, column: column as any, $columnIndex: index })),
1584
- {
1585
- children: '_children',
1586
- mapChildren: 'childNodes',
1587
- original: true
1588
- }
1589
- )
1590
- } else {
1591
- groups = XEUtils.searchTree(isGroup ? collectColumn : tableFullColumn, (column, index) => column.visible && (!columnFilterMethod || columnFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, column, $columnIndex: index })), { children: 'children', mapChildren: 'childNodes', original: true })
1592
- }
1593
- // 获取所有列
1594
- const cols: VxeTableDefines.ColumnInfo[] = []
1595
- XEUtils.eachTree(groups, column => {
1596
- const isColGroup = column.children && column.children.length
1597
- if (!isColGroup) {
1598
- cols.push(column)
1599
- }
1600
- }, { children: 'childNodes' })
1601
- // 构建分组层级
1602
- handleOptions.columns = cols
1603
- handleOptions.colgroups = convertToRows(groups)
1604
- if (filename) {
1605
- if (XEUtils.isFunction(filename)) {
1606
- handleOptions.filename = filename({
1607
- options: opts,
1608
- $table: $xeTable,
1609
- $grid: $xeGrid,
1610
- $gantt: $xeGantt
1611
- })
1612
- } else {
1613
- handleOptions.filename = `${filename}`
1614
- }
1615
- }
1616
- if (!handleOptions.filename) {
1617
- handleOptions.filename = getI18n(handleOptions.original ? 'vxe.table.expOriginFilename' : 'vxe.table.expFilename', [XEUtils.toDateString(Date.now(), 'yyyyMMddHHmmss')])
1618
- }
1619
-
1620
- if (sheetName) {
1621
- if (XEUtils.isFunction(sheetName)) {
1622
- handleOptions.sheetName = sheetName({
1623
- options: opts,
1624
- $table: $xeTable,
1625
- $grid: $xeGrid,
1626
- $gantt: $xeGantt
1627
- })
1628
- } else {
1629
- handleOptions.sheetName = `${sheetName}`
1630
- }
1631
- }
1632
- if (!handleOptions.sheetName) {
1633
- handleOptions.sheetName = document.title || ''
1634
- }
1635
-
1636
- // 检查类型,如果为自定义导出,则不需要校验类型
1637
- if (!handleOptions.exportMethod && !XEUtils.includes(XEUtils.keys(exportOpts._typeMaps), type)) {
1638
- errLog('vxe.error.notType', [type])
1639
- if (['xlsx', 'pdf'].includes(type)) {
1640
- warnLog('vxe.error.reqPlugin', [4, 'plugin-export-xlsx'])
1641
- }
1642
- const params = { status: false, msg: 'type error' }
1643
- return Promise.reject(params)
1644
- }
1645
-
1646
- if (!handleOptions.print) {
1647
- if (beforeExportMethod) {
1648
- const beRest = beforeExportMethod({ options: handleOptions, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1649
- if (XEUtils.isBoolean(beRest)) {
1650
- if (!beRest) {
1651
- const params = { status: false, msg: 'before prevent' }
1652
- return Promise.reject(params)
1653
- }
1654
- } else {
1655
- warnLog('vxe.error.returnErr', ['beforeExportMethod', 'boolean', beRest])
1656
- }
1657
- }
1658
- }
1659
- if (!handleOptions.data) {
1660
- handleOptions.data = []
1661
- if (mode === 'selected') {
1662
- if (['html', 'pdf'].indexOf(type) > -1 && treeConfig) {
1663
- handleOptions.data = XEUtils.searchTree($xeTable.getTableData().fullData, item => $xeTable.findRowIndexOf(selectRecords, item) > -1, Object.assign({}, treeOpts, { data: '_row' }))
1664
- } else {
1665
- handleOptions.data = selectRecords
1666
- }
1667
- } else if (mode === 'all') {
1668
- if (!$xeGGWrapper) {
1669
- errLog('vxe.error.errProp', ['all', 'mode=current,selected'])
1670
- }
1671
-
1672
- if ($xeGGWrapper && !handleOptions.remote) {
1673
- const gridReactData = $xeGGWrapper.reactData
1674
- const { computeProxyOpts } = $xeGGWrapper.getComputeMaps()
1675
- const proxyOpts = computeProxyOpts.value
1676
- const { sortData } = gridReactData
1677
- const { beforeQueryAll: oldBeforeQueryAll, afterQueryAll: oldAfterQueryAll, ajax = {} } = proxyOpts
1678
- const resConfigs = proxyOpts.response || proxyOpts.props || {}
1679
- const beforeQueryAllMethod = ajax.beforeQueryAll
1680
- const queryAllMethod = ajax.queryAll
1681
- const afterQueryAllMethod = ajax.afterQueryAll
1682
- const queryAllSuccessMethod = ajax.queryAllSuccess
1683
- const queryAllErrorMethod = ajax.queryAllError
1684
-
1685
- if (!queryAllMethod) {
1686
- errLog('vxe.error.notFunc', ['proxy-config.ajax.queryAll'])
1687
- }
1688
-
1689
- if (queryAllMethod) {
1690
- const params = {
1691
- $table: $xeTable,
1692
- $grid: $xeGrid,
1693
- $gantt: $xeGantt,
1694
- sort: sortData.length ? sortData[0] : {} as any,
1695
- sorts: sortData as any[],
1696
- filters: gridReactData.filterData,
1697
- form: gridReactData.formData,
1698
- options: handleOptions
1699
- }
1700
-
1701
- const handleQueryAll = () => {
1702
- return Promise.resolve((oldBeforeQueryAll || queryAllMethod)(params))
1703
- .then((rest) => {
1704
- if (afterQueryAllMethod) {
1705
- afterQueryAllMethod({ ...params, response: rest, status: 'success' })
1706
- } else {
1707
- const listProp = resConfigs.list
1708
- let tdData: any[] = []
1709
- if (listProp) {
1710
- if (XEUtils.isFunction(listProp)) {
1711
- tdData = listProp({ data: rest, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1712
- } else {
1713
- tdData = XEUtils.isArray(rest) ? rest : XEUtils.get(rest, listProp)
1714
- }
1715
- } else {
1716
- if (XEUtils.isArray(rest)) {
1717
- tdData = rest
1718
- }
1719
- }
1720
- handleOptions.data = tdData
1721
- if (oldAfterQueryAll) {
1722
- oldAfterQueryAll({ ...params, response: rest })
1723
- }
1724
- }
1725
- if (queryAllSuccessMethod) {
1726
- queryAllSuccessMethod({ ...params, response: rest })
1727
- }
1728
- return handleExport(handleOptions)
1729
- })
1730
- .catch((rest) => {
1731
- if (afterQueryAllMethod) {
1732
- afterQueryAllMethod({ ...params, response: rest, status: 'error' })
1733
- }
1734
- if (queryAllErrorMethod) {
1735
- queryAllErrorMethod({ ...params, response: rest })
1736
- }
1737
- })
1738
- }
1739
-
1740
- if (beforeQueryAllMethod) {
1741
- return Promise.resolve(beforeQueryAllMethod(params)).then(status => {
1742
- if (status !== false) {
1743
- return handleQueryAll()
1744
- }
1745
- })
1746
- }
1747
- return handleQueryAll()
1748
- }
1749
- }
1750
- } if (mode === 'current') {
1751
- handleOptions.data = treeConfig ? afterTreeFullData : afterFullData
1752
- }
1753
- } else {
1754
- handleOptions._isCustomData = true
1755
- }
1756
- return handleExport(handleOptions)
1757
- },
1758
- importByFile (file, options) {
1759
- const opts = Object.assign({}, options)
1760
- const { beforeImportMethod } = opts
1761
- if (beforeImportMethod) {
1762
- const biRest = beforeImportMethod({ options: opts, $table: $xeTable })
1763
- if (XEUtils.isBoolean(biRest)) {
1764
- if (!biRest) {
1765
- const params = { status: false, mas: 'before prevent' }
1766
- return Promise.reject(params)
1767
- }
1768
- } else {
1769
- warnLog('vxe.error.returnErr', ['beforeImportMethod', 'boolean', biRest])
1770
- }
1771
- }
1772
- return handleFileImport(file, opts)
1773
- },
1774
- importData (options) {
1775
- const importOpts = computeImportOpts.value
1776
- const opts = Object.assign({
1777
- types: XEUtils.keys(importOpts._typeMaps)
1778
- // beforeImportMethod: null,
1779
- // afterImportMethod: null
1780
- }, importOpts, options)
1781
- const { beforeImportMethod, afterImportMethod } = opts
1782
- if (beforeImportMethod) {
1783
- const biRest = beforeImportMethod({ options: opts, $table: $xeTable })
1784
- if (XEUtils.isBoolean(biRest)) {
1785
- if (!biRest) {
1786
- const params = { status: false, mas: 'before prevent' }
1787
- return Promise.reject(params)
1788
- }
1789
- } else {
1790
- warnLog('vxe.error.returnErr', ['beforeImportMethod', 'boolean', biRest])
1791
- }
1792
- }
1793
- return VxeUI.readFile(opts).catch(e => {
1794
- if (afterImportMethod) {
1795
- afterImportMethod({ status: false, options: opts, $table: $xeTable })
1796
- }
1797
- return Promise.reject(e)
1798
- }).then((params) => {
1799
- const { file } = params
1800
- return handleFileImport(file, opts)
1801
- })
1802
- },
1803
- saveFile (options) {
1804
- return VxeUI.saveFile(options)
1805
- },
1806
- readFile (options) {
1807
- return VxeUI.readFile(options)
1808
- },
1809
- print (options) {
1810
- const $xeGrid = $xeTable.xeGrid
1811
- const $xeGantt = $xeTable.xeGantt
1812
-
1813
- const printOpts = computePrintOpts.value
1814
- const opts = Object.assign({
1815
- original: false
1816
- // beforePrintMethod
1817
- }, printOpts, options, {
1818
- type: 'html',
1819
- download: false,
1820
- remote: false,
1821
- print: true
1822
- })
1823
- const { sheetName } = opts
1824
- let printTitle = ''
1825
- if (sheetName) {
1826
- if (XEUtils.isFunction(sheetName)) {
1827
- printTitle = sheetName({
1828
- options: opts,
1829
- $table: $xeTable,
1830
- $grid: $xeGrid,
1831
- $gantt: $xeGantt
1832
- })
1833
- } else {
1834
- printTitle = `${sheetName}`
1835
- }
1836
- }
1837
- if (!printTitle) {
1838
- printTitle = document.title || ''
1839
- }
1840
-
1841
- const beforePrintMethod = opts.beforePrintMethod
1842
- const printMethod = opts.printMethod
1843
- const tableHtml = opts.html || opts.content
1844
- return new Promise((resolve, reject) => {
1845
- if (VxeUI.print) {
1846
- if (tableHtml) {
1847
- resolve(
1848
- VxeUI.print({
1849
- title: printTitle,
1850
- html: tableHtml,
1851
- customStyle: opts.style,
1852
- beforeMethod: beforePrintMethod
1853
- ? ({ html }) => {
1854
- return beforePrintMethod({
1855
- html,
1856
- content: html,
1857
- options: opts,
1858
- $table: $xeTable,
1859
- $grid: $xeGrid,
1860
- $gantt: $xeGantt
1861
- })
1862
- }
1863
- : undefined,
1864
- beforePrintMethod: beforePrintMethod
1865
- ? ({ html }) => {
1866
- return beforePrintMethod({
1867
- html,
1868
- content: html,
1869
- options: opts,
1870
- $table: $xeTable,
1871
- $grid: $xeGrid,
1872
- $gantt: $xeGantt
1873
- })
1874
- }
1875
- : undefined,
1876
- printMethod: printMethod
1877
- ? ({ html }) => {
1878
- return printMethod({
1879
- html,
1880
- content: html,
1881
- options: opts,
1882
- $table: $xeTable,
1883
- $grid: $xeGrid,
1884
- $gantt: $xeGantt
1885
- })
1886
- }
1887
- : undefined
1888
- })
1889
- )
1890
- } else {
1891
- resolve(
1892
- exportMethods.exportData(opts).then(({ content }: any) => {
1893
- return VxeUI.print({
1894
- title: printTitle,
1895
- html: content,
1896
- customStyle: opts.style,
1897
- beforeMethod: beforePrintMethod
1898
- ? ({ html }) => {
1899
- return beforePrintMethod({
1900
- html,
1901
- content: html,
1902
- options: opts,
1903
- $table: $xeTable,
1904
- $grid: $xeGrid,
1905
- $gantt: $xeGantt
1906
- })
1907
- }
1908
- : undefined,
1909
- beforePrintMethod: beforePrintMethod
1910
- ? ({ html }) => {
1911
- return beforePrintMethod({
1912
- html,
1913
- content: html,
1914
- options: opts,
1915
- $table: $xeTable,
1916
- $grid: $xeGrid,
1917
- $gantt: $xeGantt
1918
- })
1919
- }
1920
- : undefined,
1921
- printMethod: printMethod
1922
- ? ({ html }) => {
1923
- return printMethod({
1924
- html,
1925
- content: html,
1926
- options: opts,
1927
- $table: $xeTable,
1928
- $grid: $xeGrid,
1929
- $gantt: $xeGantt
1930
- })
1931
- }
1932
- : undefined
1933
- })
1934
- })
1935
- )
1936
- }
1937
- } else {
1938
- errLog('vxe.error.reqComp', ['vxe-print'])
1939
- const e = { status: false, msg: 'print not exist' }
1940
- reject(e)
1941
- }
1942
- })
1943
- },
1944
- getPrintHtml (options) {
1945
- const printOpts = computePrintOpts.value
1946
- const opts = Object.assign({
1947
- original: false
1948
- // beforePrintMethod
1949
- }, printOpts, options, {
1950
- type: 'html',
1951
- download: false,
1952
- remote: false,
1953
- print: true
1954
- })
1955
- return $xeTable.exportData(opts).then(({ content }) => {
1956
- return {
1957
- html: content
1958
- }
1959
- })
1960
- },
1961
- closeImport () {
1962
- if (VxeUI.modal) {
1963
- return VxeUI.modal.close('VXE_IMPORT_MODAL')
1964
- }
1965
- return Promise.resolve()
1966
- },
1967
- openImport (options) {
1968
- const { treeConfig, importConfig } = props
1969
- const { initStore, importStore, importParams } = reactData
1970
- const importOpts = computeImportOpts.value
1971
- const defOpts = Object.assign({
1972
- mode: 'insertTop',
1973
- message: true,
1974
- types: XEUtils.keys(importOpts._typeMaps),
1975
- modes: ['insertTop', 'covering']
1976
- }, importOpts, options)
1977
- const types = defOpts.types || []
1978
- const modes = defOpts.modes || []
1979
- const isTree = !!treeConfig
1980
- if (isTree) {
1981
- if (defOpts.message) {
1982
- if (VxeUI.modal) {
1983
- VxeUI.modal.message({ content: getI18n('vxe.error.treeNotImp'), status: 'error' })
1984
- }
1985
- }
1986
- return
1987
- }
1988
- if (!hasEnableConf(importConfig, importOpts)) {
1989
- errLog('vxe.error.reqProp', ['import-config'])
1990
- }
1991
- // 处理类型
1992
- const typeList = types.map((value) => {
1993
- return {
1994
- value,
1995
- label: getI18n(`vxe.export.types.${value}`)
1996
- }
1997
- })
1998
- const modeList = modes.map((item: any) => {
1999
- if (item && item.value) {
2000
- return {
2001
- value: item.value,
2002
- label: item.label || item.value
2003
- }
2004
- }
2005
- return {
2006
- value: item,
2007
- label: getI18n(`vxe.import.modes.${item}`)
2008
- }
2009
- })
2010
- Object.assign(importStore, {
2011
- file: null,
2012
- type: '',
2013
- filename: '',
2014
- modeList,
2015
- typeList,
2016
- visible: true
2017
- })
2018
- Object.assign(importParams, defOpts)
2019
- if (!modeList.some(item => item.value === importParams.mode)) {
2020
- importParams.mode = modeList[0].value
2021
- }
2022
- initStore.import = true
2023
- },
2024
- closeExport: handleCloseExport,
2025
- openExport (options) {
2026
- const { exportConfig } = props
2027
- const exportOpts = computeExportOpts.value
2028
- const defOpts = Object.assign({
2029
- message: true,
2030
- types: XEUtils.keys(exportOpts._typeMaps)
2031
- }, exportOpts, options)
2032
- if (!hasEnableConf(exportConfig, exportOpts)) {
2033
- errLog('vxe.error.reqProp', ['export-config'])
2034
- }
2035
- return handleExportAndPrint(defOpts)
2036
- },
2037
- closePrint: handleCloseExport,
2038
- openPrint (options) {
2039
- const { printConfig } = props
2040
- const printOpts = computePrintOpts.value
2041
- const defOpts = Object.assign({
2042
- message: true
2043
- }, printOpts, options)
2044
- if (!hasEnableConf(printConfig, printOpts)) {
2045
- errLog('vxe.error.reqProp', ['print-config'])
2046
- }
2047
- return handleExportAndPrint(defOpts, true)
2048
- }
2049
- }
2050
-
2051
- return exportMethods
2052
- },
2053
- setupGrid ($xeGrid) {
2054
- return $xeGrid.extendTableMethods(tableExportMethodKeys)
2055
- },
2056
- setupGantt ($xeGantt) {
2057
- return $xeGantt.extendTableMethods(tableExportMethodKeys)
2058
- }
2059
- })
1
+ import { nextTick } from 'vue'
2
+ import XEUtils from 'xe-utils'
3
+ import { VxeUI } from '@vxe-ui/core'
4
+ import { isColumnInfo, getCellValue, createHandleGetRowId } from '../../src/util'
5
+ import { parseFile, formatText, eqEmptyValue, hasEnableConf } from '../../../ui/src/utils'
6
+ import { hasClass, toCssUnit } from '../../../ui/src/dom'
7
+ import { createHtmlPage, getExportBlobByContent } from './util'
8
+ import { createComponentLog } from '../../../ui/src/log'
9
+
10
+ import type { VxeTablePropTypes, VxeColumnPropTypes, TableExportMethods, VxeGridPropTypes, VxeTableDefines, VxeTableConstructor, VxeTablePrivateMethods } from '../../../../types'
11
+
12
+ const { warnLog, errLog } = createComponentLog('table')
13
+
14
+ const { getI18n, hooks, renderer } = VxeUI
15
+
16
+ let htmlCellElem: any
17
+
18
+ const csvBOM = '\ufeff'
19
+ const enterSymbol = '\r\n'
20
+
21
+ function defaultFilterExportColumn(column: VxeTableDefines.ColumnInfo) {
22
+ return !!column.field || ['seq', 'checkbox', 'radio'].indexOf(column.type || '') === -1
23
+ }
24
+
25
+ const getConvertColumns = (columns: any) => {
26
+ const result: any = []
27
+ columns.forEach((column: any) => {
28
+ if (column.childNodes && column.childNodes.length) {
29
+ result.push(column)
30
+ result.push(...getConvertColumns(column.childNodes))
31
+ } else {
32
+ result.push(column)
33
+ }
34
+ })
35
+ return result
36
+ }
37
+
38
+ const convertToRows = (originColumns: any): any[][] => {
39
+ let maxLevel = 1
40
+ const traverse = (column: any, parent?: any) => {
41
+ if (parent) {
42
+ column._level = parent._level + 1
43
+ if (maxLevel < column._level) {
44
+ maxLevel = column._level
45
+ }
46
+ }
47
+ if (column.childNodes && column.childNodes.length) {
48
+ let colSpan = 0
49
+ column.childNodes.forEach((subColumn: any) => {
50
+ traverse(subColumn, column)
51
+ colSpan += subColumn._colSpan
52
+ })
53
+ column._colSpan = colSpan
54
+ } else {
55
+ column._colSpan = 1
56
+ }
57
+ }
58
+
59
+ originColumns.forEach((column: any) => {
60
+ column._level = 1
61
+ traverse(column)
62
+ })
63
+
64
+ const rows: any = []
65
+ for (let i = 0; i < maxLevel; i++) {
66
+ rows.push([])
67
+ }
68
+
69
+ const allColumns = getConvertColumns(originColumns)
70
+
71
+ allColumns.forEach((column: any) => {
72
+ if (column.childNodes && column.childNodes.length) {
73
+ column._rowSpan = 1
74
+ } else {
75
+ column._rowSpan = maxLevel - column._level + 1
76
+ }
77
+ rows[column._level - 1].push(column)
78
+ })
79
+
80
+ return rows
81
+ }
82
+
83
+ function toTableBorder(border: VxeTablePropTypes.Border | undefined) {
84
+ if (border === true) {
85
+ return 'full'
86
+ }
87
+ if (border) {
88
+ return border
89
+ }
90
+ return 'default'
91
+ }
92
+
93
+ function getBooleanValue(cellValue: any) {
94
+ return cellValue === 'TRUE' || cellValue === 'true' || cellValue === true
95
+ }
96
+
97
+ function getFooterData($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, footerTableData: any[]) {
98
+ const $xeGrid = $xeTable.xeGrid
99
+ const $xeGantt = $xeTable.xeGantt
100
+
101
+ const { footerFilterMethod } = opts
102
+ return footerFilterMethod ? footerTableData.filter((items, index) => footerFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, items, $rowIndex: index })) : footerTableData
103
+ }
104
+
105
+ function getCsvCellTypeLabel(column: any, cellValue: any) {
106
+ if (cellValue) {
107
+ if (column.type === 'seq') {
108
+ return `\t${cellValue}`
109
+ }
110
+ switch (column.cellType) {
111
+ case 'string':
112
+ if (!isNaN(cellValue)) {
113
+ return `\t${cellValue}`
114
+ }
115
+ break
116
+ case 'number':
117
+ break
118
+ default:
119
+ if (cellValue.length >= 12 && !isNaN(cellValue)) {
120
+ return `\t${cellValue}`
121
+ }
122
+ break
123
+ }
124
+ }
125
+ return cellValue
126
+ }
127
+
128
+ function toTxtCellLabel(val: any) {
129
+ if (/[",\s\n]/.test(val)) {
130
+ return `"${val.replace(/"/g, '""')}"`
131
+ }
132
+ return XEUtils.eqNull(val) ? '' : val
133
+ }
134
+
135
+ function getElementsByTagName(elem: any, qualifiedName: any) {
136
+ return elem.getElementsByTagName(qualifiedName) as HTMLElement[]
137
+ }
138
+
139
+ function getTxtCellKey(now: number) {
140
+ return `#${now}@${XEUtils.uniqueId()}`
141
+ }
142
+
143
+ function replaceTxtCell(cell: any, vMaps: any) {
144
+ return cell.replace(/#\d+@\d+/g, (key: any) => (XEUtils.hasOwnProp(vMaps, key) ? vMaps[key] : key))
145
+ }
146
+
147
+ function getTxtCellValue(val: any, vMaps: any) {
148
+ const rest = replaceTxtCell(val, vMaps)
149
+ return rest.replace(/^"+$/g, (qVal: any) => '"'.repeat(Math.ceil(qVal.length / 2)))
150
+ }
151
+
152
+ function toExportField(
153
+ tableConf: {
154
+ fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
155
+ titleMaps: Record<string, VxeTableDefines.ColumnInfo>
156
+ },
157
+ field: string
158
+ ) {
159
+ const { fieldMaps, titleMaps } = tableConf
160
+ // title 转 field
161
+ if (!fieldMaps[field]) {
162
+ const teCol = titleMaps[field]
163
+ if (teCol && teCol.field) {
164
+ field = teCol.field
165
+ }
166
+ }
167
+ return field
168
+ }
169
+
170
+ function parseCsvAndTxt(
171
+ tableConf: {
172
+ fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
173
+ titleMaps: Record<string, VxeTableDefines.ColumnInfo>
174
+ },
175
+ content: string,
176
+ cellSeparator: string
177
+ ) {
178
+ const list = content.split(enterSymbol)
179
+ const rows: any[] = []
180
+ let fields: string[] = []
181
+ if (list.length) {
182
+ const vMaps: any = {}
183
+ const now = Date.now()
184
+ list.forEach((rVal) => {
185
+ if (rVal) {
186
+ const item: any = {}
187
+ rVal = rVal
188
+ .replace(/("")|(\n)/g, (text: string, dVal: string) => {
189
+ const key = getTxtCellKey(now)
190
+ vMaps[key] = dVal ? '"' : '\n'
191
+ return key
192
+ })
193
+ .replace(/"(.*?)"/g, (text: string, cVal: string) => {
194
+ const key = getTxtCellKey(now)
195
+ vMaps[key] = replaceTxtCell(cVal, vMaps)
196
+ return key
197
+ })
198
+ const cells: string[] = rVal.split(cellSeparator)
199
+ if (!fields.length) {
200
+ fields = cells.map((val: string) => toExportField(tableConf, getTxtCellValue(val.trim(), vMaps)))
201
+ } else {
202
+ cells.forEach((val, colIndex) => {
203
+ if (colIndex < fields.length) {
204
+ item[fields[colIndex]] = getTxtCellValue(val.trim(), vMaps)
205
+ }
206
+ })
207
+ rows.push(item)
208
+ }
209
+ }
210
+ })
211
+ }
212
+ return { fields, rows }
213
+ }
214
+
215
+ function parseCsv(
216
+ tableConf: {
217
+ fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
218
+ titleMaps: Record<string, VxeTableDefines.ColumnInfo>
219
+ },
220
+ content: string
221
+ ) {
222
+ return parseCsvAndTxt(tableConf, content, ',')
223
+ }
224
+
225
+ function parseTxt(
226
+ tableConf: {
227
+ fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
228
+ titleMaps: Record<string, VxeTableDefines.ColumnInfo>
229
+ },
230
+ content: string
231
+ ) {
232
+ return parseCsvAndTxt(tableConf, content, '\t')
233
+ }
234
+
235
+ function parseHTML(
236
+ tableConf: {
237
+ fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
238
+ titleMaps: Record<string, VxeTableDefines.ColumnInfo>
239
+ },
240
+ content: string
241
+ ) {
242
+ const domParser = new DOMParser()
243
+ const xmlDoc = domParser.parseFromString(content, 'text/html')
244
+ const bodyNodes = getElementsByTagName(xmlDoc, 'body')
245
+ const rows: any[] = []
246
+ const fields: string[] = []
247
+ if (bodyNodes.length) {
248
+ const tableNodes = getElementsByTagName(bodyNodes[0], 'table')
249
+ if (tableNodes.length) {
250
+ const theadNodes = getElementsByTagName(tableNodes[0], 'thead')
251
+ if (theadNodes.length) {
252
+ XEUtils.arrayEach(getElementsByTagName(theadNodes[0], 'tr'), (rowNode) => {
253
+ XEUtils.arrayEach(getElementsByTagName(rowNode, 'th'), (cellNode) => {
254
+ fields.push(toExportField(tableConf, cellNode.textContent || ''))
255
+ })
256
+ })
257
+ const tbodyNodes = getElementsByTagName(tableNodes[0], 'tbody')
258
+ if (tbodyNodes.length) {
259
+ XEUtils.arrayEach(getElementsByTagName(tbodyNodes[0], 'tr'), (rowNode) => {
260
+ const item: any = {}
261
+ XEUtils.arrayEach(getElementsByTagName(rowNode, 'td'), (cellNode, colIndex) => {
262
+ if (fields[colIndex]) {
263
+ item[fields[colIndex]] = cellNode.textContent || ''
264
+ }
265
+ })
266
+ rows.push(item)
267
+ })
268
+ }
269
+ }
270
+ }
271
+ }
272
+ return { fields, rows }
273
+ }
274
+
275
+ function parseXML(
276
+ tableConf: {
277
+ fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
278
+ titleMaps: Record<string, VxeTableDefines.ColumnInfo>
279
+ },
280
+ content: string
281
+ ) {
282
+ const domParser = new DOMParser()
283
+ const xmlDoc = domParser.parseFromString(content, 'application/xml')
284
+ const sheetNodes = getElementsByTagName(xmlDoc, 'Worksheet')
285
+ const rows: any[] = []
286
+ const fields: string[] = []
287
+ if (sheetNodes.length) {
288
+ const tableNodes = getElementsByTagName(sheetNodes[0], 'Table')
289
+ if (tableNodes.length) {
290
+ const rowNodes = getElementsByTagName(tableNodes[0], 'Row')
291
+ if (rowNodes.length) {
292
+ XEUtils.arrayEach(getElementsByTagName(rowNodes[0], 'Cell'), (cellNode) => {
293
+ fields.push(toExportField(tableConf, cellNode.textContent || ''))
294
+ })
295
+ XEUtils.arrayEach(rowNodes, (rowNode, index) => {
296
+ if (index) {
297
+ const item: any = {}
298
+ const cellNodes = getElementsByTagName(rowNode, 'Cell')
299
+ XEUtils.arrayEach(cellNodes, (cellNode, colIndex) => {
300
+ if (fields[colIndex]) {
301
+ item[fields[colIndex]] = cellNode.textContent
302
+ }
303
+ })
304
+ rows.push(item)
305
+ }
306
+ })
307
+ }
308
+ }
309
+ }
310
+ return { fields, rows }
311
+ }
312
+
313
+ function clearColumnConvert(columns: any) {
314
+ XEUtils.eachTree(
315
+ columns,
316
+ (column: any) => {
317
+ delete column._level
318
+ delete column._colSpan
319
+ delete column._rowSpan
320
+ delete column._children
321
+ delete column.childNodes
322
+ },
323
+ { children: 'children' }
324
+ )
325
+ }
326
+
327
+ const tableExportMethodKeys: (keyof TableExportMethods)[] = ['exportData', 'importByFile', 'importData', 'saveFile', 'readFile', 'print', 'getPrintHtml', 'openImport', 'closeImport', 'openExport', 'closeExport', 'openPrint', 'closePrint']
328
+
329
+ hooks.add('tableExportModule', {
330
+ setupTable($xeTable) {
331
+ const { props, reactData, internalData } = $xeTable
332
+ const { computeTreeOpts, computePrintOpts, computeExportOpts, computeImportOpts, computeSeqOpts, computeRadioOpts, computeCheckboxOpts, computeColumnOpts, computeAggregateOpts, computeRendererOpts } = $xeTable.getComputeMaps()
333
+
334
+ const getSeq = (cellValue: any, row: any, $rowIndex: number, column: VxeTableDefines.ColumnInfo, $columnIndex: number) => {
335
+ const seqOpts = computeSeqOpts.value
336
+ const seqMd = seqOpts.seqMethod || (column as any).seqMethod
337
+ if (seqMd) {
338
+ return seqMd({
339
+ $table: $xeTable,
340
+ row,
341
+ rowIndex: $xeTable.getRowIndex(row),
342
+ _rowIndex: $xeTable.getVTRowIndex(row),
343
+ $rowIndex,
344
+ column,
345
+ columnIndex: $xeTable.getColumnIndex(column),
346
+ _columnIndex: $xeTable.getVTColumnIndex(column),
347
+ $columnIndex
348
+ })
349
+ }
350
+ return cellValue
351
+ }
352
+
353
+ function getHeaderTitle(opts: VxeTablePropTypes.ExportHandleOptions, column: VxeTableDefines.ColumnInfo) {
354
+ const columnOpts = computeColumnOpts.value
355
+ const headExportMethod = column.headerExportMethod || columnOpts.headerExportMethod
356
+ return headExportMethod ? headExportMethod({ column, options: opts, $table: $xeTable }) : (opts.isTitle ? $xeTable.getHeaderCellLabel(column) : column.field) || ''
357
+ }
358
+
359
+ const toBooleanValue = (cellValue: any) => {
360
+ return XEUtils.isBoolean(cellValue) ? (cellValue ? 'TRUE' : 'FALSE') : cellValue
361
+ }
362
+
363
+ const toStringValue = (cellValue: any) => {
364
+ return eqEmptyValue(cellValue) ? '' : `${cellValue}`
365
+ }
366
+
367
+ const getBodyLabelData = (opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
368
+ const { isTreeAllExpanded, isRowGroupAllExpanded, mode: expMode } = opts
369
+ const { treeConfig } = props
370
+ const { isRowGroupStatus } = reactData
371
+ const { fullColumnFieldData, fullAllDataRowIdData } = internalData
372
+ const radioOpts = computeRadioOpts.value
373
+ const checkboxOpts = computeCheckboxOpts.value
374
+ const treeOpts = computeTreeOpts.value
375
+ const columnOpts = computeColumnOpts.value
376
+ const aggregateOpts = computeAggregateOpts.value
377
+ const rendererOpts = computeRendererOpts.value
378
+ if (!htmlCellElem) {
379
+ htmlCellElem = document.createElement('div')
380
+ }
381
+ const { handleGetRowId } = createHandleGetRowId($xeTable)
382
+ if (isRowGroupStatus) {
383
+ // 如果是数据分组
384
+ const { mode: aggMode, showTotal, totalMethod, countFields, contentMethod, formatValuesMethod, mapChildrenField } = aggregateOpts
385
+ const rest: any[] = []
386
+ const expandMaps: Record<string, boolean> = {}
387
+ const useMaps: Record<string, boolean> = {}
388
+ XEUtils.eachTree(
389
+ datas,
390
+ (item, $rowIndex, items, path, parentItem, nodes) => {
391
+ const row = item._row || item
392
+ const rowid = handleGetRowId(row)
393
+ if (useMaps[rowid]) {
394
+ return
395
+ }
396
+ const parentRow = parentItem && parentItem._row ? parentItem._row : parentItem
397
+ const pRowid = parentRow ? handleGetRowId(parentRow) : ''
398
+ if (isRowGroupAllExpanded || !parentRow || (expandMaps[pRowid] && $xeTable.isRowExpandByRow(parentRow))) {
399
+ const hasRowChild = mapChildrenField && row[mapChildrenField] && row[mapChildrenField].length
400
+ const item: any = {
401
+ _row: row,
402
+ _level: nodes.length - 1,
403
+ _hasChild: hasRowChild,
404
+ _expand: hasRowChild && $xeTable.isRowExpandByRow(row)
405
+ }
406
+ columns.forEach((column, $columnIndex) => {
407
+ const { field, editRender, cellRender, aggFunc, rowGroupNode } = column
408
+ let cellValue: string | number | boolean | null = ''
409
+ const renderOpts = editRender || cellRender
410
+ let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
411
+ if (!bodyExportMethod && renderOpts && renderOpts.name) {
412
+ const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
413
+ if (compConf) {
414
+ bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
415
+ }
416
+ }
417
+ if (!bodyExportMethod) {
418
+ bodyExportMethod = columnOpts.exportMethod
419
+ }
420
+ if (bodyExportMethod) {
421
+ cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
422
+ } else {
423
+ switch (column.type) {
424
+ case 'seq': {
425
+ const seqVal = path.map((num, i) => (i % 2 === 0 ? Number(num) + 1 : '.')).join('')
426
+ cellValue = expMode === 'all' ? seqVal : getSeq(seqVal, row, $rowIndex, column, $columnIndex)
427
+ break
428
+ }
429
+ case 'checkbox': {
430
+ cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
431
+ item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
432
+ item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
433
+ break
434
+ }
435
+ case 'radio': {
436
+ cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
437
+ item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
438
+ item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
439
+ break
440
+ }
441
+ default: {
442
+ if (field && row.isAggregate) {
443
+ const aggRow: VxeTableDefines.AggregateRowInfo = row
444
+ const aggData = aggRow.aggData
445
+ const currAggData = aggData ? aggData[field] : null
446
+ const groupField = aggRow.groupField
447
+ const groupContent = aggRow.groupContent
448
+ const childList = mapChildrenField ? aggRow[mapChildrenField] || [] : []
449
+ const childCount = aggRow.childCount
450
+ const colRest = fullColumnFieldData[groupField] || {}
451
+ const ctParams = {
452
+ $table: $xeTable,
453
+ groupField,
454
+ groupColumn: (colRest ? colRest.column : null) as VxeTableDefines.ColumnInfo,
455
+ column,
456
+ groupValue: groupContent,
457
+ childList,
458
+ childCount,
459
+ aggValue: null as any,
460
+
461
+ /**
462
+ * 已废弃
463
+ * @deprecated
464
+ */
465
+ children: childList,
466
+ /**
467
+ * 已废弃
468
+ * @deprecated
469
+ */
470
+ totalValue: childCount
471
+ }
472
+ if (aggMode === 'column' ? field === aggRow.groupField : rowGroupNode) {
473
+ cellValue = groupContent
474
+ if (contentMethod) {
475
+ cellValue = `${contentMethod(ctParams)}`
476
+ }
477
+ if (showTotal) {
478
+ cellValue = getI18n('vxe.table.rowGroupContentTotal', [cellValue, totalMethod ? totalMethod(ctParams) : childCount, childCount])
479
+ }
480
+ } else if ($xeTable.getPivotTableAggregateCellAggValue) {
481
+ const aggParams = {
482
+ $table: $xeTable,
483
+ row,
484
+ column
485
+ }
486
+ cellValue = $xeTable.getPivotTableAggregateCellAggValue(aggParams)
487
+ } else if (aggFunc === true || (countFields && countFields.includes(field))) {
488
+ cellValue = currAggData ? currAggData.value : childCount
489
+ ctParams.aggValue = cellValue
490
+ if (formatValuesMethod) {
491
+ cellValue = formatValuesMethod(ctParams)
492
+ }
493
+ }
494
+ } else if (opts.original) {
495
+ cellValue = getCellValue(row, column)
496
+ } else {
497
+ cellValue = $xeTable.getCellLabel(row, column)
498
+ if (column.type === 'html') {
499
+ htmlCellElem.innerHTML = cellValue
500
+ cellValue = htmlCellElem.innerText.trim()
501
+ } else {
502
+ const cell = $xeTable.getCellElement(row, column)
503
+ if (cell && !hasClass(cell, 'is--progress')) {
504
+ cellValue = cell.innerText.trim()
505
+ }
506
+ }
507
+ }
508
+ break
509
+ }
510
+ }
511
+ }
512
+ item[column.id] = toStringValue(cellValue)
513
+ })
514
+ useMaps[rowid] = true
515
+ if (pRowid) {
516
+ expandMaps[pRowid] = true
517
+ }
518
+ rest.push(Object.assign(item, row))
519
+ }
520
+ },
521
+ { children: mapChildrenField }
522
+ )
523
+ return rest
524
+ }
525
+ if (treeConfig) {
526
+ // 如果是树结构
527
+ const { seqMode } = treeOpts
528
+ const childrenField = treeOpts.children || treeOpts.childrenField
529
+ const rest: any[] = []
530
+ const expandMaps: Record<string, boolean> = {}
531
+ const useMaps: Record<string, boolean> = {}
532
+ XEUtils.eachTree(
533
+ datas,
534
+ (item, $rowIndex, items, path, parentItem, nodes) => {
535
+ const row = item._row || item
536
+ const rowid = handleGetRowId(row)
537
+ if (useMaps[rowid]) {
538
+ return
539
+ }
540
+ const parentRow = parentItem && parentItem._row ? parentItem._row : parentItem
541
+ const pRowid = parentRow ? handleGetRowId(parentRow) : ''
542
+ if (isTreeAllExpanded || !parentRow || (expandMaps[pRowid] && $xeTable.isTreeExpandByRow(parentRow))) {
543
+ const hasRowChild = row[childrenField] && row[childrenField].length
544
+ const item: any = {
545
+ _row: row,
546
+ _level: nodes.length - 1,
547
+ _hasChild: hasRowChild,
548
+ _expand: hasRowChild && $xeTable.isTreeExpandByRow(row)
549
+ }
550
+ const rowRest = fullAllDataRowIdData[rowid] || {}
551
+ columns.forEach((column, $columnIndex) => {
552
+ let cellValue: string | number | boolean | null = ''
553
+ const renderOpts = column.editRender || column.cellRender
554
+ let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
555
+ if (!bodyExportMethod && renderOpts && renderOpts.name) {
556
+ const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
557
+ if (compConf) {
558
+ bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
559
+ }
560
+ }
561
+ if (!bodyExportMethod) {
562
+ bodyExportMethod = columnOpts.exportMethod
563
+ }
564
+ if (bodyExportMethod) {
565
+ cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
566
+ } else {
567
+ switch (column.type) {
568
+ case 'seq': {
569
+ let seqVal: number | string = path.map((num, i) => (i % 2 === 0 ? Number(num) + 1 : '.')).join('')
570
+ if (seqMode === 'increasing') {
571
+ seqVal = rowRest ? rowRest._index + 1 : -1
572
+ }
573
+ cellValue = expMode === 'all' ? seqVal : getSeq(seqVal, row, $rowIndex, column, $columnIndex)
574
+ break
575
+ }
576
+ case 'checkbox':
577
+ cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
578
+ item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
579
+ item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
580
+ break
581
+ case 'radio':
582
+ cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
583
+ item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
584
+ item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
585
+ break
586
+ default:
587
+ if (opts.original) {
588
+ cellValue = getCellValue(row, column)
589
+ } else {
590
+ cellValue = $xeTable.getCellLabel(row, column)
591
+ if (column.type === 'html') {
592
+ htmlCellElem.innerHTML = cellValue
593
+ cellValue = htmlCellElem.innerText.trim()
594
+ } else {
595
+ const cell = $xeTable.getCellElement(row, column)
596
+ if (cell && !hasClass(cell, 'is--progress')) {
597
+ cellValue = cell.innerText.trim()
598
+ }
599
+ }
600
+ }
601
+ }
602
+ }
603
+ item[column.id] = toStringValue(cellValue)
604
+ })
605
+ useMaps[rowid] = true
606
+ if (pRowid) {
607
+ expandMaps[pRowid] = true
608
+ }
609
+ rest.push(Object.assign(item, row))
610
+ }
611
+ },
612
+ { children: childrenField }
613
+ )
614
+ return rest
615
+ }
616
+ return datas.map((row, $rowIndex) => {
617
+ const item: any = {
618
+ _row: row
619
+ }
620
+ columns.forEach((column, $columnIndex) => {
621
+ let cellValue: string | number | boolean | null = ''
622
+ const renderOpts = column.editRender || column.cellRender
623
+ let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
624
+ if (!bodyExportMethod && renderOpts && renderOpts.name) {
625
+ const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
626
+ if (compConf) {
627
+ bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
628
+ }
629
+ }
630
+ if (bodyExportMethod) {
631
+ cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
632
+ } else {
633
+ switch (column.type) {
634
+ case 'seq': {
635
+ const seqValue = $rowIndex + 1
636
+ cellValue = expMode === 'all' ? seqValue : getSeq(seqValue, row, $rowIndex, column, $columnIndex)
637
+ break
638
+ }
639
+ case 'checkbox':
640
+ cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
641
+ item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
642
+ item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
643
+ break
644
+ case 'radio':
645
+ cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
646
+ item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
647
+ item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
648
+ break
649
+ default:
650
+ if (opts.original) {
651
+ cellValue = getCellValue(row, column)
652
+ } else {
653
+ cellValue = $xeTable.getCellLabel(row, column)
654
+ if (column.type === 'html') {
655
+ htmlCellElem.innerHTML = cellValue
656
+ cellValue = htmlCellElem.innerText.trim()
657
+ } else {
658
+ const cell = $xeTable.getCellElement(row, column)
659
+ if (cell && !hasClass(cell, 'is--progress')) {
660
+ cellValue = cell.innerText.trim()
661
+ }
662
+ }
663
+ }
664
+ }
665
+ }
666
+ item[column.id] = toStringValue(cellValue)
667
+ })
668
+ return item
669
+ })
670
+ }
671
+
672
+ const getExportData = (opts: VxeTablePropTypes.ExportHandleOptions) => {
673
+ const $xeGrid = $xeTable.xeGrid
674
+ const $xeGantt = $xeTable.xeGantt
675
+
676
+ const { columns, dataFilterMethod } = opts
677
+ let datas = opts.data
678
+ if (dataFilterMethod) {
679
+ datas = datas.filter((row, index) => dataFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, row, $rowIndex: index }))
680
+ }
681
+ return getBodyLabelData(opts, columns, datas)
682
+ }
683
+
684
+ const getFooterCellValue = (opts: VxeTablePropTypes.ExportHandleOptions, row: any, column: VxeTableDefines.ColumnInfo) => {
685
+ const columnOpts = computeColumnOpts.value
686
+ const rendererOpts = computeRendererOpts.value
687
+ const renderOpts = column.editRender || column.cellRender
688
+ let footLabelMethod: VxeColumnPropTypes.FooterExportMethod | undefined = column.footerExportMethod
689
+ if (!footLabelMethod && renderOpts && renderOpts.name) {
690
+ const compConf = rendererOpts[renderOpts.name] || renderer.get(renderOpts.name)
691
+ if (compConf) {
692
+ footLabelMethod = compConf.tableFooterExportMethod || compConf.footerExportMethod
693
+ }
694
+ }
695
+ if (!footLabelMethod) {
696
+ footLabelMethod = columnOpts.footerExportMethod
697
+ }
698
+ if (footLabelMethod) {
699
+ const _columnIndex = $xeTable.getVTColumnIndex(column)
700
+ return footLabelMethod({ $table: $xeTable, items: row, itemIndex: _columnIndex, row, _columnIndex, column, options: opts })
701
+ }
702
+ const cellValue = $xeTable.getFooterCellLabel(row, column)
703
+ return cellValue
704
+ }
705
+
706
+ const toCsv = ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
707
+ let content = csvBOM
708
+ if (opts.isHeader) {
709
+ content += columns.map((column) => toTxtCellLabel(getHeaderTitle(opts, column))).join(',') + enterSymbol
710
+ }
711
+ datas.forEach((row) => {
712
+ content += columns.map((column) => toTxtCellLabel(getCsvCellTypeLabel(column, row[column.id]))).join(',') + enterSymbol
713
+ })
714
+ if (opts.isFooter) {
715
+ const { footerTableData } = reactData
716
+ const footers = getFooterData($xeTable, opts, footerTableData)
717
+ footers.forEach((row) => {
718
+ content += columns.map((column: any) => toTxtCellLabel(getFooterCellValue(opts, row, column))).join(',') + enterSymbol
719
+ })
720
+ }
721
+ return content
722
+ }
723
+
724
+ const toTxt = ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
725
+ let content = ''
726
+ if (opts.isHeader) {
727
+ content += columns.map((column) => toTxtCellLabel(getHeaderTitle(opts, column))).join('\t') + enterSymbol
728
+ }
729
+ datas.forEach((row) => {
730
+ content += columns.map((column) => toTxtCellLabel(row[column.id])).join('\t') + enterSymbol
731
+ })
732
+ if (opts.isFooter) {
733
+ const { footerTableData } = reactData
734
+ const footers = getFooterData($xeTable, opts, footerTableData)
735
+ footers.forEach((row) => {
736
+ content += columns.map((column: any) => toTxtCellLabel(getFooterCellValue(opts, row, column))).join('\t') + enterSymbol
737
+ })
738
+ }
739
+ return content
740
+ }
741
+
742
+ const hasEllipsis = (column: VxeTableDefines.ColumnInfo, property: 'showOverflow' | 'showHeaderOverflow', allColumnOverflow: VxeTablePropTypes.ShowOverflow | undefined) => {
743
+ const columnOverflow = column[property]
744
+ const headOverflow = XEUtils.isUndefined(columnOverflow) || XEUtils.isNull(columnOverflow) ? allColumnOverflow : columnOverflow
745
+ const showEllipsis = headOverflow === 'ellipsis'
746
+ const showTitle = headOverflow === 'title'
747
+ const showTooltip = headOverflow === true || headOverflow === 'tooltip'
748
+ let isEllipsis = showTitle || showTooltip || showEllipsis
749
+ // 虚拟滚动不支持动态高度
750
+ const { scrollXLoad, scrollYLoad } = reactData
751
+ if ((scrollXLoad || scrollYLoad) && !isEllipsis) {
752
+ isEllipsis = true
753
+ }
754
+ return isEllipsis
755
+ }
756
+
757
+ const getCustomColKey = (conf: VxeTableDefines.ColumnInfo<any> | VxeTablePropTypes.ExportOrPrintColumnOption) => {
758
+ return `${conf.field || ''}:${conf.type || ''}`
759
+ }
760
+
761
+ const toHtml = (opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
762
+ const { id, border, treeConfig, headerAlign: allHeaderAlign, align: allAlign, footerAlign: allFooterAlign, showOverflow: allColumnOverflow, showHeaderOverflow: allColumnHeaderOverflow } = props
763
+ const { isAllSelected, isIndeterminate } = reactData
764
+ const { mergeBodyCellMaps, mergeFooterCellMaps } = internalData
765
+ const treeOpts = computeTreeOpts.value
766
+ const { print: isPrint, widthMode, isHeader, isFooter, isColgroup, isMerge, colgroups, _columnConfs, original } = opts
767
+ const isAutoWidth = widthMode === 'auto'
768
+ const isScaleWidth = widthMode === 'scale'
769
+ const isDefaultWidth = !isAutoWidth && !isScaleWidth
770
+
771
+ const customWidthMaps: Record<string, number | string> = {}
772
+ if (_columnConfs) {
773
+ _columnConfs.forEach((conf) => {
774
+ if (!isColumnInfo(conf)) {
775
+ if ((conf.field || conf.type) && conf.width) {
776
+ customWidthMaps[getCustomColKey(conf)] = conf.width
777
+ }
778
+ }
779
+ })
780
+ }
781
+
782
+ // 计算宽度
783
+ const colWidthMaps: Record<string, number> = {}
784
+ const printWidthMaps: Record<string, number> = {}
785
+ if (isPrint) {
786
+ let tableWidth = 0
787
+ columns.forEach((column) => {
788
+ tableWidth += column.renderWidth
789
+ })
790
+ if (colgroups) {
791
+ colgroups.forEach((cols) => {
792
+ cols.forEach((column: any) => {
793
+ if (!column.childNodes || !column.childNodes.length) {
794
+ return
795
+ }
796
+ let childWidth = 0
797
+ let countChild = 0
798
+ XEUtils.eachTree(
799
+ [column],
800
+ (item) => {
801
+ if (!item.childNodes || !column.childNodes.length) {
802
+ countChild++
803
+ }
804
+ const ptWidth = printWidthMaps[item.id]
805
+ childWidth += ptWidth || 0
806
+ },
807
+ { children: 'childNodes' }
808
+ )
809
+ const colWidth = childWidth - countChild
810
+ colWidthMaps[column.id] = colWidth
811
+ printWidthMaps[column.id] = XEUtils.floor((colWidth / tableWidth) * 180, 2)
812
+ })
813
+ })
814
+ }
815
+ columns.forEach((column) => {
816
+ const colWidth = column.renderWidth
817
+ if (column.width) {
818
+ colWidthMaps[column.id] = colWidth
819
+ }
820
+ printWidthMaps[column.id] = XEUtils.floor((colWidth / tableWidth) * 180, 2)
821
+ })
822
+ }
823
+
824
+ const getHeaderWidthStyle = (column: VxeTableDefines.ColumnInfo) => {
825
+ const cmColKey = getCustomColKey(column)
826
+ const cmWidthMaps = customWidthMaps[cmColKey]
827
+ if (cmWidthMaps) {
828
+ return 'width:' + toCssUnit(cmWidthMaps)
829
+ }
830
+ if (isAutoWidth) {
831
+ return ''
832
+ }
833
+ if (isScaleWidth) {
834
+ return printWidthMaps[column.id] ? 'width:' + printWidthMaps[column.id] + 'mm' : ''
835
+ }
836
+ return colWidthMaps[column.id] ? 'width:' + toCssUnit(colWidthMaps[column.id]) : ''
837
+ }
838
+
839
+ const getCellWidthStyle = (column: VxeTableDefines.ColumnInfo) => {
840
+ const cmColKey = getCustomColKey(column)
841
+ const cmWidthMaps = customWidthMaps[cmColKey]
842
+ if (cmWidthMaps) {
843
+ return 'width:' + toCssUnit(cmWidthMaps)
844
+ }
845
+ if (isAutoWidth || isDefaultWidth) {
846
+ return ''
847
+ }
848
+ if (isScaleWidth) {
849
+ return printWidthMaps[column.id] ? 'width:' + printWidthMaps[column.id] + 'mm' : ''
850
+ }
851
+ return colWidthMaps[column.id] ? 'width:' + toCssUnit(colWidthMaps[column.id]) : ''
852
+ }
853
+
854
+ const allCls = 'check-all'
855
+ const clss = ['vxe-table', `border--${toTableBorder(border)}`, isPrint ? 'is--print' : '', isAutoWidth ? 'is--auto-width' : '', isScaleWidth ? 'is--scale-width' : '', isDefaultWidth ? 'is--default-width' : '', isHeader ? 'is--header' : ''].filter((cls) => cls)
856
+ const tables = [`<table class="${clss.join(' ')}" border="0" cellspacing="0" cellpadding="0">`, `<colgroup>${columns.map((column) => `<col style="${getHeaderWidthStyle(column)}">`).join('')}</colgroup>`]
857
+ if (isHeader) {
858
+ tables.push('<thead>')
859
+ if (isColgroup && !original) {
860
+ colgroups.forEach((cols) => {
861
+ tables.push(
862
+ `<tr>${cols
863
+ .map((column: any) => {
864
+ const headAlign = column.headerAlign || column.align || allHeaderAlign || allAlign
865
+ const classNames = hasEllipsis(column, 'showHeaderOverflow', allColumnHeaderOverflow) ? ['col--ellipsis'] : []
866
+ const cellTitle = getHeaderTitle(opts, column)
867
+ if (headAlign) {
868
+ classNames.push(`col--${headAlign}`)
869
+ }
870
+ if (column.type === 'checkbox') {
871
+ return `<th class="${classNames.join(' ')}" colspan="${column._colSpan}" rowspan="${column._rowSpan}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" class="${allCls}" ${isAllSelected ? 'checked' : ''}><span>${cellTitle}</span></div></th>`
872
+ }
873
+ return `<th class="${classNames.join(' ')}" colspan="${column._colSpan}" rowspan="${column._rowSpan}" title="${cellTitle}"><div style="${getCellWidthStyle(column)}"><span>${formatText(cellTitle, true)}</span></div></th>`
874
+ })
875
+ .join('')}</tr>`
876
+ )
877
+ })
878
+ } else {
879
+ tables.push(
880
+ `<tr>${columns
881
+ .map((column: any) => {
882
+ const headAlign = column.headerAlign || column.align || allHeaderAlign || allAlign
883
+ const classNames = hasEllipsis(column, 'showHeaderOverflow', allColumnHeaderOverflow) ? ['col--ellipsis'] : []
884
+ const cellTitle = getHeaderTitle(opts, column)
885
+ if (headAlign) {
886
+ classNames.push(`col--${headAlign}`)
887
+ }
888
+ if (column.type === 'checkbox') {
889
+ return `<th class="${classNames.join(' ')}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" class="${allCls}" ${isAllSelected ? 'checked' : ''}><span>${cellTitle}</span></div></th>`
890
+ }
891
+ return `<th class="${classNames.join(' ')}" title="${cellTitle}"><div style="${getCellWidthStyle(column)}"><span>${formatText(cellTitle, true)}</span></div></th>`
892
+ })
893
+ .join('')}</tr>`
894
+ )
895
+ }
896
+ tables.push('</thead>')
897
+ }
898
+ if (datas.length) {
899
+ tables.push('<tbody>')
900
+ if (treeConfig) {
901
+ datas.forEach((item: any) => {
902
+ tables.push(
903
+ '<tr>' +
904
+ columns
905
+ .map((column: any) => {
906
+ const colid = column.id
907
+ const cellAlign = column.align || allAlign
908
+ const classNames = hasEllipsis(column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
909
+ const cellValue = item[colid]
910
+ if (cellAlign) {
911
+ classNames.push(`col--${cellAlign}`)
912
+ }
913
+ if (column.treeNode) {
914
+ let treeIcon = ''
915
+ if (item._hasChild) {
916
+ treeIcon = `<i class="${item._expand ? 'vxe-table--tree-fold-icon' : 'vxe-table--tree-unfold-icon'}"></i>`
917
+ }
918
+ classNames.push('vxe-table--tree-node')
919
+ if (column.type === 'radio') {
920
+ return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}"><div class="vxe-table--tree-node-wrapper" style="padding-left: ${item._level * treeOpts.indent}px"><div class="vxe-table--tree-icon-wrapper">${treeIcon}</div><div class="vxe-table--tree-cell"><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></div></div></td>`
921
+ } else if (column.type === 'checkbox') {
922
+ return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}"><div class="vxe-table--tree-node-wrapper" style="padding-left: ${item._level * treeOpts.indent}px"><div class="vxe-table--tree-icon-wrapper">${treeIcon}</div><div class="vxe-table--tree-cell"><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></div></div></td>`
923
+ }
924
+ return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}"><div class="vxe-table--tree-node-wrapper" style="padding-left: ${item._level * treeOpts.indent}px"><div class="vxe-table--tree-icon-wrapper">${treeIcon}</div><div class="vxe-table--tree-cell">${cellValue}</div></div></div></td>`
925
+ }
926
+ if (column.type === 'radio') {
927
+ return `<td class="${classNames.join(' ')}"><div style="${getCellWidthStyle(column)}"><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></td>`
928
+ } else if (column.type === 'checkbox') {
929
+ return `<td class="${classNames.join(' ')}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></td>`
930
+ }
931
+ return `<td class="${classNames.join(' ')}" title="${cellValue}"><div style="${getCellWidthStyle(column)}">${formatText(cellValue, true)}</div></td>`
932
+ })
933
+ .join('') +
934
+ '</tr>'
935
+ )
936
+ })
937
+ } else {
938
+ datas.forEach((item) => {
939
+ tables.push(
940
+ '<tr>' +
941
+ columns
942
+ .map((column) => {
943
+ const cellAlign = column.align || allAlign
944
+ const classNames = hasEllipsis(column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
945
+ const cellValue = item[column.id]
946
+ let rowSpan = 1
947
+ let colSpan = 1
948
+ if (isMerge) {
949
+ const _rowIndex = $xeTable.getVTRowIndex(item._row)
950
+ const _columnIndex = $xeTable.getVTColumnIndex(column)
951
+ const spanRest = mergeBodyCellMaps[`${_rowIndex}:${_columnIndex}`]
952
+ if (spanRest) {
953
+ const { rowspan, colspan } = spanRest
954
+ if (!rowspan || !colspan) {
955
+ return ''
956
+ }
957
+ if (rowspan > 1) {
958
+ rowSpan = rowspan
959
+ }
960
+ if (colspan > 1) {
961
+ colSpan = colspan
962
+ }
963
+ }
964
+ }
965
+ if (cellAlign) {
966
+ classNames.push(`col--${cellAlign}`)
967
+ }
968
+ if (column.type === 'radio') {
969
+ return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}"><div style="${getCellWidthStyle(column)}"><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></td>`
970
+ } else if (column.type === 'checkbox') {
971
+ return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}"><div style="${getCellWidthStyle(column)}"><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></td>`
972
+ }
973
+ return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}" title="${cellValue}"><div style="${getCellWidthStyle(column)}">${formatText(cellValue, true)}</div></td>`
974
+ })
975
+ .join('') +
976
+ '</tr>'
977
+ )
978
+ })
979
+ }
980
+ tables.push('</tbody>')
981
+ }
982
+ if (isFooter) {
983
+ const { footerTableData } = reactData
984
+ const footers = getFooterData($xeTable, opts, footerTableData)
985
+ if (footers.length) {
986
+ tables.push('<tfoot>')
987
+ footers.forEach((row, rIndex) => {
988
+ tables.push(
989
+ `<tr>${columns
990
+ .map((column) => {
991
+ const footAlign = column.footerAlign || column.align || allFooterAlign || allAlign
992
+ const classNames = hasEllipsis(column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
993
+ const cellValue = getFooterCellValue(opts, row, column)
994
+ let rowSpan = 1
995
+ let colSpan = 1
996
+ if (isMerge) {
997
+ const _rowIndex = rIndex
998
+ const _columnIndex = $xeTable.getVTColumnIndex(column)
999
+ const spanRest = mergeFooterCellMaps[`${_rowIndex}:${_columnIndex}`]
1000
+ if (spanRest) {
1001
+ const { rowspan, colspan } = spanRest
1002
+ if (!rowspan || !colspan) {
1003
+ return ''
1004
+ }
1005
+ if (rowspan > 1) {
1006
+ rowSpan = rowspan
1007
+ }
1008
+ if (colspan > 1) {
1009
+ colSpan = colspan
1010
+ }
1011
+ }
1012
+ }
1013
+ if (footAlign) {
1014
+ classNames.push(`col--${footAlign}`)
1015
+ }
1016
+ return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}" title="${cellValue}"><div style="${getCellWidthStyle(column)}">${formatText(cellValue, true)}</div></td>`
1017
+ })
1018
+ .join('')}</tr>`
1019
+ )
1020
+ })
1021
+ tables.push('</tfoot>')
1022
+ }
1023
+ }
1024
+ // 是否半选状态
1025
+ const script = !isAllSelected && isIndeterminate ? `<script>(function(){var a=document.querySelector(".${allCls}");if(a){a.indeterminate=true}})()</script>` : ''
1026
+ tables.push('</table>', script)
1027
+ return isPrint ? tables.join('') : createHtmlPage(opts, tables.join(''))
1028
+ }
1029
+
1030
+ const toXML = (opts: any, columns: any, datas: any) => {
1031
+ let xml = [
1032
+ '<?xml version="1.0"?>',
1033
+ '<?mso-application progid="Excel.Sheet"?>',
1034
+ '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">',
1035
+ '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">',
1036
+ '<Version>16.00</Version>',
1037
+ '</DocumentProperties>',
1038
+ '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">',
1039
+ '<WindowHeight>7920</WindowHeight>',
1040
+ '<WindowWidth>21570</WindowWidth>',
1041
+ '<WindowTopX>32767</WindowTopX>',
1042
+ '<WindowTopY>32767</WindowTopY>',
1043
+ '<ProtectStructure>False</ProtectStructure>',
1044
+ '<ProtectWindows>False</ProtectWindows>',
1045
+ '</ExcelWorkbook>',
1046
+ `<Worksheet ss:Name="${opts.sheetName}">`,
1047
+ '<Table>',
1048
+ columns.map((column: any) => `<Column ss:Width="${column.renderWidth}"/>`).join('')
1049
+ ].join('')
1050
+ if (opts.isHeader) {
1051
+ xml += `<Row>${columns.map((column: any) => `<Cell><Data ss:Type="String">${getHeaderTitle(opts, column)}</Data></Cell>`).join('')}</Row>`
1052
+ }
1053
+ datas.forEach((row: any) => {
1054
+ xml += '<Row>' + columns.map((column: any) => `<Cell><Data ss:Type="String">${row[column.id]}</Data></Cell>`).join('') + '</Row>'
1055
+ })
1056
+ if (opts.isFooter) {
1057
+ const { footerTableData } = reactData
1058
+ const footers = getFooterData($xeTable, opts, footerTableData)
1059
+ footers.forEach((row: any) => {
1060
+ xml += `<Row>${columns.map((column: any) => `<Cell><Data ss:Type="String">${getFooterCellValue(opts, row, column)}</Data></Cell>`).join('')}</Row>`
1061
+ })
1062
+ }
1063
+ return `${xml}</Table></Worksheet></Workbook>`
1064
+ }
1065
+
1066
+ const getContent = ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) => {
1067
+ if (columns.length) {
1068
+ switch (opts.type) {
1069
+ case 'csv':
1070
+ return toCsv($xeTable, opts, columns, datas)
1071
+ case 'txt':
1072
+ return toTxt($xeTable, opts, columns, datas)
1073
+ case 'html':
1074
+ return toHtml(opts, columns, datas)
1075
+ case 'xml':
1076
+ return toXML(opts, columns, datas)
1077
+ }
1078
+ }
1079
+ return ''
1080
+ }
1081
+
1082
+ const downloadFile = (opts: any, content: any) => {
1083
+ const { filename, type, download } = opts
1084
+ if (!download) {
1085
+ const blob = getExportBlobByContent(content, opts)
1086
+ return Promise.resolve({ type, content, blob })
1087
+ }
1088
+ if (VxeUI.saveFile) {
1089
+ VxeUI.saveFile({ filename, type, content }).then(() => {
1090
+ if (opts.message !== false) {
1091
+ if (VxeUI.modal) {
1092
+ VxeUI.modal.message({ content: getI18n('vxe.table.expSuccess'), status: 'success' })
1093
+ }
1094
+ }
1095
+ })
1096
+ }
1097
+ }
1098
+
1099
+ const handleExport = (opts: VxeTablePropTypes.ExportHandleOptions) => {
1100
+ const $xeGrid = $xeTable.xeGrid
1101
+ const $xeGantt = $xeTable.xeGantt
1102
+
1103
+ const { remote, columns, colgroups, exportMethod, afterExportMethod } = opts
1104
+ return new Promise((resolve) => {
1105
+ if (remote) {
1106
+ const params = { options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt }
1107
+ resolve(exportMethod ? exportMethod(params) : params)
1108
+ } else {
1109
+ const datas = getExportData(opts)
1110
+ resolve(
1111
+ $xeTable.preventEvent(null, 'event.export', { options: opts, columns, colgroups, datas }, () => {
1112
+ return downloadFile(opts, getContent($xeTable, opts, columns, datas))
1113
+ })
1114
+ )
1115
+ }
1116
+ })
1117
+ .then((params: any) => {
1118
+ clearColumnConvert(columns)
1119
+ if (!opts.print) {
1120
+ if (afterExportMethod) {
1121
+ afterExportMethod({ status: true, options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1122
+ }
1123
+ }
1124
+ return Object.assign({ status: true }, params)
1125
+ })
1126
+ .catch(() => {
1127
+ clearColumnConvert(columns)
1128
+ if (!opts.print) {
1129
+ if (afterExportMethod) {
1130
+ afterExportMethod({ status: false, options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1131
+ }
1132
+ }
1133
+ const params = { status: false }
1134
+ return Promise.reject(params)
1135
+ })
1136
+ }
1137
+
1138
+ const handleImport = (content: any, opts: any) => {
1139
+ const { tableFullColumn, _importResolve, _importReject } = internalData
1140
+ let rest: {
1141
+ fields: string[]
1142
+ rows: any[]
1143
+ } = { fields: [], rows: [] }
1144
+ const tableFieldMaps: Record<string, VxeTableDefines.ColumnInfo> = {}
1145
+ const tableTitleMaps: Record<string, VxeTableDefines.ColumnInfo> = {}
1146
+ tableFullColumn.forEach((column) => {
1147
+ const field = column.field
1148
+ const title = $xeTable.getHeaderCellLabel(column)
1149
+ if (field) {
1150
+ tableFieldMaps[field] = column
1151
+ }
1152
+ if (title) {
1153
+ tableTitleMaps[title] = column
1154
+ }
1155
+ })
1156
+ const tableConf = {
1157
+ fieldMaps: tableFieldMaps,
1158
+ titleMaps: tableTitleMaps
1159
+ }
1160
+ switch (opts.type) {
1161
+ case 'csv':
1162
+ rest = parseCsv(tableConf, content)
1163
+ break
1164
+ case 'txt':
1165
+ rest = parseTxt(tableConf, content)
1166
+ break
1167
+ case 'html':
1168
+ rest = parseHTML(tableConf, content)
1169
+ break
1170
+ case 'xml':
1171
+ rest = parseXML(tableConf, content)
1172
+ break
1173
+ }
1174
+ const { fields, rows } = rest
1175
+ const status = fields.some((field) => tableFieldMaps[field] || tableTitleMaps[field])
1176
+ if (status) {
1177
+ $xeTable.createData(rows).then((data: any) => {
1178
+ let loadRest
1179
+ if (opts.mode === 'insert' || opts.mode === 'insertBottom') {
1180
+ loadRest = $xeTable.insertAt(data, -1)
1181
+ } else if (opts.mode === 'insertTop') {
1182
+ loadRest = $xeTable.insert(data)
1183
+ } else {
1184
+ loadRest = $xeTable.reloadData(data)
1185
+ }
1186
+ if (opts.message !== false) {
1187
+ if (VxeUI.modal) {
1188
+ VxeUI.modal.message({ content: getI18n('vxe.table.impSuccess', [rows.length]), status: 'success' })
1189
+ }
1190
+ }
1191
+ return loadRest.then(() => {
1192
+ if (_importResolve) {
1193
+ _importResolve({ status: true })
1194
+ }
1195
+ })
1196
+ })
1197
+ } else if (opts.message !== false) {
1198
+ if (VxeUI.modal) {
1199
+ VxeUI.modal.message({ content: getI18n('vxe.error.impFields'), status: 'error' })
1200
+ }
1201
+ if (_importReject) {
1202
+ _importReject({ status: false, msg: 'field mismatching' })
1203
+ }
1204
+ }
1205
+ }
1206
+
1207
+ const handleFileImport = (file: File, opts: any) => {
1208
+ const { importMethod, afterImportMethod } = opts
1209
+ const { type, filename } = parseFile(file)
1210
+ const importOpts = computeImportOpts.value
1211
+
1212
+ // 检查类型,如果为自定义导出,则不需要校验类型
1213
+ if (!importMethod && !XEUtils.includes(XEUtils.keys(importOpts._typeMaps), type)) {
1214
+ if (opts.message !== false) {
1215
+ if (VxeUI.modal) {
1216
+ VxeUI.modal.message({ content: getI18n('vxe.error.notType', [type]), status: 'error' })
1217
+ }
1218
+ }
1219
+ const params = { status: false, msg: 'type error' }
1220
+ return Promise.reject(params)
1221
+ }
1222
+
1223
+ const rest = new Promise((resolve, reject) => {
1224
+ const _importResolve = (params?: any) => {
1225
+ resolve(params)
1226
+ internalData._importResolve = null
1227
+ internalData._importReject = null
1228
+ }
1229
+ const _importReject = (params?: any) => {
1230
+ reject(params)
1231
+ internalData._importResolve = null
1232
+ internalData._importReject = null
1233
+ }
1234
+ internalData._importResolve = _importResolve
1235
+ internalData._importReject = _importReject
1236
+ if (window.FileReader) {
1237
+ const options = Object.assign({ mode: 'insertTop' }, opts, { type, filename })
1238
+ if (options.remote) {
1239
+ if (importMethod) {
1240
+ Promise.resolve(importMethod({ file, options, $table: $xeTable }))
1241
+ .then(() => {
1242
+ _importResolve({ status: true })
1243
+ })
1244
+ .catch(() => {
1245
+ _importResolve({ status: true })
1246
+ })
1247
+ } else {
1248
+ _importResolve({ status: true })
1249
+ }
1250
+ } else {
1251
+ const { tableFullColumn } = internalData
1252
+ $xeTable.preventEvent(null, 'event.import', { file, options, columns: tableFullColumn }, () => {
1253
+ const reader = new FileReader()
1254
+ reader.onerror = () => {
1255
+ errLog('vxe.error.notType', [type])
1256
+ _importReject({ status: false, msg: 'reading file error' })
1257
+ }
1258
+ reader.onload = (e: any) => {
1259
+ handleImport(e.target.result, options)
1260
+ }
1261
+ reader.readAsText(file, options.encoding || 'UTF-8')
1262
+ })
1263
+ }
1264
+ } else {
1265
+ // 不支持的浏览器
1266
+ errLog('vxe.error.notExp')
1267
+ _importResolve({ status: false, msg: 'unsupported browser' })
1268
+ }
1269
+ })
1270
+
1271
+ return rest
1272
+ .then(() => {
1273
+ if (afterImportMethod) {
1274
+ afterImportMethod({ status: true, options: opts, $table: $xeTable })
1275
+ }
1276
+ })
1277
+ .catch((e) => {
1278
+ if (afterImportMethod) {
1279
+ afterImportMethod({ status: false, options: opts, $table: $xeTable })
1280
+ }
1281
+ return Promise.reject(e)
1282
+ })
1283
+ }
1284
+
1285
+ const handleFilterColumns = (exportOpts: VxeTablePropTypes.ExportConfig, column: VxeTableDefines.ColumnInfo, columns: VxeTableDefines.ColumnInfo[] | VxeTablePropTypes.ExportOrPrintColumnOption[]) => {
1286
+ return columns.some((item: any) => {
1287
+ if (isColumnInfo(item)) {
1288
+ return column.id === (item as any).id
1289
+ } else if (XEUtils.isString(item)) {
1290
+ return column.field === item
1291
+ } else {
1292
+ const colid = item.id || item.colId
1293
+ const type = item.type
1294
+ const field = item.field
1295
+ if (colid) {
1296
+ return column.id === colid
1297
+ } else if (field && type) {
1298
+ return column.field === field && column.type === type
1299
+ } else if (field) {
1300
+ return column.field === field
1301
+ } else if (type) {
1302
+ return column.type === type
1303
+ }
1304
+ }
1305
+ return false
1306
+ })
1307
+ }
1308
+
1309
+ const handleFilterFields = (exportOpts: VxeTablePropTypes.ExportConfig, column: VxeTableDefines.ColumnInfo, includeFields: string[] | undefined, includeFdMaps: Record<string, number>, excludeFdMaps: Record<string, number>, extraFdMaps: Record<string, number>) => {
1310
+ const { field } = column
1311
+ if (excludeFdMaps[field]) {
1312
+ return false
1313
+ }
1314
+ if (includeFields) {
1315
+ if (includeFdMaps[field]) {
1316
+ return true
1317
+ }
1318
+ return false
1319
+ }
1320
+ if (extraFdMaps[field]) {
1321
+ return true
1322
+ }
1323
+ return exportOpts.original ? !!field : defaultFilterExportColumn(column)
1324
+ }
1325
+
1326
+ const handleExportAndPrint = (options: VxeTablePropTypes.ExportOpts | VxeTablePropTypes.ExportConfig, isPrint?: boolean) => {
1327
+ const $xeGrid = $xeTable.xeGrid
1328
+ const $xeGantt = $xeTable.xeGantt
1329
+ const $xeGGWrapper = $xeGrid || $xeGantt
1330
+
1331
+ const { treeConfig, showHeader, showFooter } = props
1332
+ const { initStore, isGroup, rowGroupList, footerTableData, exportStore, exportParams } = reactData
1333
+ const { collectColumn, mergeBodyList, mergeFooterList } = internalData
1334
+ const exportOpts = computeExportOpts.value
1335
+ const printOpts = computePrintOpts.value
1336
+ const hasTree = !!treeConfig
1337
+ const hasRowGroup = rowGroupList.length > 0
1338
+ const selectRecords = $xeTable.getCheckboxRecords()
1339
+ const proxyOpts = $xeGGWrapper ? $xeGGWrapper.getComputeMaps().computeProxyOpts.value : ({} as VxeGridPropTypes.ProxyOpts)
1340
+ const hasFooter = !!footerTableData.length
1341
+ const hasMerge = !!(mergeBodyList.length || mergeFooterList.length)
1342
+ const defOpts = Object.assign(
1343
+ {
1344
+ message: true,
1345
+ isHeader: showHeader,
1346
+ isTitle: showHeader,
1347
+ isFooter: showFooter,
1348
+ isColgroup: isGroup,
1349
+ isMerge: hasMerge,
1350
+ useStyle: true,
1351
+ current: 'current',
1352
+ modes: (proxyOpts.ajax && proxyOpts.ajax.queryAll ? ['all'] : []).concat(['current', 'selected', 'empty'])
1353
+ },
1354
+ options
1355
+ )
1356
+
1357
+ // 已废弃,参数 isAllExpand
1358
+ if (XEUtils.isBoolean((defOpts as any).isAllExpand)) {
1359
+ warnLog('vxe.error.delProp', ['isAllExpand', 'isTreeAllExpanded'])
1360
+ defOpts.isTreeAllExpanded = (defOpts as any).isAllExpand
1361
+ }
1362
+
1363
+ const types: string[] = isPrint ? [] : defOpts.types || XEUtils.keys(exportOpts._typeMaps)
1364
+ const modes: string[] = defOpts.modes || []
1365
+ const checkMethod = (isPrint ? printOpts : exportOpts).checkMethod
1366
+ const exportColumns = collectColumn.slice(0)
1367
+ const { columns, excludeFields, includeFields, extraFields } = defOpts
1368
+ // 处理类型
1369
+ const typeList = types.map((value) => {
1370
+ return {
1371
+ value,
1372
+ label: getI18n(`vxe.export.types.${value}`)
1373
+ }
1374
+ })
1375
+ const modeList = modes.map((item: any) => {
1376
+ if (item && item.value) {
1377
+ return {
1378
+ value: item.value,
1379
+ label: item.label || item.value
1380
+ }
1381
+ }
1382
+ return {
1383
+ value: item,
1384
+ label: getI18n(`vxe.export.modes.${item}`)
1385
+ }
1386
+ })
1387
+
1388
+ const excludeFdMaps: Record<string, number> = {}
1389
+ if (excludeFields && excludeFields.length) {
1390
+ excludeFields.forEach((field) => {
1391
+ excludeFdMaps[field] = 1
1392
+ })
1393
+ }
1394
+ const includeFdMaps: Record<string, number> = {}
1395
+ if (includeFields && includeFields.length) {
1396
+ includeFields.forEach((field) => {
1397
+ includeFdMaps[field] = 1
1398
+ })
1399
+ }
1400
+ const extraFdMaps: Record<string, number> = {}
1401
+ if (extraFields) {
1402
+ extraFields.forEach((field) => {
1403
+ extraFdMaps[field] = 1
1404
+ })
1405
+ }
1406
+
1407
+ // 默认选中
1408
+ // 优先级 columns > excludeFields > (includeFields || extraFields)
1409
+ XEUtils.eachTree(exportColumns, (column, index, items, path, parentColumn) => {
1410
+ const isColGroup = column.children && column.children.length > 0
1411
+ let isChecked = false
1412
+ const isExtraChecked = extraFdMaps[column.field]
1413
+ if (columns) {
1414
+ isChecked = handleFilterColumns(defOpts, column, columns)
1415
+ } else if (excludeFields || includeFields) {
1416
+ isChecked = handleFilterFields(defOpts, column, includeFields, includeFdMaps, excludeFdMaps, extraFdMaps)
1417
+ } else {
1418
+ if (isExtraChecked) {
1419
+ isChecked = true
1420
+ } else {
1421
+ isChecked = column.visible && (isColGroup || defaultFilterExportColumn(column))
1422
+ }
1423
+ }
1424
+ column.checked = isChecked
1425
+ column.halfChecked = false
1426
+ column.disabled = (parentColumn && parentColumn.disabled) || (checkMethod ? !checkMethod({ $table: $xeTable, column }) : false)
1427
+ })
1428
+ // 更新条件
1429
+ exportStore.columns = exportColumns
1430
+ exportStore.typeList = typeList
1431
+ exportStore.modeList = modeList
1432
+ exportStore.hasFooter = hasFooter
1433
+ exportStore.hasMerge = hasMerge
1434
+ exportStore.hasTree = hasTree
1435
+ exportStore.hasRowGroup = hasRowGroup
1436
+ exportStore.isPrint = !!isPrint
1437
+ exportStore.hasColgroup = isGroup
1438
+ exportStore.visible = true
1439
+ // 默认参数
1440
+ Object.assign(
1441
+ exportParams,
1442
+ {
1443
+ mode: selectRecords.length ? 'selected' : 'current'
1444
+ },
1445
+ defOpts
1446
+ )
1447
+ const { filename, sheetName, mode, type } = exportParams
1448
+ if (filename) {
1449
+ if (XEUtils.isFunction(filename)) {
1450
+ exportParams.filename = filename({
1451
+ options: defOpts,
1452
+ $table: $xeTable,
1453
+ $grid: $xeGrid,
1454
+ $gantt: $xeGantt
1455
+ })
1456
+ } else {
1457
+ exportParams.filename = `${filename}`
1458
+ }
1459
+ }
1460
+ if (sheetName) {
1461
+ if (XEUtils.isFunction(sheetName)) {
1462
+ exportParams.sheetName = sheetName({
1463
+ options: defOpts,
1464
+ $table: $xeTable,
1465
+ $grid: $xeGrid,
1466
+ $gantt: $xeGantt
1467
+ })
1468
+ } else {
1469
+ exportParams.sheetName = `${sheetName}`
1470
+ }
1471
+ }
1472
+ if (!modeList.some((item) => item.value === mode)) {
1473
+ exportParams.mode = modeList.length ? modeList[0].value : ''
1474
+ }
1475
+ if (!typeList.some((item) => item.value === type)) {
1476
+ exportParams.type = typeList.length ? typeList[0].value : ''
1477
+ }
1478
+ if (!exportParams.widthMode) {
1479
+ exportParams.widthMode = ''
1480
+ }
1481
+ initStore.export = true
1482
+ return nextTick()
1483
+ }
1484
+
1485
+ const handleCloseExport = () => {
1486
+ if (VxeUI.modal) {
1487
+ return VxeUI.modal.close('VXE_EXPORT_MODAL')
1488
+ }
1489
+ return Promise.resolve()
1490
+ }
1491
+
1492
+ const exportMethods: TableExportMethods = {
1493
+ /**
1494
+ * 导出文件,支持 csv/html/xml/txt
1495
+ * 如果是树表格,则默认是导出所有节点
1496
+ * 如果是启用了虚拟滚动,则只能导出数据源,可以配合 dataFilterMethod 函数转换数据
1497
+ * @param {Object} options 参数
1498
+ */
1499
+ exportData(options) {
1500
+ const $xeGrid = $xeTable.xeGrid
1501
+ const $xeGantt = $xeTable.xeGantt
1502
+ const $xeGGWrapper = $xeGrid || $xeGantt
1503
+
1504
+ const { treeConfig, showHeader, showFooter } = props
1505
+ const { isGroup } = reactData
1506
+ const { tableFullColumn, afterFullData, afterTreeFullData, collectColumn, mergeBodyList, mergeFooterList } = internalData
1507
+ const exportOpts = computeExportOpts.value
1508
+ const treeOpts = computeTreeOpts.value
1509
+ const proxyOpts = $xeGGWrapper ? $xeGGWrapper.getComputeMaps().computeProxyOpts.value : ({} as VxeGridPropTypes.ProxyOpts)
1510
+ const hasMerge = !!(mergeBodyList.length || mergeFooterList.length)
1511
+ const opts = Object.assign(
1512
+ {
1513
+ message: true,
1514
+ isHeader: showHeader,
1515
+ isTitle: showHeader,
1516
+ isFooter: showFooter,
1517
+ isColgroup: isGroup,
1518
+ isMerge: hasMerge,
1519
+ useStyle: true,
1520
+ current: 'current',
1521
+ modes: (proxyOpts.ajax && proxyOpts.ajax.queryAll ? ['all'] : []).concat(['current', 'selected', 'empty']),
1522
+ download: true,
1523
+ type: 'csv'
1524
+ // filename: '',
1525
+ // sheetName: '',
1526
+ // original: false,
1527
+ // isTreeAllExpanded: false,
1528
+ // isRowGroupAllExpanded: false,
1529
+ // data: null,
1530
+ // remote: false,
1531
+ // dataFilterMethod: null,
1532
+ // footerFilterMethod: null,
1533
+ // exportMethod: null,
1534
+ // columnFilterMethod: null,
1535
+ // beforeExportMethod: null,
1536
+ // afterExportMethod: null
1537
+ },
1538
+ exportOpts,
1539
+ options
1540
+ )
1541
+
1542
+ // 已废弃,参数 isAllExpand
1543
+ if (XEUtils.isBoolean((opts as any).isAllExpand)) {
1544
+ warnLog('vxe.error.delProp', ['isAllExpand', 'isTreeAllExpanded'])
1545
+ opts.isTreeAllExpanded = (opts as any).isAllExpand
1546
+ }
1547
+
1548
+ let { filename, sheetName, type, mode, columns, columnFilterMethod, beforeExportMethod, includeFields, excludeFields, extraFields } = opts
1549
+ let groups: any[] = []
1550
+ const selectRecords = $xeTable.getCheckboxRecords()
1551
+ if (!mode) {
1552
+ mode = selectRecords.length ? 'selected' : 'current'
1553
+ }
1554
+
1555
+ const excludeFdMaps: Record<string, number> = {}
1556
+ if (excludeFields && excludeFields.length) {
1557
+ excludeFields.forEach((field) => {
1558
+ excludeFdMaps[field] = 1
1559
+ })
1560
+ }
1561
+ const includeFdMaps: Record<string, number> = {}
1562
+ if (includeFields && includeFields.length) {
1563
+ includeFields.forEach((field) => {
1564
+ includeFdMaps[field] = 1
1565
+ })
1566
+ }
1567
+ const extraFdMaps: Record<string, number> = {}
1568
+ if (extraFields) {
1569
+ extraFields.forEach((field) => {
1570
+ extraFdMaps[field] = 1
1571
+ })
1572
+ }
1573
+
1574
+ let isCustomCol = false
1575
+ let customCols = []
1576
+ const _columns = (opts as any)._columns
1577
+ if (_columns) {
1578
+ // 内部导出使用 _columns -> _children 为自定义子集
1579
+ isCustomCol = true
1580
+ customCols = XEUtils.searchTree(_columns, () => true, { children: '_children', mapChildren: 'childNodes', original: true })
1581
+ } else if (columns) {
1582
+ isCustomCol = true
1583
+ customCols = XEUtils.searchTree(columns, () => true, { children: 'children', mapChildren: 'childNodes', original: true })
1584
+ } else {
1585
+ customCols = XEUtils.searchTree(
1586
+ collectColumn,
1587
+ (column) => {
1588
+ const isColGroup = column.children && column.children.length > 0
1589
+ let isChecked = false
1590
+ const isExtraChecked = extraFdMaps[column.field]
1591
+ if (columns) {
1592
+ isChecked = handleFilterColumns(opts, column, columns)
1593
+ } else if (excludeFields || includeFields) {
1594
+ isChecked = handleFilterFields(opts, column, includeFields, includeFdMaps, excludeFdMaps, extraFdMaps)
1595
+ } else {
1596
+ if (isExtraChecked) {
1597
+ isChecked = true
1598
+ } else {
1599
+ isChecked = column.visible && (isColGroup || defaultFilterExportColumn(column))
1600
+ }
1601
+ }
1602
+ return isChecked
1603
+ },
1604
+ { children: 'children', mapChildren: 'childNodes', original: true }
1605
+ )
1606
+ }
1607
+ const handleOptions: VxeTablePropTypes.ExportHandleOptions = Object.assign({} as { data: any[]; colgroups: any[]; columns: any[] }, opts, { filename: '', sheetName: '', _columnConfs: columns })
1608
+ // 如果设置源数据,则默认导出设置了字段的列
1609
+ if (!isCustomCol && !columnFilterMethod) {
1610
+ columnFilterMethod = ({ column }) => handleFilterFields(handleOptions, column, includeFields, includeFdMaps, excludeFdMaps, extraFdMaps)
1611
+ handleOptions.columnFilterMethod = columnFilterMethod
1612
+ }
1613
+ if (customCols) {
1614
+ handleOptions._isCustomColumn = true
1615
+ groups = XEUtils.searchTree(
1616
+ XEUtils.mapTree(
1617
+ customCols,
1618
+ (item) => {
1619
+ let targetColumn
1620
+ if (item) {
1621
+ if (isColumnInfo(item)) {
1622
+ targetColumn = item
1623
+ } else if (XEUtils.isString(item)) {
1624
+ targetColumn = $xeTable.getColumnByField(item)
1625
+ } else {
1626
+ const colid = item.id || item.colId
1627
+ const type = item.type
1628
+ const field = item.field
1629
+ if (colid) {
1630
+ targetColumn = $xeTable.getColumnById(colid)
1631
+ } else if (field && type) {
1632
+ targetColumn = tableFullColumn.find((column) => column.field === field && column.type === type)
1633
+ } else if (field) {
1634
+ targetColumn = $xeTable.getColumnByField(field)
1635
+ } else if (type) {
1636
+ targetColumn = tableFullColumn.find((column) => column.type === type)
1637
+ }
1638
+ }
1639
+ return targetColumn || {}
1640
+ }
1641
+ },
1642
+ {
1643
+ children: 'childNodes',
1644
+ mapChildren: '_children'
1645
+ }
1646
+ ),
1647
+ (column, index) => isColumnInfo(column) && (!columnFilterMethod || columnFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, column: column as any, $columnIndex: index })),
1648
+ {
1649
+ children: '_children',
1650
+ mapChildren: 'childNodes',
1651
+ original: true
1652
+ }
1653
+ )
1654
+ } else {
1655
+ groups = XEUtils.searchTree(isGroup ? collectColumn : tableFullColumn, (column, index) => column.visible && (!columnFilterMethod || columnFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, column, $columnIndex: index })), {
1656
+ children: 'children',
1657
+ mapChildren: 'childNodes',
1658
+ original: true
1659
+ })
1660
+ }
1661
+ // 获取所有列
1662
+ const cols: VxeTableDefines.ColumnInfo[] = []
1663
+ XEUtils.eachTree(
1664
+ groups,
1665
+ (column) => {
1666
+ const isColGroup = column.children && column.children.length
1667
+ if (!isColGroup) {
1668
+ cols.push(column)
1669
+ }
1670
+ },
1671
+ { children: 'childNodes' }
1672
+ )
1673
+ // 构建分组层级
1674
+ handleOptions.columns = cols
1675
+ handleOptions.colgroups = convertToRows(groups)
1676
+ if (filename) {
1677
+ if (XEUtils.isFunction(filename)) {
1678
+ handleOptions.filename = filename({
1679
+ options: opts,
1680
+ $table: $xeTable,
1681
+ $grid: $xeGrid,
1682
+ $gantt: $xeGantt
1683
+ })
1684
+ } else {
1685
+ handleOptions.filename = `${filename}`
1686
+ }
1687
+ }
1688
+ if (!handleOptions.filename) {
1689
+ handleOptions.filename = getI18n(handleOptions.original ? 'vxe.table.expOriginFilename' : 'vxe.table.expFilename', [XEUtils.toDateString(Date.now(), 'yyyyMMddHHmmss')])
1690
+ }
1691
+
1692
+ if (sheetName) {
1693
+ if (XEUtils.isFunction(sheetName)) {
1694
+ handleOptions.sheetName = sheetName({
1695
+ options: opts,
1696
+ $table: $xeTable,
1697
+ $grid: $xeGrid,
1698
+ $gantt: $xeGantt
1699
+ })
1700
+ } else {
1701
+ handleOptions.sheetName = `${sheetName}`
1702
+ }
1703
+ }
1704
+ if (!handleOptions.sheetName) {
1705
+ handleOptions.sheetName = document.title || ''
1706
+ }
1707
+
1708
+ // 检查类型,如果为自定义导出,则不需要校验类型
1709
+ if (!handleOptions.exportMethod && !XEUtils.includes(XEUtils.keys(exportOpts._typeMaps), type)) {
1710
+ errLog('vxe.error.notType', [type])
1711
+ if (['xlsx', 'pdf'].includes(type)) {
1712
+ warnLog('vxe.error.reqPlugin', [4, 'plugin-export-xlsx'])
1713
+ }
1714
+ const params = { status: false, msg: 'type error' }
1715
+ return Promise.reject(params)
1716
+ }
1717
+
1718
+ if (!handleOptions.print) {
1719
+ if (beforeExportMethod) {
1720
+ const beRest = beforeExportMethod({ options: handleOptions, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1721
+ if (XEUtils.isBoolean(beRest)) {
1722
+ if (!beRest) {
1723
+ const params = { status: false, msg: 'before prevent' }
1724
+ return Promise.reject(params)
1725
+ }
1726
+ } else {
1727
+ warnLog('vxe.error.returnErr', ['beforeExportMethod', 'boolean', beRest])
1728
+ }
1729
+ }
1730
+ }
1731
+ if (!handleOptions.data) {
1732
+ handleOptions.data = []
1733
+ if (mode === 'selected') {
1734
+ if (['html', 'pdf'].indexOf(type) > -1 && treeConfig) {
1735
+ handleOptions.data = XEUtils.searchTree($xeTable.getTableData().fullData, (item) => $xeTable.findRowIndexOf(selectRecords, item) > -1, Object.assign({}, treeOpts, { data: '_row' }))
1736
+ } else {
1737
+ handleOptions.data = selectRecords
1738
+ }
1739
+ } else if (mode === 'all') {
1740
+ if (!$xeGGWrapper) {
1741
+ errLog('vxe.error.errProp', ['all', 'mode=current,selected'])
1742
+ }
1743
+
1744
+ if ($xeGGWrapper && !handleOptions.remote) {
1745
+ const gridReactData = $xeGGWrapper.reactData
1746
+ const { computeProxyOpts } = $xeGGWrapper.getComputeMaps()
1747
+ const proxyOpts = computeProxyOpts.value
1748
+ const { sortData } = gridReactData
1749
+ const { beforeQueryAll: oldBeforeQueryAll, afterQueryAll: oldAfterQueryAll, ajax = {} } = proxyOpts
1750
+ const resConfigs = proxyOpts.response || proxyOpts.props || {}
1751
+ const beforeQueryAllMethod = ajax.beforeQueryAll
1752
+ const queryAllMethod = ajax.queryAll
1753
+ const afterQueryAllMethod = ajax.afterQueryAll
1754
+ const queryAllSuccessMethod = ajax.queryAllSuccess
1755
+ const queryAllErrorMethod = ajax.queryAllError
1756
+
1757
+ if (!queryAllMethod) {
1758
+ errLog('vxe.error.notFunc', ['proxy-config.ajax.queryAll'])
1759
+ }
1760
+
1761
+ if (queryAllMethod) {
1762
+ const params = {
1763
+ $table: $xeTable,
1764
+ $grid: $xeGrid,
1765
+ $gantt: $xeGantt,
1766
+ sort: sortData.length ? sortData[0] : ({} as any),
1767
+ sorts: sortData as any[],
1768
+ filters: gridReactData.filterData,
1769
+ form: gridReactData.formData,
1770
+ options: handleOptions
1771
+ }
1772
+
1773
+ const handleQueryAll = () => {
1774
+ return Promise.resolve((oldBeforeQueryAll || queryAllMethod)(params))
1775
+ .then((rest) => {
1776
+ if (afterQueryAllMethod) {
1777
+ afterQueryAllMethod({ ...params, response: rest, status: 'success' })
1778
+ } else {
1779
+ const listProp = resConfigs.list
1780
+ let tdData: any[] = []
1781
+ if (listProp) {
1782
+ if (XEUtils.isFunction(listProp)) {
1783
+ tdData = listProp({ data: rest, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
1784
+ } else {
1785
+ tdData = XEUtils.isArray(rest) ? rest : XEUtils.get(rest, listProp)
1786
+ }
1787
+ } else {
1788
+ if (XEUtils.isArray(rest)) {
1789
+ tdData = rest
1790
+ }
1791
+ }
1792
+ handleOptions.data = tdData
1793
+ if (oldAfterQueryAll) {
1794
+ oldAfterQueryAll({ ...params, response: rest })
1795
+ }
1796
+ }
1797
+ if (queryAllSuccessMethod) {
1798
+ queryAllSuccessMethod({ ...params, response: rest })
1799
+ }
1800
+ return handleExport(handleOptions)
1801
+ })
1802
+ .catch((rest) => {
1803
+ if (afterQueryAllMethod) {
1804
+ afterQueryAllMethod({ ...params, response: rest, status: 'error' })
1805
+ }
1806
+ if (queryAllErrorMethod) {
1807
+ queryAllErrorMethod({ ...params, response: rest })
1808
+ }
1809
+ })
1810
+ }
1811
+
1812
+ if (beforeQueryAllMethod) {
1813
+ return Promise.resolve(beforeQueryAllMethod(params)).then((status) => {
1814
+ if (status !== false) {
1815
+ return handleQueryAll()
1816
+ }
1817
+ })
1818
+ }
1819
+ return handleQueryAll()
1820
+ }
1821
+ }
1822
+ }
1823
+ if (mode === 'current') {
1824
+ handleOptions.data = treeConfig ? afterTreeFullData : afterFullData
1825
+ }
1826
+ } else {
1827
+ handleOptions._isCustomData = true
1828
+ }
1829
+ return handleExport(handleOptions)
1830
+ },
1831
+ importByFile(file, options) {
1832
+ const opts = Object.assign({}, options)
1833
+ const { beforeImportMethod } = opts
1834
+ if (beforeImportMethod) {
1835
+ const biRest = beforeImportMethod({ options: opts, $table: $xeTable })
1836
+ if (XEUtils.isBoolean(biRest)) {
1837
+ if (!biRest) {
1838
+ const params = { status: false, mas: 'before prevent' }
1839
+ return Promise.reject(params)
1840
+ }
1841
+ } else {
1842
+ warnLog('vxe.error.returnErr', ['beforeImportMethod', 'boolean', biRest])
1843
+ }
1844
+ }
1845
+ return handleFileImport(file, opts)
1846
+ },
1847
+ importData(options) {
1848
+ const importOpts = computeImportOpts.value
1849
+ const opts = Object.assign(
1850
+ {
1851
+ types: XEUtils.keys(importOpts._typeMaps)
1852
+ // beforeImportMethod: null,
1853
+ // afterImportMethod: null
1854
+ },
1855
+ importOpts,
1856
+ options
1857
+ )
1858
+ const { beforeImportMethod, afterImportMethod } = opts
1859
+ if (beforeImportMethod) {
1860
+ const biRest = beforeImportMethod({ options: opts, $table: $xeTable })
1861
+ if (XEUtils.isBoolean(biRest)) {
1862
+ if (!biRest) {
1863
+ const params = { status: false, mas: 'before prevent' }
1864
+ return Promise.reject(params)
1865
+ }
1866
+ } else {
1867
+ warnLog('vxe.error.returnErr', ['beforeImportMethod', 'boolean', biRest])
1868
+ }
1869
+ }
1870
+ return VxeUI.readFile(opts)
1871
+ .catch((e) => {
1872
+ if (afterImportMethod) {
1873
+ afterImportMethod({ status: false, options: opts, $table: $xeTable })
1874
+ }
1875
+ return Promise.reject(e)
1876
+ })
1877
+ .then((params) => {
1878
+ const { file } = params
1879
+ return handleFileImport(file, opts)
1880
+ })
1881
+ },
1882
+ saveFile(options) {
1883
+ return VxeUI.saveFile(options)
1884
+ },
1885
+ readFile(options) {
1886
+ return VxeUI.readFile(options)
1887
+ },
1888
+ print(options) {
1889
+ const $xeGrid = $xeTable.xeGrid
1890
+ const $xeGantt = $xeTable.xeGantt
1891
+
1892
+ const printOpts = computePrintOpts.value
1893
+ const opts = Object.assign(
1894
+ {
1895
+ original: false
1896
+ // beforePrintMethod
1897
+ },
1898
+ printOpts,
1899
+ options,
1900
+ {
1901
+ type: 'html',
1902
+ download: false,
1903
+ remote: false,
1904
+ print: true
1905
+ }
1906
+ )
1907
+ const { sheetName } = opts
1908
+ let printTitle = ''
1909
+ if (sheetName) {
1910
+ if (XEUtils.isFunction(sheetName)) {
1911
+ printTitle = sheetName({
1912
+ options: opts,
1913
+ $table: $xeTable,
1914
+ $grid: $xeGrid,
1915
+ $gantt: $xeGantt
1916
+ })
1917
+ } else {
1918
+ printTitle = `${sheetName}`
1919
+ }
1920
+ }
1921
+ if (!printTitle) {
1922
+ printTitle = document.title || ''
1923
+ }
1924
+
1925
+ const beforePrintMethod = opts.beforePrintMethod
1926
+ const printMethod = opts.printMethod
1927
+ const tableHtml = opts.html || opts.content
1928
+ return new Promise((resolve, reject) => {
1929
+ if (VxeUI.print) {
1930
+ if (tableHtml) {
1931
+ resolve(
1932
+ VxeUI.print({
1933
+ title: printTitle,
1934
+ html: tableHtml,
1935
+ customStyle: opts.style,
1936
+ beforeMethod: beforePrintMethod
1937
+ ? ({ html }) => {
1938
+ return beforePrintMethod({
1939
+ html,
1940
+ content: html,
1941
+ options: opts,
1942
+ $table: $xeTable,
1943
+ $grid: $xeGrid,
1944
+ $gantt: $xeGantt
1945
+ })
1946
+ }
1947
+ : undefined,
1948
+ beforePrintMethod: beforePrintMethod
1949
+ ? ({ html }) => {
1950
+ return beforePrintMethod({
1951
+ html,
1952
+ content: html,
1953
+ options: opts,
1954
+ $table: $xeTable,
1955
+ $grid: $xeGrid,
1956
+ $gantt: $xeGantt
1957
+ })
1958
+ }
1959
+ : undefined,
1960
+ printMethod: printMethod
1961
+ ? ({ html }) => {
1962
+ return printMethod({
1963
+ html,
1964
+ content: html,
1965
+ options: opts,
1966
+ $table: $xeTable,
1967
+ $grid: $xeGrid,
1968
+ $gantt: $xeGantt
1969
+ })
1970
+ }
1971
+ : undefined
1972
+ })
1973
+ )
1974
+ } else {
1975
+ resolve(
1976
+ exportMethods.exportData(opts).then(({ content }: any) => {
1977
+ return VxeUI.print({
1978
+ title: printTitle,
1979
+ html: content,
1980
+ customStyle: opts.style,
1981
+ beforeMethod: beforePrintMethod
1982
+ ? ({ html }) => {
1983
+ return beforePrintMethod({
1984
+ html,
1985
+ content: html,
1986
+ options: opts,
1987
+ $table: $xeTable,
1988
+ $grid: $xeGrid,
1989
+ $gantt: $xeGantt
1990
+ })
1991
+ }
1992
+ : undefined,
1993
+ beforePrintMethod: beforePrintMethod
1994
+ ? ({ html }) => {
1995
+ return beforePrintMethod({
1996
+ html,
1997
+ content: html,
1998
+ options: opts,
1999
+ $table: $xeTable,
2000
+ $grid: $xeGrid,
2001
+ $gantt: $xeGantt
2002
+ })
2003
+ }
2004
+ : undefined,
2005
+ printMethod: printMethod
2006
+ ? ({ html }) => {
2007
+ return printMethod({
2008
+ html,
2009
+ content: html,
2010
+ options: opts,
2011
+ $table: $xeTable,
2012
+ $grid: $xeGrid,
2013
+ $gantt: $xeGantt
2014
+ })
2015
+ }
2016
+ : undefined
2017
+ })
2018
+ })
2019
+ )
2020
+ }
2021
+ } else {
2022
+ errLog('vxe.error.reqComp', ['vxe-print'])
2023
+ const e = { status: false, msg: 'print not exist' }
2024
+ reject(e)
2025
+ }
2026
+ })
2027
+ },
2028
+ getPrintHtml(options) {
2029
+ const printOpts = computePrintOpts.value
2030
+ const opts = Object.assign(
2031
+ {
2032
+ original: false
2033
+ // beforePrintMethod
2034
+ },
2035
+ printOpts,
2036
+ options,
2037
+ {
2038
+ type: 'html',
2039
+ download: false,
2040
+ remote: false,
2041
+ print: true
2042
+ }
2043
+ )
2044
+ return $xeTable.exportData(opts).then(({ content }) => {
2045
+ return {
2046
+ html: content
2047
+ }
2048
+ })
2049
+ },
2050
+ closeImport() {
2051
+ if (VxeUI.modal) {
2052
+ return VxeUI.modal.close('VXE_IMPORT_MODAL')
2053
+ }
2054
+ return Promise.resolve()
2055
+ },
2056
+ openImport(options) {
2057
+ const { treeConfig, importConfig } = props
2058
+ const { initStore, importStore, importParams } = reactData
2059
+ const importOpts = computeImportOpts.value
2060
+ const defOpts = Object.assign(
2061
+ {
2062
+ mode: 'insertTop',
2063
+ message: true,
2064
+ types: XEUtils.keys(importOpts._typeMaps),
2065
+ modes: ['insertTop', 'covering']
2066
+ },
2067
+ importOpts,
2068
+ options
2069
+ )
2070
+ const types = defOpts.types || []
2071
+ const modes = defOpts.modes || []
2072
+ const isTree = !!treeConfig
2073
+ if (isTree) {
2074
+ if (defOpts.message) {
2075
+ if (VxeUI.modal) {
2076
+ VxeUI.modal.message({ content: getI18n('vxe.error.treeNotImp'), status: 'error' })
2077
+ }
2078
+ }
2079
+ return
2080
+ }
2081
+ if (!hasEnableConf(importConfig, importOpts)) {
2082
+ errLog('vxe.error.reqProp', ['import-config'])
2083
+ }
2084
+ // 处理类型
2085
+ const typeList = types.map((value) => {
2086
+ return {
2087
+ value,
2088
+ label: getI18n(`vxe.export.types.${value}`)
2089
+ }
2090
+ })
2091
+ const modeList = modes.map((item: any) => {
2092
+ if (item && item.value) {
2093
+ return {
2094
+ value: item.value,
2095
+ label: item.label || item.value
2096
+ }
2097
+ }
2098
+ return {
2099
+ value: item,
2100
+ label: getI18n(`vxe.import.modes.${item}`)
2101
+ }
2102
+ })
2103
+ Object.assign(importStore, {
2104
+ file: null,
2105
+ type: '',
2106
+ filename: '',
2107
+ modeList,
2108
+ typeList,
2109
+ visible: true
2110
+ })
2111
+ Object.assign(importParams, defOpts)
2112
+ if (!modeList.some((item) => item.value === importParams.mode)) {
2113
+ importParams.mode = modeList[0].value
2114
+ }
2115
+ initStore.import = true
2116
+ },
2117
+ closeExport: handleCloseExport,
2118
+ openExport(options) {
2119
+ const { exportConfig } = props
2120
+ const exportOpts = computeExportOpts.value
2121
+ const defOpts = Object.assign(
2122
+ {
2123
+ message: true,
2124
+ types: XEUtils.keys(exportOpts._typeMaps)
2125
+ },
2126
+ exportOpts,
2127
+ options
2128
+ )
2129
+ if (!hasEnableConf(exportConfig, exportOpts)) {
2130
+ errLog('vxe.error.reqProp', ['export-config'])
2131
+ }
2132
+ return handleExportAndPrint(defOpts)
2133
+ },
2134
+ closePrint: handleCloseExport,
2135
+ openPrint(options) {
2136
+ const { printConfig } = props
2137
+ const printOpts = computePrintOpts.value
2138
+ const defOpts = Object.assign(
2139
+ {
2140
+ message: true
2141
+ },
2142
+ printOpts,
2143
+ options
2144
+ )
2145
+ if (!hasEnableConf(printConfig, printOpts)) {
2146
+ errLog('vxe.error.reqProp', ['print-config'])
2147
+ }
2148
+ return handleExportAndPrint(defOpts, true)
2149
+ }
2150
+ }
2151
+
2152
+ return exportMethods
2153
+ },
2154
+ setupGrid($xeGrid) {
2155
+ return $xeGrid.extendTableMethods(tableExportMethodKeys)
2156
+ },
2157
+ setupGantt($xeGantt) {
2158
+ return $xeGantt.extendTableMethods(tableExportMethodKeys)
2159
+ }
2160
+ })