名称: 创建仪表板 描述: 创建综合性仪表板和数据分析界面,结合数据可视化、KPI卡片、实时更新和交互式布局。使用此技能构建商业智能仪表板、监控系统、执行报告或任何需要多数据展示、过滤、指标和可视化协同工作的界面。
创建仪表板
目的
此技能能够创建复杂的仪表板界面,通过协调的小部件(如KPI卡片、图表、表格和过滤器)聚合和展示数据。仪表板作为数据驱动决策的集中指挥中心,将其他技能(数据可视化、表格、设计令牌)的多个组件类型结合成统一的分析体验,具有实时更新、响应式布局和交互式过滤功能。
使用时机
在以下情况激活此技能:
- 构建商业智能或分析仪表板
- 创建执行报告界面
- 实施实时监控系统
- 设计带指标和趋势的KPI显示
- 开发可定制的小部件布局
- 协调跨多数据展示的过滤器
- 构建响应式数据密集型界面
- 实施拖放式仪表板编辑器
- 创建基于模板的分析系统
- 设计多租户SaaS仪表板
核心仪表板元素
KPI卡片解剖
┌────────────────────────────┐
│ 收入(本月) │ ← 带时间段的标签
│ │
│ $1,245,832 │ ← 大数字(主要指标)
│ ↑ 15.3% 对比上月 │ ← 带比较的趋势指示器
│ ▂▃▅▆▇█(迷你图表) │ ← 迷你可视化
└────────────────────────────┘
小部件容器结构
- 带小部件名称和操作的标题栏
- 加载状态(骨架或旋转器)
- 带重试选项的错误边界
- 可调整布局的调整手柄
- 设置菜单(导出、配置、刷新)
仪表板布局类型
固定布局:设计者定义的放置,跨用户一致 可定制网格:用户拖放、可调整大小的小部件、保存布局 基于模板:预构建模式、行业特定起点
全局仪表板控制
- 日期范围选择器(影响所有小部件)
- 过滤器面板(跨小部件协调)
- 刷新控制(手动/自动刷新)
- 导出操作(PDF、图像、数据)
- 主题切换器(浅色/深色/自定义)
实施方法
1. 选择仪表板架构
用于快速分析仪表板 → 使用 Tremor 预构建的KPI卡片、图表和表格,代码最少:
npm install @tremor/react
用于可定制仪表板 → 使用 react-grid-layout 拖放、可调整大小的小部件、用户定义布局:
npm install react-grid-layout
2. 设置全局状态管理
实现过滤器上下文以进行跨小部件协调:
// 用于共享过滤器的仪表板上下文
const DashboardContext = createContext({
filters: { dateRange: null, categories: [] },
setFilters: () => {},
refreshInterval: 30000
});
// 用提供者包裹仪表板
<DashboardContext.Provider value={dashboardState}>
<FilterPanel />
<WidgetGrid />
</DashboardContext.Provider>
3. 实施数据获取策略
并行加载:同时获取所有小部件数据 懒加载:先加载可见小部件,其他在滚动时加载 缓存更新:从缓存提供服务,同时获取新数据
4. 配置实时更新
服务器发送事件(推荐用于仪表板):
const eventSource = new EventSource('/api/dashboard/stream');
eventSource.onmessage = (event) => {
const update = JSON.parse(event.data);
updateWidget(update.widgetId, update.data);
};
5. 应用响应式设计
定义不同屏幕尺寸的断点:
- 桌面 (>1200px):多列网格
- 平板 (768-1200px):2列布局
- 移动 (<768px):单列堆叠
使用 Tremor 快速开始
基本KPI仪表板
import { Card, Grid, Metric, Text, BadgeDelta, AreaChart } from '@tremor/react';
function QuickDashboard({ data }) {
return (
<Grid numItems={1} numItemsSm={2} numItemsLg={4} className="gap-4">
{/* KPI 卡片 */}
<Card>
<Text>总收入</Text>
<Metric>$45,231.89</Metric>
<BadgeDelta deltaType="increase">+12.5%</BadgeDelta>
</Card>
<Card>
<Text>活跃用户</Text>
<Metric>1,234</Metric>
<BadgeDelta deltaType="decrease">-2.3%</BadgeDelta>
</Card>
{/* 图表小部件 */}
<Card className="lg:col-span-2">
<Text>收入趋势</Text>
<AreaChart
data={data.revenue}
index="date"
categories={["revenue"]}
valueFormatter={(value) => `$${value.toLocaleString()}`}
/>
</Card>
</Grid>
);
}
完整实现见 examples/tremor-dashboard.tsx。
可定制仪表板实施
拖放网格布局
import { Responsive, WidthProvider } from 'react-grid-layout';
import 'react-grid-layout/css/styles.css';
const ResponsiveGridLayout = WidthProvider(Responsive);
function CustomizableDashboard() {
const [layouts, setLayouts] = useState(getStoredLayouts());
return (
<ResponsiveGridLayout
layouts={layouts}
breakpoints={{ lg: 1200, md: 996, sm: 768 }}
cols={{ lg: 12, md: 10, sm: 6 }}
rowHeight={60}
onLayoutChange={(layout, layouts) => {
setLayouts(layouts);
localStorage.setItem('dashboardLayout', JSON.stringify(layouts));
}}
draggableHandle=".widget-header"
>
<div key="kpi1">
<KPIWidget data={kpiData} />
</div>
<div key="chart1">
<ChartWidget data={chartData} />
</div>
<div key="table1">
<TableWidget data={tableData} />
</div>
</ResponsiveGridLayout>
);
}
完整示例和小部件目录见 examples/customizable-dashboard.tsx。
实时数据模式
服务器发送事件(推荐)
最佳用于从服务器到仪表板的单向更新:
function useSSEUpdates(endpoint) {
useEffect(() => {
const eventSource = new EventSource(endpoint);
eventSource.onmessage = (event) => {
const update = JSON.parse(event.data);
// 更新特定小部件或所有小部件
dispatch({ type: 'UPDATE_WIDGET', payload: update });
};
return () => eventSource.close();
}, [endpoint]);
}
WebSocket(用于双向)
当仪表板需要向服务器发送命令时使用:
const ws = new WebSocket('ws://localhost:3000/dashboard');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
updateDashboard(data);
};
// 发送过滤器更改到服务器
ws.send(JSON.stringify({ type: 'FILTER_CHANGE', filters }));
智能轮询回退
用于不支持WebSocket/SSE的环境:
function useSmartPolling(fetchData, interval = 30000) {
const [isPaused, setIsPaused] = useState(false);
useEffect(() => {
if (isPaused || document.hidden) return;
const timer = setInterval(fetchData, interval);
return () => clearInterval(timer);
}, [isPaused, interval]);
// 标签页不活跃时暂停
useEffect(() => {
const handleVisibilityChange = () => {
setIsPaused(document.hidden);
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
}, []);
}
详细模式包括错误处理和重连,见 references/real-time-updates.md。
性能优化
懒加载策略
function DashboardGrid({ widgets }) {
const [visibleWidgets, setVisibleWidgets] = useState(new Set());
return widgets.map(widget => (
<LazyLoad
key={widget.id}
height={widget.height}
offset={100}
once
placeholder={<WidgetSkeleton />}
>
<Widget {...widget} />
</LazyLoad>
));
}
并行数据获取
// 同时获取所有小部件数据
const loadDashboard = async () => {
const [kpis, charts, tables] = await Promise.all([
fetchKPIs(),
fetchChartData(),
fetchTableData()
]);
return { kpis, charts, tables };
};
小部件级缓存
function CachedWidget({ id, fetcher, ttl = 60000 }) {
const cache = useRef({ data: null, timestamp: 0 });
const getData = async () => {
const now = Date.now();
if (cache.current.data && now - cache.current.timestamp < ttl) {
return cache.current.data;
}
const fresh = await fetcher();
cache.current = { data: fresh, timestamp: now };
return fresh;
};
// 获取新数据时使用缓存数据
return <Widget data={cache.current.data} onRefresh={getData} />;
}
分析和优化仪表板性能,运行:
python scripts/optimize-dashboard-performance.py --analyze dashboard-config.json
跨技能集成
使用数据可视化组件
参考 data-viz 技能以获取图表小部件:
// 使用 data-viz 技能的图表
import { createChart } from '../data-viz/chart-factory';
const revenueChart = createChart('area', {
data: revenueData,
xAxis: 'date',
yAxis: 'revenue',
theme: dashboardTheme
});
集成数据表
参考 tables 技能以获取数据网格:
// 使用 tables 技能的高级表格
import { DataGrid } from '../tables/data-grid';
<DataGrid
data={transactions}
columns={columnDefs}
pagination={true}
sorting={true}
filtering={true}
/>
应用设计令牌
使用 design-tokens 技能以获取一致主题:
// 来自 design-tokens 技能的仪表板特定令牌
const dashboardTokens = {
'--dashboard-bg': 'var(--color-bg-secondary)',
'--widget-bg': 'var(--color-white)',
'--widget-shadow': 'var(--shadow-lg)',
'--kpi-value-size': 'var(--font-size-4xl)',
'--kpi-trend-positive': 'var(--color-success)',
'--kpi-trend-negative': 'var(--color-error)'
};
过滤器输入组件
可选使用 forms 技能以获取过滤器控制:
// 来自 forms 技能的高级过滤器输入
import { DateRangePicker, MultiSelect } from '../forms/inputs';
<FilterPanel>
<DateRangePicker onChange={handleDateChange} />
<MultiSelect options={categories} onChange={handleCategoryFilter} />
</FilterPanel>
库选择指南
选择 Tremor 当:
- 需要快速构建仪表板
- 想要预样式化、专业的组件
- 在项目中使用 Tailwind CSS
- 构建标准分析界面
- 有限的自定义需求
选择 react-grid-layout 当:
- 用户需要自定义布局
- 需要拖放功能
- 不同用户需要不同视图
- 构建仪表板构建工具
- 最大灵活性是优先事项
结合两者当:
- 使用 Tremor 获取小部件内容(KPI、图表)
- 使用 react-grid-layout 进行布局管理
- 获得两者最佳
捆绑资源
脚本(无令牌执行)
scripts/generate-dashboard-layout.py- 生成响应式网格配置scripts/calculate-kpi-metrics.py- 计算趋势、比较、迷你图表scripts/validate-widget-config.py- 验证小部件和过滤器配置scripts/optimize-dashboard-performance.py- 分析和优化性能scripts/export-dashboard.py- 导出仪表板到各种格式
直接运行脚本,无需加载到上下文:
python scripts/calculate-kpi-metrics.py --data metrics.json --period monthly
参考(详细模式)
references/kpi-card-patterns.md- KPI卡片设计模式和变体references/layout-strategies.md- 网格系统和响应式方法references/real-time-updates.md- WebSocket、SSE和轮询实施references/filter-coordination.md- 跨小部件过滤器同步references/performance-optimization.md- 高级优化技术references/library-guide.md- 详细的Tremor和react-grid-layout指南
示例(完整实施)
examples/sales-dashboard.tsx- 完整销售分析仪表板examples/monitoring-dashboard.tsx- 带警报的实时监控examples/executive-dashboard.tsx- 精美的执行报告examples/customizable-dashboard.tsx- 带持久性的拖放examples/tremor-dashboard.tsx- 快速Tremor实施examples/filter-context.tsx- 全局过滤器协调
资产(模板和配置)
assets/dashboard-templates.json- 预构建仪表板布局assets/widget-library.json- 小部件目录和配置assets/grid-layouts.json- 响应式网格配置assets/kpi-formats.json- 数字格式化规则assets/theme-tokens.json- 仪表板特定设计令牌
仪表板创建工作流
- 定义需求:固定或可定制?实时还是静态?
- 选择库:Tremor用于快速,react-grid-layout用于灵活
- 设置结构:全局状态、过滤器上下文、布局系统
- 构建小部件:KPI卡片、图表(数据可视化技能)、表格(表格技能)
- 实施数据流:获取策略、缓存、更新
- 添加交互性:过滤器、下钻、导出
- 优化性能:懒加载、并行获取、缓存
- 应用主题:使用设计令牌以保持样式一致
- 测试响应式:桌面、平板、移动断点
- 部署和监控:跟踪性能、用户参与度
特定模式和详细实施,探索上述引用的捆绑资源。