# 仪表盘设计

仪表盘通常是系统中的一个可视化界面,用于展示关键数据和指标的概览。它通常以图表、图形、数字等形式呈现,旨在帮助用户直观地监测和了解系统的状态、性能或其他关键指标。

本系统支持通过客制化的方式定制仪表盘,用以显示各类图表、统计数值、表格、链接和文字说明等。

# 目标读者

本文档的目标读者为:本系统的开发和实施人员,或者对定制仪表盘感兴趣的高级用户

# 仪表盘在首页的显示

用户登录后进入首页,系统会把当前用户有权查看的所有仪表盘以标签页(Tab)的形式列出,点击标签即可切换仪表盘,右上角的 全屏显示 按钮可以将当前仪表盘全屏展示。

下图是一个名为"销售概览"的示例仪表盘,包含 3 个 STATISTIC(统计数值)、1 个 MARKDOWN、1 个柱形图、1 个饼图和 1 个 DATA_TABLE(数据表)小组件:

仪表盘首页效果

提示

首页上只负责显示仪表盘,没有新建、编辑仪表盘或小组件的按钮。仪表盘和小组件都在 开发配置 > 仪表盘 菜单下维护,见下文。

如果当前显示主题(开发配置 > 界面显示 > 显示主题)中配置了自定义首页(landingPage),首页会显示该表单,而不显示仪表盘。

# 操作概述

仪表盘由两部分组成:

  • 仪表盘:一个类型为 DASHBOARD 的表单,在 开发配置 > 仪表盘 > 仪表盘 中维护;
  • 仪表盘小组件(widget):挂在某个仪表盘下的一个显示单元,在 开发配置 > 仪表盘 > 仪表盘小组件 中维护。每个小组件通过一段核心逻辑(Dynamic Logic)返回要显示的数据。

# 创建仪表盘

进入 开发配置 > 仪表盘 > 仪表盘,点击列表右上方的 创建 按钮,弹出创建表单如下:

创建仪表盘

各字段说明如下:

字段名称 字段说明
类型(type) 必填,创建仪表盘时选择 DASHBOARD
名称(name) 必填,仪表盘的名称,唯一标识,创建后不允许修改
显示名称(label) 仪表盘在首页标签上显示的名称;为空时显示名称(name)
描述(description) 仪表盘的描述
关联对象类型(objectType) 创建仪表盘时留空
扩展信息(extInfo) 仪表盘的扩展信息,JSON 格式,可以留空

# 仪表盘的可见范围

仪表盘在首页对哪些用户可见,由表单的 accessRequirement(访问权限要求,对应一个 RoleRequirement)决定:

  • accessRequirement 为空时,所有登录用户都能看到该仪表盘;
  • 设置后,只有满足该权限要求的用户能看到该仪表盘并读取其小组件列表。

创建表单上没有这个字段,需要通过种子数据 DynamicForm.csv 的最后一列 accessRequirement.name 设置,例如:

name(*),label,description,objectType.shortName(*),type.name(*),formHook.name,formHookTriggerFields,dataHook.name,extInfo,accessRequirement.name
销售概览,销售概览,销售数据概览,,DASHBOARD,,,,,USER
1
2

提示

创建、修改、删除仪表盘的权限,看用户是否具有 DynamicForm 对象的对应权限(默认为 DEVELOPER);新增小组件的权限,看用户是否具有 DynamicDashboardWidget 对象的创建权限(默认为 DEVELOPER)。

注意

当前版本中,开发配置 > 仪表盘 > 仪表盘 列表会列出系统中全部类型的表单,而不只是 DASHBOARD 类型的表单,请根据"类型"列为 DASHBOARD 找到仪表盘。

# 新增小组件

进入 开发配置 > 仪表盘 > 仪表盘小组件,点击 创建 按钮,弹出创建表单如下:

创建仪表盘小组件

各字段说明如下:

字段名称 字段说明
仪表盘(form) 必填,该小组件所属的仪表盘
类型(type) 必填,小组件的类型,决定了该小组件在前端如何渲染,见 支持的小组件类型
名称(name) 必填,小组件的名称,唯一标识,创建后不能修改
显示名称(label) 必填,小组件卡片左上角显示的标题
描述(description) 小组件的描述
显示顺序(displaySequence) 必填,值越小越靠前
自动刷新间隔(秒)(refreshInterval) 预留字段,当前前端不会按该间隔自动刷新,见下方提示
启用逻辑(enableLogic) 控制该小组件是否显示的动态逻辑,返回 false 时隐藏;为空时总是显示
核心逻辑(coreLogic) 为该小组件准备数据和显示配置的动态逻辑,必填
显示选项(options) 必填,一个 JSON 字符串,保存小组件的宽度和显示配置,见 小组件显示选项设定;没有特别配置时填 {}

注意

当前版本的前端只在打开仪表盘时请求一次小组件数据,不会按"自动刷新间隔(秒)"或仪表盘 extInfo 中的 refreshInterval 自动刷新,需要刷新时请重新打开页面。

  • 类型下拉框中显示的是类型的英文名称(例如 Statistic、Column chart),与下文表格中的枚举值一一对应。
  • 启用逻辑和核心逻辑的写法见 小组件相关动态逻辑。

小组件也可以通过种子数据 DynamicDashboardWidget.csv 导入,列如下:

name(*),label,displaySequence,description,form.name,enableLogic.name,coreLogic.name,type,options
sales_month_amount,本月销售额,1,,销售概览,,Widget: 销售概览-本月销售额,STATISTIC,"{""position"": {""col"": 6}}"
1
2

# 修改及删除小组件

首页上的小组件没有操作菜单。需要修改或删除时,在 开发配置 > 仪表盘 > 仪表盘小组件 列表中找到对应的小组件,点击 修改 或 删除。修改核心逻辑的代码,请在 开发定制 > 动态逻辑 > 动态逻辑 中找到对应的动态逻辑进行修改。

# 内置仪表盘

系统种子数据中内置了两个仪表盘:

仪表盘 可见范围 说明
消息 USER(所有普通用户) 当前用户的消息概览
系统运行监控 DEVELOPER 共 18 个小组件,汇总各类客制化(动作、对象客制化、数据导入、定时任务等)的运行成功率、结果分布和最近的运行错误,以及无效菜单定义

"消息"仪表盘的布局如下:

消息仪表盘

  • 第一行是 4 张各占 1/4 宽度(col 6)的卡片:未读紧急信息、未读消息数量、跟踪中消息数量三个统计数值,以及"消息中心入口"。点击其中的 进入消息中心 链接会打开 消息 > 消息中心。
  • 下面是 3 个通栏(col 24)的消息列表:未读行动信息列表、未读消息列表、跟踪消息列表。列表为空时显示 "No message"(该文字由内置核心逻辑返回)。

"消息中心入口"里「进入消息中心」链接的字号比后面的文字小,这是当前版本的界面问题:该小组件返回的是一个 Markdown 三级标题,而前端全局样式给所有链接固定了字号(14px),链接不随标题放大。

# Widget 显示宽度设定及换行

系统排版小组件时,在水平方向,将所有可显示宽度划分为 24 个网格,每个小组件均可以设定 1 到 24 的显示宽度。系统会根据显示顺序对小组件进行排序,并根据每个小组件的宽度设定计算出每行可显示的小组件个数,并确保每行所有小组件的总宽度不大于 24。如果某行剩余的网格宽度不够容纳下一个待显示的小组件,则该小组件会被挪到下一行显示。

显示宽度保存在显示选项(options)字段中,通过如下的 json 数据进行指定:

// "col": 8 表示该小组件的显示宽度占据 8 个水平方向的宽度,即全部宽度的 1/3
{"position": {"col": 8}}
1
2

提示

如果在显示选项中不指定宽度,小组件的默认宽度为 8,占据一行的 1/3。

宽度按屏幕尺寸自适应:

  • 小屏幕(宽度小于 768px,即 antd 的 xs、sm 断点)上,所有小组件都占满一行(24);
  • 中等屏幕(md 断点,768px ~ 992px)上,宽度至少为 12(半行),设定值大于 12 时按设定值;
  • 大屏幕(lg 及以上)上,按设定值显示。

# 小组件显示高度

在同一行显示的所有小组件,其高度均相同。

# 小组件显示选项设定

显示选项(options)是一个 json 字符串,定义了小组件的显示配置,包括宽度和其他只适用于特定小组件类型的配置。

  • position.col:显示宽度,见上一节;
  • style:小组件外层卡片(Card)的 CSS 样式;
  • config:在前端渲染小组件时,会不经任何修改地传递给渲染的 React 控件。

如下的显示选项中,{"xField": "month", "yField": "amount"} 这个 json 对象,会被原样传递给渲染的图表控件:

{"config": {"xField": "month", "yField": "amount"}, "position": {"col": 12}}
1

# 小组件相关动态逻辑

# 启用逻辑

小组件是否显示,通过小组件的启用逻辑进行控制。

启用逻辑是逻辑类型为 DASHBOARD_WIDGET_ENABLE_LOGIC(界面显示为 "Dashboard Widget Enable Logic")的动态逻辑。

# 注入变量

前端获取某个仪表盘的小组件列表时,会先执行每个小组件的启用逻辑,如果结果不为 true,则不会返回该小组件。运行时注入的变量列表如下:

变量名称 变量类型 描述
userContext tech.muyan.api.security.MuyanAuthentication 当前操作的用户信息
application grails.core.GrailsApplication 当前的 grails 应用上下文
widget tech.muyan.dynamic.form.DynamicDashboardWidget 小组件对象

# 返回结果

客制化代码需要返回一个 Map<String, Boolean> 对象,该对象需要包含一个 key 为 result 的元素,示例如下:

// 表示该仪表盘小组件是否启用(对象动作的启用逻辑返回 [enableIds: [...]],不使用本结构)
// Indicates whether this dashboard widget is enabled (dynamic action enable logic returns [enableIds: [...]] instead)
[result: true | false]
1
2

提示

如果小组件的启用逻辑为空,则表示该小组件默认显示。

# 核心逻辑

系统通过小组件的核心逻辑生成具体要显示的数据及相关的显示属性,并传递给前端。

核心逻辑是逻辑类型为 DASHBOARD_WIDGET_CORE_LOGIC(界面显示为 "Dashboard Widget Core Logic")的动态逻辑。

# 注入变量

核心逻辑运行时的注入变量与启用逻辑相同:

变量名称 变量类型 描述
userContext tech.muyan.api.security.MuyanAuthentication 当前操作的用户信息
application grails.core.GrailsApplication 当前的 grails 应用上下文
widget tech.muyan.dynamic.form.DynamicDashboardWidget 小组件对象

此外,读取小组件数据的 HTTP 请求(GET /dashboard/widget/data/{id})上的请求参数也会一并注入。

# 返回结果

核心逻辑返回一个 Map<String, Object> 类型的对象,系统会将该 Map 直接传递给前端。前端在渲染时,会将该 Map 转化为一个 JSON 对象,并与前端渲染控件中定义的默认属性、显示选项中 key 为 config 的 JSON 对象进行合并,将合并结果作为小组件前端渲染控件的属性集。

举例如下:

  1. 小组件的显示选项如下,其中 xField 定义了图表的横坐标为 month,yField 定义了图表的纵坐标为 amount
{"config": {"xField": "month", "yField": "amount"}, "position": {"col": 12}}
1
  1. 核心逻辑返回的 Map 如下
return [
  data: [
    [month: "8月", amount: 118.0],
    [month: "9月", amount: 128.6],
  ],
  legend: false,
]
1
2
3
4
5
6
7

那么最终传递给前端图表控件的属性是上述两个来源的合并。其中 xField 和 yField 来自显示选项,data、legend 来自核心逻辑的返回值:

{
  "xField": "month",
  "yField": "amount",
  "data": [
    {"month": "8月", "amount": 118.0},
    {"month": "9月", "amount": 128.6}
  ],
  "legend": false
}
1
2
3
4
5
6
7
8
9

# 小组件类型详述

# 支持的小组件类型

系统当前支持如下 20 种小组件类型(DashboardWidgetType 枚举):

类型 下拉框中的名称 描述 对应的内部渲染控件
MARKDOWN Markdown content 一段 markdown 内容 使用 react-markdown (opens new window) 渲染
HTML Html content 一段 html 内容 显示一段 html 内容
COUNTDOWN Countdown 一个倒计时控件 Statistic 统计数值 (opens new window)
STATISTIC Statistic 单个数值的统计显示控件 Statistic 统计数值 (opens new window)
DATA_TABLE Data table 显示一个表格 Table 表格 (opens new window)
PIE_CHART Pie chart 饼图 Pie (opens new window)
LINE_CHART Line chart 折线图 Line (opens new window)
COLUMN_CHART Column chart 柱形图 Column (opens new window)
GAUGE_CHART Gauge chart 仪表盘进度图 Gauge (opens new window)
LIQUID_CHART Liquid chart 水波图 Liquid (opens new window)
BULLET_CHART Bullet chart 子弹图 Bullet (opens new window)
AREA_CHART Area chart 面积图 Area (opens new window)
BAR_CHART Bar chart 条形图 Bar (opens new window)
PROGRESS_CHART Progress chart 迷你进度条 Tiny.Progress (opens new window)
RING_PROGRESS_CHART Ring progress chart 迷你进度环图 Tiny.Ring (opens new window)
TINY_AREA_CHART Tiny area chart 迷你面积图 Tiny.Area (opens new window)
TINY_LINE_CHART Tiny line chart 迷你折线图 Tiny.Line (opens new window)
TINY_COLUMN_CHART Tiny column chart 迷你柱形图 Tiny.Column (opens new window)
BI_DIRECTION_BAR Bi direction bar 对称条形图 BidirectionalBar (opens new window)
HISTOGRAM Histogram 直方图 Histogram (opens new window)

相关的小组件类型有特定的一些设定或者使用中的注意事项,详述如下。

# 非图表类 Widget 属性结构

# Markdown 及 Html 小组件

Markdown 及 Html 类型小组件的核心逻辑返回值结构如下:

// 包含 key 为 data、value 为显示文本的一个 Map 对象
return [data: "**数据口径**\n\n按订单确认日期统计,金额为含税金额。"]
1
2

Html 小组件会把显示选项 config 中的属性和核心逻辑返回的属性(data 之外)合并后,设置到包裹 html 内容的 div 上,因此可以通过 style 设置整体样式。可以写在显示选项中:

{
  "config": {
    "style": {
      "color": "red",
      "fontSize": "32px",
      "textAlign": "center"
    }
  },
  "position": {"col": 8}
}
1
2
3
4
5
6
7
8
9
10

也可以在核心逻辑的返回值中通过 style 字段设置:

return [
  data : "<b>Hello World</b>",
  style: [
    // 可选的 CSS 样式
    fontSize: "12px"
  ]
]
1
2
3
4
5
6
7

提示

Markdown 小组件通过 remark-gfm (opens new window) 支持 GFM 标准 (opens new window),包括表格、任务列表、删除线等扩展格式。Markdown 小组件不支持通过 config 或 style 设置样式,也不会渲染 mermaid 代码块。

Markdown 表格的表头行、分隔行和数据行列数必须一致,否则整张表格会被当作普通文本显示。

注意

当前版本前端的全局样式去掉了 ul、ol 的列表符号,Markdown 小组件中的无序列表、有序列表不显示圆点和序号,只剩缩进。需要逐条列出时,可以在每行前手工写上序号或「·」,并在行尾加两个空格换行。

# 倒计时小组件

以下是倒计时类型小组件的核心逻辑返回值结构示例:

import java.time.LocalDate
import java.time.ZoneId

long target = LocalDate.of(2026, 12, 31)
  .atStartOfDay(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli()

return [
  // title 是界面上显示的倒计时标题,建议总是返回
  // (不返回时显示默认标题 Countdown,当前版本未翻译)
  title : '距年度盘点',
  // value 是倒计时的目标时间(毫秒时间戳),系统会根据当前时间自动生成倒计时显示
  value : target,
  // 可选,默认格式为 "D 天 H 时 m 分 s 秒"
  format: 'D 天 H 时',
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 数据表小组件

以下是数据表类型小组件的核心逻辑返回值结构示例:

return [
  // data 为待显示的数据数组,数组的每个元素都是一个 Map
  // 如下的结构会在前端渲染成一个具有 3 列的表格
  data: [
    [销售员: "王磊", 区域: "华东", 订单数: 86],
    [销售员: "李娜", 区域: "华南", 订单数: 74],
  ]
]
1
2
3
4
5
6
7
8
  • 列取自第一行数据的 key,列标题由 key 转换而来:驼峰命名会拆成单词并首字母大写(例如 orderCount 显示为 Order Count),中文 key 原样显示。
  • 单元格内容按 HTML 渲染,可以返回链接等 HTML 片段。
  • 返回空数组时,显示"后台返回数据为空"的提示。
  • 显示选项 config 中的属性会原样传给 antd Table (opens new window),例如用 "pagination": false 关闭分页。由于 Map 的 key 顺序在返回前端时不一定保持,需要固定列顺序或自定义列标题时,可以在 config.columns 中指定:
{
  "config": {
    "pagination": false,
    "columns": [
      {"title": "销售员", "dataIndex": "销售员"},
      {"title": "区域", "dataIndex": "区域"},
      {"title": "订单数", "dataIndex": "订单数"}
    ]
  },
  "position": {"col": 24}
}
1
2
3
4
5
6
7
8
9
10
11

# Statistic 小组件

以下是 Statistic 类型小组件的核心逻辑返回值结构示例:

return [
  // title 是统计数值上方的小标题
  title    : "本月销售额(万元)",
  // value 是界面显示的值
  value    : 128.6,
  // 可选,小数位数,默认为 2
  precision: 2,
  // 可选,取值为 "up" 或 "down",分别显示绿色向上箭头和红色向下箭头
  direction: "up",
]
1
2
3
4
5
6
7
8
9
10

小组件显示效果及各部分与返回值的对应关系如下:

  • 第一行粗体的"本月销售额"是小组件的显示名称(label);
  • 第二行灰色的"本月销售额(万元)"是核心逻辑返回的 title;
  • 数值 128.60 来自 value,按 precision 保留 2 位小数;
  • 绿色向上箭头来自 direction: "up"。

# 图表类型 Widget

所有的图表类小组件,均使用 Ant Design Charts (opens new window) 图表库进行渲染,当前只支持上述表格中列出的图表类型。

图表小组件被渲染时,会将显示选项中 key 为 config 的部分与核心逻辑返回的 Map 的顶层 key 进行合并,将合并结果直接作为参数传递给 Ant Design Charts 的渲染控件。

兼容性提示

显示选项和核心逻辑的返回值都是 JSON,不支持 javascript 回调函数类型的渲染属性。

# 图表的坐标轴设定

对于包含坐标轴的图表类型,需要在显示选项或者核心逻辑的返回值中,包含坐标轴的设定,否则有可能出现图表显示为空或者显示出错的情况。

  1. 在显示选项中设定
{"config": {"xField": "month", "yField": "amount"}, "position": {"col": 12}}
1
  1. 在核心逻辑中直接返回
return [
  xField: "month",
  yField: "amount",
  data  : [
    [month: "8月", amount: 118.0],
    [month: "9月", amount: 128.6],
  ]
]
1
2
3
4
5
6
7
8

xField 和 yField 为必传属性的图表如下:

  • 折线图 LINE_CHART
  • 面积图 AREA_CHART
  • 柱形图 COLUMN_CHART
  • 条形图 BAR_CHART
  • 对称条形图 BI_DIRECTION_BAR(yField 为两个字段名组成的数组)

饼图需要用 angleField 指定数值字段、colorField 指定分类字段,例如:

{"config": {"angleField": "amount", "colorField": "line"}, "position": {"col": 12}}
1

# 图表的传值属性列表

按照 Ant Design Charts 的 API,不同图表承载数据的属性名称不尽相同,下表列出了各图表的数据属性名称供参考,具体的值格式请参考 Ant Design Charts 文档。

图表类型 数据属性名称
折线图 LINE_CHART data
面积图 AREA_CHART data
柱形图 COLUMN_CHART data
条形图 BAR_CHART data
饼图 PIE_CHART data
仪表盘进度图 GAUGE_CHART data,格式为 {"target": 当前值, "total": 总值}
水波图 LIQUID_CHART percent(0 ~ 1)
迷你进度条 PROGRESS_CHART percent(0 ~ 1)
迷你进度环图 RING_PROGRESS_CHART percent(0 ~ 1)
子弹图 BULLET_CHART data
迷你面积图 TINY_AREA_CHART data
迷你折线图 TINY_LINE_CHART data
迷你柱形图 TINY_COLUMN_CHART data
对称条形图 BI_DIRECTION_BAR data
直方图 HISTOGRAM data(另需 binField 指定分箱字段)

仪表盘进度图的示例(前端默认会在中间显示 target / total 的百分比):

return [
  data: [
    target: 86,
    total : 100,
  ]
]
1
2
3
4
5
6

提示

承载数据的属性在核心逻辑的返回结果中是必须的,否则图表将无法显示。

兼容性提示

当前使用的 Ant Design Charts 版本为 2.6.7(v2),v2 的配置项与 v1 有较大差异,从旧版本迁移过来的小组件需要按 v2 的 API 调整配置。如果上述属性失效,请参考 Ant Design Charts 文档 (opens new window) 中各图表最新的 API。

# 注意事项

以下列出了相关仪表盘实现过程的注意事项及最佳实践

# 小组件显示属性的优先级

系统在渲染小组件时,会将小组件的核心逻辑返回值、显示选项中的 config 及前端渲染控件中定义的默认属性进行合并,作为最终的控件渲染属性。对于相同名称的属性,优先级高的来源会覆盖优先级低的来源:

  • 最高:核心逻辑返回的显示属性
  • 其次:显示选项 config 中定义的显示属性
  • 最低:各小组件 React 控件的默认显示属性

# 最佳实践

# Markdown 小组件中的换行

如果需要在渲染结果中增加换行,可以在行尾增加两个空格,或者用一个空行分隔段落。

# 小组件最小宽度

如果小组件的宽度设定小于 4(显示选项中设定的宽度为 1、2 或 3),那么有一定概率出现该小组件与后面的小组件显示重叠的情况,因此建议小组件的宽度最小为 4(占据整体宽度的 1/6 以上)。

# 显示选项字段格式特别说明

显示选项在数据库中以 jsonb 类型的字段保存,因 postgresql 要求,该 json 字符串中的字符串均需要包含在 双引号 中,不能使用单引号,如 {"position": {"col": 8}} 不能写作 {'position': {'col': 8}},否则保存到数据库会失败。

# 相关实现背景 开发

以下列出了一些可能对于创建仪表盘和进行问题排查有帮助的框架实现细节

  • 仪表盘在系统中是一种类型为 DASHBOARD 的表单(Form),与对象的列表、创建、编辑等表单相同,都存放在 dynamic_form 数据库表中;小组件存放在 dynamic_dashboard_widget 表中。
  • 仪表盘相关的 API 如下:
API 说明
GET /dashboard/list 当前用户可见的仪表盘列表
GET /dashboard/meta/{id} 指定仪表盘下的小组件列表(会执行各小组件的启用逻辑)
GET /dashboard/widget/data/{id} 执行指定小组件的核心逻辑,返回其数据和显示配置
Last Updated: 2026/9/24 14:27:35