React使用antd Table生成層級多選組件

1、需求

  用戶對不一樣的應用須要有不一樣的權限,用戶通常和角色關聯在一塊兒,新建角色的時候會選擇該角色對應的應用,而後對應用分配權限。因而寫了一種實現的方式。首先應用是一個二級樹,一級表示的是應用分組,二級表示的是應用,這是table的最左邊的數據。而後是按鈕的數據,這裏顯示在table的頭部。react

2、效果圖以下

  

 3、具體代碼

  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實現層級多選組件。webpack

  具體思路:web

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組件redux

  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]] + ";\n";
        }
        return str;
    }
}

module.exports = Map;
View Code

  js實現的Map工具類。後端

 4、需求變動

  功能雖然完成了,可是老是避免不了需求的變動。要求選擇左邊應用對應的checkbox時,不在操做該應用對應的按鈕的checkbox,也就是整個行不是全選了。應用對應的checkbox用來進行刪除操做。antd

  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

5、心得體會

  最近使用react + redux + webpack進行web開發,感受進步很快,已經熟悉了基本的流程。後續要研究一下webpack。app

相關文章
相關標籤/搜索