Designer
@easyink/designer 是面向开发者的文档/报表设计器框架。基于 Vue 3 + TypeScript,设计器与预览器分离,以组件形式嵌入宿主应用。内置画布编辑、物料拖放、数据绑定、撤销重做、自动保存等能力,开箱即用。
基本用法
vue
<script setup lang="ts">
import { ref } from 'vue'
import { EasyInkDesigner, createLocalStoragePreferenceProvider } from '@easyink/designer'
import { zhCN } from '@easyink/designer/locale'
import '@easyink/designer/index.css'
const schema = ref({})
const preferenceProvider = createLocalStoragePreferenceProvider()
</script>
<template>
<EasyInkDesigner
v-model:schema="schema"
:locale="zhCN"
:preference-provider="preferenceProvider"
/>
</template>组件 Props
| Prop | 类型 | 必填 | 说明 |
|---|---|---|---|
schema | DocumentSchemaInput | 否 | 文档模板输入,支持 v-model:schema 双向绑定;缺失字段会自动补默认值 |
dataSources | DataSourceDescriptor[] | 否 | 数据源描述符列表,定义可绑定的字段树 |
locale | LocaleMessages | 否 | 国际化消息,如 zhCN / enUS |
preferenceProvider | PreferenceProvider | 否 | 用户偏好持久化 provider |
autoSave | TemplateAutoSaveOptions | 否 | 自动保存配置 |
contributions | Contribution[] | 否 | 贡献扩展列表(如 AI 面板) |
setupStore | (store: DesignerStore) => void | 否 | Store 初始化回调,用于注册自定义物料 |
schema 是宿主输入,不要求传完整对象。传 undefined、{} 或只传部分字段时,设计器会在进入 DesignerStore 前归一化为完整 DocumentSchema,例如自动补齐 version、unit、page、guides 和 elements。update:schema、自动保存和 store 内部读到的始终是完整 Schema。
Slots
| Slot | 说明 |
|---|---|
#topbar | 自定义顶栏内容,通过 Teleport 挂载到顶栏区域 |
数据持久化
Designer 有两种独立的持久化机制,各管一件事:
自动保存 (autoSave) | 偏好持久化 (preferenceProvider) | |
|---|---|---|
| 存什么 | 模板内容(DocumentSchema) | 工作台偏好(窗口布局、缩放、吸附设置等) |
| 存到哪 | 宿主提供的 save 回调(通常是后端 API) | 默认 localStorage,也可自定义 |
| 用户感知 | 状态栏显示保存状态 | 无感,静默保存 |
| 是否进入 undo/redo | 是 | 否 |
两者互补:自动保存保证模板内容不丢失,偏好持久化保证用户的编辑环境设置不丢失。
自动保存
ts
const autoSaveOptions = {
enabled: true,
delay: 1000,
save: async (schemaSnapshot: DocumentSchema) => {
// schemaSnapshot 是当前 Schema 的快照
await saveToBackend(schemaSnapshot)
},
}自动保存的工作流程:
- 用户编辑触发 Schema 变化
- 经过
delay毫秒防抖后调用save回调 - 保存期间状态栏显示保存状态(保存中/已保存/保存失败)
详细配置(并发保护、动态启用、模板切换配合等)见 自动保存。
偏好持久化
通过 PreferenceProvider 接口保存和恢复用户的工作台偏好。这些偏好不进入 Schema,不影响 undo/redo。
持久化范围:窗口显隐/位置/尺寸、工具栏排列、面板开关、画布缩放、吸附设置。
ts
// 使用 localStorage 持久化
const preferenceProvider = createLocalStoragePreferenceProvider()也可以自定义持久化方式:
ts
const preferenceProvider = {
get: async (key: string) => {
// 从你的存储读取
},
set: async (key: string, value: unknown) => {
// 写入你的存储
},
}自定义物料
通过 setupStore 回调注册自定义物料。
ts
import { registerMaterialBundle } from '@easyink/designer'
function onSetupStore(store: DesignerStore) {
registerMaterialBundle(store, {
materials: [{
type: 'my-widget',
name: 'My Widget',
icon: 'widget',
category: 'basic',
capabilities: { resizable: true, bindable: true },
createDefaultNode: (input) => ({
id: generateId(),
type: 'my-widget',
x: 0, y: 0, width: 100, height: 50,
...input,
}),
factory: (ctx) => ({ /* DesignerExtension */ }),
}],
quickMaterialTypes: ['my-widget'],
groupedCatalog: [{ type: 'my-widget', group: 'utility' }],
})
}贡献扩展
通过 Contribution API 向设计器注入自定义面板、工具栏按钮和命令,无需修改设计器源码。
ts
import type { Contribution } from '@easyink/designer'
const myContribution: Contribution = {
id: 'my-plugin',
activate(ctx) {
// 注册自定义面板
ctx.registerPanel({
id: 'my-panel',
component: MyPanelComponent,
teleportTarget: '#ei-overlay-root',
})
// 注册工具栏按钮
ctx.registerToolbarAction({
id: 'my-action',
icon: MyIcon,
label: 'My Action',
onClick: () => { /* ... */ },
})
// 注册命令
ctx.registerCommand({
id: 'my-command',
handler: (args, ctx) => { /* ... */ },
})
// 清理回调
ctx.onDispose(() => { /* cleanup */ })
},
}vue
<EasyInkDesigner
v-model:schema="schema"
:contributions="[myContribution]"
/>Store 访问
在组件外部通过 useDesignerStore() 获取 Store 实例。
ts
import { useDesignerStore } from '@easyink/designer'
const store = useDesignerStore()
// 元素操作
store.addElement(node)
store.removeElement(id)
store.updateElement(id, { width: 200 })
// Schema 操作
store.setSchema(newSchema)
// 国际化
store.t('common.save')国际化
内置中英文语言包,也支持自定义。
ts
import { enUS, zhCN } from '@easyink/designer/locale'
// 使用内置中文
<EasyInkDesigner :locale="zhCN" />
// 使用内置英文
<EasyInkDesigner :locale="enUS" />
// 自定义语言包(结构参考 zhCN)
const myLocale = { /* ... */ }
<EasyInkDesigner :locale="myLocale" />CSS 引入
必须在入口文件中引入样式:
ts
import '@easyink/designer/index.css'