UI 组件开发
编程式场景支持自定义 React 面板组件,实现丰富的用户界面。
组件注册
第一步:定义面板
在 getPlugin() 的 ui.panels 中声明面板:
typescript
getPlugin() {
return {
ui: {
layout: 'dashboard-centric',
panels: [
{
id: 'dashboard',
component: 'DashboardPanel',
region: 'primary',
defaultVisible: true,
resizable: true,
minWidth: 300,
maxWidth: 800,
},
{
id: 'settings',
component: 'SettingsPanel',
region: 'secondary',
defaultVisible: false,
resizable: true,
minWidth: 250,
maxWidth: 500,
},
{
id: 'chat',
component: 'ChatPanel',
region: 'auxiliary',
defaultVisible: true,
resizable: true,
minWidth: 300,
maxWidth: 600,
},
],
},
}
}面板区域
| 区域 | 说明 | 位置 |
|---|---|---|
primary | 主面板 | 中央区域 |
secondary | 次面板 | 左侧或右侧 |
auxiliary | 辅助面板 | 聊天面板 |
bottom | 底部面板 | 终端/输出 |
overlay | 浮层面板 | 弹窗覆盖 |
面板配置
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 面板唯一标识 |
component | string | 组件名(对应 getComponents 的 key) |
region | string | 面板区域 |
defaultVisible | boolean | 默认是否可见 |
resizable | boolean | 是否可调整大小 |
minWidth | number | 最小宽度(px) |
maxWidth | number | 最大宽度(px) |
minHeight | number | 最小高度(px) |
maxHeight | number | 最大高度(px) |
第二步:注册组件
在 getComponents() 中返回组件映射:
typescript
import { DashboardPanel } from './components/DashboardPanel.js'
import { SettingsPanel } from './components/SettingsPanel.js'
getComponents() {
return {
DashboardPanel,
SettingsPanel,
}
}组件开发
基础组件
tsx
import React from 'react'
export const DashboardPanel: React.FC = () => {
return (
<div className="dashboard-panel">
<h2>仪表盘</h2>
<p>欢迎使用场景仪表盘</p>
</div>
)
}使用共享依赖
组件可以使用客户端注入的共享依赖:
tsx
import React, { useState, useEffect } from 'react'
import { BarChart3, TrendingUp } from 'lucide-react'
interface StatsData {
total: number
completed: number
pending: number
}
export const StatsPanel: React.FC = () => {
const [stats, setStats] = useState<StatsData>({
total: 0,
completed: 0,
pending: 0,
})
useEffect(() => {
// 获取数据
loadStats()
}, [])
const loadStats = async () => {
// 通过场景数据通道获取数据
// 具体实现取决于场景的数据源
}
return (
<div className="stats-panel p-4">
<h3 className="text-lg font-semibold mb-4">统计数据</h3>
<div className="grid grid-cols-3 gap-4">
<div className="stat-card">
<BarChart3 className="w-6 h-6 text-blue-500" />
<span className="text-2xl font-bold">{stats.total}</span>
<span className="text-sm text-gray-500">总计</span>
</div>
<div className="stat-card">
<TrendingUp className="w-6 h-6 text-green-500" />
<span className="text-2xl font-bold">{stats.completed}</span>
<span className="text-sm text-gray-500">已完成</span>
</div>
<div className="stat-card">
<div className="w-6 h-6 text-yellow-500" />
<span className="text-2xl font-bold">{stats.pending}</span>
<span className="text-sm text-gray-500">待处理</span>
</div>
</div>
</div>
)
}数据通信
组件通过数据通道与场景通信:
tsx
import React, { useEffect } from 'react'
export const DataPanel: React.FC = () => {
useEffect(() => {
// 订阅数据通道
const handleData = (event: CustomEvent) => {
console.log('收到数据:', event.detail)
}
window.addEventListener('scenario:data-update', handleData as EventListener)
return () => {
window.removeEventListener('scenario:data-update', handleData as EventListener)
}
}, [])
return <div>Data Panel</div>
}样式
组件使用 TailwindCSS 或自定义 CSS:
tsx
// 使用 TailwindCSS
<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow">
// 或使用 CSS Modules
import styles from './DashboardPanel.module.css'
<div className={styles.container}>最佳实践
- 组件轻量:保持组件简洁,避免复杂逻辑
- 响应式:使用 TailwindCSS 响应式类
- 性能:避免不必要的重渲染
- 错误边界:添加错误边界处理异常
- 加载状态:处理数据加载中的状态
- 空状态:处理无数据的情况

