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