[TOC]
### 单次操作请求
~~~
import React, {Component} from 'react';
import { Tree, Spin, Tag ,message} from 'antd'
import * as consts from '../role/RoleConst'
import {connect} from 'dva'
const TreeNode = Tree.TreeNode;
let hashData = [];
class SelectSystem extends Component {
constructor(props) {
super(props);
const checkedKeys = [];
console.log('系统',props)
this.dealWithData(props.systemTree, checkedKeys);
this.state = {
checkedKeys: checkedKeys,
dataSource: props.systemTree
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
const checkedKeys = [];
this.dealWithData(nextProps.systemTree, checkedKeys);
this.setState({
checkedKeys: checkedKeys,
dataSource: nextProps.systemTree
})
}
dealWithData (data, checkedKeys = [], parentKey = -1) {
if (data instanceof Array) {
data.map(item => {
item.name = item.name || item.containerName || item.toolName;
const key = item.code || item.containerCode || item.toolCode;
item.key = key;
item.parentKey = parentKey;
item.children = item.containers || item.subTools || [];
if (key && item.children.length <= 0 && item.isShare) checkedKeys.push(key);
this.dealWithData(item.children, checkedKeys, key)
})
}
}
renderTreeNodes(data) {
if (data instanceof Array) {
return data.map(item => {
const title = item.name;
const key = item.key;
hashData[key] = item;
return <TreeNode title={<div><span style={{marginRight: 5}}>{title}</span>{this.getTag(item)}</div>} key={key}>
{this.renderTreeNodes(item.children)}
</TreeNode>
})
}
return []
}
getTag(record) {
let title = null;
let color = "red";
if (record.code) {
title = "系统";
color = "geekblue";
} else if (record.containercode) {
title = "容器";
color = "blue";
} else if (record.isTool === 0) {
title = "工具组";
color = "cyan";
} else if (record.isTool === 1) {
title = "工具";
color = "green";
}
return title ? <Tag color={color}><span>{title}</span></Tag> : null;
}
onCheck (checkedKeys) {
const preCheckedKeys = [];
const currentCheckedKeys = [];
// console.log('this.props',this.props)
this.getKeys(this.state.checkedKeys, preCheckedKeys);
this.getKeys(checkedKeys, currentCheckedKeys);
let func = null;
const param = {
resourceCode: [],
targetDomain:''
};
if (preCheckedKeys.length > currentCheckedKeys.length) {
func = this.props.delSourceAuth
preCheckedKeys.map(item => {
if (currentCheckedKeys.indexOf(item) === -1) {
param.resourceCode.push(item);
param.targetDomain=this.props.code.domaincode;
}
})
} else {
func = this.props.addSourceAuth
currentCheckedKeys.map(item => {
if (preCheckedKeys.indexOf(item) === -1) {
param.resourceCode.push(item)
param.targetDomain=this.props.code.domaincode;
}
})
}
func && func(param).then(results=>{
this.setState({
checkedKeys
})
let res = results.code!==1000
if(!res){
this.setState({
curChecked:[],
curUnchecked:[]
});
// this.props.getShareSystem();
message.success("操作成功");
}else{
message.error("操作失败");
}
}
);
}
findParent(key, desArr = []) {
const a = hashData[key];
if (!a) return;
if (desArr.indexOf(a.key) === -1) {
desArr.push(a.key);
if (a.parentKey && a.parentKey !== -1) {
this.findParent(a.parentKey, desArr)
}
}
}
getKeys(data = [], desArr = []) {
data.map(item => {
const a = hashData[item];
if (!a) return;
if (a.children.length <= 0 && desArr.indexOf(item) === -1) {
desArr.push(item);
if (a.parentKey && a.parentKey !== -1) {
this.findParent(a.parentKey, desArr);
}
}
})
}
render() {
hashData = [];
return (
<Spin spinning={this.props.loading}>
<div style={{minHeight: 250, overflowY: "auto", maxHeight: 450}}>
{
this.props.systemTree.length > 0 ? <Tree
checkable
defaultExpandAll
checkedKeys={this.state.checkedKeys}
onCheck={this.onCheck.bind(this)}
>
{this.renderTreeNodes(this.state.dataSource)}
</Tree> : <div style={{textAlign: "center", marginTop: 20}}>暂无数据</div>
}
</div>
</Spin>
)
}
}
function mapStateToProps(state){
return {
loading: state.loading.models.system,
...state.system
};
}
export default connect(mapStateToProps)(SelectSystem);
~~~
### 含保存按钮的
~~~
import React, { Component } from 'react'
import { Tree, List, Icon, Button, Spin } from 'antd'
import style from '../role/role.css'
import {connect} from 'dva'
import { message } from 'antd';
const TreeNode = Tree.TreeNode;
//获取接口中所有的子元素的code再和父元素的code进行拼接
因为tree中的key被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复!,有可能后台提供的接口中对应的key相同的话,项目就会报错,所有用拼接的方法,将所有的节点的key和它的父节点的key进行拼接,来实现key的唯一性
const getDataContentDic = (data, dic) => {
data.map(item => {
if (item && item.code) {
const key = item.code + '^' +(item.parentcode? item.parentcode : '');
dic[key] = item;
if (item.sub instanceof Array) {
getDataContentDic(item.sub, dic);
}
}
});
};
let dataContentDic = [];
let topicKeys = [];
let lastChecked = [];
class SelectResourcesData extends Component {
constructor(props) {
super(props);
// console.log('llllllllllllllllllll',props)
let selectDataContent = null;
if (props.thematicScheme instanceof Array) {
if (props.thematicScheme.length > 0) {
selectDataContent = props.thematicScheme[0];
}
dataContentDic = [];
getDataContentDic([selectDataContent], dataContentDic);
}
const initState = this.initUI(selectDataContent);
this.state = {
selectDataContent,
checkedKeys: initState.checkedKeys,
checkStrictly: initState.checkStrictly,
expandedKeys: initState.expandedKeys,
curChecked: [],
curUnchecked: []
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
let selectDataContent = null;
if (nextProps.thematicScheme instanceof Array) {
const findSDC = this.state.selectDataContent ? nextProps.thematicScheme.filter(it => (it.code === this.state.selectDataContent.code)) : [];
if (findSDC.length > 0) {
selectDataContent = findSDC[0]
} else if (nextProps.thematicScheme.length > 0) {
selectDataContent = nextProps.thematicScheme[0];
}
dataContentDic = [];
getDataContentDic([selectDataContent], dataContentDic);
const initState = this.initUI(selectDataContent);
this.setState({
selectDataContent,
checkedKeys: initState.checkedKeys,
checkStrictly: initState.checkStrictly,
expandedKeys: initState.expandedKeys,
curChecked: [],
curUnchecked: []
})
}
}
onDataContentListClick(record, isFirst) {
dataContentDic = [];
getDataContentDic([record], dataContentDic);
const initState = this.initUI(record);
if (!isFirst) {
this.setState({
selectDataContent: record,
checkedKeys: initState.checkedKeys,
checkStrictly: initState.checkStrictly,
expandedKeys: initState.expandedKeys,
curChecked: [],
curUnchecked: []
})
}
}
initUI(record) {
let checkedKeys = { checked: [], halfChecked: [] };
let checkStrictly = true;
const expandedKeys = this.findExpandedKeys(dataContentDic);
if (record) {
checkedKeys = this.findCheckedTopicKeys(dataContentDic);
checkStrictly = false;
}
topicKeys = this.getTopicKeys(dataContentDic);
lastChecked = checkedKeys;
return {
checkedKeys,
checkStrictly,
expandedKeys
}
}
findExpandedKeys(data) {
const keys = [];
for (let key in data) {
const item = dataContentDic[key];
if (Object.prototype.toString.apply(item) !== "[object Function]" && item.sub instanceof Array && item.sub.length > 0) {
keys.push(key);
}
}
return keys;
}
//获取接口中保存的为选择状态的key
findCheckedTopicKeys(data) {
const keys = [];
for (let key in data) {
const item = dataContentDic[key];
if (Object.prototype.toString.apply(item) !== "[object Function]" && !item.type && item.topictype === 1 && item.isShare === true) {
keys.push(key);
}
}
return keys;
}
//获取接口数据中所有key
getTopicKeys(data){
const keys = [];
for (let key in data) {
const item = dataContentDic[key];
if (Object.prototype.toString.apply(item) !== "[object Function]" && !item.type && item.topictype === 1 ) {
keys.push(key);
}
}
return keys;
}
//点击复选框时触发
onCheck(keys, {checked, node}) {
// console.log("keys",keys)//选中包含父节点的key
// console.log("checkedKeys",this.state)//选中的子节点的key
// var _lastKeys = lastKeys.map(item => item.split('^')[0]);
let tempKeys = keys instanceof Array ? keys : [...keys.checked];
tempKeys = tempKeys.filter(item => topicKeys.indexOf(item)>-1);//去除所有父节点
let checkedKeys = [...tempKeys];
let curKey = node.props.eventKey
let curCode = curKey.split('^')[0];
let spliceIndexs = [];
let childs = [];
//去除相同code的情况
if(node.props.children && node.props.children.length){//存在子节点
let temp = this.getSubKey(curKey);
temp = temp.filter(item =>topicKeys.indexOf(item)>-1);;
temp.map(item => {
if(checked){
checkedKeys = checkedKeys.concat(topicKeys.filter(key => key.split('^')[0]===item.split('^')[0]));
}else{
tempKeys.map((it, index)=> {
item.split('^')[0] === it.split('^')[0] && spliceIndexs.push(index);
})
}
})
// 通过上次已勾选的键得到净键
childs = temp.filter(item => {
let exist = lastChecked.indexOf(item);
return checked ? exist===-1 : exist>-1;
});
}
else{//最下级节点
if(checked){
checkedKeys = checkedKeys.concat(topicKeys.filter(key => key.split('^')[0]===curCode));
}
else{
tempKeys.map((item,index) => {
item.split('^')[0] === curCode && spliceIndexs.push(index);
})
}
}
spliceIndexs = [...new Set(spliceIndexs.sort())].reverse();//排序,去重,反转
spliceIndexs.map(item => {
checkedKeys.splice(item, 1);
});
// 增加删除的内容
const {curChecked, curUnchecked} = this.getAddDelKeys(checked, curCode, childs);
lastChecked = checkedKeys;
this.setState({
checkedKeys,
checkStrictly: false,
curChecked,
curUnchecked
})
}
getAddDelKeys(checked, curCode, childs) {
let curChecked = [...this.state.curChecked];
let curUnchecked = [...this.state.curUnchecked];
childs = childs.length ? childs.map(item=>item.split('^')[0]) : [curCode];
if (checked) {
const {delArr, addArr} = this.updateAddDelKeys(childs, curUnchecked, curChecked);
curUnchecked = delArr;
curChecked = addArr;
} else {
const {delArr, addArr} = this.updateAddDelKeys(childs, curChecked, curUnchecked);
curChecked = delArr;
curUnchecked = addArr;
}
return {curChecked, curUnchecked};
}
/**
* 更新要删除和要增加的键
* @param {*} codes
* @param {*} delArr
* @param {*} addArr
*/
updateAddDelKeys (codes, delArr, addArr) {
delArr = delArr.filter(
item => {
let exist = codes.indexOf(item);
if(exist === -1){
return true;
}
else{
codes.splice(exist, 1);
}
}
);
addArr = addArr.concat(codes);
return {delArr, addArr};
}
//获取子节点的key
getSubKey(key) {
let des = [];
const item = dataContentDic[key];
if (item.sub instanceof Array) {
for (let i = 0; i < item.sub.length; i++) {
const key = item.sub[i].code+'^'+item.sub[i].parentcode;
des.push(key);
des = des.concat(this.getSubKey(key))
}
}
return des;
}
onSave() {
//树主要操作的是子节点(先取出接口中的子节点code当成key然后再实现相应逻辑,父节点是否勾选通过checkStrictly属性判断是否关联)
//实现逻辑:将现阶段新添加和取消的数据(这部分数据可从onCheck函数中获得)与原数据进行对比(tree中的checkedKeys勾选状态的数据),将新添加的数据和取消的数据分别取出来。
// 子节点的key可能存在相同的情况,如果是相同的就去重
let proms = [];
let {curChecked, curUnchecked, selectDataContent} = this.state;
let readyDelList={};
let readyAddList={};
readyDelList.targetDomain=this.props.code.domaincode;
readyAddList.targetDomain=this.props.code.domaincode;
readyDelList.resourceCode=curUnchecked
readyAddList.resourceCode=curChecked
curUnchecked.length && proms.push(this.props.delSourceAuth(readyDelList))
curChecked.length && curChecked.unshift(selectDataContent.code) && proms.push(this.props.addSourceAuth(readyAddList))
proms.length && Promise.all(proms).then(results=>{
let res = results.some(result=>result.code!==1000)
if(!res){
this.setState({
curChecked:[],
curUnchecked:[]
});
// this.props.getShareSystem();
message.success("保存成功");
}else{
message.error("保存失败");
}
})
}
getRightContent(data) {
if (data instanceof Array) {
return data.map(item => {
const key = item.code+'^'+(item.parentcode ? item.parentcode : '');
return <TreeNode title={(item.name ? item.name : item.topicname) || '未知'} key={key} selectable={false}>
{this.getRightContent(item.sub)}
</TreeNode>
})
}
return null
}
getRightTree(data){
const treeProps = {
//已选中的子节点的key(也就是接口中的唯一标识符code)
checkedKeys: this.state.checkedKeys,
//判断是否关联,当点击子节点复选框时,父节点是否一起勾选
checkStrictly: this.state.checkStrictly,
checkable: true,
// defaultExpandAll: true,
// autoExpandParent: true,
//点击复选框时触发
onCheck: this.onCheck.bind(this),
//展开指定的树节点
expandedKeys: this.state.expandedKeys,
//展开/收起节点时触发(一般与上连用)
onExpand: this.onExpand.bind(this),
}
return data.length ? (<Tree
{...treeProps}
>
{this.getRightContent(data)}
</Tree>) : null;
}
getLeftList(data) {
if (data instanceof Array && data.length <= 0) {
return
}
if (!this.state.selectDataContent) {
this.onDataContentListClick(data[0], true);
}
return <List itemLayout="horizontal"
dataSource={data || []}
renderItem={(item, index) => (
<List.Item
onClick={this.onDataContentListClick.bind(this, item, false)}
actions={[<Icon type='right' style={{ fontSize: 19, color: `${this.state.selectDataContent === item ? "white" : "rgba(0, 0, 0, 0.65)"}` }} />]}
className={this.state.selectDataContent === item ? style.active : null}>
<div style={{ paddingLeft: 5, marginRight: -45 }}>{item.name}</div>
</List.Item>
)} />
}
getSubCatalog(key) {
let res = [];
let temp = dataContentDic[key];
if (temp.sub) {
temp.sub.map(item => {
if (item.sub) {
const key = item.code + '^' + item.parentcode;
res.push(key);
res = res.concat(this.getSubCatalog(key))
}
});
}
return res;
}
//收起,展开数结构
onExpand(keys, {expanded, node}) {
const key = node.props.eventKey;
let expandedKeys = [...keys];
let temp = this.getSubCatalog(key);
if(!expanded){
expandedKeys = expandedKeys.filter(item => {
return temp.indexOf(item)===-1;
});
}
else{
expandedKeys = expandedKeys.concat(temp);
}
this.setState({
expandedKeys
})
}
render() {
return (
<Spin spinning={this.props.loading}>
<div className={style.dataContentPaneContent}>
<div className={style.dataContentLeftContent}>
<div className={style.header}>数据资源目录列表</div>
<div className={style.content}>
{this.getLeftList(this.props.thematicScheme)}
</div>
</div>
<div className={style.dataContentCenterContent}>
>
</div>
<div className={style.dataContentRightContent}>
<div className={style.header}>
<span>数据资源目录树</span>
<Button className={style["ant-btn"]} onClick={this.onSave.bind(this)} disabled={!this.state.selectDataContent} size="small">保存</Button>
</div>
<div className={style.content}>
{this.getRightTree(this.state.selectDataContent ? [this.state.selectDataContent] : [])}
</div>
</div>
</div>
</Spin>
)
}
}
function mapStateToProps(state){
return {
loading: state.loading.models.system,
...state.system
};
}
export default connect(mapStateToProps)(SelectResourcesData);
~~~
- 第一章 起步
- 第1节 创建react项目
- 第2节 hello world
- 第3节 数据绑定+事件处理
- 3.1 for循环事件处理中的传参写法、条件渲染
- 第4章 点击切换文字
- 第5章 使用html写react
- 第二章 运用
- 第1节 循环
- 第2节 实现一个简单的TodoList
- 第2.1节 删除
- 第3节 父子组件传参
- 1. 父组件向子组件传参
- 2. 子组件向父组件传参
- 第4节 react-router实现一个简单路由
- 第5节 生命周期
- 第6节 取数据
- 第 7节 获取dom节点
- 第8节 双向数据绑定
- 第三章 redux
- 第1节 介绍
- 第2节 安装redux
- 第3节 使用
- 3.1 action
- 3.2 使用redux实现 todolist
- 第4节封装redux中的action
- 第5节 redux-thunk中间件
- 5.1介绍
- 5.2使用
- 第四章 ant-design前端ui
- 第一节 安装
- 第2节 使用
- 2.1 ant-design实现todoList增删功能
- 第3节 使用整理
- 第五章 vue和react的比较
- 第六章 dva.js轻量级应用框架
- 第1节 介绍
- 第2节 安装dva
- 第3节 页面跳转
- 1. 事件路由跳转
- 2. 通过路由跳转
- 第4节 组件之间通信
- 1. 父组件向子组件传参
- 2. 子组件向父组件传参
- 第5节 事件处理
- 第6节 发送请求
- 1. 通过路由判断页面渲染数据
- 2. 通过事件发送请求
- 第7节 运用
- 1. TodoList
- 1.添加数据
- 1.2输入框敲回车触发事件
- 2.删除数据
- 3. 总结
- 第8节 配合antd使用
- 1. 引入antd
- 2.dva 使用antd注意事项
- 3. 知识点整理
- 第七章 dva后台项目实战
- 第1节 登录加密
- 1.具体实现
- 第2节 知识点
- 第3节 树结构
- 第八章 react新特性 hooks
- 第1节 hooks介绍
- 第2节 useState的使用
- 第3节 useEffect的使用
- 第4节 dva+antd+hooks企业后台项目开发流程
- 第 5节 hooks 使用
- 运用
- 第6节 hook整理
- 第7节 react memo
- 第九章 react中使用Echarts
- 知识点
- react中使用mobx
- 知识点
- react中使用rem
- 递归实现目录数
- react使用图表
- react 同步更新策略
- antd tree默认展开无效
- ts中lint修复篇
- React-query方案
- 高阶组件