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。

  • 相关阅读:
    Balance的数学思想构造辅助函数
    1663. Smallest String With A Given Numeric Value (M)
    1680. Concatenation of Consecutive Binary Numbers (M)
    1631. Path With Minimum Effort (M)
    1437. Check If All 1's Are at Least Length K Places Away (E)
    1329. Sort the Matrix Diagonally (M)
    1657. Determine if Two Strings Are Close (M)
    1673. Find the Most Competitive Subsequence (M)
    1641. Count Sorted Vowel Strings (M)
    1679. Max Number of K-Sum Pairs (M)
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/5812046.html
Copyright © 2011-2022 走看看