export-panel.js 32 KB

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