react 导出 excel

react 导出 excel  

// 导入 组件  组件在代码的最后部分 按自己的需求更改    如果有用给个赞

import { DownloadExcel } from '@/components/downloadExcel/downloadExcel';

 

组件使用 两种方法 

<DownloadExcel name={this.state.ExcelName} fields={this.jsonFieldsList} title={this.titleData} footer={this.footerData}  fetch={this.fetchFun.bind(this)} btnName="考勤导出" />
                

<DownloadExcel name={this.state.ExcelName} fields={this.jsonFieldsList} title={this.titleData} footer={this.footerData}  fetch={this.fetchFun.bind(this)} btnName="考勤导出" >
         <p>点击下载</p> 
 </DownloadExcel>

// 传入参数 0_ 只是保持顺序 也可以不写
jsonFieldsList  'key' 是 导出格式的名称 val 绑定对应的数据参数 
jsonFieldsList =  {
        '0_序号': 'aa',
        '1_姓名': 'uicName',
        "2_公民身份证号码": {
            field: 'idCard',
            callback: value => {
                return '&nbsp;' + value
            }
        },

        "3_电话": 'uPhone',
        "4_公司": "eName",
        "5_部门": 'teName',
        '6_岗位': 'nameWork',

        '7_1':'d1','7_2':'d2','7_3':'d3','7_4':'d4','7_5':'d5','7_6':'d6','7_7':'d7','7_8':'d8','7_9':'d9','7_10':'d10','7_11':'d11',
        '7_12': 'd12', '7_13': 'd13','7_14': 'd14', '7_15': 'd15','7_16': 'd16', '7_17': 'd17','7_18': 'd18', '7_19': 'd19','7_20': 'd20',
        '7_21': 'd21', '7_22': 'd22','7_23': 'd23', '7_24': 'd24','7_25': 'd25', '7_26': 'd26','7_27': 'd27', '7_28': 'd28','7_29': 'd29','7_30': 'd30','7_31': 'd31',
        '8_合计': 'total'

      }

      titleData = [
        {
            thStyle: 'style=height:60px; font-size:20px;',
            html: `<div style="font-size:22px;">珠江三角洲水资源配置工程土建施工C1标智慧工程考勤表<br/><span style="font-size:16px; font-weight: normal;">日期:2020-11-01 至 2020-11-30</span></div>`
        }
     ]


     footerData = [
        [{
            thStyle: `style=height:20px;`,
            html: `<div style=' text-align: left; display:black; height:200px;' >申明:此表登记劳务作业人员为我单位本月在该工程全部出勤人数,出勤情况属实;我单位已将此表向全体劳务作业人员公示,均无异议。</div>`,
            colspan: 36
        },
        {
            thStyle: `style=height:20px;`,
            html: `<div style=' text-align: left; display:black; height:200px;' >总计</div>`,
            colspan: 2
        },
        {
            thStyle: `style=height:20px;`,
            html: `<div style=' text-align: left; display:black; height:200px;' >629</div>`,
            colspan: 1
        }],

         [{
            thStyle: `style=height:80px;`,
            html: `<div style=' text-align: left; display:black; height:200px; vertical-align:top;'>班组长签名: </div>`,
            colspan: 3
        },
        {
            thStyle: `style=height:80px;`,
            html: `<div style=' text-align: left; display:black; height:200px; vertical-align:top;' >用工企业劳动<br/>力管理员签字:</div>`,
            colspan: 3
        },
        {
            thStyle: `style=height:80px;`,
            html: `<div style=' text-align: left; display:black; height:200px; vertical-align:top;' >用工企业项目负责人<br/>(授权队长)签字:</div>`,
            colspan: 5
        },
        {
            thStyle: `style=height:80px;`,
            html: `<div style=' text-align: left; display:black; height:200px; vertical-align:top;' >填表时间:</div>`,
            colspan: 14
        },
        {
            thStyle: `style=height:80px; width="20px;"`,
            html: `<div style=' text-align: left; display:black; height:200px; vertical-align:top;'>用工企业盖章:</div>`,
            colspan: 14
        }],
        
    ]

 

// 点击 执行的 方法  执行返回 数据

  // 方法导出
   fetchFun() {

        return new Promise(resolve => {
        let params = {}
        for(let i in this.state.params) {
            params[i] = this.state.params[i]
        }
        let date = new Date(params.time * 1000)
        let time = formatTime(date, 'yyyy-MM-dd')
        let year = date.getFullYear()
        let month = date.getMonth()+1
        let lastDay =  new Date(year,month,0).getDate()
        let strDate =  year + '-' + month + '-' + lastDay
        this.titleData[0].html = `<div style="font-size:22px;">${this.state.projectName}<br/><span style="font-size:16px; font-weight: normal;">日期:${time} 至 ${strDate}</span></div>`        
        params.export = 2
        React.$axios.post('userAttendanceList', params).then(res => {
            let sum = 0
            res.data.list.map((item,index) => {
                item.aa = index+1
                for(let i in item) {
                    let a = /^d\d+/g.test(i)
                    if(a) {
                        if(item[i] == 1) {
                            item[i] ='√'
                        } else {
                            item[i] = ' '
                        }
                    }
                }
                sum += item.total
            })
            
            this.footerData[0][2].html =`<div style=' text-align: left; display:black; height:200px;' >${sum}</div>`
            resolve(res.data.list)
            })
        })    
    }

 

// 组件   安装   downloadjs   框架不同 可自行修改 框架组件

import React from 'react'

import './downloadExcel.less'

import download from "downloadjs";

import { Button} from 'antd';
import { VerticalAlignBottomOutlined } from '@ant-design/icons';




export const DownloadExcel = (
    class DownloadExcel extends React.Component {

        state = {
            visible: true,
            imageUrl: '',
            loading: false
        }

        static defaultProps = {
            type: "xls",
              // Json to download
              data: [],

              btnName: '导出',

              fields: false,

              exportFields: false,

              defaultValue: false,
              title: null,
              footer: null,
              name: "data.xls",
              fetch: null,
              meta: [], 
              worksheet: 'Sheet1',
              beforeGenerate:{
                type: Function,
              },
              beforeFinish:{
                type: Function,
              },
          }

        downloadFields() {
            if (this.props.fields) return this.props.fields;

            if (this.props.exportFields) return this.props.exportFields;
        }


        componentDidMount() {
            console.log(this.props)
        }

        async setDownLoadData() {

            let data = this.props.data
            let fetch = this.props.fetch


            if(fetch) {
                data = await this.props.fetch()
                console.log(data)
            }

            if (!data || !data.length) {
                return;
            }

            
            let json = this.getProcessedJson(data, this.downloadFields());

            console.log(json)

            return this.export(
                this.jsonToXLS(json),
                this.props.name,
                "application/vnd.ms-excel"
            );
        }


        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]--><style>br {mso-data-placement: same-cell;}</style></head><body><table>${table}</table></body></html>';
            let xlsData = "<thead>";
            const colspan = Object.keys(data[0]).length;
            let _self = this;

            if (this.props.title != null) {
                this.props.title.map(item => {
                  xlsData += '<tr><th '+ item.thStyle +' colspan="' + colspan + '">'+ item.html +'</th></tr>'
              })

            }
            

            console.log(data)  
            xlsData += "<tr>";
            for (let key in data[0]) {
              let t = key.replace(/\d+_/, "")
              key = t;
              if(/\d+/g.test(key)) {
                xlsData += "<th><div style='width:20px;'>" +  key + "</div></th>";
              } else {
                xlsData += "<th>" + key + "</th>";
              }
            }
            xlsData += "</tr>";
            xlsData += "</thead>";


            xlsData += "<tbody>";
            data.map(function(item, index) {
                xlsData += "<tr>";
                for (let key in item) {
                xlsData += "<td>" + _self.valueReformattedForMultilines(item[key]) + "</td>";
                }
                xlsData += "</tr>";
            });
            xlsData += "</tbody>";

            if (this.props.footer != null) {
                xlsData += "<tfoot>";

                this.props.footer.filter(item => {
                  if(Array.isArray(item)) {
    
                    xlsData += '<tr>'
                    item.forEach(val => {
                      if(val.colspan) {
                         xlsData += '<td '+ val.thStyle +' colspan="' + val.colspan + '">' + val.html + "</td>";
                      } else {
                         xlsData += '<td '+ val.thStyle +' colspan="' + colspan + '">' + val.html + "</td>";
                      }
                    })
    
                    xlsData += "</tr>";
    
                  } else {
                   if(item.colspan) {
                      xlsData += '<tr><th '+ item.thStyle +' colspan="' + item.colspan + '">'+ item.html +'</th></tr>'
                    } else {
                      xlsData += '<tr><th '+ item.thStyle +' colspan="' + colspan + '">'+ item.html +'</th></tr>'
                    }
                  }
              })

                // xlsData += this.parseExtraData(
                //   this.props.footer,
                //   '<tr><td colspan="' + colspan + '">${data}</td></tr>'
                // );
                xlsData += "</tfoot>";
              }

              return xlsTemp.replace("${table}", xlsData).replace("${worksheet}", this.props.worksheet);
        }


        parseExtraData(extraData, format) {
          console.log(extraData)
          
          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;
        }


        valueReformattedForMultilines(value) {
          if (typeof(value)=="string") return(value.replace(/\n/ig,"<br/>"));
          else return(value);
        }


       async export(data, filename, mime) {
            let blob = this.base64ToBlob(data, mime);
            if(typeof this.beforeFinish === 'function')
              await this.beforeFinish();
            download(blob, filename, mime);
        }


        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 });
          }



          getProcessedJson(data, header) {
            let keys = this.getKeys(data, header);
            

            let newData = [];
            let _self = this;
            data.map(function(item, index) {
                let newItem = {};
                for (let label in keys) {
                  let property = keys[label];
                  newItem[label] = _self.getValue(property, item);
                }
                newData.push(newItem);
              });
            
            return newData;
        }

        getKeys(data, header) {
            if (header) {
                return header;
            }
        
            let keys = {};
            for (let key in data[0]) {
                keys[key] = key;
            }
            return keys;
        }


        getValue(key, item) {
            const field = typeof key   !== "object" ? key : key.field;
            let indexes = typeof field !== "string" ? []  : field.split(".");
            let value   = this.defaultValue;
          
            if (!field)
                value = item;
            else if( indexes.length > 1 )
              value = this.getValueFromNestedItem(item, indexes);
            else
              value = this.parseValue(item[field]);
            
            if( key.hasOwnProperty('callback'))
              value = this.getValueFromCallback(value, key.callback);
            
            return value;
        }



        getValueFromNestedItem(item, indexes){
            let nestedItem = item;
            for (let index of indexes) {
              if(nestedItem)
                nestedItem = nestedItem[index];
            }
            return this.parseValue(nestedItem);
          }


        parseValue(value){
        return value || value === 0 || typeof value === 'boolean'
            ? value
            : this.defaultValue;
        }

        getValueFromCallback(item, callback){
            if(typeof callback !== "function")
              return this.defaultValue
            const value = callback(item);
            return this.parseValue(value);
          }
 

        render() {
            return <div >
                {
                  function () {
                    if(this.props.children) {

                      return (
                        <span onClick={this.setDownLoadData.bind(this)}>
                          { this.props.children}
                        </span>
                      )

                    } else {
                      return (
                        <Button type="primary" onClick={this.setDownLoadData.bind(this)} icon={<VerticalAlignBottomOutlined />}>
                            {this.props.btnName}
                        </Button>
                      )
                      
                    }


                  }.bind(this)()
                } 


               
            </div>
        }
    }
)

 

posted @ 2021-09-23 18:07  大帅比2  阅读(231)  评论(0编辑  收藏  举报