bootstrap-table-print.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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. }
  49. Object.assign($.fn.bootstrapTable.locales, {
  50. formatPrint () {
  51. return 'Print'
  52. }
  53. })
  54. Object.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
  55. Object.assign($.fn.bootstrapTable.defaults, {
  56. showPrint: false,
  57. printAsFilteredAndSortedOnUI: true,
  58. printSortColumn: undefined,
  59. printSortOrder: 'asc',
  60. printPageBuilder (table) {
  61. return printPageBuilderDefault(table)
  62. }
  63. })
  64. Object.assign($.fn.bootstrapTable.columnDefaults, {
  65. printFilter: undefined,
  66. printIgnore: false,
  67. printFormatter: undefined
  68. })
  69. Object.assign($.fn.bootstrapTable.defaults.icons, {
  70. print: {
  71. bootstrap3: 'glyphicon-print icon-share',
  72. bootstrap5: 'bi-printer',
  73. 'bootstrap-table': 'icon-printer'
  74. }[$.fn.bootstrapTable.theme] || 'fa-print'
  75. })
  76. $.BootstrapTable = class extends $.BootstrapTable {
  77. init (...args) {
  78. super.init(...args)
  79. if (!this.options.showPrint) {
  80. return
  81. }
  82. this.mergedCells = []
  83. }
  84. initToolbar (...args) {
  85. this.showToolbar = this.showToolbar || this.options.showPrint
  86. if (this.options.showPrint) {
  87. this.buttons = Object.assign(this.buttons, {
  88. print: {
  89. text: this.options.formatPrint(),
  90. icon: this.options.icons.print,
  91. event: () => {
  92. this.doPrint(this.options.printAsFilteredAndSortedOnUI ? this.getData() : this.options.data.slice(0))
  93. },
  94. attributes: {
  95. 'aria-label': this.options.formatPrint(),
  96. title: this.options.formatPrint()
  97. }
  98. }
  99. })
  100. }
  101. super.initToolbar(...args)
  102. }
  103. mergeCells (options) {
  104. super.mergeCells(options)
  105. if (!this.options.showPrint) {
  106. return
  107. }
  108. let col = this.getVisibleFields().indexOf(options.field)
  109. if (Utils.hasDetailViewIcon(this.options)) {
  110. col += 1
  111. }
  112. this.mergedCells.push({
  113. row: options.index,
  114. col,
  115. rowspan: options.rowspan || 1,
  116. colspan: options.colspan || 1
  117. })
  118. }
  119. doPrint (data) {
  120. const canPrint = column => {
  121. return !column.printIgnore && column.visible
  122. }
  123. const formatValue = (row, i, column) => {
  124. const value_ = Utils.getItemField(row, column.field, this.options.escape, column.escape)
  125. const value = Utils.calculateObjectValue(column,
  126. column.printFormatter || column.formatter,
  127. [value_, row, i], value_)
  128. return typeof value === 'undefined' || value === null ?
  129. this.options.undefinedText : value
  130. }
  131. const buildTable = (data, columnsArray) => {
  132. const dir = this.$el.attr('dir') || 'ltr'
  133. const html = [`<table dir="${dir}"><thead>`]
  134. for (const columns of columnsArray) {
  135. html.push('<tr>')
  136. for (let h = 0; h < columns.length; h++) {
  137. if (canPrint(columns[h])) {
  138. html.push(
  139. `<th
  140. ${Utils.sprintf(' rowspan="%s"', columns[h].rowspan)}
  141. ${Utils.sprintf(' colspan="%s"', columns[h].colspan)}
  142. >${columns[h].title}</th>`)
  143. }
  144. }
  145. html.push('</tr>')
  146. }
  147. html.push('</thead><tbody>')
  148. const notRender = []
  149. if (this.mergedCells) {
  150. for (let mc = 0; mc < this.mergedCells.length; mc++) {
  151. const currentMergedCell = this.mergedCells[mc]
  152. for (let rs = 0; rs < currentMergedCell.rowspan; rs++) {
  153. const row = currentMergedCell.row + rs
  154. for (let cs = 0; cs < currentMergedCell.colspan; cs++) {
  155. const col = currentMergedCell.col + cs
  156. notRender.push(`${row},${col}`)
  157. }
  158. }
  159. }
  160. }
  161. for (let i = 0; i < data.length; i++) {
  162. html.push('<tr>')
  163. const columns = columnsArray.flat(1)
  164. columns.sort((c1, c2) => {
  165. return c1.colspanIndex - c2.colspanIndex
  166. })
  167. for (let j = 0; j < columns.length; j++) {
  168. if (columns[j].colspanGroup > 0) continue
  169. let rowspan = 0
  170. let colspan = 0
  171. if (this.mergedCells) {
  172. for (let mc = 0; mc < this.mergedCells.length; mc++) {
  173. const currentMergedCell = this.mergedCells[mc]
  174. if (currentMergedCell.col === j && currentMergedCell.row === i) {
  175. rowspan = currentMergedCell.rowspan
  176. colspan = currentMergedCell.colspan
  177. }
  178. }
  179. }
  180. if (
  181. canPrint(columns[j]) &&
  182. (
  183. !notRender.includes(`${i},${j}`) ||
  184. rowspan > 0 && colspan > 0
  185. )
  186. ) {
  187. if (rowspan > 0 && colspan > 0) {
  188. html.push(`<td ${Utils.sprintf(' rowspan="%s"', rowspan)} ${Utils.sprintf(' colspan="%s"', colspan)}>`, formatValue(data[i], i, columns[j]), '</td>')
  189. } else {
  190. html.push('<td>', formatValue(data[i], i, columns[j]), '</td>')
  191. }
  192. }
  193. }
  194. html.push('</tr>')
  195. }
  196. html.push('</tbody>')
  197. if (this.options.showFooter) {
  198. html.push('<footer><tr>')
  199. for (const columns of columnsArray) {
  200. for (let h = 0; h < columns.length; h++) {
  201. if (canPrint(columns)) {
  202. const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr'))
  203. const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '')
  204. html.push(`<th>${footerValue}</th>`)
  205. }
  206. }
  207. }
  208. html.push('</tr></footer>')
  209. }
  210. html.push('</table>')
  211. return html.join('')
  212. }
  213. const sortRows = (data, colName, sortOrder) => {
  214. if (!colName) {
  215. return data
  216. }
  217. let reverse = sortOrder !== 'asc'
  218. reverse = -(+reverse || -1)
  219. return data.sort((a, b) => reverse * a[colName].localeCompare(b[colName]))
  220. }
  221. const filterRow = (row, filters) => {
  222. for (let index = 0; index < filters.length; ++index) {
  223. if (row[filters[index].colName] !== filters[index].value) {
  224. return false
  225. }
  226. }
  227. return true
  228. }
  229. const filterRows = (data, filters) => data.filter(row => filterRow(row, filters))
  230. const getColumnFilters = columns => !columns || !columns[0] ? [] : columns[0].filter(col => col.printFilter).map(col => ({
  231. colName: col.field,
  232. value: col.printFilter
  233. }))
  234. data = filterRows(data, getColumnFilters(this.options.columns))
  235. data = sortRows(data, this.options.printSortColumn, this.options.printSortOrder)
  236. const table = buildTable(data, this.options.columns)
  237. const newWin = window.open('')
  238. const calculatedPrintPage = Utils.calculateObjectValue(this, this.options.printPageBuilder, [table], printPageBuilderDefault(table))
  239. newWin.document.write(calculatedPrintPage)
  240. newWin.document.close()
  241. newWin.focus()
  242. newWin.print()
  243. newWin.close()
  244. }
  245. }