= observer(
-
-
-
+ {renderToolbarItems(model, showDeleteButton, showCopyUidButton, flowEngine)}
diff --git a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/MinimalDrawerTest.tsx b/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/MinimalDrawerTest.tsx
deleted file mode 100644
index 3d7167898e..0000000000
--- a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/MinimalDrawerTest.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * This file is part of the NocoBase (R) project.
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
- * Authors: NocoBase Team.
- *
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
- * For more information, please refer to: https://www.nocobase.com/agreement.
- */
-
-import React from 'react';
-import { Button } from 'antd';
-import { openStepSettingsDrawer } from '../StepSettingsDrawer';
-
-/**
- * 最小化的抽屉测试
- */
-
-// 创建一个模拟的模型对象
-const mockModel = {
- uid: 'test-model',
- flowEngine: {
- context: {},
- flowSettings: {
- components: {},
- scopes: {},
- },
- },
- getFlow: (flowKey: string) => {
- if (flowKey === 'testFlow') {
- return {
- key: 'testFlow',
- title: '测试流程',
- steps: {
- drawerStep: {
- title: '抽屉步骤',
- settingMode: 'drawer',
- uiSchema: {
- title: {
- type: 'string',
- title: '标题',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input',
- },
- description: {
- type: 'string',
- title: '描述',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input.TextArea',
- },
- },
- defaultParams: {
- title: '默认标题',
- description: '默认描述',
- },
- },
- },
- };
- }
- return null;
- },
- getStepParams: (flowKey: string, stepKey: string) => {
- return {
- title: '当前标题',
- description: '当前描述',
- };
- },
- setStepParams: (flowKey: string, stepKey: string, params: any) => {
- console.log('设置步骤参数:', { flowKey, stepKey, params });
- },
- save: async () => {
- console.log('保存模型');
- return Promise.resolve();
- },
-};
-
-const MinimalDrawerTest: React.FC = () => {
- const handleOpenDrawer = async () => {
- try {
- const result = await openStepSettingsDrawer({
- model: mockModel,
- flowKey: 'testFlow',
- stepKey: 'drawerStep',
- drawerWidth: 600,
- drawerTitle: '测试抽屉配置',
- });
- console.log('抽屉配置结果:', result);
- } catch (error) {
- console.log('抽屉配置取消或出错:', error);
- }
- };
-
- return (
-
-
最小化抽屉测试
-
这是一个最小化的抽屉测试,用于验证基本功能。
-
-
- );
-};
-
-export default MinimalDrawerTest;
diff --git a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/SimpleDrawerTest.tsx b/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/SimpleDrawerTest.tsx
deleted file mode 100644
index aa7542f2ae..0000000000
--- a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/SimpleDrawerTest.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * This file is part of the NocoBase (R) project.
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
- * Authors: NocoBase Team.
- *
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
- * For more information, please refer to: https://www.nocobase.com/agreement.
- */
-
-import React from 'react';
-import { Button } from 'antd';
-import { FlowModel } from '../../../../../models';
-import { openStepSettings } from '../StepSettings';
-
-/**
- * 简单的抽屉测试示例
- */
-
-// 创建一个简单的测试模型
-class SimpleTestModel extends FlowModel {
- render() {
- return (
-
-
简单抽屉测试
-
点击下面的按钮测试抽屉配置功能
-
-
- );
- }
-}
-
-// 注册简单的测试流程
-SimpleTestModel.registerFlow({
- key: 'testFlow',
- title: '测试流程',
- steps: {
- drawerStep: {
- title: '抽屉步骤',
- settingMode: 'drawer', // 使用抽屉模式
- uiSchema: {
- title: {
- type: 'string',
- title: '标题',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input',
- 'x-component-props': {
- placeholder: '请输入标题',
- },
- },
- description: {
- type: 'string',
- title: '描述',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input.TextArea',
- 'x-component-props': {
- placeholder: '请输入描述',
- rows: 3,
- },
- },
- enabled: {
- type: 'boolean',
- title: '启用',
- 'x-decorator': 'FormItem',
- 'x-component': 'Switch',
- },
- priority: {
- type: 'string',
- title: '优先级',
- enum: [
- { label: '低', value: 'low' },
- { label: '中', value: 'medium' },
- { label: '高', value: 'high' },
- ],
- 'x-decorator': 'FormItem',
- 'x-component': 'Select',
- },
- },
- defaultParams: {
- title: '默认标题',
- description: '默认描述',
- enabled: true,
- priority: 'medium',
- },
- // 简单的处理函数
- handler: (ctx, params) => {
- console.log('执行抽屉步骤:', params);
- return params;
- },
- },
- },
-});
-
-export { SimpleTestModel };
diff --git a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/StepSettingsDrawerExample.tsx b/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/StepSettingsDrawerExample.tsx
deleted file mode 100644
index 966279b088..0000000000
--- a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/StepSettingsDrawerExample.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-/**
- * This file is part of the NocoBase (R) project.
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
- * Authors: NocoBase Team.
- *
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
- * For more information, please refer to: https://www.nocobase.com/agreement.
- */
-
-import React from 'react';
-import { Button, Space } from 'antd';
-import { FlowModel } from '../../../../../models';
-import { openStepSettings, getStepSettingMode } from '../StepSettings';
-
-/**
- * 示例:展示如何使用 settingMode: 'drawer' 配置
- */
-
-// 创建一个示例模型类
-class ExampleModel extends FlowModel {
- render() {
- return (
-
-
示例模型
-
这是一个配置了不同 settingMode 的示例模型
-
-
-
-
-
-
Dialog Step 模式: {getStepSettingMode(this, 'exampleFlow', 'dialogStep')}
-
Drawer Step 模式: {getStepSettingMode(this, 'exampleFlow', 'drawerStep')}
-
-
- );
- }
-}
-
-// 注册示例流程
-ExampleModel.registerFlow({
- key: 'exampleFlow',
- title: '示例流程',
- auto: true,
- steps: {
- // 使用默认的 dialog 模式
- dialogStep: {
- title: '对话框步骤',
- use: 'exampleAction',
- // settingMode 默认为 'dialog'
- uiSchema: {
- message: {
- type: 'string',
- title: '消息内容',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input.TextArea',
- },
- type: {
- type: 'string',
- title: '消息类型',
- enum: [
- { label: '信息', value: 'info' },
- { label: '成功', value: 'success' },
- { label: '警告', value: 'warning' },
- { label: '错误', value: 'error' },
- ],
- 'x-decorator': 'FormItem',
- 'x-component': 'Select',
- },
- },
- defaultParams: {
- message: '这是一个对话框配置的步骤',
- type: 'info',
- },
- },
- // 使用 drawer 模式
- drawerStep: {
- title: '抽屉步骤',
- use: 'exampleAction',
- settingMode: 'drawer', // 配置为使用抽屉模式
- uiSchema: {
- title: {
- type: 'string',
- title: '标题',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input',
- },
- description: {
- type: 'string',
- title: '描述',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input.TextArea',
- },
- priority: {
- type: 'string',
- title: '优先级',
- enum: [
- { label: '低', value: 'low' },
- { label: '中', value: 'medium' },
- { label: '高', value: 'high' },
- ],
- 'x-decorator': 'FormItem',
- 'x-component': 'Radio.Group',
- },
- enabled: {
- type: 'boolean',
- title: '启用',
- 'x-decorator': 'FormItem',
- 'x-component': 'Switch',
- },
- },
- defaultParams: {
- title: '这是一个抽屉配置的步骤',
- description: '抽屉模式提供更大的配置空间',
- priority: 'medium',
- enabled: true,
- },
- },
- },
-});
-
-// 注册示例动作 (需要通过 FlowEngine 实例注册)
-// ExampleModel.registerAction({
-// name: 'exampleAction',
-// title: '示例动作',
-// handler: (ctx, params) => {
-// console.log('执行示例动作:', params);
-// return params;
-// },
-// });
-
-export { ExampleModel };
diff --git a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/TestDrawerFixed.tsx b/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/TestDrawerFixed.tsx
deleted file mode 100644
index 6a38895244..0000000000
--- a/packages/core/flow-engine/src/components/settings/wrappers/contextual/__examples__/TestDrawerFixed.tsx
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * This file is part of the NocoBase (R) project.
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
- * Authors: NocoBase Team.
- *
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
- * For more information, please refer to: https://www.nocobase.com/agreement.
- */
-
-import React from 'react';
-import { Button } from 'antd';
-import { FlowModel } from '../../../../../models';
-import { openStepSettings } from '../StepSettings';
-
-/**
- * 测试修复后的抽屉功能
- */
-
-// 创建一个测试模型
-class TestDrawerModel extends FlowModel {
- render() {
- return (
-
-
测试修复后的抽屉功能
-
点击下面的按钮测试抽屉配置功能
-
-
- );
- }
-}
-
-// 注册测试流程
-TestDrawerModel.registerFlow({
- key: 'testFlow',
- title: '测试流程',
- steps: {
- drawerStep: {
- title: '抽屉步骤',
- settingMode: 'drawer', // 使用抽屉模式
- uiSchema: {
- title: {
- type: 'string',
- title: '标题',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input',
- 'x-component-props': {
- placeholder: '请输入标题',
- },
- },
- description: {
- type: 'string',
- title: '描述',
- 'x-decorator': 'FormItem',
- 'x-component': 'Input.TextArea',
- 'x-component-props': {
- placeholder: '请输入描述',
- rows: 3,
- },
- },
- enabled: {
- type: 'boolean',
- title: '启用',
- 'x-decorator': 'FormItem',
- 'x-component': 'Switch',
- },
- priority: {
- type: 'string',
- title: '优先级',
- enum: [
- { label: '低', value: 'low' },
- { label: '中', value: 'medium' },
- { label: '高', value: 'high' },
- ],
- 'x-decorator': 'FormItem',
- 'x-component': 'Select',
- },
- tags: {
- type: 'array',
- title: '标签',
- 'x-decorator': 'FormItem',
- 'x-component': 'Select',
- 'x-component-props': {
- mode: 'tags',
- placeholder: '请输入标签',
- },
- },
- },
- defaultParams: {
- title: '默认标题',
- description: '默认描述',
- enabled: true,
- priority: 'medium',
- tags: ['测试', '抽屉'],
- },
- // 简单的处理函数
- handler: (ctx, params) => {
- console.log('执行抽屉步骤:', params);
- return params;
- },
- },
- },
-});
-
-export { TestDrawerModel };
diff --git a/packages/core/flow-engine/src/flowSettings.ts b/packages/core/flow-engine/src/flowSettings.ts
index c6712228cc..82e4ef4576 100644
--- a/packages/core/flow-engine/src/flowSettings.ts
+++ b/packages/core/flow-engine/src/flowSettings.ts
@@ -9,23 +9,41 @@
import { define, observable } from '@formily/reactive';
import { openStepSettingsDialog } from './components/settings/wrappers/contextual/StepSettingsDialog';
-import { StepSettingsDialogProps } from './types';
+import { StepSettingsDialogProps, ToolbarItemConfig } from './types';
+import { DefaultSettingsIcon } from './components/settings/wrappers/contextual/DefaultSettingsIcon';
export class FlowSettings {
public components: Record
= {};
public scopes: Record = {};
private antdComponentsLoaded = false;
public enabled: boolean;
+ public toolbarItems: ToolbarItemConfig[] = [];
constructor() {
// 初始默认为 false,由 SchemaComponentProvider 根据实际设计模式状态同步设置
this.enabled = false;
+ // 添加默认的配置项目
+ this.addDefaultToolbarItems();
+
define(this, {
enabled: observable,
});
}
+ /**
+ * 添加默认的工具栏项目
+ * @private
+ */
+ private addDefaultToolbarItems(): void {
+ // 添加基础的配置菜单项目(原有的菜单功能)
+ this.toolbarItems.push({
+ key: 'settings-menu',
+ component: DefaultSettingsIcon,
+ sort: 0, // 默认为0,作为第一个添加的项目
+ });
+ }
+
/**
* 加载 FlowSettings 所需的资源。
* @returns {Promise}
@@ -193,6 +211,105 @@ export class FlowSettings {
this.enabled = false;
}
+ /**
+ * 添加扩展工具栏项目
+ * @param {ToolbarItemConfig} config 项目配置
+ * @example
+ * // 添加一个复制图标组件
+ * const CopyIcon = ({ model }) => {
+ * const handleCopy = () => {
+ * navigator.clipboard.writeText(model.uid);
+ * };
+ * return (
+ *
+ *
+ *
+ * );
+ * };
+ *
+ * flowSettings.addToolbarItem({
+ * key: 'copy',
+ * component: CopyIcon,
+ * sort: 10 // 数字越小越靠右
+ * });
+ *
+ * // 添加下拉菜单项目组件
+ * const MoreActionsIcon = ({ model }) => {
+ * const menuItems = [
+ * { key: 'action1', label: '操作1', onClick: () => console.log('操作1', model) },
+ * { key: 'action2', label: '操作2', onClick: () => console.log('操作2', model) }
+ * ];
+ * return (
+ *
+ *
+ *
+ * );
+ * };
+ *
+ * flowSettings.addToolbarItem({
+ * key: 'more-actions',
+ * component: MoreActionsIcon,
+ * visible: (model) => model.someCondition,
+ * sort: 20 // 数字越大越靠左
+ * });
+ */
+ public addToolbarItem(config: ToolbarItemConfig): void {
+ // 检查是否已存在相同 key 的项目
+ const existingIndex = this.toolbarItems.findIndex((item) => item.key === config.key);
+ if (existingIndex !== -1) {
+ console.warn(`FlowSettings: Toolbar item with key '${config.key}' already exists and will be replaced.`);
+ this.toolbarItems[existingIndex] = config;
+ } else {
+ this.toolbarItems.push(config);
+ }
+
+ // 按 sort 字段反向排序,sort 越小越靠右(先添加的在右边)
+ this.toolbarItems.sort((a, b) => (b.sort || 0) - (a.sort || 0));
+ }
+
+ /**
+ * 批量添加工具栏项目
+ * @param {ToolbarItemConfig[]} configs 项目配置数组
+ * @example
+ * flowSettings.addToolbarItems([
+ * { key: 'copy', component: CopyIcon, sort: 10 },
+ * { key: 'edit', component: EditIcon, sort: 20 }
+ * ]);
+ */
+ public addToolbarItems(configs: ToolbarItemConfig[]): void {
+ configs.forEach((config) => this.addToolbarItem(config));
+ }
+
+ /**
+ * 移除工具栏项目
+ * @param {string} key 项目的唯一标识
+ * @example
+ * flowSettings.removeToolbarItem('copy');
+ */
+ public removeToolbarItem(key: string): void {
+ const index = this.toolbarItems.findIndex((item) => item.key === key);
+ if (index !== -1) {
+ this.toolbarItems.splice(index, 1);
+ }
+ }
+
+ /**
+ * 获取所有工具栏项目配置
+ * @returns {ToolbarItemConfig[]} 所有项目配置
+ */
+ public getToolbarItems(): ToolbarItemConfig[] {
+ return [...this.toolbarItems];
+ }
+
+ /**
+ * 清空所有工具栏项目
+ * @example
+ * flowSettings.clearToolbarItems();
+ */
+ public clearToolbarItems(): void {
+ this.toolbarItems = [];
+ }
+
/**
* 显示单个步骤的配置界面
* @param {StepSettingsDialogProps} props 步骤设置对话框的属性
diff --git a/packages/core/flow-engine/src/types.ts b/packages/core/flow-engine/src/types.ts
index 286c7b6248..4c959d0322 100644
--- a/packages/core/flow-engine/src/types.ts
+++ b/packages/core/flow-engine/src/types.ts
@@ -361,3 +361,17 @@ export interface FieldFlowModelMeta extends FlowModelMeta {
}
export type { ForkFlowModel } from './models';
+
+/**
+ * 工具栏项目配置接口
+ */
+export interface ToolbarItemConfig {
+ /** 项目的唯一标识 */
+ key: string;
+ /** 项目组件,接收 model 作为 props,内部处理所有逻辑 */
+ component: React.ComponentType<{ model: FlowModel; [key: string]: any }>;
+ /** 是否显示项目的条件函数 */
+ visible?: (model: FlowModel) => boolean;
+ /** 排序权重,数字越小越靠右(先添加的在右边) */
+ sort?: number;
+}