
Halo 仪表盘扩展点开发指南自定义小部件与快速操作项【免费下载链接】haloHalo 是一款强大易用的开源建站工具从个人博客、知识库到企业官网、在线商城Halo 都能助您轻松实现一站式满足您的多样化建站需求。项目地址: https://gitcode.com/GitHub_Trending/ha/halo仪表盘Dashboard是 Halo 控制台登录后的首屏也是站点运维中最常用的信息聚合与操作入口。本文以 仪表盘扩展点文档 为核心系统讲解 Halo 提供给插件开发者的两个仪表盘扩展点console:dashboard:widgets:create创建自定义小部件与console:dashboard:widgets:internal:quick-action:item:create为快速操作小部件添加自定义操作项。读完本文你将掌握小部件定义、组件开发、配置表单、权限控制以及快速操作项的完整开发流程并理解这些扩展点在前端源码中的真实消费方式。概述两个扩展点能做什么仪表盘扩展点允许插件为 Halo 的控制台仪表盘添加两类能力创建自定义的仪表盘小部件Widget用于在仪表盘上展示特定数据或功能例如文章统计、访问量曲线、待办提醒等为快速操作小部件添加自定义操作项Quick Action Item即在仪表盘内置的快速操作卡片中追加插件自己的快捷入口。这两个扩展点均通过插件模块Plugin Module的extensionPoints字段声明属于halo-dev/ui-shared提供的 UI 扩展点机制。扩展点消费端位于ui/console-src/modules/dashboard目录插件只需在definePlugin中注册对应回调函数控制台启动时便会自动收集并渲染。扩展点一console:dashboard:widgets:create此扩展点用于创建自定义的仪表盘小部件回调函数返回一个DashboardWidgetDefinition数组每个元素描述一个小部件的定义组件、分组、默认配置、尺寸约束与权限。定义方式在插件的definePlugin中声明扩展点import { definePlugin } from halo-dev/ui-shared; import { markRaw } from vue; import MyCustomWidget from ./components/MyCustomWidget.vue; export default definePlugin({ extensionPoints: { console:dashboard:widgets:create: () { return [ { id: my-custom-widget, component: markRaw(MyCustomWidget), group: my-plugin, configFormKitSchema: [ { $formkit: text, name: title, label: 标题, value: 默认标题, }, { $formkit: number, name: refresh_interval, label: 刷新间隔秒, value: 30, min: 10, }, ], defaultConfig: { title: 我的自定义小部件, refresh_interval: 30, }, defaultSize: { w: 6, h: 8, minW: 3, minH: 4, maxW: 12, maxH: 16, }, permissions: [plugin:my-plugin:view], }, ]; }, }, });代码要点component必须使用markRaw()包装见 ui/packages/shared/src/plugin/types/dashboard-widget.ts 的注释说明避免 Vue 将组件对象转换为响应式代理configFormKitSchema用于声明小部件的配置表单用户在设计器中点击设置按钮时自动生成表单并保存配置permissions传入的是权限标识如plugin:my-plugin:view不满足权限的用户将看不到该小部件。DashboardWidgetDefinition 类型全解DashboardWidgetDefinition的完整定义位于 ui/packages/shared/src/plugin/types/dashboard-widget.ts字段说明如下字段类型必填说明idstring是小部件唯一标识符推荐使用命名空间风格如plugin-name:widget-idcomponentRawComponent是渲染小部件的 Vue 组件须用markRaw包装groupstring是小部件分组用于在小部件库Widget Hub中按分组展示常见分组如statistics、content、systemconfigFormKitSchema数组 / 同步函数 / 异步函数否配置表单的 FormKit schema支持Recordstring, unknown[]、() Recordstring, unknown[]与() PromiseRecordstring, unknown[]三种形态异步函数可用于动态加载选项defaultConfigRecordstring, unknown否新小部件实例的默认配置用户首次添加小部件时写入defaultSize{ w, h, minW?, minH?, maxW?, maxH? }是默认尺寸与约束网格单位permissionsstring[]否查看/添加该小部件所需的权限标识关于defaultSize的网格单位仪表盘采用 12 列网格布局见 Dashboard.vue 中的:cols{ lg: 12, md: 12, sm: 6, xs: 4 }即在大屏上每行最多 12 个网格单位。同一网格单位在不同屏幕尺寸下对应的实际宽度不同可参考{ lg: 12, md: 12, sm: 6, xs: 4 }的列数配置来估算小部件在不同断点下的展示宽度。小部件组件开发小部件组件是普通 Vue 组件但有以下约定必须使用全局注册的WidgetCard作为根组件无需手动 import并接收editMode、previewMode、config三个属性。WidgetCard的实现见 WidgetCard.vue它提供统一的卡片外壳标题栏 内容区。一个完整的小部件组件示例template WidgetCard v-bind$attrs :body-class[!p-0] template #title div classinline-flex items-center gap-2 div classtext-base font-medium flex-1 {{ config?.title || 默认标题 }} /div IconSettings v-ifeditMode classhover:text-gray-600 cursor-pointer clickshowConfigModal true / /div /template !-- 小部件内容 -- div classp-4 div v-ifpreviewMode classtext-center text-gray-500 预览模式 /div div v-else !-- 实际小部件内容 -- p刷新间隔{{ config?.refresh_interval || 30 }}秒/p /div /div /WidgetCard /template script langts setup import { IconSettings } from halo-dev/components; import { ref } from vue; const props defineProps{ editMode?: boolean; // 是否为编辑模式 previewMode?: boolean; // 是否为预览模式 config?: Recordstring, unknown; // 小部件配置 }(); const emit defineEmits{ // (e: update:config, config: Recordstring, unknown): void; }(); /script小部件组件的属性与事件属性类型说明editModeboolean是否为编辑模式previewModeboolean是否为预览模式configRecordstring, unknown小部件配置事件说明update:config小部件配置更新事件WidgetCard 组件的属性与插槽属性类型说明titlestring小部件标题bodyClassstring[]小部件内容区域样式插槽说明title小部件标题default小部件内容actions小部件操作项重要说明小部件组件必须使用WidgetCard作为根组件此组件已经在全局注册不需要导入支持editMode和previewMode两种模式当仪表盘处于编辑页面DashboardDesigner时editMode为true在小部件选择列表Widget Hub中时previewMode为true。可根据这两个属性控制小部件的显示内容例如在预览模式下显示占位内容update:config事件通常不需要实现控制台内部已实现打开配置表单的功能此事件仅用于自行实现配置表单的场景使用markRaw()包装组件以避免响应式转换。源码侧扩展点如何被消费理解消费端的实现有助于开发者把握小部件从定义到展示的完整链路收集定义use-dashboard-extension-point.ts 在组件挂载后遍历pluginModuleMap逐个调用插件模块的console:dashboard:widgets:create回调将返回的定义收集起来。注意其中对id做了前缀处理definition.id ${name}-${definition.id}即以插件模块名为前缀重写 id避免多插件 id 冲突。合并内置小部件控制台自身也内置了若干小部件统计卡片、快速操作、通知等见 widgets/index.ts 与 defaults.ts。Dashboard.vue 与 DashboardDesigner.vue 中通过[...internalWidgetDefinitions, ...widgetDefinitions.value]合并内置与插件定义并通过provide(availableWidgetDefinitions, ...)注入给子组件。渲染与布局视图页 Dashboard.vue 使用grid-layout按用户偏好布局渲染小部件设计页 DashboardDesigner.vue 允许拖拽、缩放、添加、移除小部件并通过ucApiClient.user.preference.updateMyPreference({ group: dashboard-widgets, body: layouts.value })将布局保存到用户偏好中读取逻辑见 use-dashboard-widgets-fetch.ts查询键为core:dashboard:widgets。添加小部件在设计器中点击添加小部件会打开 WidgetHubModal.vue该弹窗按group分组展示所有可用小部件并按defaultSize.w × defaultSize.h尺寸预览点击某个小部件后DashboardDesigner.vue 的handleAddWidget会基于defaultSize、defaultConfig、permissions生成一个小部件实例i使用utils.id.uuid()生成唯一实例 idid指向定义 id。配置表单WidgetEditableItem.vue 在编辑模式下渲染小部件组件传入edit-mode与config当定义存在configFormKitSchema时显示设置按钮点击后打开 WidgetConfigFormModal.vue 按 schema 生成表单保存后通过update:config事件写回实例配置。扩展点二console:dashboard:widgets:internal:quick-action:item:create此扩展点用于为内置的快速操作小部件core:quick-action添加自定义操作项。快速操作小部件默认展示在新用户、新建文章、主题管理、插件管理等快捷入口见 defaults.ts 中的enabled_items配置。定义方式标准操作项import { definePlugin } from halo-dev/ui-shared; import { markRaw } from vue; import { IconPlug } from halo-dev/components; import { useRouter } from vue-router; export default definePlugin({ extensionPoints: { console:dashboard:widgets:internal:quick-action:item:create: () { return [ { id: my-plugin-action, icon: markRaw(IconPlug), title: 我的插件操作, action: () { // do something }, permissions: [plugin:my-plugin:manage], }, ]; }, }, });标准操作项由icon图标组件、title标题与action点击回调构成控制台会以统一样式渲染。自定义组件操作项当标准操作项的展示形式无法满足需求时可以提供一个自定义组件取代默认渲染import CustomActionItem from ./components/CustomActionItem.vue; export default definePlugin({ extensionPoints: { console:dashboard:widgets:internal:quick-action:item:create: () { return [ { id: custom-action, component: markRaw(CustomActionItem), permissions: [plugin:my-plugin:view], }, ]; }, }, });自定义组件接收itemDashboardWidgetQuickActionItem类型作为属性template div classgroup relative cursor-pointer rounded-lg bg-blue-50 p-4 transition-all hover:bg-blue-100 div classflex items-center gap-3 component :isitem.icon classtext-blue-600 / div h3 classtext-sm font-semibold text-blue-900 {{ item.title }} /h3 p classtext-xs text-blue-700自定义操作描述/p /div /div /div /template script langts setup import type { DashboardWidgetQuickActionItem } from halo-dev/ui-shared; defineProps{ item: DashboardWidgetQuickActionItem; }(); /scriptDashboardWidgetQuickActionItem 类型三种形态该类型定义在 ui/packages/shared/src/plugin/types/dashboard-widget.ts为联合类型包含三种形态interface DashboardWidgetQuickActionBaseItem { id: string; // 操作项唯一标识符 permissions?: string[]; // 访问权限 } interface DashboardWidgetQuickActionComponentItem extends DashboardWidgetQuickActionBaseItem { component: RawComponent; // 自定义组件 icon?: RawComponent; // 图标可选 title?: string; // 标题可选 action?: () void; // 点击操作可选 } interface DashboardWidgetQuickActionStandardItem extends DashboardWidgetQuickActionBaseItem { component?: never; // 不使用自定义组件 icon: RawComponent; // 图标必需 title: string; // 标题必需 action: () void; // 点击操作必需 } interface DashboardWidgetQuickActionRouteItem extends DashboardWidgetQuickActionBaseItem { component?: never; // 不使用自定义组件 action?: never; // 不使用 action 回调 icon: RawComponent; // 图标组件必需 title: string; // 标题文本必需 route: RouteLocationRaw; // 导航目标路由必需可以是路由名称、路径或完整路由配置 } export type DashboardWidgetQuickActionItem | DashboardWidgetQuickActionComponentItem | DashboardWidgetQuickActionStandardItem | DashboardWidgetQuickActionRouteItem;三种形态的适用场景形态关键字段适用场景StandardItemicontitleaction均必填简单的点击操作如打开弹窗、执行某个动作RouteItemicontitleroute需要跳转到控制台某个路由的操作项route可为路由名称、路径字符串或完整路由配置ComponentItemcomponent必填其余可选需要完全自定义操作项 UI 与交互的场景提供最大灵活性源码侧快速操作项如何被消费快速操作扩展点的消费逻辑位于 widgets/presets/core/quick-action/composables/use-dashboard-extension-point.ts与第一个扩展点完全对称挂载后遍历插件模块收集console:dashboard:widgets:internal:quick-action:item:create回调的返回值并以插件模块名为前缀重写id。收集到的操作项会与内置操作项定义在 QuickActionWidget.vue 的presetItems中合并展示其中标准操作项由 QuickActionItem.vue 统一渲染自定义组件操作项则直接渲染对应组件。权限控制两个扩展点都支持权限控制小部件权限通过DashboardWidgetDefinition.permissions字段控制小部件的显示操作项权限通过DashboardWidgetQuickActionItem.permissions字段控制快速操作项的显示。权限检查会自动进行用户只能看到有权限访问的小部件和操作项。源码侧有两处校验WidgetHubModal.vue 在展示小部件库时调用utils.permission.has(item.permissions || [])过滤无权小部件WidgetEditableItem.vue 在渲染每个小部件实例前同样执行utils.permission.has(item.permissions || [])校验。因此插件在定义小部件或操作项时应传入合适的权限标识如plugin:my-plugin:view、plugin:my-plugin:manage确保权限体系生效。布局、断点与用户偏好持久化理解仪表盘的网格布局机制有助于为插件小部件设置合理的defaultSize仪表盘基于vue-grid-layout实现响应式网格总列数按断点变化lg: 12, md: 12, sm: 6, xs: 4断点阈值为lg: 1200, md: 996, sm: 768, xs: 480见 Dashboard.vue每个用户的小部件布局位置、尺寸、配置、启用的操作项以用户偏好的形式持久化存储 group 为dashboard-widgets通过用户中心 API 读写保存逻辑见 DashboardDesigner.vue 的handleSave若用户尚无偏好数据控制台使用 defaults.ts 中的DefaultResponsiveLayouts作为默认布局。因此插件小部件的defaultSize.w建议不超过 12大屏列数上限并同时给出minW/minH约束避免在窄屏断点上布局异常。相关源码路径汇总扩展点类型定义ui/packages/shared/src/plugin/types/dashboard-widget.ts小部件扩展点消费逻辑ui/console-src/modules/dashboard/composables/use-dashboard-extension-point.ts快速操作扩展点消费逻辑ui/console-src/modules/dashboard/widgets/presets/core/quick-action/composables/use-dashboard-extension-point.ts仪表盘视图页ui/console-src/modules/dashboard/Dashboard.vue仪表盘设计页ui/console-src/modules/dashboard/DashboardDesigner.vue小部件外壳组件ui/console-src/modules/dashboard/components/WidgetCard.vue小部件库弹窗ui/console-src/modules/dashboard/components/WidgetHubModal.vue可编辑小部件项ui/console-src/modules/dashboard/components/WidgetEditableItem.vue默认布局ui/console-src/modules/dashboard/widgets/defaults.ts布局读取逻辑ui/console-src/modules/dashboard/composables/use-dashboard-widgets-fetch.ts【免费下载链接】haloHalo 是一款强大易用的开源建站工具从个人博客、知识库到企业官网、在线商城Halo 都能助您轻松实现一站式满足您的多样化建站需求。项目地址: https://gitcode.com/GitHub_Trending/ha/halo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考