• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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