ReactJS编写的树形表格

表格使用ReactJs编写的树形表格。

表格功能:

以树形表格的格式显示数据;

每条数据的右击菜单根据这条数据中不同的属性标示,可控制对应的类型是否可以下钻;

数据对应的地域下钻之后,点击地域前面的小三角可进行本省份下的地市下钻。

reportTreeTable.js文件

/**
 * Created by Administrator on 2016/12/12 0012.
 */
import React from 'react'
import './reportTreeTable.less'
require('../../node_modules/webpack-dev-server/client/web_modules/jquery/jquery-1.8.1');
var gIndex = -1;
export default class ReportTreeTable extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            thData: ["指标名称", "本月值", "日均环比增幅", "本年累计", "累计同比增幅"],
            /*datalist: [
                {title: "测试数据", pid: "-1", id: '1', "space": "2",region_drill:"0", user_drill:"0",channel_drill:"0",contract_drill:"0", values: ["", "", "", ""]}
            ],*/
            datalist: [
                {title: "测试数据", pid: "-1", id: '1', "space": "0",region_drill:"0", user_drill:"0",channel_drill:"0",contract_drill:"0", values: ["", "", "", ""]},
                {title: "测试数据11", pid: "1", id: '2', "space": "0",region_drill:"0", user_drill:"0",channel_drill:"0",contract_drill:"0", values: ["", "", "", ""]},
                {title: "测试数据12", pid: "1", id: '3', "space": "0",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1",values: ["", "-220", "", "100%"]},
                {title: "测试数据22", pid: "2", id: '4', "space": "0",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"0", values: ["20", "220", "20%", "100%"]},
                {title: "测试数据21", pid: "2", id: '5', "space": "1",region_drill:"0", user_drill:"0",channel_drill:"0",contract_drill:"1",  values: ["30", "220", "20%", "100%"]},
                {title: "测试数据23", pid: "2", id: '6', "space": "2", region_drill:"0", user_drill:"1",channel_drill:"0",contract_drill:"0",values: ["40", "-220", "20%", "100%"]},
                {title: "测试数据111", pid: "1", id: '7', "space": "1",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["50", "220", "20%", "100%"]},
                {title: "测试数据123", pid: "1", id: '8', "space": "2",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["60", "220", "20%", "100%"]},
                {title: "测试数据223", pid: "-1", id: '9', "space": "0",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["", "", "", ""]},
                {title: "测试数据321", pid: "9", id: '10', "space": "0", region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1",values: ["20", "-220", "20%", "100%"]},
                {title: "测试数据002", pid: "9", id: '11', "space": "0",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["", "220", "", "100%"]},
                {title: "测试数据234", pid: "11", id: '12', "space": "0",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["20", "220", "20%", "100%"]},
                {title: "测试数据43", pid: "11", id: '13', "space": "1", region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1",values: ["30", "-220", "20%", "100%"]},
                {title: "测试数据54", pid: "11", id: '14', "space": "2",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["40", "220", "20%", "100%"]},
                {title: "测试数据12345", pid: "9", id: '15', "space": "0",region_drill:"1", user_drill:"1",channel_drill:"1",contract_drill:"1", values: ["50", "220", "20%", "100%"]},
                {title: "测试数据54321", pid: "9", id: '16', "space": "0",region_drill:"0", user_drill:"0",channel_drill:"0",contract_drill:"0", values: ["60", "220", "20%", "100%"]}
            ],
            pid: "",
            clickId: "",
            area: this.props.area,
            city: this.props.city,
            date: this.props.date,
            rightClickKpiCode:"",
            client: '',
            channel: '',
            contract: this.props.contract
        }
    }
    static defaultProps={
        rightMenuItems:[
            {itemName:"地域",itemId:"region"},
            {itemName:"客户类型",itemId:"userType"},
            {itemName:"渠道类型",itemId:"channelType"},
            {itemName:"合约类型",itemId:"contractType"}
        ]
    };

    componentWillReceiveProps(nextProps){
         //debugger;
         if(nextProps&&nextProps.tabledata!=null&&nextProps.tabledata.datalist!=undefined&&nextProps.tabledata.datalist.length>0){
            this.setState({datalist:nextProps.tabledata.datalist,thData:nextProps.tabledata.title});
         }
     }

    /**
     * 递归获取table的合并行数,即rowspan
     * @param data
     * @returns {number} rowspan的值
     */
    getDepth(data) {
        var depth = 0;
        for (var i = 0; i < data.length; i++) {
            var _data = data[i];
            if (_data.title == undefined || _data.title == "") {
                depth++;
            }
            else {
                // _data.title有值,说明还有还有子table数据结构
                var _depth = this.getDepth(_data.data);
                depth += _depth;
            }
        }
        return depth;
    }

    /**
     * table后四td的style
     * @param index
     * @returns {string}
     */
    setNormalTdStyle(index,_down_drill) {//_down_drill(为false时)标示数据是否是下钻的数据,若是下钻的数据则鼠标变为默认箭头样式
        // debugger;
        if(_down_drill!=undefined){
            if(_down_drill==false){
                return index % 2 == 0 ? "bg-white mouse-icon-default" : "bg-blue mouse-icon-default";
            }
        }else {
            return index % 2 == 0 ? "bg-white mouse-icon-pointer" : "bg-blue mouse-icon-pointer";
        }
        // return index % 2 == 0 ? "bg-white" : "bg-blue"+" "+_down_drill==false?"mouse-icon-default":"mouse-icon-pointer";
    }

    handleLeftClick(kid, _down_drill) {
        // debugger
        if (_down_drill == undefined) {
            // debugger
            this.props.callbackParent(kid);
        } else if (_down_drill != undefined && _down_drill == false) {
            return;
        }
    }

    handleRightMenuClick(event) {
        // var moveId = event.target.id;
        var moveId = event.id;
        var pid = this.state.pid;
        var clickId = this.state.clickId;
        var kpi_code=this.state.rightClickKpiCode;
        var area = this.props.tableParams.area;
        var client = this.props.tableParams.user;
        var channel = this.props.tableParams.channel;
        var contract = this.props.tableParams.contract;
        var date=this.props.tableParams.date;
        var province_code=this.props.tableParams.pro;
        var city_code=this.props.tableParams.city;
        var _data = this.state.datalist;
        var _index = 0;
        var tableType = this.props.tableType;
        for (var i = 0; i < _data.length; i++) {
            if (_data[i].id == clickId) {
                _index = i + 1;
            }
        }
        var right_click_drill_url = "";
        var _self = this;
        switch (moveId) {
            case 'region':
                var _region_data = [
                 {title: "河北", pid: pid, id: '20', province: "1", "space":"1",values: ["5555", "55551", "225555", "222555555"]},
                 {title: "北京", pid: pid, id: '21', province: "1","space":"1", values: ["666", "55551", "225555", "222555555"]},
                 {title: "山西", pid: pid, id: '22', province: "1","space":"1", values: ["7777", "55551", "225555", "222555555"]},
                 {title: "山东", pid: pid, id: '23', province: "1","space":"1", values: ["888", "55551", "225555", "222555555"]},
                 ];
                 for (var i = 0; i < _region_data.length; i++) {
                 // _region_data[i].id=20+i+"";
                 _region_data[i].pid = pid;
                 _region_data[i].deleteMark = clickId;//插入的数据加入clickId(所点击行的id)标示,删除插入的数据时用此标识删除。
                 _region_data[i].bid = clickId;
                 _region_data[i].down_drill = false;//插入的数据加入down_drill标示,标示插入的数据不能下钻,不出现右击菜单。
                 _data.splice(_index + i, 0, _region_data[i]);
                 }
                 _self.setState({datalist: _data});
                break;
            case 'userType':
                var _user_type_data = [
                 {title: "公众", pid: pid, id: '24',"space":"1", values: ["89", "55551", "225555", "222555555"]},
                 {title: "集客", pid: pid, id: '25', "space":"1",values: ["56", "55551", "225555", "222555555"]},
                 ];
                for (var j = 0; j < _user_type_data.length; j++) {
                    _user_type_data[j].pid = pid;
                    _user_type_data[j].deleteMark = clickId;
                    _user_type_data[j].bid = clickId;
                    _user_type_data[j].down_drill = false;//插入的数据加入down_drill标示,标示插入的数据不能下钻,不出现右击菜单。
                    _data.splice(_index + j, 0, _user_type_data[j]);
                }
                _self.setState({datalist: _data});
                break;
            case 'channelType':
                var _channel_type_data = [
                 {title: "营业渠道", pid: pid, id: '26',"space":"1", values: ["89", "55551", "225555", "222555555"]},
                 {title: "社会渠道", pid: pid, id: '27', "space":"1",values: ["56", "55551", "225555", "222555555"]},
                 ];
                for (var k = 0; k < _channel_type_data.length; k++) {
                    _channel_type_data[k].pid = pid;
                    _channel_type_data[k].deleteMark = clickId;
                    _channel_type_data[k].bid = clickId;
                    _channel_type_data[k].down_drill = false;//插入的数据加入down_drill标示,标示插入的数据不能下钻,不出现右击菜单。
                    _data.splice(_index + k, 0, _channel_type_data[k]);
                }
                _self.setState({datalist: _data});
                break;
            case 'contractType':
                var _contract_type_data = [
                 {title: "存费送机", pid: pid, id: '28',"space":"1", values: ["89", "55551", "225555", "222555555"]},
                 {title: "存费送费", pid: pid, id: '29',"space":"1", values: ["56", "55551", "225555", "222555555"]},
                 ];
                for (var h = 0; h < _contract_type_data.length; h++) {
                    _contract_type_data[h].pid = pid;
                    _contract_type_data[h].deleteMark = clickId;
                    _contract_type_data[h].bid = clickId;
                    _contract_type_data[h].down_drill = false;//插入的数据加入down_drill标示,标示插入的数据不能下钻,不出现右击菜单。
                    _data.splice(_index + h, 0, _contract_type_data[h]);
                }
                _self.setState({datalist: _data});
                break;
        }
        // event.preventDefault();
        // event.stopPropagation();
        var menu = document.getElementById('rightMenuBox');
        menu.style.visibility = "hidden";
    }
    clearRightMenuTable(menuTable){
        var tr_len=menuTable.children.length;
        if(tr_len>0){
            for(var i=tr_len-1;i>=0;i--){
                var tr = menuTable.children[i];
                tr.parentNode.removeChild(tr);
            }
        }
    }
    createRightMenuItems(self,menuTable,data){
        var flag = [0, 0, 0, 0];
        var city = this.props.tableParams.city;
        var client = this.props.tableParams.user;
        var channel = this.props.tableParams.channel;
        var contract = this.props.tableParams.contract;
        /*var city = -1;
        var client = ["1"];
        var channel =  ["-1"];
        var contract =  ["-1"];*/
        if (city != "-1") {
            flag[0] = 1
        }
        if (client.length == 1) {
            if (client[0] != "-1") {
                flag[1] = 1
            }
        }
        if (channel.length == 1) {
            if (channel[0] != "-1") {
                flag[2] = 1
            }
        }
        if (contract.length == 1) {
            if (contract[0] != "-1") {
                flag[3] = 1
            }
        }
        var _right_menu_items=this.props.rightMenuItems;
        var _region_drill=data.region_drill,_user_drill=data.user_drill,_channel_drill=data.channel_drill,_contract_drill=data.contract_drill;
        var _row;
        var _cell;
        for(var j = 0; j <_right_menu_items.length; j++) {
            _row = document.createElement("tr");
            menuTable.appendChild(_row);
            _cell = document.createElement("td");
            _cell.id = _right_menu_items[j].itemId;
            _cell.innerText = _right_menu_items[j].itemName;
            if(_region_drill=="1"&&_right_menu_items[j].itemId=="region"&&flag[0]=="0"){//当单个指标地域可以下钻时,筛选条件的地域没有具体到地市时右击菜单可下钻
                _cell.className = "rightMenuTd";
                _cell.onclick = function () {
                    self.handleRightMenuClick(this)
                }; //为每个单元格增加单击事件
            }
            else if(_user_drill=="1"&&_right_menu_items[j].itemId=="userType"&&flag[1]=="0"){//当单个指标用户类型可以下钻时,筛选条件的用户类型为全部或者选择了两个以上时右击菜单可下钻
                _cell.className = "rightMenuTd";
                _cell.onclick = function () {
                    self.handleRightMenuClick(this)
                }; //为每个单元格增加单击事件
            }
            else if(_channel_drill=="1"&&_right_menu_items[j].itemId=="channelType"&&flag[2]=="0"){//当单个指标渠道类型可以下钻时,筛选条件的渠道类型为全部或者选择了两个以上时右击菜单可下钻
                _cell.className = "rightMenuTd";
                _cell.onclick = function () {
                    self.handleRightMenuClick(this)
                }; //为每个单元格增加单击事件
            }
            else if(_contract_drill=="1"&&_right_menu_items[j].itemId=="contractType"&&flag[3]=="0"){//当单个指标合约类型可以下钻时,筛选条件的合约类型为全部或者选择了两个以上时右击菜单可下钻
                _cell.className = "rightMenuTd";
                _cell.onclick = function () {
                    self.handleRightMenuClick(this)
                }; //为每个单元格增加单击事件
            }else {
                _cell.className = "norightMenuTd";
            }
            _row.appendChild(_cell);
        }
    }
    handleRightClick(pId, clickItemId, data, event) {
        //debugger;
        this.setState({pid: pId, clickId: clickItemId,rightClickKpiCode:data.kpiCode});
        // this.setState({pid: pId, clickId: clickItemId});
        var _down_drill = data.down_drill;
        if (event.button == 2) {
            var _data = this.state.datalist;
            var _index = -1; // clickItemId在 datalist的索引
            for (var i = _data.length - 1; i > 0; i--) {
                if (_data[i].delete_city_mark != undefined) {
                    if (_data[i].delete_city_mark == clickItemId) {
                        _data.splice(i, 1); // 根据id删除地市
                    }
                }
            }
            for (var j = _data.length - 1; j > 0; j--) {
                if (_data[j].deleteMark != undefined) {
                    if (_data[j].deleteMark == clickItemId) {
                        _data.splice(j, 1); // 根据id删除(省,客户类型,渠道类型,合约类型)
                    }
                }
            }
            if (_down_drill == undefined) {
                var contextMenu = document.getElementById("rightMenuBox");
                var menuTable=document.getElementById("rightMenuTable");

                this.clearRightMenuTable(menuTable);//清除右击菜单表格的所有tr

                let xOffset = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
                let yOffset = Math.max(document.documentElement.scrollTop, document.body.scrollTop);

                this.createRightMenuItems(this,menuTable,data);//生成右击菜单表格的所有tr。

                contextMenu.style.cssText =
                    'left: ' + (event.clientX + xOffset-30 ) + 'px;' +
                    'top: ' + (event.clientY + yOffset-45) + 'px;' +
                    'visibility: visible;';
            } else if (_down_drill != undefined && _down_drill == false) {
                return;
            }
            event.preventDefault();
            event.stopPropagation();
            var tableId = this.props.tableId;
            var reportTreeTable = document.getElementById(tableId);
            reportTreeTable.oncontextmenu = function () {
                return false;
            }
        } else if (event.button == 0) {
            this.handleLeftClick(data.kpiCode, _down_drill);
        }
    }
    /**
     * 箭头是否显示
     * @param isProvince -1:不显示,0: 显示并且不展开,1: 显示并且展开
     * @returns {string} 箭头style
     */
    setIconStyle(isProvince) {
        var arrowStyle = "rtt-icon rtt-icon";
        if (isProvince == -1) {
            arrowStyle += "-none";
        } else if (isProvince == 0) {
            arrowStyle += "-def"
        } else if (isProvince == 1) {
            arrowStyle += "-changed";
        } else {
            arrowStyle += "-none";
        }
        return arrowStyle;
    }

    handleProvinceClick(pId, clickItemId, bid, event) {//clickItemId当前点击的省的id
        var self = this;
        var tar = event.target;
        var className = tar.className;
        if (className.indexOf("rtt-icon") != -1) {
            if (className.indexOf("rtt-icon-changed") != -1) {
                tar.className = "rtt-icon rtt-icon-def";
                var _data_ = this.state.datalist;
                var _index = -1; // clickItemId在 datalist的索引
                for (var i = ( _data_.length - 1); i > 0; i--) {
                    if (_data_[i].id == clickItemId && _data_[i].bid == bid) {
                        _index = i; // 当前点击项clickItemId的在datalist的index
                    }
                    if (_data_[i].city != undefined) {
                        if (_data_[i].city == clickItemId && _data_[i].bid == bid) {
                            _data_.splice(i, 1); // 根据id删除
                        }
                    }
                }
                var _child_data = null;
                if (_index != -1) {
                    _child_data = _data_[_index]; // 根据_index拿到当前clickItemId的数据项,把箭头状态改为false
                    _child_data.arrowSelected = false;
                }
                this.setState({datalist: _data_});
            } else {
                tar.className = "rtt-icon rtt-icon-changed";
                var kpi_code=this.state.rightClickKpiCode;
                var area = this.props.tableParams.area;
                var client = this.props.tableParams.user;
                var channel = this.props.tableParams.channel;
                var contract = this.props.tableParams.contract;
                var date=this.props.tableParams.date;
                var province_code=this.props.tableParams.pro;
                var city_code=this.props.tableParams.city;
                var body="area="+area+"&prov="+province_code+"&city="+city_code+"&date="+date+"&client="+client+"&channel="+channel+"&contract="+contract+"&kid="+kpi_code;
                this.setState({pid: pId, clickId: clickItemId}, function () {
                    // debugger;
                    var pid = this.state.pid;
                    var clickId = this.state.clickId;
                    var _data = this.state.datalist;
                    var deleteCityMark = '';
                    var _index = 0;  // 当前点击项,要开始插入数据的位置
                    for (var i = 0; i < _data.length; i++) {
                        if (_data[i].id == clickId && _data[i].bid == bid) {
                            _index = i + 1;
                            deleteCityMark = _data[i].deleteMark;//插入省时点击的那一行指标名的id,(此标识用来标示地市所在指标名称)
                        }
                    }
                    var _child_data = _data[_index - 1]; // 当前点击的数据项 (_index-1)当前点击项在datalist的索引
                    _child_data.arrowSelected = true; // 将当前箭头状态改为展开
                    // debugger;

                    var tableType = this.props.tableType;
                    var city_url = "";
                    var _region_data_ = [
                     {
                     title: "石家庄",
                     // city: clickId,//clickId是点击的省的id,标示该城市属于哪个省
                     pid: pid,
                     id: '40',
                     "space":"2",
                     values: ["5555", "55551", "225555", "222555555"]
                     },
                     {
                     title: "邯郸",
                     // city: clickId,
                     pid: pid,
                     id: '41',
                     "space":"2",
                     values: ["666", "55551", "225555", "222555555"]
                     },
                     {
                     title: "保定",
                     // city: clickId,
                     pid: pid,
                     id: '42',"space":"2",
                     values: ["7777", "55551", "225555", "222555555"]
                     },
                     {
                     title: "承德",
                     // city: clickId,
                     pid: pid,
                     id: '43',"space":"2",
                     values: ["888", "55551", "225555", "222555555"]
                     },
                     ];
                     for (var i = 0; i < _region_data_.length; i++) {
                     _region_data_[i].pid = pid;
                     _region_data_[i].bid = bid;
                     _region_data_[i].city = clickId; //clickId是点击的省的id,标示该城市属于哪个省
                     _region_data_[i].delete_city_mark = deleteCityMark;//插入省时点击的那一行指标名的id,(此标识用来标示地市所在指标名称)
                     _region_data_[i].down_drill = false;//插入的数据加入down_drill标示,标示插入的数据不能下钻,不出现右击菜单。
                     _data.splice(_index + i, 0, _region_data_[i]);
                     }
                     self.setState({datalist: _data});
                });
            }
        }
    }

    /**
     * 生成table需要的tr,td结构
     * @param table 数组用来存放生成的tr数据
     * @param title 合并行td显示的数据
     * @param data 生成table的数据
     * @param level 控制嵌套table结构的深度 目前只有2级 level = {1|2}
     * @param ptitle 父合并行td显示的数据,当嵌套talbe在首位的时候需要
     * @param pdepth 父合并行的合并行数
     */
    getTableNode(table, title, data, level, ptitle, pdepth) {
        var _normal_td_width=0,_rowspan_td_width=0,_colspan_td_width=0,kpi_name_td_width=0;
        switch (window.screen.width){
            case 1366:
                _normal_td_width=100;
                _rowspan_td_width=80;
                _colspan_td_width=330;
                kpi_name_td_width=240;
                break;
            case 1920:
                _normal_td_width=180;
                _rowspan_td_width=120;
                _colspan_td_width=430;
                kpi_name_td_width=310;
                break;
        }
        if(data.length>0){
            data.map((d, index)=> {
                var _data = d;
                var obj = null;
                var isProvince = -1; // -1 不展示 0 展示不展开  1 展示并展开
                if (_data.province != undefined) {
                    if (_data.province == '1') {
                        // datalist数据项默认没有arrowSelected 只有在调用
                        // handleProvinceClick 方法{
                        //    var _child_data = _data[_index - 1];
                        //    _child_data.arrowSelected = true;
                        //} 才会生成
                        if (_data.arrowSelected == undefined || _data.arrowSelected == false) {
                            isProvince = 0;
                        } else {
                            isProvince = 1;
                        }
                    }
                }
                if (_data.values != undefined && _data.values.length > 0) {
                    var pId = _data.pid;
                    var clickItemId = _data.id;
                    var bid = _data.bid;
                    gIndex++;
                    if(_data.values.length>0){
                        var _down_drill=_data.down_drill;
                        var normalTd = _data.values.map((d, index)=> {
                            if (index == 1) {
                                if (d.length === 1) {
                                    return <td width={_normal_td_width}
                                               style={{color: 'black'}}
                                               className={this.setNormalTdStyle(gIndex, _down_drill)}
                                               onMouseDown={this.handleRightClick.bind(this, pId, clickItemId, _data)}>{d}</td>
                                } else {
                                    if (d.toString().substr(0, 1) == '-') {
                                        return <td width={_normal_td_width}
                                                   style={{color: 'red'}}
                                                   className={this.setNormalTdStyle(gIndex, _down_drill)}
                                                   onMouseDown={this.handleRightClick.bind(this, pId, clickItemId, _data)}>{d}</td>
                                    } else {
                                        return <td width={_normal_td_width}
                                                   style={{color: 'green'}}
                                                   className={this.setNormalTdStyle(gIndex, _down_drill)}
                                                   onMouseDown={this.handleRightClick.bind(this, pId, clickItemId, _data)}>{d}</td>
                                    }
                                }
                            } else {
                                return <td width={_normal_td_width}
                                           className={this.setNormalTdStyle(gIndex,_down_drill)}
                                           onMouseDown={this.handleRightClick.bind(this, pId, clickItemId, _data)}>{d}</td>
                            }
                        });
                    }

                }
                if (index == 0) {  // 合并行tr走此逻辑
                    //data是处理后的数据,以此来计算这条数据中包括几行,然后第一列合并多少行
                    var depth = this.getDepth(data);
                    //是否有嵌套table是否在首位
                    //_data.title == undefined || _data.title == "" 表示无嵌套table
                    // 否则有嵌套table
                    if (_data.title == undefined || _data.title == "") {
                        if (ptitle != undefined && ptitle != "") { // 当嵌套table在首位时走此逻辑
                            obj = <tr>
                                <td rowSpan={pdepth} width={_rowspan_td_width} className="kpi-bg">{ptitle}</td>
                                <td rowSpan={depth} width={_rowspan_td_width} className="kpi-bg-two">{title}</td>
                                <td width={level > 1 ? kpi_name_td_width : _colspan_td_width} colSpan={level == 1 ? 2 : 1}
                                    className="kpi-bg">
                                    <img src="../src/reportTable/images/hide.png"
                                         className={this.setIconStyle(isProvince)}
                                         onClick={this.handleProvinceClick.bind(this, pId, clickItemId, bid)}/>
                                    {_data.kpi_name}
                                </td>
                                {normalTd}
                            </tr>
                        } else { // 无嵌套table,或者嵌套table不在首位
                            obj = <tr>
                                <td rowSpan={depth} width={_rowspan_td_width} className="kpi-bg-two">{title}</td>
                                <td width={level > 1 ? kpi_name_td_width : _colspan_td_width} colSpan={level == 1 ? 2 : 1}
                                    className="kpi-bg" style={{'paddingLeft':5}}>
                                    <img src="../src/reportTable/images/hide.png"
                                         className={this.setIconStyle(isProvince)}
                                         onClick={this.handleProvinceClick.bind(this, pId, clickItemId, bid)}/>
                                    {_data.kpi_name}
                                </td>
                                {normalTd}
                            </tr>
                        }
                    } else { //有嵌套table走此逻辑,并且当嵌套table在首位时走此逻辑
                        this.getTableNode(table, _data.title, _data.data, ++level, title, depth);
                        --level;
                    }
                } else if (_data.title != undefined && _data.title != "") { //有嵌套table走此逻辑,嵌套table在不在首位时走此逻辑
                    this.getTableNode(table, _data.title, _data.data, ++level, "", 0);
                    --level;
                } else { // 不需要合并行的tr
                    //根据space设置空格
                    var space=_data.space*10+5+'px'
                    obj = <tr>
                        {/*   <td width={level > 1 ? 240 : 330} colSpan={level == 1 ? 2 : 1} // 根据level判断是否要合并列
                         className={classname}>*/}
                        <td width={level > 1 ? kpi_name_td_width : _colspan_td_width} colSpan={level == 1 ? 2 : 1} // 根据level判断是否要合并列
                            className='kpi-bg' style={{'paddingLeft':space}}>
                            <img src="../src/reportTable/images/hide.png"
                                 className={this.setIconStyle(isProvince)}
                                 onClick={this.handleProvinceClick.bind(this, pId, clickItemId, bid)}/>
                            {_data.kpi_name}
                        </td>
                        {normalTd}
                    </tr>
                }
                if (obj) {
                    table.push(obj);
                }
            })
        }
    }

    /**
     * 生成table
     * @param table
     * @param data
     */
    getTable(table, data) {
        var _normal_td_width=0;
        switch (window.screen.width){
            case 1366:
                _normal_td_width=100;
                break;
            case 1920:
                _normal_td_width=180;
                break;
        }
        var level = 1;
        if(data.length>0){
            data.map((d, index)=> {
                var _data = d.data;
                var title = d.title;
                if(_data!=undefined){
                    this.getTableNode(table, title, _data, level, "", 0);
                }
                else {
                    gIndex++;
                    var isProvince = -1; // -1 不展示 0 展示不展开  1 展示并展开
                    if (d.province != undefined) {
                        if (d.province == '1') {
                            // datalist数据项默认没有arrowSelected 只有在调用
                            // clickProvince 方法{
                            //    var _child_data = _data[_index - 1];
                            //    _child_data.arrowSelected = true;
                            //} 才会生成
                            if (d.arrowSelected == undefined || d.arrowSelected == false) {
                                isProvince = 0;
                            } else {
                                isProvince = 1;
                            }
                        }
                    }
                    if(d.values.length>0){
                        var _space=d.space*10;
                        var _down_drill=d.down_drill;
                        var normalTd1 = d.values.map((data, index)=> {
                            return <td width={_normal_td_width}
                                       className={this.setNormalTdStyle(gIndex,_down_drill)}
                                       onMouseDown={this.handleRightClick.bind(this, d.pid, d.id,d)}>{data}</td>
                        });
                    }
                    var trObj=<tr>
                        <td className="kpi-bg" colSpan="3" style={{paddingLeft:_space}}>
                            {/*<td className="kpi-bg" colSpan="3">*/}
                            <img src="../src/reportTable/images/hide.png"
                                 className={this.setIconStyle(isProvince)}
                                 onClick={this.handleProvinceClick.bind(this, d.pid, d.id,d.bid)}/>{d.kpi_name}</td>
                        {normalTd1}
                    </tr>;
                    table.push(trObj);
                }
            })
        }

    }

    setThBg(index) {
        return index == 0 ? 'kpi-bg' : '';
    }
    componentDidMount(){
        // debugger
        $("#report-table").mouseleave(function(){
            var menu = document.getElementById('rightMenuBox');
            menu.style.visibility = "hidden";
        });
    }
    /**
     * 数据数据
     * @param pid 父id
     * @param data
     * @returns {Array}
     */
    build(pid, data) {
        var parentList = [];
        for (var i = 0; i < data.length; i++) {
            var _data = data[i];
            if (_data.pid == pid) {
                var childList = this.build(_data.id, data);
                if (childList.length == 0) {  // childList.length==0 说明_data没有子项
                    parentList.push({
                        kpi_name: _data.title,
                        kpiCode:_data.kpiCode,
                        pid: _data.pid,
                        id: _data.id,
                        bid: _data.bid,
                        down_drill: _data.down_drill,
                        delete_city_mark: _data.delete_city_mark,
                        deleteMark: _data.deleteMark,
                        province: _data.province,
                        region_drill:_data.region_drill,
                        user_drill:_data.user_drill,
                        channel_drill:_data.channel_drill,
                        contract_drill:_data.contract_drill,
                        arrowSelected: _data.arrowSelected,// 箭头是否展示  true :展开  false:收起
                        values: _data.values,
                        space: _data.space,
                    });
                } else {
                    // _data有子项 将_data数据和childList压入数组
                    parentList.push({title: _data.title, pid: _data.pid, id: _data.id, data: childList});
                }
            }
        }
        return parentList;
    }

    componentDidMount(){
        $("#report-table").mouseleave(function(){
            var menu = document.getElementById('rightMenuBox');
            menu.style.visibility = "hidden";
        });
    }
    render() {
        var tree = [];
        var thData = this.state.thData;
        // var data = this.state.data;  //第一次定义的数据格式
        var dataList = this.state.datalist;
        var list = this.build(-1, dataList);
        var th = thData.map((d, index)=> {
            return <th className="tab-th" colSpan={index == 0 ? 3 : 1}>{d}</th>
        });
        gIndex = -1;
        this.getTable(tree, list);
        var tableId = this.props.tableId;
        var treeTableStyle=null;
        switch (window.screen.width){
            case 1366:
                treeTableStyle={
                    borderSpacing: '0px',
                    borderCollapse: 'collapse',
                    fontFamily: 'Microsoft YaHei',
                    fontWeight: '400',
                    fontStyle: 'normal',
                    fontSize: '14px',
                    marginBottom:'20px'
                };
                break;
            case 1920:
                treeTableStyle={
                    borderSpacing: '0px',
                    borderCollapse: 'collapse',
                    fontFamily: 'Microsoft YaHei',
                    fontWeight: '400',
                    fontStyle: 'normal',
                    fontSize: '18px',
                    marginBottom:'20px'
                };
                break;
        }
        return (
            <div id="report-table">
                <table style={treeTableStyle} id={tableId}>
                    <thead>
                    <tr>{th}</tr>
                    </thead>
                    <tbody>
                    {tree}
                    </tbody>
                </table>
                <div id="rightMenuBox">
                    <table id="rightMenuTable">
                    </table>
                </div>
            </div>
        );
    }
}

reportTreeTable.less文件

.bg-blue{
  //cursor: pointer;
  background-color: #EDF1F6;
  text-align: center;
}
.tab-th{
  height: 40px;
  color: #333333;
  text-align: center;
}
.bg-white{
  //cursor: pointer;
  background-color: #ffffff;
  text-align: center;
}
.mouse-icon-pointer{
   cursor: pointer;
 }
.mouse-icon-default{
  cursor: default;
  //cursor: not-allowed;
}
.kpi-bg{
  color:#FFF7F6;
  height: 48px;
  border: solid 1px #AEBECF;
  background-color: #B7CDE5;
}
.kpi-bg-two{
  color:#FFF7F6;
  height: 48px;
  padding-left: 10px;
  padding-right: 10px;
  border: solid 1px #AEBECF;
  background-color: #B7CDE5;
}

.kpi-bg-onespace {
  color:#FFF7F6;
  border: solid 1px #AEBECF;
  height: 48px;
  padding-left: 10px;
  background-color: #B7CDE5;
}
.kpi-bg-twospace {
  color:#FFF7F6;
  border: solid 1px #AEBECF;
  height: 48px;
  padding-left: 20px;
  background-color: #B7CDE5;
}
.kpi-bg-threespace {
  color:#FFF7F6;
  border: solid 1px #AEBECF;
  height: 48px;
  padding-left: 30px;
  background-color: #B7CDE5;
}
.kpi-bg-fourspace {
  color:#FFF7F6;
  border: solid 1px #AEBECF;
  height: 48px;
  padding-left: 40px;
  background-color: #B7CDE5;
}
@media only screen and (min-width:961px) and (max-width: 1366px){
  .rightMenuTd {
    cursor: default;
    border: solid 1px #cfcfcf;
    font-family: 'MicrosoftYaHei', 'Microsoft YaHei';
    font-size: 14px;
    width: 100px;
    height: 38px;
    text-align: center;
    background-color: #F0F0F0;
  }
  .norightMenuTd{
    cursor: no-drop;
    border: solid 1px #cfcfcf;
    font-family: 'MicrosoftYaHei', 'Microsoft YaHei';
    font-size: 14px;
    width: 100px;
    height: 38px;
    text-align: center;
    color: #9999FF;
    background-color: #F0F0F0;
  }
}
//右击菜单在1080p样式
@media only screen and (min-width:1367px) and (max-width: 1920px){
  .rightMenuTd {
    cursor: default;
    border: solid 1px #cfcfcf;
    font-family: 'MicrosoftYaHei', 'Microsoft YaHei';
    font-size: 18px;
    width: 130px;
    height: 45px;
    text-align: center;
    background-color: #F0F0F0;
  }
  .norightMenuTd{
    cursor: no-drop;
    border: solid 1px #cfcfcf;
    font-family: 'MicrosoftYaHei', 'Microsoft YaHei';
    font-size: 18px;
    width: 130px;
    height: 45px;
    text-align: center;
    color: #9999FF;
    background-color: #F0F0F0;
  }
}
.rightMenuTd:hover{
  background-color:#4A9AFB;
  //cursor: not-allowed;
}
#rightMenuBox {
  position: absolute;
  visibility: hidden;
  z-index: 1000;
}
.rtt-icon{
  width: 10px;
  height: 10px;
  cursor: pointer;
}
.rtt-icon-none{
  width: 15px;
  height: 15px;
  display: none;
}
.rtt-icon-def{
  -webkit-transform: rotateZ(0deg);
}
.rtt-icon-changed{
  -webkit-transform: rotateZ(90deg);
  transform:rotateZ(90deg);
  -ms-transform:rotateZ(90deg); /* IE 9 */
  -moz-transform:rotateZ(90deg); /* Firefox */
  -webkit-transform:rotateZ(90deg); /* Safari 和 Chrome */
  -o-transform:rotateZ(90deg); /* Opera */
}

表格截图:

初始显示:


任意数据右击:


点击右击菜单插入数据:


点击省份前面的小三角插入数据:


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用ReactJS编写谷歌插件,您需要使用Chrome扩展程序API。以下是一些步骤: 1.创建一个新的Chrome扩展程序项目,并在其中创建一个名为popup.html的文件。 2.在popup.html文件中,您需要添加一个div元素,该元素将用于呈现您的React组件。您还需要在文件中添加一个script标记,该标记将引用您的React组件的JavaScript文件。 3.创建一个名为popup.js的JavaScript文件,并在其中编写您的React组件。您可以使用JSX编写组件,因为Chrome扩展程序支持JSX。 4.在popup.js文件中,您需要使用Chrome扩展程序API来与浏览器进行交互。例如,您可以使用chrome.tabs API来获取当前选项卡的URL。 5.将您的React组件呈现到popup.html文件中的div元素中。 以下是一个简单的示例,演示如何使用ReactJS编写Chrome扩展程序: 1.在Chrome扩展程序项目中创建一个名为popup.html的文件,并添加以下内容: ```html <!DOCTYPE html> <html> <head> <title>My Extension</title> </head> <body> <div id="root"></div> <script src="popup.js"></script> </body> </html> ``` 2.创建一个名为popup.js的文件,并添加以下内容: ```javascript import React from 'react'; import ReactDOM from 'react-dom'; class MyComponent extends React.Component { constructor(props) { super(props); this.state = { url: '' }; } componentDidMount() { chrome.tabs.query({ active: true, currentWindow: true }, tabs => { this.setState({ url: tabs[0].url }); }); } render() { return <div>Current URL: {this.state.url}</div>; } } ReactDOM.render(<MyComponent />, document.getElementById('root')); ``` 3.在Chrome扩展程序项目中加载您的扩展程序,并单击浏览器工具栏中的扩展程序图标。您应该会看到一个弹出窗口,其中包含当前选项卡的URL。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值