自定义指令
除了CabloyJS提供的基本指令
,业务模块还可以提供与具体业务相关的自定义指令
下面,以模块test-party
为例,实现两个自定义指令:
partyOver
:在Party结束时,通过点击按钮Party Over
,把正式
副本设置为Over
状态partyOverBulk
:在列表页面,对已选中的条目进行批量处理
自定义指令:代码逻辑
一个自定义指令的完整逻辑,需要前端和后端联动,这必然涉及到多个代码文件的创建与变更。为了进一步简化开发步骤,提升开发体验,CabloyJS内置了一个Cli命令
,通过此命令可以快速创建前后端代码骨架
因此,在这里,我们先以模块test-party
为例,来梳理一下自定义指令前端和后端的代码逻辑线索,然后再介绍如何通过Cli命令
进行快速创建
后端代码
- 指令定义
在模块meta
文件的base.atoms.[atomClass].actions
节点添加指令定义
src/suite-vendor/test-party/modules/test-party/backend/src/meta.js
- 1base: {
- 2 atoms: {
- 3 party: {
- 4 actions: {
- 5 partyOver: {
- 6 code: 101,
- 7 title: 'PartyOver',
- 8 actionModule: moduleInfo.relativeName,
- 9 actionComponent: 'action',
- 10 icon: { material: 'check_circle_outline' },
- 11 enableOnOpened: true,
- 12 stage: 'formal',
- 13 },
- 14 partyOverBulk: {
- 15 code: 201,
- 16 title: 'PartyOver',
- 17 actionModule: moduleInfo.relativeName,
- 18 actionComponent: 'action',
- 19 icon: { material: 'check_circle_outline' },
- 20 bulk: true,
- 21 select: true,
- 22 },
- 23 },
- 24 },
- 25 },
- 26},
名称 | 默认值 | 说明 |
---|---|---|
partyOver/partyOverBulk | 指令名称 | |
code | 指令代码。自定义指令从101开始 | |
title | 指令的标题 | |
actionModule | 前端处理组件所属模块名: test-party |
|
actionComponent | 前端处理组件名: action |
|
icon | 图标 | |
bulk | false | 批量指令与列表操作相关 |
select | null | 对于批量指令,true:只有选择了条目才有效,false:没有选择条目才有效,null:总是有效 |
enableOnOpened | false | 对于进入编辑状态的数据 是否有效 |
stage | 针对哪个原子阶段有效,在这里只针对formal 副本有效 |
- API路由
定义两个API路由,用于前端调用
- 可根据实际业务决定是否需要设置中间件
transaction
- 必须配置中间件
right
的meta参数
src/suite-vendor/test-party/modules/test-party/backend/src/routes.js
- 1{ method: 'post', path: 'party/over', controller: 'party', middlewares: 'transaction',
- 2 meta: { right: { type: 'atom', atomClass: 'test-party:party', action: 'partyOver' } },
- 3},
- 4{ method: 'post', path: 'party/overBulk', controller: 'party', middlewares: 'transaction',
- 5 meta: { right: { type: 'atom', atomClass: 'test-party:party', action: 'partyOverBulk' } },
- 6},
- Controller
添加API路由对应的Controller方法
src/suite-vendor/test-party/modules/test-party/backend/src/controller/party.js
- 1async over() {
- 2 const res = await this.ctx.service.party.over({
- 3 key: this.ctx.request.body.key,
- 4 user: this.ctx.state.user.op,
- 5 });
- 6 this.ctx.success(res);
- 7}
- 8
- 9async overBulk() {
- 10 const res = await this.ctx.service.party.overBulk({
- 11 keys: this.ctx.request.body.keys,
- 12 user: this.ctx.state.user.op,
- 13 });
- 14 this.ctx.success(res);
- 15}
- Service
在Service中执行具体的业务逻辑
src/suite-vendor/test-party/modules/test-party/backend/src/service/party.js
- 1async over({ key, user }) {
- 2 await this.ctx.model.party.update({
- 3 id: key.itemId,
- 4 partyOver: 1,
- 5 });
- 6}
- 7
- 8async overBulk({ keys, user }) {
- 9 const resKeys = [];
- 10 for (const key of keys) {
- 11 const res = await this._overBulk_item({ key, user });
- 12 if (res) {
- 13 resKeys.push(key);
- 14 }
- 15 }
- 16 return { keys: resKeys };
- 17}
- 18
- 19async _overBulk_item({ key, user }) {
- 20 // check right
- 21 const res = await this.ctx.bean.atom.checkRightAction({
- 22 atom: { id: key.atomId }, action: 'partyOver', user,
- 23 });
- 24 if (!res) return false;
- 25 // over
- 26 await this.over({ key, user });
- 27 // ok
- 28 return true;
- 29}
- 原子授权
自定义指令必须进行授权,相应的用户才能在前端使用该指令对应的按钮
src/suite-vendor/test-party/modules/test-party/backend/src/bean/version.manager.js
- 1async init(options) {
- 2 // only in test/local
- 3 if (!app.meta.isTest && !app.meta.isLocal) return;
- 4
- 5 // init
- 6 if (options.version === 1) {
- 7 // add role rights
- 8 const roleRights = [
- 9 // custom
- 10 { roleName: 'system', action: 'partyOver', scopeNames: 0 },
- 11 { roleName: 'system', action: 'partyOverBulk' },
- 12 ];
- 13 await this.ctx.bean.role.addRoleRightBatch({ atomClassName: 'party', roleRights });
- 14 }
- 15
- 16}
前端代码
- 前端组件定义
在后端定义的自定义指令,会自动在前端渲染成按钮。当点击按钮时,系统会自动调用指令定义
中约定的前端组件test-party:action
因此,需要在前端创建一个组件,该组件提供一个约定的方法onAction
,用于处理前端逻辑
src/suite-vendor/test-party/modules/test-party/front/src/components/action.js
- 1export default {
- 2 meta: {
- 3 global: false,
- 4 },
- 5 methods: {
- 6 async onAction({ ctx, action, item }) {
- 7 if (action.name === 'partyOver') {
- 8 const key = { atomId: item.atomId, itemId: item.itemId };
- 9 return await this._onActionPartyOver({ ctx, key });
- 10 } else if (action.name === 'partyOverBulk') {
- 11 return await this._onActionPartyOverBulk({ ctx, item });
- 12 }
- 13 },
- 14 async _onActionPartyOver({ ctx, key }) {
- 15 await ctx.$api.post('/test/party/party/over', { key });
- 16 ctx.$meta.eventHub.$emit('atom:action', { key, action: { name: 'save' } });
- 17 },
- 18 async _onActionPartyOverBulk({ ctx, item }) {
- 19 // confirm
- 20 await ctx.$view.dialog.confirm();
- 21 // atomClass
- 22 const atomClass = { id: item.atomClassId };
- 23 // keys
- 24 const selectedAtoms = ctx.bulk.selectedAtoms;
- 25 const keys = selectedAtoms.map(item => {
- 26 return { atomId: item.atomId, itemId: item.itemId };
- 27 });
- 28 // overBulk
- 29 const res = await ctx.$api.post('/test/party/party/overBulk', { atomClass, keys });
- 30 // change
- 31 for (const key of res.keys) {
- 32 // action
- 33 ctx.$meta.eventHub.$emit('atom:action', { key, action: { name: 'save' } });
- 34 }
- 35 // clear selection
- 36 ctx.bulk_clearSelectedAtoms();
- 37 // check result
- 38 if (res.keys.length === keys.length) return true;
- 39 return this.$text('PartyOverBulkNotAllDone');
- 40 },
- 41 },
- 42};
- 前端组件注册
由于该组件被跨模块使用,因此需要进行注册,注册名称为action
src/suite-vendor/test-party/modules/test-party/front/src/components.js
- 1import action from './components/action.js';
- 2
- 3export default {
- 4 action,
- 5};
评论: