zoukankan      html  css  js  c++  java
  • React使用antd Table生成层级多选组件

    一、需求

      用户对不同的应用需要有不同的权限,用户一般和角色关联在一起,新建角色的时候会选择该角色对应的应用,然后对应用分配权限。于是写了一种实现的方式。首先应用是一个二级树,一级表示的是应用分组,二级表示的是应用,这是table的最左边的数据。然后是按钮的数据,这里显示在table的头部。

    二、效果图如下

      

     三、具体代码

      1.RoleApplicationTable.js

    import React from 'react';
    import RoleCheckbox from 'components/role/RoleCheckbox';
    import {Menu, Table, message} from 'antd';
    import Btn from 'components/public/BaseBtn';
    import {connect} from 'react-redux'; 
    import 'styles/less/personType.less';
    import 'styles/less/basebtn.less';
    import Map from 'components/role/Map';
    import { operationRoleAppBtn, queryRoleAppBtnData} from 'actions/role';
    
    var mapStateToProps = function(state){
      return {
        roleData: state.getRole  
      }
    };
    //规范属性类型
    var propTypes = {
      personTypes: React.PropTypes.object,
      dispatch : React.PropTypes.func
    };
    class RoleApplicationTable extends React.Component {
        constructor(props) {
        super(props);
        this.state = {
          
        };
        this.chooseApp = this.chooseApp.bind(this);
        this.addColName = this.addColName.bind(this);
        this.addDataPid = this.addDataPid.bind(this);
        this.onChecked = this.onChecked.bind(this);
        this.addChildrenRow = this.addChildrenRow.bind(this);
        this.addData = this.addData.bind(this);
        this.isGroupRow = this.isGroupRow.bind(this);
        this.checkGroupAndColumnState = this.checkGroupAndColumnState.bind(this);//确保 组全选 和 列 全选
    
        this.cid = 0;
        this.rowNum = 0;
        this.colNum = 0;
    
        //map
        this.checkboxIdMapState= new Map();//checkboxId 映射 State
        this.parentRow = new Map();//每个checkboxId节点 对应最左边的哪个应用
        this.parentCol = new Map();//每个checkboxId节点 对应最上边的哪个按钮
        this.childrenRow = new Map();//当前行的所有子行
        this.checkboxIdMapData = new Map();//每个checkbox对应的 appid,btnGroupId
    
        //保存数据
        this.checked = null;//标识数据是 新增 还是 删除
        this.dataQueue = [];// appid,btngroupId队列
    
        //测试数据
        this.appData = [{name: '报表',id: "456",key: '5', children: [{ name: '合同价款', id: "45xx61", key: '6', },{ name: '合同台账', id: "45xf61", key: '7', }], }, { name: '图标', id: "789", key: '1', children: [{ name: '小图标', id: "45xx60", key: '4' },{ name: '大图标',  id: "4xx560", key: '8' }] }];
        this.btnGroupColumns = [{id: '12xx3', name: '小部件', colname: 'name'}, {id:'43xx5', name:'显示'}, {id:'43xfffx5', name:'test'}];
        }
    
    
      componentDidMount() {
        //const roleId = '4028968156b025da0156b027d0180000';
        const roleId = this.props.roleId;
        if(roleId) {//通过角色id加载 数据
          const { dispatch } = this.props;
          const querydata = {roleId: roleId};
          dispatch(queryRoleAppBtnData(querydata));
        }
      }
    
      componentWillReceiveProps(nextProps) {
        const {roleData} = nextProps;
        if (roleData.msg) {
          if(roleData.msg.indexOf('成功') >= 0)
            message.success(roleData.msg, 5);
          else if(roleData.msg.indexOf('失败') >= 0)
            message.error(roleData.msg, 5);
          else 
            message.info(roleData.msg, 5);
          // if (roleData.msg == '保存成功') {//角色保存成功后 仍然留在当前页面, 继续 角色按钮组权限
          //   this.props.history.pushState(null, 'rolecenter');
          // }
        }
      }
    
      chooseApp(){
        this.props.chooseApp();
      }
    
      sendCheckData(){
        const { dispatch } = this.props;
        const queryData = {
          vos: this.dataQueue,//对应后端的字段
        };
        dispatch(operationRoleAppBtn(this.checked, queryData));
      }
    
      ////////////////////////////////////////////////////////////////////////////////
      
      addChildrenRow(appData){//添加所有子行 标识
        if(!appData) return;
        for(var i=0; i<appData.length; ++i) {//获取行头的checkboxId
          this.rowNum++;//获取行号
          var curRowHeadCheckboxId = appData[i].name.split('_')[1];
          var childrenRow = this.childrenRow;
          if(!childrenRow.get(curRowHeadCheckboxId)) childrenRow.put(curRowHeadCheckboxId, []);
          this.addChildrenRow(appData[i].children);
          childrenRow.get(curRowHeadCheckboxId).push(curRowHeadCheckboxId);//加入当前行
          if(appData[i].children) {//加入子行
            for(var j=0; j<appData[i].children.length; ++j) {
              var childCurRowHeadCheckboxId = appData[i].children[j].name.split('_')[1];
              var descendants = childrenRow.get(childCurRowHeadCheckboxId);//孙子们节点
              for(var k=0; k<descendants.length; ++k){
                childrenRow.get(curRowHeadCheckboxId).push(descendants[k]);
              }
            }
          }
        }
      }
    
      addDataPid(btnGroupColumns, appData) {//生成新的列, 并且为非表头的每一个单元格设置固定 id,(防止表格渲染时 id发生变化)
        if(!appData) return;
        for(var i=0; i<appData.length; ++i) {
          for(var j=0; j<btnGroupColumns.length; ++j) {
            if(!appData[i][btnGroupColumns[j].colname]) {
              appData[i][btnGroupColumns[j].colname] = btnGroupColumns[j].id + '_' + (++this.cid);//为这一行数据添加新的列
    
              //判断应用对应的按钮是否已经选择上, judgeDefaultChecked
              
              if(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupId
                this.checkboxIdMapState.put(this.cid, true);
              } else {
                this.checkboxIdMapState.put(this.cid, false);
              }
            } else if(btnGroupColumns[j].colname == 'name'){
              if(appData[i][btnGroupColumns[j].colname].indexOf('_') >= 0) continue;
              appData[i][btnGroupColumns[j].colname] += '_' + (++this.cid);
              this.checkboxIdMapState.put(this.cid, false);
            }
          }
          this.addDataPid(btnGroupColumns, appData[i].children);
        }
      }
    
    
    
      addColName(btnGroupColumns, appData){
        if(btnGroupColumns) {
          btnGroupColumns.map((elem, index)=> { 
            if(!elem.colname) {
              elem.colname = elem.id;
            }
            elem.cid = ++this.cid;
          });
        }
    
        if(appData) {
          this.addDataPid(btnGroupColumns, appData);
          /////清空数据
          var keySet = this.childrenRow.keySet();
          for(var key in keySet){
            if(this.childrenRow.get(keySet[key]) && this.childrenRow.get(keySet[key]).length)
              this.childrenRow.get(keySet[key]).length = 0;
          }
          /////总行数
          this.rowNum = 0;
          this.addChildrenRow(appData);
          ++this.rowNum;
          /////判断应用对应的checkbox是否选中,列头对应的checkbox是否选中
          this.checkGroupAndColumnState();
        }
      }
    
      addData(cid, checked){
        var curCheckboxData = this.checkboxIdMapData.get(cid);
        if(curCheckboxData) {
          var curQueueData = {
            roleId: this.props.roleId,
            btnGroupId: curCheckboxData.btnGroupId,
            appId: curCheckboxData.appId,
          };
          this.dataQueue.push(curQueueData);
        }
      }
    
      isGroupRow(cid){//判断是否为分组
        //第一行当做分组
        if(parseInt((cid-1)/this.colNum)*this.colNum+1 == 1) return true;
    
        const parentRow = this.parentRow;
        const childrenRow = this.childrenRow;
        var curRowHeadCheckboxId = parentRow.get(cid) ? parentRow.get(cid) : parseInt((cid-1)/this.colNum)*this.colNum+1;//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离
        var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId
        return rowIds.length > 1 ? true : false;
      }
    
      checkGroupAndColumnState() {
        const childrenRow = this.childrenRow;
        const checkboxIdMapState = this.checkboxIdMapState;
        const colNum = this.colNum;
        const rowNum = this.rowNum;
    
        const rowState = [];
    
        for(var i=0; i<=rowNum; ++i)
          rowState.push(true)//默认所有的行全选
        rowState[1] = false;
    
        for(var row=2; row <= rowNum; ++row) {
          var cb = (row-1)*colNum+2;//这一行从第2个 checkbox 开始
          if(this.isGroupRow(cb)) {//分组行,不算入
            rowState[row] = false;
            continue;
          }
          var ce = row*colNum;
          var curRowState = true;//默认这一行全选
          for(var cid=cb; cid<=ce; ++cid) {//遍历这一行
            if(checkboxIdMapState.get(cid) == false) {
              curRowState = false;
              break;
            }
          }
          rowState[row] = curRowState;
          if(rowState[row] == true) {//应用对应的checkbox选中
            checkboxIdMapState.put((row-1)*colNum+1, true);
          } else {
            checkboxIdMapState.put((row-1)*colNum+1, false);
          }
        }
    
        //判断分组是否选中
        for(var row=2; row <= rowNum; ++row) {
          const cid = (row-1)*colNum+1;//每一行的第一个
          if(!this.isGroupRow(cid)) continue;
          //计算分组行
          var cids = childrenRow.get(cid);
          var groupState = true;//默认这个分组被选中
          for(var i=0; i<cids.length; ++i){
            if(cids[i] != cid) {//不是分组行
              var cur_row = (cids[i]-1)/this.colNum+1;
              if(rowState[cur_row] == false) {
                groupState = false;
                break;
              }
            }
          }
          for(var cur_cid=cid; cur_cid <= row*colNum; ++cur_cid){//当前分组行的 checkbox 状态
            checkboxIdMapState.put(cur_cid, groupState);
          }
          if(groupState == false) {//如果当前分组行没有状态改变,查看这一行的某一个分组列是否有变化
            const childRowNum = cids.length-1;
            for(var curRowCid = cid; curRowCid<cid+this.colNum; ++curRowCid) {//遍历这一分组行的checkboxId
              var curColState = true;
              for(var childRowCid = curRowCid+this.colNum, cnt = 0; cnt < childRowNum; childRowCid += this.colNum, ++cnt) {
                if(checkboxIdMapState.get(childRowCid) == false) {
                  curColState = false;
                  break;
                }
              }
              checkboxIdMapState.put(curRowCid, curColState);
            }
          }
        }
    
        // 判断列 是否被选中
        if(rowNum > 1) {
          for(var col=1; col<=colNum; ++col) {
            var curColState = true;
            for(var cid=col+colNum; cid<=colNum*rowNum; cid+=colNum){
              if(checkboxIdMapState.get(cid) == false) {
                curColState = false;
                break;
              }
            }
            var cid = col;
            checkboxIdMapState.put(cid, curColState);//这一列的状态
          }
        }
    
      }
    
      onChecked(cid, btnGroupId, appId, checked){//checkboxId, 按钮id,应用id
        const checkboxIdMapState = this.checkboxIdMapState;
        const parentRow = this.parentRow;
        const parentCol = this.parentCol;
        const childrenRow = this.childrenRow;
        const colNum = this.colNum;
        const rowNum = this.rowNum;
        //清空数据队列
        this.dataQueue.length = 0;
        //标识当前的操作
        this.checked = checked;
    
        if(btnGroupId == null && appId == null) {
          for(var cur_cid=1; cur_cid<=colNum*rowNum; ++cur_cid) {
            checkboxIdMapState.put(cur_cid, checked);
            if(!this.isGroupRow(cur_cid))
              this.addData(cur_cid, checked);
          }
        } else if(btnGroupId == null) {//appId 不为null, 这一行全选
          var rowHeadCheckboxIds = childrenRow.get(cid);//所有子行的行头的 checkboxId
          for(var i=0; i<rowHeadCheckboxIds.length; ++i) {
            var cur_cid = rowHeadCheckboxIds[i];
            var cur_row_max_cid = parseInt(cur_cid) + colNum;
            while(cur_cid < cur_row_max_cid){
              checkboxIdMapState.put(cur_cid, checked);
              if(!this.isGroupRow(cur_cid))
                this.addData(cur_cid, checked);
              ++cur_cid;
            }
          }
        } else if(appId == null) {//btnId不为null,这一列全部check
          var cur_cid = cid;
          while(cur_cid <= rowNum*colNum) {
            checkboxIdMapState.put(cur_cid, checked);
            if(!this.isGroupRow(cur_cid)) 
              this.addData(cur_cid, checked);
            cur_cid += colNum;
          }
        } else {//都不为null
          var curRowHeadCheckboxId = parentRow.get(cid);//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离
          var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId
          for(var i=0; i<rowIds.length; ++i) {//这一列全部check
            var cur_cid = parseInt(rowIds[i]) + (cid-curRowHeadCheckboxId);
            checkboxIdMapState.put(cur_cid, checked);
            if(!this.isGroupRow(cur_cid))
              this.addData(cur_cid, checked);
          }
          
        }
        this.setState({});
        this.sendCheckData();//发送数据
      }
    
    
      ////////////////////////////////////////////////////////////////////////////////
    
        render() {
        const appData = this.appData;
        const btnGroupColumns = this.btnGroupColumns;
        console.log(appData)
        let self = this;
        this.cid = 0;
        this.colNum = btnGroupColumns.length;//获得列宽
        const checkboxIdMapState = this.checkboxIdMapState;
        const parentRow = this.parentRow;
        const parentCol = this.parentCol
        if(btnGroupColumns) {
          this.addColName(btnGroupColumns, appData);//对应用的数据进行一个简单的处理
    
          btnGroupColumns.map((elem, index)=> { 
            //elem.colname=='name' ? null : elem.id, 默认左上角的id 没有 appId 和 btnGroupId
            elem.title= <RoleCheckbox btnGroupId={elem.colname=='name' ? null : elem.id} appId={null} cid={elem.cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(elem.cid)} title={elem.name}/>,
            elem.key = elem.dataIndex = elem.colname;
            elem.render = function(text, record, index){// text的值 == 对应表头列的Id == elem.id
              var contents = text.split('_');
              text = contents[0];
              var cur_cid = contents[1];//当前列顶端 checkboxId
    
              //判断是否是第一列
              if(record.name.split('_')[0] != text) {//不是第一列
                var leftCheckBoxId = record.name.split('_')[1];
                parentRow.put(cur_cid, leftCheckBoxId);//该 checkboxId 对应的 (应用Id == leftCheckBoxId)
    
                //加入每个checkbox  要传输的数据(appId, btnGroupId)
                self.checkboxIdMapData.put(cur_cid, {appId: record.id, btnGroupId: elem.id})
              }
              //该 checkboxId 对应的 最上边的 checkboxId
              parentCol.put(cur_cid, elem.cid);//该 checkboxId 对应的 (按钮Id == elem.cid)
    
              //record.name.split('_')[0] 最原始的 name 的value
              return <RoleCheckbox btnGroupId={record.name.split('_')[0] == text ? null : elem.id} appId={record.id} cid={cur_cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(cur_cid)} title={text==elem.id ? null : text}/>
            }
          });
        }
    
        return (
          <div>
            <Btn iconName="icon-add" onClick={this.chooseApp} btnClass="add-btn" btnName="选择应用"/>
            <Table 
              indentSize={15}
              className="personType-table" 
              columns={btnGroupColumns} 
              dataSource={appData} 
              pagination={false}
            />
          </div>
        );
      }
    }
    module.exports = RoleApplicationTable;
    RoleApplicationTable.propTypes = propTypes;
    module.exports = connect(mapStateToProps)(RoleApplicationTable);
    View Code

      利用antd table实现层级多选组件。

      具体思路:

    addDataPid(btnGroupColumns, appData) {//生成新的列, 并且为非表头的每一个单元格设置固定 id,(防止表格渲染时 id发生变化)
      if(!appData) return;
      for(var i=0; i<appData.length; ++i) {
        for(var j=0; j<btnGroupColumns.length; ++j) {
          if(!appData[i][btnGroupColumns[j].colname]) {
            appData[i][btnGroupColumns[j].colname] = btnGroupColumns[j].id + '_' + (++this.cid);//为这一行数据添加新的列
    
            //判断应用对应的按钮是否已经选择上, judgeDefaultChecked
            
            if(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupId
              this.checkboxIdMapState.put(this.cid, true);
            } else {
              this.checkboxIdMapState.put(this.cid, false);
            }
          } else if(btnGroupColumns[j].colname == 'name'){
            if(appData[i][btnGroupColumns[j].colname].indexOf('_') >= 0) continue;
            appData[i][btnGroupColumns[j].colname] += '_' + (++this.cid);
            this.checkboxIdMapState.put(this.cid, false);
          }
        }
        this.addDataPid(btnGroupColumns, appData[i].children);
      }
    }
    
    addColName(btnGroupColumns, appData){//为每一列添加 映射字段 colname
      if(btnGroupColumns) {
        btnGroupColumns.map((elem, index)=> { 
          if(!elem.colname) {
            elem.colname = elem.id;
          }
          elem.cid = ++this.cid;
        });
      }
    
      if(appData) {
        this.addDataPid(btnGroupColumns, appData);
        /////清空数据
        var keySet = this.childrenRow.keySet();
        for(var key in keySet){
          if(this.childrenRow.get(keySet[key]) && this.childrenRow.get(keySet[key]).length)
            this.childrenRow.get(keySet[key]).length = 0;
        }
        /////总行数
        this.rowNum = 0;
        this.addChildrenRow(appData);
        ++this.rowNum;
        /////判断应用对应的checkbox是否选中,列头对应的checkbox是否选中
        this.checkGroupAndColumnState();
      }
    }

      2.RoleCheckbox.js

    import {Checkbox} from 'antd';
    import React from 'react';
    class RoleCheckbox extends React.Component{
      constructor(props) {
        super(props);
        this.onChange = this.onChange.bind(this);
      }
    
      onChange(e){
        const cid = this.props.cid;
        const btnGroupId = this.props.btnGroupId;
        const appId = this.props.appId;
        this.props.onChecked(cid, btnGroupId, appId, e.target.checked);
      }
      
        render() {
        const checked = this.props.checked;
        const title = this.props.title;
        const cid = this.props.cid;
            return(
            <div>
              <Checkbox checked={checked} onChange={this.onChange}/>{title}
            </div>
            );
        }
    }
    module.exports = RoleCheckbox;
    View Code

       封装antd 的Checkbox组件

      3.Map.js

    class Map {
        constructor(){
            this.container = new Object();
        }
    
        put(key, value){
            this.container[key] = value;
        }
    
        get(key){
            return this.container[key];
        }
    
        keySet() {
            var keyset = new Array();
            var count = 0;
            for (var key in this.container) {
                // 跳过object的extend函数
                if (key == 'extend') {
                continue;
            }
                keyset[count] = key;
                count++;
            }
            return keyset;
        }
    
        size() {
            var count = 0;
            for (var key in this.container) {
                // 跳过object的extend函数
                if (key == 'extend'){
                    continue;
                }
                count++;
            }
            return count;
        }
    
        remove(key) {
            delete this.container[key];
        }
    
        toString(){
            var str = "";
            for (var i = 0, keys = this.keySet(), len = keys.length; i < len; i++) {
                str = str + keys[i] + "=" + this.container[keys[i]] + ";
    ";
            }
            return str;
        }
    }
    
    module.exports = Map;
    View Code

      js实现的Map工具类。

     四、需求变更

      功能虽然完成了,但是总是避免不了需求的变更。要求选择左边应用对应的checkbox时,不在操作该应用对应的按钮的checkbox,也就是整个行不是全选了。应用对应的checkbox用来进行删除操作。

      1.改变后的Table效果

      

      2.RoleApplicationTable.js

    import React from 'react';
    import RoleCheckbox from 'components/role/RoleCheckbox';
    import {Menu, Table, message, Modal} from 'antd';
    const confirm = Modal.confirm;
    import Btn from 'components/public/BaseBtn';
    import {connect} from 'react-redux'; 
    import 'styles/less/personType.less';
    import 'styles/less/basebtn.less';
    import Map from 'components/role/Map';
    import { operationRoleAppBtn, queryRoleAppBtnData, deleteAppAction} from 'actions/role';
    
    var mapStateToProps = function(state){
      return {
        roleData: state.getRole  
      }
    };
    //规范属性类型
    var propTypes = {
      personTypes: React.PropTypes.object,
      dispatch : React.PropTypes.func
    };
    class RoleApplicationTable extends React.Component {
        constructor(props) {
        super(props);
        this.state = {
          isEdit: true,
        };
        this.chooseApp = this.chooseApp.bind(this);
        this.addColName = this.addColName.bind(this);
        this.addDataPid = this.addDataPid.bind(this);
        this.onChecked = this.onChecked.bind(this);
        this.addChildrenRow = this.addChildrenRow.bind(this);
        this.addAppBtnData = this.addAppBtnData.bind(this);
        this.addAppData = this.addAppData.bind(this);
        this.isGroupRow = this.isGroupRow.bind(this);
        this.checkGroupAndColumnState = this.checkGroupAndColumnState.bind(this);//确保 组全选 和 列 全选
        this.deleteApp = this.deleteApp.bind(this);
        this.showConfirm = this.showConfirm.bind(this);
        this.initRoleAppBtnData = this.initRoleAppBtnData.bind(this);
        this.cancelChooseState = this.cancelChooseState.bind(this);
        this.saveCheckedAppBtn = this.saveCheckedAppBtn.bind(this);
        this.afterSaveCheckedAppBtn = this.afterSaveCheckedAppBtn.bind(this);
    
        this.cid = 0;
        this.rowNum = 0;
        this.colNum = 0;
    
        //map
        this.checkboxIdMapState= new Map();//checkboxId 映射 State
        this.parentRow = new Map();//每个checkboxId节点 对应最左边的哪个应用
        this.parentCol = new Map();//每个checkboxId节点 对应最上边的哪个按钮
        this.childrenRow = new Map();//当前行的所有子行
        this.checkboxIdMapAppBtnData = new Map();//每个checkbox对应的 appid,btnGroupId
        this.checkboxIdMapAppData = new Map();//记录被选中的应用
    
        //保存数据
        this.dataQueue = [];// appid,btngroupId队列
        //删除应用
        this.deleteAppIds = [];
    
        //测试数据
        this.appData = [{name: '报表',id: "456",key: '5', children: [{ name: '合同价款', id: "45xx61", key: '6', },{ name: '合同台账', id: "45xf61", key: '7', }], }, { name: '图标', id: "789", key: '1', children: [{ name: '小图标', id: "45xx60", key: '4' },{ name: '大图标',  id: "4xx560", key: '8' }] }];
        this.btnGroupColumns = [{id: '12xx3', name: '小部件', colname: 'name'}, {id:'43xx5', name:'显示'}, {id:'43xfffx5', name:'test'}];
        }
    
      //确认提示框
      showConfirm(title,message,dispatch,functionT,functionQueryData) {
        confirm({
          title: title,
          content: message,
          onOk() {
            dispatch(functionT(functionQueryData));  
          },
          onCancel() {
            
          }
        });
      }
    
      componentDidMount() {
        //const roleId = '4028968156b025da0156b027d0180000';
        this.initRoleAppBtnData();
      }
    
      initRoleAppBtnData(){
        const roleId = this.props.roleId;
        if(roleId) {//通过角色id加载 数据
          const { dispatch } = this.props;
          const querydata = {roleId: roleId};
          dispatch(queryRoleAppBtnData(querydata));
        }
      }
    
      cancelChooseState(){//取消权限的更改
        this.initRoleAppBtnData();
      }
    
      componentWillReceiveProps(nextProps) {
        const {roleData} = nextProps;
        if (roleData.msg) {
          if(roleData.msg.indexOf('成功') >= 0)
            message.success(roleData.msg, 5);
          else if(roleData.msg.indexOf('失败') >= 0)
            message.error(roleData.msg, 5);
          else 
            message.info(roleData.msg, 5);
          // if (roleData.msg == '保存成功') {//角色保存成功后 仍然留在当前页面, 继续 角色按钮组权限
          //   this.props.history.pushState(null, 'rolecenter');
          // }
        }
      }
    
      chooseApp(){
        this.props.chooseApp();
      }
    
      sendCheckData(){
        const { dispatch } = this.props;
        const queryData = {
          'vos': this.dataQueue,//对应后端的字段
          'roleId': this.props.roleId,
        };
        dispatch(operationRoleAppBtn(queryData, this.afterSaveCheckedAppBtn));
      }
    
      ////////////////////////////////////////////////////////////////////////////////
      
      addChildrenRow(appData){//添加所有子行 标识
        if(!appData) return;
        for(var i=0; i<appData.length; ++i) {//获取行头的checkboxId
          this.rowNum++;//获取行号
          var curRowHeadCheckboxId = appData[i].name.split('_')[1];
          var childrenRow = this.childrenRow;
          if(!childrenRow.get(curRowHeadCheckboxId)) childrenRow.put(curRowHeadCheckboxId, []);
          this.addChildrenRow(appData[i].children);
          childrenRow.get(curRowHeadCheckboxId).push(curRowHeadCheckboxId);//加入当前行
          if(appData[i].children) {//加入子行
            for(var j=0; j<appData[i].children.length; ++j) {
              var childCurRowHeadCheckboxId = appData[i].children[j].name.split('_')[1];
              var descendants = childrenRow.get(childCurRowHeadCheckboxId);//孙子们节点
              for(var k=0; k<descendants.length; ++k){
                childrenRow.get(curRowHeadCheckboxId).push(descendants[k]);
              }
            }
          }
        }
      }
    
      addDataPid(btnGroupColumns, appData) {//生成新的列, 并且为非表头的每一个单元格设置固定 id,(防止表格渲染时 id发生变化)
        if(!appData) return;
        for(var i=0; i<appData.length; ++i) {
          for(var j=0; j<btnGroupColumns.length; ++j) {
            if(!appData[i][btnGroupColumns[j].colname]) {
              appData[i][btnGroupColumns[j].colname] = btnGroupColumns[j].id + '_' + (++this.cid);//为这一行数据添加新的列
    
              //判断应用对应的按钮是否已经选择上, judgeDefaultChecked
              
              if(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupId
                this.checkboxIdMapState.put(this.cid, true);
              } else {
                this.checkboxIdMapState.put(this.cid, false);
              }
            } else if(btnGroupColumns[j].colname == 'name'){
              if(appData[i][btnGroupColumns[j].colname].indexOf('_') >= 0) continue;
              appData[i][btnGroupColumns[j].colname] += '_' + (++this.cid);
              this.checkboxIdMapState.put(this.cid, false);
            }
          }
          this.addDataPid(btnGroupColumns, appData[i].children);
        }
      }
    
      addColName(btnGroupColumns, appData){
        if(btnGroupColumns) {
          btnGroupColumns.map((elem, index)=> { 
            if(!elem.colname) {
              elem.colname = elem.id;
            }
            elem.cid = ++this.cid;
          });
        }
    
        if(appData) {
          this.addDataPid(btnGroupColumns, appData);
          /////清空数据
          var keySet = this.childrenRow.keySet();
          for(var key in keySet){
            if(this.childrenRow.get(keySet[key]) && this.childrenRow.get(keySet[key]).length)
              this.childrenRow.get(keySet[key]).length = 0;
          }
          /////总行数
          this.rowNum = 0;
          this.addChildrenRow(appData);
          ++this.rowNum;
          /////判断应用对应的checkbox是否选中,列头对应的checkbox是否选中
          this.checkGroupAndColumnState();
        }
      }
    
      addAppBtnData(cid){
        var curCheckboxData = this.checkboxIdMapAppBtnData.get(cid);
        if(curCheckboxData) {
          var curQueueData = {
            roleId: this.props.roleId,
            btnGroupId: curCheckboxData.btnGroupId,
            appId: curCheckboxData.appId,
          };
          this.dataQueue.push(curQueueData);
        }
      }
    
      addAppData(cid){
        var checked = this.checkboxIdMapState.get(cid);
        if(checked == false) return;
        var curAppId = this.checkboxIdMapAppData.get(cid);
        if(curAppId) {
          var curQueueData = {
            roleId: this.props.roleId,
            appId: curAppId,
          };
          this.deleteAppIds.push(curQueueData);
        }
      }
    
      isGroupRow(cid){//判断是否为分组
        //第一行当做分组
        if(parseInt((cid-1)/this.colNum)*this.colNum+1 == 1) return true;
    
        const parentRow = this.parentRow;
        const childrenRow = this.childrenRow;
        var curRowHeadCheckboxId = parentRow.get(cid) ? parentRow.get(cid) : parseInt((cid-1)/this.colNum)*this.colNum+1;//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离
        var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId
        return rowIds.length > 1 ? true : false;
      }
    
      checkGroupAndColumnState() {
        const childrenRow = this.childrenRow;
        const checkboxIdMapState = this.checkboxIdMapState;
        const colNum = this.colNum;
        const rowNum = this.rowNum;
    
        const rowState = [];
    
        for(var i=0; i<=rowNum; ++i)
          rowState.push(true)//默认所有的行全选
        rowState[1] = false;
    
        //判断分组列
        for(var row=2; row <= rowNum; ++row) {
          const cid = (row-1)*colNum+1;//每一行的第一个
          if(!this.isGroupRow(cid)) continue;
          var cids = childrenRow.get(cid);
          const childRowNum = cids.length-1;
          for(var curRowCid = cid; curRowCid<cid+this.colNum; ++curRowCid) {//遍历这一分组行的checkboxId
            var curColState = true;
            for(var childRowCid = curRowCid+this.colNum, cnt = 0; cnt < childRowNum; childRowCid += this.colNum, ++cnt) {
              if(checkboxIdMapState.get(childRowCid) == false) {
                curColState = false;
                break;
              }
            }
            checkboxIdMapState.put(curRowCid, curColState);
          }
        }
    
        // 判断列 是否被选中
        if(rowNum > 1) {
          for(var col=1; col<=colNum; ++col) {
            var curColState = true;
            for(var cid=col+colNum; cid<=colNum*rowNum; cid+=colNum){
              if(checkboxIdMapState.get(cid) == false) {
                curColState = false;
                break;
              }
            }
            var cid = col;
            checkboxIdMapState.put(cid, curColState);//这一列的状态
          }
        } else if(rowNum == 1) {//每一列的状态清空
          for(var cid = 1; cid <= this.colNum; ++cid)
            checkboxIdMapState.put(cid, false);
        }
    
      }
    
      onChecked(cid, btnGroupId, appId, checked){//checkboxId, 按钮id,应用id
        if(this.state.isEdit == true && cid%this.colNum != 1) {//第一列为应用列,随时可以编辑
          message.info('请进入编辑状态', 2);
          return ;
        }
        const checkboxIdMapState = this.checkboxIdMapState;
        const parentRow = this.parentRow;
        const parentCol = this.parentCol;
        const childrenRow = this.childrenRow;
        const colNum = this.colNum;
        const rowNum = this.rowNum;
    
        if(btnGroupId == null && appId == null) {
          for(var cur_cid=1; cur_cid<=colNum*rowNum; cur_cid+=colNum) {
            checkboxIdMapState.put(cur_cid, checked);
          }
        } else if(btnGroupId == null) {//appId 不为null, 所有的子应用全选
          var rowHeadCheckboxIds = childrenRow.get(cid);//所有子行的行头的 checkboxId(对应应用)
          for(var i=0; i<rowHeadCheckboxIds.length; ++i) {
            var cur_cid = rowHeadCheckboxIds[i];
            checkboxIdMapState.put(cur_cid, checked);
          }
        } else if(appId == null) {//btnId不为null,这一列全部check
          var cur_cid = cid;
          while(cur_cid <= rowNum*colNum) {
            checkboxIdMapState.put(cur_cid, checked);
            cur_cid += colNum;
          }
        } else {//都不为null
          var curRowHeadCheckboxId = parentRow.get(cid);//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离
          var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId
          for(var i=0; i<rowIds.length; ++i) {//这一列全部check
            var cur_cid = parseInt(rowIds[i]) + (cid-curRowHeadCheckboxId);
            checkboxIdMapState.put(cur_cid, checked);
          }
          
        }
        this.setState({});
      }
    
      deleteApp(){
        this.deleteAppIds.length = 0;//清空数据
        const {dispatch} = this.props;
        for(var cid = 1; cid <= this.rowNum*this.colNum; cid += this.colNum) {
          if(!this.isGroupRow(cid)) {
            this.addAppData(cid);
          }
        }
    
        if(this.deleteAppIds.length == 0) {
          message.success('请选择应用', 5);
          return;
        }
    
        const queryData = {
          vos: this.deleteAppIds,
        }
    
        this.showConfirm('删除应用', '确定删除应用?', dispatch, deleteAppAction, queryData); 
      }
    
      afterSaveCheckedAppBtn(){
        this.setState({
          isEdit: true,
        });
      }
    
      saveCheckedAppBtn(){
        if(this.state.isEdit == true) {
          this.setState({
            isEdit: false,
          });
          return ;
        } 
        //清空数据队列
        this.dataQueue.length = 0;
        for(var cid = this.colNum+1; cid <= this.colNum*this.rowNum; ++cid) {//从第二行的checkbox 开始
          if(this.isGroupRow(cid)) {
            cid += this.colNum;
          }
          if(cid%this.colNum != 1) {//第一列为 应用列
            if(this.checkboxIdMapState.get(cid) == true)
              this.addAppBtnData(cid);
          }
        }
    
        this.sendCheckData();
      }
    
      ////////////////////////////////////////////////////////////////////////////////
    
        render() {
        let {roleData} = this.props;
        var appData = [];
        var btnGroupColumns = [];
        if(roleData.permissiondData) {
          if(roleData.permissiondData.listAppBtnGroup) {
            btnGroupColumns = roleData.permissiondData.listAppBtnGroup;
          }
          if(roleData.permissiondData.listPermissionApp) {
            appData = roleData.permissiondData.listPermissionApp;
          }
        }
        // const appData = this.appData;
        // const btnGroupColumns = this.btnGroupColumns;
        // console.log(appData)
        let self = this;
        this.cid = 0;
        this.colNum = btnGroupColumns.length;//获得列宽
        const checkboxIdMapState = this.checkboxIdMapState;
        const parentRow = this.parentRow;
        const parentCol = this.parentCol
        if(btnGroupColumns) {
          this.addColName(btnGroupColumns, appData);//对应用的数据进行一个简单的处理
    
          btnGroupColumns.map((elem, index)=> { 
            //elem.colname=='name' ? null : elem.id, 默认左上角的id 没有 appId 和 btnGroupId
            elem.title= <RoleCheckbox btnGroupId={elem.colname=='name' ? null : elem.id} appId={null} cid={elem.cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(elem.cid)} title={elem.name}/>,
            elem.key = elem.dataIndex = elem.colname;
            elem.render = function(text, record, index){// text的值 == 对应表头列的Id == elem.id
              var contents = text.split('_');
              text = contents[0];
              var cur_cid = contents[1];//当前列顶端 checkboxId
    
              //判断是否是第一列
              if(record.name.split('_')[0] != text) {//不是第一列
                var leftCheckBoxId = record.name.split('_')[1];
                parentRow.put(cur_cid, leftCheckBoxId);//该 checkboxId 对应的 (应用Id == leftCheckBoxId)
    
                //加入每个checkbox  要传输的数据(appId, btnGroupId)
                self.checkboxIdMapAppBtnData.put(cur_cid, {appId: record.id, btnGroupId: elem.id})
              } else {//应用列
                self.checkboxIdMapAppData.put(cur_cid, record.id);
              }
              //该 checkboxId 对应的 最上边的 checkboxId
              parentCol.put(cur_cid, elem.cid);//该 checkboxId 对应的 (按钮Id == elem.cid)
    
              //record.name.split('_')[0] 最原始的 name 的value
              return <RoleCheckbox btnGroupId={record.name.split('_')[0] == text ? null : elem.id} appId={record.id} cid={cur_cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(cur_cid)} title={text==elem.id ? null : text}/>
            }
          });
        }
    
        return (
          <div>
            <Btn iconName="icon-add" isdisabled={self.props.roleId ? false : true} onClick={this.chooseApp} btnClass="add-btn" btnName="选择应用"/>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <Btn iconName="icon-jianhao" isdisabled={self.props.roleId ? false : true} btnClass="delete-btn" btnName="删除应用" onClick={self.deleteApp}/>  
            <Table style={{marginTop: "10px", marginBottom: "10px"}}
              indentSize={15}
              className="personType-table" 
              columns={btnGroupColumns} 
              dataSource={appData} 
              pagination={false}
            />
            <div style={{display: self.rowNum > 1 ? '' : 'none'}}>
              <Btn btnClass="save-btn" btnName={self.state.isEdit == true ? "编辑" : "保存"} onClick={this.saveCheckedAppBtn}/>
              &nbsp;&nbsp;&nbsp;&nbsp;
              <Btn btnClass="cancel-btn" btnName="取消" onClick={self.cancelChooseState}/>
            </div>
          </div>
        );
      }
    }
    module.exports = RoleApplicationTable;
    RoleApplicationTable.propTypes = propTypes;
    module.exports = connect(mapStateToProps)(RoleApplicationTable);
    View Code

    五、心得体会

      最近使用react + redux + webpack进行web开发,感觉进步很快,已经熟悉了基本的流程。后续要研究一下webpack。

  • 相关阅读:
    jquery直接操作元素的方式
    ie6下,给a添加事件,如果事件中有http请求,将会无效
    一个Tahoma字体bug引发的思考—关于样式bug的分析流程
    用弧度画圆
    【译】OWIN: Open Web Server Interface for .NET
    【译】Dependency Injection with Autofac
    Asp.net Identity身份与权限体系设计
    winform 数据(双向)绑定 快速更新实体
    泛型与非泛型的区别。
    使用XmlReader读Xml
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/5812046.html
Copyright © 2011-2022 走看看