feat(form-schema,form,editor,table): 完善表单配置类型

This commit is contained in:
roymondchen 2026-03-20 17:38:11 +08:00
parent feefd3779e
commit e8714c96c9
25 changed files with 278 additions and 240 deletions

View File

@ -63,7 +63,14 @@ import { computed, inject, nextTick, Ref, ref, useTemplateRef, watch } from 'vue
import type { CodeBlockContent } from '@tmagic/core';
import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design';
import { type ContainerChangeEventData, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
import {
type ContainerChangeEventData,
defineFormConfig,
defineFormItem,
type FormConfig,
MFormBox,
type TableColumnConfig,
} from '@tmagic/form';
import FloatingBox from '@editor/components/FloatingBox.vue';
import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
@ -112,7 +119,7 @@ const diffChange = () => {
difVisible.value = false;
};
const defaultParamColConfig = {
const defaultParamColConfig = defineFormItem<TableColumnConfig>({
type: 'row',
label: '参数类型',
items: [
@ -140,76 +147,79 @@ const defaultParamColConfig = {
],
},
],
};
});
const functionConfig = computed<FormConfig>(() => [
{
text: '名称',
name: 'name',
rules: [{ required: true, message: '请输入名称', trigger: 'blur' }],
},
{
text: '描述',
name: 'desc',
},
{
text: '执行时机',
name: 'timing',
type: 'select',
options: () => {
const options = [
{ text: '初始化前', value: 'beforeInit' },
{ text: '初始化后', value: 'afterInit' },
];
if (props.dataSourceType !== 'base') {
options.push({ text: '请求前', value: 'beforeRequest' });
options.push({ text: '请求后', value: 'afterRequest' });
}
return options;
},
display: () => props.isDataSource,
},
{
type: 'table',
border: true,
text: '参数',
enableFullscreen: false,
enableToggleMode: false,
name: 'params',
dropSort: false,
items: [
const functionConfig = computed(
() =>
defineFormConfig([
{
type: 'text',
label: '参数名',
text: '名称',
name: 'name',
rules: [{ required: true, message: '请输入名称', trigger: 'blur' }],
},
{
type: 'text',
label: '描述',
name: 'extra',
text: '描述',
name: 'desc',
},
codeBlockService.getParamsColConfig() || defaultParamColConfig,
],
},
{
name: 'content',
type: 'vs-code',
options: inject('codeOptions', {}),
autosize: { minRows: 10, maxRows: 30 },
onChange: (formState: FormState | undefined, code: string) => {
try {
// js
getEditorConfig('parseDSL')(code);
{
text: '执行时机',
name: 'timing',
type: 'select',
options: () => {
const options = [
{ text: '初始化前', value: 'beforeInit' },
{ text: '初始化后', value: 'afterInit' },
];
if (props.dataSourceType !== 'base') {
options.push({ text: '请求前', value: 'beforeRequest' });
options.push({ text: '请求后', value: 'afterRequest' });
}
return options;
},
display: () => props.isDataSource,
},
{
type: 'table',
border: true,
text: '参数',
enableFullscreen: false,
enableToggleMode: false,
name: 'params',
dropSort: false,
items: [
{
type: 'text',
label: '参数名',
name: 'name',
},
{
type: 'text',
label: '描述',
name: 'extra',
},
codeBlockService.getParamsColConfig() || defaultParamColConfig,
],
},
{
name: 'content',
type: 'vs-code',
options: inject('codeOptions', {}),
autosize: { minRows: 10, maxRows: 30 },
onChange: (_formState, code: string) => {
try {
// js
getEditorConfig('parseDSL')(code);
return code;
} catch (error: any) {
tMagicMessage.error(error.message);
return code;
} catch (error: any) {
tMagicMessage.error(error.message);
throw error;
}
},
},
]);
throw error;
}
},
},
]) as FormConfig,
);
const parseContent = (content: any) => {
if (typeof content === 'string') {

View File

@ -13,7 +13,7 @@
<script lang="ts" setup>
import { computed, useTemplateRef } from 'vue';
import { type ContainerChangeEventData, type FormConfig, type FormValue, MForm } from '@tmagic/form';
import { type ContainerChangeEventData, type FormItemConfig, type FormValue, MForm } from '@tmagic/form';
import type { CodeParamStatement } from '@editor/type';
import { error } from '@editor/utils';
@ -34,7 +34,7 @@ const emit = defineEmits(['change']);
const formRef = useTemplateRef<InstanceType<typeof MForm>>('form');
const getFormConfig = (items: FormConfig = []) => [
const getFormConfig = (items: FormItemConfig[] = []) => [
{
type: 'fieldset',
items,
@ -51,7 +51,7 @@ const codeParamsConfig = computed(() =>
name,
text,
extra,
fieldConfig: config,
fieldConfig: config as FormItemConfig,
})),
),
);

View File

@ -50,6 +50,7 @@ import {
createValues,
type FieldProps,
filterFunction,
type FormItemConfig,
type FormState,
MSelect,
type SelectConfig,
@ -141,7 +142,9 @@ const onCodeIdChangeHandler = (value: any) => {
changeRecords.push({
propPath: props.prop.replace(`${props.name}`, 'params'),
value: paramsConfig.value.length ? createValues(mForm, paramsConfig.value, {}, props.model.params) : {},
value: paramsConfig.value.length
? createValues(mForm, paramsConfig.value as unknown as FormItemConfig[], {}, props.model.params)
: {},
});
emit('change', value, {

View File

@ -98,7 +98,9 @@ const dataSources = computed(() => dataSourceService.get('dataSources') || []);
const disabledDataSource = computed(() => propsService.getDisabledDataSource());
const type = computed((): string => {
let type = props.config.fieldConfig?.type;
if (!props.config.fieldConfig) return '';
let type = 'type' in props.config.fieldConfig ? props.config.fieldConfig.type : '';
if (typeof type === 'function') {
type = type(mForm, {
model: props.model,

View File

@ -48,6 +48,7 @@ import {
type DataSourceMethodSelectConfig,
type FieldProps,
filterFunction,
type FormItemConfig,
type FormState,
MCascader,
} from '@tmagic/form';
@ -142,7 +143,9 @@ const onChangeHandler = (value: any) => {
changeRecords.push({
propPath: props.prop.replace(`${props.name}`, 'params'),
value: paramsConfig.value.length ? createValues(mForm, paramsConfig.value, {}, props.model.params) : {},
value: paramsConfig.value.length
? createValues(mForm, paramsConfig.value as unknown as FormItemConfig[], {}, props.model.params)
: {},
});
emit('change', value, {

View File

@ -62,14 +62,15 @@ import type {
CodeSelectColConfig,
ContainerChangeEventData,
DataSourceMethodSelectConfig,
DynamicTypeConfig,
EventSelectConfig,
FieldProps,
FormState,
OnChangeHandlerData,
PanelConfig,
TableConfig,
UISelectConfig,
} from '@tmagic/form';
import { MContainer as MFormContainer, MPanel, MTable } from '@tmagic/form';
import { defineFormItem, MContainer as MFormContainer, MPanel, MTable } from '@tmagic/form';
import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX, traverseNode } from '@tmagic/utils';
import { useServices } from '@editor/hooks/use-services';
@ -212,12 +213,12 @@ const actionTypeConfig = computed(() => {
//
const targetCompConfig = computed(() => {
const defaultTargetCompConfig = {
const defaultTargetCompConfig: UISelectConfig = {
name: 'to',
text: '联动组件',
type: 'ui-select',
display: (mForm: FormState, { model }: { model: Record<any, any> }) => model.actionType === ActionType.COMP,
onChange: (MForm: FormState, v: string, { setModel }: OnChangeHandlerData) => {
display: (_mForm, { model }) => model.actionType === ActionType.COMP,
onChange: (_MForm, _v, { setModel }) => {
setModel('method', '');
},
};
@ -226,7 +227,7 @@ const targetCompConfig = computed(() => {
//
const compActionConfig = computed(() => {
const defaultCompActionConfig = {
const defaultCompActionConfig: DynamicTypeConfig = {
name: 'method',
text: '动作',
type: (mForm: FormState | undefined, { model }: any) => {
@ -304,62 +305,68 @@ const dataSourceActionConfig = computed(() => {
});
//
const tableConfig = computed<TableConfig>(() => ({
type: 'table',
name: 'events',
items: [
{
name: 'name',
label: '事件名',
type: eventNameConfig.value.type,
options: (mForm: FormState, { formValue }: any) =>
eventsService.getEvent(formValue.type).map((option: any) => ({
text: option.label,
value: option.value,
})),
},
{
name: 'to',
label: '联动组件',
type: 'ui-select',
},
{
name: 'method',
label: '动作',
type: compActionConfig.value.type,
options: (mForm: FormState, { model }: any) => {
const node = editorService.getNodeById(model.to);
if (!node?.type) return [];
const tableConfig = computed(
() =>
defineFormItem({
type: 'table',
name: 'events',
items: [
{
name: 'name',
label: '事件名',
type: eventNameConfig.value.type,
options: (mForm: FormState, { formValue }: any) =>
eventsService.getEvent(formValue.type).map((option: any) => ({
text: option.label,
value: option.value,
})),
},
{
name: 'to',
label: '联动组件',
type: 'ui-select',
},
{
name: 'method',
label: '动作',
type: compActionConfig.value.type,
options: (mForm: FormState, { model }: any) => {
const node = editorService.getNodeById(model.to);
if (!node?.type) return [];
return eventsService.getMethod(node.type, model.to).map((option: any) => ({
text: option.label,
value: option.value,
}));
},
},
],
}));
return eventsService.getMethod(node.type, model.to).map((option: any) => ({
text: option.label,
value: option.value,
}));
},
},
],
}) as TableConfig,
);
//
const actionsConfig = computed<PanelConfig>(() => ({
type: 'panel',
items: [
{
type: 'group-list',
name: 'actions',
expandAll: true,
enableToggleMode: false,
titlePrefix: '动作',
const actionsConfig = computed(
() =>
defineFormItem({
type: 'panel',
items: [
actionTypeConfig.value,
targetCompConfig.value,
compActionConfig.value,
codeActionConfig.value,
dataSourceActionConfig.value,
{
type: 'group-list',
name: 'actions',
expandAll: true,
enableToggleMode: false,
titlePrefix: '动作',
items: [
actionTypeConfig.value,
targetCompConfig.value,
compActionConfig.value,
codeActionConfig.value,
dataSourceActionConfig.value,
],
},
],
},
],
}));
}) as PanelConfig,
);
//
const isOldVersion = computed(() => {

View File

@ -39,46 +39,48 @@
import { computed, ref } from 'vue';
import type { ContainerChangeEventData, FormValue } from '@tmagic/form';
import { MContainer } from '@tmagic/form';
import { defineFormItem, type MContainer } from '@tmagic/form';
import type { StyleSchema } from '@tmagic/schema';
const direction = ref('');
const config = computed(() => ({
items: [
{
name: `border${direction.value}Width`,
text: '边框宽度',
labelWidth: '68px',
type: 'data-source-field-select',
fieldConfig: {
type: 'text',
const config = computed(() =>
defineFormItem({
items: [
{
name: `border${direction.value}Width`,
text: '边框宽度',
labelWidth: '68px',
type: 'data-source-field-select',
fieldConfig: {
type: 'text',
},
},
},
{
name: `border${direction.value}Color`,
text: '边框颜色',
labelWidth: '68px',
type: 'data-source-field-select',
fieldConfig: {
type: 'colorPicker',
{
name: `border${direction.value}Color`,
text: '边框颜色',
labelWidth: '68px',
type: 'data-source-field-select',
fieldConfig: {
type: 'colorPicker',
},
},
},
{
name: `border${direction.value}Style`,
text: '边框样式',
labelWidth: '68px',
type: 'data-source-field-select',
fieldConfig: {
type: 'select',
options: ['solid', 'dashed', 'dotted'].map((item) => ({
value: item,
text: item,
})),
{
name: `border${direction.value}Style`,
text: '边框样式',
labelWidth: '68px',
type: 'data-source-field-select',
fieldConfig: {
type: 'select',
options: ['solid', 'dashed', 'dotted'].map((item) => ({
value: item,
text: item,
})),
},
},
},
],
}));
],
}),
);
const selectDirection = (d?: string) => (direction.value = d || '');

View File

@ -5,7 +5,7 @@
<script lang="ts" setup>
import { markRaw } from 'vue';
import { ContainerChangeEventData, MContainer } from '@tmagic/form';
import { type ContainerChangeEventData, defineFormItem, type MContainer } from '@tmagic/form';
import type { StyleSchema } from '@tmagic/schema';
import BackgroundPosition from '../components/BackgroundPosition.vue';
@ -21,7 +21,7 @@ const emit = defineEmits<{
change: [v: StyleSchema, eventData: ContainerChangeEventData];
}>();
const config = {
const config = defineFormItem({
items: [
{
name: 'backgroundColor',
@ -39,7 +39,7 @@ const config = {
type: 'data-source-field-select',
fieldConfig: {
type: 'img-upload',
},
} as any,
},
{
name: 'backgroundSize',
@ -74,7 +74,7 @@ const config = {
labelWidth: '68px',
},
],
};
});
const change = (value: StyleSchema, eventData: ContainerChangeEventData) => {
emit('change', value, eventData);

View File

@ -4,7 +4,7 @@
</template>
<script lang="ts" setup>
import { type ContainerChangeEventData, MContainer } from '@tmagic/form';
import { type ContainerChangeEventData, defineFormItem, type MContainer } from '@tmagic/form';
import type { StyleSchema } from '@tmagic/schema';
import Border from '../components/Border.vue';
@ -19,7 +19,7 @@ const emit = defineEmits<{
change: [v: StyleSchema, eventData: ContainerChangeEventData];
}>();
const config = {
const config = defineFormItem({
items: [
{
labelWidth: '68px',
@ -31,7 +31,7 @@ const config = {
},
},
],
};
});
const change = (value: StyleSchema, eventData: ContainerChangeEventData) => {
emit('change', value, eventData);

View File

@ -5,7 +5,7 @@
<script lang="ts" setup>
import { markRaw } from 'vue';
import { ContainerChangeEventData, MContainer } from '@tmagic/form';
import { type ContainerChangeEventData, defineFormItem, type MContainer } from '@tmagic/form';
import type { StyleSchema } from '@tmagic/schema';
import { AlignCenter, AlignLeft, AlignRight } from '../icons/text-align';
@ -20,7 +20,7 @@ const emit = defineEmits<{
change: [v: StyleSchema, eventData: ContainerChangeEventData];
}>();
const config = {
const config = defineFormItem({
items: [
{
type: 'row',
@ -86,7 +86,7 @@ const config = {
],
},
],
};
});
const change = (value: StyleSchema, eventData: ContainerChangeEventData) => {
emit('change', value, eventData);

View File

@ -12,7 +12,7 @@
<script lang="ts" setup>
import { markRaw } from 'vue';
import type { ContainerChangeEventData } from '@tmagic/form';
import type { ChildConfig, ContainerChangeEventData } from '@tmagic/form';
import { defineFormItem, MContainer } from '@tmagic/form';
import type { StyleSchema } from '@tmagic/schema';
@ -180,7 +180,7 @@ const config = defineFormItem({
],
},
],
});
}) as ChildConfig;
const change = (value: string | StyleSchema, eventData: ContainerChangeEventData) => {
emit('change', value, eventData);

View File

@ -3,7 +3,7 @@
</template>
<script lang="ts" setup>
import { ContainerChangeEventData, MContainer } from '@tmagic/form';
import { type ContainerChangeEventData, defineFormItem, type MContainer } from '@tmagic/form';
import type { StyleSchema } from '@tmagic/schema';
const props = defineProps<{
@ -24,7 +24,7 @@ const positionText: Record<string, string> = {
sticky: '粘性定位',
};
const config = {
const config = defineFormItem({
items: [
{
name: 'position',
@ -95,7 +95,7 @@ const config = {
},
},
],
};
});
const change = (value: string | StyleSchema, eventData: ContainerChangeEventData) => {
emit('change', value, eventData);

View File

@ -1,6 +1,6 @@
import { defineFormConfig } from '@tmagic/form';
import { defineFormConfig, type FormConfig } from '@tmagic/form';
export default () =>
export default (): FormConfig =>
defineFormConfig([
{
name: 'id',

View File

@ -1,11 +1,11 @@
import { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/core';
import { CascaderOption, FormConfig, FormState } from '@tmagic/form';
import type { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/core';
import { type CascaderOption, defineFormItem, type FormConfig } from '@tmagic/form';
import { dataSourceTemplateRegExp, getKeysArray, isNumber } from '@tmagic/utils';
import BaseFormConfig from './formConfigs/base';
import HttpFormConfig from './formConfigs/http';
const dataSourceFormConfig = {
const dataSourceFormConfig = defineFormItem({
type: 'tab',
items: [
{
@ -50,7 +50,7 @@ const dataSourceFormConfig = {
},
{
title: '请求参数裁剪',
display: (_formState: FormState, { model }: any) => model.type === 'http',
display: (_formState, { model }) => model.type === 'http',
items: [
{
name: 'beforeRequest',
@ -62,7 +62,7 @@ const dataSourceFormConfig = {
},
{
title: '响应数据裁剪',
display: (_formState: FormState, { model }: any) => model.type === 'http',
display: (_formStat, { model }) => model.type === 'http',
items: [
{
name: 'afterResponse',
@ -73,7 +73,7 @@ const dataSourceFormConfig = {
],
},
],
};
});
const fillConfig = (config: FormConfig): FormConfig => [...BaseFormConfig(), ...config, dataSourceFormConfig];

View File

@ -24,7 +24,7 @@ import {
NODE_DISABLE_DATA_SOURCE_KEY,
} from '@tmagic/core';
import { tMagicMessage } from '@tmagic/design';
import type { ChildConfig, FormConfig, TabConfig, TabPaneConfig } from '@tmagic/form';
import type { ChildConfig, DisplayCondsConfig, FormConfig, TabConfig, TabPaneConfig } from '@tmagic/form';
export const arrayOptions = [
{ text: '包含', value: 'include' },
@ -168,7 +168,7 @@ export const advancedTabConfig: TabPaneConfig = {
],
};
export const displayTabConfig: TabPaneConfig = {
export const displayTabConfig: TabPaneConfig<DisplayCondsConfig> = {
title: '显示条件',
display: (_state, { model }) => model.type !== 'page',
items: [

View File

@ -91,12 +91,10 @@ export interface FormItem {
/** vnode的key值默认是遍历数组时的index */
__key?: string | number;
/** 表单域标签的的宽度,例如 '50px'。支持 auto。 */
labelWidth?: string;
labelWidth?: string | number;
/** label 标签的title属性 */
labelTitle?: string;
className?: string;
/** 表单组件类型 */
type?: string | TypeFunction;
/** 字段名 */
name?: string | number;
/** 额外的提示信息,和 help 类似,当提示文案同时出现时,可以使用这个。 */
@ -132,7 +130,12 @@ export interface FormItem {
labelPosition?: 'top' | 'left' | 'right';
}
export interface ContainerCommonConfig<T extends Record<string, any> = never> {
export interface DynamicTypeConfig extends FormItem {
type: TypeFunction;
[key: string]: any;
}
export interface ContainerCommonConfig<T = never> extends FormItem {
items: FormConfig<T>;
onInitValue?: (
mForm: FormState | undefined,
@ -182,12 +185,12 @@ export interface Input {
placeholder?: string;
}
export type TypeFunction = (
export type TypeFunction<T extends string = string> = (
mForm: FormState | undefined,
data: {
model: FormValue;
},
) => string;
) => T;
export type FilterFunction<T = boolean> = (
mForm: FormState | undefined,
@ -208,6 +211,7 @@ export type FilterFunction<T = boolean> = (
*/
export interface SelectConfigOption {
/** 选项的标签 */
label?: string | SelectOptionTextFunction;
text: string | SelectOptionTextFunction;
/** 选项的值 */
value: any | SelectOptionValueFunction;
@ -499,7 +503,7 @@ export interface CheckboxGroupOption {
*
*/
export interface CheckboxGroupConfig extends FormItem {
type: 'checkbox-group';
type: 'checkbox-group' | 'checkboxGroup';
options: CheckboxGroupOption[] | FilterFunction<CheckboxGroupOption[]>;
}
@ -546,7 +550,7 @@ export interface SelectConfig extends FormItem, Input {
/**
*
*/
export interface LinkConfig<T extends Record<string, any> = never> extends FormItem {
export interface LinkConfig<T = never> extends FormItem {
type: 'link';
href?: string | ((model: Record<string, any>) => string);
css?: {
@ -615,7 +619,7 @@ export interface CascaderConfig extends FormItem, Input {
}
export interface DynamicFieldConfig extends FormItem {
type: 'dynamic-field';
type: 'dynamic-field' | 'dynamicField';
returnFields: (
config: DynamicFieldConfig,
model: Record<any, any>,
@ -631,16 +635,16 @@ export interface DynamicFieldConfig extends FormItem {
/**
*
*/
export interface RowConfig<T extends Record<string, any> = never> extends FormItem {
export interface RowConfig<T = never> extends FormItem {
type: 'row';
span: number;
items: ({ span?: number } & (ChildConfig<T> | EditorChildConfig | NoInfer<T>))[];
items: ({ span?: number } & (ChildConfig<T> | EditorChildConfig | T))[];
}
/**
*
*/
export interface TabPaneConfig<T extends Record<string, any> = never> {
export interface TabPaneConfig<T = never> {
status?: string;
/** 标签页名称,用于关联 model 中的数据 */
name?: string | number;
@ -652,7 +656,7 @@ export interface TabPaneConfig<T extends Record<string, any> = never> {
onTabClick?: (mForm: FormState | undefined, tab: any, data: any) => void;
}
export interface TabConfig<T extends Record<string, any> = never> extends FormItem, ContainerCommonConfig<T> {
export interface TabConfig<T = never> extends FormItem, ContainerCommonConfig<T> {
type: 'tab' | 'dynamic-tab';
tabType?: string;
editable?: boolean;
@ -673,7 +677,7 @@ export interface TabConfig<T extends Record<string, any> = never> extends FormIt
/**
*
*/
export interface FieldsetConfig<T extends Record<string, any> = never> extends FormItem, ContainerCommonConfig<T> {
export interface FieldsetConfig<T = never> extends FormItem, ContainerCommonConfig<T> {
type: 'fieldset';
checkbox?:
| boolean
@ -690,7 +694,7 @@ export interface FieldsetConfig<T extends Record<string, any> = never> extends F
/**
*
*/
export interface PanelConfig<T extends Record<string, any> = never> extends FormItem, ContainerCommonConfig<T> {
export interface PanelConfig<T = never> extends FormItem, ContainerCommonConfig<T> {
type: 'panel';
expand?: boolean;
title?: string;
@ -705,6 +709,7 @@ export interface TableColumnConfig extends FormItem {
items?: FormConfig;
itemsFunction?: (row: any) => FormConfig;
titleTip?: FilterFunction<string>;
type?: string;
}
/**
@ -765,7 +770,7 @@ export interface TableConfig extends FormItem {
sortKey?: string;
}
export interface GroupListConfig<T extends Record<string, any> = never> extends FormItem {
export interface GroupListConfig<T = never> extends FormItem {
type: 'table' | 'groupList' | 'group-list';
span?: number;
enableToggleMode?: boolean;
@ -801,11 +806,11 @@ export interface GroupListConfig<T extends Record<string, any> = never> extends
};
}
interface StepItemConfig<T extends Record<string, any> = never> extends FormItem, ContainerCommonConfig<T> {
interface StepItemConfig<T = never> extends FormItem, ContainerCommonConfig<T> {
title: string;
}
export interface StepConfig<T extends Record<string, any> = never> extends FormItem {
export interface StepConfig<T = never> extends FormItem {
type: 'step';
/** 每个 step 的间距,不填写将自适应间距。支持百分比。 */
space?: string | number;
@ -820,14 +825,14 @@ export interface ComponentConfig extends FormItem {
component: any;
}
export interface FlexLayoutConfig<T extends Record<string, any> = never> extends FormItem, ContainerCommonConfig<T> {
export interface FlexLayoutConfig<T = never> extends FormItem, ContainerCommonConfig<T> {
type: 'flex-layout';
/** flex 子项间距,默认 '16px' */
gap?: string;
}
export type ChildConfig<T extends Record<string, any> = never> =
| (FormItem & Partial<ContainerCommonConfig<T>>)
export type ChildConfig<T = never> =
| ContainerCommonConfig<T>
| TabConfig<T>
| RowConfig<T>
| FieldsetConfig<T>
@ -859,6 +864,6 @@ export type ChildConfig<T extends Record<string, any> = never> =
| ComponentConfig
| FlexLayoutConfig<T>;
export type FormItemConfig<T extends Record<string, any> = never> = ChildConfig<T> | EditorChildConfig<T> | NoInfer<T>;
export type FormItemConfig<T = never> = ChildConfig<T> | DynamicTypeConfig | EditorChildConfig<T> | T;
export type FormConfig<T extends Record<string, any> = never> = FormItemConfig<T>[];
export type FormConfig<T = never> = FormItemConfig<T>[];

View File

@ -2,7 +2,7 @@ import type { DataSourceFieldType, DataSourceSchema } from '@tmagic/schema';
import type { FilterFunction, FormItem, FormItemConfig, FormState, Input } from './base';
export interface DataSourceFieldSelectConfig<T extends Record<string, any> = never> extends FormItem {
export interface DataSourceFieldSelectConfig<T = never> extends FormItem {
type: 'data-source-field-select';
/**
* data
@ -104,6 +104,7 @@ export interface DataSourceSelect extends FormItem, Input {
}
export interface DisplayCondsConfig extends FormItem {
type: 'display-conds';
titlePrefix?: string;
parentFields?: string[] | FilterFunction<string[]>;
}
@ -144,7 +145,7 @@ export interface StyleSetterConfig extends FormItem {
type: 'style-setter';
}
export type EditorChildConfig<T extends Record<string, any> = never> =
export type EditorChildConfig<T = never> =
| DataSourceFieldSelectConfig<T>
| CodeConfig
| CodeLinkConfig

View File

@ -3,7 +3,6 @@ import type { FormConfig, FormItemConfig } from './base';
export * from './base';
export * from './editor';
export const defineFormConfig = <T extends Record<string, any> = never>(config: FormConfig<T>): FormConfig<T> => config;
export const defineFormConfig = <T = never>(config: FormConfig<T>): FormConfig<T> => config;
export const defineFormItem = <T extends Record<string, any> = never>(config: FormItemConfig<T>): FormItemConfig<T> =>
config;
export const defineFormItem = <T = never>(config: FormItemConfig<T>): FormItemConfig<T> => config;

View File

@ -117,19 +117,25 @@ const stepActive = ref(1);
const bodyHeight = ref(`${document.body.clientHeight - 194}px`);
const stepCount = computed(() => {
const { length } = props.config;
for (let index = 0; index < length; index++) {
if (props.config[index].type === 'step') {
return (props.config[index] as StepConfig).items.length;
if (!Array.isArray(props.config)) {
return 0;
}
for (const item of props.config) {
if ('type' in item && item.type === 'step') {
return (item as StepConfig).items.length;
}
}
return 0;
});
const hasStep = computed(() => {
const { length } = props.config;
for (let index = 0; index < length; index++) {
if (props.config[index].type === 'step') {
if (!Array.isArray(props.config)) {
return false;
}
for (const item of props.config) {
if ('type' in item && item.type === 'step') {
return true;
}
}

View File

@ -1,5 +1,5 @@
<template>
<TMagicCol v-show="display && config.type !== 'hidden'" :span="span">
<TMagicCol v-show="display && 'type' in config && config.type !== 'hidden'" :span="span">
<Container
:model="model"
:lastValues="lastValues"
@ -21,7 +21,7 @@ import { computed, inject } from 'vue';
import { TMagicCol } from '@tmagic/design';
import type { ChildConfig, ContainerChangeEventData, FormState } from '../schema';
import type { ContainerChangeEventData, FormItemConfig, FormState } from '../schema';
import { display as displayFunction } from '../utils/form';
import Container from './Container.vue';
@ -34,8 +34,8 @@ const props = defineProps<{
model: any;
lastValues?: any;
isCompare?: boolean;
config: ChildConfig;
labelWidth?: string;
config: FormItemConfig;
labelWidth?: string | number;
expandMore?: boolean;
span?: number;
size?: string;

View File

@ -175,10 +175,10 @@ import { getValueByKeyPath } from '@tmagic/utils';
import MHidden from '../fields/Hidden.vue';
import type {
CheckboxConfig,
ChildConfig,
ComponentConfig,
ContainerChangeEventData,
ContainerCommonConfig,
FormItemConfig,
FormState,
FormValue,
ToolTipConfigType,
@ -198,10 +198,10 @@ const props = withDefaults(
model: FormValue;
/** 需对比的值(开启对比模式时传入) */
lastValues?: FormValue;
config: ChildConfig;
config: FormItemConfig;
prop?: string;
disabled?: boolean;
labelWidth?: string;
labelWidth?: string | number;
expandMore?: boolean;
stepActive?: string | number;
size?: string;
@ -253,7 +253,7 @@ const itemProp = computed(() => {
});
const type = computed((): string => {
let { type } = props.config;
let type = 'type' in props.config ? props.config.type : '';
type = type && filterFunction<string>(mForm, type, props);
if (type === 'form') return '';
if (type === 'container') return '';

View File

@ -1,7 +1,7 @@
import { computed, inject } from 'vue';
import { tMagicMessage } from '@tmagic/design';
import type { FormState } from '@tmagic/form-schema';
import type { FormConfig, FormState } from '@tmagic/form-schema';
import { initValue } from '../utils/form';
@ -86,7 +86,7 @@ export const useAdd = (
}
inputs = await initValue(mForm, {
config: columns,
config: columns as FormConfig,
initValues: inputs,
});
}

View File

@ -3,7 +3,7 @@ import { WarningFilled } from '@element-plus/icons-vue';
import { cloneDeep } from 'lodash-es';
import { type TableColumnOptions, TMagicIcon, TMagicTooltip } from '@tmagic/design';
import type { FormState, TableColumnConfig } from '@tmagic/form-schema';
import type { FormItemConfig, FormState, TableColumnConfig } from '@tmagic/form-schema';
import Container from '../containers/Container.vue';
import type { ContainerChangeEventData } from '../schema';
@ -68,7 +68,7 @@ export const useTableColumns = (
return `${props.prop}${props.prop ? '.' : ''}${index + 1 + currentPage.value * pageSize.value - 1}`;
};
const makeConfig = (config: TableColumnConfig, row: any) => {
const makeConfig = (config: TableColumnConfig, row: any): TableColumnConfig => {
const newConfig = cloneDeep(config);
if (typeof config.itemsFunction === 'function') {
newConfig.items = config.itemsFunction(row);
@ -199,7 +199,7 @@ export const useTableColumns = (
disabled: props.disabled,
prop: getProp($index),
rules: column.rules,
config: makeConfig(column, row),
config: makeConfig(column, row) as FormItemConfig,
model: row,
lastValues: lastData.value[$index],
isCompare: props.isCompare,

View File

@ -23,13 +23,12 @@ import { cloneDeep } from 'lodash-es';
import { getValueByKeyPath } from '@tmagic/utils';
import {
import type {
ChildConfig,
ContainerCommonConfig,
DaterangeConfig,
FilterFunction,
FormConfig,
FormItem,
FormState,
FormValue,
HtmlField,
@ -120,7 +119,8 @@ const initValueItem = function (
) {
const { items } = item as ContainerCommonConfig;
const { names } = item as DaterangeConfig;
const { type, name } = item as FormItem;
const type = 'type' in item ? item.type : '';
const { name } = item;
if (isTableSelect(type) && name) {
value[name] = initValue[name] ?? '';
@ -172,8 +172,8 @@ export const createValues = function (
value: FormValue = {},
) {
if (Array.isArray(config)) {
config.forEach((item: ChildConfig | TabPaneConfig) => {
initValueItem(mForm, item, initValue, value);
config.forEach((item) => {
initValueItem(mForm, item as ChildConfig | TabPaneConfig, initValue, value);
});
}

View File

@ -5,7 +5,7 @@
<MForm
v-else-if="(config.type || config.editInlineFormConfig) && editState[index]"
label-width="0"
:config="config.editInlineFormConfig ?? [config]"
:config="config.editInlineFormConfig ?? [config as FormItemConfig]"
:init-values="editState[index]"
@change="formChangeHandler"
></MForm>
@ -46,7 +46,7 @@
<script lang="ts" setup>
import { TMagicButton, TMagicTag, TMagicTooltip } from '@tmagic/design';
import { type ContainerChangeEventData, MForm } from '@tmagic/form';
import type { FormValue } from '@tmagic/form-schema';
import type { FormItemConfig, FormValue } from '@tmagic/form-schema';
import { setValueByKeyPath } from '@tmagic/utils';
import { ColumnConfig } from './schema';