返回博客

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

  1. 声明式优先:YAML 定义布局和数据绑定,复杂交互用 Python API
  2. 数据源灵活:支持指标查询和 OQL 查询两种数据源
  3. 交互联动:全局过滤器、Widget 间联动、下钻分析形成完整分析体验
  4. 实时能力:WebSocket 推送实现秒级刷新的监控大屏
  5. 权限分层:Dashboard 级查看/编辑权限 + 行级数据权限
  6. 分享导出:支持 PDF 导出、分享链接和定时报表

#Next Article

下一篇:S12-11 权限配置指南 — 学习 coomia-dip 的三层权限模型:RBAC + ABAC + 行级安全。

Tags: Dashboard 可视化 图表 报表 实时监控 coomia-dip