feat(editor): 对比表单支持自定义 loadConfig 加载逻辑

将 CompareCategory 等类型抽取到 type.ts,
新增 CompareFormLoadConfig 支持外部接管表单配置加载,
HistoryDiffDialog 透传 loadConfig 并支持 width 配置及对外导出。
This commit is contained in:
roymondchen 2026-06-02 17:03:27 +08:00
parent 12069e0937
commit 1cd69b33fe
4 changed files with 90 additions and 29 deletions

View File

@ -24,20 +24,13 @@ import { type CodeBlockContent, type DataSourceSchema, HookType, type MNode } fr
import { type FormConfig, type FormState, type FormValue, MForm } from '@tmagic/form';
import { useServices } from '@editor/hooks/use-services';
import type { CompareCategory, CompareFormLoadConfig } from '@editor/type';
import { getCodeBlockFormConfig } from '@editor/utils/code-block';
defineOptions({
name: 'MEditorCompareForm',
});
/**
* 对比类型
* - node: 节点组件 `type` propsService 获取属性表单配置
* - data-source: 数据源 `type`(base/http/...) dataSourceService 获取数据源表单配置
* - code-block: 数据源代码块使用内置的代码块表单配置
*/
export type CompareCategory = 'node' | 'data-source' | 'code-block';
const props = withDefaults(
defineProps<{
/** 当前值(修改后的值) */
@ -68,6 +61,12 @@ const props = withDefaults(
* 因此在差异对比场景下也需要透传避免出现 `formState.xxx is undefined` 的运行时错误
*/
extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
/**
* 自定义 FormConfig 加载逻辑传入后将接管内置的按 `category`(node/data-source/code-block)
* 取配置逻辑调用方可根据业务自行返回或异步返回表单配置可通过
* `ctx.defaultLoadConfig()` 复用默认结果再做二次加工返回的 config 直接用于对比展示
*/
loadConfig?: CompareFormLoadConfig;
}>(),
{
category: 'node',
@ -153,22 +152,23 @@ const showDiff = ({ curValue, lastValue, config }: { curValue: any; lastValue: a
return !isEqual(curValue, lastValue);
};
const loadConfig = async () => {
/**
* 内置的默认 FormConfig 加载逻辑 `category` 从对应 service / 工具取配置
* 作为 ctx.defaultLoadConfig 透传给自定义 `loadConfig`方便复用与二次加工
*/
const defaultLoadConfig = async (): Promise<FormConfig> => {
switch (props.category) {
case 'node': {
if (!props.type) {
config.value = [];
return;
return [];
}
config.value = await propsService.getPropsConfig(props.type);
break;
return await propsService.getPropsConfig(props.type);
}
case 'data-source': {
config.value = dataSourceService.getFormConfig(props.type || 'base');
break;
return dataSourceService.getFormConfig(props.type || 'base');
}
case 'code-block': {
config.value = getCodeBlockFormConfig({
return getCodeBlockFormConfig({
paramColConfig: codeBlockService.getParamsColConfig(),
// dataSourceType "" props.dataSourceType
// step
@ -178,15 +178,28 @@ const loadConfig = async () => {
// /
editable: false,
});
break;
}
default:
config.value = [];
return [];
}
};
const loadConfig = async () => {
if (props.loadConfig) {
config.value = await props.loadConfig({
category: props.category,
type: props.type,
dataSourceType: props.dataSourceType,
defaultLoadConfig,
});
return;
}
config.value = await defaultLoadConfig();
};
watch(
[() => props.category, () => props.type, () => props.dataSourceType],
[() => props.category, () => props.type, () => props.dataSourceType, () => props.loadConfig],
() => {
loadConfig();
},

View File

@ -72,6 +72,7 @@ export { default as Resizer } from './components/Resizer.vue';
export { default as CodeBlockEditor } from './components/CodeBlockEditor.vue';
export { default as CompareForm } from './components/CompareForm.vue';
export { default as HistoryListBucket } from './layouts/history-list/Bucket.vue';
export { default as HistoryDiffDialog } from './layouts/history-list/HistoryDiffDialog.vue';
export { default as FloatingBox } from './components/FloatingBox.vue';
export { default as Tree } from './components/Tree.vue';
export { default as TreeNode } from './components/TreeNode.vue';

View File

@ -4,10 +4,10 @@
v-model="visible"
class="m-editor-history-diff-dialog"
title="查看修改差异"
width="900px"
top="5vh"
destroy-on-close
append-to-body
:width="width"
>
<div v-if="payload" class="m-editor-history-diff-dialog-body">
<div class="m-editor-history-diff-dialog-header">
@ -42,6 +42,7 @@
:value="rightValue"
:last-value="leftValue"
:extend-state="extendState"
:load-config="loadConfig"
height="70vh"
/>
@ -71,21 +72,33 @@ import { isEqual } from 'lodash-es';
import { TMagicButton, TMagicDialog, TMagicRadioButton, TMagicRadioGroup, TMagicTag } from '@tmagic/design';
import type { FormState } from '@tmagic/form';
import CompareForm, { type CompareCategory } from '@editor/components/CompareForm.vue';
import CompareForm from '@editor/components/CompareForm.vue';
import CodeEditor from '@editor/layouts/CodeEditor.vue';
import type { CompareCategory, CompareFormLoadConfig } from '@editor/type';
defineOptions({
name: 'MEditorHistoryDiffDialog',
});
defineProps<{
/**
* 来自 Editor 顶层的 `extendFormState`用于扩展 MForm.formState
* 透传给 CompareForm从而让差异对比时表单 item 中依赖业务上下文的
* `display` / `disabled` filterFunction 正常工作
*/
extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
}>();
withDefaults(
defineProps<{
/**
* 来自 Editor 顶层的 `extendFormState`用于扩展 MForm.formState
* 透传给 CompareForm从而让差异对比时表单 item 中依赖业务上下文的
* `display` / `disabled` filterFunction 正常工作
*/
extendState?: (_state: FormState) => Record<string, any> | Promise<Record<string, any>>;
/**
* 自定义 FormConfig 加载逻辑透传给 CompareForm传入后将接管内置的按 `category`
* 取配置逻辑可通过 `ctx.defaultLoadConfig()` 复用默认结果再做二次加工
*/
loadConfig?: CompareFormLoadConfig;
width?: string;
}>(),
{
width: '900px',
},
);
/** 差异对话框的入参 */
export interface DiffDialogPayload {

View File

@ -498,6 +498,40 @@ export interface HistoryListExtraTab {
}
// #endregion HistoryListExtraTab
// #region CompareForm
/**
* CompareForm
* - node: 节点组件 `type` propsService
* - data-source: 数据源 `type`(base/http/...) dataSourceService
* - code-block: 数据源代码块使
*/
export type CompareCategory = 'node' | 'data-source' | 'code-block';
/**
* `loadConfig`
* 便 FormConfig
*/
export interface CompareFormLoadConfigContext {
/** 对比类型,见 CompareCategory */
category: string;
/** 节点 / 数据源类型 */
type?: string;
/** 数据源代码块场景下的数据源类型 */
dataSourceType?: string;
/**
* FormConfig `category` propsService / dataSourceService /
* `loadConfig`
*/
defaultLoadConfig: () => Promise<FormConfig>;
}
/**
* FormConfig `category`
* `ctx.defaultLoadConfig()`
*/
export type CompareFormLoadConfig = (ctx: CompareFormLoadConfigContext) => FormConfig | Promise<FormConfig>;
// #endregion CompareForm
// #region SideItemKey
export enum SideItemKey {
COMPONENT_LIST = 'component-list',