You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

149 lines
3.9 KiB

import ExcelJS from 'exceljs/dist/es5/exceljs.browser'
import { mergeCells, saveAsExcel } from './utils'
import { WIDTH_RATIO } from './constants'
import plugins from './plugins'
const PLUGIN_FUNCS = ['workbookCreated', 'worksheetCreated', 'worksheetCompleted', 'workcellCreated']
const DEFAULT_WORKBOOK_OPTIONS = {
views: [{
x: 0, y: 0, width: 10000, height: 20000,
firstSheet: 0, activeTab: 1, visibility: 'visible'
}]
}
const DEFAULT_OPTIONS = {
workbook: DEFAULT_WORKBOOK_OPTIONS,
widthRatio: WIDTH_RATIO,
plugins: [...Object.values(plugins)]
}
export default class Table2Excel {
constructor (selector = 'table', options = {}) {
this.tables = Array.from(
typeof selector === 'string'
? document.querySelectorAll(selector)
: selector
)
this.options = Object.assign({}, DEFAULT_OPTIONS, options)
this.plugins = {}
PLUGIN_FUNCS.forEach(funName => {
this.plugins[funName] = this.options.plugins.filter(plugin => plugin[funName]).map(plugin => plugin[funName])
})
this.pluginContext = {}
}
_invokePlugin (func, context = {}) {
this.pluginContext = Object.assign({}, this.pluginContext, context)
this.plugins[func].forEach(handler => handler.call(this, this.pluginContext))
}
toExcel () {
const { tables, options } = this
const workbook = new ExcelJS.Workbook() // create workbook
Object.assign(workbook, options)
// workbookCreated plugins
this._invokePlugin('workbookCreated', { workbook, tables })
tables.forEach((table, index) => {
const worksheet = workbook.addWorksheet(`Sheet ${index + 1}`)
// worksheetCreated plugins
this._invokePlugin('worksheetCreated', { worksheet, table })
this.toSheet(table, worksheet)
// worksheetCompleted plugins
this._invokePlugin('worksheetCompleted', { worksheet, table })
})
return this.workbook = workbook
}
toSheet (table, worksheet) {
// get total cols and rows
const totalRows = table.rows.length
let totalCols = 0
if (table.rows.length > 0) {
for (let i = 0; i < table.rows[0].cells.length; i++) {
totalCols += table.rows[0].cells[i].colSpan
}
}
const cells = []
Array.from(table.rows).forEach(row => {
Array.from(row.cells).forEach(cell => {
cells.push({
rowRange: {},
colRange: {},
el: cell
})
})
})
// create matrix
const helperMatrix = []
for (let r = 0; r < totalRows; r++) {
const row = []
for (let c = 0; c < totalCols; c++) {
row.push({ cell: null })
}
helperMatrix.push(row)
}
// mark matrix
let cursor = 0
for (let r = 0; r < totalRows; r++) {
for (let c = 0; c < totalCols; c++) {
// skip if current matrix unit is already assigned
if (helperMatrix[r][c].cell) {
continue
}
// assign cell to current matrix unit
const cell = cells[cursor++]
const { rowSpan, colSpan } = cell.el
cell.rowRange = { from: r, to: r }
cell.colRange = { from: c, to: c }
for (let y = r; y < r + rowSpan; y++) {
for (let x = c; x < c + colSpan; x++) {
helperMatrix[y][x].cell = cell
cell.colRange.to = x
cell.rowRange.to = y
}
}
}
}
// read matrix to sheet
cells.forEach(cell => {
const { rowRange, colRange, el } = cell
const { innerText } = el
const workcell = mergeCells(worksheet, colRange.from, rowRange.from, colRange.to, rowRange.to)
const cellStyle = getComputedStyle(el)
workcell.value = innerText
// workcellCreated
this._invokePlugin('workcellCreated', { workcell, cell: el, rowRange, colRange, cellStyle })
})
}
export (fileName, ext) {
if (!this.workbook) {
this.toExcel()
}
saveAsExcel(this.workbook, fileName, ext)
}
}