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;//mapthis.checkboxIdMapState= new Map();//checkboxId 映射 Statethis.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) {//获取行头的checkboxIdthis.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);//为这一行数据添加新的列//判断应用对应的按钮是否已经选择上, judgeDefaultCheckedif(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupIdthis.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);//所有子行的行头的 checkboxIdreturn 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) {//遍历这一分组行的checkboxIdvar 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,应用idconst 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);//所有子行的行头的 checkboxIdfor(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,这一列全部checkvar 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 {//都不为nullvar curRowHeadCheckboxId = parentRow.get(cid);//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxIdfor(var i=0; i<rowIds.length; ++i) {//这一列全部checkvar 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.parentColif(btnGroupColumns) {this.addColName(btnGroupColumns, appData);//对应用的数据进行一个简单的处理
btnGroupColumns.map((elem, index)=> { //elem.colname=='name' ? null : elem.id, 默认左上角的id 没有 appId 和 btnGroupIdelem.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.idvar 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 对应的 最上边的 checkboxIdparentCol.put(cur_cid, elem.cid);//该 checkboxId 对应的 (按钮Id == elem.cid)//record.name.split('_')[0] 最原始的 name 的valuereturn <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);//为这一行数据添加新的列//判断应用对应的按钮是否已经选择上, judgeDefaultCheckedif(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupIdthis.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){//为每一列添加 映射字段 colnameif(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]] + ";\n";}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;//mapthis.checkboxIdMapState= new Map();//checkboxId 映射 Statethis.parentRow = new Map();//每个checkboxId节点 对应最左边的哪个应用this.parentCol = new Map();//每个checkboxId节点 对应最上边的哪个按钮this.childrenRow = new Map();//当前行的所有子行this.checkboxIdMapAppBtnData = new Map();//每个checkbox对应的 appid,btnGroupIdthis.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) {//获取行头的checkboxIdthis.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);//为这一行数据添加新的列//判断应用对应的按钮是否已经选择上, judgeDefaultCheckedif(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupIdthis.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);//所有子行的行头的 checkboxIdreturn 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) {//遍历这一分组行的checkboxIdvar 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,应用idif(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,这一列全部checkvar cur_cid = cid;while(cur_cid <= rowNum*colNum) {checkboxIdMapState.put(cur_cid, checked);cur_cid += colNum;}} else {//都不为nullvar curRowHeadCheckboxId = parentRow.get(cid);//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxIdfor(var i=0; i<rowIds.length; ++i) {//这一列全部checkvar 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.parentColif(btnGroupColumns) {this.addColName(btnGroupColumns, appData);//对应用的数据进行一个简单的处理
btnGroupColumns.map((elem, index)=> { //elem.colname=='name' ? null : elem.id, 默认左上角的id 没有 appId 和 btnGroupIdelem.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.idvar 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 对应的 最上边的 checkboxIdparentCol.put(cur_cid, elem.cid);//该 checkboxId 对应的 (按钮Id == elem.cid)//record.name.split('_')[0] 最原始的 name 的valuereturn <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。

转载于:https://www.cnblogs.com/hujunzheng/p/5812046.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

junit4进行单元测试

一、前言 提供服务的时候&#xff0c;为了保证服务的正确性&#xff0c;有时候需要编写测试类验证其正确性和可用性。以前的做法都是自己简单写一个控制层&#xff0c;然后在控制层里调用服务并测试&#xff0c;这样做虽然能够达到测试的目的&#xff0c;但是太不专业了。还是老…

快速搭建springmvc+spring data jpa工程

一、前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程&#xff0c;并提供了一个简单的demo作为参考。 二、创建maven工程 http://www.cnblogs.com/hujunzheng/p/5450255.html 三、配置文件说明 1.application.properties jdbc.drivercom.mysql.jd…

git亲测命令

一、Git新建本地分支与远程分支关联问题 git checkout -b branch_name origin/branch_name 或者 git branch --set-upstream branch_name origin/branch_name 或者 git branch branch_name git branch --set-upstream-toorigin/branch_name branch_name 二、查看本地分支所关…

mysql 7下载安装及问题解决

mysql 7安装及问题解决 一、mysql下载 下载地址&#xff1a;https://www.mysql.com/downloads/Community (GPL) DownloadsMySQL Community Server (GPL)Windows (x86, 64-bit), ZIP ArchiveNo thanks, just start my download.二、mysql安装 解压到指定目录在mysql bin目录下打…

tomcat开发远程调试端口以及利用eclipse进行远程调试

一、tomcat开发远程调试端口 方法1 WIN系统 在catalina.bat里&#xff1a;   SET CATALINA_OPTS-server -Xdebug -Xnoagent -Djava.compilerNONE -Xrunjdwp:transportdt_socket,servery,suspendn,address8899   Linux系统 在catalina.sh里&#xff1a;   CATALINA_OPTS&q…

webpack+react+redux+es6开发模式

一、预备知识 node, npm, react, redux, es6, webpack 二、学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入门教程 redux middleware 详解 Redux研究 React 入门实例教程 webpack学习demo NPM 使用介绍 三、工程搭建 之前有写过 webpackreactes6开发模式…

fiddler发送post请求

1.指定为 post 请求&#xff0c;输入 url Content-Type: application/x-www-form-urlencoded;charsetutf-8 request body中的参数格式&#xff1a;userNameadminicxp&userPassword123qwe!# 这种方式可以用 request.getParameter的方式来获得。 2.指定为 post 请求&#xff…

Kettle之数据抽取、转换、装载

Kettle 官网 ETL利器Kettle实战应用解析系列 利用kettle组件导入excel文件到数据库 kettle中实现动态SQL查询 java中调用kettle转换文件 kettle 7.x版本下载&#xff1a;https://pan.baidu.com/s/1nvnzzCH  密码&#xff1a;6f5c mac 下运行spoon.sh,  windows下为spoon.bat…

webpack+react+redux+es6开发模式---续

一、前言 之前介绍了webpackreactreduxes6开发模式 &#xff0c;这个项目对于一个独立的功能节点来说是没有问题的。假如伴随着源源不断的需求&#xff0c;前段项目会涌现出更多的功能节点&#xff0c;需要独立部署运行。为了更好地管理这些独立的功能节点&#xff0c;我们需要…

RabbitMQ安装和使用(和Spring集成)

一、安装Rabbit MQ   Rabbit MQ 是建立在强大的Erlang OTP平台上&#xff0c;因此安装Rabbit MQ的前提是安装Erlang。通过下面两个连接下载安装3.2.3 版本&#xff1a; 下载并安装 Eralng OTP For Windows (vR16B03)运行安装 Rabbit MQ Server Windows Installer (v3.2.3)具体…

单点登录实现(spring session+redis完成session共享)

一、前言 项目中用到的SSO&#xff0c;使用开源框架cas做的。简单的了解了一下cas&#xff0c;并学习了一下 单点登录的原理&#xff0c;有兴趣的同学也可以学习一下&#xff0c;写个demo玩一玩。 二、工程结构 我模拟了 sso的客户端和sso的服务端&#xff0c; sso-core中主要是…

加密策略

一、前言 这两天研究了一下项目中的密码加密&#xff0c;可以说得上是学到了很多。下面来大致说一下。 二、常用加密 1.单向加密算法 单向加密算法主要用来验证数据传输的过程中&#xff0c;是否被篡改过。 BASE64 严格地说&#xff0c;属于编码格式&#xff0c;而非加密算法 …

Spring Data JPA: 实现自定义Repository

一、前言 由于项目中的 实体&#xff08;entity&#xff09;默认都是继承一个父类&#xff08;包含一些公共的属性&#xff0c;比如创建时间&#xff0c;修改时间&#xff0c;是否删除&#xff0c;主键id&#xff09;。为了实现逻辑删除&#xff0c;一般会自己实现RepositoryFa…

js冲刺一下

js中__proto__和prototype的区别和关系 1.对象有属性__proto__,指向该对象的构造函数的原型对象。  2.方法除了有属性__proto__,还有属性prototype&#xff0c;prototype指向该方法的原型对象。 深入浅出妙用 Javascript 中 apply、call、bind ***两道面试题*** 关于js中伪数…

Jackson序列化实例

参考文章 Jackson使用ContextualSerializer在序列化时获取字段注解的属性 使用BeanSerializerModifier定制jackson的自定义序列化(null值的处理) 关于使用ContextualSerializer的补充 BeanSerializerFactory中有如下代码&#xff0c; 关于设置SerializerModifier&#xff0c;如…

cas4.2.7实现单点登录

准备前参考&#xff1a;  cas server下载地址 cas client 下载地址 安全cookie setSecure详解 Spring通过构造方法注入的四种方式 cas 学习博文 自定义登录页和登录认证 cas server端的login-webflow详细流程 CAS服务端自定义数据库认证用户 准备工作 1. cas server下载之后解…

swagger restful api form映射实体对象和body映射实体对象配置

实体Model ModelAttribute一个具有如下三个作用&#xff1a; ①绑定请求参数到命令对象&#xff1a;放在功能处理方法的入参上时&#xff0c;用于将多个请求参数绑定到一个命令对象&#xff0c;从而简化绑定流程&#xff0c;而且自动暴露为模型数据用于视图页面展示时使用&…

ssh端口转发(之kettle ssh方式连接数据库)

ssh参数解释 格式  ssh [user]host [command] 选项&#xff1a; -1&#xff1a;强制使用ssh协议版本1&#xff1b; -2&#xff1a;强制使用ssh协议版本2&#xff1b; -4&#xff1a;强制使用IPv4地址&#xff1b; -6&#xff1a;强制使用IPv6地址&#xff1b; -A&#xff1a…

ThreadLocal和InheritableThreadLocal使用

InheritableThreadLocal代码 public class InheritableThreadLocal<T> extends ThreadLocal<T> {protected T childValue(T parentValue) {return parentValue;}ThreadLocalMap getMap(Thread t) {return t.inheritableThreadLocals;}void createMap(Thread t, T f…

mybatis generator修改默认生成的sql模板

相关连接&#xff1a; mybatis-generator扩展教程系列 -- 自定义sql xml文件 git项目地址 转载于:https://www.cnblogs.com/hujunzheng/p/7110510.html