@huanban/rulego-editor-vue

RuleGo 编辑器 Vue 3 适配层 - 提供 Vue 组件和 Composables
5,776
Install
npm install @huanban/rulego-editor-vue
Latest Version:1.4.2
Vue:3
License:Apache-2.0
Last Updated:Sep 4, 2026
Links: npm
Maintainer: haunbanclaw

@huanban/rulego-editor-vue

RuleGo 编辑器 Vue 3 适配层 — 提供 Vue 组件和 Composables

npm version license

✨ 特性

  • 开箱即用 — 提供 <RuleGoEditor /> 组件,一行代码嵌入编辑器
  • Vue 3 Composables — useEditorCore、useEditorWorkspace、useEditorDock、useEditorPanels、useServerStatus、useConnectionStatus、useEditorTheme、useEditorI18n
  • 事件监听 — 支持 @node-click、@ready、@change 等 Vue 事件;保存观察使用 @save,保存接管通过 options.saveMode + saveHandler
  • 完整内置 UI — 工具栏、侧边栏、属性抽屉、设置、AI 助理、运行调试由 core 统一提供
  • 大列表性能 — 组件侧栏对超大分类使用固定行高虚拟窗口,搜索和拖拽行为保持不变
  • 独立管理组件 — WorkflowList / WorkflowInfoPanel 可组合出列表、详情和编辑器联动页面
  • 独立 AI 对话组件 — CopilotChat 可单独引用,支持流式响应、停止、思考过程和宿主持久化
  • 响应式状态 — 所有状态自动转为 Vue ref,模板中直接使用
  • TypeScript — 完整类型定义
  • 兼容 Vue 3.2+ — 支持 Composition API

📦 安装

npm install @huanban/rulego-editor-vue

@huanban/rulego-editor-core 和 @huanban/rulego-editor-ui 是 Vue 包的正式运行依赖, 包管理器会自动安装。只有直接使用它们的独立 API 时才需要在宿主清单中显式声明。

🚀 快速开始

方式一:使用 <RuleGoEditor /> 组件

<template>
  <RuleGoEditor
    height="100vh"
    :data="ruleChainData"
    :components="components"
    :options="editorOptions"
    @node-click="onNodeClick"
    @change="onChange"
  />
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { RuleGoEditor } from '@huanban/rulego-editor-vue'
import '@huanban/rulego-editor-vue/style.css'

const apiBase = ref('http://127.0.0.1:9090/api/v1')
const ruleChainData = ref<any>(null)
const components = ref<any[]>([])

const editorOptions = computed(() => ({
  apiBase: apiBase.value,
  showToolbar: true,
  showSidebar: true,
  showSettingsButton: true,
  showAiChatButton: true,
  showRunButton: true,
}))

const onNodeClick = (node) => console.log('点击节点:', node)
const onChange = () => console.log('画布已变更')
</script>

独立 CopilotChat

CopilotChat 不依赖 <RuleGoEditor />,可以放在宿主自己的右侧 AI 面板或业务页面中。 默认只保留内存会话;需要刷新恢复时显式传入宿主管理的 persistence:

<CopilotChat
  rule-chain-id="orders"
  :api-base="apiBase"
  model="gpt-5.4-mini"
  :fetch-headers="() => ({ Authorization: `Bearer ${token}` })"
  :persistence="{
    adapter: {
      getItem: key => localStorage.getItem(key),
      setItem: (key, value) => localStorage.setItem(key, value),
      removeItem: key => localStorage.removeItem(key),
    },
    namespace: { host: 'orders-app', editorInstance: 'customer-copilot', version: 'v1' },
  }"
/>

持久化 key 按 host/editorInstance/version/chainId/component 隔离;不传 persistence 时组件仍调用宿主提供的真实 OpenAI 兼容接口,但刷新后不恢复历史。

方式二:使用 useEditorCore Composable

<template>
  <div ref="editorRef" style="height: 100%"></div>
</template>

<script setup lang="ts">
import { useEditorCore } from '@huanban/rulego-editor-vue'

const { core, isReady, loadData, save } = useEditorCore()

watch(isReady, (ready) => {
  if (ready) {
    loadData(myRuleChainData)
  }
})
</script>

📖 API

<RuleGoEditor /> Props

属性 类型 说明
data RuleChainData | null 规则链数据
components RawComponentData 组件列表,可不传;有 options.apiBase 时会自动请求 /components
options Partial<HuanbanRulegoEditorOptions> 透传 core 配置,如 apiBase/fetchHeaders/onSettingsSubmit/onLoginClick
enableConnectionStatus boolean 开启真实规则链节点、endpoint 和共享节点连接状态轮询,默认关闭
height string | number 编辑器高度,默认 100%
width string | number 编辑器宽度,默认 100%
theme string 主题名称
className string 自定义 class
customStyle Record<string,string | number> 自定义内联样式
renderNode (type, data, model) => VNode 自定义 Headless 节点渲染

事件

事件 参数 说明
@save SaveEventData 兼容事件;默认保存不依赖它,接管保存请使用 options.onSave
@node-click NodeData 节点点击时触发
@ready — 编辑器就绪时触发
@change — 画布数据变化
@edge-click EdgeData 连线点击
@deploy chainId, action 部署/下线;后端动作严格对应 start/stop
@restart chainId 重启;与 operate 分离,内置流程读取服务端 DSL 后原样保存
@connection-status-change ConnectionStatusState 当前 Core 节点/共享节点连接状态变化,不增加轮询

在 options.showRestartButton=true 时显示重启入口。重启会重建节点实例,内存会话、 计数器、定时器等瞬态状态会重置,端点连接可能短暂重连。宿主使用 options.onRestart 接管时也必须执行 GET /rules/:id 后原样 POST /rules/:id,不得调用 operate/reload。 options.showReloadButton 只作为弃用兼容别名保留。

enableConnectionStatus 默认关闭。开启后,编辑器实例按当前规则链串行请求 GET {apiBase}/rules/:id/status,共享节点管理面板打开期间按引用请求 GET {apiBase}/shared-node-statuses。Vue 适配层不会额外创建轮询器;可通过组件 ref 暴露的 方法控制同一个 standalone 实例:

editorRef.value?.refreshConnectionStatuses()
const release = editorRef.value?.acquireSharedConnectionStatuses()
// 关闭共享节点管理面板时释放本次引用。
release?.()

宿主需要在自定义 UI 中响应式展示状态时,主组件直接监听变更事件:

<RuleGoEditor
  ref="editorRef"
  :enable-connection-status="true"
  @connection-status-change="connectionState = $event"
/>

自定义组合层已经持有 ConnectionStatusStore 时,可使用 useConnectionStatus({ connectionStatus: hostStore }) 订阅同一个 store。composable 不创建请求; 未传 store 时只返回空状态。

状态接口返回 401/403 时会暂停对应轮询并交给宿主认证流程,404/501 表示后端未提供能力 并停止探测,网络错误只标记状态可能已过期,不会伪造在线状态。连接状态是运行时展示数据, 不会写入 LogicFlow history、节点复制结果、DSL 导出或保存 payload。

命令式加载与工作区 Tab

组件 ref 暴露的命令式 API 会复用当前 HuanbanRulegoEditor,不会因为加载或切换 Tab 重建 LogicFlow:

<script setup lang="ts">
import { ref } from 'vue'
import {
  RuleGoEditor,
  type RuleGoEditorRef,
} from '@huanban/rulego-editor-vue'

const editorRef = ref<RuleGoEditorRef | null>(null)

function loadRemote(remoteChain: any) {
  // 新远程数据或导入数据:建立新的已保存基线。
  editorRef.value?.loadData(remoteChain)
}

function restoreDraft(tabDraft: any) {
  // 恢复当前 Tab 草稿:保留 savedData、dirty 标记和 JSON diff。
  editorRef.value?.loadData(tabDraft, { preserveWorkspaceTab: true })
}

function activateTab(tabId: string) {
  // Tab 不存在时返回 false。
  return editorRef.value?.activateWorkspaceTab(tabId) ?? false
}
</script>

<template>
  <RuleGoEditor ref="editorRef" :options="editorOptions" :data="ruleChainData" />
</template>

preserveWorkspaceTab 只用于恢复当前已有 Tab 的草稿。首次加载、新建远程规则链或 导入 clean 快照时不要开启。确实需要同时打开同一 chainId 的多个工作副本时,显式 传 { allowDuplicateWorkspaceTab: true }。

自定义工作台隐藏内置工具栏时,可以直接打开组件管理的指定页签:

editorRef.value?.openComponentManager('shared')

页签类型为 ComponentManageDialogTab,可选 installed / market / dsl / shared。设置 options.onComponentManage 接管弹窗时,component-manage 事件和宿主回调都会 收到同一个初始页签;未接管时使用 Core 内置管理器,不会在 Vue 层创建第二套请求或状态轮询。

保存协议

默认不要传 options.onSave。只要在 options.apiBase 配置后台地址,保存按钮会直接调用:

POST {apiBase}/rules/:id
GET  {apiBase}/rules/:id

第二次 GET 用于回读校验,只有后端返回的数据与当前画布一致时才会显示已保存。

只有宿主确实要完全接管保存时才在 options 中设置 saveMode: 'host' 并传 saveHandler。执行器必须返回明确结果:

const editorOptions = computed(() => ({
  apiBase: apiBase.value,
  saveMode: 'host' as const,
  saveHandler: async (data: any) => {
    const id = data?.ruleChain?.id
    const response = await fetch(`${apiBase.value}/rules/${encodeURIComponent(id)}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', ...fetchHeaders() },
      body: JSON.stringify(data),
    })
    return response.ok ? { success: true } : { success: false, message: `HTTP ${response.status}` }
  },
}))

单纯监听 @save 只观察保存请求,不会短路内置保存。不要在 @save 中再次 POST, 否则会和内置保存重复。旧版 options.onSave 仍兼容宿主执行器,但新接入应使用明确的 saveMode + saveHandler 合同。

<WorkflowList /> 管理列表

WorkflowList 是独立管理组件,不是编辑器。它负责查询、搜索、创建、部署/下线、复制、删除和选择规则链;进入画布编辑需要通过 :on-design 切换到 <RuleGoEditor />。

工作流列表的内置请求层支持宿主管理的认证和服务状态:

<WorkflowList
  :api-base="apiBase"
  :api-options="{
    headers: () => ({ Authorization: `Bearer ${readToken()}` }),
    credentials: 'include',
    onAuthRequired: ({ status }) => host.openLogin({ reason: status }),
    serverStatus,
  }"
  :on-error="showRequestError"
/>

默认兼容浏览器 token/access_token;纯 Cookie 接入设置 includeStoredToken: false。HTTP 401 表示凭据缺失或失效,宿主应打开登录流程并清理失效凭据; HTTP 403 表示凭据有效但权限不足,保留当前凭据并显示权限提示;网络失败和超时会通过 :on-error 暴露为离线或请求失败,不能被当成空列表。Vue 只会替换列表请求层,不会因为认证配置变化重建编辑器画布。

结构性配置与重建边界

lfOptions、lfPlugins 和 persistence 在编辑器实例创建时绑定,属于结构性配置。 它们不会被普通 prop 更新热替换;updateOptions() 返回的 structuralKeys 会明确列出这类变更。 宿主应先保存或处理 dirty 状态,再改变 Vue 的原生 key,让组件完整销毁并重建:

<RuleGoEditor
  :key="`${editorInstanceId}:${structuralConfigVersion}`"
  :options="{ lfOptions, lfPlugins, persistence }"
  :data="chainData"
/>

不要用每次 render 都新建的对象内容作为 key,否则会造成画布闪屏、焦点丢失和未保存数据风险。 普通 API、主题、语言、显示开关和回调仍走热更新,不应为了这些选项重建画布。React 和 standalone 使用同一边界契约。

<template>
  <section class="workspace">
    <WorkflowList
      :api-base="apiBase"
      layout="grid"
      :on-info="workflow => selectedWorkflow = workflow"
      :on-design="openEditor"
    />
    <WorkflowInfoPanel
      :api-base="apiBase"
      :workflow="selectedWorkflow"
    />
  </section>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { WorkflowInfoPanel, WorkflowList } from '@huanban/rulego-editor-vue'

const apiBase = 'http://127.0.0.1:9090/api/v1'
const selectedWorkflow = ref<any>(null)

async function openEditor(id: string) {
  const response = await fetch(`${apiBase}/rules/${encodeURIComponent(id)}`)
  const chainData = await response.json()
  console.log('switch to editor with', chainData)
}
</script>

常用属性:

属性 说明
layout 默认 grid 卡片布局;传 list 使用紧凑列表
autoOpenAfterCreate 传了 onDesign 时默认开启;新建成功后自动进入编辑器
onDesign 双击卡片或点击菜单“设计”时触发,宿主在这里打开编辑器
onInfo 单击卡片或点击菜单“信息”时触发,宿主在这里联动详情
onViewLogs 点击“日志”时触发,参数为 (chainId, workflow?);第二个参数是当前列表接口返回的真实工作流对象

默认新建弹窗包含 ID、名称、主链/子链、初始状态、调试模式、分类、描述。ID 自动生成,也可手动输入;为兼容后台路由,ID 不能包含 /、\ 或 .。

WorkflowInfoPanel 默认只显示基础信息、输入定义、变量和应用集成。维护验证是扩展能力,不是默认工作流详情的一部分;只有宿主后端已经实现 validate-upstream、schema-diff、repair-plan、patch-preview 这组分析接口时才开启:

<WorkflowInfoPanel
  :api-base="apiBase"
  :workflow="selectedWorkflow"
  show-maintenance
/>

如果后台没有这些接口,保持默认关闭,避免用户点击后出现 404 Not Found。

服务地址、设置和登录

Vue 版通过 :options 传入后台地址、认证和设置回调:

const editorOptions = computed(() => ({
  apiBase: apiBase.value,
  allowedApiOrigins: [new URL(apiBase.value, window.location.origin).origin],
  showSettingsButton: true,
  fetchHeaders: () => {
    const token = localStorage.getItem('token') || localStorage.getItem('access_token')
    return token ? { Authorization: `Bearer ${token}` } : {}
  },
  onSettingsSubmit: ({ apiBase: nextApiBase }: { apiBase: string }) => {
    localStorage.setItem('huanban_rulego_api_base', nextApiBase)
    apiBase.value = nextApiBase
  },
  onLoginClick: () => window.dispatchEvent(new CustomEvent('open-login')),
  onAuthExpired: () => window.dispatchEvent(new CustomEvent('open-login')),
  clearToken: () => {
    localStorage.removeItem('token')
    localStorage.removeItem('access_token')
    localStorage.removeItem('username')
  },
}))

如果不传 onLoginClick,内置设置页会打开默认登录弹窗,并请求 POST {apiBase}/login。完整新项目接入说明见根目录 docs/CLIENT_INTEGRATION.md。

useEditorCore(options?) 返回值

属性 类型 说明
core EditorCore 编辑器核心实例
isReady Ref<boolean> 编辑器是否就绪
isDirty Ref<boolean> 数据是否已修改
loadData (data) => void 加载规则链数据
save () => void 触发保存
on (event, handler) => void 监听事件

工作区、Dock 和服务状态 Composables

需要自己搭建工作台时,使用这些 composable。它们只负责 Vue 响应式桥接,Tab、dirty 草稿、关闭确认、尺寸限制和 401/1006 状态都由 editor-core 统一管理。

import {
  useEditorWorkspace,
  useEditorDock,
  useServerStatus,
  useConnectionStatus,
} from '@huanban/rulego-editor-vue'

const { tabs, activeTab, openTab, closeTab } = useEditorWorkspace()
const { state: dockState, setDockWidth } = useEditorDock()
const { state: serverState, recordHttpStatus, recordWebSocketStatus } = useServerStatus({
  baseUrl: 'http://127.0.0.1:19806',
})
// 已持有主编辑器的 Core store 时使用;这里只订阅,不创建轮询。
const { state: connectionState } = useConnectionStatus({ connectionStatus: hostConnectionStatus })

独立工作区 Tab

需要自己组合多规则链工作台时,可以使用 WorkspaceTabs。它只负责渲染 EditorWorkspace 状态,保存、关闭确认和后端请求仍由宿主处理:

<script setup lang="ts">
import { WorkspaceTabs, useEditorWorkspace } from '@huanban/rulego-editor-vue'
import '@huanban/rulego-editor-vue/style.css'

const workspace = useEditorWorkspace()
</script>

<template>
  <WorkspaceTabs
    :tabs="workspace.tabs.value"
    :active-tab-id="workspace.activeTab.value?.id"
    @activate="workspace.activateTab"
    @close="workspace.closeTab"
    @add="() => workspace.openTab({ title: '新规则链' })"
    @edit-info="openRuleChainInfo"
    :on-tab-action="(tabId, action) => {
      if (action === 'rename') openRuleChainInfo(tabId)
      if (action === 'run-history') openRunHistory(tabId)
      if (action === 'debug') openDebugPanel(tabId)
      if (action === 'toggle-disabled') toggleChainDisabled(tabId)
    }"
  />
</template>

Tab 组件会显示主链/子链、加载状态、未保存标记和溢出选择菜单,不会重新创建 画布,也不会绕过宿主的保存和权限策略。组件同时发出 tab-action 事件,稳定动作 ID 为 rename、toggle-disabled、run-history、debug;动作对应的真实保存、 start/stop 请求、登录和错误反馈仍由宿主处理。

serverState.value.api 与 serverState.value.ws 独立更新。收到 401/403 时展示登录 入口,收到 WS 1006 时展示实时连接断开和重连入口,不会把两种问题混成同一个状态。

独立状态栏与连接状态

需要自己组合编辑器外壳时,可以复用 EditorStatusBar 和 EditorConnectionStatus。组件只消费宿主传入的 LogicFlow/Core 状态,不自行请求、 重连或登录;服务端动作由宿主回调接管:

<EditorConnectionStatus
  :state="serverState"
  :on-login="openLogin"
  :on-retry="checkConnection"
/>
<EditorStatusBar
  :lf="editorRef?.lf"
  :problem-count="problems.length"
  :on-open-diagnostics="openDiagnostics"
  @open-diagnostics="openDiagnostics"
/>

EditorConnectionStatus 分别显示 API 与 WS 状态,EditorStatusBar 提供缩放、节点 数、边数、选中数和诊断入口。未传 on-login/on-retry 时,Vue 组件会发出对应事件, 方便宿主接入自己的认证和重试流程。

独立 Dock 面板

EditorPanelDock 只渲染 EditorPanelRegistry / EditorDockStore 的状态,支持左侧 堆叠、右侧/底部/AI Tab、关闭和拖动尺寸;面板内容通过命名 slot 提供:

<EditorPanelDock
  dock="right"
  :dock-state="dockState"
  :panel-state="panelsState"
  @activate-panel="panels.activatePanel"
  @close-panel="panels.closePanel"
  @toggle-dock="(_, visible) => dock.setDockVisibility('right', visible)"
  :on-resize="(id, size) => dock.setDockWidth(id, size)"
>
  <template #panel-info><InfoPanel /></template>
  <template #panel-node-config><NodeConfigPanel /></template>
</EditorPanelDock>

组件不自行保存、请求或创建面板状态;Vue 宿主可以继续使用自己的设置、AI、登录和 客服测试页面,而不会把场景模块混入编辑器包。

节点与连线悬浮工具

EditorNodeHoverTools 和 EditorEdgeHoverTools 接收宿主计算的目标 ID 与画布坐标, 负责统一渲染编辑、复制、执行、插入和删除按钮,并通过回调或 action 事件转发:

<EditorNodeHoverTools
  :target-id="selectedNode.id"
  :x="toolbarPosition.x"
  :y="toolbarPosition.y"
  :on-edit="openNodeEditor"
  :on-delete="confirmDeleteNode"
  :on-run-from="openRunPanel"
/>
<EditorEdgeHoverTools
  :target-id="selectedEdge.id"
  :x="edgePosition.x"
  :y="edgePosition.y"
  :on-insert-node="insertNodeOnEdge"
  :on-delete="confirmDeleteEdge"
/>

删除动作只通知宿主,不直接修改画布;二次确认、权限和保存仍由 Core/宿主处理。所有 按钮都带有 title 与 aria-label,flip-down 可用于靠近画布顶部的工具条。

EditorEdgeHoverTools 的 onInsertNode 参数是连线 ID。宿主应调用主编辑器的 openNodePicker({ edgeId, excludeInputNodes: true }),由 Core 统一完成 source -> new -> target 替换和失败回滚,不能把该 ID 当作节点 ID 直接追加边。

🔗 相关包

📄 协议

Apache-2.0

Related Packages

@vt7/vue2-composables

Vue2 composables

523 1
@shopware/composables

Shopware Frontends composables for Vue

141,216 230
@tb-dev/vue

Vue utilities

12,617
@alis-build/vue-ideate

Vue 3 composables and components to help integrate Alis Ideate into your product...

2,053 0
@oiij/auto-router

Vue Router utilities and composables for Vue 3

1,394 1

Version History

Version Released Vue License
1.4.2 >=3.2.0 <4 Apache-2.0
1.4.1 >=3.2.0 <4 Apache-2.0
1.4.0 >=3.2.0 <4 Apache-2.0
1.3.18 >=3.2.0 Apache-2.0
1.3.17 >=3.2.0 Apache-2.0