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