UNPKG

@opentiny/vue-renderless

Version:

An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.

502 lines (501 loc) 16.8 kB
import "../../chunk-G2ADBYYC.js"; import { extend, browserInfo } from "@opentiny/utils"; const isIE = browserInfo.name === "ie"; const rgbRegExp = /^rgba?\((\d+),\s(\d+),\s(\d+)([\s\S]*)\)$/; const hexRegExp = /^#([a-zA-Z0-9]{3}|[a-zA-Z0-9]{6})$/; function computeColor(rgbColor) { const rgb = rgbRegExp.exec(rgbColor).slice(1, 4); return parseInt(rgb[0]).toString(16) + parseInt(rgb[1]).toString(16) + parseInt(rgb[2]).toString(16); } function getBgc(dom) { const getComputedStyle = window.getComputedStyle; const backgroundColor = isIE ? dom.currentStyle.backgroundColor : getComputedStyle(dom).backgroundColor; if (rgbRegExp.test(backgroundColor)) { return computeColor(backgroundColor); } else if (hexRegExp.test(backgroundColor)) { const bgc = backgroundColor.slice(1); if (bgc.length === 3) { return bgc.split("").map((s) => s + s).join(""); } return bgc; } return "ffffff"; } function funcFromCodePoint() { let codeUnitArr = []; let codeLength = 0; let resultStr = ""; for (let i = 0, length = arguments.length; i !== length; ++i) { let cp = Number(arguments[i]); if (!(cp < 1114111 && cp >>> 0 === cp)) { throw new RangeError("Invalid code point: " + cp); } if (cp <= 65535) { codeLength = codeUnitArr.push(cp); } else { cp -= 65536; codeLength = codeUnitArr.push((cp >> 10) + 55296, cp % 1024 + 56320); } if (codeLength >= 16383) { resultStr += String.fromCharCode.apply(null, codeUnitArr); codeUnitArr.length = 0; } } return resultStr + String.fromCharCode.apply(null, codeUnitArr); } const defaultOptions = { plugins: { XLSX: null, // xlsx 插件 XLSXX: null, // xlsx-style 插件 FileSaver: null // FileSaver 插件 }, table: { sheetName: "tiny-sheet", formatMethod: ({ value, type }) => ({ value, type }), styleMethod: ({ style }) => style, rowHeightMethod: ({ height }) => height, columnWidthMethod: ({ width }) => width, mergesMethod: (merges) => merges } }; function s2ab(s) { const buf = new ArrayBuffer(s.length); const view = new Uint8Array(buf); for (let i = 0; i !== s.length; i++) { view[i] = s.charCodeAt(i) & 255; } return buf; } function adjustHeight(hpx) { const n = parseInt(hpx / 36); return hpx - 10 * n; } function initHeaderDatas({ datas, headerRowCount, headerTrs }) { let maxColSpanCount = [-1, 0]; for (let i = 0; i < headerRowCount; i++) { const childNodes = headerTrs[i].childNodes; let colSpanCount = 0; for (let j = 0; j < childNodes.length; j++) { if (~childNodes[j].className.split(/\s/).indexOf("col__gutter")) { break; } colSpanCount += childNodes[j].colSpan; } if (colSpanCount > maxColSpanCount[1]) { maxColSpanCount[0] = i; maxColSpanCount[1] = colSpanCount; } } for (let i = 0; i < headerRowCount; i++) { datas.push([]); for (let j = 0; j < maxColSpanCount[1]; j++) { datas[i].push(""); } } } function buildHeaderMerges({ datas, headerTrs, rowHeightMethod, ths, ws }) { for (let i = 0; i < headerTrs.length; i++) { const headerTrRect = headerTrs[i].getBoundingClientRect(); const childNodes = headerTrs[i].childNodes; let rowHeight = Math.round(headerTrRect.height); let lastColSpan = 0; rowHeight = rowHeightMethod ? rowHeightMethod({ rowIndex: i, height: rowHeight }) : rowHeight; ws["!rows"].push({ hpx: adjustHeight(rowHeight) }); for (let j = 0; j < childNodes.length; j++) { if (~childNodes[j].className.split(/\s/).indexOf("col__gutter")) { break; } ths.push(childNodes[j]); const colSpan = childNodes[j].colSpan; const rowSpan = childNodes[j].rowSpan; const textContent = childNodes[j].textContent; if (colSpan > 1) { ws["!merges"].push({ s: { r: i, c: lastColSpan }, e: { r: i, c: lastColSpan + colSpan - 1 } }); } if (rowSpan > 1) { ws["!merges"].push({ s: { r: i, c: lastColSpan }, e: { r: i + rowSpan - 1, c: lastColSpan } }); } if (i !== headerTrs.length - 1) { datas[i].splice(lastColSpan, 1, textContent); } lastColSpan += colSpan; } } } function buildColids({ $table, colids, columnWidthMethod, datas, ths, ws }) { const getColWidth = (column, level) => { if (column.children) { for (let i = 0; i < column.children.length; i++) { getColWidth(column.children[i], level + 1); } } else { const colid = column.id; for (let i = 0; i < ths.length; i++) { if (ths[i].dataset.colid === colid) { colids.push(colid); const thRect = ths[i].getBoundingClientRect(); let columnWidth = Math.round(thRect.width); columnWidth = columnWidthMethod ? columnWidthMethod({ columnIndex: colids.length - 1, width: columnWidth }) : columnWidth; ws["!cols"].push({ wch: Math.round(columnWidth / 10) }); datas[level].splice( colids.length - 1, 1, typeof column.title === "string" ? column.title : ths[i].textContent ); break; } } } }; const collectColumn = $table.collectColumn; for (let i = 0; i < collectColumn.length; i++) { getColWidth(collectColumn[i], 0); } } function buildHeader({ $table, colids, datas, headerRowCount, headerTrs, opts, ws }) { if (headerRowCount === 0) { return; } const rowHeightMethod = opts.table.rowHeightMethod; const columnWidthMethod = opts.table.columnWidthMethod; const ths = []; initHeaderDatas({ datas, headerRowCount, headerTrs }); buildHeaderMerges({ datas, headerTrs, rowHeightMethod, ths, ws }); buildColids({ $table, colids, columnWidthMethod, datas, ths, ws }); } function updateRowsDatas({ childNodes, colids, datas, i, offset, rowHeight, rowHeightMethod, ws }) { rowHeight = rowHeightMethod ? rowHeightMethod({ rowIndex: i + offset, height: rowHeight }) : rowHeight; ws["!rows"].push({ hpx: adjustHeight(rowHeight) }); datas.push([]); for (let j = 0; j < colids.length; j++) { let rowTd = null; let textContent = ""; for (let k = 0; k < childNodes.length; k++) { if (childNodes[k].dataset.colid === colids[j]) { rowTd = childNodes[k]; break; } } if (rowTd) { textContent = rowTd.textContent; rowTd = null; } datas[offset + i].push(textContent); } } function updateMerges({ childNodes, colids, i, offset, ws }) { for (let j = 0; j < childNodes.length; j++) { const colSpan = childNodes[j].colSpan; const rowSpan = childNodes[j].rowSpan; const colid = childNodes[j].dataset.colid; const sc = colids.indexOf(colid); const sr = offset + i; if (colSpan > 1 && rowSpan > 1) { ws["!merges"].push({ s: { r: sr, c: sc }, e: { r: sr + rowSpan - 1, c: sc + colSpan - 1 } }); } else if (colSpan > 1) { ws["!merges"].push({ s: { r: sr, c: sc }, e: { r: sr, c: sc + colSpan - 1 } }); } else if (rowSpan > 1) { ws["!merges"].push({ s: { r: sr, c: sc }, e: { r: sr + rowSpan - 1, c: sc } }); } } } function buildBody({ bodyRowCount, bodyTrs, colids, datas, headerRowCount, opts, ws }) { if (bodyRowCount === 0) { return; } const rowHeightMethod = opts.table.rowHeightMethod; const offset = headerRowCount; for (let i = 0; i < bodyTrs.length; i++) { const bodyTrRect = bodyTrs[i].getBoundingClientRect(); const childNodes = bodyTrs[i].childNodes; let rowHeight = Math.round(bodyTrRect.height); updateRowsDatas({ colids, childNodes, i, datas, rowHeight, rowHeightMethod, offset, ws }); updateMerges({ childNodes, colids, i, offset, ws }); } } function genExcelColNames() { const excelColNames = []; const f = funcFromCodePoint; for (let i = -1; i < 26; i++) { for (let j = 0; j < 26; j++) { excelColNames.push((i === -1 ? "" : f(65 + i)) + f(65 + j)); } } return excelColNames; } function buildRef({ colids, datas, excelColNames, ws }) { let fullref = ""; if (colids.length > 0 && datas.length > 0) { fullref = "A1:" + excelColNames[colids.length - 1] + datas.length; } ws["!fullref"] = fullref; ws["!ref"] = fullref; } function updateCellStyle({ bodyRowCount, bodyTrBgcArr, footerTrBgc, headerRowCount, headerWrapperBgc, rowIndex, showBorder, style }) { style.font = { name: "Microsoft YaHei", sz: 12, color: { rgb: "000000" } }; if (rowIndex < headerRowCount) { style.fill = { fgColor: { rgb: headerWrapperBgc } }; style.font.bold = true; } else if (rowIndex < headerRowCount + bodyRowCount) { style.fill = { fgColor: { rgb: bodyTrBgcArr[rowIndex - headerRowCount] } }; } else { style.fill = { fgColor: { rgb: footerTrBgc } }; } if (showBorder) { style.border = { top: { style: "thin", color: { rgb: "000000" } }, bottom: { style: "thin", color: { rgb: "000000" } }, left: { style: "thin", color: { rgb: "000000" } }, right: { style: "thin", color: { rgb: "000000" } } }; } style.alignment = { vertical: "center", horizontal: "left", wrapText: false }; } function buildDatas({ showBorder, bodyRowCount, bodyTrBgcArr, headerRowCount, colids, datas, footerTrBgc, headerWrapperBgc, excelColNames, opts, $table, ws }) { if (datas.length === 0) { return; } const styleMethod = opts.table.styleMethod; const formatMethod = opts.table.formatMethod; const fullColumn = $table.getTableColumn().fullColumn; const isIndexColData = (i, j, indexColIndex2, headerRowCount2, bodyRowCount2) => indexColIndex2 === j && i >= headerRowCount2 && i < headerRowCount2 + bodyRowCount2; let indexColIndex; for (let i = 0; i < fullColumn.length; i++) { if (fullColumn[i].type === "index") { indexColIndex = colids.indexOf(fullColumn[i].id); break; } } for (let i = 0; i < datas.length; i++) { for (let j = 0; j < datas[i].length; j++) { let type = isIndexColData(i, j, indexColIndex, headerRowCount, bodyRowCount) ? "n" : "s"; let value = isIndexColData(i, j, indexColIndex, headerRowCount, bodyRowCount) ? parseInt(datas[i][j]) : datas[i][j].trim(); let style = {}; updateCellStyle({ bodyRowCount, bodyTrBgcArr, columnIndex: j, footerTrBgc, headerRowCount, headerWrapperBgc, rowIndex: i, showBorder, style }); if (styleMethod) { style = styleMethod({ rowIndex: i, columnIndex: j, style }); } if (formatMethod) { const ret = formatMethod({ rowIndex: i, columnIndex: j, value, type }); type = ret.type; value = ret.value; } ws[excelColNames[j] + (i + 1)] = { t: type, v: value, s: style }; } } } function buildWb({ XLSXX, opts, ws }) { ws = ws["!cols"].length === 0 || ws["!rows"].length === 0 ? {} : ws; const sheetName = opts.table.sheetName; const merges = ws["!merges"]; if (merges) { const mergesMethod = opts.table.mergesMethod; ws["!merges"] = mergesMethod ? mergesMethod(merges) : merges; } const wb = { Props: { Application: "SheetJS", SheetNames: [sheetName], Worksheets: 1 }, SSF: XLSXX.SSF.get_table(), SheetNames: [sheetName], Sheets: { [sheetName]: ws } }; return wb; } function computeBodyTrBgcArr(bodyTrs, isStripe) { const arr = []; for (let i = 0; i < bodyTrs.length; i++) { arr.push(isStripe ? getBgc(bodyTrs[i]) : "ffffff"); } return arr; } function queryDom($table) { const headerTrs = $table.$el.querySelectorAll(".tiny-grid__header-wrapper.body__wrapper .tiny-grid-header__row"); const bodyTrs = $table.$el.querySelectorAll(".tiny-grid__body-wrapper.body__wrapper .tiny-grid-body__row:not(.group)"); const footerTrs = $table.$el.querySelectorAll(".tiny-grid__footer-wrapper.body__wrapper .tiny-grid-footer__row"); const headerWrapper = $table.$el.querySelector(".tiny-grid__header-wrapper.body__wrapper"); return { bodyTrs, footerTrs, headerTrs, headerWrapper }; } function getTableAttr($table, headerWrapper, bodyTrs) { const showBorder = ~$table.$el.className.split(/\s/).indexOf("tiny-grid__border"); const isStripe = ~$table.$el.className.split(/\s/).indexOf("tiny-grid__stripe"); const headerWrapperBgc = headerWrapper ? getBgc(headerWrapper) : "ffffff"; const bodyTrBgcArr = computeBodyTrBgcArr(bodyTrs, isStripe); const footerTrBgc = "ffffff"; return { showBorder, headerWrapperBgc, bodyTrBgcArr, footerTrBgc }; } function buildColidsByVisibleColumn({ $table, bodyRowCount, bodyTrs, colids, opts, ws }) { if (colids.length > 0 || bodyRowCount === 0) { return; } const columnWidthMethod = opts.table.columnWidthMethod; const tds = []; for (let i = 0; i < bodyTrs.length; i++) { for (let j = 0; j < bodyTrs[i].childNodes.length; j++) { tds.push(bodyTrs[i].childNodes[j]); } } for (let i = 0; i < $table.visibleColumn.length; i++) { let colid = $table.visibleColumn[i].id; for (let j = 0; j < tds.length; j++) { if (tds[j].dataset.colid === colid) { colids.push(colid); const tdRect = tds[j].getBoundingClientRect(); const colSpan = tds[j].colSpan; let columnWidth = Math.round(tdRect.width / colSpan); columnWidth = columnWidthMethod ? columnWidthMethod({ columnIndex: colids.length - 1, width: columnWidth }) : columnWidth; ws["!cols"].push({ wch: Math.round(columnWidth / 10) }); break; } } } } function buildFooter({ bodyRowCount, colids, datas, footerRowCount, footerTrs, headerRowCount, opts, ws }) { if (footerRowCount === 0) { return; } const rowHeightMethod = opts.table.rowHeightMethod; const offset = headerRowCount + bodyRowCount; for (let i = 0; i < footerTrs.length; i++) { const footerTrRect = footerTrs[i].getBoundingClientRect(); const childNodes = footerTrs[i].childNodes; let rowHeight = Math.round(footerTrRect.height); updateRowsDatas({ childNodes, colids, datas, i, offset, rowHeight, rowHeightMethod, ws }); updateMerges({ childNodes, colids, i, offset, ws }); } } function createExcelFromDom($table, opts) { const { XLSXX } = opts.plugins; const { bodyTrs, footerTrs, headerTrs, headerWrapper } = queryDom($table); const { showBorder, headerWrapperBgc, bodyTrBgcArr, footerTrBgc } = getTableAttr($table, headerWrapper, bodyTrs); const headerRowCount = headerTrs.length; const bodyRowCount = bodyTrs.length; const footerRowCount = footerTrs.length; const ws = {}; const datas = []; const colids = []; const excelColNames = genExcelColNames(); ws["!rows"] = []; ws["!cols"] = []; ws["!merges"] = []; buildHeader({ $table, colids, datas, headerRowCount, headerTrs, opts, ws }); buildColidsByVisibleColumn({ $table, bodyRowCount, bodyTrs, colids, opts, ws }); buildBody({ bodyRowCount, bodyTrs, colids, datas, headerRowCount, opts, ws }); buildFooter({ bodyRowCount, colids, datas, footerRowCount, footerTrs, headerRowCount, opts, ws }); buildRef({ colids, datas, excelColNames, ws }); buildDatas({ $table, bodyRowCount, bodyTrBgcArr, colids, datas, excelColNames, footerTrBgc, headerRowCount, headerWrapperBgc, opts, showBorder, ws }); return buildWb({ XLSXX, opts, ws }); } function exportExcel($table, options) { const opts = extend(true, {}, options); opts.plugins = opts.plugins || {}; if (!opts.plugins.XLSX || !opts.plugins.XLSXX || !opts.plugins.FileSaver) { return; } opts.table = opts.table || {}; opts.table.sheetName = opts.table.sheetName || defaultOptions.table.sheetName; opts.table.formatMethod = opts.table.formatMethod || defaultOptions.table.formatMethod; opts.table.styleMethod = opts.table.styleMethod || defaultOptions.table.styleMethod; opts.table.rowHeightMethod = opts.table.rowHeightMethod || defaultOptions.table.rowHeightMethod; opts.table.columnWidthMethod = opts.table.columnWidthMethod || defaultOptions.table.columnWidthMethod; opts.table.mergesMethod = opts.table.mergesMethod || defaultOptions.table.mergesMethod; const wb = createExcelFromDom($table, opts); const { XLSXX, FileSaver } = opts.plugins; const wopts = { bookType: "xlsx", bookSST: false, type: "binary" }; const wbout = XLSXX.write(wb, wopts); FileSaver.saveAs(new Blob([s2ab(wbout)], { type: "" }), opts.table.sheetName + ".xlsx"); } export { exportExcel };