mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-09-14 16:09:08 +00:00
fix(tmagic-form): 合并宿主 $MAGIC_FORM 与 formOptions,避免二次安装清空 request
This commit is contained in:
parent
5a3edacb96
commit
39ef49db7d
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
@ -583,7 +583,7 @@ importers:
|
||||
version: link:../packages/tdesign-vue-next-adapter
|
||||
'@tmagic/tmagic-form-runtime':
|
||||
specifier: 1.1.6
|
||||
version: link:../runtime/tmagic-form
|
||||
version: 1.1.6(@tmagic/core@packages+core)(@tmagic/editor@packages+editor)(element-plus@2.14.4(vue@3.5.41(typescript@6.0.3)))(typescript@6.0.3)(vue@3.5.41(typescript@6.0.3))
|
||||
element-plus:
|
||||
specifier: ^2.14.4
|
||||
version: 2.14.4(vue@3.5.41(typescript@6.0.3))
|
||||
@ -2902,6 +2902,21 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@tmagic/tmagic-form-runtime@1.1.6':
|
||||
resolution: {integrity: sha512-iRvsrNxrY2KsUh5qiDo+v0bvNzfk41+viQGvuTCdF3lbD4J1ylZ/PNbjAnkFWLMx7Rc6UHcbvRfyx6r22TYHiQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@tmagic/core': '>=1.7.0'
|
||||
'@tmagic/editor': '>=1.7.0'
|
||||
element-plus: ^2.14.4
|
||||
typescript: ^5.9.3
|
||||
vue: ^3.5.41
|
||||
peerDependenciesMeta:
|
||||
'@tmagic/core':
|
||||
optional: true
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@tmagic/utils@1.7.0':
|
||||
resolution: {integrity: sha512-s4K66sgg/K4191vw/D2y7t4RpoS1qZGUaonn2Pkq1t8nKXtRuBVzKfp2eycVlVAVQavyDRxmuB5XQGYHlZCZTw==}
|
||||
engines: {node: '>=18'}
|
||||
@ -8571,6 +8586,15 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 6.0.3
|
||||
|
||||
'@tmagic/tmagic-form-runtime@1.1.6(@tmagic/core@packages+core)(@tmagic/editor@packages+editor)(element-plus@2.14.4(vue@3.5.41(typescript@6.0.3)))(typescript@6.0.3)(vue@3.5.41(typescript@6.0.3))':
|
||||
dependencies:
|
||||
'@tmagic/editor': link:packages/editor
|
||||
element-plus: 2.14.4(vue@3.5.41(typescript@6.0.3))
|
||||
vue: 3.5.41(typescript@6.0.3)
|
||||
optionalDependencies:
|
||||
'@tmagic/core': link:packages/core
|
||||
typescript: 6.0.3
|
||||
|
||||
'@tmagic/utils@1.7.0(@tmagic/schema@1.7.0(typescript@6.0.3))(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@tmagic/schema': 1.7.0(typescript@6.0.3)
|
||||
|
||||
@ -35,4 +35,29 @@ import {
|
||||
} from '@tmagic/tmagic-form-runtime';
|
||||
|
||||
const { render } = useRuntime();
|
||||
```
|
||||
```
|
||||
|
||||
## 表单配置需要发请求时
|
||||
|
||||
`@tmagic/form` 的 `request` 是模块级配置,`setConfig` 会整对象替换。请在宿主 Vue
|
||||
组件的 setup 中调用 `useRuntime()`:此时会读取宿主 `$MAGIC_FORM`,与 `formOptions`
|
||||
浅合并后再安装 formPlugin,默认不会清空宿主已有的 `request` / `flat` 等。
|
||||
|
||||
若宿主未配 `request`,或画布侧需要覆盖,通过 `formOptions` 传入。`request` 的语义与
|
||||
宿主 `editorPlugin` 一致:入参为 `{ method, url, data, ... }`,**resolve 出接口 body**
|
||||
(不要返回整个 Response / axios response)。
|
||||
|
||||
```ts
|
||||
const { render } = useRuntime({
|
||||
formOptions: {
|
||||
request: async ({ url, method = 'GET', data }) => {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: method === 'GET' ? undefined : JSON.stringify(data),
|
||||
});
|
||||
return response.json();
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.1.6",
|
||||
"version": "1.1.8",
|
||||
"name": "@tmagic/tmagic-form-runtime",
|
||||
"type": "module",
|
||||
"main": "dist/tmagic-tmagic-form.umd.cjs",
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { createApp, onBeforeUnmount, Plugin } from 'vue';
|
||||
import { createApp, getCurrentInstance, onBeforeUnmount, Plugin } from 'vue';
|
||||
import cssStyle from 'element-plus/dist/index.css?raw';
|
||||
|
||||
import type { FormConfig, StageCore } from '@tmagic/editor';
|
||||
import type { FormConfig, FormInstallOptions, StageCore } from '@tmagic/editor';
|
||||
import { editorService, formPlugin, injectStyle, Layout, propsService, uiService } from '@tmagic/editor';
|
||||
|
||||
import commonConfig from './form-config/common';
|
||||
import App from './App.vue';
|
||||
import formConfigs from './form-config';
|
||||
import { mergeFormInstallOptions } from './mergeFormOptions';
|
||||
|
||||
export * from './component-group-list';
|
||||
|
||||
@ -15,10 +16,22 @@ export const propsConfigs = formConfigs;
|
||||
export const useRuntime = ({
|
||||
plugins = [],
|
||||
fillConfig = (config) => config,
|
||||
formOptions = {},
|
||||
}: {
|
||||
plugins?: Plugin[];
|
||||
fillConfig?: (config: FormConfig, mForm: any) => FormConfig;
|
||||
/**
|
||||
* 透传给 `@tmagic/form` 的安装选项(如 `request`)。
|
||||
*
|
||||
* formPlugin 的 `setConfig` 是整对象替换。`useRuntime` 在调用时读取宿主
|
||||
* `$MAGIC_FORM`,再与 `formOptions` 浅合并后安装,避免画布二次安装清空
|
||||
* 宿主的 `request` / `flat` 等。画布侧要覆盖或补齐时再传入。
|
||||
*/
|
||||
formOptions?: FormInstallOptions;
|
||||
} = {}) => {
|
||||
const hostFormOptions = getCurrentInstance()?.appContext.config.globalProperties.$MAGIC_FORM as
|
||||
FormInstallOptions | undefined;
|
||||
|
||||
const render = (stage: StageCore) => {
|
||||
const doc = stage.renderer?.getDocument();
|
||||
|
||||
@ -48,7 +61,7 @@ export const useRuntime = ({
|
||||
stage,
|
||||
fillConfig,
|
||||
});
|
||||
vueApp.use(formPlugin);
|
||||
vueApp.use(formPlugin, mergeFormInstallOptions(hostFormOptions, formOptions));
|
||||
plugins.forEach((plugin) => vueApp.use(plugin));
|
||||
vueApp.mount(el);
|
||||
|
||||
|
||||
10
runtime/tmagic-form/src/mergeFormOptions.ts
Normal file
10
runtime/tmagic-form/src/mergeFormOptions.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { FormInstallOptions } from '@tmagic/editor';
|
||||
|
||||
/**
|
||||
* formPlugin.install 会 setConfig 整对象替换。
|
||||
* 把宿主 `$MAGIC_FORM` 与画布 `formOptions` 浅合并后再装,避免清空 request / flat 等。
|
||||
*/
|
||||
export const mergeFormInstallOptions = (
|
||||
host: FormInstallOptions | undefined,
|
||||
formOptions: FormInstallOptions = {},
|
||||
): FormInstallOptions => ({ ...(host ?? {}), ...formOptions });
|
||||
35
runtime/tmagic-form/tests/merge-form-options.test.ts
Normal file
35
runtime/tmagic-form/tests/merge-form-options.test.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* formPlugin.install 会 setConfig 整对象替换。
|
||||
* mergeFormInstallOptions 把宿主 $MAGIC_FORM 与 formOptions 浅合并。
|
||||
*/
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { mergeFormInstallOptions } from '../src/mergeFormOptions';
|
||||
|
||||
describe('mergeFormInstallOptions', () => {
|
||||
const hostRequest = vi.fn();
|
||||
const hostFields = { select: { component: { name: 'HostSelect' } } };
|
||||
const host = { request: hostRequest, flat: true, fields: hostFields };
|
||||
|
||||
it('无 formOptions 时原样带回宿主配置,避免二次安装清空', () => {
|
||||
expect(mergeFormInstallOptions(host)).toEqual(host);
|
||||
expect(mergeFormInstallOptions(host, {})).toEqual(host);
|
||||
});
|
||||
|
||||
it('formOptions 只覆盖传入的键,保留宿主其余配置', () => {
|
||||
const request = vi.fn();
|
||||
|
||||
expect(mergeFormInstallOptions(host, { request })).toEqual({
|
||||
request,
|
||||
flat: true,
|
||||
fields: hostFields,
|
||||
});
|
||||
});
|
||||
|
||||
it('没有宿主配置时只使用 formOptions', () => {
|
||||
const request = vi.fn();
|
||||
|
||||
expect(mergeFormInstallOptions(undefined, { request })).toEqual({ request });
|
||||
expect(mergeFormInstallOptions(undefined)).toEqual({});
|
||||
});
|
||||
});
|
||||
78
runtime/tmagic-form/tests/use-runtime.test.ts
Normal file
78
runtime/tmagic-form/tests/use-runtime.test.ts
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* `useRuntime` 读取宿主 `$MAGIC_FORM`,合并后再交给 formPlugin。
|
||||
*/
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useRuntime } from '../src/index';
|
||||
|
||||
const { formPluginMock, createAppMock, appUseMock, getCurrentInstanceMock } = vi.hoisted(() => {
|
||||
const appUseMock = vi.fn();
|
||||
return {
|
||||
formPluginMock: { install: vi.fn() },
|
||||
createAppMock: vi.fn(() => ({ use: appUseMock, mount: vi.fn() })),
|
||||
appUseMock,
|
||||
getCurrentInstanceMock: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('vue', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('vue')>()),
|
||||
createApp: createAppMock,
|
||||
onBeforeUnmount: vi.fn(),
|
||||
getCurrentInstance: getCurrentInstanceMock,
|
||||
}));
|
||||
|
||||
vi.mock('@tmagic/editor', () => ({
|
||||
formPlugin: formPluginMock,
|
||||
createForm: (config: unknown) => config,
|
||||
editorService: { usePlugin: vi.fn(), removeAllPlugins: vi.fn() },
|
||||
propsService: { usePlugin: vi.fn(), removeAllPlugins: vi.fn() },
|
||||
uiService: { set: vi.fn(), get: vi.fn() },
|
||||
injectStyle: vi.fn(),
|
||||
Layout: { RELATIVE: 'relative' },
|
||||
}));
|
||||
|
||||
vi.mock('../src/App.vue', () => ({ default: { name: 'App' } }));
|
||||
|
||||
const stage = { renderer: { getDocument: () => undefined } } as any;
|
||||
|
||||
const hostRequest = vi.fn();
|
||||
const hostFormOptions = { request: hostRequest, flat: true, extra: 'keep' };
|
||||
|
||||
const withHostForm = () => {
|
||||
getCurrentInstanceMock.mockReturnValue({
|
||||
appContext: { config: { globalProperties: { $MAGIC_FORM: hostFormOptions } } },
|
||||
});
|
||||
};
|
||||
|
||||
describe('useRuntime — formOptions', () => {
|
||||
it('setup 中能读到宿主 $MAGIC_FORM 时,默认安装不会清空 request / flat', () => {
|
||||
withHostForm();
|
||||
|
||||
useRuntime().render(stage);
|
||||
|
||||
expect(appUseMock).toHaveBeenCalledWith(formPluginMock, hostFormOptions);
|
||||
});
|
||||
|
||||
it('formOptions 覆盖 request,保留宿主 flat 等其余键', () => {
|
||||
withHostForm();
|
||||
const request = vi.fn();
|
||||
|
||||
useRuntime({ formOptions: { request } }).render(stage);
|
||||
|
||||
expect(appUseMock).toHaveBeenCalledWith(formPluginMock, {
|
||||
request,
|
||||
flat: true,
|
||||
extra: 'keep',
|
||||
});
|
||||
});
|
||||
|
||||
it('不在 setup 中调用时,只透传 formOptions', () => {
|
||||
getCurrentInstanceMock.mockReturnValue(null);
|
||||
const request = vi.fn();
|
||||
|
||||
useRuntime({ formOptions: { request } }).render(stage);
|
||||
|
||||
expect(appUseMock).toHaveBeenCalledWith(formPluginMock, { request });
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user