Skip to content

Action

Action是指可以在Flow, Process, Business Process等对象中调用的Script。

Action需要满足如下条件:

  • 有明确的输入输出参数

  • 有唯一的入口方法

下面是一个是一个计算器Action的示例代码:

ts
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2016-2020. All rights reserved.
 *
 * 
 */

import { Decimal } from 'decimal';
import { Error } from 'error';

export class Input {
    @action.param({ type: "String", required: true, description: "the operation type" })
    op: string;

    @action.param({ type: "Number", required: true, description: "the operation value 1" })
    value1: Decimal;

    @action.param({ type: "Number", required: true, description: "the operation value 2" })
    value2: Decimal;
}

export class Output {
    @action.param({ type: "Number", required: true })
    result: Decimal;
}

export class Calculator {
    @action.method({ input: "Input", output: "Output", description: "do a operation" })
    run(input: Input): Output {
        let output = new Output();
        switch (input.op) {
            case "+":
                output.result = this.sum(input.value1, input.value2);
                break;
            case "-":
                output.result = this.sub(input.value1, input.value2);
                break;
            default:
                throw new Error("00001", `unsupported calculator operator ${input.op}`);
        }

        return output;
    }

    sum(a: Decimal, b: Decimal): Decimal {
        return a.Add(b)
    }

    sub(a: Decimal, b: Decimal): Decimal {
        return a.Sub(b)
    }
}

Action可以通过restful请求调用,发送如下请求参数进行求和计算:

json
{
    "op": "+",
    "value1": 99,
    "value2": 100
}

入口方法定义

使用action.method函数标识Action的调用方法,如上面的Calculator.run, 入口方法有如下要求:

  • 必须是class的实例方法
  • 在一个Action文件中,只能有一个入口方法

action.method函数参数类型MethodOptions定义如下:

ts
interface MethodOptions {
    // 输入参数类型名, 没有输入参数时,请填写为""
    input: string;

    // 输出参数类型名,没有输出参数时,请填写为""
    output: string;

    // 方法标签,默认与方法名相同
    label?: string;

    // 方法描述,默认为空
    description?: string;
}

参数定义

被标识的方法可以有多个输入输出参数,也可以没有。

所有的输入或输入参数必须封装在一个class中,作为实例成员,每一个参数均被action.param注解。

如上面的ActionInput的实例成员。

action.param函数的参数类型ParamOptions定义如下:

ts
interface ParamOptions {
    // 参数类型名, 对应Flow中支持的数据类型。
    type: string;

    // 参数是否是必须的
    required?: boolean;

    // 参数是否是集合类型
    isCollection?: boolean;

    // Schema对象名称,仅在type为Object时有效,表示Object绑定的Schema Object.
    metaName?: string;

    // 参数最小值
    min?: number|string;

    // 参数最大值
    max?: number|string;

    // 参数模式
    pattern?: string;

    // 参数检验提示信息
    message?: string;

    // 参数标签,默认与变量名相同
    label?: string;

    // 参数描述,默认为空
    description?: string;
}

参数类型

因为Action大多数时候是提供给Flow调用,所以输入输出参数类型沿用Flow中的类型定义。

  • Boolean

Boolean类型对应typescript的boolean类型:

ts
@action.param({type: 'Boolean'})
boolVal: boolean;
  • String

String类型对应typescript的string类型:

ts
@action.param({type: 'String'})
stringVal: string;
  • Number

Number类型对应typescript的Decimal类型:

ts
import {Decimal} from 'decimal';

@action.param({type: 'Number'})
numberVal: Decimal;

不能使用typescript的number类型,因为Flow中没有简单的number类型,传给脚本Action的Number数值是一个Decimal对象,不是简单的数值。

  • Date

Date类型对应typescript的Date类型:

ts
@action.param({type: 'Date'})
dateVal: Date;

Date类型是只有年月日,不包含时区信息。

  • Datetime

Datetime类型对应typescript的Date类型:

ts
@action.param({type: 'Datetime'})
dateVal: Date;

Datetime类型包含了年月日时分秒。

  • Struct

Struct类型对应typescript的class或interface类型:

ts
import {Decimal} from 'decimal';

export class Student {
    @action.param({type: 'String'})
    name: string;
    @action.param({type: 'Number'})
    age: Decimal;
}

@action.param({type: 'Student'})
student: Student;

class的成员需要使用action.param装饰。

  • Object

Object类型对应typescript的Object类型,可以通过metaName属性绑定到具体某个Object:

ts
@action.param({type: 'Object', metaName: 'student__cst'})
objectVal: Object;

绑定一个Object后,脚本引擎会按照Object字段的定义信息进行参数校验。

  • Blob

用于接收文件流,如图片,音频等。 接收参数固定为 $data

ts
@action.param({ type: "Blob", required: true, description: "文件流" })
$data: any;
  • File

用于接收 multipart/form-data 格式数据的结构体, 当用 custom api 封装文件上传接口时可以使用。

ts
@action.param({ type: "File", required: true, description: "form data 数据" })
file: http.FormData;
  • Any

Any类型对应typescript的any类型:

ts
@action.param({type: 'Any'})
anyVal: any;

定义数组参数

  • 使用[]表示数组
ts
@action.param({type: 'String[]'})
stringList: string[];
  • 通过isCollection属性来标识参数是否是数组。
ts
@action.param({type: 'String', isCollection: true})
stringList: string[];

isCollection不再推荐使用,为了兼容而保留。

参数检验

required

定义参数是否必须有值。

ts
@action.param({type:'Boolean', required: true})
boolVal: boolean;
@action.param({type:'String', required: false})
stringVal?: string;

required默认值为false, 当required为false,建议变量定义后面追加一个?号,告诉typescript编译器这是一个可选的成员。

min, max

定义参数的的最小值,最大值.

  • Number类型
ts
import {Decimal} from 'decimal';

@action.param({type:'Number', min: 0, max: 200})
age: Decimal;
  • String类型
ts
@action.param({type:'String', min: 0, max: 200, lengthInCharacter: true})
str1: string;

@action.param({type:'String', min: 'zzz', max: 'a'}
str2: string;

min, max值是number类型时,表示字符串的长度的范围,长度按照字节计算,可以把lengthInCharacter设置为true,表示以字符来计数字符串长度。 min, max值是string类型时,表示字符串值的范围。

  • Date类型
ts
@action.param({type: 'Date', min: '2018-1-1', max: '2019-12-31'})
dateVal: Date;

表示日期的取值范围。

  • Datetime类型
ts
@action.param({type: 'Datetime', min: '2018-1-1 00:00:00', max: '2019-12-31 59:59:59'})
dateVal: Date;

表示日期时间的取值范围。

pattern

  • Date类型

指定日期参数的默认layout,可以不指定,将使用javascript内置支持的layout。

ts
@action.param({type:'Date', pattern: 'yyyy-MM-dd'})
dateVal: Date;
  • Datetime类型

指定日期时间参数的默认layout, 可以不指定,将使用javascript内置支持的layout。

ts
@action.param({type:'Datetime', pattern: 'yyyy-MM-dd HH:mm:ss'})
dateVal: Date;
  • String类型

表示字符串符合某种javascript的正则表达式。

支持几种内置的正则表达式:email, url, postalcode, ip, address, phone

ts
@action.param({type:'String', pattern: 'email'})
email: string;

@action.param({type:'String', pattern: 'url'})
url: string;

@action.param({type:'String', pattern: 'postalcode'})
postalCode: string;

@action.param({type:'String', pattern: 'ip'})
ip: string;

@action.param({type:'String', pattern: 'address'})
address: string;

@action.param({type:'String', pattern: 'phone'})
phone: string;

如果不是内置的正则表达式,则需要写出正则表达式的内容:

ts
@action.param({type: 'String', pattern: '^\d{4}-\d{1,2}-\d{1,2}'})
stringVal: string;

message

定义参数值无法通过检验时的错误提示信息:

ts
@action.param({type:'String', pattern: 'email', message: '格式不正确的email邮箱'})
email: string;

常见问题

class定义不要使用default导出

ts
export default class Calculator {

}

增加default关键字后,运行时会提示如下错误:

bash
TypeError: Value is not a object: undefined.

输出参数的成员中不能包含循环引用

ts
export class Input {
    @action.param({type: 'String', required: true})
    name: string;
}

export class Item {
    @action.param({type: 'String'})
    name: string;
    @action.param({type: 'Item'})
    subItems: Item[];
}

export class Output {
    @action.param({type: 'Item'})
    root: Item;
}

export class Action {
    @action.method({input: 'Input', output: 'Output'})
    run(input: Input): Output {
        let item = {
            name: input.name,
            subItems: []
        }

        let out = new Output();

        out.root = item;

        out.root.subItems.push(out.root);
        return out;
    }
}

在上面的示例代码中,out.root.subItems中又包含了out.root本身,构成了一个循环引用。

这种输出参数在如下使用场景下,会报错:

  • 返回给flow, 前端等

  • 作为console.log参数

  • 其它涉及到把对象序列化的场景, 比如JSON.stringify

因为大多数序列化库都不支持循环引用的结构。