一,概述
RDS 系统,以天风低代码任务引擎 + JavaScript 在线脚本的组合方式,来支持业务流程二次开发。
本文讲解一些实战案例,供编写业务参考。
二,脚本加载及运行方式
在菜单栏点击【脚本操作】按钮,打开在线脚本页面。
在该页面,可以直接编辑、保存、运行 Javascript 脚本,以及观测脚本执行过程中输出的日志信息。所有的 .js 文件都保存在 data/rds/script/ 目录下。
**在脚本代码中,必须存在唯一的 boot() 方法。**RDS 系统每次启动,会加载脚本,并自动执行一次 boot() 方法。如果脚本被在线修改,也可以手动点击【启动】按钮,重新执行 boot() 方法。boot() 方法中,将进行注册接口、注册事件处理器、注册按钮等操作,这些必须在业务开始前,被执行一次。
三,脚本开发实战案例
3.1 注册接口并创建任务实例
- 如下图所示,创建天风任务:
将任务命名为 ”DemoWindTask“。我们为其设置一个输入参数destination
,字符串类型,并将该参数填入【C机器人通用动作】块的【目标站点名】内。
- 打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
- 点击【启动】按钮,令 RDS 系统重新加载脚本,执行 boot() 方法。点击【日志】按钮,打开日志输出栏。
- 使用 Postman 工具,发送请求:
POST http://127.0.0.1:8080/script-api/postOrder
请求体是 JSON 格式,将 destination
参数赋值为 “AP123”,如图所示:
- 在脚本日志界面,可见日志输出:
同时,在任务管理界面,生成一个 DemoWindTask 的实例。调试成功。
脚本解析:
function boot() {
// 注册一个接口,并关联到 postOrder 方法,且不需要登录权限。
// jj 是 Java - JavaScript Bridge 的简称。是脚本中可以使用的全局对象。
// 关于 jj 提供方法的详细说明,请参考《脚本方法字典》。
// 注意!!!注册的接口,前缀必须是 /script-api/,才能保证不需要登录就可以访问此接口。
jj.registerHandler("POST", "/script-api/postOrder", "postOrder", false);
}
function postOrder(param) {
// 解析 param。包括请求的内容,均是通过 param 字段传入。
var paramObject = JSON.parse(param);
// 使用请求参数,构造任务的输入参数。
let inputParams =
{
// destination 字段,是从 POST 请求的 body 中获取。
destination: paramObject["destination"]
};
// 构造任务参数。
let taskParam = {
// 上文定义的天风任务名称。
taskLabel: "DemoWindTask",
// 注意,输入参数需要格式化为 JSON 字符串。
inputParams: JSON.stringify(inputParams)
};
// 下发任务。注意,任务参数,需要格式化为 JSON 字符串。
jj.createWindTask(JSON.stringify(taskParam));
// 输出日志。使用该方法,可以将日志打印到 RDS 前端日志栏内。
jj.scriptLog("info", "postOrder", "Hello world")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
3.2 通过监听 Modbus Tcp 信号创建任务实例
- 打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
var modbusIp = "127.0.0.1" //modbus ip
var modbusPort = 503 //modbus 端口
var modbusSlaveId = 3 //modbus 主/从服务slaveId
var modbusOffset = 0 //信号读取地址
var modbusAddrType = "4x" //信号数据类型 0x:读线圈 1x:读离散量输入 3x:读输入寄存器 4x:读保持寄存器
function boot() {
// 注册运单方法,rds服务启动4秒后,每隔10秒执行一次运单方法
jj.defineScheduledFunctions(true, 4000, 10000, "postOrder", [])
}
function postOrder(){
// 读取 Modbus 信号值
var signalValue = jj.readSingleModbusValue(modbusIp, modbusPort, modbusSlaveId, modbusAddrType, modbusOffset)
// 信号是发起任务的值
if(signalValue == 1){
// 构造任务输入参数
let inputParams = {
destination:"AP1" //机器人目标站点
}
// 构造任务参数
let orderReq = {
taskLabel:"DemoWindTask", //任务名
inputParams:JSON.stringify(inputParams)
}
// 发起任务
jj.createWindTask(JSON.stringify(orderReq))
// 打印日志
jj.scriptLog("INFO", "postOrder", "post order to wind engine of rds")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- 点击【启动】按钮,**令 RDS 系统重新加载脚本,执行 boot() 方法,RDS 脚本引擎将加载注册的定时方法,按照配置的时间间隔执行 postOrder() 方法。**点击【日志】按钮,打开日志输出栏,可查看方法运行过程中的日志。
3.2.1 利用缓存变量,避免重复创建任务实例
假设场景:
需要机器人从产线出货口 A 处,将料箱运送到仓库入口 B。
上节中的 signalValue 是产线出货口 A 处的光电传感器信号,当该处存在料箱时,signalValue 的值为 1。此时,希望 RDS 自动发起运输任务。
2
3
按上节的脚本代码,在机器人将 A 处的料箱取走前,由于 RDS 每次读取 signalValue
的值都是 1,将导致不断的创建任务实例。本节案例将解决此问题。
思路:针对出货口 A 处的光电传感器信号,当该处存在料箱时,signalValue
的值为 1。在首次满足条件时,可在缓存中记录一个变量,再生成任务。由于当前已经生成任务实例,但 A 处料箱尚未取走,下次轮询仍将满足条件;但通过该变量,可过滤 signalValue
信号,避免重复创建任务实例。然后在天风任务中,当 A处料箱被取走后,清空该缓存变量。
- 脚本实现
const modbusIp = "127.0.0.1" //modbus ip
const modbusPort = 503 //modbus 端口
const modbusSlaveId = 3 //modbus 主/从服务slaveId
const modbusOffset = 0 //信号读取地址
const modbusAddrType = "4x" // data type 0x:Read coil 1x:Read discrete input 3x:Read input register 4x:Read holding register
function boot() {
// 注册运单方法,rds服务启动4秒后,每隔10秒执行一次运单方法
jj.defineScheduledFunctions(true, 4000, 10000, "postOrder", [])
}
function postOrder(){
// 读取 Modbus 信号值
var signalValue= jj.readSingleModbusValue(modbusIp, modbusPort, modbusSlaveId, modbusAddrType, modbusOffset)
// 生成任务之前不仅要先读取 Modbus 生成任务信号,还要读取缓存变量 name
var flag = jj.getCacheParam("name")// 获取缓存变量 name。
// 发起任务的信号值 == 1 && 缓存变量 name != true
if(signalValue == 1 && flag != "true"){
// 构造任务输入参数
let inputParams = {
destination:"AP1" //机器人目标站点
}
// 构造任务参数
let orderReq = {
taskLabel:"test1", //任务名
inputParams:JSON.stringify(inputParams)
}
// 发起任务
jj.createWindTask(JSON.stringify(orderReq))
// 将 name 变量设置为 true。此处仅举例说明,缓存变量的处理,应按实际业务需求进行。
jj.putCacheParam("name", true+"")
// 打印日志
jj.scriptLog("INFO", "postOrder", "post order to wind engine of rds")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
- 天风任务中,需要清空缓存变量
name
。
3.3 注册事件处理器
- 目前 RDS 有如下几种系统事件处理器。
- agvActionDone 动作完成事件。机器人动作完成后触发该事件。
- agvActionStopped 动作终止事件。机器人动作终止后触发该事件。
- agvActionFailed 动作失败事件。机器人动作失败后触发该事件。
- taskDone 任务完成事件。运单任务完成后触发该事件。
- taskStopped 任务终止事件。运单任务终止后触发该事件。
- taskFailed 任务失败事件。任务异常结束后后触发该事件。
- workSiteChanged 库位数据改变事件。数据库保存的库位数据发生改变后触发该事件。
- robotsStatusInfoChanged 机器人errors或fatals信息改变事件。机器人报警信息发生改变后触发该事件。
- robotsStatusDispatchableChanged 机器人接单状态改变事件。机器人接单状态改变后触发该事件。
- 打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
function boot() {
// 注册事件方法,机器人动作完成后,rds触发事件执行该方法
jj.registerTaskEventFunction("agvActionDone")
}
function agvActionDone(param){
//事件数据
var paramJson = JSON.parse(param)
//机器人id
var agvId = paramJson["agvId"]
//站点名称
var siteId = paramJson["workSite"]
//打印日志
jj.scriptLog("INFO", "agvActionDone", "agv action done,agvId=" + agvId)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 点击【启动】按钮,**令 RDS 系统重新加载脚本,执行 boot() 方法,RDS 脚本引擎加载注册的事件方法,如果系统有对应的事件触发,则执行该方法。**点击【日志】按钮,打开日志输出栏,可查看方法运行过程中的日志。
3.3.1 注册按钮
1. 打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
function boot() {
//注册按钮,当点击按钮时,执行绑定事件
jj.registerButton("button", "按钮", "buttonEvent", "red");
}
// 按钮事件
function buttonEvent(){
// 注:该方法没有参数,没有返回值
jj.scriptLog("INFO","buttonEvent","按钮事件执行了");
}
2
3
4
5
6
7
8
9
10
- 点击【启动】按钮,**令 RDS 系统重新加载脚本,执行 boot() 方法,RDS 脚本引擎加载注册的事件方法,b此时脚本页面会出现注册的按钮,如果点击按钮,则执行对应方法。**点击【日志】按钮,打开日志输出栏,可查看方法运行过程中的日志
3.4 查询当前机器人信息
3.4.1 脚本调用示例
var robotInfoStr = jj.getRobotsStatus();
3.4.2 响应示例
https://books.seer-group.com/public/rdscore/master/zh/api/http/robot/robotsStatus.html
3.4.3 脚本解析示例
- 判断是否有空闲机器人,需要使用dispatchable与procBusiness这两个字段共同判断,当dispatchable == true && procBusiness == false时,该机器人空闲。
function boot() {
jj.registerHandler("POST", "/script-api/existIdleRobot", "existIdleRobot", false);
}
function existIdleRobot() {
var robotInfoStr = jj.getRobotsStatus();
var robotInfo = JSON.parse(robotInfoStr);
var report = robotInfo["report"];
var availbleRobot = false;// 是否有空闲机器人
for (var key in report) {
var dispatchable = report[key]["dispatchable"];// 机器人可接单
var procBusiness = report[key]["procBusiness"];// 是否在执行业务相关的运单
availbleRobot = dispatchable && !procBusiness;
return availbleRobot;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3.5 发起 HTTP 请求
- 发起 POST 请求
脚本中添加以下代码:
// 目标url地址
var url = "http://127.0.0.1:8080/test/siteStatus";
function boot() {
// 定时轮询获取目标url的数据
jj.defineScheduledFunctions(true, 10000, 5000, "postRequest", []);
}
// 向目标地址发起POST请求
function postRequest() {
// 请求参数
let param = {
"type": "ALL"
};
// 需要将请求参数转成JSON格式进行传输
let response = jj.requestPost(url, JSON.stringify(param));
var projectResponse = JSON.parse(response);
// 判断目标接口返回的http code码是否为200,一般情况下200的code码代表返回正常。
if(projectResponse["code"] == 200) {
// resBodyJson为接口返回的业务数据,JSON格式。后续开发者可根据业务自行解析处理
let resBodyJson = projectResponse["body"];
jj.scriptLog("INFO", "postRequest", resBodyJson);
} else {
jj.scriptLog("ERROR", "postRequest", "接口请求异常!");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
以上脚本代码,通过发起定时轮询,向目标 URL 发起 POST 请求获取数据,返回数据进行日志打印。
- 发起 GET 请求
脚本中添加以下代码:
// 目标url地址
var url = "http://127.0.0.1:8080/test/siteStatus2";
function boot() {
// 定时轮询获取目标url的数据
jj.defineScheduledFunctions(true, 10000, 5000, "getRequest", []);
}
// 向目标地址发起GET请求
function getRequest() {
// 向url发起请求
let responseJson = jj.requestGet(url);
jj.scriptLog("INFO", "getRequest", responseJson);
}
2
3
4
5
6
7
8
9
10
11
12
以上脚本代码,通过发起定时轮询,向目标URL进行 GET 请求获取数据,并打印返回的数据。
3.6 OPC 通信
- 修改 application.yml 配置文件,启用 OPC 功能。
opc:
enable: true
# 是否匿名连接
isAnonymousConnect: true
# 用户名(非匿名连接)
serverUsername: testUser
# 密码(非匿名连接)
serverPassword: 123456
#opc客户端连接服务的地址
opcuaEndpointUrl: opc.tcp://127.0.0.1:49320
#订阅PLC节点数据,数据变化后发布时间间隔ms
opcuaEndpointSubInterval: 2000
#读写重试次数,-1表示无限制
retry: -1
#读写重试时间间隔,ms
retryInterval: 1000
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
RDS 作为客户端进行 OPC 通信,OPC 配置中主要需修改以下参数:
opc:
# 启用opc
enable: true
#opc客户端连接服务的地址,需根据实际情况修改opc服务地址
opcuaEndpointUrl: opc.tcp://127.0.0.1:49320
2
3
4
5
- OPC 读
脚本中添加以下代码,定时轮询 OPC 通信,读取目标 PLC 的值,并打印结果值。
function boot() {
// 定时轮询获取opc的数据
jj.defineScheduledFunctions(true, 10000, 5000, "readOpc", []);
}
function readOpc() {
// 读取opc,第一个参数simu.test.k1是目标PLC设备的OPC标识(Identifier)
let value = jj.readOpcValue("simu.test.k1");
jj.scriptLog("INFO", "readOpc", "opcua读取结果值:" + value);
}
2
3
4
5
6
7
8
9
打印结果如下:
- OPC 写
脚本中添加以下代码,定时写入 OPC,并打印写入结果。
function boot() {
// 定时写入opc数据
jj.defineScheduledFunctions(true, 10000, 5000, "writeOpc", []);
}
function writeOpc() {
// 写入opc,第一个参数simu.test.k1是目标PLC设备的OPC标识(Identifier)
// 第三个参数是代表写入的数据类型,0:String,1:Boolean,2: Word, 3:Short, 4:Long, 5: DWord
// 此处第三个参数值3代表,写入OPC的值是一个Short类型的值
let result = jj.writeOpcValueByType("simu.test.k1", "21", 3);
jj.scriptLog("INFO", "writeOpc", "opcua写入结果:" + result);
}
2
3
4
5
6
7
8
9
10
11
打印结果如下:
方法返回 true 代表写入成功。
3.7 Modbus TCP 通用方法
3.7.1 读取 Modbus Slave 的内容
打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
var modbusIp = "127.0.0.1" //modbus ip
var modbusPort = 502 //modbus 端口
var modbusSlaveId = 3 //modbus 主/从服务slaveId
var modbusOffset = 0 //信号读取地址
var modbusAddrType = "4x" //信号数据类型 0x:读线圈 1x:读离散量输入 3x:读输入寄存器 4x:读保持寄存器
function boot() {
// 定时读取Modbus数据
jj.defineScheduledFunctions(true, 10000, 5000, "readSingleModbusValue", []);
}
function readSingleModbusValue() {
// 定时读取modbus指定地址位的值
var result = jj.readSingleModbusValue(modbusIp, modbusPort, modbusSlaveId, modbusAddrType, modbusOffset)
jj.scriptLog("INFO", "readSingleModbusValue", "readSingleModbusValue 读取值:" + result);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3.7.2 向 Modbus Slave 写入
打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
var modbusIp = "127.0.0.1" //modbus ip
var modbusPort = 502 //modbus 端口
var modbusSlaveId = 3 //modbus 主/从服务slaveId
var modbusOffset = 0 //信号写入地址
var modbusAddrType = "4x" //信号数据类型 0x:写线圈 4x:写保持寄存器
function boot() {
// 定时写入Modbus数据
jj.defineScheduledFunctions(true, 10000, 5000, "writeSingleModbusValue", []);
}
function writeSingleModbusValue() {
// 定时写入modbus指定地址位的值为1
var result = jj.writeSingleModbusValue(modbusIp, modbusPort, modbusSlaveId, modbusAddrType, modbusOffset, 1)
jj.scriptLog("INFO", "writeSingleModbusValue", "writeSingleModbusValue 写入成功标识:" + result);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
3.8 发送邮件
- 修改 application-biz.yml 配置文件,发送邮件配置如下:
emailConfig:
host: "smtp.qq.com" // 邮件服务器
port: 465 // 端口号
username: "your username" // 发件人邮箱
password: "your password" // 密码
protocol: "smtp" // 协议,默认 smtp
2
3
4
5
6
- 在脚本文件 boot.js 中,将如下代码写入脚本,并点击【保存】。
function boot() {
// 方式一:启动boot时调用一次调用
sendMail()
// 方式二:注册接口发送邮件。关于 jj 提供方法的详细说明,请参考《脚本方法字典》。
jj.registerHandler("POST", "/script-api/sendMail", "sendMail", false);
}
//无参发送邮件,适用于固定邮件内容
function sendMail() {
const messageJson = {
to: "someone@qq.com",
subject: "Daily Meeting",
text: "Meeting Content"
}
jj.sendMail(JSON.stringify(messageJson));
}
//无参发送邮件,适用于动态邮件内容,发送内容可以通过接口指定。
function sendMail(param) {
// 解析 param。包括请求的内容,均是通过 param 字段传入,param 结构见下面的 body 格式。
var paramObject = JSON.parse(param);
var messageJson = {
to: paramObject["to"],
subject: paramObject["subject"],
text: paramObject["text"]
}
jj.sendMail(JSON.stringify(messageJson));
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
通过接口发邮件时,请求体 body 格式为:
{
"to": "someone@qq.com",
"subject": "Daily Meeting",
"text": "Meeting Content"
}
2
3
4
5
3.9 JS脚本GET方式调用接口
打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
function boot() {
//使用GET请求调用接口
jj.registerHandler("GET", "/script-api/{id}/EasyTransferTask", "EasyTransferTask", false);
}
//获取接口里面的动态参数(id)
function EasyTransferTask(params,data){
var paramObject = JSON.parse(data);
let id = paramObject["id"];
//打印我们获取到的请求路径里面动态参数的值
jj.scriptLog("id = " + id,"","");
}
2
3
4
5
6
7
8
9
10
11
12
13
以上脚本代码,通过postman测试调用脚本接口地址http://127.0.0.1:8080/script-api/10086/EasyTransferTask,向目标URL进行 GET 请求获取数据,并打印返回的数据。
日志打印 id的值代表调用成功,其中id值为10086,与脚本接口地址http://127.0.0.1:8080/script-api/10086/EasyTransferTask中的10086对应。
3.10 TCP使用案例
3.10.1 接收TCP数据
脚本中添加以下代码,接收到客户通过TCP传输的数据,并打印结果值。
function boot() {
//需要监听的端口Port,例如:8888。
jj.registerTcpPort(8888);
//注册监听tcp数据事件。
jj.registerTaskEventFunction('listenTcpData');
}
//在此方法中获取监听到的消息。每收到一次消息,调用一次该方法。
function listenTcpData(param){
//取出发送过来的字符串。
var data = JSON.parse(param).data
//打印data信息,观察控制台是否收到该信息。
jj.scriptLog("data = " + data,"","");
}
2
3
4
5
6
7
8
9
10
11
12
13
3.10.2 发送TCP数据
脚本中添加以下代码,定时发送TCP数据,并打印发送结果。
function boot() {
//轮询调用sendTcpMessage方法
jj.defineScheduledFunctions(true, 10000, 5000, "sendTcpMessage", []);
}
//发送消息测试方法
function sendTcpMessage(param) {
//模拟data字符串
var data = "moniyichuanzifuchuan"
//调用jj.sendTcpMessage,传入三个参数,地址,端口,需要发送给的数据。
var result = jj.sendTcpMessage("127.0.0.1",7200,data);
jj.scriptLog("INFO", "sendTcpMessage", "tcp发送消息结果:" + result);
}
2
3
4
5
6
7
8
9
10
11
12
打印结果如下
3.11 任务终止事件响应案例
脚本中添加以下代码,实现任务终止时,复位modbus的信号
function boot() {
// 注册一个接口,并关联到 postOrder 方法,且不需要登录权限。
// jj 是 Java - JavaScript Bridge 的简称。是脚本中可以使用的全局对象。
// 关于 jj 提供方法的详细说明,请参考《脚本方法字典》。
jj.registerTaskEventFunction("taskStopped");
}
function taskStopped(param){
//将param字符串转化为对象,不用修改
var paramJson = JSON.parse(param);
//获取taskLabel参数,通过taskLabel参数来确定是哪一个天风任务被终止
var taskLabel = paramJson["taskLabel"];
//if判断是什么taskLabel,从而执行不同的逻辑。
if(taskLabel == "去空托盘"){
//获取PLC参数
var emptyPlc = new EmptyPlatePlcConfig();
//对PLC进行复位
jj.writeCoilStatus(emptyPlc.host,emptyPlc.port,1,emptyPlc.arrived,false);
jj.writeCoilStatus(emptyPlc.host,emptyPlc.port,1,emptyPlc.operationFinished,false);
}
}
//定义PLC参数
var EmptyPlatePlcConfig = (function () {
function EmptyPlatePlcConfig() {
this.host = "127.0.0.1";
this.port = 501;
this.arrived = 101;
this.canOperation = 102;
this.operationFinished = 103;
this.canLeave = 104;
}
return EmptyPlatePlcConfig;
}());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
taskStopped任务终止事件返回参数示例:
{
"status": "1001",
"taskId": "89cbfba9-d724-46d9-a8a8-71b5a025442d",
"taskLabel": "test",
"taskRecord": {
"createdOn": 1664508083000,
"defId": "89cbfba9-d724-46d9-a8a8-71b5a025442d",
"defLabel": "test",
"defVersion": 6,
"id": "45110942-95b1-466f-b405-8ceb42f699c3",
"inputParams": "[{\"defaultValue\":\"DEFAULT MESSAGE\",\"name\":\"message\"
",\"label\":\"消息\",\"type\":\"String\",\"required\":false}]",
"isDel": 0,
"orderId": {},
"priority": 1,
"rootTaskRecordId": "45110942-95b1-466f-b405-8ceb42f699c3",
"status": 1001,
"taskDefDetail": "{\"inputParams\":[{\"name\":\"message\",\"type\":\"String\",\"label\":\"消息\",\"required\":false,\"defaultValue\":\"DEFAULT MESSAGE\"}],\"outputParams\":[],\"rootBlock\":{\"id\":-1,\"name\":\"-1\",\"blockType\":\"RootBp\",\"children\":{\"default\":[{\"id\":2,\"name\":\"b2\",\"blockType\":\"DelayBp\",\"children\":{},\"inputParams\":{\"timeMillis\":{\"type\":\"Simple\",\"value\":\"20000\"}},\"refTaskDefId\":\"\",\"selected\":false},{\"id\":1,\"name\":\"b1\",\"blockType\":\"SetSiteLockedBp\",\"children\":{},\"inputParams\":{\"siteId\":{\"type\":\"Simple\",\"value\":\"\\t 50-10-03B-01-1\"},\"ifFair\":{\"type\":\"Simple\",\"value\":true}},\"refTaskDefId\":\"\",\"selected\":false}]},\"selected\":false,\"refTaskDefId\":\"\",\"inputParams\":{}}}"
},
"type": 0
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
常用字段说明:
Name | Description |
---|---|
status | 任务状态:1000(运行中)、1001(终止)、1002(暂停)、1003(结束)、1004(异常结束)、1005(重启异常)、1006(异常中断)、1007(手动结束)、1008(已分配) |
taskId | 任务实例ID |
taskLabel | 任务名称 |
createOn | 任务创建时间 |
inputParams | 任务输入参数 |
priority | 任务优先级 |
四,手持操作端开发实战案例
4.1 手持端配置说明
operator:
# 是否允许动态修改手持端首页菜单属性,默认为不允许
runtimeMenuPropsUpdate: false
# 岗位数组
workTypes:
# 岗位id
- id: COMMON-TYPE
# 岗位名
label: 通用岗位
# 工位数组
workStations:
# 工位id
- id: COMMON-STATION
# 工位名
label: 通用工位
# 绑定岗位,未绑定时则不显示
type: COMMON-TYPE
# 需求单配置
demandTask:
# 是否启用需求单功能,true:启用,false:禁用,默认为禁用
enable: true
# 手持端需求单标签页的名称
tabName: 需求单
# 是否显示需求单中的删除按钮,true:显示,false:隐藏,默认为隐藏
showDeleteButton: false
# 需求单响应方法配置
processFuncList:
# 需求单数据的名称
- defLabel: chooseSite
# 需求单详情页点击"下单"后,对应的脚本响应方法名
funcName: findSiteByGroupName
# 数据单
tableShow:
# 是否启用数据单,true:启用,false:禁用,默认为禁用
enable: true
# 数据单自定义名称
tabName: 数据单
showSql:
# 数据单唯一id
- id: ts
# 执行的sql语句 AND LIKE HAVING WHERE 必须是大写
sql: select site_id,locked,locked_by from t_worksite WHERE site_id = {site_id}
# 查询语句自定名称
label: 库位展示
# sql语句注册的查询条件参数
params: [site_id]
# 查询参数的类型,目前只支持string、number两种。和params先后顺序一一对应
paramsType: [string]
# 查询参数显示的信息
paramsTipName: [库位id]
# 手持端表格显示字段
tableHead:
- value: site_id # 需要显示的查询字段
label: 库位id # 手持端页面表头显示名称
- value: locked # 需要显示的查询字段
label: 是否锁定 # 手持端页面表头显示名称
# 字段值转成需要展示的文字
status:
# 当locked这个字段值为0时,页面对应的要显示成未锁定,当值为1时,页面对应的要显示成锁定
- value: 0
label: 未锁定
- value: 1
label: 锁定
- value: locked_by # 需要显示的查询字段
label: 锁定者 # 手持端页面表头显示名称
# 任务菜单数组
orders:
# 菜单id
- menuId: moveTaskChain
# 菜单名
label: 运输任务链
# 下单的响应方法(POST)路由
route: moveTaskChainFunc
# 菜单背景颜色
menuItemBackground: '#ffff33'
# 菜单文字颜色
menuItemTextColor: '#aff2dd'
# 菜单关联的任务定义,用于脚本进行方法(GET)路由
robotTaskDef: moveTaskChain
# 是否禁用菜单,true为禁用,默认为启用。禁用菜单后,菜单将变成灰色,不能点击下单。
disabled: false
# 可查看该菜单的岗位数组
workTypes: [ COMMON-TYPE ]
# 可查看该菜单的工位数组
workStations: [ COMMON-STATION ]
# 下单时是否隐藏查询按钮,true:隐藏,false:显示,默认为隐藏。
canSendTask: true
# 下单界面首部的提示
tip: 运输任务链
# 点击下单按钮后,弹出的提示性文本
confirmMessage: 确定发起运输任务链吗?
# 菜单组件列表
params:
# 菜单组件名
- name: fromSite
# 菜单组件类型如下:
# text:单行文本,textarea:多行文本,select:单选下拉菜单,selectField:多选下拉菜单
input: text
# 菜单组件提示文字
label: 物料缓存库位
- name: matSite
input: select
label: 放置物料的库位
# 静态下拉菜单,该下拉菜单的所有选项需事先在配置文件中配置完成
options:
# 下拉菜单选项值
- value: buf-1
# 下拉菜单选项文字
label: 物料缓存位1
- value: buf-2
label: 物料缓存位2
- name: traySite
input: select
label: 选择空托盘的库位
# 动态下拉菜单。它的数据来源自脚本的getForkSiteList方法,即在脚本中要定义名为
# getForkSiteList的数据接口
dynamicOptionsSource: getForkSiteList
# 下拉菜单是否进行懒加载。true:进行懒加载,false:放弃懒加载。
# 下拉菜单懒加载意味着用户只有点击下拉菜单时,下拉菜单才会渲染其中的选项数据,
# 它的数据不会提前加载。
lazyGetSource: false
- name: toSite
input: select
label: 放置空托盘的库位
options:
# 下拉菜单选项值
- value: tray-1
# 下拉菜单选项文字
label: 托盘缓存位1
# 静态多级联动菜单配置
checkParent:
# matSite为该下拉菜单选项绑定的同级菜单组件名,一旦用户在名
# 为matSite的下拉菜单中变更了选项,该下拉菜单的选项将跟着变化
- parent: matSite
# 用户在名为matSite的下拉菜单中选择了值为buf-1的选项,
# value: tray-1的下拉菜单选项就会动态显示出来供用户选择
value: [ buf-1 ]
- value: tray-2
label: 托盘缓存位2
checkParent:
- parent: matSite
value: [ buf-2 ]
- name: actionRecord
# 多行文本
input: textarea
# 多行文本框的行数
multiple: 3
# 菜单组件提示文字
label: 操作记录
- name: componentId
input: text
label: 组件id
# hidden 属性代表名为 componentId 的菜单组件在界面上隐藏
hidden: true
# 组件隐藏时,默认填充的值(适用于 text 和 textarea 类型的组件)
defaultValue: "id1"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
4.2 创建基本运输任务
1.创建天风任务,如下图所示:
将任务命名为EasyTransferTask
。为其设置两个输入参数from
,to
,字符串类型。将第一个参数from
填入【关键路径】内。
并将这两个参数,分别填入两个【C机器人通用动作】块的【目标站点名】内。
2.打开配置文件,按以下方式配置:
rdscore:
baseUrl: http://127.0.0.1:8088
operator:
orders:
- menuId: moveTaskChain
label: 简单运输任务 # 手持端选项的提示说明
menuItemBackground: '#32CD32' # 手持端选项的背景颜色
menuItemTextColor: black # 手持端字体的颜色
route: EasyTransferTask # boot.js 脚本里面,对手持端下单的响应方法(POST)路由
tip: 简单运输任务
confirmMessage: 确定下单吗? # 点击下单按钮之后的弹窗提示
params:
- name: from
input: text # 采用输入或扫码的方式录入参数
label: 请选择起点库位
- name: to
input: text # 采用输入或扫码的方式录入参数
label: 请选择终点库位
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3.打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
注意:后面有//------更改 的代表着根据需求可能需要修改。没有的话代表无需更改。
const version = "1.0";
function boot() {
//按手持端配置里面写的路由进行注册
//下例为:手持端配置中 router:EasyTransferTask 。故此处写/EasyTransferTask,后面"EasyTransferTask",引号的内容也需要与router里面配置的一致
//若手持端配置中 router:task。则应写成 jj.registerHandler("POST", "/script-api/task", "task", false);
jj.registerHandler("POST", "/script-api/EasyTransferTask", "EasyTransferTask", false); //------更改
}
//注册完成后,需要通过下方函数实现,函数名根据自己配置的路由,在此例中路由配置为router:EasyTransferTask
//则实现的函数也为EasyTransferTask
function EasyTransferTask(param){//------更改
//注意!!!!!!!后面有//------更改 的代表着可能需要修改。没有的话代表无需更改
//1.对手持端参数进行处理,转换格式(无需更改)
jj.getLogger().info("下单接口参数:" + param);
var paramJson = JSON.parse(param);
var params = paramJson["params"];
/*2.读取手持端传来的参数,(依据实际情况进行更改)
若传入参数个数等于1:保留 ```let from = params[0]["value"];``` ,将 ```let to = params[1]["value"];``` 删除。
若传入参数等于2:保持原状即可。
若传入参数大于2;则按规则增加代码,例如:传入参数为3个,则增加 ```let site = params[2]["value"];```。
在读取手持端传来的参数时,在一下几点需要注意:
1.等号左边参数的命名,对应于天风任务中[任务输入参数]-->[变量名],在本例中,天风任务写的传入变量名分别为 from , to.故在此脚本中,也命名为 from , to。
2.params[]中的数值0对应的是第一个参数,1对应的是第二个参数,以此类推第三个参数则为params[2]。。。
*/
let from = params[0]["value"];//------更改
let to = params[1]["value"];//------更改
/*3.判断输入参数为空,假如参数有任一参数为空,则在手持端进行提示。
1.if (from == "" || to == "") 这一行,需要根据实际的参数数量增删,以及根据实际参数的命名进行变更。
2. || 此符号表达的意思是 或运算 ,符号两边只要有任意一个条件成立,则执行下述代码
3.如果有三个或以上参数需要判断,则表达式为 :if (... || ... || ... || ...)
4.operatorResponse.msg = "请输入起点库位或终点库位"; 根据实际需要的弹窗信息进行更改
*/
if (from == "" || to == "") { //------更改
jj.getLogger().info("参数为空!!!!!1");
var res = { code:400, msg: "请输入起点库位或终点库位" }
return { code: 400, body: JSON.stringify(res) };
}
try {
//4.将前面代码获取到的 from,to 塞入inputParams里面,需要注意的点如下
/*
1. :号左右两边,命名严格一致,都对应于天风任务中[任务输入参数]-->[变量名]的命名
2. 如果需要增加,例如天风任务中[任务输入参数]-->[变量名],除了有 from,to 之外还有 site ,则增加一下代码 ```site: site,```
3. 如果需要删除,直接删除对应行即可
*/
let inputParams = {
from: from, //------更改
to: to, //------更改
};
//5.生成天风任务
//需要将 taskLabel: 后面的内容改成对应的天风任务的任务名,此例为 EasyTransferTask。
let taskParam = {
taskLabel: "EasyTransferTask",//------更改
inputParams: JSON.stringify(inputParams),
};
jj.createWindTask(JSON.stringify(taskParam));
var res = { code:200, msg: "下单成功" }
return { code: 200, body: JSON.stringify(res) };
} catch (error) {
jj.getLogger().error("create tss task error", error);
var res = { code:400, msg: "fail" }
return { code: 400, body: JSON.stringify(res) };
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

4.打开手持端界面进行下单。

4.3 下单时通知任务发起者
注意:1.以下描述的两例,全都包含在创建基本任务的脚本中,具体见【创建基本运输任务】。
2.后面有//------更改 的代表着根据需求可能需要修改,没有的话代表无需更改。
1.任务发起成功通知任务发起者。
operatorResponse.code = 200;
operatorResponse.msg = "下单成功";
response.body = JSON.stringify(operatorResponse);
return response;
2
3
4
2.任务发起失败时通知任务发起者。
---由于有输入参数为空导致任务发起失败。
let from = params[0]["value"];//------更改
let to = params[1]["value"];//------更改
/*3.判断输入参数为空,假如参数有任一参数为空,则在手持端进行提示。
1.if (from == "" || to == "") 这一行,需要根据实际的参数数量增删,以及根据实际参数的命名进行变更。
2. || 此符号表达的意思是 或运算 ,符号两边只要有任意一个条件成立,则执行下述代码
3.如果有三个或以上参数需要判断,则表达式为 :if (... || ... || ... || ...)
4.operatorResponse.msg = "请输入起点库位或终点库位"; 根据实际需要的弹窗信息进行更改
*/
if (from == "" || to == "") { //------更改
jj.getLogger().info("参数为空!!!!!1");
operatorResponse.code = 400;
operatorResponse.msg = "请输入起点库位或终点库位";//------更改
response.body = JSON.stringify(operatorResponse);
return response;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4.4 设置一个静态下拉菜单参数
1.配置文件如下:
operator:
orders:
- menuId: EasyTransferTask
label: 简单运输任务 # 手持端选项的提示说明
menuItemBackground: "#32CD32" # 手持端选项的背景颜色
menuItemTextColor: black # 手持端字体的颜色
route: EasyTransferTask # 该选项绑定的路由
tip: 简单运输任务
confirmMessage: 确定下单吗? # 点击下单按钮之后的弹窗提示
params:
- name: from # 代表起点
input: select # 下拉框
label: 请选择起点库位
options:
- value: A-from # 下拉框代表的值
label: A号起点 # 下拉框的描述
- value: B-from
label: B号起点
- name: to # 代表终点
input: select # 下拉框
label: 请选择起点库位
options:
- value: C-to
label: C号终点
- value: D-to
label: D号终点
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2.其他部分详见【创建基本运输任务】,将此配置文件替换 【创建基本运输任务】的配置文件即可。
3.手持端界面显示:
起点下拉框固定显示:(配置文件中配置了起点为:A号起点和B号起点两个)。
终点下拉框固定显示:(配置文件中配置了终点为:C号终点和D号终点两个)。
4.5 设置一个静态联动的下拉菜单参数
1.配置文件如下:
operator:
orders:
- menuId: EasyTransferTask
label: 简单运输任务 # 手持端选项的提示说明
menuItemBackground: "#32CD32" # 手持端选项的背景颜色
menuItemTextColor: black # 手持端字体的颜色
route: EasyTransferTask # 该选项绑定的路由
tip: 简单运输任务
confirmMessage: 确定下单吗? # 点击下单按钮之后的弹窗提示
params:
- name: from
input: select # 下拉框
label: 请选择起点库位
options:
- value: A-from # 下拉框代表的值
label: A号起点 # 下拉框的描述
- value: B-from
label: B号起点 # 终点下拉框通过checkParent来实现静态联动(后一个下拉框显示的内容和前一个下拉框内容有关)
- name: to
input: select # 下拉框
label: 请选择起点库位
options:
- value: C-to
label: C号终点
checkParent: # checkParent
- parent: from # 与哪一个下拉框绑定,在本例中与 name 参数为 from 的下拉框绑定
value: [A-from] # 当 from 下拉框选择 A-from 时,本下拉框 C-to 可以显示
- value: D-to
label: D号终点
checkParent:
- parent: from
value: [A-from] # 当 from 下拉框选择 A-from 时,本下拉框 D-to 可以显示
- value: E-to
label: E号终点
checkParent:
- parent: from
value: [B-from] # 当 from 下拉框选择 B-from 时,本下拉框 E-to 可以显示
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2.其他部分详见【创建基本运输任务】,将此配置文件替换 【创建基本运输任务】的配置文件即可。
3.手持端界面显示:
当起点库位选择 A 号起点,即 A-from 时,终点下拉框显示为:
当起点库位选择 B 号起点,即 B-from 时,终点下拉框显示为:
4.6 创建修改库位状态任务
1、在application.biz.yml文件中添加
operator:
orders:
- menuId: updateSite
label: 库位设置
menuItemBackground: red
menuItemTextColor: white
# 下单的响应方法(POST)路由
route: updateSite
disabled: false
canSendTask: true
tip: 库位设置
confirmMessage: 确定要执行吗?
params:
- name: siteId
input: select
label: 库位Id
options:
- value: Loc-01
label: 库位1
- value: Loc-02
label: 库位2
- name: content
input: select
label: 库位内容
options:
- value: ""
label: 清空
- value: EmptyTray
label: 空托盘
- value: 满料架
label: 满料架
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2、打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
function boot() {
// updateSite和①中的route保持一致,"/script-api/"为固定字符串,后面的可以自定义保持和route一直
jj.registerHandler("POST", "/script-api/updateSite", "updateSite", false);
}
function updateSite(params) {
try {
// 选择修改的库位id
var siteId = JSON.parse(params)["params"][0]["value"];
// 设置库位内容
var content = JSON.parse(params)["params"][1]["value"];
var inputParams = {
"siteId": siteId,
"content": content
};
//创建任务
var taskParam = {
// 天风任务的名称
"taskLabel": "updateSite",
// 天风任务生成的需要的入参
"inputParams": JSON.stringify(inputParams)
};
jj.createWindTask(JSON.stringify(taskParam));
var res = { code: 200, msg: "设置成功" };
return { code: 200, body: JSON.stringify(res) };
}
catch (error) {
var res = { code: 400, msg: "设置失败" };
return { code: 400, body: JSON.stringify(res) };
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
3、 新建天风任务
上图中 ① ② 处任务输入参数和 2 中的 inputParams参数名保持一致
4.7 设置一个动态下拉菜单参数
1、在application.biz.yml文件中如下配置
operator:
orders:
- menuId: dynamic
label: 动态下拉菜单
menuItemBackground: red
menuItemTextColor: white
disabled: false
# 下单的路由
route: updateSite
tip: 动态
confirmMessage: 确定要执行吗?
params:
- name: siteId
input: select
label: 库位
# 绑定脚本的路由post
dynamicOptionsSource: getForkSiteList
lazyGetSource: true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2、打开脚本操作页面,新建脚本 boot.js,将如下代码写入脚本,并点击【保存】。
function boot() {
// /script-api/l2-operator/ 为固定字符串,getForkSiteList与上文的1中dynamicOptionsSource参数的值保持一致
jj.registerHandler("POST", "/script-api/l2-operator/getForkSiteList", "getForkSiteList", false);
}
function getForkSiteList(params) {
// 动态下拉菜单的返回值数据结构一定为数组对象,如下案例'list'
var list = [{
value: "option1",
label: "选项一"
},
{
value: "option2",
label: "选项二"
},
{
value: "option3",
label: "选项三"
},
{
value: "option4",
label: "选项四"
},
{
value: "option5",
label: "选项五"
}];
return { code: 200, body: JSON.stringify(list) };
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
4.7.1 在下拉菜单中显示库位信息
1.在application.biz.yml配置文件中设置如下
operator:
orders:
- menuId: setStockNumber
label: 配置备货完成数量
menuItemBackground: #00CCCC
menuItemTextColor: black
robotTaskDef: setStockNumber
disabled: false
workTypes: [ COMMON-TYPE ]
workStations: [store ]
tip: 下单
confirmMessage: 确定下单
params:
- name: workSites
# 需将input的类型设置为worksite
input: worksite
label: 库位情况
# 读取库区库位信息,可设置多个库区
groupNames:
- ProductSite
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 打开手持端显示库位信息:
4.7.2 为下拉菜单的选项设置背景色
1.在application.biz.yml中的options选项中添加color字段设置颜色
operator:
orders:
- menuId: setStockNumber
label: 配置备货完成数量
menuItemBackground: #00CCCC
menuItemTextColor: black
robotTaskDef: setStockNumber
disabled: false
workTypes: [ COMMON-TYPE ]
workStations: [store ]
tip: 下单
confirmMessage: 确定下单
params:
- name: site
input: select
label: 库位信息
lazyGetSource: false
options:
- label: 库位1
value: location1
# 颜色格式为十六进制
color: #9999CC
- label: 库位2
value: location2
color: #32CD32
defaultOption: true
- label: 库位3
value: location3
color: #3CB371
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.打开手持端显示下拉选项对应的颜色
4.8 在任务中通知某岗位/工位/用户
1、通知用户在天风任务中使用'通知手持端的用户'块
2、通知工位/岗位
1、在application.biz.yml文件中添加岗位、工位配置
operator:
# 岗位数组
workTypes:
# 岗位id
- id: WS
# 岗位名
label: WS
# 工位数组
workStations:
# 工位id
- id: WT
# 工位名
label: WT
2
3
4
5
6
7
8
9
10
11
12
13
2、手持端先绑定工位/岗位
3、天风任务使用 '通知手持端' 块,推送岗位、工位、岗位&&工位
4.9 将任务关联到岗位/工位/用户
1. 天风任务使用 '设置工位岗位' 块<br />
- 设置手持端工位岗位
- 任务界面查看我的任务
4.10 创建需求单
- 案例需求描述
线边工位发起叫料需求,并选择一个线边的库位作为叫料点;仓库管理员收到需求后,选择仓库的一个库位作为物料发货点,然后发起从仓库到线边的物料搬运任务。
该需求可以使用需求单的功能实现。 - 配置文件开启需求单功能
operator:
workTypes:
- id: COMMON-TYPE
label: 通用岗位
workStations:
- id: COMMON-STATION
label: 通用工位
# 需求单配置
demandTask:
# 启用需求单
enable: true
# 手持端需求单标签页的名称
tabName: 需求单
processFuncList:
# 需求单页面中工单的名称
- defLabel: callMatFromBuf
# 需求单该工单下单后,对应的脚本响应方法名
funcName: dealOrder
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
以上 application-biz.yml 配置参数中,“enable: true” 启用需求单功能,开启后手持端将出现需求单标签页面。tabName 字段可自定义需求单标签页的名称。
- application-biz.yml 配置文件中增加用于线边工位叫料的菜单。
operator:
workTypes:
- id: COMMON-TYPE
label: 通用岗位
workStations:
- id: COMMON-STATION
label: 通用工位
# 需求单配置
demandTask:
# 启用需求单
enable: true
# 手持端需求单标签页的名称
tabName: 需求单
processFuncList:
# 需求单页面中工单的名称
- defLabel: callMatFromBuf
# 需求单该工单下单后,对应的脚本响应方法名
funcName: dealOrder
orders:
- menuId: callMatFromBuf
label: 仓库出货
robotTaskDef: callMatFromBuf
route: addDemandData
menuItemBackground: #ffff33
workTypes: [ COMMON-TYPE ]
workStations: [ COMMON-STATION ]
tip: 仓库出货
confirmMessage: 确定从仓库出货吗?
params:
- name: targetSite
input: select
label: 叫料库位
options:
- value: PS-1
label: 线边库位1
- value: PS-2
label: 线边库位2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
以上配置参数中,“menuId: callMatFromBuf” 开始的部分正是新增的叫料菜单参数。此时刷新手持端首页,可以看到多了一个名叫“仓库出货”的菜单,点击菜单后可以选择一个叫料点库位。
- 脚本中增加处理线边叫料的响应方法。
function boot() {
// "仓库出货"菜单的下单按钮的响应方法进行注册
jj.registerHandler("POST", "/script-api/addDemandData", "addDemandData", false);
}
function addDemandData(param) {
var paramObject = JSON.parse(param);
let response = new ScriptRepsonseEntity();
let operatorResponse = new OperatorRepsonseEntity();
// 创建需求单
let robotDefLabel = paramObject["robotTaskDef"];
let menuId = paramObject["menuId"];
let addParam = {
// 需求单数据名称
defLabel: robotDefLabel,
description: "仓库出货",
// 需求单补充内容对应的菜单id,需在yml配置中存在
menuId: "chooseMatSite",
// 需求单数据可见的岗位
workTypes: "COMMON-TYPE",
// 需求单数据可见的工位
workStations: "COMMON-STATION",
createdBy: menuId,
<