mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-09-03 22:39:52 +08:00
style(editor): 完善service use-plugin的ts类型定义
This commit is contained in:
parent
5cf137e5e8
commit
16e45cb45d
@ -84,6 +84,7 @@
|
|||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
"tsc-alias": "^1.8.5",
|
"tsc-alias": "^1.8.5",
|
||||||
|
"type-fest": "^4.10.3",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
"vite": "^5.0.7",
|
"vite": "^5.0.7",
|
||||||
"vue-tsc": "^1.8.25"
|
"vue-tsc": "^1.8.25"
|
||||||
|
@ -194,6 +194,9 @@ export default class extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 请使用usePlugin代替
|
||||||
|
*/
|
||||||
public use(options: Record<string, Function>) {
|
public use(options: Record<string, Function>) {
|
||||||
Object.entries(options).forEach(([methodName, method]: [string, Function]) => {
|
Object.entries(options).forEach(([methodName, method]: [string, Function]) => {
|
||||||
if (typeof method === 'function') this.middleware[methodName].push(method);
|
if (typeof method === 'function') this.middleware[methodName].push(method);
|
||||||
|
@ -18,16 +18,24 @@
|
|||||||
|
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { keys, pick } from 'lodash-es';
|
import { keys, pick } from 'lodash-es';
|
||||||
|
import type { Writable } from 'type-fest';
|
||||||
|
|
||||||
import type { ColumnConfig } from '@tmagic/form';
|
import type { ColumnConfig } from '@tmagic/form';
|
||||||
import type { CodeBlockContent, CodeBlockDSL, Id } from '@tmagic/schema';
|
import type { CodeBlockContent, CodeBlockDSL, Id } from '@tmagic/schema';
|
||||||
|
|
||||||
import type { CodeState } from '@editor/type';
|
import type { AsyncHookPlugin, CodeState } from '@editor/type';
|
||||||
import { CODE_DRAFT_STORAGE_KEY } from '@editor/type';
|
import { CODE_DRAFT_STORAGE_KEY } from '@editor/type';
|
||||||
import { getConfig } from '@editor/utils/config';
|
import { getConfig } from '@editor/utils/config';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: ['setCodeDslById', 'setEditStatus', 'setCombineIds', 'setUndeleteableList', 'deleteCodeDslByIds'] as const,
|
||||||
|
sync: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
|
||||||
|
|
||||||
class CodeBlock extends BaseService {
|
class CodeBlock extends BaseService {
|
||||||
private state = reactive<CodeState>({
|
private state = reactive<CodeState>({
|
||||||
codeDsl: null,
|
codeDsl: null,
|
||||||
@ -38,13 +46,7 @@ class CodeBlock extends BaseService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super(canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true })));
|
||||||
{ name: 'setCodeDslById', isAsync: true },
|
|
||||||
{ name: 'setEditStatus', isAsync: true },
|
|
||||||
{ name: 'setCombineIds', isAsync: true },
|
|
||||||
{ name: 'setUndeleteableList', isAsync: true },
|
|
||||||
{ name: 'deleteCodeDslByIds', isAsync: true },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -243,6 +245,10 @@ class CodeBlock extends BaseService {
|
|||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
this.removeAllPlugins();
|
this.removeAllPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public usePlugin(options: AsyncHookPlugin<AsyncMethodName, CodeBlock>): void {
|
||||||
|
super.usePlugin(options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CodeBlockService = CodeBlock;
|
export type CodeBlockService = CodeBlock;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { Writable } from 'type-fest';
|
||||||
|
|
||||||
import type { EventOption } from '@tmagic/core';
|
import type { EventOption } from '@tmagic/core';
|
||||||
import type { FormConfig } from '@tmagic/form';
|
import type { FormConfig } from '@tmagic/form';
|
||||||
import type { DataSourceSchema } from '@tmagic/schema';
|
import type { DataSourceSchema } from '@tmagic/schema';
|
||||||
import { guid } from '@tmagic/utils';
|
import { guid } from '@tmagic/utils';
|
||||||
|
|
||||||
import type { DatasourceTypeOption } from '@editor/type';
|
import type { DatasourceTypeOption, SyncHookPlugin } from '@editor/type';
|
||||||
import { getFormConfig, getFormValue } from '@editor/utils/data-source';
|
import { getFormConfig, getFormValue } from '@editor/utils/data-source';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
@ -22,6 +23,27 @@ interface State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type StateKey = keyof State;
|
type StateKey = keyof State;
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: [],
|
||||||
|
sync: [
|
||||||
|
'getFormConfig',
|
||||||
|
'setFormConfig',
|
||||||
|
'getFormValue',
|
||||||
|
'setFormValue',
|
||||||
|
'getFormEvent',
|
||||||
|
'setFormEvent',
|
||||||
|
'getFormMethod',
|
||||||
|
'setFormMethod',
|
||||||
|
'add',
|
||||||
|
'update',
|
||||||
|
'remove',
|
||||||
|
'createId',
|
||||||
|
] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
|
||||||
|
|
||||||
class DataSource extends BaseService {
|
class DataSource extends BaseService {
|
||||||
private state = reactive<State>({
|
private state = reactive<State>({
|
||||||
datasourceTypeList: [],
|
datasourceTypeList: [],
|
||||||
@ -34,20 +56,7 @@ class DataSource extends BaseService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super(canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false })));
|
||||||
{ name: 'getFormConfig', isAsync: false },
|
|
||||||
{ name: 'setFormConfig', isAsync: false },
|
|
||||||
{ name: 'getFormValue', isAsync: false },
|
|
||||||
{ name: 'setFormValue', isAsync: false },
|
|
||||||
{ name: 'getFormEvent', isAsync: false },
|
|
||||||
{ name: 'setFormEvent', isAsync: false },
|
|
||||||
{ name: 'getFormMethod', isAsync: false },
|
|
||||||
{ name: 'setFormMethod', isAsync: false },
|
|
||||||
{ name: 'add', isAsync: false },
|
|
||||||
{ name: 'update', isAsync: false },
|
|
||||||
{ name: 'remove', isAsync: false },
|
|
||||||
{ name: 'createId', isAsync: false },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public set<K extends StateKey, T extends State[K]>(name: K, value: T) {
|
public set<K extends StateKey, T extends State[K]>(name: K, value: T) {
|
||||||
@ -123,6 +132,10 @@ class DataSource extends BaseService {
|
|||||||
this.emit('remove', id);
|
this.emit('remove', id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createId(): string {
|
||||||
|
return `ds_${guid()}`;
|
||||||
|
}
|
||||||
|
|
||||||
public getDataSourceById(id: string) {
|
public getDataSourceById(id: string) {
|
||||||
return this.get('dataSources').find((ds) => ds.id === id);
|
return this.get('dataSources').find((ds) => ds.id === id);
|
||||||
}
|
}
|
||||||
@ -137,8 +150,8 @@ class DataSource extends BaseService {
|
|||||||
this.removeAllPlugins();
|
this.removeAllPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
private createId(): string {
|
public usePlugin(options: SyncHookPlugin<SyncMethodName, DataSource>): void {
|
||||||
return `ds_${guid()}`;
|
super.usePlugin(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import { reactive, toRaw } from 'vue';
|
import { reactive, toRaw } from 'vue';
|
||||||
import { cloneDeep, get, isObject, mergeWith, uniq } from 'lodash-es';
|
import { cloneDeep, get, isObject, mergeWith, uniq } from 'lodash-es';
|
||||||
|
import { Writable } from 'type-fest';
|
||||||
|
|
||||||
import { DepTargetType } from '@tmagic/dep';
|
import { DepTargetType } from '@tmagic/dep';
|
||||||
import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
||||||
@ -29,7 +30,15 @@ import propsService from '@editor/services//props';
|
|||||||
import depService from '@editor/services/dep';
|
import depService from '@editor/services/dep';
|
||||||
import historyService from '@editor/services/history';
|
import historyService from '@editor/services/history';
|
||||||
import storageService, { Protocol } from '@editor/services/storage';
|
import storageService, { Protocol } from '@editor/services/storage';
|
||||||
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '@editor/type';
|
import type {
|
||||||
|
AddMNode,
|
||||||
|
AsyncHookPlugin,
|
||||||
|
EditorNodeInfo,
|
||||||
|
PastePosition,
|
||||||
|
StepValue,
|
||||||
|
StoreState,
|
||||||
|
StoreStateKey,
|
||||||
|
} from '@editor/type';
|
||||||
import { LayerOffset, Layout } from '@editor/type';
|
import { LayerOffset, Layout } from '@editor/type';
|
||||||
import {
|
import {
|
||||||
change2Fixed,
|
change2Fixed,
|
||||||
@ -46,6 +55,36 @@ import {
|
|||||||
} from '@editor/utils/editor';
|
} from '@editor/utils/editor';
|
||||||
import { beforePaste, getAddParent } from '@editor/utils/operator';
|
import { beforePaste, getAddParent } from '@editor/utils/operator';
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: [
|
||||||
|
'getLayout',
|
||||||
|
'highlight',
|
||||||
|
'select',
|
||||||
|
'multiSelect',
|
||||||
|
'doAdd',
|
||||||
|
'add',
|
||||||
|
'doRemove',
|
||||||
|
'remove',
|
||||||
|
'doUpdate',
|
||||||
|
'update',
|
||||||
|
'sort',
|
||||||
|
'copy',
|
||||||
|
'paste',
|
||||||
|
'doPaste',
|
||||||
|
'doAlignCenter',
|
||||||
|
'alignCenter',
|
||||||
|
'moveLayer',
|
||||||
|
'moveToContainer',
|
||||||
|
'dragTo',
|
||||||
|
'undo',
|
||||||
|
'redo',
|
||||||
|
'move',
|
||||||
|
] as const,
|
||||||
|
sync: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
|
||||||
|
|
||||||
class Editor extends BaseService {
|
class Editor extends BaseService {
|
||||||
public state: StoreState = reactive({
|
public state: StoreState = reactive({
|
||||||
root: null,
|
root: null,
|
||||||
@ -65,29 +104,7 @@ class Editor extends BaseService {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
[
|
canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true })),
|
||||||
{ name: 'getLayout', isAsync: true },
|
|
||||||
{ name: 'select', isAsync: true },
|
|
||||||
{ name: 'doAdd', isAsync: true },
|
|
||||||
{ name: 'add', isAsync: true },
|
|
||||||
{ name: 'doRemove', isAsync: true },
|
|
||||||
{ name: 'remove', isAsync: true },
|
|
||||||
{ name: 'doUpdate', isAsync: true },
|
|
||||||
{ name: 'update', isAsync: true },
|
|
||||||
{ name: 'sort', isAsync: true },
|
|
||||||
{ name: 'copy', isAsync: true },
|
|
||||||
{ name: 'paste', isAsync: true },
|
|
||||||
{ name: 'doPaste', isAsync: true },
|
|
||||||
{ name: 'doAlignCenter', isAsync: true },
|
|
||||||
{ name: 'alignCenter', isAsync: true },
|
|
||||||
{ name: 'moveLayer', isAsync: true },
|
|
||||||
{ name: 'moveToContainer', isAsync: true },
|
|
||||||
{ name: 'move', isAsync: true },
|
|
||||||
{ name: 'undo', isAsync: true },
|
|
||||||
{ name: 'redo', isAsync: true },
|
|
||||||
{ name: 'highlight', isAsync: true },
|
|
||||||
{ name: 'dragTo', isAsync: true },
|
|
||||||
],
|
|
||||||
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
||||||
['select', 'update', 'moveLayer'],
|
['select', 'update', 'moveLayer'],
|
||||||
);
|
);
|
||||||
@ -696,7 +713,7 @@ class Editor extends BaseService {
|
|||||||
|
|
||||||
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
||||||
propsService.clearRelateId();
|
propsService.clearRelateId();
|
||||||
const pasteConfigs = await beforePaste(position, cloneDeep(config));
|
const pasteConfigs = beforePaste(position, cloneDeep(config));
|
||||||
return pasteConfigs;
|
return pasteConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,6 +1002,10 @@ class Editor extends BaseService {
|
|||||||
this.get('modifiedNodeIds').clear();
|
this.get('modifiedNodeIds').clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public usePlugin(options: AsyncHookPlugin<AsyncMethodName, Editor>): void {
|
||||||
|
super.usePlugin(options);
|
||||||
|
}
|
||||||
|
|
||||||
private addModifiedNodeId(id: Id) {
|
private addModifiedNodeId(id: Id) {
|
||||||
if (!this.isHistoryStateChange) {
|
if (!this.isHistoryStateChange) {
|
||||||
this.get('modifiedNodeIds').set(id, id);
|
this.get('modifiedNodeIds').set(id, id);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { cloneDeep, mergeWith } from 'lodash-es';
|
import { cloneDeep, mergeWith } from 'lodash-es';
|
||||||
|
import { Writable } from 'type-fest';
|
||||||
|
|
||||||
import { DepTargetType } from '@tmagic/dep';
|
import { DepTargetType } from '@tmagic/dep';
|
||||||
import type { FormConfig } from '@tmagic/form';
|
import type { FormConfig } from '@tmagic/form';
|
||||||
@ -26,11 +27,26 @@ import { getValueByKeyPath, guid, setValueByKeyPath, toLine } from '@tmagic/util
|
|||||||
|
|
||||||
import depService from '@editor/services/dep';
|
import depService from '@editor/services/dep';
|
||||||
import editorService from '@editor/services/editor';
|
import editorService from '@editor/services/editor';
|
||||||
import type { PropsState } from '@editor/type';
|
import type { AsyncHookPlugin, PropsState, SyncHookPlugin } from '@editor/type';
|
||||||
import { fillConfig } from '@editor/utils/props';
|
import { fillConfig } from '@editor/utils/props';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: [
|
||||||
|
'setPropsConfig',
|
||||||
|
'getPropsConfig',
|
||||||
|
'setPropsValue',
|
||||||
|
'getPropsValue',
|
||||||
|
'fillConfig',
|
||||||
|
'getDefaultPropsValue',
|
||||||
|
] as const,
|
||||||
|
sync: ['createId', 'setNewItemId'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
|
||||||
|
type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
|
||||||
|
|
||||||
class Props extends BaseService {
|
class Props extends BaseService {
|
||||||
private state = reactive<PropsState>({
|
private state = reactive<PropsState>({
|
||||||
propsConfigMap: {},
|
propsConfigMap: {},
|
||||||
@ -40,14 +56,8 @@ class Props extends BaseService {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super([
|
||||||
{ name: 'setPropsConfig', isAsync: true },
|
...canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true })),
|
||||||
{ name: 'getPropsConfig', isAsync: true },
|
...canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false })),
|
||||||
{ name: 'setPropsValue', isAsync: true },
|
|
||||||
{ name: 'getPropsValue', isAsync: true },
|
|
||||||
{ name: 'createId', isAsync: false },
|
|
||||||
{ name: 'setNewItemId', isAsync: true },
|
|
||||||
{ name: 'fillConfig', isAsync: true },
|
|
||||||
{ name: 'getDefaultPropsValue', isAsync: true },
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,11 +72,6 @@ class Props extends BaseService {
|
|||||||
return fillConfig(config, typeof labelWidth !== 'function' ? labelWidth : '80px');
|
return fillConfig(config, typeof labelWidth !== 'function' ? labelWidth : '80px');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 为指定类型组件设置组件属性表单配置
|
|
||||||
* @param type 组件类型
|
|
||||||
* @param config 组件属性表单配置
|
|
||||||
*/
|
|
||||||
public async setPropsConfig(type: string, config: FormConfig) {
|
public async setPropsConfig(type: string, config: FormConfig) {
|
||||||
this.state.propsConfigMap[type] = await this.fillConfig(Array.isArray(config) ? config : [config]);
|
this.state.propsConfigMap[type] = await this.fillConfig(Array.isArray(config) ? config : [config]);
|
||||||
}
|
}
|
||||||
@ -115,16 +120,14 @@ class Props extends BaseService {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [id, defaultPropsValue, data] = await Promise.all([
|
const id = this.createId(type);
|
||||||
this.createId(type),
|
const defaultPropsValue = this.getDefaultPropsValue(type);
|
||||||
this.getDefaultPropsValue(type),
|
const data = this.setNewItemId(
|
||||||
this.setNewItemId(
|
cloneDeep({
|
||||||
cloneDeep({
|
type,
|
||||||
type,
|
...defaultValue,
|
||||||
...defaultValue,
|
} as any),
|
||||||
} as any),
|
);
|
||||||
),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
@ -133,7 +136,7 @@ class Props extends BaseService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createId(type: string | number): Promise<string> {
|
public createId(type: string | number): string {
|
||||||
return `${type}_${guid()}`;
|
return `${type}_${guid()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,16 +147,16 @@ class Props extends BaseService {
|
|||||||
* @param {Boolean} force 是否强制设置新的ID
|
* @param {Boolean} force 是否强制设置新的ID
|
||||||
*/
|
*/
|
||||||
/* eslint no-param-reassign: ["error", { "props": false }] */
|
/* eslint no-param-reassign: ["error", { "props": false }] */
|
||||||
public async setNewItemId(config: MNode, force = true) {
|
public setNewItemId(config: MNode, force = true) {
|
||||||
if (force || editorService.getNodeById(config.id)) {
|
if (force || editorService.getNodeById(config.id)) {
|
||||||
const newId = await this.createId(config.type || 'component');
|
const newId = this.createId(config.type || 'component');
|
||||||
this.setRelateId(config.id, newId);
|
this.setRelateId(config.id, newId);
|
||||||
config.id = newId;
|
config.id = newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.items && Array.isArray(config.items)) {
|
if (config.items && Array.isArray(config.items)) {
|
||||||
for (const item of config.items) {
|
for (const item of config.items) {
|
||||||
await this.setNewItemId(item);
|
this.setNewItemId(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +168,7 @@ class Props extends BaseService {
|
|||||||
* @param type 组件类型
|
* @param type 组件类型
|
||||||
* @returns Object
|
* @returns Object
|
||||||
*/
|
*/
|
||||||
public async getDefaultPropsValue(type: string) {
|
public getDefaultPropsValue(type: string) {
|
||||||
return ['page', 'container'].includes(type)
|
return ['page', 'container'].includes(type)
|
||||||
? {
|
? {
|
||||||
type,
|
type,
|
||||||
@ -227,6 +230,10 @@ class Props extends BaseService {
|
|||||||
this.removeAllPlugins();
|
this.removeAllPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public usePlugin(options: AsyncHookPlugin<AsyncMethodName, Props> & SyncHookPlugin<SyncMethodName, Props>): void {
|
||||||
|
super.usePlugin(options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取setNewItemId前后映射关系
|
* 获取setNewItemId前后映射关系
|
||||||
* @param oldId 原组件ID
|
* @param oldId 原组件ID
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
import type { Writable } from 'type-fest';
|
||||||
|
|
||||||
import StageCore from '@tmagic/stage';
|
import StageCore from '@tmagic/stage';
|
||||||
|
|
||||||
import { useStage } from '@editor/hooks/use-stage';
|
import { useStage } from '@editor/hooks/use-stage';
|
||||||
import BaseService from '@editor/services//BaseService';
|
import BaseService from '@editor/services//BaseService';
|
||||||
import editorService from '@editor/services//editor';
|
import editorService from '@editor/services//editor';
|
||||||
import type { StageOptions, StageOverlayState } from '@editor/type';
|
import type { StageOptions, StageOverlayState, SyncHookPlugin } from '@editor/type';
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: [],
|
||||||
|
sync: ['openOverlay', 'closeOverlay', 'updateOverlay', 'createStage'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
|
||||||
|
|
||||||
class StageOverlay extends BaseService {
|
class StageOverlay extends BaseService {
|
||||||
private state: StageOverlayState = reactive({
|
private state: StageOverlayState = reactive({
|
||||||
@ -20,12 +28,7 @@ class StageOverlay extends BaseService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super(canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false })));
|
||||||
{ name: 'openOverlay', isAsync: false },
|
|
||||||
{ name: 'closeOverlay', isAsync: false },
|
|
||||||
{ name: 'updateOverlay', isAsync: false },
|
|
||||||
{ name: 'createStage', isAsync: false },
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.get('wrapDiv').classList.add('tmagic-editor-sub-stage-wrap');
|
this.get('wrapDiv').classList.add('tmagic-editor-sub-stage-wrap');
|
||||||
}
|
}
|
||||||
@ -111,6 +114,10 @@ class StageOverlay extends BaseService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public usePlugin(options: SyncHookPlugin<SyncMethodName, StageOverlay>): void {
|
||||||
|
super.usePlugin(options);
|
||||||
|
}
|
||||||
|
|
||||||
private createContentEl() {
|
private createContentEl() {
|
||||||
const sourceEl = this.get('sourceEl');
|
const sourceEl = this.get('sourceEl');
|
||||||
if (!sourceEl) return;
|
if (!sourceEl) return;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import serialize from 'serialize-javascript';
|
import serialize from 'serialize-javascript';
|
||||||
|
import type { Writable } from 'type-fest';
|
||||||
|
|
||||||
|
import type { SyncHookPlugin } from '@editor/type';
|
||||||
import { getConfig } from '@editor/utils/config';
|
import { getConfig } from '@editor/utils/config';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
@ -17,6 +19,13 @@ export enum Protocol {
|
|||||||
BOOLEAN = 'boolean',
|
BOOLEAN = 'boolean',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: [],
|
||||||
|
sync: ['getStorage', 'getNamespace', 'clear', 'getItem', 'removeItem', 'setItem'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据存储服务
|
* 数据存储服务
|
||||||
*/
|
*/
|
||||||
@ -25,14 +34,7 @@ export class WebStorage extends BaseService {
|
|||||||
private namespace = 'tmagic';
|
private namespace = 'tmagic';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super(canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false })));
|
||||||
{ name: 'getStorage', isAsync: false },
|
|
||||||
{ name: 'getNamespace', isAsync: false },
|
|
||||||
{ name: 'clear', isAsync: false },
|
|
||||||
{ name: 'getItem', isAsync: false },
|
|
||||||
{ name: 'removeItem', isAsync: false },
|
|
||||||
{ name: 'setItem', isAsync: false },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,6 +125,10 @@ export class WebStorage extends BaseService {
|
|||||||
this.removeAllPlugins();
|
this.removeAllPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public usePlugin(options: SyncHookPlugin<SyncMethodName, WebStorage>): void {
|
||||||
|
super.usePlugin(options);
|
||||||
|
}
|
||||||
|
|
||||||
private getValueAndProtocol(value: string | null) {
|
private getValueAndProtocol(value: string | null) {
|
||||||
let protocol = '';
|
let protocol = '';
|
||||||
|
|
||||||
|
@ -17,11 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
import type { Writable } from 'type-fest';
|
||||||
|
|
||||||
import { convertToNumber } from '@tmagic/utils';
|
import { convertToNumber } from '@tmagic/utils';
|
||||||
|
|
||||||
import editorService from '@editor/services/editor';
|
import editorService from '@editor/services/editor';
|
||||||
import type { StageRect, UiState } from '@editor/type';
|
import type { AsyncHookPlugin, StageRect, UiState } from '@editor/type';
|
||||||
|
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
|
|
||||||
@ -50,12 +51,16 @@ const state = reactive<UiState>({
|
|||||||
hideSlideBar: false,
|
hideSlideBar: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const canUsePluginMethods = {
|
||||||
|
async: ['zoom', 'calcZoom'] as const,
|
||||||
|
sync: [] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
|
||||||
|
|
||||||
class Ui extends BaseService {
|
class Ui extends BaseService {
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super(canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true })));
|
||||||
{ name: 'zoom', isAsync: true },
|
|
||||||
{ name: 'calcZoom', isAsync: true },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public set<K extends keyof UiState, T extends UiState[K]>(name: K, value: T) {
|
public set<K extends keyof UiState, T extends UiState[K]>(name: K, value: T) {
|
||||||
@ -134,6 +139,10 @@ class Ui extends BaseService {
|
|||||||
this.removeAllPlugins();
|
this.removeAllPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public usePlugin(options: AsyncHookPlugin<AsyncMethodName, Ui>): void {
|
||||||
|
super.usePlugin(options);
|
||||||
|
}
|
||||||
|
|
||||||
private async setStageRect(value: StageRect) {
|
private async setStageRect(value: StageRect) {
|
||||||
state.stageRect = {
|
state.stageRect = {
|
||||||
...state.stageRect,
|
...state.stageRect,
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Component } from 'vue';
|
import type { Component } from 'vue';
|
||||||
|
import type { PascalCasedProperties } from 'type-fest';
|
||||||
|
|
||||||
import type { ColumnConfig, FilterFunction, FormConfig, FormItem } from '@tmagic/form';
|
import type { ColumnConfig, FilterFunction, FormConfig, FormItem } from '@tmagic/form';
|
||||||
import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
||||||
@ -670,3 +671,35 @@ export interface TreeNodeData {
|
|||||||
items?: TreeNodeData[];
|
items?: TreeNodeData[];
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AsyncBeforeHook<Value extends Array<string>, C extends Record<Value[number], (...args: any) => any>> = {
|
||||||
|
[K in Value[number]]?: (...args: Parameters<C[K]>) => Promise<Parameters<C[K]>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AsyncAfterHook<Value extends Array<string>, C extends Record<Value[number], (...args: any) => any>> = {
|
||||||
|
[K in Value[number]]?: (result: Awaited<ReturnType<C[K]>>, ...args: Parameters<C[K]>) => ReturnType<C[K]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SyncBeforeHook<Value extends Array<string>, C extends Record<Value[number], (...args: any) => any>> = {
|
||||||
|
[K in Value[number]]?: (...args: Parameters<C[K]>) => Parameters<C[K]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SyncAfterHook<Value extends Array<string>, C extends Record<Value[number], (...args: any) => any>> = {
|
||||||
|
[K in Value[number]]?: (result: ReturnType<C[K]>, ...args: Parameters<C[K]>) => ReturnType<C[K]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AddPrefixToObject<T, P extends string> = {
|
||||||
|
[K in keyof T as K extends string ? `${P}${K}` : never]: T[K];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AsyncHookPlugin<
|
||||||
|
T extends Array<string>,
|
||||||
|
C extends Record<T[number], (...args: any) => any>,
|
||||||
|
> = AddPrefixToObject<PascalCasedProperties<AsyncBeforeHook<T, C>>, 'before'> &
|
||||||
|
AddPrefixToObject<PascalCasedProperties<AsyncAfterHook<T, C>>, 'after'>;
|
||||||
|
|
||||||
|
export type SyncHookPlugin<
|
||||||
|
T extends Array<string>,
|
||||||
|
C extends Record<T[number], (...args: any) => any>,
|
||||||
|
> = AddPrefixToObject<PascalCasedProperties<SyncBeforeHook<T, C>>, 'before'> &
|
||||||
|
AddPrefixToObject<PascalCasedProperties<SyncAfterHook<T, C>>, 'after'>;
|
||||||
|
@ -15,55 +15,53 @@ import { generatePageNameByApp, getInitPositionStyle } from '@editor/utils/edito
|
|||||||
* @param config 待粘贴的元素配置(复制时保存的那份配置)
|
* @param config 待粘贴的元素配置(复制时保存的那份配置)
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const beforePaste = async (position: PastePosition, config: MNode[]): Promise<MNode[]> => {
|
export const beforePaste = (position: PastePosition, config: MNode[]): MNode[] => {
|
||||||
if (!config[0]?.style) return config;
|
if (!config[0]?.style) return config;
|
||||||
const curNode = editorService.get('node');
|
const curNode = editorService.get('node');
|
||||||
// 将数组中第一个元素的坐标作为参照点
|
// 将数组中第一个元素的坐标作为参照点
|
||||||
const { left: referenceLeft, top: referenceTop } = config[0].style;
|
const { left: referenceLeft, top: referenceTop } = config[0].style;
|
||||||
// 坐标校准后的粘贴数据
|
// 坐标校准后的粘贴数据
|
||||||
const pasteConfigs: MNode[] = await Promise.all(
|
const pasteConfigs: MNode[] = config.map((configItem: MNode): MNode => {
|
||||||
config.map(async (configItem: MNode): Promise<MNode> => {
|
// 解构 position 对象,从 position 删除 offsetX、offsetY字段
|
||||||
// 解构 position 对象,从 position 删除 offsetX、offsetY字段
|
const { offsetX = 0, offsetY = 0, ...positionClone } = position;
|
||||||
const { offsetX = 0, offsetY = 0, ...positionClone } = position;
|
let pastePosition = positionClone;
|
||||||
let pastePosition = positionClone;
|
|
||||||
|
|
||||||
if (!isEmpty(pastePosition) && curNode?.items) {
|
if (!isEmpty(pastePosition) && curNode?.items) {
|
||||||
// 如果没有传入粘贴坐标则可能为键盘操作,不再转换
|
// 如果没有传入粘贴坐标则可能为键盘操作,不再转换
|
||||||
// 如果粘贴时选中了容器,则将元素粘贴到容器内,坐标需要转换为相对于容器的坐标
|
// 如果粘贴时选中了容器,则将元素粘贴到容器内,坐标需要转换为相对于容器的坐标
|
||||||
pastePosition = getPositionInContainer(pastePosition, curNode.id);
|
pastePosition = getPositionInContainer(pastePosition, curNode.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将所有待粘贴元素坐标相对于多选第一个元素坐标重新计算,以保证多选粘贴后元素间距不变
|
||||||
|
if (pastePosition.left && configItem.style?.left) {
|
||||||
|
pastePosition.left = configItem.style.left - referenceLeft + pastePosition.left;
|
||||||
|
}
|
||||||
|
if (pastePosition.top && configItem.style?.top) {
|
||||||
|
pastePosition.top = configItem.style?.top - referenceTop + pastePosition.top;
|
||||||
|
}
|
||||||
|
const pasteConfig = propsService.setNewItemId(configItem, false);
|
||||||
|
|
||||||
|
if (pasteConfig.style) {
|
||||||
|
const { left, top } = pasteConfig.style;
|
||||||
|
// 判断能转换为数字时,做粘贴偏移量计算
|
||||||
|
if (typeof left === 'number' || (!!left && !isNaN(Number(left)))) {
|
||||||
|
pasteConfig.style.left = Number(left) + offsetX;
|
||||||
|
}
|
||||||
|
if (typeof top === 'number' || (!!top && !isNaN(Number(top)))) {
|
||||||
|
pasteConfig.style.top = Number(top) + offsetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将所有待粘贴元素坐标相对于多选第一个元素坐标重新计算,以保证多选粘贴后元素间距不变
|
pasteConfig.style = {
|
||||||
if (pastePosition.left && configItem.style?.left) {
|
...pasteConfig.style,
|
||||||
pastePosition.left = configItem.style.left - referenceLeft + pastePosition.left;
|
...pastePosition,
|
||||||
}
|
};
|
||||||
if (pastePosition.top && configItem.style?.top) {
|
}
|
||||||
pastePosition.top = configItem.style?.top - referenceTop + pastePosition.top;
|
const root = editorService.get('root');
|
||||||
}
|
if ((isPage(pasteConfig) || isPageFragment(pasteConfig)) && root) {
|
||||||
const pasteConfig = await propsService.setNewItemId(configItem, false);
|
pasteConfig.name = generatePageNameByApp(root, isPage(pasteConfig) ? NodeType.PAGE : NodeType.PAGE_FRAGMENT);
|
||||||
|
}
|
||||||
if (pasteConfig.style) {
|
return pasteConfig as MNode;
|
||||||
const { left, top } = pasteConfig.style;
|
});
|
||||||
// 判断能转换为数字时,做粘贴偏移量计算
|
|
||||||
if (typeof left === 'number' || (!!left && !isNaN(Number(left)))) {
|
|
||||||
pasteConfig.style.left = Number(left) + offsetX;
|
|
||||||
}
|
|
||||||
if (typeof top === 'number' || (!!top && !isNaN(Number(top)))) {
|
|
||||||
pasteConfig.style.top = Number(top) + offsetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
pasteConfig.style = {
|
|
||||||
...pasteConfig.style,
|
|
||||||
...pastePosition,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const root = editorService.get('root');
|
|
||||||
if ((isPage(pasteConfig) || isPageFragment(pasteConfig)) && root) {
|
|
||||||
pasteConfig.name = generatePageNameByApp(root, isPage(pasteConfig) ? NodeType.PAGE : NodeType.PAGE_FRAGMENT);
|
|
||||||
}
|
|
||||||
return pasteConfig as MNode;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return pasteConfigs;
|
return pasteConfigs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ export const displayTabConfig: TabPaneConfig = {
|
|||||||
* @param config 组件属性配置
|
* @param config 组件属性配置
|
||||||
* @returns Object
|
* @returns Object
|
||||||
*/
|
*/
|
||||||
export const fillConfig = (config: FormConfig = [], labelWidth = '80px') => [
|
export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormConfig => [
|
||||||
{
|
{
|
||||||
type: 'tab',
|
type: 'tab',
|
||||||
labelWidth,
|
labelWidth,
|
||||||
|
@ -11,17 +11,17 @@ test('createId', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('setNewItemId', () => {
|
describe('setNewItemId', () => {
|
||||||
test('普通', async () => {
|
test('普通', () => {
|
||||||
const config = {
|
const config = {
|
||||||
id: 1,
|
id: 1,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
};
|
};
|
||||||
// 将组件与组件的子元素配置中的id都设置成一个新的ID
|
// 将组件与组件的子元素配置中的id都设置成一个新的ID
|
||||||
await props.setNewItemId(config);
|
props.setNewItemId(config);
|
||||||
expect(config.id === 1).toBeFalsy();
|
expect(config.id === 1).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('items', async () => {
|
test('items', () => {
|
||||||
const config = {
|
const config = {
|
||||||
id: 1,
|
id: 1,
|
||||||
type: NodeType.PAGE,
|
type: NodeType.PAGE,
|
||||||
@ -32,7 +32,7 @@ describe('setNewItemId', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
await props.setNewItemId(config);
|
props.setNewItemId(config);
|
||||||
expect(config.id === 1).toBeFalsy();
|
expect(config.id === 1).toBeFalsy();
|
||||||
expect(config.items[0].id === 2).toBeFalsy();
|
expect(config.items[0].id === 2).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
@ -227,7 +227,7 @@ asyncLoadJs(`${VITE_ENTRY_PATH}/ds-value/index.umd.cjs`).then(() => {
|
|||||||
save();
|
save();
|
||||||
|
|
||||||
editorService.usePlugin({
|
editorService.usePlugin({
|
||||||
beforeDoAdd: (config: MNode, parent?: MContainer | null) => {
|
beforeDoAdd: async (config: MNode, parent: MContainer) => {
|
||||||
if (config.type === 'overlay') {
|
if (config.type === 'overlay') {
|
||||||
config.style = {
|
config.style = {
|
||||||
...config.style,
|
...config.style,
|
||||||
@ -235,7 +235,7 @@ editorService.usePlugin({
|
|||||||
top: 0,
|
top: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
return [config, editorService.get('page')];
|
return [config, editorService.get('page') as MContainer];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [config, parent];
|
return [config, parent];
|
||||||
|
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@ -377,6 +377,9 @@ importers:
|
|||||||
tsc-alias:
|
tsc-alias:
|
||||||
specifier: ^1.8.5
|
specifier: ^1.8.5
|
||||||
version: 1.8.5
|
version: 1.8.5
|
||||||
|
type-fest:
|
||||||
|
specifier: ^4.10.3
|
||||||
|
version: 4.11.1
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.0.4
|
specifier: ^5.0.4
|
||||||
version: 5.0.4
|
version: 5.0.4
|
||||||
@ -9552,7 +9555,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
find-up: 6.3.0
|
find-up: 6.3.0
|
||||||
read-pkg: 8.1.0
|
read-pkg: 8.1.0
|
||||||
type-fest: 4.6.0
|
type-fest: 4.11.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/read-pkg-up@7.0.1:
|
/read-pkg-up@7.0.1:
|
||||||
@ -9581,7 +9584,7 @@ packages:
|
|||||||
'@types/normalize-package-data': 2.4.1
|
'@types/normalize-package-data': 2.4.1
|
||||||
normalize-package-data: 6.0.0
|
normalize-package-data: 6.0.0
|
||||||
parse-json: 7.1.1
|
parse-json: 7.1.1
|
||||||
type-fest: 4.6.0
|
type-fest: 4.11.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/readable-stream@3.6.2:
|
/readable-stream@3.6.2:
|
||||||
@ -10491,8 +10494,8 @@ packages:
|
|||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/type-fest@4.6.0:
|
/type-fest@4.11.1:
|
||||||
resolution: {integrity: sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==}
|
resolution: {integrity: sha512-MFMf6VkEVZAETidGGSYW2B1MjXbGX+sWIywn2QPEaJ3j08V+MwVRHMXtf2noB8ENJaD0LIun9wh5Z6OPNf1QzQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const useRuntime = ({
|
|||||||
fillConfig = (config) => config,
|
fillConfig = (config) => config,
|
||||||
}: {
|
}: {
|
||||||
plugins?: Plugin[];
|
plugins?: Plugin[];
|
||||||
fillConfig?: (config: FormConfig) => FormConfig;
|
fillConfig?: (config: FormConfig, mForm: any) => FormConfig;
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
const render = (stage: StageCore) => {
|
const render = (stage: StageCore) => {
|
||||||
injectStyle(stage.renderer.getDocument()!, cssStyle);
|
injectStyle(stage.renderer.getDocument()!, cssStyle);
|
||||||
@ -60,24 +60,24 @@ export const useRuntime = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
propsService.usePlugin({
|
propsService.usePlugin({
|
||||||
afterFillConfig(config: FormConfig, itemConfig: FormConfig) {
|
async afterFillConfig(config: FormConfig, itemConfig: FormConfig, labelWidth = '80px') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: 'tab',
|
type: 'tab',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
title: '属性',
|
title: '属性',
|
||||||
labelWidth: '80px',
|
labelWidth,
|
||||||
items: [...commonConfig, ...itemConfig],
|
items: [...commonConfig, ...itemConfig],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
] as FormConfig;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
editorService.usePlugin({
|
editorService.usePlugin({
|
||||||
afterGetLayout() {
|
async afterGetLayout() {
|
||||||
return Layout.RELATIVE;
|
return Layout.RELATIVE;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user