Dashboard 开发指南
Dashboard 是 coomia-dip 平台的可视化层,将 Ontology 数据和指标转化为交互式图表和报表。本文介绍如何使用 YAML 和 Python SDK 构建 Dashboard,包括布局设计、数据源绑定、图表配置、交互联动、权限控制和实时刷新。
Coomia发布于 2026年1月19日10 分钟阅读
分享本文Twitter / X
“系列:S12 开发者教程 · 第 10 篇 | 难度:中级 | 阅读时间:15 分钟
Dashboard 开发指南
#TL;DR
Dashboard 是 coomia-dip 平台的可视化层,将 Ontology 数据和指标转化为交互式图表和报表。本文介绍如何使用 YAML 和 Python SDK 构建 Dashboard,包括布局设计、数据源绑定、图表配置、交互联动、权限控制和实时刷新。
#1. Dashboard 概述
#1.1 架构
Code
┌─────────────────────────────────────┐
│ Dashboard Runtime │
│ (Frontend - React/Vue) │
├─────────────────────────────────────┤
│ Layout Engine │ Widget Registry │
│ Filter Engine │ Theme Manager │
└────────┬────────────────┬───────────┘
│ gRPC/WebSocket │
▼ ▼
┌─────────────────┐ ┌────────────────┐
│ Control Layer │ │ Data Layer │
│ (Metric API) │ │ (OQL Query) │
└─────────────────┘ └────────────────┘
#1.2 核心概念
| 概念 | 说明 |
|---|---|
| Dashboard | 仪表盘,包含多个 Widget |
| Widget | 图表/表格/指标卡等可视化组件 |
| DataSource | 数据源,关联指标或 OQL 查询 |
| Filter | 全局/局部过滤器,支持联动 |
| Layout | 布局,基于 Grid 系统 |
#2. 创建 Dashboard
#2.1 YAML 声明
YAML
# dashboards/sales_overview.yaml
name: sales_overview
display_name: 销售总览仪表盘
description: 实时展示销售核心指标和趋势
category: sales
owner: sales-team
refresh_interval: 300 # 5 分钟自动刷新
theme:
primary_color: "#1890ff"
chart_palette: ["#1890ff", "#52c41a", "#faad14", "#f5222d", "#722ed1"]
permissions:
view: [sales-team, management]
edit: [sales-admin]
filters:
- name: time_range
type: date_range
default: last_30_days
position: header
- name: region
type: select
source: "FIND Region SELECT name, code ORDER BY name"
multiple: true
position: header
- name: product_category
type: select
source: "FIND ProductCategory SELECT name, code"
multiple: true
position: header
layout:
columns: 24
row_height: 60
widgets:
# 第一行:核心指标卡
- name: total_revenue_card
type: metric_card
position: {x: 0, y: 0, w: 6, h: 2}
config:
metric: total_revenue
format: "currency"
comparison: month_over_month
trend: true
icon: dollar
- name: order_count_card
type: metric_card
position: {x: 6, y: 0, w: 6, h: 2}
config:
metric: order_count
format: "number"
comparison: month_over_month
icon: shopping-cart
- name: avg_order_value_card
type: metric_card
position: {x: 12, y: 0, w: 6, h: 2}
config:
metric: avg_order_value
format: "currency"
comparison: month_over_month
icon: bar-chart
- name: customer_count_card
type: metric_card
position: {x: 18, y: 0, w: 6, h: 2}
config:
metric: active_customer_count
format: "number"
comparison: month_over_month
icon: team
# 第二行:趋势图和饼图
- name: revenue_trend
type: line_chart
position: {x: 0, y: 2, w: 16, h: 4}
config:
title: 收入趋势
data_source:
metric: total_revenue
granularity: day
apply_filters: [time_range, region]
series:
- name: 本期
color: "#1890ff"
- name: 上期
type: comparison
period: previous_period
style: dashed
color: "#d9d9d9"
axes:
x: { type: time, format: "MM-DD" }
y: { type: value, format: "currency_short" }
- name: region_pie
type: pie_chart
position: {x: 16, y: 2, w: 8, h: 4}
config:
title: 区域收入占比
data_source:
metric: total_revenue
dimension: region
apply_filters: [time_range]
show_percentage: true
show_legend: true
# 第三行:柱状图和排名表
- name: product_bar
type: bar_chart
position: {x: 0, y: 6, w: 12, h: 4}
config:
title: 产品类别销售额
data_source:
metric: total_revenue
dimension: product_category
apply_filters: [time_range, region]
orientation: horizontal
sort: desc
show_value: true
- name: top_customers
type: table
position: {x: 12, y: 6, w: 12, h: 4}
config:
title: 客户排名 TOP 10
data_source:
type: oql
query: |
FIND Customer
INCLUDE
TRAVERSE serves <- Project <- Order
WHERE Order.status = 'completed'
AGGREGATE SUM(Order.total_amount) AS revenue, COUNT(*) AS order_count
SELECT Customer.name, Customer.tier, revenue, order_count
ORDER BY revenue DESC
LIMIT 10
apply_filters: [time_range]
columns:
- { field: name, title: 客户名称, width: 200 }
- { field: tier, title: 等级, width: 80, render: tag }
- { field: revenue, title: 总收入, width: 120, format: currency }
- { field: order_count, title: 订单数, width: 80, align: center }
#2.2 Python API 创建
Python
from ontology_sdk import OntoPlatform
from ontology_sdk.dashboard import (
DashboardBuilder, MetricCard, LineChart, PieChart,
BarChart, Table, Filter, Layout
)
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052"
)
dashboard = (
DashboardBuilder("sales_overview")
.display_name("销售总览仪表盘")
.category("sales")
.refresh_interval(300)
.filter(Filter.date_range("time_range", default="last_30_days"))
.filter(Filter.select("region", source="FIND Region SELECT name, code", multiple=True))
# 指标卡
.widget(
MetricCard("total_revenue_card")
.metric("total_revenue")
.format("currency")
.comparison("month_over_month")
.position(0, 0, 6, 2)
)
.widget(
MetricCard("order_count_card")
.metric("order_count")
.format("number")
.comparison("month_over_month")
.position(6, 0, 6, 2)
)
# 趋势图
.widget(
LineChart("revenue_trend")
.title("收入趋势")
.metric("total_revenue", granularity="day")
.comparison_series("previous_period")
.apply_filters(["time_range", "region"])
.position(0, 2, 16, 4)
)
# 饼图
.widget(
PieChart("region_pie")
.title("区域收入占比")
.metric("total_revenue", dimension="region")
.show_percentage(True)
.position(16, 2, 8, 4)
)
# 柱状图
.widget(
BarChart("product_bar")
.title("产品类别销售额")
.metric("total_revenue", dimension="product_category")
.orientation("horizontal")
.sort("desc")
.position(0, 6, 12, 4)
)
# 表格
.widget(
Table("top_customers")
.title("客户排名 TOP 10")
.oql_source("""
FIND Customer
INCLUDE TRAVERSE serves <- Project <- Order
WHERE Order.status = 'completed'
AGGREGATE SUM(Order.total_amount) AS revenue
SELECT Customer.name, Customer.tier, revenue
ORDER BY revenue DESC LIMIT 10
""")
.columns([
{"field": "name", "title": "客户名称"},
{"field": "tier", "title": "等级", "render": "tag"},
{"field": "revenue", "title": "总收入", "format": "currency"},
])
.position(12, 6, 12, 4)
)
.build()
)
platform.dashboards.register(dashboard)
print(f"Dashboard 已注册: {dashboard.name}")
#3. Widget 类型详解
#3.1 指标卡(Metric Card)
Python
card = (
MetricCard("revenue_card")
.metric("total_revenue")
.format("currency")
.comparison("month_over_month") # 环比
.trend(True) # 显示趋势线
.sparkline(True) # 迷你趋势图
.threshold(
warning=1000000, # 黄色警告阈值
danger=500000, # 红色危险阈值
direction="below" # 低于阈值触发
)
.position(0, 0, 6, 2)
)
#3.2 折线图(Line Chart)
Python
line = (
LineChart("multi_metric_trend")
.title("多指标趋势对比")
.series("total_revenue", label="收入", color="#1890ff", y_axis="left")
.series("order_count", label="订单数", color="#52c41a", y_axis="right")
.series("avg_order_value", label="客单价", color="#faad14", y_axis="left")
.dual_y_axis(left_label="金额(元)", right_label="数量(个)")
.granularity("day")
.apply_filters(["time_range"])
.legend(position="top")
.tooltip(shared=True)
.position(0, 2, 24, 5)
)
#3.3 地图(Map)
Python
from ontology_sdk.dashboard import MapChart
geo_map = (
MapChart("revenue_map")
.title("全国收入分布")
.map_type("china")
.metric("total_revenue", dimension="region")
.color_scale(["#e6f7ff", "#1890ff", "#003a8c"])
.show_labels(True)
.drill_down(enabled=True, levels=["province", "city"])
.position(0, 10, 24, 6)
)
#3.4 仪表盘(Gauge)
Python
from ontology_sdk.dashboard import Gauge
completion_gauge = (
Gauge("project_completion")
.title("项目整体完成率")
.metric("project_completion_rate")
.format("percentage")
.ranges([
{"min": 0, "max": 60, "color": "#f5222d"},
{"min": 60, "max": 80, "color": "#faad14"},
{"min": 80, "max": 100, "color": "#52c41a"},
])
.position(0, 16, 8, 4)
)
#4. 交互与联动
#4.1 全局过滤器联动
YAML
filters:
- name: department
type: cascade
levels:
- source: "FIND BusinessUnit SELECT name, code"
label: 事业部
- source: "FIND Department WHERE business_unit = :parent SELECT name, code"
label: 部门
- source: "FIND Team WHERE department = :parent SELECT name, code"
label: 团队
cascade: true
position: header
#4.2 Widget 间联动
Python
# 点击饼图区域 → 过滤表格数据
dashboard_builder.interaction(
source_widget="region_pie",
event="click",
target_widget="top_customers",
action="filter",
mapping={"region": "$clicked.dimension_value"}
)
# 选择表格行 → 显示详情面板
dashboard_builder.interaction(
source_widget="top_customers",
event="row_click",
target_widget="customer_detail_panel",
action="load_detail",
mapping={"customer_rid": "$row.rid"}
)
#4.3 下钻分析
Python
# 从月度 → 周 → 日下钻
line_chart = (
LineChart("revenue_trend")
.title("收入趋势")
.metric("total_revenue", granularity="month")
.drill_down(
levels=["month", "week", "day"],
animation=True
)
.position(0, 2, 16, 4)
)
#5. 实时 Dashboard
#5.1 WebSocket 实时推送
Python
from ontology_sdk.dashboard import RealtimeDashboard
realtime = (
RealtimeDashboard("ops_monitor")
.display_name("运维监控大屏")
.refresh_mode("realtime")
.websocket_config(
url="ws://data-Layer:8081/ws/metrics",
reconnect_interval=5
)
.widget(
MetricCard("current_qps")
.metric("realtime_request_rate")
.format("number")
.suffix("/s")
.realtime(True)
.position(0, 0, 6, 2)
)
.widget(
LineChart("qps_trend")
.title("QPS 实时趋势")
.metric("realtime_request_rate")
.granularity("1m")
.rolling_window("30m")
.realtime(True)
.position(0, 2, 24, 4)
)
.build()
)
#6. Dashboard 模板
#6.1 内置模板
Python
# 从模板创建
dashboard = platform.dashboards.create_from_template(
template="executive_overview",
name="ceo_dashboard",
config={
"metrics": {
"primary_revenue": "total_revenue",
"primary_cost": "total_cost",
"primary_count": "order_count",
},
"dimensions": {
"region": "customer.region",
"category": "product.category",
}
}
)
# 列出可用模板
templates = platform.dashboards.list_templates()
for t in templates:
print(f"{t.name}: {t.description} (Widgets: {t.widget_count})")
#6.2 导出为模板
Python
# 将现有 Dashboard 导出为模板
platform.dashboards.export_as_template(
dashboard_name="sales_overview",
template_name="sales_dashboard_template",
parameterize=["metrics", "dimensions", "filters"]
)
#7. 权限控制
Python
from ontology_sdk.dashboard import DashboardPermission
# 设置 Dashboard 权限
platform.dashboards.set_permissions(
"sales_overview",
permissions=[
DashboardPermission(role="sales-admin", level="edit"),
DashboardPermission(role="sales-team", level="view"),
DashboardPermission(role="management", level="view"),
DashboardPermission(
role="regional-manager",
level="view",
row_filter={"region": "$user.region"} # 行级数据权限
),
]
)
#8. 导出与分享
Python
# 导出为 PDF
pdf_bytes = platform.dashboards.export(
"sales_overview",
format="pdf",
filters={"time_range": "2025-01-01,2025-03-31"},
paper_size="A3",
orientation="landscape"
)
with open("sales_report_Q1.pdf", "wb") as f:
f.write(pdf_bytes)
# 生成分享链接
share_link = platform.dashboards.share(
"sales_overview",
expires_in="7d",
password="optional-password",
filters_locked=True
)
print(f"分享链接: {share_link.url}")
# 定时邮件报表
platform.dashboards.schedule_report(
"sales_overview",
schedule="0 9 * * 1", # 每周一上午9点
format="pdf",
recipients=["management@company.com"],
subject="周度销售报表"
)
#9. 完整实战:项目管理仪表盘
Python
from ontology_sdk import OntoPlatform
from ontology_sdk.dashboard import (
DashboardBuilder, MetricCard, LineChart, BarChart,
Table, PieChart, Filter, Gauge
)
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052"
)
dashboard = (
DashboardBuilder("project_management")
.display_name("项目管理仪表盘")
.category("project")
.refresh_interval(600)
# 过滤器
.filter(Filter.date_range("time_range", default="last_90_days"))
.filter(Filter.select("department", source="FIND Department SELECT name"))
.filter(Filter.select("status", options=["planning", "in_progress", "done", "paused"]))
# 第一行:核心指标
.widget(MetricCard("active_projects").metric("active_project_count").position(0, 0, 6, 2))
.widget(MetricCard("completion_rate").metric("project_completion_rate").format("percentage").position(6, 0, 6, 2))
.widget(MetricCard("overdue_tasks").metric("overdue_task_count").threshold(danger=10).position(12, 0, 6, 2))
.widget(MetricCard("team_velocity").metric("avg_team_velocity").position(18, 0, 6, 2))
# 第二行:项目状态分布 + 完成趋势
.widget(
PieChart("status_distribution")
.title("项目状态分布")
.oql_source("FIND Project GROUP BY status AGGREGATE COUNT(*) AS count")
.position(0, 2, 8, 4)
)
.widget(
LineChart("completion_trend")
.title("任务完成趋势")
.metric("completed_task_count", granularity="week")
.comparison_series("previous_period")
.position(8, 2, 16, 4)
)
# 第三行:部门工作量 + 项目列表
.widget(
BarChart("dept_workload")
.title("部门任务负载")
.oql_source("""
FIND Task WHERE status != 'done'
TRAVERSE assigned_to -> Employee
TRAVERSE works_in -> Department
GROUP BY Department.name
AGGREGATE COUNT(*) AS pending_tasks
""")
.position(0, 6, 10, 4)
)
.widget(
Table("project_list")
.title("项目进度详情")
.oql_source("""
FIND Project
WHERE status IN ('planning', 'in_progress')
INCLUDE TRAVERSE has_task -> Task
AGGREGATE COUNT(*) AS total, COUNT(CASE WHEN Task.status='done' THEN 1 END) AS done
SELECT name, status, priority, end_date, total, done
ORDER BY end_date ASC
""")
.columns([
{"field": "name", "title": "项目名称", "width": 200},
{"field": "status", "title": "状态", "render": "tag"},
{"field": "priority", "title": "优先级", "render": "tag"},
{"field": "end_date", "title": "截止日期"},
{"field": "progress", "title": "进度", "render": "progress_bar",
"computed": "done / total * 100"},
])
.position(10, 6, 14, 4)
)
.build()
)
platform.dashboards.register(dashboard)
url = platform.dashboards.get_url("project_management")
print(f"Dashboard URL: {url}")
#Key Takeaways
- 声明式优先:YAML 定义布局和数据绑定,复杂交互用 Python API
- 数据源灵活:支持指标查询和 OQL 查询两种数据源
- 交互联动:全局过滤器、Widget 间联动、下钻分析形成完整分析体验
- 实时能力:WebSocket 推送实现秒级刷新的监控大屏
- 权限分层:Dashboard 级查看/编辑权限 + 行级数据权限
- 分享导出:支持 PDF 导出、分享链接和定时报表
#Next Article
下一篇:S12-11 权限配置指南 — 学习 coomia-dip 的三层权限模型:RBAC + ABAC + 行级安全。
Tags: Dashboard 可视化 图表 报表 实时监控 coomia-dip