天天看点

bootstrap-table 打印动态数据组合列

前言:bootstrap-table默认的打印组件对于数据组合表头并不是很合适,打印组合列会出现各种各样的问题,于是对bootstrap-table-print进行升级。

先看结果:

bootstrap-table 打印动态数据组合列
bootstrap-table 打印动态数据组合列

说到底,是因为插件的原理是,将table进行重组重新渲染,渲染的时候因为合并列造成合并的数据无法渲染,于是小小的重写了一下。

/**
 * @update sunck
 */

const Utils = $.fn.bootstrapTable.utils

function printPageBuilderDefault (table) {
  return `
  <html>
  <head>
  <style type="text/css" media="print">
  @page {
    size: auto;
    margin: 25px 0 25px 0;
  }
  </style>
  <style type="text/css" media="all">
  table {
    border-collapse: collapse;
    font-size: 12px;
  }
  table, th, td {
    border: 1px solid grey;
  }
  th, td {
    text-align: center;
    vertical-align: middle;
  }
  p {
    font-weight: bold;
    margin-left:20px;
  }
  table {
    width:94%;
    margin-left:3%;
    margin-right:3%;
  }
  div.bs-table-print {
    text-align:center;
  }
  </style>
  </head>
  <title>Print Table</title>
  <body>

  <div class="bs-table-print">${table}</div>
  </body>
  </html>`
}

$.extend($.fn.bootstrapTable.defaults, {
  showPrint: false,
  printAsFilteredAndSortedOnUI: true,
  printSortColumn: undefined,
  printSortOrder: 'asc',
  printPageBuilder (table) {
    return printPageBuilderDefault(table)
  }
})

$.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
  printFilter: undefined,
  printIgnore: false,
  printFormatter: undefined
})

$.extend($.fn.bootstrapTable.defaults.icons, {
  print: {
    bootstrap3: 'glyphicon-print icon-share',
    'bootstrap-table': 'icon-printer'
  }[$.fn.bootstrapTable.theme] || 'fa-print'
})

$.BootstrapTable = class extends $.BootstrapTable {
  init (...args) {
    super.init(...args)

    if (!this.options.showPrint) {
      return
    }

    this.mergedCells = []
  }

  initToolbar (...args) {
    this.showToolbar = this.showToolbar || this.options.showPrint

    super.initToolbar(...args)

    if (!this.options.showPrint) {
      return
    }

    const $btnGroup = this.$toolbar.find('>.columns')
    let $print = $btnGroup.find('button.bs-print')

    if (!$print.length) {
      $print = $(`
        <button class="${this.constants.buttonsClass} bs-print" type="button">
        <i class="${this.options.iconsPrefix} ${this.options.icons.print}"></i>
        </button>`
      ).appendTo($btnGroup)
    }

    $print.off('click').on('click', () => {
      this.doPrint(this.options.printAsFilteredAndSortedOnUI ?
        this.getData() : this.options.data.slice(0))
    })
  }

  mergeCells (options) {
    super.mergeCells(options)

    if (!this.options.showPrint) {
      return
    }

    let col = this.getVisibleFields().indexOf(options.field)

    if (Utils.hasDetailViewIcon(this.options)) {
      col += 1
    }

    this.mergedCells.push({
      row: options.index,
      col,
      rowspan: options.rowspan || 1,
      colspan: options.colspan || 1
    })
  }

  doPrint (data) {
    const formatValue = (row, i, column) => {
      const value = Utils.calculateObjectValue(column, column.printFormatter,
        [row[column.field], row, i], row[column.field])

      return typeof value === 'undefined' || value === null
        ? this.options.undefinedText : value
    }

    /**
     * 格式化列
     * @param columnsArray
     */
    const formatColumnsArray = (columnsArray) =>{
      let volimnsArray = [];
      for (let i = 0; i < columnsArray[0].length; i++) {
        let spanNum = columnsArray[0][i].colspan ? columnsArray[0][i].colspan : 1;
        for (let j = 0; j < spanNum; j++) {
          volimnsArray.push("");
        }
      }

      for (let i = 0; i < columnsArray.length; i++) {
        let volimnsArrayNum = 0;
        for (let j = 0; j < columnsArray[i].length; j++) {
          let column = columnsArray[i][j];
          if(!column.printIgnore && column.field !=undefined && (i == columnsArray.length-1 || column.rowspan == columnsArray.length - i)){
            if(volimnsArray.length > volimnsArrayNum ){
              if(volimnsArray[volimnsArrayNum] == ""){
                volimnsArray[volimnsArrayNum] = column;
                console.log(column.title);
              }else{
                for (let k = volimnsArrayNum+1; k < volimnsArray.length; k++) {
                  if(volimnsArray[k] == ""){
                    volimnsArray[k] = column;
                    volimnsArrayNum = k;
                    break;
                  }
                }
              }
            }
            volimnsArrayNum++;
          }else{
            volimnsArrayNum =volimnsArrayNum + column.colspan
          }
        }
      }
      return volimnsArray;
    }


    const buildTable = (data, columnsArray) => {
      const dir = this.$el.attr('dir') || 'ltr'
      const html = [`<table dir="${dir}"><thead>`]

      for (const columns of columnsArray) {
        html.push('<tr>')
        for (let h = 0; h < columns.length; h++) {
          if (!columns[h].printIgnore) {
            html.push(
              `<th
              ${Utils.sprintf(' rowspan="%s"', columns[h].rowspan)}
              ${Utils.sprintf(' colspan="%s"', columns[h].colspan)}
              >${columns[h].title}</th>`)
          }
        }
        html.push('</tr>')
      }

      html.push('</thead><tbody>')

      const dontRender = []
      if (this.mergedCells) {
        for (let mc = 0; mc < this.mergedCells.length; mc++) {
          const currentMergedCell = this.mergedCells[mc]
          for (let rs = 0; rs < currentMergedCell.rowspan; rs++) {
            const row = currentMergedCell.row + rs
            for (let cs = 0; cs < currentMergedCell.colspan; cs++) {
              const col = currentMergedCell.col + cs
              dontRender.push(row + ',' + col)
            }
          }
        }
      }


      let columns = formatColumnsArray(columnsArray)//使用格式化后的数据操作
      for (let i = 0; i < data.length; i++) {
        html.push('<tr>')
          for (let j = 0; j < columns.length; j++) {
            let rowspan = 0
            let colspan = 0
            if (this.mergedCells) {
              for (let mc = 0; mc < this.mergedCells.length; mc++) {
                const currentMergedCell = this.mergedCells[mc]
                if (currentMergedCell.col === j && currentMergedCell.row === i) {
                  rowspan = currentMergedCell.rowspan
                  colspan = currentMergedCell.colspan
                }
              }
            }

            if (
              !columns[j].printIgnore && columns[j].field != undefined
              && (
                !dontRender.includes(i + ',' + j)
                || (rowspan > 0 && colspan > 0)
              )
            ) {
             // console.log("处理当前的id+"+columns[j].title);
              if (rowspan > 0 && colspan > 0) {
                html.push(`<td ${Utils.sprintf(' rowspan="%s"', rowspan)} ${Utils.sprintf(' colspan="%s"', colspan)}>`, formatValue(data[i], i, columns[j]), '</td>')
              } else {
                html.push('<td>', formatValue(data[i], i, columns[j]), '</td>')
              }
            }
          }
        html.push('</tr>')
      }

      html.push('</tbody>')
      if (this.options.showFooter) {
        html.push('<footer><tr>')
        for (let h = 0; h < columns.length; h++) {
          if (!columns[h].printIgnore) {
            const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr'))
            const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '')
            html.push(`<th>${footerValue}</th>`)
          }
        }

        /*for (const columns of columnsArray) {
          for (let h = 0; h < columns.length; h++) {
            if (!columns[h].printIgnore) {
              const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr'))
              const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '')
              html.push(`<th>${footerValue}</th>`)
            }
          }
        }*/

        html.push('</tr></footer>')
      }
      html.push('</table>')
      return html.join('')
    }

    const sortRows = (data, colName, sortOrder) => {
      if (!colName) {
        return data
      }
      let reverse = sortOrder !== 'asc'
      reverse = -((+reverse) || -1)
      return data.sort((a, b) => reverse * (a[colName].localeCompare(b[colName])))
    }

    const filterRow = (row, filters) => {
      for (let index = 0; index < filters.length; ++index) {
        if (row[filters[index].colName] !== filters[index].value) {
          return false
        }
      }
      return true
    }

    const filterRows = (data, filters) => data.filter(row => filterRow(row, filters))
    const getColumnFilters = columns => !columns || !columns[0] ? [] : columns[0].filter(col => col.printFilter).map(col => ({
      colName: col.field,
      value: col.printFilter
    }))

    data = filterRows(data, getColumnFilters(this.options.columns))
    data = sortRows(data, this.options.printSortColumn, this.options.printSortOrder)
    const table = buildTable(data, this.options.columns)
    const newWin = window.open('')
    newWin.document.write(this.options.printPageBuilder.call(this, table))
    newWin.document.close()
    newWin.focus()
    newWin.print()
    newWin.close()
  }
}
           

将官方的文件替换即可。

继续阅读