做一个自定义操作按钮

在 NocoBase 中,操作(Action)是区块里的按钮,用于触发业务逻辑——比如「新建」「编辑」「删除」等。这个示例展示怎么用 ActionModel 做自定义操作按钮,并通过 ActionSceneEnum 控制按钮出现的场景。

前置阅读

建议先了解以下内容,开发时会更顺畅:

最终效果

我们要做三个自定义操作按钮,分别对应三种操作场景:

  • 数据表级操作collection)— 出现在区块顶部的操作栏,比如「新建」按钮旁边
  • 记录级操作record)— 出现在表格每行的操作列,比如「编辑」「删除」旁边
  • 两者都适用both)— 两种场景都会出现

完整源码见 @nocobase-example/plugin-simple-action。如果你想直接在本地跑起来看效果:

yarn pm enable @nocobase-example/plugin-simple-action

下面从零开始,一步步搭建这个插件。

第一步:创建插件骨架

在仓库根目录执行:

yarn pm create @my-project/plugin-simple-action

详细说明见 编写第一个插件

第二步:创建操作模型

每个操作需要声明它出现的场景,通过 static scene 属性指定:

场景说明
collectionActionSceneEnum.collection作用于数据表,比如「新建」按钮
recordActionSceneEnum.record作用于单条记录,比如「编辑」「删除」按钮
bothActionSceneEnum.both两种场景都可用

数据表级操作

新建 src/client-v2/models/SimpleCollectionActionModel.tsx

// src/client-v2/models/SimpleCollectionActionModel.tsx
import { ActionModel, ActionSceneEnum } from '@nocobase/client-v2';
import { ButtonProps } from 'antd';
import { tExpr } from '../locale';

export class SimpleCollectionActionModel extends ActionModel {
  static scene = ActionSceneEnum.collection;

  defaultProps: ButtonProps = {
    children: tExpr('Simple collection action'),
  };
}

SimpleCollectionActionModel.define({
  label: tExpr('Simple collection action'),
});

// 通过 registerFlow 监听点击事件,用 ctx.message 给用户反馈
SimpleCollectionActionModel.registerFlow({
  key: 'clickFlow',
  title: tExpr('Simple collection action'),
  on: 'click',
  steps: {
    showMessage: {
      async handler(ctx) {
        ctx.message.success(ctx.t('Collection action clicked'));
      },
    },
  },
});

记录级操作

新建 src/client-v2/models/SimpleRecordActionModel.tsx

// src/client-v2/models/SimpleRecordActionModel.tsx
import { ActionModel, ActionSceneEnum } from '@nocobase/client-v2';
import { ButtonProps } from 'antd';
import { tExpr } from '../locale';

export class SimpleRecordActionModel extends ActionModel {
  static scene = ActionSceneEnum.record;

  defaultProps: ButtonProps = {
    children: tExpr('Simple record action'),
  };
}

SimpleRecordActionModel.define({
  label: tExpr('Simple record action'),
});

// 记录级操作可以通过 ctx.model.context 拿到当前行的数据和索引
SimpleRecordActionModel.registerFlow({
  key: 'clickFlow',
  title: tExpr('Simple record action'),
  on: 'click',
  steps: {
    showMessage: {
      async handler(ctx) {
        const index = ctx.model.context.recordIndex;
        const record = ctx.model.context.record;
        const id = record?.id;
        ctx.message.info(ctx.t('Record action clicked, record ID: {{id}}, row index: {{index}}', { id, index }));
      },
    },
  },
});

两种场景都适用

新建 src/client-v2/models/SimpleBothActionModel.tsx

// src/client-v2/models/SimpleBothActionModel.tsx
import { ActionModel, ActionSceneEnum } from '@nocobase/client-v2';
import { ButtonProps } from 'antd';
import { tExpr } from '../locale';

export class SimpleBothActionModel extends ActionModel {
  static scene = ActionSceneEnum.both;

  defaultProps: ButtonProps = {
    children: tExpr('Simple both action'),
  };
}

SimpleBothActionModel.define({
  label: tExpr('Simple both action'),
});

SimpleBothActionModel.registerFlow({
  key: 'clickFlow',
  title: tExpr('Simple both action'),
  on: 'click',
  steps: {
    showMessage: {
      async handler(ctx) {
        ctx.message.info(ctx.t('Both action clicked'));
      },
    },
  },
});

三种写法的结构一样——区别只在 static scene 的值和按钮文案。每个按钮都通过 registerFlow({ on: 'click' }) 监听点击事件,用 ctx.message 弹出提示,让用户能看到按钮确实生效了。

第三步:添加多语言文件

编辑插件的 src/locale/ 下的翻译文件:

// src/locale/zh-CN.json
{
  "Simple collection action": "简单数据表操作",
  "Simple record action": "简单记录操作",
  "Simple both action": "简单通用操作",
  "Collection action clicked": "数据表操作被点击了",
  "Record action clicked, record ID: {{id}}, row index: {{index}}": "记录操作被点击了,记录 ID:{{id}},行索引:{{index}}",
  "Both action clicked": "通用操作被点击了"
}
// src/locale/en-US.json
{
  "Simple collection action": "Simple collection action",
  "Simple record action": "Simple record action",
  "Simple both action": "Simple both action",
  "Collection action clicked": "Collection action clicked",
  "Record action clicked, record ID: {{id}}, row index: {{index}}": "Record action clicked, record ID: {{id}}, row index: {{index}}",
  "Both action clicked": "Both action clicked"
}
注意

初次添加语言文件需要重启应用才能生效。

关于翻译文件的写法和 tExpr() 的更多用法,详见 i18n 国际化

第四步:在插件中注册

编辑 src/client-v2/plugin.tsx,用 registerModelLoaders 按需加载注册:

// src/client-v2/plugin.tsx
import { Plugin } from '@nocobase/client-v2';

export class PluginSimpleActionClient extends Plugin {
  async load() {
    this.flowEngine.registerModelLoaders({
      SimpleCollectionActionModel: {
        loader: () => import('./models/SimpleCollectionActionModel'),
      },
      SimpleRecordActionModel: {
        loader: () => import('./models/SimpleRecordActionModel'),
      },
      SimpleBothActionModel: {
        loader: () => import('./models/SimpleBothActionModel'),
      },
    });
  }
}

export default PluginSimpleActionClient;

第五步:启用插件

yarn pm enable @my-project/plugin-simple-action

启用后,在表格区块的「配置操作」中就能添加这些自定义操作按钮了。

完整源码

小结

这个示例用到的能力:

能力用法文档
操作按钮ActionModel + static sceneFlowEngine → 操作扩展
操作场景ActionSceneEnum.collection / record / both / allFlowEngine → 操作扩展
菜单注册define({ label })FlowEngine 概述
模型注册this.flowEngine.registerModelLoaders()Plugin 插件
延迟翻译tExpr()i18n 国际化

相关链接