interface IJson2ExcelParam { data : object [ ] ; orderedKey : string [ ] ; filters : string [ ] ; title : any [ ] ; footer : any [ ] ; keyMap : object ; name : string ; type : string ; onStart : ( ) => void ; onSuccess : ( ) => void ; } export default class Json2Excel { data : object [ ] ; orderedKey : string [ ] ; filters : string [ ] ; title : any [ ] ; footer : any [ ] ; keyMap : object ; name : string ; type : string ; onStart : ( ) => void ; onSuccess : ( ) => void ; constructor ( { data = [ ] , orderedKey = [ ] , filters = [ ] , title = [ ] , footer = [ ] , keyMap = { } , name = "excel" , type = "xls" , onStart = ( ) => { } , onSuccess = ( ) => { } } ) { this . data = data ; this . filters = filters ; this . footer = footer ; this . orderedKey = orderedKey ; this . keyMap = keyMap ; this . name = name ; this . title = title ; ( this . type = type ) , ( this . onStart = onStart ) ; this . onSuccess = onSuccess ; } toChsKeys ( json , keyMap ) { return json . map ( item => { let newItem = { } ; if ( this . orderedKey . length ) { for ( let keyItem of this . orderedKey ) { if ( keyMap . hasOwnProperty ( keyItem ) ) { newItem [ keyMap [ keyItem ] ] = item [ keyItem ] ; } else { newItem [ keyItem ] = item [ keyItem ] ; } } } else if ( this . filters . length ) { for ( let filterItem of this . filters ) { delete item [ filterItem ] ; for ( let key in item ) { if ( keyMap . hasOwnProperty ( key ) ) { newItem [ keyMap [ key ] ] = item [ key ] ; } else { newItem [ key ] = item [ key ] ; } } } } else { for ( let key in item ) { if ( keyMap . hasOwnProperty ( key ) ) { newItem [ keyMap [ key ] ] = item [ key ] ; } else { newItem [ key ] = item [ key ] ; } } } return newItem ; } ) ; } generate ( ) { if ( ! this . data . length ) { return ; } this . onStart ( ) ; let json = this . getProcessedJson ( this . data ) ; json = this . toChsKeys ( json , this . keyMap ) ; if ( this . type == "csv" ) { return this . export ( this . jsonToCSV ( json ) , `${ this . name }.${ this . type }` , "application/csv" ) ; } return this . export ( this . jsonToXLS ( json ) , `${ this . name }.${ this . type }` , "application/vnd.ms-excel" ) ; } download ( blob , filename ) { if ( window . navigator . msSaveOrOpenBlob ) { navigator . msSaveOrOpenBlob ( blob , filename ) ; } else { const anchor = document . createElement ( "a" ) ; const url = window . URL . createObjectURL ( blob ) ; anchor . href = url ; anchor . setAttribute ( "download" , filename ) ; anchor . innerHTML = "downloading..." ; anchor . style . display = "none" ; document . body . appendChild ( anchor ) ; setTimeout ( ( ) => { anchor . click ( ) ; document . body . removeChild ( anchor ) ; setTimeout ( ( ) => { self . URL . revokeObjectURL ( anchor . href ) ; } , 250 ) ; } , 66 ) ; } } export ( data , filename , mime ) { new Promise ( ( resolve ) => { let blob = this . base64ToBlob ( data , mime ) ; resolve ( this . download ( blob , filename ) ) ; } ) . then ( ( ) => { this . onSuccess ( ) ; } ) . catch ( ( ) => { } ) ; } jsonToXLS ( data ) { let xlsTemp = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${table}</table></body></html>' ; let xlsData = "<thead><tr>" ; if ( this . title . length ) { for ( let i of this . title ) { xlsData += `<th colspan=${ i . colspan }>${ i . name }` ; } xlsData += "<th></tr>" ; } for ( let key in data [ 0 ] ) { xlsData += "<th>" + key + "</th>" ; } xlsData += "</tr></thead>" ; xlsData += "<tbody>" ; data . map ( function ( item , index ) { xlsData += "<tbody><tr>" ; for ( let key in item ) { xlsData += "<td>" + item [ key ] + "</td>" ; } xlsData += "</tr></tbody>" ; } ) ; if ( this . footer . length != 0 ) { xlsData += "<tfooter><tr>" ; for ( let i of this . footer ) { xlsData += `<th colspan=${ i . colspan }>${ i . name }` ; } xlsData += "<th></tr></tr></tfooter>" ; } return xlsTemp . replace ( "${table}" , xlsData ) ; } jsonToCSV ( data ) { var csvData = "" ; if ( this . title . length != 0 ) { for ( let i of this . title ) { csvData += `${ i . name }` ; } csvData += "\r\n" ; } for ( let key in data [ 0 ] ) { csvData += key + "," ; } csvData = csvData . slice ( 0 , csvData . length - 1 ) ; csvData += "\r\n" ; data . map ( function ( item ) { for ( let key in item ) { let escapedCSV = item [ key ] + "" ; if ( escapedCSV . match ( /[,"\n]/ ) ) { escapedCSV = '"' + escapedCSV . replace ( /\"/g , '""' ) + '"' ; } csvData += escapedCSV + "," ; } csvData = csvData . slice ( 0 , csvData . length - 1 ) ; csvData += "\r\n" ; } ) ; if ( this . footer . length != 0 ) { for ( let i of this . footer ) { csvData += `${ i . name }` ; } csvData += "\r\n" ; } return csvData ; } getProcessedJson ( data ) { let keys = this . getKeys ( data ) ; let newData = [ ] ; data . map ( ( item ) => { let newItem = { } ; for ( let label in keys ) { let property = keys [ label ] ; newItem [ label ] = this . getNestedData ( property , item ) ; } newData . push ( newItem ) ; } ) ; return newData ; } getKeys ( data ) { let keys = { } ; for ( let key in data [ 0 ] ) { keys [ key ] = key ; } return keys ; } parseExtraData ( extraData , format ) { let parseData = "" ; if ( Array . isArray ( extraData ) ) { for ( var i = 0 ; i < extraData . length ; i ++ ) { parseData += format . replace ( "${data}" , extraData [ i ] ) ; } } else { parseData += format . replace ( "${data}" , extraData ) ; } return parseData ; } callItemCallback ( field , itemValue ) { if ( typeof field === "object" && typeof field . callback === "function" ) { return field . callback ( itemValue ) ; } return itemValue ; } getNestedData ( key , item ) { const field = typeof key === "object" ? key . field : key ; let valueFromNestedKey = null ; let keyNestedSplit = field . split ( "." ) ; valueFromNestedKey = item [ keyNestedSplit [ 0 ] ] ; for ( let j = 1 ; j < keyNestedSplit . length ; j ++ ) { valueFromNestedKey = valueFromNestedKey [ keyNestedSplit [ j ] ] ; } valueFromNestedKey = this . callItemCallback ( key , valueFromNestedKey ) ; valueFromNestedKey = valueFromNestedKey === null || valueFromNestedKey === undefined ? "" : valueFromNestedKey ; return valueFromNestedKey ; } base64ToBlob ( data , mime ) { let base64 = window . btoa ( window . unescape ( encodeURIComponent ( data ) ) ) ; let bstr = atob ( base64 ) ; let n = bstr . length ; let u8arr = new Uint8ClampedArray ( n ) ; while ( n -- ) { u8arr [ n ] = bstr . charCodeAt ( n ) ; } return new Blob ( [ u8arr ] , { type : mime } ) ; } }