mixin.ts 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682
  1. import XEUtils from 'xe-utils'
  2. import { VxeUI } from '../../../ui'
  3. import { isColumnInfo, getCellValue, createHandleGetRowId } from '../../src/util'
  4. import { parseFile, formatText, eqEmptyValue } from '../../../ui/src/utils'
  5. import { hasClass } from '../../../ui/src/dom'
  6. import { createHtmlPage, getExportBlobByContent } from './util'
  7. import { warnLog, errLog } from '../../../ui/src/log'
  8. import type { VxeTablePropTypes, VxeTableDefines, TableReactData, VxeTablePrivateMethods, TableInternalData, GridReactData, VxeColumnPropTypes, VxeTableConstructor } from '../../../../types'
  9. const { getI18n, renderer } = VxeUI
  10. let htmlCellElem: any
  11. const csvBOM = '\ufeff'
  12. const enterSymbol = '\r\n'
  13. function hasTreeChildren ($xeTable: VxeTableConstructor, row: any) {
  14. const treeOpts = $xeTable.computeTreeOpts
  15. const childrenField = treeOpts.children || treeOpts.childrenField
  16. return row[childrenField] && row[childrenField].length
  17. }
  18. function getSeq ($xeTable: VxeTableConstructor, cellValue: any, row: any, $rowIndex: number, column: VxeTableDefines.ColumnInfo, $columnIndex: number) {
  19. const seqOpts = $xeTable.computeSeqOpts
  20. const seqMethod = seqOpts.seqMethod || (column as any).seqMethod
  21. if (seqMethod) {
  22. return seqMethod({
  23. $table: $xeTable,
  24. row,
  25. rowIndex: $xeTable.getRowIndex(row),
  26. $rowIndex,
  27. column,
  28. columnIndex: $xeTable.getColumnIndex(column),
  29. $columnIndex
  30. })
  31. }
  32. return cellValue
  33. }
  34. function defaultFilterExportColumn (column: VxeTableDefines.ColumnInfo) {
  35. return !!column.field || ['seq', 'checkbox', 'radio'].indexOf(column.type || '') === -1
  36. }
  37. function toTableBorder (border: VxeTablePropTypes.Border | undefined) {
  38. if (border === true) {
  39. return 'full'
  40. }
  41. if (border) {
  42. return border
  43. }
  44. return 'default'
  45. }
  46. function toBooleanValue (cellValue: any) {
  47. return XEUtils.isBoolean(cellValue) ? (cellValue ? 'TRUE' : 'FALSE') : cellValue
  48. }
  49. const toStringValue = (cellValue: any) => {
  50. return eqEmptyValue(cellValue) ? '' : `${cellValue}`
  51. }
  52. function getBodyLabelData ($xeTable: VxeTableConstructor, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) {
  53. const props = $xeTable
  54. const { isAllExpand, mode } = opts
  55. const { treeConfig } = props
  56. const radioOpts = $xeTable.computeRadioOpts
  57. const checkboxOpts = $xeTable.computeCheckboxOpts
  58. const treeOpts = $xeTable.computeTreeOpts
  59. const columnOpts = $xeTable.computeColumnOpts
  60. if (!htmlCellElem) {
  61. htmlCellElem = document.createElement('div')
  62. }
  63. if (treeConfig) {
  64. const childrenField = treeOpts.children || treeOpts.childrenField
  65. // 如果是树表格只允许导出数据源
  66. const rest: any[] = []
  67. const expandMaps: Record<string, boolean> = {}
  68. const useMaps: Record<string, boolean> = {}
  69. const { handleGetRowId } = createHandleGetRowId($xeTable)
  70. XEUtils.eachTree(datas, (item, $rowIndex, items, path, parent, nodes) => {
  71. const row = item._row || item
  72. const rowid = handleGetRowId(row)
  73. if (useMaps[rowid]) {
  74. return
  75. }
  76. const parentRow = parent && parent._row ? parent._row : parent
  77. const pRowid = parentRow ? handleGetRowId(parentRow) : ''
  78. if ((isAllExpand || !parentRow || (expandMaps[pRowid] && $xeTable.isTreeExpandByRow(parentRow)))) {
  79. const hasRowChild = hasTreeChildren($xeTable, row)
  80. const item: any = {
  81. _row: row,
  82. _level: nodes.length - 1,
  83. _hasChild: hasRowChild,
  84. _expand: hasRowChild && $xeTable.isTreeExpandByRow(row)
  85. }
  86. columns.forEach((column, $columnIndex) => {
  87. let cellValue: string | number | boolean | null = ''
  88. const renderOpts = column.editRender || column.cellRender
  89. let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
  90. if (!bodyExportMethod && renderOpts && renderOpts.name) {
  91. const compConf = renderer.get(renderOpts.name)
  92. if (compConf) {
  93. bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
  94. }
  95. }
  96. if (!bodyExportMethod) {
  97. bodyExportMethod = columnOpts.exportMethod
  98. }
  99. if (bodyExportMethod) {
  100. cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
  101. } else {
  102. switch (column.type) {
  103. case 'seq': {
  104. const seqVal = path.map((num, i) => i % 2 === 0 ? (Number(num) + 1) : '.').join('')
  105. cellValue = mode === 'all' ? seqVal : getSeq($xeTable, seqVal, row, $rowIndex, column, $columnIndex)
  106. break
  107. }
  108. case 'checkbox':
  109. cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
  110. item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
  111. item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
  112. break
  113. case 'radio':
  114. cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
  115. item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
  116. item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
  117. break
  118. default:
  119. if (opts.original) {
  120. cellValue = getCellValue(row, column)
  121. } else {
  122. cellValue = $xeTable.getCellLabel(row, column)
  123. if (column.type === 'html') {
  124. htmlCellElem.innerHTML = cellValue
  125. cellValue = htmlCellElem.innerText.trim()
  126. } else {
  127. const cell = $xeTable.getCellElement(row, column)
  128. if (cell && !hasClass(cell, 'is--progress')) {
  129. cellValue = cell.innerText.trim()
  130. }
  131. }
  132. }
  133. }
  134. }
  135. item[column.id] = toStringValue(cellValue)
  136. })
  137. useMaps[rowid] = true
  138. if (pRowid) {
  139. expandMaps[pRowid] = true
  140. }
  141. rest.push(Object.assign(item, row))
  142. }
  143. }, { children: childrenField })
  144. return rest
  145. }
  146. return datas.map((row, $rowIndex) => {
  147. const item: any = {
  148. _row: row
  149. }
  150. columns.forEach((column, $columnIndex) => {
  151. let cellValue: string | number | boolean | null = ''
  152. const renderOpts = column.editRender || column.cellRender
  153. let bodyExportMethod: VxeColumnPropTypes.ExportMethod | undefined = column.exportMethod || columnOpts.exportMethod
  154. if (!bodyExportMethod && renderOpts && renderOpts.name) {
  155. const compConf = renderer.get(renderOpts.name)
  156. if (compConf) {
  157. bodyExportMethod = compConf.tableExportMethod || compConf.exportMethod
  158. }
  159. }
  160. if (bodyExportMethod) {
  161. cellValue = bodyExportMethod({ $table: $xeTable, row, column, options: opts })
  162. } else {
  163. switch (column.type) {
  164. case 'seq': {
  165. const seqValue = $rowIndex + 1
  166. cellValue = mode === 'all' ? seqValue : getSeq($xeTable, seqValue, row, $rowIndex, column, $columnIndex)
  167. break
  168. }
  169. case 'checkbox':
  170. cellValue = toBooleanValue($xeTable.isCheckedByCheckboxRow(row))
  171. item._checkboxLabel = checkboxOpts.labelField ? XEUtils.get(row, checkboxOpts.labelField) : ''
  172. item._checkboxDisabled = checkboxOpts.checkMethod && !checkboxOpts.checkMethod({ $table: $xeTable, row })
  173. break
  174. case 'radio':
  175. cellValue = toBooleanValue($xeTable.isCheckedByRadioRow(row))
  176. item._radioLabel = radioOpts.labelField ? XEUtils.get(row, radioOpts.labelField) : ''
  177. item._radioDisabled = radioOpts.checkMethod && !radioOpts.checkMethod({ $table: $xeTable, row })
  178. break
  179. default:
  180. if (opts.original) {
  181. cellValue = getCellValue(row, column)
  182. } else {
  183. cellValue = $xeTable.getCellLabel(row, column)
  184. if (column.type === 'html') {
  185. htmlCellElem.innerHTML = cellValue
  186. cellValue = htmlCellElem.innerText.trim()
  187. } else {
  188. const cell = $xeTable.getCellElement(row, column)
  189. if (cell && !hasClass(cell, 'is--progress')) {
  190. cellValue = cell.innerText.trim()
  191. }
  192. }
  193. }
  194. }
  195. }
  196. item[column.id] = toStringValue(cellValue)
  197. })
  198. return item
  199. })
  200. }
  201. function getExportData ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions) {
  202. const $xeGrid = $xeTable.$xeGrid
  203. const $xeGantt = $xeTable.$xeGantt
  204. const { columns, dataFilterMethod } = opts
  205. let datas = opts.data
  206. if (dataFilterMethod) {
  207. datas = datas.filter((row, index) => dataFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, row, $rowIndex: index }))
  208. }
  209. return getBodyLabelData($xeTable, opts, columns, datas)
  210. }
  211. function getBooleanValue (cellValue: any) {
  212. return cellValue === 'TRUE' || cellValue === 'true' || cellValue === true
  213. }
  214. function getHeaderTitle ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, column: VxeTableDefines.ColumnInfo) {
  215. const columnOpts = $xeTable.computeColumnOpts
  216. const headExportMethod = column.headerExportMethod || columnOpts.headerExportMethod
  217. return headExportMethod ? headExportMethod({ column, options: opts, $table: $xeTable }) : ((opts.isTitle ? column.getTitle() : column.field) || '')
  218. }
  219. function getFooterCellValue ($xeTable: any, opts: VxeTablePropTypes.ExportHandleOptions, row: any, column: VxeTableDefines.ColumnInfo) {
  220. const columnOpts = $xeTable.computeColumnOpts
  221. const renderOpts = column.editRender || column.cellRender
  222. let footLabelMethod: VxeColumnPropTypes.FooterExportMethod | undefined = column.footerExportMethod
  223. if (!footLabelMethod && renderOpts && renderOpts.name) {
  224. const compConf = renderer.get(renderOpts.name)
  225. if (compConf) {
  226. footLabelMethod = compConf.tableFooterExportMethod || compConf.footerExportMethod || (compConf as any).footerCellExportMethod
  227. }
  228. }
  229. if (!footLabelMethod) {
  230. footLabelMethod = columnOpts.footerExportMethod
  231. }
  232. const _columnIndex = $xeTable.getVTColumnIndex(column)
  233. if (footLabelMethod) {
  234. return footLabelMethod({ $table: $xeTable, items: row, itemIndex: _columnIndex, row, _columnIndex, column, options: opts })
  235. }
  236. // 兼容老模式
  237. if (XEUtils.isArray(row)) {
  238. return XEUtils.toValueString(row[_columnIndex])
  239. }
  240. return XEUtils.get(row, column.field)
  241. }
  242. function getFooterData ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, footerTableData: any[]) {
  243. const $xeGrid = $xeTable.$xeGrid
  244. const $xeGantt = $xeTable.$xeGantt
  245. const { footerFilterMethod } = opts
  246. return footerFilterMethod ? footerTableData.filter((items: any, index: any) => footerFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, items, $rowIndex: index })) : footerTableData
  247. }
  248. function getCsvCellTypeLabel (column: any, cellValue: any) {
  249. if (cellValue) {
  250. if (column.type === 'seq') {
  251. return `\t${cellValue}`
  252. }
  253. switch (column.cellType) {
  254. case 'string':
  255. if (!isNaN(cellValue)) {
  256. return `\t${cellValue}`
  257. }
  258. break
  259. case 'number':
  260. break
  261. default:
  262. if (cellValue.length >= 12 && !isNaN(cellValue)) {
  263. return `\t${cellValue}`
  264. }
  265. break
  266. }
  267. }
  268. return cellValue
  269. }
  270. function toTxtCellLabel (val: any) {
  271. if (/[",\s\n]/.test(val)) {
  272. return `"${val.replace(/"/g, '""')}"`
  273. }
  274. return val
  275. }
  276. function toCsv ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) {
  277. const reactData = $xeTable as unknown as TableReactData
  278. let content = csvBOM
  279. if (opts.isHeader) {
  280. content += columns.map(column => toTxtCellLabel(getHeaderTitle($xeTable, opts, column))).join(',') + enterSymbol
  281. }
  282. datas.forEach(row => {
  283. content += columns.map(column => toTxtCellLabel(getCsvCellTypeLabel(column, row[column.id]))).join(',') + enterSymbol
  284. })
  285. if (opts.isFooter) {
  286. const { footerTableData } = reactData
  287. const footers = getFooterData($xeTable, opts, footerTableData)
  288. footers.forEach((row) => {
  289. content += columns.map(column => toTxtCellLabel(getFooterCellValue($xeTable, opts, row, column))).join(',') + enterSymbol
  290. })
  291. }
  292. return content
  293. }
  294. function toTxt ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) {
  295. const reactData = $xeTable as unknown as TableReactData
  296. let content = ''
  297. if (opts.isHeader) {
  298. content += columns.map(column => toTxtCellLabel(getHeaderTitle($xeTable, opts, column))).join('\t') + enterSymbol
  299. }
  300. datas.forEach(row => {
  301. content += columns.map(column => toTxtCellLabel(row[column.id])).join('\t') + enterSymbol
  302. })
  303. if (opts.isFooter) {
  304. const { footerTableData } = reactData
  305. const footers = getFooterData($xeTable, opts, footerTableData)
  306. footers.forEach((row) => {
  307. content += columns.map(column => toTxtCellLabel(getFooterCellValue($xeTable, opts, row, column))).join('\t') + enterSymbol
  308. })
  309. }
  310. return content
  311. }
  312. function hasEllipsis ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, column: VxeTableDefines.ColumnInfo, property: 'showOverflow' | 'showHeaderOverflow', allColumnOverflow: VxeTablePropTypes.ShowOverflow | undefined) {
  313. const reactData = $xeTable as unknown as TableReactData
  314. const columnOverflow = column[property]
  315. const headOverflow = XEUtils.isUndefined(columnOverflow) || XEUtils.isNull(columnOverflow) ? allColumnOverflow : columnOverflow
  316. const showEllipsis = headOverflow === 'ellipsis'
  317. const showTitle = headOverflow === 'title'
  318. const showTooltip = headOverflow === true || headOverflow === 'tooltip'
  319. let isEllipsis = showTitle || showTooltip || showEllipsis
  320. // 虚拟滚动不支持动态高度
  321. const { scrollXLoad, scrollYLoad } = reactData
  322. if ((scrollXLoad || scrollYLoad) && !isEllipsis) {
  323. isEllipsis = true
  324. }
  325. return isEllipsis
  326. }
  327. function toHtml ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) {
  328. const props = $xeTable
  329. const reactData = $xeTable as unknown as TableReactData
  330. const internalData = $xeTable as unknown as TableInternalData
  331. const { id, border, treeConfig, headerAlign: allHeaderAlign, align: allAlign, footerAlign: allFooterAlign, showOverflow: allColumnOverflow, showHeaderOverflow: allColumnHeaderOverflow } = props
  332. const { isAllSelected, isIndeterminate } = reactData
  333. const { mergeBodyCellMaps } = internalData
  334. const treeOpts = $xeTable.computeTreeOpts
  335. const { print: isPrint, isHeader, isFooter, isColgroup, isMerge, colgroups, original } = opts
  336. const allCls = 'check-all'
  337. const clss = [
  338. 'vxe-table',
  339. `border--${toTableBorder(border)}`,
  340. isPrint ? 'is--print' : '',
  341. isHeader ? 'is--header' : ''
  342. ].filter(cls => cls)
  343. const tables = [
  344. `<table class="${clss.join(' ')}" border="0" cellspacing="0" cellpadding="0">`,
  345. `<colgroup>${columns.map(column => `<col style="width:${column.renderWidth}px">`).join('')}</colgroup>`
  346. ]
  347. if (isHeader) {
  348. tables.push('<thead>')
  349. if (isColgroup && !original) {
  350. colgroups.forEach((cols: any[]) => {
  351. tables.push(
  352. `<tr>${cols.map(column => {
  353. const headAlign = column.headerAlign || column.align || allHeaderAlign || allAlign
  354. const classNames = hasEllipsis($xeTable, column, 'showHeaderOverflow', allColumnHeaderOverflow) ? ['col--ellipsis'] : []
  355. const cellTitle = getHeaderTitle($xeTable, opts, column)
  356. let childWidth = 0
  357. let countChild = 0
  358. XEUtils.eachTree([column], item => {
  359. if (!item.childNodes || !column.childNodes.length) {
  360. countChild++
  361. }
  362. childWidth += item.renderWidth
  363. }, { children: 'childNodes' })
  364. const cellWidth = childWidth - countChild
  365. if (headAlign) {
  366. classNames.push(`col--${headAlign}`)
  367. }
  368. if (column.type === 'checkbox') {
  369. return `<th class="${classNames.join(' ')}" colspan="${column._colSpan}" rowspan="${column._rowSpan}"><div ${isPrint ? '' : `style="width: ${cellWidth}px"`}><input type="checkbox" class="${allCls}" ${isAllSelected ? 'checked' : ''}><span>${cellTitle}</span></div></th>`
  370. }
  371. return `<th class="${classNames.join(' ')}" colspan="${column._colSpan}" rowspan="${column._rowSpan}" title="${cellTitle}"><div ${isPrint ? '' : `style="width: ${cellWidth}px"`}><span>${formatText(cellTitle, true)}</span></div></th>`
  372. }).join('')}</tr>`
  373. )
  374. })
  375. } else {
  376. tables.push(
  377. `<tr>${columns.map(column => {
  378. const headAlign = column.headerAlign || column.align || allHeaderAlign || allAlign
  379. const classNames = hasEllipsis($xeTable, column, 'showHeaderOverflow', allColumnHeaderOverflow) ? ['col--ellipsis'] : []
  380. const cellTitle = getHeaderTitle($xeTable, opts, column)
  381. if (headAlign) {
  382. classNames.push(`col--${headAlign}`)
  383. }
  384. if (column.type === 'checkbox') {
  385. return `<th class="${classNames.join(' ')}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><input type="checkbox" class="${allCls}" ${isAllSelected ? 'checked' : ''}><span>${cellTitle}</span></div></th>`
  386. }
  387. return `<th class="${classNames.join(' ')}" title="${cellTitle}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><span>${formatText(cellTitle, true)}</span></div></th>`
  388. }).join('')}</tr>`
  389. )
  390. }
  391. tables.push('</thead>')
  392. }
  393. if (datas.length) {
  394. tables.push('<tbody>')
  395. if (treeConfig) {
  396. datas.forEach(item => {
  397. tables.push(
  398. '<tr>' + columns.map(column => {
  399. const cellAlign = column.align || allAlign
  400. const classNames = hasEllipsis($xeTable, column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
  401. const cellValue = item[column.id]
  402. if (cellAlign) {
  403. classNames.push(`col--${cellAlign}`)
  404. }
  405. if (column.treeNode) {
  406. let treeIcon = ''
  407. if (item._hasChild) {
  408. treeIcon = `<i class="${item._expand ? 'vxe-table--tree-fold-icon' : 'vxe-table--tree-unfold-icon'}"></i>`
  409. }
  410. classNames.push('vxe-table--tree-node')
  411. if (column.type === 'radio') {
  412. return `<td class="${classNames.join(' ')}" title="${cellValue}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><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>`
  413. } else if (column.type === 'checkbox') {
  414. return `<td class="${classNames.join(' ')}" title="${cellValue}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><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>`
  415. }
  416. return `<td class="${classNames.join(' ')}" title="${cellValue}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><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>`
  417. }
  418. if (column.type === 'radio') {
  419. return `<td class="${classNames.join(' ')}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></td>`
  420. } else if (column.type === 'checkbox') {
  421. return `<td class="${classNames.join(' ')}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></td>`
  422. }
  423. return `<td class="${classNames.join(' ')}" title="${cellValue}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}>${formatText(cellValue, true)}</div></td>`
  424. }).join('') + '</tr>'
  425. )
  426. })
  427. } else {
  428. datas.forEach(item => {
  429. tables.push(
  430. '<tr>' + columns.map(column => {
  431. const colid = column.id
  432. const cellAlign = column.align || allAlign
  433. const classNames = hasEllipsis($xeTable, column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
  434. const cellValue = item[colid]
  435. let rowSpan = 1
  436. let colSpan = 1
  437. if (isMerge) {
  438. const _rowIndex = $xeTable.getVTRowIndex(item._row)
  439. const _columnIndex = $xeTable.getVTColumnIndex(column)
  440. const spanRest = mergeBodyCellMaps[`${_rowIndex}:${_columnIndex}`]
  441. if (spanRest) {
  442. const { rowspan, colspan } = spanRest
  443. if (!rowspan || !colspan) {
  444. return ''
  445. }
  446. if (rowspan > 1) {
  447. rowSpan = rowspan
  448. }
  449. if (colspan > 1) {
  450. colSpan = colspan
  451. }
  452. }
  453. }
  454. if (cellAlign) {
  455. classNames.push(`col--${cellAlign}`)
  456. }
  457. if (column.type === 'radio') {
  458. return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><input type="radio" name="radio_${id}" ${item._radioDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._radioLabel}</span></div></td>`
  459. } else if (column.type === 'checkbox') {
  460. return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}><input type="checkbox" ${item._checkboxDisabled ? 'disabled ' : ''}${getBooleanValue(cellValue) ? 'checked' : ''}><span>${item._checkboxLabel}</span></div></td>`
  461. }
  462. return `<td class="${classNames.join(' ')}" rowspan="${rowSpan}" colspan="${colSpan}" title="${cellValue}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}>${formatText(cellValue, true)}</div></td>`
  463. }).join('') + '</tr>'
  464. )
  465. })
  466. }
  467. tables.push('</tbody>')
  468. }
  469. if (isFooter) {
  470. const { footerTableData } = reactData
  471. const footers = getFooterData($xeTable, opts, footerTableData)
  472. if (footers.length) {
  473. tables.push('<tfoot>')
  474. footers.forEach((row: any) => {
  475. tables.push(
  476. `<tr>${columns.map(column => {
  477. const footAlign = column.footerAlign || column.align || allFooterAlign || allAlign
  478. const classNames = hasEllipsis($xeTable, column, 'showOverflow', allColumnOverflow) ? ['col--ellipsis'] : []
  479. const cellValue = getFooterCellValue($xeTable, opts, row, column)
  480. if (footAlign) {
  481. classNames.push(`col--${footAlign}`)
  482. }
  483. return `<td class="${classNames.join(' ')}" title="${cellValue}"><div ${isPrint ? '' : `style="width: ${column.renderWidth}px"`}>${formatText(cellValue, true)}</div></td>`
  484. }).join('')}</tr>`
  485. )
  486. })
  487. tables.push('</tfoot>')
  488. }
  489. }
  490. // 是否半选状态
  491. const script = !isAllSelected && isIndeterminate ? `<script>(function(){var a=document.querySelector(".${allCls}");if(a){a.indeterminate=true}})()</script>` : ''
  492. tables.push('</table>', script)
  493. return isPrint ? tables.join('') : createHtmlPage(opts, tables.join(''))
  494. }
  495. function toXML ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: any, columns: any[], datas: any[]) {
  496. const reactData = $xeTable as unknown as TableReactData
  497. let xml = [
  498. '<?xml version="1.0"?>',
  499. '<?mso-application progid="Excel.Sheet"?>',
  500. '<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">',
  501. '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">',
  502. '<Version>16.00</Version>',
  503. '</DocumentProperties>',
  504. '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">',
  505. '<WindowHeight>7920</WindowHeight>',
  506. '<WindowWidth>21570</WindowWidth>',
  507. '<WindowTopX>32767</WindowTopX>',
  508. '<WindowTopY>32767</WindowTopY>',
  509. '<ProtectStructure>False</ProtectStructure>',
  510. '<ProtectWindows>False</ProtectWindows>',
  511. '</ExcelWorkbook>',
  512. `<Worksheet ss:Name="${opts.sheetName}">`,
  513. '<Table>',
  514. columns.map(column => `<Column ss:Width="${column.renderWidth}"/>`).join('')
  515. ].join('')
  516. if (opts.isHeader) {
  517. xml += `<Row>${columns.map(column => `<Cell><Data ss:Type="String">${getHeaderTitle($xeTable, opts, column)}</Data></Cell>`).join('')}</Row>`
  518. }
  519. datas.forEach(row => {
  520. xml += '<Row>' + columns.map(column => `<Cell><Data ss:Type="String">${row[column.id]}</Data></Cell>`).join('') + '</Row>'
  521. })
  522. if (opts.isFooter) {
  523. const { footerTableData } = reactData
  524. const footers = getFooterData($xeTable, opts, footerTableData)
  525. footers.forEach((row: any) => {
  526. xml += `<Row>${columns.map(column => `<Cell><Data ss:Type="String">${getFooterCellValue($xeTable, opts, row, column)}</Data></Cell>`).join('')}</Row>`
  527. })
  528. }
  529. return `${xml}</Table></Worksheet></Workbook>`
  530. }
  531. function getContent ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions, columns: VxeTableDefines.ColumnInfo[], datas: any[]) {
  532. if (columns.length) {
  533. switch (opts.type) {
  534. case 'csv':
  535. return toCsv($xeTable, opts, columns, datas)
  536. case 'txt':
  537. return toTxt($xeTable, opts, columns, datas)
  538. case 'html':
  539. return toHtml($xeTable, opts, columns, datas)
  540. case 'xml':
  541. return toXML($xeTable, opts, columns, datas)
  542. }
  543. }
  544. return ''
  545. }
  546. function downloadFile ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: any, content: any) {
  547. const { filename, type, download } = opts
  548. if (!download) {
  549. const blob = getExportBlobByContent(content, opts)
  550. return Promise.resolve({ type, content, blob })
  551. }
  552. if (VxeUI.saveFile) {
  553. VxeUI.saveFile({ filename, type, content }).then(() => {
  554. if (opts.message !== false) {
  555. if (VxeUI.modal) {
  556. VxeUI.modal.message({ content: getI18n('vxe.table.expSuccess'), status: 'success' })
  557. }
  558. }
  559. })
  560. }
  561. }
  562. function clearColumnConvert (columns: any) {
  563. XEUtils.eachTree(columns, column => {
  564. delete column._level
  565. delete column._colSpan
  566. delete column._rowSpan
  567. delete column._children
  568. delete column.childNodes
  569. }, { children: 'children' })
  570. }
  571. function handleExport ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, opts: VxeTablePropTypes.ExportHandleOptions) {
  572. const $xeGrid = $xeTable.$xeGrid
  573. const $xeGantt = $xeTable.$xeGantt
  574. const { remote, columns, colgroups, exportMethod, afterExportMethod } = opts
  575. return new Promise(resolve => {
  576. if (remote) {
  577. const params = { options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt }
  578. resolve(exportMethod ? exportMethod(params) : params)
  579. } else {
  580. const datas = getExportData($xeTable, opts)
  581. resolve(
  582. $xeTable.preventEvent(null, 'event.export', { options: opts, columns, colgroups, datas }, () => {
  583. return downloadFile($xeTable, opts, getContent($xeTable, opts, columns, datas))
  584. })
  585. )
  586. }
  587. }).then((params) => {
  588. clearColumnConvert(columns)
  589. if (!opts.print) {
  590. if (afterExportMethod) {
  591. afterExportMethod({ status: true, options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
  592. }
  593. }
  594. return Object.assign({ status: true }, params)
  595. }).catch(() => {
  596. clearColumnConvert(columns)
  597. if (!opts.print) {
  598. if (afterExportMethod) {
  599. afterExportMethod({ status: false, options: opts, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
  600. }
  601. }
  602. const params = { status: false }
  603. return Promise.reject(params)
  604. })
  605. }
  606. function getElementsByTagName (elem: any, qualifiedName: any) {
  607. return elem.getElementsByTagName(qualifiedName) as HTMLElement[]
  608. }
  609. function getTxtCellKey (now: any) {
  610. return `#${now}@${XEUtils.uniqueId()}`
  611. }
  612. function replaceTxtCell (cell: any, vMaps: any) {
  613. return cell.replace(/#\d+@\d+/g, (key: any) => XEUtils.hasOwnProp(vMaps, key) ? vMaps[key] : key)
  614. }
  615. function getTxtCellValue (val: any, vMaps: any) {
  616. const rest = replaceTxtCell(val, vMaps)
  617. return rest.replace(/^"+$/g, (qVal: any) => '"'.repeat(Math.ceil(qVal.length / 2)))
  618. }
  619. function toExportField (tableConf: {
  620. fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
  621. titleMaps: Record<string, VxeTableDefines.ColumnInfo>
  622. }, field: string) {
  623. const { fieldMaps, titleMaps } = tableConf
  624. // title 转 field
  625. if (!fieldMaps[field]) {
  626. const teCol = titleMaps[field]
  627. if (teCol && teCol.field) {
  628. field = teCol.field
  629. }
  630. }
  631. return field
  632. }
  633. function parseCsvAndTxt (tableConf: {
  634. fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
  635. titleMaps: Record<string, VxeTableDefines.ColumnInfo>
  636. }, content: string, cellSeparator: string) {
  637. const list = content.split(enterSymbol)
  638. const rows: any[] = []
  639. let fields: string[] = []
  640. if (list.length) {
  641. const vMaps: any = {}
  642. const now = Date.now()
  643. list.forEach((rVal) => {
  644. if (rVal) {
  645. const item: any = {}
  646. rVal = rVal.replace(/("")|(\n)/g, (text: string, dVal: string) => {
  647. const key = getTxtCellKey(now)
  648. vMaps[key] = dVal ? '"' : '\n'
  649. return key
  650. }).replace(/"(.*?)"/g, (text: string, cVal: string) => {
  651. const key = getTxtCellKey(now)
  652. vMaps[key] = replaceTxtCell(cVal, vMaps)
  653. return key
  654. })
  655. const cells: string[] = rVal.split(cellSeparator)
  656. if (!fields.length) {
  657. fields = cells.map((val: string) => toExportField(tableConf, getTxtCellValue(val.trim(), vMaps)))
  658. } else {
  659. cells.forEach((val, colIndex) => {
  660. if (colIndex < fields.length) {
  661. item[fields[colIndex]] = getTxtCellValue(val.trim(), vMaps)
  662. }
  663. })
  664. rows.push(item)
  665. }
  666. }
  667. })
  668. }
  669. return { fields, rows }
  670. }
  671. function parseCsv (tableConf: {
  672. fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
  673. titleMaps: Record<string, VxeTableDefines.ColumnInfo>
  674. }, content: string) {
  675. return parseCsvAndTxt(tableConf, content, ',')
  676. }
  677. function parseTxt (tableConf: {
  678. fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
  679. titleMaps: Record<string, VxeTableDefines.ColumnInfo>
  680. }, content: string) {
  681. return parseCsvAndTxt(tableConf, content, '\t')
  682. }
  683. function parseHTML (tableConf: {
  684. fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
  685. titleMaps: Record<string, VxeTableDefines.ColumnInfo>
  686. }, content: string) {
  687. const domParser = new DOMParser()
  688. const xmlDoc = domParser.parseFromString(content, 'text/html')
  689. const bodyNodes = getElementsByTagName(xmlDoc, 'body')
  690. const rows: any[] = []
  691. const fields: string[] = []
  692. if (bodyNodes.length) {
  693. const tableNodes = getElementsByTagName(bodyNodes[0], 'table')
  694. if (tableNodes.length) {
  695. const theadNodes = getElementsByTagName(tableNodes[0], 'thead')
  696. if (theadNodes.length) {
  697. XEUtils.arrayEach(getElementsByTagName(theadNodes[0], 'tr'), rowNode => {
  698. XEUtils.arrayEach(getElementsByTagName(rowNode, 'th'), cellNode => {
  699. fields.push(toExportField(tableConf, cellNode.textContent || ''))
  700. })
  701. })
  702. const tbodyNodes = getElementsByTagName(tableNodes[0], 'tbody')
  703. if (tbodyNodes.length) {
  704. XEUtils.arrayEach(getElementsByTagName(tbodyNodes[0], 'tr'), rowNode => {
  705. const item: any = {}
  706. XEUtils.arrayEach(getElementsByTagName(rowNode, 'td'), (cellNode, colIndex) => {
  707. if (fields[colIndex]) {
  708. item[fields[colIndex]] = cellNode.textContent || ''
  709. }
  710. })
  711. rows.push(item)
  712. })
  713. }
  714. }
  715. }
  716. }
  717. return { fields, rows }
  718. }
  719. function parseXML (tableConf: {
  720. fieldMaps: Record<string, VxeTableDefines.ColumnInfo>
  721. titleMaps: Record<string, VxeTableDefines.ColumnInfo>
  722. }, content: string) {
  723. const domParser = new DOMParser()
  724. const xmlDoc = domParser.parseFromString(content, 'application/xml')
  725. const sheetNodes = getElementsByTagName(xmlDoc, 'Worksheet')
  726. const rows: any[] = []
  727. const fields: string[] = []
  728. if (sheetNodes.length) {
  729. const tableNodes = getElementsByTagName(sheetNodes[0], 'Table')
  730. if (tableNodes.length) {
  731. const rowNodes = getElementsByTagName(tableNodes[0], 'Row')
  732. if (rowNodes.length) {
  733. XEUtils.arrayEach(getElementsByTagName(rowNodes[0], 'Cell'), cellNode => {
  734. fields.push(toExportField(tableConf, cellNode.textContent || ''))
  735. })
  736. XEUtils.arrayEach(rowNodes, (rowNode, index) => {
  737. if (index) {
  738. const item: any = {}
  739. const cellNodes = getElementsByTagName(rowNode, 'Cell')
  740. XEUtils.arrayEach(cellNodes, (cellNode, colIndex) => {
  741. if (fields[colIndex]) {
  742. item[fields[colIndex]] = cellNode.textContent
  743. }
  744. })
  745. rows.push(item)
  746. }
  747. })
  748. }
  749. }
  750. }
  751. return { fields, rows }
  752. }
  753. function handleImport ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, content: any, opts: any) {
  754. const internalData = $xeTable as unknown as TableInternalData
  755. const { tableFullColumn, _importResolve, _importReject } = internalData
  756. let rest: {
  757. fields: string[];
  758. rows: any[];
  759. } = { fields: [], rows: [] }
  760. const tableFieldMaps: Record<string, VxeTableDefines.ColumnInfo> = {}
  761. const tableTitleMaps: Record<string, VxeTableDefines.ColumnInfo> = {}
  762. tableFullColumn.forEach((column) => {
  763. const field = column.field
  764. const title = column.getTitle()
  765. if (field) {
  766. tableFieldMaps[field] = column
  767. }
  768. if (title) {
  769. tableTitleMaps[column.getTitle()] = column
  770. }
  771. })
  772. const tableConf = {
  773. fieldMaps: tableFieldMaps,
  774. titleMaps: tableTitleMaps
  775. }
  776. switch (opts.type) {
  777. case 'csv':
  778. rest = parseCsv(tableConf, content)
  779. break
  780. case 'txt':
  781. rest = parseTxt(tableConf, content)
  782. break
  783. case 'html':
  784. rest = parseHTML(tableConf, content)
  785. break
  786. case 'xml':
  787. rest = parseXML(tableConf, content)
  788. break
  789. }
  790. const { fields, rows } = rest
  791. const status = fields.some(field => tableFieldMaps[field] || tableTitleMaps[field])
  792. if (status) {
  793. $xeTable.createData(rows)
  794. .then((data: any) => {
  795. let loadRest
  796. if (opts.mode === 'insert' || opts.mode === 'insertBottom') {
  797. loadRest = $xeTable.insertAt(data, -1)
  798. } if (opts.mode === 'insertTop') {
  799. loadRest = $xeTable.insert(data)
  800. } else {
  801. loadRest = $xeTable.reloadData(data)
  802. }
  803. if (opts.message !== false) {
  804. // 检测弹窗模块
  805. if (!VxeUI.modal) {
  806. errLog('vxe.error.reqModule', ['Modal'])
  807. }
  808. VxeUI.modal.message({ content: getI18n('vxe.table.impSuccess', [rows.length]), status: 'success' })
  809. }
  810. return loadRest.then(() => {
  811. if (_importResolve) {
  812. _importResolve({ status: true })
  813. }
  814. })
  815. })
  816. } else if (opts.message !== false) {
  817. // 检测弹窗模块
  818. if (!VxeUI.modal) {
  819. errLog('vxe.error.reqModule', ['Modal'])
  820. }
  821. VxeUI.modal.message({ content: getI18n('vxe.error.impFields'), status: 'error' })
  822. if (_importReject) {
  823. _importReject({ status: false })
  824. }
  825. }
  826. }
  827. function handleFileImport ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, file: any, opts: any) {
  828. const internalData = $xeTable as unknown as TableInternalData
  829. const importOpts = $xeTable.computeImportOpts
  830. const { importMethod, afterImportMethod } = opts
  831. const { type, filename } = parseFile(file)
  832. // 检查类型,如果为自定义导出,则不需要校验类型
  833. if (!importMethod && !XEUtils.includes(XEUtils.keys(importOpts._typeMaps), type)) {
  834. if (opts.message !== false) {
  835. // 检测弹窗模块
  836. if (!VxeUI.modal) {
  837. errLog('vxe.error.reqModule', ['Modal'])
  838. }
  839. VxeUI.modal.message({ content: getI18n('vxe.error.notType', [type]), status: 'error' })
  840. }
  841. const params = { status: false }
  842. return Promise.reject(params)
  843. }
  844. const rest = new Promise((resolve, reject) => {
  845. const _importResolve = (params: any) => {
  846. resolve(params)
  847. ;($xeTable as any)._importResolve = null
  848. ;($xeTable as any)._importReject = null
  849. }
  850. const _importReject = (params: any) => {
  851. reject(params)
  852. ;($xeTable as any)._importResolve = null
  853. ;($xeTable as any)._importReject = null
  854. }
  855. ;($xeTable as any)._importResolve = _importResolve
  856. ;($xeTable as any)._importReject = _importReject
  857. if (window.FileReader) {
  858. const options = Object.assign({ mode: 'insertTop' }, opts, { type, filename })
  859. if (options.remote) {
  860. if (importMethod) {
  861. Promise.resolve(importMethod({ file, options, $table: $xeTable })).then(() => {
  862. _importResolve({ status: true })
  863. }).catch(() => {
  864. _importResolve({ status: true })
  865. })
  866. } else {
  867. _importResolve({ status: true })
  868. }
  869. } else {
  870. const { tableFullColumn } = internalData
  871. $xeTable.preventEvent(null, 'event.import', { file, options, columns: tableFullColumn }, () => {
  872. const reader = new FileReader()
  873. reader.onerror = () => {
  874. errLog('vxe.error.notType', [type])
  875. _importReject({ status: false })
  876. }
  877. reader.onload = (e: any) => {
  878. handleImport($xeTable, e.target.result, options)
  879. }
  880. reader.readAsText(file, options.encoding || 'UTF-8')
  881. })
  882. }
  883. } else {
  884. // 不支持的浏览器
  885. errLog('vxe.error.notExp')
  886. _importResolve({ status: true })
  887. }
  888. })
  889. return rest.then(() => {
  890. if (afterImportMethod) {
  891. afterImportMethod({ status: true, options: opts, $table: $xeTable })
  892. }
  893. }).catch((e) => {
  894. if (afterImportMethod) {
  895. afterImportMethod({ status: false, options: opts, $table: $xeTable })
  896. }
  897. return Promise.reject(e)
  898. })
  899. }
  900. function handleCloseExport () {
  901. if (VxeUI.modal) {
  902. return VxeUI.modal.close('VXE_EXPORT_MODAL')
  903. }
  904. return Promise.resolve()
  905. }
  906. function handleFilterColumns (exportOpts: VxeTablePropTypes.ExportConfig, column: VxeTableDefines.ColumnInfo, columns: VxeTableDefines.ColumnInfo[] | VxeTablePropTypes.ExportOrPrintColumnOption[]) {
  907. return columns.some((item: any) => {
  908. if (isColumnInfo(item)) {
  909. return column.id === (item as any).id
  910. } else if (XEUtils.isString(item)) {
  911. return column.field === item
  912. } else {
  913. const colid = item.id || item.colId
  914. const type = item.type
  915. const field = item.field
  916. if (colid) {
  917. return column.id === colid
  918. } else if (field && type) {
  919. return column.field === field && column.type === type
  920. } else if (field) {
  921. return column.field === field
  922. } else if (type) {
  923. return column.type === type
  924. }
  925. }
  926. return false
  927. })
  928. }
  929. function handleFilterFields (exportOpts: VxeTablePropTypes.ExportConfig, column: VxeTableDefines.ColumnInfo, includeFields: string[] | undefined, excludeFields: string[] | undefined) {
  930. if (excludeFields) {
  931. if (XEUtils.includes(excludeFields, column.field)) {
  932. return false
  933. }
  934. }
  935. if (includeFields) {
  936. if (XEUtils.includes(includeFields, column.field)) {
  937. return true
  938. }
  939. return false
  940. }
  941. return exportOpts.original ? !!column.field : defaultFilterExportColumn(column)
  942. }
  943. function handleExportAndPrint ($xeTable: VxeTableConstructor, options: VxeTablePropTypes.ExportOpts | VxeTablePropTypes.ExportConfig, isPrint?: any) {
  944. const props = $xeTable
  945. const reactData = $xeTable as unknown as TableReactData
  946. const internalData = $xeTable as unknown as TableInternalData
  947. const $xeGrid = $xeTable.$xeGrid
  948. const $xeGantt = $xeTable.$xeGantt
  949. const $xeGGWrapper = $xeGrid || $xeGantt
  950. const { treeConfig, showHeader, showFooter } = props
  951. const { initStore, isGroup, footerTableData, exportStore, exportParams } = reactData
  952. const { collectColumn, mergeBodyList, mergeFooterList } = internalData
  953. const exportOpts = $xeTable.computeExportOpts
  954. const hasTree = treeConfig
  955. const customOpts = $xeTable.computeCustomOpts
  956. const selectRecords = $xeTable.getCheckboxRecords()
  957. const proxyOpts = $xeGGWrapper ? $xeGGWrapper.computeProxyOpts : {}
  958. const hasFooter = !!footerTableData.length
  959. const hasMerge = !!(mergeBodyList.length || mergeFooterList.length)
  960. const defOpts = Object.assign({
  961. message: true,
  962. isHeader: showHeader,
  963. isTitle: showHeader,
  964. isFooter: showFooter,
  965. isColgroup: isGroup,
  966. isMerge: hasMerge,
  967. useStyle: true,
  968. current: 'current',
  969. modes: (proxyOpts.ajax && proxyOpts.ajax.queryAll ? ['all'] : []).concat(['current', 'selected', 'empty'])
  970. }, options)
  971. const types = defOpts.types || XEUtils.keys(exportOpts._typeMaps)
  972. const modes = defOpts.modes || []
  973. const checkMethod = customOpts.checkMethod
  974. const exportColumns = collectColumn.slice(0)
  975. const { columns, excludeFields, includeFields } = defOpts
  976. // 处理类型
  977. const typeList = types.map((value) => {
  978. return {
  979. value,
  980. label: getI18n(`vxe.export.types.${value}`)
  981. }
  982. })
  983. const modeList = modes.map((item: any) => {
  984. if (item && item.value) {
  985. return {
  986. value: item.value,
  987. label: item.label || item.value
  988. }
  989. }
  990. return {
  991. value: item,
  992. label: getI18n(`vxe.export.modes.${item}`)
  993. }
  994. })
  995. // 默认选中
  996. XEUtils.eachTree(exportColumns, (column, index, items, path, parent) => {
  997. const isColGroup = column.children && column.children.length > 0
  998. let isChecked = false
  999. if (columns && columns.length) {
  1000. isChecked = handleFilterColumns(defOpts, column, columns)
  1001. } else if (excludeFields || includeFields) {
  1002. isChecked = handleFilterFields(defOpts, column, includeFields, excludeFields)
  1003. } else {
  1004. isChecked = column.visible && (isColGroup || defaultFilterExportColumn(column))
  1005. }
  1006. column.checked = isChecked
  1007. column.halfChecked = false
  1008. column.disabled = (parent && parent.disabled) || (checkMethod ? !checkMethod({ $table: $xeTable, column }) : false)
  1009. })
  1010. // 更新条件
  1011. Object.assign(exportStore, {
  1012. columns: exportColumns,
  1013. typeList,
  1014. modeList,
  1015. hasFooter,
  1016. hasMerge,
  1017. hasTree,
  1018. isPrint,
  1019. hasColgroup: isGroup,
  1020. visible: true
  1021. })
  1022. // 默认参数
  1023. Object.assign(exportParams, {
  1024. mode: selectRecords.length ? 'selected' : 'current'
  1025. }, defOpts)
  1026. const { filename, sheetName, mode, type } = exportParams
  1027. if (filename) {
  1028. if (XEUtils.isFunction(filename)) {
  1029. exportParams.filename = filename({
  1030. options: defOpts,
  1031. $table: $xeTable,
  1032. $grid: $xeGrid,
  1033. $gantt: $xeGantt
  1034. })
  1035. } else {
  1036. exportParams.filename = `${filename}`
  1037. }
  1038. }
  1039. if (sheetName) {
  1040. if (XEUtils.isFunction(sheetName)) {
  1041. exportParams.sheetName = sheetName({
  1042. options: defOpts,
  1043. $table: $xeTable,
  1044. $grid: $xeGrid,
  1045. $gantt: $xeGantt
  1046. })
  1047. } else {
  1048. exportParams.sheetName = `${sheetName}`
  1049. }
  1050. }
  1051. if (!modeList.some(item => item.value === mode)) {
  1052. exportParams.mode = modeList[0].value
  1053. }
  1054. if (!typeList.some(item => item.value === type)) {
  1055. exportParams.type = typeList[0].value
  1056. }
  1057. initStore.export = true
  1058. return $xeTable.$nextTick()
  1059. }
  1060. const getConvertColumns = (columns: any[]) => {
  1061. const result: any[] = []
  1062. columns.forEach((column) => {
  1063. if (column.childNodes && column.childNodes.length) {
  1064. result.push(column)
  1065. result.push(...getConvertColumns(column.childNodes))
  1066. } else {
  1067. result.push(column)
  1068. }
  1069. })
  1070. return result
  1071. }
  1072. const convertToRows = (originColumns: any[]) => {
  1073. let maxLevel = 1
  1074. const traverse = (column: any, parent?: any) => {
  1075. if (parent) {
  1076. column._level = parent._level + 1
  1077. if (maxLevel < column._level) {
  1078. maxLevel = column._level
  1079. }
  1080. }
  1081. if (column.childNodes && column.childNodes.length) {
  1082. let colSpan = 0
  1083. column.childNodes.forEach((subColumn: any) => {
  1084. traverse(subColumn, column)
  1085. colSpan += subColumn._colSpan
  1086. })
  1087. column._colSpan = colSpan
  1088. } else {
  1089. column._colSpan = 1
  1090. }
  1091. }
  1092. originColumns.forEach((column) => {
  1093. column._level = 1
  1094. traverse(column)
  1095. })
  1096. const rows: any[] = []
  1097. for (let i = 0; i < maxLevel; i++) {
  1098. rows.push([])
  1099. }
  1100. const allColumns = getConvertColumns(originColumns)
  1101. allColumns.forEach((column) => {
  1102. if (column.childNodes && column.childNodes.length) {
  1103. column._rowSpan = 1
  1104. } else {
  1105. column._rowSpan = maxLevel - column._level + 1
  1106. }
  1107. rows[column._level - 1].push(column)
  1108. })
  1109. return rows
  1110. }
  1111. export default {
  1112. methods: {
  1113. /**
  1114. * 导出文件,支持 csv/html/xml/txt
  1115. * 如果是树表格,则默认是导出所有节点
  1116. * 如果是启用了虚拟滚动,则只能导出数据源,可以配合 dataFilterMethod 函数转换数据
  1117. * @param {Object} options 参数
  1118. */
  1119. _exportData (options?: VxeTablePropTypes.ExportConfig) {
  1120. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1121. const props = $xeTable
  1122. const reactData = $xeTable as unknown as TableReactData
  1123. const internalData = $xeTable as unknown as TableInternalData
  1124. const $xeGrid = $xeTable.$xeGrid
  1125. const $xeGantt = $xeTable.$xeGantt
  1126. const $xeGGWrapper = $xeGrid || $xeGantt
  1127. const { treeConfig, showHeader, showFooter } = props
  1128. const { isGroup } = reactData
  1129. const { tableFullColumn, afterFullData, afterTreeFullData, collectColumn, mergeBodyList, mergeFooterList } = internalData
  1130. const exportOpts = $xeTable.computeExportOpts
  1131. const treeOpts = $xeTable.computeTreeOpts
  1132. const proxyOpts = $xeGGWrapper ? $xeGGWrapper.computeProxyOpts : {}
  1133. const hasMerge = !!(mergeBodyList.length || mergeFooterList.length)
  1134. const opts = Object.assign({
  1135. message: true,
  1136. isHeader: showHeader,
  1137. isTitle: showHeader,
  1138. isFooter: showFooter,
  1139. isColgroup: isGroup,
  1140. isMerge: hasMerge,
  1141. useStyle: true,
  1142. current: 'current',
  1143. modes: (proxyOpts.ajax && proxyOpts.ajax.queryAll ? ['all'] : []).concat(['current', 'selected', 'empty']),
  1144. download: true,
  1145. type: 'csv'
  1146. // filename: '',
  1147. // sheetName: '',
  1148. // original: false,
  1149. // isAllExpand: false,
  1150. // data: null,
  1151. // remote: false,
  1152. // dataFilterMethod: null,
  1153. // footerFilterMethod: null,
  1154. // exportMethod: null,
  1155. // columnFilterMethod: null,
  1156. // beforeExportMethod: null,
  1157. // afterExportMethod: null
  1158. }, exportOpts, options)
  1159. let { filename, sheetName, type, mode, columns, original, columnFilterMethod, beforeExportMethod, includeFields, excludeFields } = opts
  1160. let groups: any[] = []
  1161. const selectRecords = $xeTable.getCheckboxRecords()
  1162. if (!mode) {
  1163. mode = selectRecords.length ? 'selected' : 'current'
  1164. }
  1165. let isCustomCol = false
  1166. let customCols = []
  1167. if (columns && columns.length) {
  1168. isCustomCol = true
  1169. customCols = columns
  1170. } else {
  1171. customCols = XEUtils.searchTree(collectColumn, column => {
  1172. const isColGroup = column.children && column.children.length > 0
  1173. let isChecked = false
  1174. if (columns && columns.length) {
  1175. isChecked = handleFilterColumns(opts, column, columns)
  1176. } else if (excludeFields || includeFields) {
  1177. isChecked = handleFilterFields(opts, column, includeFields, excludeFields)
  1178. } else {
  1179. isChecked = column.visible && (isColGroup || defaultFilterExportColumn(column))
  1180. }
  1181. return isChecked
  1182. }, { children: 'children', mapChildren: 'childNodes', original: true })
  1183. }
  1184. const handleOptions: VxeTablePropTypes.ExportHandleOptions = Object.assign({ } as { data: any[], colgroups: any[], columns: any[] }, opts, { filename: '', sheetName: '' })
  1185. // 如果设置源数据,则默认导出设置了字段的列
  1186. if (!isCustomCol && !columnFilterMethod) {
  1187. columnFilterMethod = ({ column }) => {
  1188. if (excludeFields) {
  1189. if (XEUtils.includes(excludeFields, column.field)) {
  1190. return false
  1191. }
  1192. }
  1193. if (includeFields) {
  1194. if (XEUtils.includes(includeFields, column.field)) {
  1195. return true
  1196. }
  1197. return false
  1198. }
  1199. return original ? !!column.field : defaultFilterExportColumn(column)
  1200. }
  1201. handleOptions.columnFilterMethod = columnFilterMethod
  1202. }
  1203. if (customCols) {
  1204. handleOptions._isCustomColumn = true
  1205. groups = XEUtils.searchTree(
  1206. XEUtils.mapTree(customCols, (item) => {
  1207. let targetColumn
  1208. if (item) {
  1209. if (isColumnInfo(item)) {
  1210. targetColumn = item
  1211. } else if (XEUtils.isString(item)) {
  1212. targetColumn = $xeTable.getColumnByField(item)
  1213. } else {
  1214. const colid = item.id || item.colId
  1215. const type = item.type
  1216. const field = item.field
  1217. if (colid) {
  1218. targetColumn = $xeTable.getColumnById(colid)
  1219. } else if (field && type) {
  1220. targetColumn = tableFullColumn.find((column: VxeTableDefines.ColumnInfo) => column.field === field && column.type === type)
  1221. } else if (field) {
  1222. targetColumn = $xeTable.getColumnByField(field)
  1223. } else if (type) {
  1224. targetColumn = tableFullColumn.find((column: VxeTableDefines.ColumnInfo) => column.type === type)
  1225. }
  1226. }
  1227. return targetColumn || {}
  1228. }
  1229. }, {
  1230. children: 'childNodes',
  1231. mapChildren: '_children'
  1232. }),
  1233. (column, index) => isColumnInfo(column) && (!columnFilterMethod || columnFilterMethod({ $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt, column: column as any, $columnIndex: index })),
  1234. {
  1235. children: '_children',
  1236. mapChildren: 'childNodes',
  1237. original: true
  1238. }
  1239. )
  1240. } else {
  1241. 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 })
  1242. }
  1243. // 获取所有列
  1244. const cols: VxeTableDefines.ColumnInfo[] = []
  1245. XEUtils.eachTree(groups, column => {
  1246. const isColGroup = column.children && column.children.length
  1247. if (!isColGroup) {
  1248. cols.push(column)
  1249. }
  1250. }, { children: 'childNodes' })
  1251. // 构建分组层级
  1252. handleOptions.columns = cols
  1253. handleOptions.colgroups = convertToRows(groups)
  1254. if (filename) {
  1255. if (XEUtils.isFunction(filename)) {
  1256. handleOptions.filename = filename({
  1257. options: opts,
  1258. $table: $xeTable,
  1259. $grid: $xeGrid,
  1260. $gantt: $xeGantt
  1261. })
  1262. } else {
  1263. handleOptions.filename = `${filename}`
  1264. }
  1265. }
  1266. if (!handleOptions.filename) {
  1267. handleOptions.filename = getI18n(handleOptions.original ? 'vxe.table.expOriginFilename' : 'vxe.table.expFilename', [XEUtils.toDateString(Date.now(), 'yyyyMMddHHmmss')])
  1268. }
  1269. if (sheetName) {
  1270. if (XEUtils.isFunction(sheetName)) {
  1271. handleOptions.sheetName = sheetName({
  1272. options: opts,
  1273. $table: $xeTable,
  1274. $grid: $xeGrid,
  1275. $gantt: $xeGantt
  1276. })
  1277. } else {
  1278. handleOptions.sheetName = `${sheetName}`
  1279. }
  1280. }
  1281. if (!handleOptions.sheetName) {
  1282. handleOptions.sheetName = document.title || ''
  1283. }
  1284. // 检查类型,如果为自定义导出,则不需要校验类型
  1285. if (!handleOptions.exportMethod && !XEUtils.includes(XEUtils.keys(exportOpts._typeMaps), type)) {
  1286. errLog('vxe.error.notType', [type])
  1287. if (['xlsx', 'pdf'].includes(type)) {
  1288. warnLog('vxe.error.reqPlugin', [4, 'plugin-export-xlsx'])
  1289. }
  1290. const params = { status: false }
  1291. return Promise.reject(params)
  1292. }
  1293. if (!handleOptions.print) {
  1294. if (beforeExportMethod) {
  1295. beforeExportMethod({ options: handleOptions, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt })
  1296. }
  1297. }
  1298. if (!handleOptions.data) {
  1299. handleOptions.data = []
  1300. if (mode === 'selected') {
  1301. if (['html', 'pdf'].indexOf(type) > -1 && treeConfig) {
  1302. handleOptions.data = XEUtils.searchTree($xeTable.getTableData().fullData, item => $xeTable.findRowIndexOf(selectRecords, item) > -1, Object.assign({}, treeOpts, { data: '_row' }))
  1303. } else {
  1304. handleOptions.data = selectRecords
  1305. }
  1306. } else if (mode === 'all') {
  1307. if (!$xeGGWrapper) {
  1308. errLog('vxe.error.errProp', ['all', 'mode=current,selected'])
  1309. }
  1310. if ($xeGGWrapper && !handleOptions.remote) {
  1311. const gridReactData = $xeGGWrapper as unknown as GridReactData
  1312. const proxyOpts = $xeGGWrapper.computeProxyOpts
  1313. const { sortData } = gridReactData
  1314. const { beforeQueryAll, afterQueryAll, ajax = {} } = proxyOpts
  1315. const resConfigs = proxyOpts.response || proxyOpts.props || {}
  1316. const ajaxMethods = ajax.queryAll
  1317. const queryAllSuccessMethods = ajax.queryAllSuccess
  1318. const queryAllErrorMethods = ajax.queryAllError
  1319. if (!ajaxMethods) {
  1320. errLog('vxe.error.notFunc', ['proxy-config.ajax.queryAll'])
  1321. }
  1322. if (ajaxMethods) {
  1323. const params = {
  1324. $table: $xeTable,
  1325. $grid: $xeGrid,
  1326. $gantt: $xeGantt,
  1327. sort: sortData.length ? sortData[0] : {} as any,
  1328. sorts: sortData as any[],
  1329. filters: gridReactData.filterData,
  1330. form: gridReactData.formData,
  1331. options: handleOptions
  1332. }
  1333. return Promise.resolve((beforeQueryAll || ajaxMethods)(params))
  1334. .then(rest => {
  1335. const listProp = resConfigs.list
  1336. handleOptions.data = (listProp ? (XEUtils.isFunction(listProp) ? listProp({ data: rest, $table: $xeTable, $grid: $xeGrid, $gantt: $xeGantt }) : XEUtils.get(rest, listProp)) : rest) || []
  1337. if (afterQueryAll) {
  1338. afterQueryAll(params)
  1339. }
  1340. if (queryAllSuccessMethods) {
  1341. queryAllSuccessMethods({ ...params, response: rest })
  1342. }
  1343. return handleExport($xeTable, handleOptions)
  1344. })
  1345. .catch((rest) => {
  1346. if (queryAllErrorMethods) {
  1347. queryAllErrorMethods({ ...params, response: rest })
  1348. }
  1349. })
  1350. }
  1351. }
  1352. } else if (mode === 'current') {
  1353. handleOptions.data = treeConfig ? afterTreeFullData : afterFullData
  1354. }
  1355. } else {
  1356. handleOptions._isCustomData = true
  1357. }
  1358. return handleExport($xeTable, handleOptions)
  1359. },
  1360. _importByFile (file: File, options: VxeTablePropTypes.ImportConfig) {
  1361. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1362. const opts = Object.assign({}, options)
  1363. const { beforeImportMethod } = opts
  1364. if (beforeImportMethod) {
  1365. beforeImportMethod({ options: opts, $table: $xeTable })
  1366. }
  1367. return handleFileImport($xeTable, file, opts)
  1368. },
  1369. _importData (options?: VxeTablePropTypes.ImportConfig) {
  1370. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1371. const { importOpts } = this
  1372. const opts = Object.assign({
  1373. types: XEUtils.keys(importOpts._typeMaps)
  1374. // beforeImportMethod: null,
  1375. // afterImportMethod: null
  1376. }, importOpts, options)
  1377. const { beforeImportMethod, afterImportMethod } = opts
  1378. if (beforeImportMethod) {
  1379. beforeImportMethod({ options: opts, $table: this })
  1380. }
  1381. return VxeUI.readFile(opts).catch(e => {
  1382. if (afterImportMethod) {
  1383. afterImportMethod({ status: false, options: opts, $table: $xeTable })
  1384. }
  1385. return Promise.reject(e)
  1386. }).then((params) => {
  1387. const { file } = params
  1388. return handleFileImport($xeTable, file, opts)
  1389. })
  1390. },
  1391. _saveFile (options: {
  1392. filename: string
  1393. type: string
  1394. content: string | Blob
  1395. }) {
  1396. return VxeUI.saveFile(options)
  1397. },
  1398. _readFile (options?: {
  1399. multiple?: boolean
  1400. types?: string[]
  1401. message?: boolean
  1402. }) {
  1403. return VxeUI.readFile(options)
  1404. },
  1405. _print (options?: VxeTablePropTypes.PrintConfig) {
  1406. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1407. const $xeGrid = $xeTable.$xeGrid
  1408. const $xeGantt = $xeTable.$xeGantt
  1409. const printOpts = $xeTable.computePrintOpts
  1410. const opts = Object.assign({
  1411. original: false
  1412. // beforePrintMethod
  1413. }, printOpts, options, {
  1414. type: 'html',
  1415. download: false,
  1416. remote: false,
  1417. print: true
  1418. })
  1419. const { sheetName } = opts
  1420. let printTitle = ''
  1421. if (sheetName) {
  1422. if (XEUtils.isFunction(sheetName)) {
  1423. printTitle = sheetName({
  1424. options: opts,
  1425. $table: $xeTable,
  1426. $grid: $xeGrid,
  1427. $gantt: $xeGantt
  1428. })
  1429. } else {
  1430. printTitle = `${sheetName}`
  1431. }
  1432. }
  1433. if (!printTitle) {
  1434. printTitle = document.title || ''
  1435. }
  1436. const beforePrintMethod = opts.beforePrintMethod
  1437. const tableHtml = opts.html || opts.content
  1438. return new Promise((resolve, reject) => {
  1439. if (VxeUI.print) {
  1440. if (tableHtml) {
  1441. resolve(
  1442. VxeUI.print({
  1443. title: printTitle,
  1444. html: tableHtml,
  1445. customStyle: opts.style,
  1446. beforeMethod: beforePrintMethod
  1447. ? ({ html }) => {
  1448. return beforePrintMethod({
  1449. html,
  1450. content: html,
  1451. options: opts,
  1452. $table: $xeTable,
  1453. $grid: $xeGrid,
  1454. $gantt: $xeGantt
  1455. })
  1456. }
  1457. : undefined
  1458. })
  1459. )
  1460. } else {
  1461. resolve(
  1462. $xeTable.exportData(opts).then(({ content }: any) => {
  1463. return VxeUI.print({
  1464. title: printTitle,
  1465. html: content,
  1466. customStyle: opts.style,
  1467. beforeMethod: beforePrintMethod
  1468. ? ({ html }) => {
  1469. return beforePrintMethod({
  1470. html,
  1471. content: html,
  1472. options: opts,
  1473. $table: $xeTable,
  1474. $grid: $xeGrid,
  1475. $gantt: $xeGantt
  1476. })
  1477. }
  1478. : undefined
  1479. })
  1480. })
  1481. )
  1482. }
  1483. } else {
  1484. const e = { status: false }
  1485. reject(e)
  1486. }
  1487. })
  1488. },
  1489. _getPrintHtml (options: VxeTablePropTypes.PrintConfig) {
  1490. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1491. const printOpts = $xeTable.computePrintOpts
  1492. const opts = Object.assign({
  1493. original: false
  1494. // beforePrintMethod
  1495. }, printOpts, options, {
  1496. type: 'html',
  1497. download: false,
  1498. remote: false,
  1499. print: true
  1500. })
  1501. return $xeTable.exportData(opts).then(({ content }: any) => {
  1502. return {
  1503. html: content
  1504. }
  1505. })
  1506. },
  1507. _closeImport () {
  1508. if (VxeUI.modal) {
  1509. return VxeUI.modal.close('VXE_IMPORT_MODAL')
  1510. }
  1511. return Promise.resolve()
  1512. },
  1513. _openImport (options?: VxeTablePropTypes.ImportConfig) {
  1514. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1515. const props = $xeTable
  1516. const reactData = $xeTable as unknown as TableReactData
  1517. const { treeConfig, importConfig } = props
  1518. const { initStore, importStore, importParams } = reactData
  1519. const importOpts = $xeTable.computeImportOpts
  1520. const defOpts = Object.assign({
  1521. mode: 'insertTop',
  1522. message: true,
  1523. types: XEUtils.keys(importOpts._typeMaps),
  1524. modes: ['insertTop', 'covering']
  1525. }, importOpts, options)
  1526. const types = defOpts.types || []
  1527. const modes = defOpts.modes || []
  1528. const isTree = !!treeConfig
  1529. if (isTree) {
  1530. if (defOpts.message) {
  1531. VxeUI.modal.message({ content: getI18n('vxe.error.treeNotImp'), status: 'error' })
  1532. }
  1533. return
  1534. }
  1535. if (!importConfig) {
  1536. errLog('vxe.error.reqProp', ['import-config'])
  1537. }
  1538. // 处理类型
  1539. const typeList = types.map((value: any) => {
  1540. return {
  1541. value,
  1542. label: getI18n(`vxe.export.types.${value}`)
  1543. }
  1544. })
  1545. const modeList = modes.map((item: any) => {
  1546. if (item && item.value) {
  1547. return {
  1548. value: item.value,
  1549. label: item.label || item.value
  1550. }
  1551. }
  1552. return {
  1553. value: item,
  1554. label: getI18n(`vxe.import.modes.${item}`)
  1555. }
  1556. })
  1557. Object.assign(importStore, {
  1558. file: null,
  1559. type: '',
  1560. filename: '',
  1561. modeList,
  1562. typeList,
  1563. visible: true
  1564. })
  1565. Object.assign(importParams, defOpts)
  1566. if (!modeList.some(item => item.value === importParams.mode)) {
  1567. importParams.mode = modeList[0].value
  1568. }
  1569. initStore.import = true
  1570. },
  1571. _closeExport: handleCloseExport,
  1572. _openExport (options: any) {
  1573. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1574. const props = $xeTable
  1575. const exportOpts = $xeTable.computeExportOpts
  1576. const defOpts = Object.assign({
  1577. message: true,
  1578. types: XEUtils.keys(exportOpts._typeMaps)
  1579. }, exportOpts, options)
  1580. if (!props.exportConfig) {
  1581. errLog('vxe.error.reqProp', ['export-config'])
  1582. }
  1583. return handleExportAndPrint($xeTable, defOpts)
  1584. },
  1585. _closePrint: handleCloseExport,
  1586. _openPrint (options: any) {
  1587. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1588. const props = $xeTable
  1589. const printOpts = $xeTable.computePrintOpts
  1590. const defOpts = Object.assign({
  1591. message: true
  1592. }, printOpts, options)
  1593. if (!props.printConfig) {
  1594. errLog('vxe.error.reqProp', ['print-config'])
  1595. }
  1596. return handleExportAndPrint($xeTable, defOpts, true)
  1597. }
  1598. } as any
  1599. } as any