mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-01 18:52:20 +08:00
feat: support switch menu when add sub models
This commit is contained in:
parent
3dbd75b9e4
commit
dec669a94a
@ -14,7 +14,7 @@ import { FlowModel } from '../../models';
|
||||
import { FlowModelOptions, ModelConstructor } from '../../types';
|
||||
import { FlowSettingsButton } from '../common/FlowSettingsButton';
|
||||
import { withFlowDesignMode } from '../common/withFlowDesignMode';
|
||||
import { AddSubModelButton, SubModelItemsType, mergeSubModelItems } from './AddSubModelButton';
|
||||
import { AddSubModelButton, SubModelItemsType, mergeSubModelItems, AddSubModelContext } from './AddSubModelButton';
|
||||
|
||||
export type BuildCreateModelOptionsType = {
|
||||
defaultOptions: FlowModelOptions;
|
||||
@ -129,12 +129,47 @@ const AddFieldButtonCore: React.FC<AddFieldButtonProps> = ({
|
||||
key: field.name,
|
||||
label: field.title,
|
||||
icon: fieldClass.meta?.icon,
|
||||
unique: true,
|
||||
createModelOptions: buildCreateModelOptions({
|
||||
defaultOptions,
|
||||
collectionField: field,
|
||||
fieldPath: field.name,
|
||||
fieldModelClass: fieldClass,
|
||||
}),
|
||||
toggleDetector: (ctx: AddSubModelContext) => {
|
||||
// 检测是否已存在该字段的子模型
|
||||
const subModels = ctx.model.subModels[subModelKey];
|
||||
|
||||
const checkFieldInStepParams = (subModel: FlowModel): boolean => {
|
||||
const stepParams = subModel.stepParams;
|
||||
|
||||
// 快速检查:如果 stepParams 为空,直接返回 false
|
||||
if (!stepParams || Object.keys(stepParams).length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 遍历所有 flow 和 step 来查找 fieldPath 或 field 参数
|
||||
for (const flowKey in stepParams) {
|
||||
const flowSteps = stepParams[flowKey];
|
||||
if (!flowSteps) continue;
|
||||
|
||||
for (const stepKey in flowSteps) {
|
||||
const stepData = flowSteps[stepKey];
|
||||
if (stepData?.fieldPath === field.name || stepData?.field === field.name) {
|
||||
return true; // 找到匹配,立即返回
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (Array.isArray(subModels)) {
|
||||
return subModels.some(checkFieldInStepParams);
|
||||
} else if (subModels) {
|
||||
return checkFieldInStepParams(subModels);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
allFields.push(fieldItem);
|
||||
}
|
||||
@ -151,7 +186,7 @@ const AddFieldButtonCore: React.FC<AddFieldButtonProps> = ({
|
||||
},
|
||||
];
|
||||
};
|
||||
}, [model, subModelBaseClass, fields, buildCreateModelOptions]);
|
||||
}, [model, subModelBaseClass, fields, buildCreateModelOptions, subModelKey]);
|
||||
|
||||
const fieldItems = useMemo(() => {
|
||||
return mergeSubModelItems([buildFieldItems, appendItems], { addDividers: true });
|
||||
|
@ -8,12 +8,17 @@
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { Switch } from 'antd';
|
||||
import { FlowModel } from '../../models';
|
||||
import { ModelConstructor } from '../../types';
|
||||
import { withFlowDesignMode } from '../common/withFlowDesignMode';
|
||||
import LazyDropdown, { Item, ItemsType } from './LazyDropdown';
|
||||
import _ from 'lodash';
|
||||
|
||||
// ============================================================================
|
||||
// 类型定义
|
||||
// ============================================================================
|
||||
|
||||
export interface AddSubModelContext {
|
||||
model: FlowModel;
|
||||
globals: Record<string, any>;
|
||||
@ -22,85 +27,6 @@ export interface AddSubModelContext {
|
||||
subModelBaseClass?: ModelConstructor;
|
||||
}
|
||||
|
||||
export type SubModelItemsType =
|
||||
| SubModelItem[]
|
||||
| ((ctx: AddSubModelContext) => SubModelItem[] | Promise<SubModelItem[]>);
|
||||
|
||||
/**
|
||||
* 合并多个 SubModelItemsType 的选项
|
||||
*/
|
||||
export interface MergeSubModelItemsOptions {
|
||||
/**
|
||||
* 是否在不同来源之间添加分割线
|
||||
*/
|
||||
addDividers?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并多个不同来源的 SubModelItemsType 成一个
|
||||
*
|
||||
* 支持静态数组和异步函数的混合合并,统一返回异步函数处理所有情况
|
||||
*
|
||||
* @param sources - 要合并的 SubModelItemsType 数组,支持 undefined 和 null(会被过滤)
|
||||
* @param options - 合并选项
|
||||
* @returns 合并后的 SubModelItemsType(如果有多个来源则返回异步函数)
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const mergedItems = mergeSubModelItems([
|
||||
* fieldItems, // 字段 items(静态数组)
|
||||
* customItems, // 自定义 items(静态数组)
|
||||
* async (ctx) => [...], // 动态 items(异步函数)
|
||||
* condition ? extraItems : null, // 条件性 items
|
||||
* ], { addDividers: true });
|
||||
* ```
|
||||
*/
|
||||
export function mergeSubModelItems(
|
||||
sources: (SubModelItemsType | undefined | null)[],
|
||||
options: MergeSubModelItemsOptions = {},
|
||||
): SubModelItemsType {
|
||||
const { addDividers = false } = options;
|
||||
|
||||
// 过滤掉空值
|
||||
const validSources = sources.filter((source): source is SubModelItemsType => source !== undefined && source !== null);
|
||||
|
||||
if (validSources.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (validSources.length === 1) {
|
||||
return validSources[0];
|
||||
}
|
||||
|
||||
// 统一返回异步函数处理所有情况
|
||||
return async (ctx: AddSubModelContext) => {
|
||||
const result: SubModelItem[] = [];
|
||||
|
||||
for (let i = 0; i < validSources.length; i++) {
|
||||
const source = validSources[i];
|
||||
let items: SubModelItem[] = [];
|
||||
|
||||
if (Array.isArray(source)) {
|
||||
items = source;
|
||||
} else {
|
||||
items = await source(ctx);
|
||||
}
|
||||
|
||||
// 添加分割线(除了第一个来源)
|
||||
if (i > 0 && addDividers && items.length > 0) {
|
||||
result.push({
|
||||
key: `divider-${i}`,
|
||||
type: 'divider',
|
||||
} as SubModelItem);
|
||||
}
|
||||
|
||||
result.push(...items);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SubModelItem {
|
||||
key?: string;
|
||||
label?: string;
|
||||
@ -111,68 +37,53 @@ export interface SubModelItem {
|
||||
createModelOptions?:
|
||||
| { use: string; stepParams?: Record<string, any> }
|
||||
| ((item: SubModelItem) => { use: string; stepParams?: Record<string, any> });
|
||||
/**
|
||||
* 是否在 group 内启用搜索功能(仅对 group 类型有效)
|
||||
*/
|
||||
searchable?: boolean;
|
||||
/**
|
||||
* 搜索占位符文本(仅对启用搜索的 group 有效)
|
||||
*/
|
||||
searchPlaceholder?: string;
|
||||
/**
|
||||
* 点击后是否保持下拉菜单打开状态
|
||||
*/
|
||||
keepDropdownOpen?: boolean;
|
||||
unique?: boolean;
|
||||
toggleDetector?: (ctx: AddSubModelContext) => boolean | Promise<boolean>;
|
||||
removeModelOptions?: {
|
||||
customRemove?: (ctx: AddSubModelContext, item: SubModelItem) => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
export type SubModelItemsType =
|
||||
| SubModelItem[]
|
||||
| ((ctx: AddSubModelContext) => SubModelItem[] | Promise<SubModelItem[]>);
|
||||
|
||||
export interface MergeSubModelItemsOptions {
|
||||
addDividers?: boolean;
|
||||
}
|
||||
|
||||
interface AddSubModelButtonProps {
|
||||
/**
|
||||
* 父模型实例
|
||||
*/
|
||||
model: FlowModel;
|
||||
|
||||
/**
|
||||
* 子模型类型列表
|
||||
*/
|
||||
items: SubModelItemsType;
|
||||
|
||||
/**
|
||||
* 子模型基类,传递给 context 供 items 函数使用
|
||||
*/
|
||||
subModelBaseClass?: string | ModelConstructor;
|
||||
|
||||
/**
|
||||
* 子模型类型:'object' 表示单个子模型,'array' 表示子模型数组
|
||||
*/
|
||||
subModelType?: 'object' | 'array';
|
||||
|
||||
/**
|
||||
* 子模型在父模型中的键名
|
||||
*/
|
||||
subModelKey: string;
|
||||
|
||||
/**
|
||||
* 创建后的回调函数
|
||||
*/
|
||||
onModelCreated?: (subModel: FlowModel) => Promise<void>;
|
||||
/**
|
||||
* 添加到父模型后的回调函数
|
||||
*/
|
||||
onSubModelAdded?: (subModel: FlowModel) => Promise<void>;
|
||||
|
||||
/**
|
||||
* 按钮文本,默认为 "Add"
|
||||
*/
|
||||
children?: React.ReactNode;
|
||||
|
||||
/**
|
||||
* 全局设置:点击菜单项后是否保持下拉菜单打开状态
|
||||
* 如果设置为 true,所有菜单项点击后都不会关闭下拉菜单
|
||||
* 单个菜单项的 keepDropdownOpen 属性会覆盖此全局设置
|
||||
*/
|
||||
keepDropdownOpen?: boolean;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 工具函数
|
||||
// ============================================================================
|
||||
|
||||
// 预定义样式对象,避免重复创建
|
||||
const SWITCH_CONTAINER_STYLE = {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
padding: '0 4px',
|
||||
} as const;
|
||||
|
||||
const SWITCH_STYLE = {
|
||||
pointerEvents: 'none' as const,
|
||||
};
|
||||
|
||||
/**
|
||||
* 验证 createModelOptions 的有效性
|
||||
*/
|
||||
@ -183,12 +94,10 @@ const validateCreateModelOptions = (
|
||||
console.warn('No createModelOptions found for item');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createOpts.use) {
|
||||
console.warn('createModelOptions must specify "use" property:', createOpts);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -206,22 +115,143 @@ const handleModelCreationError = async (error: any, addedModel?: FlowModel) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 安全地获取菜单项的创建选项
|
||||
*/
|
||||
const getCreateModelOptions = (item: SubModelItem) => {
|
||||
let createOpts = item.createModelOptions;
|
||||
if (typeof createOpts === 'function') {
|
||||
createOpts = createOpts(item);
|
||||
}
|
||||
return createOpts;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建构建上下文的工厂函数
|
||||
*/
|
||||
const createBuildContext = (model: FlowModel, subModelBaseClass?: string | ModelConstructor): AddSubModelContext => {
|
||||
const globalContext = model.flowEngine.getContext();
|
||||
return {
|
||||
model,
|
||||
globals: globalContext,
|
||||
subModelBaseClass:
|
||||
typeof subModelBaseClass === 'string' ? model.flowEngine.getModelClass(subModelBaseClass) : subModelBaseClass,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 合并多个不同来源的 SubModelItemsType 成一个
|
||||
*/
|
||||
export function mergeSubModelItems(
|
||||
sources: (SubModelItemsType | undefined | null)[],
|
||||
options: MergeSubModelItemsOptions = {},
|
||||
): SubModelItemsType {
|
||||
const { addDividers = false } = options;
|
||||
const validSources = sources.filter((source): source is SubModelItemsType => source !== undefined && source !== null);
|
||||
|
||||
if (validSources.length === 0) return [];
|
||||
if (validSources.length === 1) return validSources[0];
|
||||
|
||||
return async (ctx: AddSubModelContext) => {
|
||||
const result: SubModelItem[] = [];
|
||||
for (let i = 0; i < validSources.length; i++) {
|
||||
const source = validSources[i];
|
||||
const items: SubModelItem[] = Array.isArray(source) ? source : await source(ctx);
|
||||
|
||||
if (i > 0 && addDividers && items.length > 0) {
|
||||
result.push({ key: `divider-${i}`, type: 'divider' } as SubModelItem);
|
||||
}
|
||||
result.push(...items);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 转换器函数
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 创建 Switch 标签的工厂函数
|
||||
*/
|
||||
const createSwitchLabel = (originalLabel: string, isToggled: boolean) => (
|
||||
<div style={SWITCH_CONTAINER_STYLE}>
|
||||
<span>{originalLabel}</span>
|
||||
<Switch size="small" checked={isToggled} style={SWITCH_STYLE} />
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* 检查是否包含 unique 项
|
||||
*/
|
||||
const hasUniqueItems = (items: SubModelItem[]): boolean => {
|
||||
return items.some((item) => item.unique && item.toggleDetector && !item.children);
|
||||
};
|
||||
|
||||
/**
|
||||
* 递归转换 SubModelItem 数组为 LazyDropdown 的 Item 格式
|
||||
*/
|
||||
const transformSubModelItems = (items: SubModelItem[], context: AddSubModelContext): Item[] => {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
children: item.children
|
||||
? typeof item.children === 'function'
|
||||
? async () => {
|
||||
const childrenFn = item.children as (ctx: AddSubModelContext) => SubModelItem[] | Promise<SubModelItem[]>;
|
||||
const result = await childrenFn(context);
|
||||
return transformSubModelItems(result, context);
|
||||
}
|
||||
: transformSubModelItems(item.children as SubModelItem[], context)
|
||||
: undefined,
|
||||
}));
|
||||
const transformSubModelItems = async (items: SubModelItem[], context: AddSubModelContext): Promise<Item[]> => {
|
||||
if (items.length === 0) return [];
|
||||
|
||||
// 批量收集需要异步检测的 unique 项
|
||||
const uniqueItems: Array<{ item: SubModelItem; index: number }> = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
if (item.unique && item.toggleDetector && !item.children) {
|
||||
uniqueItems.push({ item, index: i });
|
||||
}
|
||||
}
|
||||
|
||||
// 批量执行 toggleDetector
|
||||
const toggleResults = await Promise.allSettled(uniqueItems.map(({ item }) => item.toggleDetector!(context)));
|
||||
|
||||
const toggleMap = new Map<number, boolean>();
|
||||
uniqueItems.forEach(({ index }, i) => {
|
||||
const result = toggleResults[i];
|
||||
toggleMap.set(index, result.status === 'fulfilled' ? result.value : false);
|
||||
});
|
||||
|
||||
// 并发转换所有项目
|
||||
const transformPromises = items.map(async (item, index) => {
|
||||
const transformedItem: Item = {
|
||||
key: item.key,
|
||||
label: item.label,
|
||||
type: item.type,
|
||||
disabled: item.disabled,
|
||||
icon: item.icon,
|
||||
searchable: item.searchable,
|
||||
searchPlaceholder: item.searchPlaceholder,
|
||||
keepDropdownOpen: item.keepDropdownOpen,
|
||||
originalItem: item,
|
||||
};
|
||||
|
||||
// 处理 children
|
||||
if (item.children) {
|
||||
if (typeof item.children === 'function') {
|
||||
transformedItem.children = async () => {
|
||||
const childrenFn = item.children as (ctx: AddSubModelContext) => SubModelItem[] | Promise<SubModelItem[]>;
|
||||
const childrenResult = await childrenFn(context);
|
||||
return transformSubModelItems(childrenResult, context);
|
||||
};
|
||||
} else {
|
||||
transformedItem.children = await transformSubModelItems(item.children as SubModelItem[], context);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理开关式菜单项
|
||||
if (item.unique && item.toggleDetector && !item.children) {
|
||||
const isToggled = toggleMap.get(index) || false;
|
||||
const originalLabel = item.label || '';
|
||||
transformedItem.label = createSwitchLabel(originalLabel, isToggled);
|
||||
transformedItem.isToggled = isToggled;
|
||||
transformedItem.unique = true;
|
||||
}
|
||||
|
||||
return transformedItem;
|
||||
});
|
||||
|
||||
return Promise.all(transformPromises);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -234,9 +264,88 @@ const transformItems = (items: SubModelItemsType, context: AddSubModelContext):
|
||||
return transformSubModelItems(result, context);
|
||||
};
|
||||
}
|
||||
return transformSubModelItems(items, context);
|
||||
|
||||
const hasUnique = hasUniqueItems(items as SubModelItem[]);
|
||||
if (hasUnique) {
|
||||
return () => transformSubModelItems(items as SubModelItem[], context);
|
||||
} else {
|
||||
let cachedResult: Item[] | null = null;
|
||||
return async () => {
|
||||
if (!cachedResult) {
|
||||
cachedResult = await transformSubModelItems(items as SubModelItem[], context);
|
||||
}
|
||||
return cachedResult;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 删除处理器
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 从 stepParams 中查找字段路径匹配
|
||||
*/
|
||||
const findFieldInStepParams = (subModel: FlowModel, fieldKey: string): boolean => {
|
||||
const stepParams = subModel.stepParams;
|
||||
if (!stepParams || Object.keys(stepParams).length === 0) return false;
|
||||
|
||||
for (const flowKey in stepParams) {
|
||||
const flowSteps = stepParams[flowKey];
|
||||
if (!flowSteps) continue;
|
||||
|
||||
for (const stepKey in flowSteps) {
|
||||
const stepData = flowSteps[stepKey];
|
||||
if (stepData?.fieldPath === fieldKey || stepData?.field === fieldKey) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建默认删除处理器
|
||||
*/
|
||||
const createDefaultRemoveHandler = (config: {
|
||||
model: FlowModel;
|
||||
subModelKey: string;
|
||||
subModelType: 'object' | 'array';
|
||||
}) => {
|
||||
return async (item: SubModelItem, _context: AddSubModelContext): Promise<void> => {
|
||||
const { model, subModelKey, subModelType } = config;
|
||||
|
||||
if (subModelType === 'array') {
|
||||
const subModels = (model.subModels as any)[subModelKey] as FlowModel[];
|
||||
if (Array.isArray(subModels)) {
|
||||
const createOpts = getCreateModelOptions(item);
|
||||
const targetModel = subModels.find((subModel) => {
|
||||
if (item.key && findFieldInStepParams(subModel, item.key)) return true;
|
||||
return (
|
||||
(subModel as any).constructor.name === createOpts?.use || (subModel as any).uid.includes(createOpts?.use)
|
||||
);
|
||||
});
|
||||
|
||||
if (targetModel) {
|
||||
targetModel.remove();
|
||||
const index = subModels.indexOf(targetModel);
|
||||
if (index > -1) subModels.splice(index, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const subModel = (model.subModels as any)[subModelKey] as FlowModel;
|
||||
if (subModel) {
|
||||
subModel.remove();
|
||||
(model.subModels as any)[subModelKey] = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 主组件
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* 为 FlowModel 实例添加子模型的通用按钮组件
|
||||
*
|
||||
@ -244,7 +353,7 @@ const transformItems = (items: SubModelItemsType, context: AddSubModelContext):
|
||||
* - 支持异步加载 items
|
||||
* - 支持多层级嵌套菜单
|
||||
* - 支持从 flowEngine 全局上下文获取服务
|
||||
*
|
||||
* - 支持 unique 菜单项的开关切换
|
||||
*/
|
||||
const AddSubModelButtonCore = function AddSubModelButton({
|
||||
model,
|
||||
@ -257,27 +366,47 @@ const AddSubModelButtonCore = function AddSubModelButton({
|
||||
children = 'Add',
|
||||
keepDropdownOpen = false,
|
||||
}: AddSubModelButtonProps) {
|
||||
// 构建上下文对象,从 flowEngine 的全局上下文中获取服务
|
||||
const buildContext = useMemo((): AddSubModelContext => {
|
||||
const globalContext = model.flowEngine.getContext();
|
||||
return {
|
||||
model,
|
||||
globals: globalContext,
|
||||
subModelBaseClass:
|
||||
typeof subModelBaseClass === 'string' ? model.flowEngine.getModelClass(subModelBaseClass) : subModelBaseClass,
|
||||
};
|
||||
}, [model, model.flowEngine, subModelBaseClass]);
|
||||
// 构建上下文对象
|
||||
const buildContext = useMemo(
|
||||
() => createBuildContext(model, subModelBaseClass),
|
||||
[model, model.flowEngine, subModelBaseClass],
|
||||
);
|
||||
|
||||
// 创建删除处理器
|
||||
const removeHandler = useMemo(
|
||||
() =>
|
||||
createDefaultRemoveHandler({
|
||||
model,
|
||||
subModelKey,
|
||||
subModelType,
|
||||
}),
|
||||
[model, subModelKey, subModelType],
|
||||
);
|
||||
|
||||
// 点击处理逻辑
|
||||
const onClick = async (info: any) => {
|
||||
const item = info.originalItem as SubModelItem;
|
||||
let createOpts = item.createModelOptions;
|
||||
const clickedItem = info.originalItem || info;
|
||||
const item = clickedItem.originalItem || (clickedItem as SubModelItem);
|
||||
const isToggled = clickedItem.isToggled;
|
||||
const isUnique = clickedItem.unique || item.unique;
|
||||
|
||||
// 如果 createModelOptions 是函数,则调用它获取实际的选项
|
||||
if (typeof createOpts === 'function') {
|
||||
createOpts = createOpts(item);
|
||||
// 处理 unique 菜单项的开关操作
|
||||
if (isUnique && item.toggleDetector && isToggled) {
|
||||
try {
|
||||
if (item.removeModelOptions?.customRemove) {
|
||||
await item.removeModelOptions.customRemove(buildContext, item);
|
||||
} else {
|
||||
await removeHandler(item, buildContext);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to remove sub model:', error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证 createModelOptions 的有效性
|
||||
// 处理添加操作
|
||||
const createOpts = getCreateModelOptions(item);
|
||||
|
||||
if (!validateCreateModelOptions(createOpts)) {
|
||||
return;
|
||||
}
|
||||
@ -293,7 +422,6 @@ const AddSubModelButtonCore = function AddSubModelButton({
|
||||
});
|
||||
|
||||
addedModel.setParent(model);
|
||||
|
||||
await addedModel.configureRequiredSteps();
|
||||
|
||||
if (onModelCreated) {
|
||||
|
@ -22,6 +22,18 @@ export type Item = {
|
||||
searchable?: boolean;
|
||||
searchPlaceholder?: string;
|
||||
keepDropdownOpen?: boolean;
|
||||
/**
|
||||
* 开关状态标记(内部使用)
|
||||
*/
|
||||
isToggled?: boolean;
|
||||
/**
|
||||
* 原始菜单项数据(内部使用)
|
||||
*/
|
||||
originalItem?: any;
|
||||
/**
|
||||
* 是否为唯一项标记(内部使用)
|
||||
*/
|
||||
unique?: boolean;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user