Skip to content

Commit 71f50bf

Browse files
committed
docs: add docs for dashboard widgets extension points
Signed-off-by: Ryan Wang <i@ryanc.cc>
1 parent 02c3d79 commit 71f50bf

File tree

3 files changed

+285
-0
lines changed

3 files changed

+285
-0
lines changed
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
---
2+
title: 仪表盘扩展点
3+
description: 扩展仪表盘小部件 - console:dashboard:widgets:create
4+
---
5+
6+
仪表盘扩展点允许插件为 Halo 的控制台仪表盘添加自定义小部件和快速操作项。通过这些扩展点,插件可以:
7+
8+
- 创建自定义的仪表盘小部件来展示特定数据或功能
9+
- 为快速操作小部件添加自定义操作项
10+
11+
![仪表盘扩展点](/img/developer-guide/plugin/extension-points/ui/dashboard-widgets.png)
12+
13+
## console:dashboard:widgets:create
14+
15+
此扩展点用于创建自定义的仪表盘小部件。
16+
17+
### 定义方式
18+
19+
```ts
20+
import { definePlugin } from "@halo-dev/console-shared";
21+
import { markRaw } from "vue";
22+
import MyCustomWidget from "./components/MyCustomWidget.vue";
23+
24+
export default definePlugin({
25+
extensionPoints: {
26+
"console:dashboard:widgets:create": () => {
27+
return [
28+
{
29+
id: "my-custom-widget",
30+
component: markRaw(MyCustomWidget),
31+
group: "my-plugin",
32+
configFormKitSchema: [
33+
{
34+
$formkit: "text",
35+
name: "title",
36+
label: "标题",
37+
value: "默认标题",
38+
},
39+
{
40+
$formkit: "number",
41+
name: "refresh_interval",
42+
label: "刷新间隔(秒)",
43+
value: 30,
44+
min: 10,
45+
},
46+
],
47+
defaultConfig: {
48+
title: "我的自定义小部件",
49+
refresh_interval: 30,
50+
},
51+
defaultSize: {
52+
w: 6,
53+
h: 8,
54+
minW: 3,
55+
minH: 4,
56+
maxW: 12,
57+
maxH: 16,
58+
},
59+
permissions: ["plugin:my-plugin:view"],
60+
},
61+
];
62+
},
63+
},
64+
});
65+
```
66+
67+
### DashboardWidgetDefinition 类型
68+
69+
```ts
70+
export interface DashboardWidgetDefinition {
71+
id: string; // 小部件唯一标识符
72+
component: Raw<Component>; // 小部件 Vue 组件
73+
group: string; // 小部件分组,用于在小部件库中分类显示
74+
configFormKitSchema?: Record<string, unknown>[]; // 配置表单 FormKit 定义
75+
defaultConfig?: Record<string, unknown>; // 默认配置
76+
defaultSize: { // 默认尺寸
77+
w: number; // 宽度(网格单位),根据不同屏幕尺寸,网格单位不同,可参考:{ lg: 12, md: 12, sm: 6, xs: 4 }
78+
h: number; // 高度(网格单位)
79+
minW?: number; // 最小宽度
80+
minH?: number; // 最小高度
81+
maxW?: number; // 最大宽度
82+
maxH?: number; // 最大高度
83+
};
84+
permissions?: string[]; // 访问权限
85+
}
86+
```
87+
88+
### 小部件组件开发
89+
90+
```html
91+
<template>
92+
<WidgetCard v-bind="$attrs" :body-class="['!p-0']">
93+
<template #title>
94+
<div class="inline-flex items-center gap-2">
95+
<div class="text-base font-medium flex-1">
96+
{{ config?.title || "默认标题" }}
97+
</div>
98+
<IconSettings
99+
v-if="editMode"
100+
class="hover:text-gray-600 cursor-pointer"
101+
@click="showConfigModal = true"
102+
/>
103+
</div>
104+
</template>
105+
106+
<!-- 小部件内容 -->
107+
<div class="p-4">
108+
<div v-if="previewMode" class="text-center text-gray-500">
109+
预览模式
110+
</div>
111+
<div v-else>
112+
<!-- 实际小部件内容 -->
113+
<p>刷新间隔:{{ config?.refresh_interval || 30 }}秒</p>
114+
</div>
115+
</div>
116+
</WidgetCard>
117+
</template>
118+
119+
<script lang="ts" setup>
120+
import { IconSettings } from "@halo-dev/components";
121+
import { ref } from "vue";
122+
123+
const props = defineProps<{
124+
editMode?: boolean; // 是否为编辑模式
125+
previewMode?: boolean; // 是否为预览模式
126+
config?: Record<string, unknown>; // 小部件配置
127+
}>();
128+
129+
const emit = defineEmits<{
130+
//
131+
(e: "update:config", config: Record<string, unknown>): void;
132+
}>();
133+
134+
</script>
135+
```
136+
137+
**小部件组件的属性与事件:**
138+
139+
| 属性 | 类型 | 说明 |
140+
|---------------|-------------------------|--------------|
141+
| `editMode` | boolean | 是否为编辑模式 |
142+
| `previewMode` | boolean | 是否为预览模式 |
143+
| `config` | Record\<string, unknown\> | 小部件配置 |
144+
145+
| 事件 | 说明 |
146+
|-----------------|------------------|
147+
| `update:config` | 小部件配置更新事件 |
148+
149+
**WidgetCard 组件的属性与插槽:**
150+
151+
| 属性 | 类型 | 说明 |
152+
|---------------|-------------------------|--------------|
153+
| `title` | string | 小部件标题 |
154+
| `bodyClass` | string[] | 小部件内容区域样式 |
155+
156+
| 插槽 | 说明 |
157+
|-----------|------------|
158+
| `title` | 小部件标题 |
159+
| `default` | 小部件内容 |
160+
| `actions` | 小部件操作项 |
161+
162+
**重要说明:**
163+
164+
- 小部件组件必须使用 `WidgetCard` 作为根组件,此组件已经在全局注册,不需要导入
165+
- 支持 `editMode``previewMode` 两种模式,当仪表盘处于编辑页面时,`editMode``true`,在小组件选择列表时,`previewMode``true`。可以根据这两个属性来控制小部件的显示内容
166+
- `update:config` 事件通常不需要实现,已经在内部实现了打开配置表单的功能,此事件用于自行实现配置表单
167+
- 使用 `markRaw()` 包装组件以避免响应式转换
168+
169+
## console:dashboard:widgets:internal:quick-action:item:create
170+
171+
此扩展点用于为快速操作小部件添加自定义操作项。
172+
173+
### 定义方式
174+
175+
```ts
176+
import { definePlugin } from "@halo-dev/console-shared";
177+
import { markRaw } from "vue";
178+
import { IconPlug } from "@halo-dev/components";
179+
import { useRouter } from "vue-router";
180+
181+
export default definePlugin({
182+
extensionPoints: {
183+
"console:dashboard:widgets:internal:quick-action:item:create": () => {
184+
return [
185+
{
186+
id: "my-plugin-action",
187+
icon: markRaw(IconPlug),
188+
title: "我的插件操作",
189+
action: () => {
190+
// do something
191+
},
192+
permissions: ["plugin:my-plugin:manage"],
193+
},
194+
];
195+
},
196+
},
197+
});
198+
```
199+
200+
### 自定义组件操作项
201+
202+
你也可以提供自定义组件而不是标准的操作项:
203+
204+
```ts
205+
import CustomActionItem from "./components/CustomActionItem.vue";
206+
207+
export default definePlugin({
208+
extensionPoints: {
209+
"console:dashboard:widgets:internal:quick-action:item:create": () => {
210+
return [
211+
{
212+
id: "custom-action",
213+
component: markRaw(CustomActionItem),
214+
permissions: ["plugin:my-plugin:view"],
215+
},
216+
];
217+
},
218+
},
219+
});
220+
```
221+
222+
自定义组件:
223+
224+
```html
225+
<template>
226+
<div class="group relative cursor-pointer rounded-lg bg-blue-50 p-4 transition-all hover:bg-blue-100">
227+
<div class="flex items-center gap-3">
228+
<component :is="item.icon" class="text-blue-600" />
229+
<div>
230+
<h3 class="text-sm font-semibold text-blue-900">
231+
{{ item.title }}
232+
</h3>
233+
<p class="text-xs text-blue-700">自定义操作描述</p>
234+
</div>
235+
</div>
236+
</div>
237+
</template>
238+
239+
<script lang="ts" setup>
240+
import type { DashboardWidgetQuickActionItem } from "@halo-dev/console-shared";
241+
242+
defineProps<{
243+
item: DashboardWidgetQuickActionItem;
244+
}>();
245+
</script>
246+
```
247+
248+
### DashboardWidgetQuickActionItem 类型
249+
250+
```ts
251+
interface DashboardWidgetQuickActionBaseItem {
252+
id: string; // 操作项唯一标识符
253+
permissions?: string[]; // 访问权限
254+
}
255+
256+
interface DashboardWidgetQuickActionComponentItem
257+
extends DashboardWidgetQuickActionBaseItem {
258+
component: Raw<Component>; // 自定义组件
259+
icon?: Raw<Component>; // 图标(可选)
260+
title?: string; // 标题(可选)
261+
action?: () => void; // 点击操作(可选)
262+
}
263+
264+
interface DashboardWidgetQuickActionStandardItem
265+
extends DashboardWidgetQuickActionBaseItem {
266+
component?: never; // 不使用自定义组件
267+
icon: Raw<Component>; // 图标(必需)
268+
title: string; // 标题(必需)
269+
action: () => void; // 点击操作(必需)
270+
}
271+
272+
export type DashboardWidgetQuickActionItem =
273+
| DashboardWidgetQuickActionComponentItem
274+
| DashboardWidgetQuickActionStandardItem;
275+
```
276+
277+
## 权限控制
278+
279+
两个扩展点都支持权限控制:
280+
281+
- **小部件权限**:通过 `permissions` 字段控制小部件的显示
282+
- **操作项权限**:通过 `permissions` 字段控制快速操作项的显示
283+
284+
权限检查会自动进行,用户只能看到有权限访问的小部件和操作项。

sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ module.exports = {
297297
"developer-guide/plugin/extension-points/ui/post-list-item-field-create",
298298
"developer-guide/plugin/extension-points/ui/user-detail-tabs-create",
299299
"developer-guide/plugin/extension-points/ui/uc-user-profile-tabs-create",
300+
"developer-guide/plugin/extension-points/ui/dashboard-widgets",
300301
],
301302
},
302303
],
333 KB
Loading

0 commit comments

Comments
 (0)