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 16const htmlStr = (): unknown => { 17 let AsciiValues = [104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 84, 82, 47, 82, 69, 67, 45, 104, 116, 109, 108, 52, 48]; 18 let str = String.fromCharCode.apply(null, AsciiValues); 19 const html_start = 20 `<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=${str}>`; 21 return { 22 uri: 'data:application/vnd.ms-excel;base64,', 23 template_ExcelWorksheet: 24 '<x:ExcelWorksheet><x:Name>{SheetName}</x:Name><x:WorksheetSource HRef="sheet{SheetIndex}.htm"/><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>', 25 template_ListWorksheet: '<o:File HRef="sheet{SheetIndex}.htm"/>', 26 template_WorkBook: 27 `MIME-Version: 1.0 28X-Document-Type: Workbook 29Content-Type: multipart/related; boundary="----=_NextPart_dummy" 30 31------=_NextPart_dummy 32Content-Location: WorkBook.htm 33Content-Type: text/html; charset=windows-1252 34 35` + 36 html_start + 37 ` 38<head> 39<meta name="Excel Workbook Frameset"> 40<meta http-equiv="Content-Type" charset="UTF-8" content="text/html; charset=windows-1252"> 41<link rel="File-List" href="filelist.xml"> 42<!--[if gte mso 9]><xml> 43 <x:ExcelWorkbook> 44 <x:ExcelWorksheets>{ExcelWorksheets}</x:ExcelWorksheets> 45 <x:ActiveSheet>0</x:ActiveSheet> 46 </x:ExcelWorkbook> 47</xml><![endif]--> 48</head> 49<frameset> 50 <frame src="sheet0.htm" name="frSheet"> 51 <noframes><body><p>This page uses frames, but your browser does not support them.</p></body></noframes> 52</frameset> 53</html> 54{HTMLWorksheets} 55Content-Location: filelist.xml 56Content-Type: text/xml; charset="utf-8" 57 58<xml xmlns:o="urn:schemas-microsoft-com:office:office"> 59 <o:MainFile HRef="../WorkBook.htm"/> 60 {ListWorksheets} 61 <o:File HRef="filelist.xml"/> 62</xml> 63------=_NextPart_dummy-- 64`, 65 }; 66}; 67 68export class ExcelFormater { 69 static tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>'; 70 static base64 = function (s: unknown): string { 71 //@ts-ignore 72 return window.btoa(unescape(encodeURIComponent(s))); 73 }; 74 75 static format(s: unknown, c: unknown): string { 76 //@ts-ignore 77 return s.replace(/{(\w+)}/g, function (m: unknown, p: unknown) { 78 //@ts-ignore 79 return c[p]; 80 }); 81 } 82 83 static createExcelRow(columns: unknown[], data: unknown): string { 84 let rowsXML = ''; 85 rowsXML += '<Row>'; 86 for (let k = 0; k < columns.length; k++) { 87 //@ts-ignore 88 let dataIndex = columns[k].getAttribute('data-index'); //@ts-ignore 89 let columnName = columns[k].getAttribute('title'); 90 if (columnName === '') { 91 columnName = dataIndex; 92 } 93 let ctx = { 94 attributeStyleID: '', 95 nameType: 'String', //@ts-ignore 96 data: data ? data[dataIndex] || '' : columnName, 97 attributeFormula: '', 98 }; 99 rowsXML += this.format(this.tmplCellXML, ctx); 100 } 101 rowsXML += '</Row>'; //@ts-ignore 102 if (data && data.children !== undefined && data.children.length > 0) { 103 //@ts-ignore 104 data.children.forEach((child: unknown) => { 105 rowsXML += this.createExcelRow(columns, child); 106 }); 107 } 108 return rowsXML; 109 } 110 111 static addImage(baseStr: string): string { 112 return `<Row>${this.format(this.tmplCellXML, { 113 attributeStyleID: '', 114 nameType: 'String', 115 data: `<div><img src="${baseStr}"></img></div>`, 116 attributeFormula: '', 117 })}</Row>`; 118 } 119 120 static testExport( 121 dataSource: { columns: unknown[]; tables: unknown[]; sheetName: string }[], 122 fileName: string 123 ): void { 124 this.tablesToHtmlExcelMultipleSheet(dataSource, fileName); 125 } 126 127 static tablesToHtmlExcelMultipleSheet( 128 dataSource: { columns: unknown[]; tables: unknown[]; sheetName: string }[], 129 fileName: string, 130 image?: string 131 ): void { 132 let sheets: unknown[] = []; 133 dataSource.forEach((data): void => { 134 sheets.push(this.createTableData(data.columns, data.tables, image)); 135 }); 136 this.tablesToExcelTestSheet(sheets, fileName, dataSource); 137 } 138 139 static createTableData(columns: unknown[], dataSource: unknown[], image?: string): string { 140 let tableData = ''; 141 let columnDatas = columns.map((column) => { 142 //@ts-ignore 143 let dataIndex = column.getAttribute('data-index'); //@ts-ignore 144 let columnName = column.getAttribute('title'); 145 if (columnName === '') { 146 columnName = dataIndex; 147 } 148 return { 149 columnName: columnName, 150 dataIndex: dataIndex, 151 }; 152 }); 153 tableData += this.createTHead( 154 columnDatas.map((item) => { 155 return item.columnName; 156 }) 157 ); 158 let columnDataIndexes = columnDatas.map((item) => item.dataIndex); 159 dataSource.forEach((data, index) => { 160 if (index === 0 && image) { 161 tableData += this.createTableRow(columnDataIndexes, data, image); 162 } else { 163 tableData += this.createTableRow(columnDataIndexes, data); 164 } 165 }); 166 return tableData; 167 } 168 169 static createTHead(columns: unknown[]): string { 170 let header = '<thead>'; 171 columns.forEach((column) => { 172 header += `<td>${column}</td>`; 173 }); 174 header += '</thrad>'; 175 return header; 176 } 177 178 static createTableRow(columns: unknown[], data: unknown, image?: unknown): string { 179 let childrenData = ''; //@ts-ignore 180 if (data.children !== undefined) { 181 //@ts-ignore 182 data.children.forEach((child: unknown) => { 183 if (child) { 184 childrenData += this.createTableRow(columns, child); 185 } 186 }); 187 } 188 return `<tr>${columns 189 .map((column) => { 190 //@ts-ignore 191 return `<td>${(data[column] + '').replace('μ', 'u')}</td>` || ''; 192 }) 193 .join('')}${image ? `<td><div><img src="${image}"></img></div></td>` : ''}</tr>${childrenData}`; 194 } 195 196 static tablesToExcelTestSheet( 197 tables: unknown[], 198 filename: string, 199 dataSource: { columns: unknown[]; tables: unknown[]; sheetName: string }[] 200 ): void { 201 let AsciiValues = [104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 84, 82, 47, 82, 69, 202 67, 45, 104, 116, 109, 108, 52, 48]; 203 let str = String.fromCharCode.apply(null, AsciiValues); 204 const html_start = 205 `<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=${str}>`; //@ts-ignore 206 let { uri, template_ExcelWorksheet, template_ListWorksheet, template_WorkBook } = htmlStr(); 207 let template_HTMLWorksheet = 208 ` 209------=_NextPart_dummy 210Content-Location: sheet{SheetIndex}.htm 211Content-Type: text/html; charset=windows-1252 212 213` + 214 html_start + 215 ` 216<head> 217 <meta http-equiv="Content-Type" charset="UTF-8" content="text/html; charset=windows-1252"> 218 <link id="Main-File" rel="Main-File" href="../WorkBook.htm"> 219 <link rel="File-List" href="filelist.xml"> 220</head> 221<body><table>{SheetContent}</table></body> 222</html>`; 223 let context_WorkBook = { 224 ExcelWorksheets: '', 225 HTMLWorksheets: '', 226 ListWorksheets: '', 227 }; 228 tables.forEach((item, sheetIndex) => { 229 context_WorkBook.ExcelWorksheets += this.format(template_ExcelWorksheet, { 230 SheetIndex: sheetIndex, 231 SheetName: dataSource[sheetIndex].sheetName, 232 }); 233 context_WorkBook.HTMLWorksheets += this.format(template_HTMLWorksheet, { 234 SheetIndex: sheetIndex, 235 SheetContent: item, 236 }); 237 context_WorkBook.ListWorksheets += this.format(template_ListWorksheet, { 238 SheetIndex: sheetIndex, 239 }); 240 }); 241 let link = document.createElement('a'); 242 link.href = uri + this.base64(this.format(template_WorkBook, context_WorkBook)); 243 link.download = filename + '.xls'; 244 link.target = '_blank'; 245 link.click(); 246 } 247} 248