UNPKG

plus-base-on-baosight

Version:

Expansion based on the Baosight methods.

241 lines (235 loc) 7.15 kB
import { nextTick } from 'vue'; import type { ExcelStyle, ExcelRow, ExcelFont, ExcelAlignment, ExcelBorder, ExcelBorders, ColDef } from '@ag-grid-community/core'; type ExcelStyle_ = Omit<ExcelStyle, 'id'>; type ExportStyle = ExcelStyle_ | (() => ExcelStyle_); interface ExportConfigCellContent { value: string | null; type?: 'string' | 'number'; merge?: number; style?: ExportStyle; } interface ExportConfigCell { [key: `cell${number}`]: ExportConfigCellContent; style?: ExportStyle; } interface ExportConfigLine { [key: `line${number}`]: ExportConfigCell; style?: ExportStyle; } interface ExportConfig { top: ExportConfigLine; bottom: ExportConfigLine; } type ExportTopConfig = ExportConfig['top']; type ExportBottomConfig = ExportConfig['bottom']; interface ExportColEvent { export: { setCellStyle: (style: ExcelStyle_) => void; setCellStyleID: (id: string) => void; setHeaderStyle: (style: ExcelStyle_) => void; setHeaderStyleID: (id: string) => void; }; } type ExportCol = ColDef & ExportColEvent; export class AgGridCustomExportManager { #erFormHelper: any = null; #orginStylesTop: ExcelStyle[] = []; #orginStylesBottom: ExcelStyle[] = []; #orginStylesCustom: ExcelStyle[] = []; #soruce: { [key: string]: any }[] = []; #fileName = ''; #gridId = ''; #exportConfig = { sheetName: 'Sheet1', columnKeys: [], prependContent: {}, appendContent: {}, }; constructor(erFormHelper: any, grid: string, fileName?: string) { this.#erFormHelper = erFormHelper; this.#gridId = grid; fileName && (this.#fileName = fileName); } #api() { const api = this.#erFormHelper?.getGridApi(this.#gridId) ?? null; return api; } #formatParams(type: 'top' | 'bottom', params: ExportConfigLine) { let res = [] as any[]; let styles = deepClone(params.style ?? {}); Object.entries(params).map(([line, lineCfg]: [string, ExportConfigCell]) => { // pos 是从1开始的 const pos_line = Number.parseInt(line.split('line')[1]); // 处理cell let cells: any[] = []; Object.entries(lineCfg).map(([cell, cellCfg]: [string, ExportConfigCellContent]) => { const pos_cell = Number.parseInt(cell.split('cell')[1]); // 设置单元格内容数据格式 const cellContent: { [key: string]: any } = {}; // 单元格值 const valType = cellCfg.type === 'number' ? 'Number' : 'String'; cellContent['data'] = { type: valType, value: valType === 'String' ? String(cellCfg.value) : Number(cellCfg.value), }; // 设置单元格样式 if (cellCfg.style) { const id = `-auto-style-${type === 'top' ? 'top' : 'bottom'}-cell${pos_cell}`; if (typeof cellCfg.style === 'object') { styles = deepMerge(styles, cellCfg.style); } if (typeof cellCfg.style === 'function') { styles = deepMerge(styles, cellCfg.style()); } if (type === 'top') { this.#orginStylesTop.push({ ...styles, id }); } else { this.#orginStylesBottom.push({ ...styles, id }); } cellContent['styleId'] = id; } // 横向合并单元格 if (cellCfg.merge) { cellContent['mergeAcross'] = cellCfg.merge - 1; } cells[pos_cell - 1] = cellContent; }); // 填充undefined cells = Array.from(cells).map((v) => (!v ? { cells: [] } : v)); res[pos_line - 1] = { cells }; }); // 填充undefined res = Array.from(res).map((v) => (!v ? { cells: [] } : v)); return res; } addLineTop(params: ExportTopConfig) { this.#exportConfig.prependContent = this.#formatParams('top', params); } addLineBottom(params: ExportBottomConfig) { this.#exportConfig.appendContent = this.#formatParams('bottom', params); } addStyles(...styles: ExcelStyle[]) { const res = { status: 0, msg: '' }; const ids = this.#orginStylesTop .concat(this.#orginStylesBottom) .concat(this.#orginStylesCustom) .map((style) => style.id); styles.map((style) => { if (ids.includes(style.id)) { res.status--; res.msg += `ID[${style.id}]已存在;`; } else { this.#orginStylesCustom.push(style); } }); return res; } #addCol(col: ColDef) { const col_ = col as any; col_['export'] = { setCellStyleID: (id: string) => { col.cellClass = id; }, setHeaderStyleID: (id: string) => { col.headerClass = id; }, setHeaderStyle: (style: ExcelStyle) => { const id = `-auto-style-head-${col.field}`; this.addStyles({ ...style, id }); col.headerClass = id; }, setCellStyle: (style: ExcelStyle) => { const id = `-auto-style-cell-${col.field}`; this.addStyles({ ...style, id }); col.cellClass = id; }, }; return col_ as ExportCol; } setColumnStyle(callback: (col: ExportCol) => void) { this.#erFormHelper.setGridColumnOptions('exportGrid', (col: ColDef) => { callback.call(window, this.#addCol(col)); }); } createStyles(styles: ExcelStyle_) { return styles; } getStyles() { return this.#orginStylesTop.concat(this.#orginStylesBottom).concat(this.#orginStylesCustom); } setSoruce(source: { [key: string]: any }[]) { const api = this.#api(); if (api) { this.#soruce = source; return true; } return false; } clearSource() { const api = this.#api(); if (api) { this.#soruce = []; return true; } return false; } setFileName(fileName: string) { this.#fileName = fileName; } export(sheetName = 'Sheet1'): Promise<boolean> { return new Promise((resolve, reject) => { nextTick(async () => { const api = this.#api(); // 清空原本数据源 api.setRowData([]); api.setRowData(this.#soruce); this.#exportConfig.sheetName = sheetName; this.#exportConfig.columnKeys = this.#erFormHelper.getGridColumnFields(this.#gridId, 'Array'); const exportData = api?.getSheetDataForExcel(this.#exportConfig); if (exportData) { api.exportMultipleSheetsAsExcel({ data: [exportData], fileName: `${this.#fileName ?? `export_${new Date().getTime()}`}.xlsx`, }); resolve(true); } reject(false); }); }); } } export type { ExcelStyle_, ExcelFont, ExcelAlignment, ExcelBorder, ExcelBorders }; function deepMerge(obj1: { [key: string]: any }, obj2?: { [key: string]: any }) { if (obj2) { const result = deepClone(obj1); for (const key in obj2) { const value = obj2[key]; const isNorObj = typeof obj2[key] === 'object' && obj2[key] !== null; const isArr = Array.isArray(value); const isData = value instanceof Date; if (value && isNorObj && !isArr && !isData) { result[key] = deepMerge(result[key] || {}, obj2[key]); } else { result[key] = value; } } return result; } else { return deepClone(obj1); } } function deepClone(obj: { [key: string]: any }, hash = new WeakMap()) { if (obj === null) return null; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const cloneObj: { [key: string]: any } = Array.isArray(obj) ? [] : {}; hash.set(obj, cloneObj); for (const key in obj) { if (obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key], hash); } } return cloneObj; }