在现代企业管理系统中,组织架构图是一个常见且重要的功能模块。本文将分享如何使用 react-org-tree 组件库实现一个卡片模式的组织架构图,并解决在使用过程中遇到的 expand 展开固定层级的问题。
项目背景
在开发企业管理系统时,我们需要展示一个清晰的组织架构图,让用户能够直观地了解公司的部门结构和人员分布。传统的树形结构虽然直观,但缺乏交互性和信息展示能力。因此,我们决定采用卡片模式来展示组织架构,每个节点以卡片形式呈现,包含更多详细信息。
技术选型
我们选择了 react-org-tree
组件库来实现组织架构图,主要基于以下几点考虑:
- 纯 React 实现:与我们的技术栈完美契合
- 丰富的配置选项:支持横向/纵向布局、可折叠等特性
- 良好的扩展性:可以通过自定义节点渲染实现个性化需求
效果图
实现过程
1. 数据准备与转换
首先,我们需要将后端返回的组织数据转换为 react-org-tree
所需的格式。原始数据结构如下:
[{"id": 0,"name": "公司总部","expand": true, // 默认展开一级组织"children": [{"id": 1,"name": "技术部","children": [...]},{"id": 2,"name": "市场部","children": [...]}]}
]
我们编写了 flattenData
函数来转换数据格式:
const flattenData = (data) => {return data?.map((item) => {const newItem = {...item,// 自定义节点渲染label: labelDiv({id: item.id,pid: item.pid,name: item.name,type: item.type,})}// 递归处理子节点if(Array.isArray(newItem.children) && newItem.children.length > 0) {newItem.children = flattenData(newItem.children);}return newItem;})
}
2. 自定义节点渲染
为了在节点中展示更多信息,我们使用了 Ant Design
的 Card
组件来自定义节点渲染:
const labelDiv = (record) => (<Cardkey={`card${record.id}`}size="small"title={<div className="word-ellipsis" title={record.name}><ClusterOutlined />{record.name}</div>}hoverable={!(record.id===0 || exceptDept.includes(record.id))}className="card-item"onClick={() => enterDetail(record)}>{/* 根节点特有操作 */}{record.id===0 &&<div className="item-info"><div className="info-btn" style={{marginTop: 0}}><Buttontype="link"size="small"onClick={() => handleAddOrg(record)}>新增子组织</Button></div></div>}{/* 普通节点操作按钮 */}{record.id!==0 &&<div className="item-info"><span className="org-type"><span style={{color:"#00000080"}}>组织类型:</span><span title={record.type}>{record?.type || "--"}</span></span><span className="org-type"><span style={{color:"#00000080"}}>责任人:</span><span>{handleUserName(record.real_name, record.username) || "--"}</span></span><div className="info-btn"><Buttontype="link"size="small"onClick={(e) => {e.stopPropagation();handleAddOrg(record);}}>新增</Button><Buttontype="link"size="small"onClick={() => enterDetail(record)}>详情</Button><Buttontype="link"size="small"onClick={(e) => {e.stopPropagation();handleEdit(record);}}>编辑</Button><Popconfirmplacement="topRight"title="请确认是否删除?"onConfirm={(e) => {e?.preventDefault();e?.stopPropagation();handleDelete(record);}}onCancel={onCancel}><Buttontype="link"size="small"onClick={onCancel}>删除</Button></Popconfirm></div></div>}</Card>
)
3. 初始化数据与展开控制
在组件挂载时,我们初始化组织架构数据,并尝试设置默认展开状态:
const [data, setData] = useState({});useEffect(() => {if(orgTreeData && orgTreeData[0] && orgTreeData[0].id===0) {let tempData = {id: orgTreeData[0]?.id,expand: true, // 这里尝试设置展开状态label: labelDiv({id: orgTreeData[0]?.id,name: orgTreeData[0]?.name,}),children: flattenData(orgTreeData[0].children)};setData(tempData);}
}, [orgTreeData]);
4. 渲染组织架构图
最后,我们使用 OrgTree
组件渲染组织架构图:
return (<div className="card-list"><OrgTreedata={data}horizontal={true} // 横向布局collapsable={true} // 可折叠expandAll={true} // 尝试全部展开/></div>
)
遇到的问题与解决方案
问题1:expandAll 不生效
现象:设置 expandAll={true}
后,节点并未全部展开。
原因分析:
- 当
collapsable={true}
时,expandAll
可能不会生效 - 数据初始化方式可能存在问题
解决方案:
- 当
collapsable={false}
时,expandAll
会生效,如果需求没有强制要求,可将collapsable
直接设置为false
- 在数据中 设置
expand
来单独控制元素的展开
问题2:刷新页面数据恢复初始化层级
现象:编辑操作后,组织树会恢复默认层级,不会记录上次操作的曾经
原因分析:
- 插件不支持设置类似
expandedKeys
的树形 - 可能是插件内部具有bug
解决方案
- 手动控制数据,在数据中更改
expand
的值 为true/false
最终实现效果
通过以上调整,我们成功实现了以下功能:
- 卡片式组织架构展示
- 每个节点显示详细信息
- 支持节点展开/折叠
- 根节点支持新增子组织
- 普通节点支持增删改查操作
react-org-tree官方文档
总结
使用 react-org-tree
实现卡片模式组织架构图是一个不错的选择,但在实际开发中需要注意以下几点:
- 数据结构:确保数据格式符合组件要求
- 展开控制:当 collapsable={true} 时,优先使用
expand
而非expandAll
- 自定义渲染:通过
label
属性实现高度自定义的节点展示 - 样式调整:根据需求调整节点样式和布局
通过本文的分享,希望能帮助你在项目中更高效地实现组织架构图功能。如果你有更好的实现方式或遇到其他问题,欢迎在评论区交流讨论!
推荐更多阅读内容
echarts绘制3D旋转地球 JavaScript中的对象字段过滤:只保留特定值的字段
JavaScript 嵌套数组扁平化的 5 种核心方案与深度实践指南
你的网站正在裸奔?Lodash原型链污染漏洞引发的“全员恶人“事件
手把手教你用 React 实现可拖拽排序的 Ant Design 表格
深入理解 Ant Design 中 Popconfirm 的 overlayClassName 属性
从JSON过滤到编程范式:深入理解JavaScript数据操作
React表单状态管理深度解析:Form.useWatch与onChange技术选型指南
Ant Design按钮样式深度适配:实现<Button>与<a>标签颜色完美同步