• 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
16export class JSONToCSV {
17  static setCsvData(obj: unknown): void {
18    let browserType = this.browserType();
19    // @ts-ignore
20    if (browserType.ie < 9) {
21      return;
22    }
23    // @ts-ignore
24    let data = obj.data;
25    // @ts-ignore
26    let isShowLabel = typeof obj.showLabel === 'undefined' ? true : obj.showLabel;
27    // @ts-ignore
28    let fileName = (obj.fileName || 'UserExport') + '.csv';
29    // @ts-ignore
30    let columns = obj.columns || {
31      title: [],
32      key: [],
33      formatter: undefined,
34    };
35    let showLabel = typeof isShowLabel === 'undefined' ? true : isShowLabel;
36    let row = '';
37    let csv = '';
38    let key: string;
39    // 如果要现实表头文字
40    if (showLabel) {
41      // 如果有传入自定义的表头文字
42      if (columns.title.length) {
43        columns.title.map(function (n: unknown) {
44          row += n + ',';
45        });
46      } else {
47        // 如果没有,就直接取数据第一条的对象的属性
48        for (key in data[0]) {
49          row += key + ',';
50        }
51      }
52      row = row.slice(0, -1);
53      csv += row + '\r\n';
54    }
55    // 具体的数据处理
56    data.map((n: unknown) => {
57      row = '';
58      // 如果存在自定义key值
59      if (columns.key.length) {
60        row = this.getCsvStr(columns, obj, n, row);
61      } else {
62        // @ts-ignore
63        for (key in n) {
64          row +=
65            // @ts-ignore
66            '"' + (typeof columns.formatter === 'function' ? columns.formatter(key, n[key]) || n[key] : n[key]) + '",';
67        }
68      }
69      row.slice(0, row.length - 1); // 删除最后一个,
70      csv += row + '\r\n'; // 添加换行符号
71    });
72    if (!csv) {
73      return;
74    }
75    this.saveCsvFile(fileName, csv);
76  }
77
78  static getCsvStr(columns: unknown, obj: unknown, n: unknown, row: string): string {
79    // @ts-ignore
80    columns.key.map(function (m: unknown, idx: number) {
81      let strItem: unknown = '';
82      // @ts-ignore
83      if (obj.exportFormatter && obj.exportFormatter.has(m)) {
84        // @ts-ignore
85        strItem = obj.exportFormatter.get(m)?.(n) || n[m];
86        // @ts-ignore
87      } else if (obj.formatter && obj.formatter.has(m)) {
88        // @ts-ignore
89        strItem = obj.formatter.get(m)?.(n[m]) || n[m];
90      } else {
91        // @ts-ignore
92        strItem = n[m];
93      }
94      if (typeof strItem === 'undefined') {
95        strItem = '';
96      } else if (typeof strItem === 'object') {
97        strItem = JSON.stringify(strItem);
98        // @ts-ignore
99        strItem = strItem.replaceAll('"', '');
100      }
101      // @ts-ignore
102      if (idx === 0 && typeof n.depthCSV !== 'undefined') {
103        row +=
104          '"' +
105          // @ts-ignore
106          this.treeDepth(n.depthCSV) +
107          // @ts-ignore
108          (typeof columns.formatter === 'function' ? columns.formatter(m, n[m]) || n[m] : strItem) +
109          '",';
110      } else {
111        // @ts-ignore
112        row += '"' + (typeof columns.formatter === 'function' ? columns.formatter(m, n[m]) || n[m] : strItem) + '",';
113      }
114    });
115    return row;
116  }
117
118  static saveCsvFile(fileName: unknown, csvData: unknown): void {
119    let browserType: unknown = this.browserType();
120    // @ts-ignore
121    if (!browserType.edge || !browserType.ie) {
122      let alink: unknown = document.createElement('a');
123      // @ts-ignore
124      alink.id = 'csvDownloadLink';
125
126      const href = this.getDownloadUrl(csvData);
127      // @ts-ignore
128      alink.href = href === '' ? null : href;
129      // @ts-ignore
130      document.body.appendChild(alink);
131      let linkDom: unknown = document.getElementById('csvDownloadLink');
132      // @ts-ignore
133      linkDom.setAttribute('download', fileName);
134      // @ts-ignore
135      linkDom.click();
136      // @ts-ignore
137      document.body.removeChild(linkDom);
138      // @ts-ignore
139    } else if (browserType.ie >= 10 || browserType.edge === 'edge') {
140      // @ts-ignore
141      (navigator as unknown).msSaveBlob(
142        new Blob(['\uFEFF' + csvData], {
143          type: 'text/csv',
144        }),
145        fileName
146      );
147    } else {
148      let oWin: unknown = window.top?.open('about:blank', '_blank');
149      // @ts-ignore
150      oWin.document.write('sep=,\r\n' + csvData);
151      // @ts-ignore
152      oWin.document.close();
153      // @ts-ignore
154      oWin.document.execCommand('SaveAs', true, fileName);
155      // @ts-ignore
156      oWin.close();
157    }
158  }
159
160  static getDownloadUrl(csvData: unknown): string {
161    // @ts-ignore
162    if (window.Blob && window.URL && (window.URL as unknown).createObjectURL) {
163      return URL.createObjectURL(
164        new Blob(['\uFEFF' + csvData], {
165          type: 'text/csv',
166        })
167      );
168    }
169    return '';
170  }
171
172  static browserType(): { edge: string; ie: string } {
173    const type: { edge: string; ie: string } = { edge: '', ie: '' };
174    const agent = navigator.userAgent.toLowerCase();
175    const edgeMatch = agent.match(/edge/);
176    if (edgeMatch) {
177      type.edge = 'edge';
178    } else {
179      const ieMatch = agent.match(/rv:([\d.]+)\) like gecko/) || agent.match(/msie ([\d.]+)/);
180      if (ieMatch) {
181        type.ie = ieMatch[1];
182      }
183    }
184
185    return type;
186  }
187
188  static treeDepth(depth: number): string {
189    let str = '';
190    for (let i = 0; i < depth; i++) {
191      str += '    ';
192    }
193    return str;
194  }
195
196  static treeToArr(data: unknown): unknown[] {
197    const result: Array<unknown> = [];
198    // @ts-ignore
199    data.forEach((item: unknown) => {
200      let depthCSV = 0;
201      const loop = (data: unknown, depth: unknown): void => {
202        // @ts-ignore
203        result.push({ depthCSV: depth, ...data });
204        // @ts-ignore
205        let child = data.children;
206        if (child) {
207          for (let i = 0; i < child.length; i++) {
208            // @ts-ignore
209            loop(child[i], depth + 1);
210          }
211        }
212      };
213      loop(item, depthCSV);
214    });
215    return result;
216  }
217
218  static columnsData(columns: Array<unknown>): {
219    titleList: unknown[];
220    ketList: unknown[];
221  } {
222    let titleList: Array<unknown> = [];
223    let ketList: Array<unknown> = [];
224    columns.forEach((column) => {
225      // @ts-ignore
226      let dataIndex = column.getAttribute('data-index');
227      // @ts-ignore
228      let columnName = column.getAttribute('title');
229      if (columnName === '') {
230        columnName = dataIndex === 'busyTimeStr' ? 'GetBusyTime(ms)' : dataIndex;
231      }
232      if (columnName !== '  ') {
233        titleList.push(columnName);
234        ketList.push(dataIndex);
235      }
236    });
237    return {
238      titleList: titleList,
239      ketList: ketList,
240    };
241  }
242
243  static async csvExport(dataSource: {
244    columns: unknown[];
245    tables: unknown[];
246    fileName: string;
247    columnFormatter: Map<string, (value: unknown) => string>;
248    exportFormatter: Map<string, (value: unknown) => string>;
249  }): Promise<string> {
250    return new Promise((resolve) => {
251      let data: unknown = this.columnsData(dataSource.columns);
252      let columns = {
253        // @ts-ignore
254        title: data.titleList,
255        // @ts-ignore
256        key: data.ketList,
257      };
258      if (dataSource.tables.length > 0) {
259        if (Array.isArray(dataSource.tables[0])) {
260          dataSource.tables.forEach((childArr, childIndex) => {
261            let resultArr = JSONToCSV.treeToArr(childArr);
262            JSONToCSV.setCsvData({
263              data: resultArr,
264              fileName: `${dataSource.fileName}_${childIndex}`,
265              columns: columns,
266              formatter: dataSource.columnFormatter,
267            });
268          });
269        } else {
270          let resultArr = JSONToCSV.treeToArr(dataSource.tables);
271          JSONToCSV.setCsvData({
272            data: resultArr,
273            fileName: dataSource.fileName,
274            columns: columns,
275            formatter: dataSource.columnFormatter,
276            exportFormatter: dataSource.exportFormatter,
277          });
278        }
279      }
280      resolve('ok');
281    });
282  }
283}
284