除了CabloyJS提供的基本指令,业务模块还可以提供与具体业务相关的自定义指令

下面,以模块test-party为例,实现两个自定义指令:

  1. partyOver:在Party结束时,通过点击按钮Party Over,把正式副本设置为Over状态
  2. partyOverBulk:在列表页面,对已选中的条目进行批量处理

后端代码

- 指令定义

在模块meta文件的base.atoms.[atomClass].actions节点添加指令定义

src/module/test-party/backend/src/meta.js

base: {
  atoms: {
    party: {
      actions: {
        partyOver: {
          code: 101,
          title: 'PartyOver',
          actionModule: moduleInfo.relativeName,
          actionComponent: 'action',
          icon: { material: 'check_circle_outline' },
          enableOnOpened: true,
          stage: 'formal',
        },
        partyOverBulk: {
          code: 201,
          title: 'PartyOver',
          actionModule: moduleInfo.relativeName,
          actionComponent: 'action',
          icon: { material: 'check_circle_outline' },
          bulk: true,
          select: true,
        },
      },
    },
  },
},
名称 默认值 说明
partyOver/partyOverBulk 指令名称
code 指令代码。自定义指令从101开始
title 指令的标题
actionModule 前端处理组件所属模块名: test-party
actionComponent 前端处理组件名: action
icon 图标
bulk false 批量指令与列表操作相关
select null 对于批量指令,true:只有选择了条目才有效,false:没有选择条目才有效,null:总是有效
enableOnOpened false 对于进入编辑状态的数据是否有效
stage 针对哪个原子阶段有效,在这里只针对formal副本有效

- API路由

定义两个API路由,用于前端调用

  1. 可根据实际业务决定是否需要设置中间件transaction
  2. 必须配置中间件right的meta参数

src/module/test-party/backend/src/routes.js

{ method: 'post', path: 'party/over', controller: 'party', middlewares: 'transaction',
  meta: { right: { type: 'atom', action: 'partyOver' } },
},
{ method: 'post', path: 'party/overBulk', controller: 'party', middlewares: 'transaction',
  meta: { right: { type: 'atom', action: 'partyOverBulk' } },
},

- Controller

添加API路由对应的Controller方法

src/module/test-party/backend/src/controller/party.js

async over() {
  const res = await this.ctx.service.party.over({
    key: this.ctx.request.body.key,
    user: this.ctx.state.user.op,
  });
  this.ctx.success(res);
}

async overBulk() {
  const res = await this.ctx.service.party.overBulk({
    keys: this.ctx.request.body.keys,
    user: this.ctx.state.user.op,
  });
  this.ctx.success(res);
}

- Service

在Service中执行具体的业务逻辑

src/module/test-party/backend/src/service/party.js

async over({ key, user }) {
  await this.ctx.model.party.update({
    id: key.itemId,
    partyOver: 1,
  });
}

async overBulk({ keys, user }) {
  const resKeys = [];
  for (const key of keys) {
    const res = await this._overBulk_item({ key, user });
    if (res) {
      resKeys.push(key);
    }
  }
  return { keys: resKeys };
}

async _overBulk_item({ key, user }) {
  // check right
  const res = await this.ctx.bean.atom.checkRightAction({
    atom: { id: key.atomId }, action: 'partyOver', user,
  });
  if (!res) return false;
  // over
  await this.over({ key, user });
  // ok
  return true;
}

- 原子授权

自定义指令必须进行授权,相应的用户才能在前端使用该指令对应的按钮

src/module/test-party/backend/src/bean/version.manager.js

async init(options) {
  // only in test/local
  if (!app.meta.isTest && !app.meta.isLocal) return;

  // init
  if (options.version === 1) {
    // add role rights
    const roleRights = [
      // custom
      { roleName: 'system', action: 'partyOver', scopeNames: 0 },
      { roleName: 'system', action: 'partyOverBulk' },
    ];
    await this.ctx.bean.role.addRoleRightBatch({ atomClassName: 'party', roleRights });
  }

}

前端代码

- 前端组件定义

在后端定义的自定义指令,会自动在前端渲染成按钮。当点击按钮时,系统会自动调用指令定义中约定的前端组件test-party:action

因此,需要在前端创建一个组件,该组件提供一个约定的方法onAction,用于处理前端逻辑

src/module/test-party/front/src/components/action.js

export default {
  meta: {
    global: false,
  },
  methods: {
    async onAction({ ctx, action, item }) {
      if (action.name === 'partyOver') {
        const key = { atomId: item.atomId, itemId: item.itemId };
        return await this._onActionPartyOver({ ctx, key });
      } else if (action.name === 'partyOverBulk') {
        return await this._onActionPartyOverBulk({ ctx, item });
      }
    },
    async _onActionPartyOver({ ctx, key }) {
      await ctx.$api.post('/test/party/party/over', { key });
      ctx.$meta.eventHub.$emit('atom:action', { key, action: { name: 'save' } });
    },
    async _onActionPartyOverBulk({ ctx, item }) {
      // confirm
      await ctx.$view.dialog.confirm();
      // atomClass
      const atomClass = { id: item.atomClassId };
      // keys
      const selectedAtoms = ctx.bulk.selectedAtoms;
      const keys = selectedAtoms.map(item => {
        return { atomId: item.atomId, itemId: item.itemId };
      });
      // overBulk
      const res = await ctx.$api.post('/test/party/party/overBulk', { atomClass, keys });
      // change
      for (const key of res.keys) {
        // action
        ctx.$meta.eventHub.$emit('atom:action', { key, action: { name: 'save' } });
      }
      // clear selection
      ctx.bulk_clearSelectedAtoms();
      // check result
      if (res.keys.length === keys.length) return true;
      return this.$text('PartyOverBulkNotAllDone');
    },
  },
};

- 前端组件注册

由于该组件被跨模块使用,因此需要进行注册,注册名称为action

src/module/test-party/front/src/components.js

import action from './components/action.js';

export default {
  action,
};