1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16export class ExcelFormater { 17 static tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>'; 18 static base64 = function (s: any) { 19 return window.btoa(unescape(encodeURIComponent(s))); 20 }; 21 22 static format(s: any, c: any): string { 23 return s.replace(/{(\w+)}/g, function (m: any, p: any) { 24 return c[p]; 25 }); 26 } 27 28 static createExcelRow(columns: any[], data: any): string { 29 let rowsXML = ''; 30 rowsXML += '<Row>'; 31 for (let k = 0; k < columns.length; k++) { 32 let dataIndex = columns[k].getAttribute('data-index'); 33 let columnName = columns[k].getAttribute('title'); 34 if (columnName == '') { 35 columnName = dataIndex; 36 } 37 let ctx = { 38 attributeStyleID: '', 39 nameType: 'String', 40 data: data ? data[dataIndex] || '' : columnName, 41 attributeFormula: '', 42 }; 43 rowsXML += this.format(this.tmplCellXML, ctx); 44 } 45 rowsXML += '</Row>'; 46 if (data && data.children != undefined && data.children.length > 0) { 47 data.children.forEach((child: any) => { 48 rowsXML += this.createExcelRow(columns, child); 49 }); 50 } 51 return rowsXML; 52 } 53 54 static addImage(baseStr: string) { 55 return `<Row>${this.format(this.tmplCellXML, { 56 attributeStyleID: '', 57 nameType: 'String', 58 data: `<div><img src="${baseStr}"></img></div>`, 59 attributeFormula: '', 60 })}</Row>`; 61 } 62 63 static testExport(dataSource: { columns: any[]; tables: any[]; sheetName: string }[], fileName: string) { 64 this.tablesToHtmlExcelMultipleSheet(dataSource, fileName); 65 } 66 67 static tablesToHtmlExcelMultipleSheet( 68 dataSource: { columns: any[]; tables: any[]; sheetName: string }[], 69 fileName: string, 70 image?: string 71 ) { 72 let sheets: any[] = []; 73 dataSource.forEach((data) => { 74 sheets.push(this.createTableData(data.columns, data.tables, image)); 75 }); 76 this.tablesToExcelTestSheet(sheets, fileName, dataSource); 77 } 78 79 static createTableData(columns: any[], dataSource: any[], image?: string) { 80 let tableData = ''; 81 let columnDatas = columns.map((column) => { 82 let dataIndex = column.getAttribute('data-index'); 83 let columnName = column.getAttribute('title'); 84 if (columnName == '') { 85 columnName = dataIndex; 86 } 87 return { 88 columnName: columnName, 89 dataIndex: dataIndex, 90 }; 91 }); 92 tableData += this.createTHead( 93 columnDatas.map((item) => { 94 return item.columnName; 95 }) 96 ); 97 let columnDataIndexes = columnDatas.map((item) => item.dataIndex); 98 dataSource.forEach((data, index) => { 99 if (index == 0 && image) { 100 tableData += this.createTableRow(columnDataIndexes, data, image); 101 } else { 102 tableData += this.createTableRow(columnDataIndexes, data); 103 } 104 }); 105 return tableData; 106 } 107 108 static createTHead(columns: any[]) { 109 let header = '<thead>'; 110 columns.forEach((column) => { 111 header += `<td>${column}</td>`; 112 }); 113 header += '</thrad>'; 114 return header; 115 } 116 117 static createTableRow(columns: any[], data: any, image?: any) { 118 let childrenData = ''; 119 if (data.children !== undefined) { 120 data.children.forEach((child: any) => { 121 if (child) { 122 childrenData += this.createTableRow(columns, child); 123 } 124 }); 125 } 126 return `<tr>${columns 127 .map((column) => { 128 return `<td>${(data[column] + '').replace('μ', 'u')}</td>` || ''; 129 }) 130 .join('')}${image ? `<td><div><img src="${image}"></img></div></td>` : ''}</tr>${childrenData}`; 131 } 132 133 static tablesToExcelTestSheet( 134 tables: any[], 135 filename: string, 136 dataSource: { columns: any[]; tables: any[]; sheetName: string }[] 137 ) { 138 let uri = 'data:application/vnd.ms-excel;base64,', 139 html_start = `<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">`, 140 template_ExcelWorksheet = `<x:ExcelWorksheet><x:Name>{SheetName}</x:Name><x:WorksheetSource HRef="sheet{SheetIndex}.htm"/><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>`, 141 template_ListWorksheet = `<o:File HRef="sheet{SheetIndex}.htm"/>`, 142 template_HTMLWorksheet = 143 ` 144------=_NextPart_dummy 145Content-Location: sheet{SheetIndex}.htm 146Content-Type: text/html; charset=windows-1252 147 148` + 149 html_start + 150 ` 151<head> 152 <meta http-equiv="Content-Type" charset="UTF-8" content="text/html; charset=windows-1252"> 153 <link id="Main-File" rel="Main-File" href="../WorkBook.htm"> 154 <link rel="File-List" href="filelist.xml"> 155</head> 156<body><table>{SheetContent}</table></body> 157</html>`, 158 template_WorkBook = 159 `MIME-Version: 1.0 160X-Document-Type: Workbook 161Content-Type: multipart/related; boundary="----=_NextPart_dummy" 162 163------=_NextPart_dummy 164Content-Location: WorkBook.htm 165Content-Type: text/html; charset=windows-1252 166 167` + 168 html_start + 169 ` 170<head> 171<meta name="Excel Workbook Frameset"> 172<meta http-equiv="Content-Type" charset="UTF-8" content="text/html; charset=windows-1252"> 173<link rel="File-List" href="filelist.xml"> 174<!--[if gte mso 9]><xml> 175 <x:ExcelWorkbook> 176 <x:ExcelWorksheets>{ExcelWorksheets}</x:ExcelWorksheets> 177 <x:ActiveSheet>0</x:ActiveSheet> 178 </x:ExcelWorkbook> 179</xml><![endif]--> 180</head> 181<frameset> 182 <frame src="sheet0.htm" name="frSheet"> 183 <noframes><body><p>This page uses frames, but your browser does not support them.</p></body></noframes> 184</frameset> 185</html> 186{HTMLWorksheets} 187Content-Location: filelist.xml 188Content-Type: text/xml; charset="utf-8" 189 190<xml xmlns:o="urn:schemas-microsoft-com:office:office"> 191 <o:MainFile HRef="../WorkBook.htm"/> 192 {ListWorksheets} 193 <o:File HRef="filelist.xml"/> 194</xml> 195------=_NextPart_dummy-- 196`; 197 let context_WorkBook = { 198 ExcelWorksheets: '', 199 HTMLWorksheets: '', 200 ListWorksheets: '', 201 }; 202 tables.forEach((item, sheetIndex) => { 203 context_WorkBook.ExcelWorksheets += this.format(template_ExcelWorksheet, { 204 SheetIndex: sheetIndex, 205 SheetName: dataSource[sheetIndex].sheetName, 206 }); 207 context_WorkBook.HTMLWorksheets += this.format(template_HTMLWorksheet, { 208 SheetIndex: sheetIndex, 209 SheetContent: item, 210 }); 211 context_WorkBook.ListWorksheets += this.format(template_ListWorksheet, { 212 SheetIndex: sheetIndex, 213 }); 214 }); 215 let link = document.createElement('a'); 216 link.href = uri + this.base64(this.format(template_WorkBook, context_WorkBook)); 217 link.download = filename + '.xls'; 218 link.target = '_blank'; 219 link.click(); 220 } 221} 222