有时在工作流开发过程中,我们到目前为止讨论过的工具不足以实现所需的逻辑。通常,每当您需要操作原始输入数据时,例如,在表达式中比较原始输入数据之前或将其保存在上下文变量中之前,都会发生这种情况。在这些情况下,在工作流标记中使用我们的嵌入式 JavaScript (JS) 引擎的选项应该会提供一个可行的解决方案。

在工作流中使用 JavaScript 时,应始终在标记中 <![CDATA[ ... ]]> ,以避免 XML 解析器错误。使用 ?{ ... }?打开和关闭 JS 作用域。您可以使用 从 JS 作用域内部访问 context.variable_name上下文变量。要访问事件数据,您可以类似地使用,例如 event.field

<setvar id=“add_digit_from_speech_command”><context_of>
    workflow</context_of>
    <context_update>
        <param name=“number” type=“long”><![CDATA[ ?{ context.number + Number(event.command.substr(event.command.length - 1, event.command.length)) }? ]]></param>
    </context_update>
</setvar>

正如你在上面的例子中看到的,你可以编写任意的原生JS。这还可以跨越多条生产线和更复杂的处理。您将在下一篇文章中看到更多示例。

嵌入式函数

有一些嵌入式函数可以直接在工作流 XML 中使用,而无需打开 JS 上下文。其中一些示例经常用于特定用例:

  • 存在: exists(#{shelve})
  • toUppercase: toUppercase( '#{material_name}' )
  • toLowercase: toLowercase( '#{material_name}')
  • 修剪: trim( #{material_name} )
  • 包含: contains( #{first_code}, #{second_code})
  • startsWith: startsWith( #{first_code}, #{second_code})
  • endsWith: endsWith( #{first_code}, #{second_code})
  • 等于: equals( #{first_code}, #{second_code})
  • 子字符串: substring( #{material_name}, 0, 3)

下面的示例包含 toUpperCase和  trim, substring函数。

<规则 id=“speak_material”>
    <表达式><![CDATA[ #{event:command} == toUpperCase('#{material_name}') ]]></expression>
    <actions>
        <setvar id=“set_material_type”>
            <context_update>
                <param name=“material_type” type=“string”>trim(substring(#{material_name}, 0, 3))</param>
            </context_update>
        </setvar>
    </actions>
</rule>

上面是一个典型的例子,因为语音命令总是以大写字母发出。如果要将语音命令与工作流中的某些内容进行比较,则也应始终将其转换为大写。

提示和技巧:不要在 param 类型 string标签中使用空格以获得更好的代码可读性,因为它会成为您正在操作的字符串的一部分。例如, <param name="material_type" type="string">trim(substring(#{material_name}, 0, 3)) </param> 即使您使用了 trim,也会导致例如 MAT_ (其中 _ 是空格)。

让我们再看几个 JS 引擎派上用场的用例示例:

动态访问数据

有时您需要动态访问数据(基于另一个上下文变量的内容):

    <setvar id=“set_step”>
        <context_update>
            <参数名称=“step” type=“object”><![CDATA[ ?{context.steps[context.current_step_index]}?]]></param>
        </context_update>
    </setvar>

条件数据操作

虽然您也可以创建多个操作和规则来实现这一点,但 JS 允许简洁:

    <setvar id=“set_text_color”>
        <context_update>
            <参数名称=“label_text_color” type=“string”><![CDATA[ ?{(context.urgent)?'red' : 'black' }?]]></param>
        </context_update>
    </setvar>

对象的生成和操作

JavaScript 还可以帮助您生成或操作对象。在下面的示例中,我们希望使工作人员能够使用语音命令来表示 0-99 的数量。每个语音命令都需要单独添加到语音语法中,但使用 JavaScript,我们可以将其缩短为:

<action id=“add_amount_speech_commands” type=“speech_modify_commands_in_grammar”>
    <参数名称=“插槽”>wf_editor_slot</参数>
    <参数名称=“命令”><![CDATA[ ?{
        Array.apply(null, {length: 100})
             .map(Number.call, Number)
             .map(function(e) { 
                    return { 'name': 'AMOUNT ' + (e), 'description': 'AMOUNT [0-99]'}
                }
        )}? ]]></param>
    <参数名称=“modification”>add_commands</param>
</action>

在表达式中

还有一些用例,JS 在表达式中提供帮助。在下面的示例中,我们处理在第三方设备断开连接时发出的事件。我们使用 JS 搜索一串 MAC 地址,以查找断开连接设备的 MAC。

<rule id=“device_vanished”>
    <expression><![CDATA[ #{event:command}== 'DEVICEVANISHED' && ?{context.mac.search(event.mac)>-1}?]]></expression>
    <actions>
        <action ref=“back_to_start”/>
    </actions>
</rule>

注意: JavaScript 的使用仅限于表达式。将修剪所有表达式的内容,以删除所有可能破坏逻辑的换行符和空格。因此,不能在表达式中使用多行 JavaScript。

通配符小部件

JS 的另一个典型用例是 通配符小部件。由于我们还没有介绍布局,我们不会在这里看一个例子,但 小部件文档 有一个。

📌分配

在组件的当前版本中,我们选择的输出全部为大写,并在下一个组件的 UI 中显示为大写。让我们让它看起来更好一点:

  • 使用 JavaScript 或嵌入式函数将生成的选择保存为更自然的大写字母。

 下载组件(预分配)

溶液

下面是一个示例性解决方案:

<rule id=“choice_made”>
    <expression><![CDATA[ #{event:command} == 'APPLE' || #{event:command} == 'PEAR' ]]></expression><
    actions>
        <setvar id=“save_choice”>
            <context_of>workflow</context_of>
            <context_update>
                <param name=“choice” type=“string”><![CDATA[ ?{ event.command.slice(0,1) + event.command.slice(1).toLowerCase() }? ]]></param>
            </context_update>
        </setvar>
        <action ref=“show_confirmation_dialog”/>
    </actions>
</rule>  

 下载组件(分配后)

在下一课中,我们将最终研究如何设计组件的用户界面。