# 仪表盘设计

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

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

# 目标读者

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

# 操作概述

# 创建仪表盘

具有创建仪表盘权限的用户登陆进入系统后,会在首页看到新建仪表盘的按钮如下所示

Create Dashboard

点击该按钮后,会弹出仪表盘的创建表单如下

Create Dashboard Form

其中重点的相关字段描述如下:

字段名称 字段说明
Form Type 创建仪表盘时,值设定为 Dashboard
Name 该仪表盘的名称,设定后不允许修改
Label 该仪表盘在界面上显示的名称
Organization 该仪表盘的所属组织
Enable Role 可以查看该仪表盘的用户角色列表, 如果该用户也具有仪表盘编辑的权限,则该用户同时可以编辑仪表盘

提示

用户是否具有创建、编辑、删除 Dashboard 的权限判断,是看用户是否具有 DynamicForm 这一 Domain 对象的对应权限。

# 仪表盘编辑及其他相关操作

  1. 切换到待修改的仪表盘,并点击仪表盘显示标签后的齿轮图标,即可弹出仪表盘操作菜单,其中包括如下相关功能

Dashboard operate

编辑仪表盘的操作与创建类似,此处不再赘述。

# 新增 widget

在上述仪表盘的操作菜单中,点击 Add new widget 即可在当前仪表盘下新增一个 widget ,新增 widget 的表单如下所示:

Create widget

其中重点的相关字段描述如下:

字段名称 字段说明
Dashboard 该 widget 所属的 dashboard
Type 该 widget 的类型,决定了该 widget 在前台如何进行渲染
Name 该 widget 的名称,唯一标识,创建后即无法修改
Label 该 widget 的显示名称
Display Sequence 该 widget 的显示顺序,display sequence 越小的 widget, 显示越靠前
Enable Logic 该 widget 是否显示的动态逻辑,如执行的结果为 false 则该 widget 会隐藏
Core Logic 该 widget 的数据准备和显示配置的核心逻辑
Options 一个 JSON 字符串,保存该 widget 的显示配置

# 修改及删除 widget

将鼠标放到 widget 上,在 widget 的右上方会出现一个齿轮图标,点击该齿轮图标,则会出现操作菜单如下所示:

Widget operate

如果当前用户有编辑 widget 的权限,则会出现如下的相关操作菜单

  • Refresh data: 刷新数据
  • Show in popup window: 在更大的弹出窗口中显示该 widget 的内容
  • Edit Widget settings: 编辑 Widget 的相关设定
  • Edit widget core logic: 编辑该 widget 的核心逻辑,widget 的核心逻辑是一个 dynamic logic 对象,用于向前台返回渲染 widget 所需要的数据和配置信息

# Widget 显示宽度设定及换行

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

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

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

提示

如果在 Options 中不指定 widget 的宽度,则 widget 的默认宽度为 12, 占据一行的 1/2。

# Widget 显示高度

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

# Widget Options 设定

Widget 定义中的 Options 是一个 json 字符串,定义了 widget 的显示配置, 包括宽度和其他只适用于特定 widget 类型的配置。

此外,在 Options 字段的 config 下定义的配置,在前端渲染 widget 时,会不经任何修改的, 传递给渲染的 React 控件。如下的 Options 设定中,{"xField": "year", "yField": "value", "tooltip": {"showMarkers": true}} 这个 json 对象,会被原样传递给渲染的 React 控件。

{"config": {"xField": "year", "yField": "value", "tooltip": {"showMarkers": true}}, "position": {"col": 8}}
1

# Widget 相关动态逻辑

# Enable logic

Widget 是否显示是通过 widget 的 enable logic 进行控制,而显示的相关配置和数据,

Widget 的 enable logic 是 Logic Type 为 "Dashboard widget enable logic" 的 Dynamic Logic 对象

# 注入变量

前台获取某个 Dashboard 的 widget 列表时,会先调用每个 widget 定义中的 enable logic 动态逻辑并进行计算, 如果计算结果为 false, 则不会将该 widget 返回,运行时注入的变量列表如下:

变量名称 变量类型 描述
userContext grails.plugin.springsecurity.userdetails.GrailsUser 当前操作的用户信息
application grails.core.GrailsApplication 当前的 grails 应用上下文
widget tech.muyan.dynamic.form.DynamicDashboardWidget widget 对象

# 返回结果

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

// 表示该 action 或 task 或 widget 是否启用
[result: true | false]
1

提示

如果 widget 定义中的 enable logic 字段为空,则表示该 widget 默认显示

# Core logic

系统通过 widget 的 core logic 生成具体要显示的数据及相关的显示属性,并传递给前台。

# 注入变量

Widget core logic 运行时的注入变量如下表所示:

变量名称 变量类型 描述
userContext grails.plugin.springsecurity.userdetails.GrailsUser 当前操作的用户信息
application grails.core.GrailsApplication 当前的 grails 应用上下文
widget tech.muyan.dynamic.form.DynamicDashboardWidget widget 对象

# 返回结果

Widget core logic 运行返回的结果是一个类型为 Map<String, Object> 类型的对象, 系统会将返回的该 Map 对象直接传递给前台。前台在渲染时,会将该 Map 对象直接转化为一个 JSON 对象, 并与前台的 Widget 渲染控件 中定义的默认属性和 Widget 定义的 Options 中, key 为 config 的 JSON 对象进行合并, 合并后, 将合并结果作为 Widget 的前台渲染控件的属性集。

举例如下:

  1. Widget 定义的 Options 字段的值如下,其中 xField 定义了图表的横坐标为 year, yField 定义了图表的纵坐标为 value
{"config": {"xField": "year", "yField": "value", "position": {"col": 8}}
1
  1. 在 Widget core logic 中返回的 Map 的值如下
def data = [
  [x: 1, y: 2],
  [x: 3, y: 4]
]
def result = [
  data: data,
  legend: [
      custom: true,
      position: 'bottom',
  ]
]
return result 
1
2
3
4
5
6
7
8
9
10
11
12

那么最终传递给 React 的渲染控件的属性是上述两个来源的合并。

其中, xField 和 yField 属性来自 widget 定义中的 Options 字段, data, legend 两个属性来自 Widget core logic 的返回值

{
  "xField": "year",
  "yField": "value",
  "data": [
    {"x": 1, "y": 2},
    {"x": 3, "y": 4}
  ],
  "legend": {
    "custom": true,
    "position": "bottom"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# Widget 类型详述

# 支持的 Widget 类型列表

以下列出了系统当前支持的 widget 类型及其简要描述

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

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

# 非图表类 Widget 属性结构

# Markdown 及 Html Widget

以下是 markdown 及 html 类型 widget 的 core logic 返回值的结构

// 包含 key 为 data, value 为显示文本的一个 Map 对象
[ data: "Markdown 文本" ]

:::

可以在 Html widget 的 options 中,通过 `config` 字段来设置 widget 整体的样式,例如

``` json
{
  "config": {
    "style": {
      "color": "red",
      "fontSize": "32px",
      "textAlign": "center"
    }
  }
}

也可以在 widget 的 core logic 返回值中,通过 `style` 字段来设置 widget 整体的样式,例如

``` groovy

return [
  data: "Hello World",
  style: [
    // 可选的 CSS 样式
    fontSize: "12px"
  ]
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

:::


::: tip

Markdown widget 通过 [remark-gfm](https://github.com/remarkjs/remark-gfm) 支持
[gfm 标准](https://github.github.com/gfm/)支持包括表格、列表、TODO 等在内的一些
列高级格式控制。

::: 

#### 倒计时 Widget

以下是倒计时类型 widget 的 core logic 返回值的结构示例

``` groovy
Date d = new Date()
d.setYear(2022 - 1900);
d.setMonth(1)
d.setDate(4);

return [
  // Title 是界面上显示的倒计时的标题
  title: '冬奥会倒计时',
  // Value 是倒计时的目标时间,系统会根据当前时间自动生成倒计时显示
  value: d.getTime()
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 数据表 Widget

以下是数据表类型 widget 的 core logic 返回值的结构示例

return [
  // 包含 key 为 data, value 为待显示的数据的数组
  // 数组的每个元素都是一个 Map 类型的结构
  // 如下的结构会在前台渲染成一个具有两列的表格
  // 列标题分别为 First Column 和 Second Column
  data: [
    [
        "FirstColumn": "Hahaha",
        "SecondColumn": "Good"
    ], [
        "FirstColumn": "Hahaha2",
        "SecondColumn": "Good2"
    ]
  ]
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Statistic Widget

以下是 Statistic 类型 widget 的 core logic 返回值的结构示例

return [
  // title 是界面显示的标题
  title: "昨天的销售情况",
  // value 是界面显示的值
  value: 50 
  // direction 可选值为 up 和 down, 决定界面显示的箭头的颜色和方向
  direction:  "up" | "down"
]
1
2
3
4
5
6
7
8

Widget 显示效果及各部分与后台传递参数的对应关系如下图所示

# 图表类型 Widget

所有的仪表盘图表,均使用 antd chart (opens new window) 图表库进行渲染, 但当前只支持部分的图表类型,具体支持列表请参考上述表格。

图表 Widget 被渲染时,会将 Widget 定义中的 Options 字段中, key 为 config 的部分与 Core Logic 中返回的 Map 的最顶层 key 进行合并,将合并结果直接作为参数传递给 antd chart 的渲染控件。

兼容性提示

当前的 widget 渲染不支持 javascript 回调函数类型的渲染属性。

# 图表的坐标轴设定

对于包含坐标轴的图表类型,需要在 widget 的 Options 或者 core logic 的返回值中,包含 坐标轴的设定,否则有可能出现图表显示为空或者显示出错的情况。

  1. Options 字段中进行设定
// 设定 x 轴为 year, y 轴为 value
{"config": {"xField": "year", "yField": "value", "position": {"col": 8}}
1
2
  1. 在 core logic 中直接返回
return [
  xField: "时间",
  yField: "销售额"
  data: [...]
]
1
2
3
4
5

xFieldyField 为必传属性的图表列表如下:

  • 线图 Line chart
  • 面积图 Area chart
  • 柱形图 Column chart
  • 条形图 Bar chart

xField 为可选属性的图表列表如下:

  • 子弹图进度图 Bullet chart

# 图表的传值属性列表

按照 Antd chart 的 API, 设定图表中的显示数据的属性名称可能不尽相同, 下表列出了各图表的数据属性名称供参考, 具体属性的值格式请参考 antd chart 文档。

图表类型 数据属性名称
线图 Line chart data
面积图 Area chart data
柱形图 Column chart data
条形图 Bar chart data
饼图 Pie chart data
仪表盘进度图 Gauge percent
水滴图进度图 Liquid percent
迷你进度条 Progress chart percent
子弹图进度图 Bullet data
迷你进度环图 Ring progress chart percent
迷你面积图 Tiny area chart data
迷你折线图 Tiny line chart data
迷你柱形图 Tiny column chart data
对称条形图 Bi direction bar data
直方图 Histogram data

提示

传递值的属性在 core logic 运行的返回结果中是必须的,否则图表将无法显示。

兼容性提示

当前使用的 antd chart 版本为 1.0.11, 请注意在未来的版本中,antd chart 的 API 可能会有变化,如果上述属性失效,请参考各图表最新的 API 文档

# 注意事项

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

# Widget 显示的属性的优先级

系统在渲染 widget 控件时,会将 widget 的 core logic, Options 字段及前台渲染控件中 定义的默认属性进行合并,作为最终的控件渲染属性,如下列出了这三个属性来源的属性的优先级, 对于相同名称的属性,优先级高来源的值会覆盖优先级低来源的值。

* 最高:在 widget 的 core logic 中返回的显示属性
* 其次:在 widget 的 Options 字段中定义的显示属性
* 最低:各 widget 的 React 控件的默认显示属性 

# 最佳实践

# Markdown widget 中的换行

如果需要在渲染结果中,增加换行,可以在行后面增加两个空格,最终渲染出来的效果,会进行换行

# Widget 最小宽度

如果 widget 的宽度设定小于 4(Widget Options 中设定的宽度为1, 2 或3 {"position": {"col": 1 | 2 | 3}}), 那么有一定概率出现该 widget 与后面的 widget 显示有重叠的情况,因此建议在设计 widget 排版时,widget 的宽度 最小为 4 或以上(占据整体宽度的 1/6 以上)

# Options 字段格式特别说明

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

# 相关实现背景 开发

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

  • 仪表盘在系统中,是一种类型为 Dashboard 的表单(Form),与对象的 CRUD 及向导定义 的表单相同,都存放在 dynamic_form 数据库表中。
  • 仪表盘的元数据获取、渲染、数据获取等 API 均以 /dashboard/ 开头,具体可以参考 系统中的 swagger 页面
Last Updated: 2024/7/14 12:09:51