export-panel.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. import { CreateElement } from 'vue'
  2. import { VxeUI } from '../../../ui'
  3. import XEUtils from 'xe-utils'
  4. import { formatText } from '../../../ui/src/utils'
  5. import { errLog } from '../../../ui/src/log'
  6. import type { VxeTableConstructor, VxeTablePrivateMethods } from '../../../../types'
  7. const { getI18n, getIcon, globalMixins, renderEmptyElement } = VxeUI
  8. export default {
  9. name: 'VxeTableExportPanel',
  10. mixins: [
  11. globalMixins.sizeMixin
  12. ],
  13. props: {
  14. defaultOptions: Object,
  15. storeData: Object
  16. },
  17. components: {
  18. // VxeModal,
  19. // VxeInput,
  20. // VxeCheckbox,
  21. // VxeSelect,
  22. // VxeOption
  23. },
  24. inject: {
  25. $xeTable: {
  26. default: null
  27. }
  28. },
  29. data () {
  30. return {
  31. isAll: false,
  32. isIndeterminate: false,
  33. loading: false
  34. }
  35. },
  36. computed: {
  37. checkedAll () {
  38. return this.storeData.columns.every((column: any) => column.checked)
  39. },
  40. showSheet () {
  41. return ['html', 'xml', 'xlsx', 'pdf'].indexOf(this.defaultOptions.type) > -1
  42. },
  43. supportMerge () {
  44. const { storeData, defaultOptions } = this
  45. return !defaultOptions.original && defaultOptions.mode === 'current' && (storeData.isPrint || ['html', 'xlsx'].indexOf(defaultOptions.type) > -1)
  46. },
  47. // computeSupportGroup () {
  48. // const { defaultOptions } = this
  49. // return ['html', 'xlsx', 'csv', 'txt'].indexOf(defaultOptions.type) > -1
  50. // },
  51. supportStyle () {
  52. const { defaultOptions } = this
  53. return !defaultOptions.original && ['xlsx'].indexOf(defaultOptions.type) > -1
  54. }
  55. } as any,
  56. created (this: any) {
  57. const $xeTableExportPanel = this
  58. const VxeUIModalComponent = VxeUI.getComponent('VxeModal')
  59. const VxeUIButtonComponent = VxeUI.getComponent('VxeButton')
  60. const VxeUISelectComponent = VxeUI.getComponent('VxeSelect')
  61. const VxeUIInputComponent = VxeUI.getComponent('VxeInput')
  62. const VxeUICheckboxComponent = VxeUI.getComponent('VxeCheckbox')
  63. $xeTableExportPanel.$nextTick(() => {
  64. if (!VxeUIModalComponent) {
  65. errLog('vxe.error.reqComp', ['vxe-modal'])
  66. }
  67. if (!VxeUIButtonComponent) {
  68. errLog('vxe.error.reqComp', ['vxe-button'])
  69. }
  70. if (!VxeUISelectComponent) {
  71. errLog('vxe.error.reqComp', ['vxe-select'])
  72. }
  73. if (!VxeUIInputComponent) {
  74. errLog('vxe.error.reqComp', ['vxe-input'])
  75. }
  76. if (!VxeUICheckboxComponent) {
  77. errLog('vxe.error.reqComp', ['vxe-checkbox'])
  78. }
  79. })
  80. },
  81. render (this: any, h: CreateElement) {
  82. const $xeTable = this.$xeTable as VxeTableConstructor & VxeTablePrivateMethods
  83. const $xeGrid = $xeTable.$xeGrid
  84. const $xeGantt = $xeTable.$xeGantt
  85. const { _e, checkedAll, isAll: isAllChecked, isIndeterminate: isAllIndeterminate, showSheet, supportMerge, supportStyle, defaultOptions, storeData } = this
  86. const { hasTree, hasMerge, isPrint, hasColgroup, columns } = storeData
  87. const { isHeader } = defaultOptions
  88. // const supportGroup = this.computeSupportGroup
  89. const slots = defaultOptions.slots || {}
  90. const topSlot = slots.top
  91. const bottomSlot = slots.bottom
  92. const defaultSlot = slots.default
  93. const footerSlot = slots.footer
  94. const parameterSlot = slots.parameter
  95. const cols: any[] = []
  96. XEUtils.eachTree(columns, column => {
  97. const colTitle = formatText(column.getTitle(), 1)
  98. const isColGroup = column.children && column.children.length
  99. const isChecked = column.checked
  100. const indeterminate = column.halfChecked
  101. const isHtml = column.type === 'html'
  102. cols.push(
  103. h('li', {
  104. class: ['vxe-table-export--panel-column-option', `level--${column.level}`, {
  105. 'is--group': isColGroup,
  106. 'is--checked': isChecked,
  107. 'is--indeterminate': indeterminate,
  108. 'is--disabled': column.disabled
  109. }],
  110. attrs: {
  111. title: colTitle
  112. },
  113. on: {
  114. click: () => {
  115. if (!column.disabled) {
  116. this.changeOption(column)
  117. }
  118. }
  119. }
  120. }, [
  121. h('span', {
  122. class: ['vxe-checkbox--icon', indeterminate ? getIcon().TABLE_CHECKBOX_INDETERMINATE : (isChecked ? getIcon().TABLE_CHECKBOX_CHECKED : getIcon().TABLE_CHECKBOX_UNCHECKED)]
  123. }),
  124. isHtml
  125. ? h('span', {
  126. key: '1',
  127. class: 'vxe-checkbox--label',
  128. domProps: {
  129. innerHTML: colTitle
  130. }
  131. })
  132. : h('span', {
  133. key: '0',
  134. class: 'vxe-checkbox--label'
  135. }, colTitle)
  136. ])
  137. )
  138. })
  139. return h('vxe-modal', {
  140. ref: 'modal',
  141. props: {
  142. id: 'VXE_EXPORT_MODAL',
  143. value: storeData.visible,
  144. title: getI18n(isPrint ? 'vxe.export.printTitle' : 'vxe.export.expTitle'),
  145. width: 660,
  146. minWidth: 500,
  147. minHeight: 400,
  148. mask: true,
  149. lockView: true,
  150. showFooter: true,
  151. escClosable: true,
  152. maskClosable: true,
  153. showMaximize: true,
  154. resize: true,
  155. loading: this.loading
  156. },
  157. on: {
  158. input (value: any) {
  159. storeData.visible = value
  160. },
  161. show: this.showEvent
  162. },
  163. scopedSlots: {
  164. default: () => {
  165. const params = {
  166. $table: $xeTable,
  167. $grid: $xeGrid,
  168. $gantt: $xeGantt,
  169. options: defaultOptions,
  170. columns,
  171. params: defaultOptions.params as any
  172. }
  173. const hasEmptyData = defaultOptions.mode === 'empty'
  174. return h('div', {
  175. class: 'vxe-table-export--panel'
  176. }, [
  177. topSlot
  178. ? h('div', {
  179. class: 'vxe-table-export--panel-top'
  180. }, $xeTable.callSlot(topSlot, params, h))
  181. : renderEmptyElement(this),
  182. h('div', {
  183. class: 'vxe-table-export--panel-body'
  184. }, defaultSlot
  185. ? $xeTable.callSlot(defaultSlot, params, h)
  186. : [
  187. h('table', {
  188. attrs: {
  189. class: 'vxe-table-export--panel-table',
  190. cellspacing: 0,
  191. cellpadding: 0,
  192. border: 0
  193. }
  194. }, [
  195. h('tbody', [
  196. [
  197. isPrint
  198. ? _e()
  199. : h('tr', [
  200. h('td', getI18n('vxe.export.expName')),
  201. h('td', [
  202. h('vxe-input', {
  203. ref: 'filename',
  204. props: {
  205. value: defaultOptions.filename,
  206. type: 'text',
  207. clearable: true,
  208. placeholder: getI18n('vxe.export.expNamePlaceholder')
  209. },
  210. on: {
  211. modelValue (value: any) {
  212. defaultOptions.filename = value
  213. }
  214. }
  215. })
  216. ])
  217. ]),
  218. isPrint
  219. ? _e()
  220. : h('tr', [
  221. h('td', getI18n('vxe.export.expType')),
  222. h('td', [
  223. h('vxe-select', {
  224. props: {
  225. value: defaultOptions.type,
  226. options: storeData.typeList
  227. },
  228. on: {
  229. modelValue (value: any) {
  230. defaultOptions.type = value
  231. }
  232. }
  233. })
  234. ])
  235. ]),
  236. isPrint || showSheet
  237. ? h('tr', [
  238. h('td', getI18n('vxe.export.expSheetName')),
  239. h('td', [
  240. h('vxe-input', {
  241. ref: 'sheetname',
  242. props: {
  243. value: defaultOptions.sheetName,
  244. type: 'text',
  245. clearable: true,
  246. placeholder: getI18n('vxe.export.expSheetNamePlaceholder')
  247. },
  248. on: {
  249. modelValue (value: any) {
  250. defaultOptions.sheetName = value
  251. }
  252. }
  253. })
  254. ])
  255. ])
  256. : _e(),
  257. h('tr', [
  258. h('td', getI18n('vxe.export.expMode')),
  259. h('td', [
  260. h('vxe-select', {
  261. props: {
  262. value: defaultOptions.mode,
  263. options: storeData.modeList
  264. },
  265. on: {
  266. modelValue (value: any) {
  267. defaultOptions.mode = value
  268. }
  269. }
  270. })
  271. ])
  272. ]),
  273. h('tr', [
  274. h('td', [getI18n('vxe.export.expColumn')]),
  275. h('td', [
  276. h('div', {
  277. class: 'vxe-table-export--panel-column'
  278. }, [
  279. h('ul', {
  280. class: 'vxe-table-export--panel-column-header'
  281. }, [
  282. h('li', {
  283. class: ['vxe-table-export--panel-column-option', {
  284. 'is--checked': isAllChecked,
  285. 'is--indeterminate': isAllIndeterminate
  286. }],
  287. attrs: {
  288. title: getI18n('vxe.table.allTitle')
  289. },
  290. on: {
  291. click: this.allColumnEvent
  292. }
  293. }, [
  294. h('span', {
  295. class: ['vxe-checkbox--icon', isAllIndeterminate ? getIcon().TABLE_CHECKBOX_INDETERMINATE : (isAllChecked ? getIcon().TABLE_CHECKBOX_CHECKED : getIcon().TABLE_CHECKBOX_UNCHECKED)]
  296. }),
  297. h('span', {
  298. class: 'vxe-checkbox--label'
  299. }, getI18n('vxe.export.expCurrentColumn'))
  300. ])
  301. ]),
  302. h('ul', {
  303. class: 'vxe-table-export--panel-column-body'
  304. }, cols)
  305. ])
  306. ])
  307. ]),
  308. h('tr', [
  309. h('td', getI18n('vxe.export.expOpts')),
  310. parameterSlot
  311. ? h('td', [
  312. h('div', {
  313. class: 'vxe-table-export--panel-option-row'
  314. }, $xeTable.callSlot(parameterSlot, params, h))
  315. ])
  316. : h('td', [
  317. h('div', {
  318. class: 'vxe-table-export--panel-option-row'
  319. }, [
  320. h('vxe-checkbox', {
  321. props: {
  322. value: hasEmptyData || isHeader,
  323. disabled: hasEmptyData,
  324. title: getI18n('vxe.export.expHeaderTitle'),
  325. content: getI18n('vxe.export.expOptHeader')
  326. },
  327. on: {
  328. input (value: any) {
  329. defaultOptions.isHeader = value
  330. }
  331. }
  332. }),
  333. h('vxe-checkbox', {
  334. props: {
  335. value: isHeader ? defaultOptions.isTitle : false,
  336. disabled: !isHeader,
  337. title: getI18n('vxe.export.expTitleTitle'),
  338. content: getI18n('vxe.export.expOptTitle')
  339. },
  340. on: {
  341. input (value: any) {
  342. defaultOptions.isTitle = value
  343. }
  344. }
  345. }),
  346. h('vxe-checkbox', {
  347. props: {
  348. value: isHeader && hasColgroup && supportMerge ? defaultOptions.isColgroup : false,
  349. disabled: !isHeader || !hasColgroup || !supportMerge,
  350. title: getI18n('vxe.export.expColgroupTitle'),
  351. content: getI18n('vxe.export.expOptColgroup')
  352. },
  353. on: {
  354. input (value: any) {
  355. defaultOptions.isColgroup = value
  356. }
  357. }
  358. })
  359. ]),
  360. h('div', {
  361. class: 'vxe-table-export--panel-option-row'
  362. }, [
  363. h('vxe-checkbox', {
  364. props: {
  365. value: hasEmptyData ? false : defaultOptions.original,
  366. disabled: hasEmptyData,
  367. title: getI18n('vxe.export.expOriginalTitle'),
  368. content: getI18n('vxe.export.expOptOriginal')
  369. },
  370. on: {
  371. input (value: any) {
  372. defaultOptions.original = value
  373. }
  374. }
  375. }),
  376. h('vxe-checkbox', {
  377. props: {
  378. value: hasMerge && supportMerge && checkedAll ? defaultOptions.isMerge : false,
  379. disabled: hasEmptyData || !hasMerge || !supportMerge || !checkedAll,
  380. title: getI18n('vxe.export.expMergeTitle'),
  381. content: getI18n('vxe.export.expOptMerge')
  382. },
  383. on: {
  384. input (value: any) {
  385. defaultOptions.isMerge = value
  386. }
  387. }
  388. }),
  389. isPrint
  390. ? _e()
  391. : h('vxe-checkbox', {
  392. props: {
  393. value: supportStyle ? defaultOptions.useStyle : false,
  394. disabled: !supportStyle,
  395. title: getI18n('vxe.export.expUseStyleTitle'),
  396. content: getI18n('vxe.export.expOptUseStyle')
  397. },
  398. on: {
  399. input (value: any) {
  400. defaultOptions.useStyle = value
  401. }
  402. }
  403. }),
  404. h('vxe-checkbox', {
  405. props: {
  406. value: hasTree ? defaultOptions.isAllExpand : false,
  407. disabled: hasEmptyData || !hasTree,
  408. title: getI18n('vxe.export.expAllExpandTitle'),
  409. content: getI18n('vxe.export.expOptAllExpand')
  410. },
  411. on: {
  412. input (value: any) {
  413. defaultOptions.isAllExpand = value
  414. }
  415. }
  416. })
  417. ]),
  418. h('div', {
  419. class: 'vxe-table-export--panel-option-row'
  420. }, [
  421. h('vxe-checkbox', {
  422. props: {
  423. value: defaultOptions.isFooter,
  424. disabled: !storeData.hasFooter,
  425. title: getI18n('vxe.export.expFooterTitle'),
  426. content: getI18n('vxe.export.expOptFooter')
  427. },
  428. on: {
  429. input (value: any) {
  430. defaultOptions.isFooter = value
  431. }
  432. }
  433. })
  434. ])
  435. ])
  436. ])
  437. ]
  438. ])
  439. ])
  440. ]),
  441. bottomSlot
  442. ? h('div', {
  443. class: 'vxe-table-export--panel-bottom'
  444. }, $xeTable.callSlot(bottomSlot, params, h))
  445. : renderEmptyElement(this)
  446. ])
  447. },
  448. footer: () => {
  449. const params = {
  450. $table: $xeTable,
  451. $grid: $xeGrid,
  452. $gantt: $xeGantt,
  453. options: defaultOptions,
  454. columns,
  455. params: defaultOptions.params as any
  456. }
  457. return h('div', {
  458. class: 'vxe-table-export--panel-footer'
  459. }, footerSlot
  460. ? $xeTable.callSlot(footerSlot, params, h)
  461. : [
  462. h('div', {
  463. class: 'vxe-table-export--panel-btns'
  464. }, [
  465. h('vxe-button', {
  466. props: {
  467. content: getI18n('vxe.export.expCancel')
  468. },
  469. on: {
  470. click: this.cancelEvent
  471. }
  472. }),
  473. h('vxe-button', {
  474. ref: 'confirmBtn',
  475. props: {
  476. status: 'primary',
  477. content: getI18n(isPrint ? 'vxe.export.expPrint' : 'vxe.export.expConfirm')
  478. },
  479. on: {
  480. click: this.confirmEvent
  481. }
  482. })
  483. ])
  484. ])
  485. }
  486. }
  487. })
  488. },
  489. methods: {
  490. changeOption (column: any) {
  491. const isChecked = !column.checked
  492. XEUtils.eachTree([column], (item) => {
  493. item.checked = isChecked
  494. item.halfChecked = false
  495. })
  496. this.handleOptionCheck(column)
  497. this.checkStatus()
  498. },
  499. handleOptionCheck (column: any) {
  500. const matchObj = XEUtils.findTree(this.storeData.columns as any[], item => item === column)
  501. if (matchObj && matchObj.parent) {
  502. const { parent } = matchObj
  503. if (parent.children && parent.children.length) {
  504. parent.checked = parent.children.every((column: any) => column.checked)
  505. parent.halfChecked = !parent.checked && parent.children.some((column: any) => column.checked || column.halfChecked)
  506. this.handleOptionCheck(parent)
  507. }
  508. }
  509. },
  510. checkStatus () {
  511. const columns = this.storeData.columns
  512. this.isAll = columns.every((column: any) => column.disabled || column.checked)
  513. this.isIndeterminate = !this.isAll && columns.some((column: any) => !column.disabled && (column.checked || column.halfChecked))
  514. },
  515. allColumnEvent () {
  516. const isAll = !this.isAll
  517. XEUtils.eachTree(this.storeData.columns, column => {
  518. if (!column.disabled) {
  519. column.checked = isAll
  520. column.halfChecked = false
  521. }
  522. })
  523. this.isAll = isAll
  524. this.checkStatus()
  525. },
  526. showEvent () {
  527. this.$nextTick(() => {
  528. const { $refs } = this
  529. const targetElem = $refs.filename || $refs.sheetname || $refs.confirmBtn
  530. if (targetElem) {
  531. targetElem.focus()
  532. }
  533. })
  534. this.checkStatus()
  535. },
  536. getExportOption () {
  537. const { checkedAll, storeData, defaultOptions, supportMerge } = this
  538. const { hasMerge, columns } = storeData
  539. const expColumns = XEUtils.searchTree(columns, column => column.checked, { children: 'children', mapChildren: 'childNodes', original: true })
  540. return Object.assign({}, defaultOptions, {
  541. columns: expColumns,
  542. isMerge: hasMerge && supportMerge && checkedAll ? defaultOptions.isMerge : false
  543. })
  544. },
  545. cancelEvent () {
  546. this.storeData.visible = false
  547. },
  548. confirmEvent (evnt: any) {
  549. if (this.storeData.isPrint) {
  550. this.printEvent(evnt)
  551. } else {
  552. this.exportEvent(evnt)
  553. }
  554. },
  555. printEvent () {
  556. const $xeTable = this.$parent as VxeTableConstructor & VxeTablePrivateMethods
  557. this.storeData.visible = false
  558. $xeTable.print(Object.assign({}, $xeTable.printOpts, this.getExportOption()))
  559. },
  560. exportEvent () {
  561. const $xeTable = this.$xeTable
  562. const exportOpts = $xeTable.exportOpts
  563. this.loading = true
  564. $xeTable.exportData(Object.assign({}, exportOpts, this.getExportOption())).then(() => {
  565. this.loading = false
  566. this.storeData.visible = false
  567. }).catch(() => {
  568. this.loading = false
  569. })
  570. }
  571. } as any
  572. }