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