bootstrap-table-print.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /**
  2. * @update zhixin wen <wenzhixin2010@gmail.com>
  3. */
  4. const Utils = $.fn.bootstrapTable.utils
  5. function printPageBuilderDefault (table) {
  6. return `
  7. <html>
  8. <head>
  9. <style type="text/css" media="print">
  10. @page {
  11. size: auto;
  12. margin: 25px 0 25px 0;
  13. }
  14. </style>
  15. <style type="text/css" media="all">
  16. table {
  17. border-collapse: collapse;
  18. font-size: 12px;
  19. }
  20. table, th, td {
  21. border: 1px solid grey;
  22. }
  23. th, td {
  24. text-align: center;
  25. vertical-align: middle;
  26. }
  27. p {
  28. font-weight: bold;
  29. margin-left:20px;
  30. }
  31. table {
  32. width:94%;
  33. margin-left:3%;
  34. margin-right:3%;
  35. }
  36. div.bs-table-print {
  37. text-align:center;
  38. }
  39. </style>
  40. </head>
  41. <title>Print Table</title>
  42. <body>
  43. <p>Printed on: ${new Date} </p>
  44. <div class="bs-table-print">${table}</div>
  45. </body>
  46. </html>`
  47. }
  48. $.extend($.fn.bootstrapTable.locales, {
  49. formatPrint () {
  50. return 'Print'
  51. }
  52. })
  53. $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
  54. $.extend($.fn.bootstrapTable.defaults, {
  55. showPrint: false,
  56. printAsFilteredAndSortedOnUI: true,
  57. printSortColumn: undefined,
  58. printSortOrder: 'asc',
  59. printPageBuilder (table) {
  60. return printPageBuilderDefault(table)
  61. }
  62. })
  63. $.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
  64. printFilter: undefined,
  65. printIgnore: false,
  66. printFormatter: undefined
  67. })
  68. $.extend($.fn.bootstrapTable.defaults.icons, {
  69. print: {
  70. bootstrap3: 'glyphicon-print icon-share',
  71. bootstrap5: 'bi-printer',
  72. 'bootstrap-table': 'icon-printer'
  73. }[$.fn.bootstrapTable.theme] || 'fa-print'
  74. })
  75. $.BootstrapTable = class extends $.BootstrapTable {
  76. init (...args) {
  77. super.init(...args)
  78. if (!this.options.showPrint) {
  79. return
  80. }
  81. this.mergedCells = []
  82. }
  83. initToolbar (...args) {
  84. this.showToolbar = this.showToolbar || this.options.showPrint
  85. if (this.options.showPrint) {
  86. this.buttons = Object.assign(this.buttons, {
  87. print: {
  88. text: this.options.formatPrint(),
  89. icon: this.options.icons.print,
  90. event: () => {
  91. this.doPrint(this.options.printAsFilteredAndSortedOnUI ? this.getData() : this.options.data.slice(0))
  92. },
  93. attributes: {
  94. 'aria-label': this.options.formatPrint(),
  95. title: this.options.formatPrint()
  96. }
  97. }
  98. })
  99. }
  100. super.initToolbar(...args)
  101. }
  102. mergeCells (options) {
  103. super.mergeCells(options)
  104. if (!this.options.showPrint) {
  105. return
  106. }
  107. let col = this.getVisibleFields().indexOf(options.field)
  108. if (Utils.hasDetailViewIcon(this.options)) {
  109. col += 1
  110. }
  111. this.mergedCells.push({
  112. row: options.index,
  113. col,
  114. rowspan: options.rowspan || 1,
  115. colspan: options.colspan || 1
  116. })
  117. }
  118. doPrint(data) {
  119. var _this2 = this
  120. const formatValue = (row, i, column) => {
  121. let value_ = Utils.getItemField(row, column.field, _this2.options.escape, column.escape);
  122. const value = Utils.calculateObjectValue(column,
  123. column.printFormatter || column.formatter,
  124. [value_, row, i], value_)
  125. return typeof value === 'undefined' || value === null ?
  126. this.options.undefinedText : value
  127. }
  128. const buildTable = (data, columnsArray) => {
  129. const dir = this.$el.attr('dir') || 'ltr'
  130. const html = [`<table dir="${dir}"><thead>`]
  131. for (const columns of columnsArray) {
  132. html.push('<tr>')
  133. for (let h = 0; h < columns.length; h++) {
  134. if (!columns[h].printIgnore) {
  135. html.push(
  136. `<th
  137. ${Utils.sprintf(' rowspan="%s"', columns[h].rowspan)}
  138. ${Utils.sprintf(' colspan="%s"', columns[h].colspan)}
  139. >${columns[h].title}</th>`)
  140. }
  141. }
  142. html.push('</tr>')
  143. }
  144. html.push('</thead><tbody>')
  145. const dontRender = []
  146. if (this.mergedCells) {
  147. for (let mc = 0; mc < this.mergedCells.length; mc++) {
  148. const currentMergedCell = this.mergedCells[mc]
  149. for (let rs = 0; rs < currentMergedCell.rowspan; rs++) {
  150. const row = currentMergedCell.row + rs
  151. for (let cs = 0; cs < currentMergedCell.colspan; cs++) {
  152. const col = currentMergedCell.col + cs
  153. dontRender.push(`${row },${ col}`)
  154. }
  155. }
  156. }
  157. }
  158. for (let i = 0; i < data.length; i++) {
  159. html.push('<tr>')
  160. const columns = columnsArray.flat(1)
  161. columns.sort((c1, c2) => {
  162. return c1.colspanIndex - c2.colspanIndex
  163. })
  164. for (let j = 0; j < columns.length; j++) {
  165. if (columns[j].colspanGroup > 0) continue
  166. let rowspan = 0
  167. let colspan = 0
  168. if (this.mergedCells) {
  169. for (let mc = 0; mc < this.mergedCells.length; mc++) {
  170. const currentMergedCell = this.mergedCells[mc]
  171. if (currentMergedCell.col === j && currentMergedCell.row === i) {
  172. rowspan = currentMergedCell.rowspan
  173. colspan = currentMergedCell.colspan
  174. }
  175. }
  176. }
  177. if (
  178. !columns[j].printIgnore && columns[j].field &&
  179. (
  180. !dontRender.includes(`${i },${ j}`) ||
  181. (rowspan > 0 && colspan > 0)
  182. )
  183. ) {
  184. if (rowspan > 0 && colspan > 0) {
  185. html.push(`<td ${Utils.sprintf(' rowspan="%s"', rowspan)} ${Utils.sprintf(' colspan="%s"', colspan)}>`, formatValue(data[i], i, columns[j]), '</td>')
  186. } else {
  187. html.push('<td>', formatValue(data[i], i, columns[j]), '</td>')
  188. }
  189. }
  190. }
  191. html.push('</tr>')
  192. }
  193. html.push('</tbody>')
  194. if (this.options.showFooter) {
  195. html.push('<footer><tr>')
  196. for (const columns of columnsArray) {
  197. for (let h = 0; h < columns.length; h++) {
  198. if (!columns[h].printIgnore) {
  199. const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr'))
  200. const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '')
  201. html.push(`<th>${footerValue}</th>`)
  202. }
  203. }
  204. }
  205. html.push('</tr></footer>')
  206. }
  207. html.push('</table>')
  208. return html.join('')
  209. }
  210. const sortRows = (data, colName, sortOrder) => {
  211. if (!colName) {
  212. return data
  213. }
  214. let reverse = sortOrder !== 'asc'
  215. reverse = -((+reverse) || -1)
  216. return data.sort((a, b) => reverse * (a[colName].localeCompare(b[colName])))
  217. }
  218. const filterRow = (row, filters) => {
  219. for (let index = 0; index < filters.length; ++index) {
  220. if (row[filters[index].colName] !== filters[index].value) {
  221. return false
  222. }
  223. }
  224. return true
  225. }
  226. const filterRows = (data, filters) => data.filter(row => filterRow(row, filters))
  227. const getColumnFilters = columns => !columns || !columns[0] ? [] : columns[0].filter(col => col.printFilter).map(col => ({
  228. colName: col.field,
  229. value: col.printFilter
  230. }))
  231. data = filterRows(data, getColumnFilters(this.options.columns))
  232. data = sortRows(data, this.options.printSortColumn, this.options.printSortOrder)
  233. const table = buildTable(data, this.options.columns)
  234. const newWin = window.open('')
  235. const calculatedPrintPage = Utils.calculateObjectValue(this, this.options.printPageBuilder, [table], printPageBuilderDefault(table))
  236. newWin.document.write(calculatedPrintPage)
  237. newWin.document.close()
  238. newWin.focus()
  239. newWin.print()
  240. newWin.close()
  241. }
  242. }