基本指令 - 执行策略

对于基本指令,模块a-detail提供了统一的对外API接口,有如下好处:

  1. 封装数据库事务配置
  2. 封装权限判断
  3. 简化业务Bean组件的开发

基本指令 - 执行链

delete指令为例,指令执行链如下:

1. 模块a-detail:提供API路由

src/module-system/a-detail/backend/src/routes.js

  1. 1{ method: 'post', path: 'detail/delete', controller: 'detail', middlewares: 'transaction',
  2. 2 meta: { right: { type: 'detail', action: 4 } },
  3. 3},

2. 任何前端模块:通过/a/detail/atom/delete调用后端API接口

src/module-system/a-detail/front/src/components/detail/action.js

  1. 1const flowTaskId = (meta && meta.flowTaskId) || 0;
  2. 2const key = { detailId: item.detailId, detailItemId: item.detailItemId };
  3. 3await ctx.$api.post('/a/detail/detail/delete', { flowTaskId, key });

3. 模块a-detail: API路由对应Controller方法,组织好参数调用Service方法

src/module-system/a-detail/backend/src/controller/detail.js

  1. 1async delete() {
  2. 2 await this.ctx.service.detail.delete({
  3. 3 key: this.ctx.request.body.key,
  4. 4 user: this.ctx.state.user.op,
  5. 5 });
  6. 6 this.ctx.success();
  7. 7}

4. 模块a-detail: Service方法调用ctx.bean.detail方法

  1. 1async delete({ key, user }) {
  2. 2 return await this.ctx.bean.detail.delete({ key, user });
  3. 3}

5. 模块a-detail: ctx.bean.detail调用具体业务的bean方法

src/module-system/a-detail/backend/src/bean/bean.detail.js

  1. 1async delete({ key, target, user }) {
  2. 2 const detailClass = await ctx.bean.detailClass.getByDetailId({ detailId: key.detailId });
  3. 3 if (!detailClass) ctx.throw.module('a-base', 1002);
  4. 4 if (!key.detailItemId) key.detailItemId = detailClass.detailItemId;
  5. 5 // delete
  6. 6 await this._delete2({ detailClass, key, target, user });
  7. 7}
  8. 8
  9. 9async _delete2({ detailClass, key, target, user }) {
  10. 10 // detail bean
  11. 11 const _moduleInfo = mparse.parseInfo(detailClass.module);
  12. 12 const _detailClass = ctx.bean.detailClass.detailClass(detailClass);
  13. 13 const beanFullName = `${_moduleInfo.relativeName}.detail.${_detailClass.bean}`;
  14. 14 // delete
  15. 15 await ctx.executeBean({
  16. 16 beanModule: _moduleInfo.relativeName,
  17. 17 beanFullName,
  18. 18 context: { detailClass, target, key, user },
  19. 19 fn: 'delete',
  20. 20 });
  21. 21}
  1. 通过key获取业务数据的detailClass信息
  1. 通过detailClass信息构造beanFullName
  1. 通过beanFullName执行ctx.executeBean,从而调用业务模块提供的业务Bean组件。参见:跨模块调用本地Bean:ctx.executeBean

业务Bean组件

由以上基本指令的执行链可以看到,针对具体的业务开发,我们只需要针对明细类型提供一个业务Bean组件即可。所有通用的核心逻辑都由模块a-detail进行封装,我们只需要在业务Bean组件中提供与业务相关的自定义逻辑即可

定义Bean组件

src/module/test-flow/backend/src/bean/detail.purchaseOrder.js

  1. 1module.exports = app => {
  2. 2
  3. 3 class Detail extends app.meta.DetailBase {
  4. 4
  5. 5 async create({ atomKey, detailClass, item, user }) {
  6. 6 // super
  7. 7 const key = await super.create({ atomKey, detailClass, item, user });
  8. 8 // add purchaseOrder detail
  9. 9 const res = await this.ctx.model.purchaseOrderDetail.insert({
  10. 10 atomId: atomKey.atomId,
  11. 11 detailId: key.detailId,
  12. 12 });
  13. 13 // return key
  14. 14 return { detailId: key.detailId, detailItemId: res.insertId };
  15. 15 }
  16. 16
  17. 17 async read({ detailClass, options, key, user }) {
  18. 18 // super
  19. 19 const item = await super.read({ detailClass, options, key, user });
  20. 20 if (!item) return null;
  21. 21 // meta
  22. 22 this._getMeta(item);
  23. 23 // ok
  24. 24 return item;
  25. 25 }
  26. 26
  27. 27 async select({ atomKey, detailClass, options, items, user }) {
  28. 28 // super
  29. 29 await super.select({ atomKey, detailClass, options, items, user });
  30. 30 // meta
  31. 31 for (const item of items) {
  32. 32 this._getMeta(item);
  33. 33 }
  34. 34 }
  35. 35
  36. 36 async write({ detailClass, target, key, item, options, user }) {
  37. 37 // super
  38. 38 await super.write({ detailClass, target, key, item, options, user });
  39. 39 // update purchaseOrder detail
  40. 40 const data = await this.ctx.model.purchaseOrderDetail.prepareData(item);
  41. 41 data.id = key.detailItemId;
  42. 42 // update
  43. 43 await this.ctx.model.purchaseOrderDetail.update(data);
  44. 44 }
  45. 45
  46. 46 async delete({ detailClass, target, key, user }) {
  47. 47 // delete purchaseOrder detail
  48. 48 await this.ctx.model.purchaseOrderDetail.delete({
  49. 49 id: key.detailItemId,
  50. 50 });
  51. 51 // super
  52. 52 await super.delete({ detailClass, target, key, user });
  53. 53 }
  54. 54
  55. 55 _getMeta(item) {
  56. 56 const meta = this._ensureItemMeta(item);
  57. 57 // meta.flags
  58. 58 if (item.quantity > 1) {
  59. 59 meta.flags.push(item.quantity);
  60. 60 }
  61. 61 const amount = (item.amount / 100).toFixed(2);
  62. 62 meta.flags.push(amount);
  63. 63 // meta.summary
  64. 64 meta.summary = item.detailCode;
  65. 65 }
  66. 66
  67. 67 }
  68. 68
  69. 69 return Detail;
  70. 70};

业务Bean组件必须继承基类app.meta.DetailBase

注册Bean组件

src/module/test-flow/backend/src/beans.js

  1. 1const detailPurchaseOrder = require('./bean/detail.purchaseOrder.js');
  2. 2
  3. 3module.exports = app => {
  4. 4 const beans = {
  5. 5 // detail
  6. 6 'detail.purchaseOrder': {
  7. 7 mode: 'app',
  8. 8 bean: detailPurchaseOrder,
  9. 9 },
  10. 10 };
  11. 11 return beans;
  12. 12};
注册名称 场景 所属模块 global beanFullName
purchaseOrder detail test-flow false test-flow.detail.purchaseOrder

Bean组件方法

- create

  1. 调用基类方法生成明细Key,得到key.detailId
  2. 新建业务表明细条目
  3. 返回明细Key
名称 说明
atomKey 原子Key
detailClass 明细类型
item 明细条目数据,前端可以通过item传递更多初始化数据
user 当前操作用户

- read

read业务逻辑一般为空,因为这时对象item已经提取了明细的基本表业务表的数据

如果想附加基本表业务表之外的数据,可在这里直接操作对象item

名称 说明
detailClass 明细类型
options 自定义参数
key 明细Key
user 当前操作用户

- select

select业务逻辑一般为空,因为这时对象items已经提取了明细的基本表业务表的数据

如果想附加基本表业务表之外的数据,可在这里直接操作对象items

名称 说明
detailClass 明细类型
options 自定义参数
items 已经检索出来的数据集
user 当前操作用户

- write

  1. 调用基类方法,更新数据表aDetail的基本信息
  2. 更新业务表明细条目
名称 说明
detailClass 明细类型
target 针对什么目标进行write操作
key 明细Key
item 条目数据
options 自定义参数
user 当前操作用户
  • target

一般而言,target参数来自原子write方法。比如,将原子数据从草稿提交至正式副本时,也会同时把该原子关联的明细数据提交至正式副本,此时target值就是formal

名称 说明
(empty) 保存草稿
draft 从历史副本恢复旧版本,或者从正式副本再次编辑
formal 草稿提交至正式副本
history 正式副本推入历史副本
clone 克隆一个新副本,直接进入草稿编辑状态

- delete

  1. 删除业务表明细条目
  2. 调用基类方法,删除数据表aDetail条目
名称 说明
detailClass 明细类型
key 明细Key
user 当前操作用户