ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[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); ~~~