feat(orchestration): 实现应用组件信息展示功能

- 新增侧边栏组件列表展示与搜索功能
- 添加组件详情信息展示模块
- 实现组件预览区域与参数表格展示
- 集成组件选择交互逻辑
- 引入样式模块优化界面布局
- 移除旧版数据获取逻辑,使用 Redux 状态管理
master
钟良源 4 months ago
parent b81b0dbf38
commit 5b2f1020d2

@ -0,0 +1,79 @@
import React from 'react';
import styles from './style/compInfo.module.less';
import { Space, Divider, Table, TableColumnProps } from '@arco-design/web-react';
const CompInfo = ({ currentCompInfo }) => {
console.log('传入的组件信息:', currentCompInfo);
const columns: TableColumnProps[] = [
{
title: '参数名',
dataIndex: 'id'
},
{
title: '参数类型',
dataIndex: 'dataType'
},
{
title: '描述',
dataIndex: 'desc'
}
];
// 渲染节点参数列表
const renderParamsTable = () => {
return (
<div className={styles['params']}>
<h3></h3>
<Table
columns={columns}
data={currentCompInfo.def?.dataIns}
pagination={false}
scroll={{
y: 150
}} />
<h3></h3>
<Table
columns={columns}
data={currentCompInfo.def?.dataOuts}
pagination={false}
scroll={{
y: 150
}} />
</div>
);
};
return (
currentCompInfo ? (<div className={styles['comp-container']}>
<div className={styles['comp-preview']}>
<h3></h3>
<div className={styles['comp-housing']}></div>
</div>
<div className={styles['comp-info']}>
<div className={styles['header']}>
<Space size={40}>
<div className={styles['title']}>{currentCompInfo.name}</div>
</Space>
</div>
<Divider style={{ borderColor: '#5484ff', marginTop: 0, marginBottom: 30 }} />
<div className={styles['extra']}>
<Space size={30}>
<div className={styles['extra-font']}>{currentCompInfo.identifier}</div>
<div className={styles['extra-font']}>{currentCompInfo.componentClassify}</div>
<div className={styles['extra-font']}>{currentCompInfo.codeLanguage}</div>
</Space>
</div>
<Divider style={{ marginTop: 15, borderBottomStyle: 'dashed' }} />
<div className={styles['description']}>
{currentCompInfo.description ? currentCompInfo.description : ' - '}
</div>
<Divider style={{ borderBottomStyle: 'dashed' }} />
{renderParamsTable()}
<Divider style={{ borderBottomStyle: 'dashed' }} />
</div>
</div>) : <div></div>
);
};
export default CompInfo;

@ -1,24 +1,26 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { getProjectComp } from '@/api/scene'; import styles from './style/index.module.less';
import SideBar from './sideBar';
import CompInfo from './compInfo';
const AppCompComponent = () => { const AppCompComponent = () => {
const [compList, setCompList] = useState([]); const [compList, setCompList] = useState([]);
const { info } = useSelector((state: any) => state.ideContainer); const [currentCompInfo, setCurrentCompInfo] = useState(null);
const { info, projectComponentData } = useSelector((state: any) => state.ideContainer);
const fetchData = async () => {
const res: any = await getProjectComp(info.id);
console.log('res:', res);
if (res.code === 200) setCompList(res.data);
};
useEffect(() => { useEffect(() => {
fetchData(); setCompList(projectComponentData[info.id]);
}, []); }, []);
return ( return (
<div> <div className={styles['app-comp-component']}>
<div className={styles['left']}>
<SideBar compList={compList} onSelect={(e) => setCurrentCompInfo(e)} />
</div>
<div className={styles['right']}>
<CompInfo currentCompInfo={currentCompInfo} />
</div>
</div> </div>
); );
}; };

@ -0,0 +1,114 @@
import React from 'react';
import styles from './style/sideBar.module.less';
import { Button, Input, Tree } from '@arco-design/web-react';
import { IconSearch } from '@arco-design/web-react/icon';
const TreeNode = Tree.Node;
const SideBar = ({ compList, onSelect }) => {
const renderTreeNode = (menuItems, parentKey = '0') => {
// 标题枚举值
const titleMap = new Map([
['projectCompDto', {
title: '基础组件',
icon: <img src={'/ideContainer/icon/projectComp.png'} style={{ width: 17, height: 17 }} />
}],
['projectFlowDto', {
title: '复合组件',
icon: <img src={'/ideContainer/icon/projectComp.png'} style={{ width: 17, height: 17 }} />
}],
['mineComp', {
title: '我的组件',
icon: <img src={'/ideContainer/icon/mineComp.png'} style={{ width: 17, height: 17 }} />
}],
['pubComp', {
title: '公共组件',
icon: <img src={'/ideContainer/icon/pubComp.png'} style={{ width: 17, height: 17 }} />
}],
['teamWorkComp', {
title: '协助组件',
icon: <img src={'/ideContainer/icon/teamWorkComp.png'} style={{ width: 17, height: 17 }} />
}],
['mineFlow', {
title: '我的组件',
icon: <img src={'/ideContainer/icon/mineComp.png'} style={{ width: 17, height: 17 }} />
}],
['pubFlow', {
title: '公共组件',
icon: <img src={'/ideContainer/icon/pubComp.png'} style={{ width: 17, height: 17 }} />
}]
]);
if (!menuItems) return null;
// 如果是数组,表示是最底层的子节点,直接渲染
if (Array.isArray(menuItems)) {
return menuItems.map((item, index) => {
const treeNodeProps = {
dataRef: item // 传递原始数据
};
return (<TreeNode
{...treeNodeProps}
key={`${parentKey}-${index}`}
title={item.name}
icon={<img src={'/ideContainer/icon/compItem.png'} style={{ width: 17, height: 17 }} />}
/>);
});
}
// 如果是对象,递归渲染子节点
return Object.keys(menuItems).map((key, index) => {
const child = menuItems[key];
const currentKey = `${parentKey}-${index}`;
const title = titleMap.get(key)?.title || key;
const icon = titleMap.get(key)?.icon || null;
// 如果子节点是数组或对象,继续递归
if (Array.isArray(child) || typeof child === 'object') {
return (
<TreeNode key={currentKey} title={title} icon={icon}>
{renderTreeNode(child, currentKey)}
</TreeNode>
);
}
// 否则直接渲染叶子节点
return <TreeNode key={currentKey} title={title} />;
});
};
return (
<div className={styles['side-bar']}>
<div className={styles['handle-box']}>
<Input
prefix={<IconSearch />}
placeholder={'搜索组件'}
style={{ width: '90%' }}
/>
<Button
type="primary"
style={{ marginLeft: 5 }}
>
</Button>
</div>
<div className={styles['comp-list']}>
<Tree
defaultExpandedKeys={['0-0-0']}
defaultSelectedKeys={['0-0-0', '0-0-1']}
selectedKeys={[]} // 移除选中样式
style={{ background: 'transparent' }} // 移除背景色
onSelect={(value, info) => {
if (info.node.props.dataRef.children) return;
onSelect(info.node?.props?.dataRef || null);
}}
>
{renderTreeNode(compList)}
</Tree>
</div>
</div>
);
};
export default SideBar;

@ -0,0 +1,59 @@
.comp-container {
box-sizing: border-box;
display: flex;
width: 100%;
height: 100%;
background-color: #fff;
padding: 32px 27px 27px 29px;
.comp-preview {
box-sizing: border-box;
width: 345px;
height: 100%;
margin-right: 68px;
padding: 20px 25px;
border-radius: 8px;
box-shadow: 2px 2px 20px 0 rgba(0, 0, 0, .25);
.comp-housing {
width: 95%;
height: 250px;
margin: 0 auto;
border: 1px solid #CCCCCC;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
}
.comp-info {
flex: 1;
.header {
.title {
font-size: 22px;
font-weight: 700;
}
.update-time {
color: #888888;
}
}
.extra {
.extra-font {
font-size: 18px;
font-weight: 700;
}
}
.description {
max-height: 15%;
overflow-y: auto;
}
.params {
box-sizing: border-box;
padding: 10px 0 25px 20px;
background-color: #fbfbfb;
}
}
}

@ -0,0 +1,17 @@
.app-comp-component {
height: 100%;
display: flex;
.left {
width: 314px;
padding: 17px;
background-color: #ffffff;
border-right: 4px solid #E5E6EB;
}
.right {
flex: 1;
background-color: #f7f8fa;
padding: 20px;
}
}

@ -0,0 +1,11 @@
.side-bar {
box-sizing: border-box;
.handle-box {
display: flex;
}
.comp-list {
}
}
Loading…
Cancel
Save