华为云用户手册

  • 发布须知 应用包编译类型 在AstroZero经典版应用设计器中,支持编译资产包和源码包两种的应用包。 资产包:资产包中组件默认是设置为受保护状态,可以用在运行环境中安装后,进行预览,运行使用。也可以分享给其他租户安装,在其他租户的开发环境安装后,将显示在“库”页签下,资产包安装后仅能浏览不支持修改。 源码包:源码包中的组件不受保护和限制。源码包可以分享给其他租户,其他租户安装在开发环境中后,可以进行二次开发,安装后将显示在“项目”页签下,详细操作请参见在其他租户环境安装应用包,另外,运行环境中不能安装源码包。 发布方式 AstroZero应用(资产包)发布有多种发布方式:我的仓库、Welink、华为OneMobile、微信、下载小程序,详细介绍请参考发布App。 本示例中,主要介绍把应用发布到“我的仓库”,并通过“我的仓库”再部署到运行环境。 编译类型为“源码包”时,只有发布到“我的仓库”一种发布方式。
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在应用中,单击下方“配置”,进入应用配置。 图1 应用配置入口 在应用配置页面,单击“业务权限凭证”页签,进入业务权限凭证。 图2 业务权限凭证 单击“导入”,在弹窗中勾选“cs”、“ds”、“ms”、“Login”,然后单击“导入”。 图3 导入业务权限凭证 在页面下方,单击“服务”,进入公共接口页面。 图4 创建公共接口入口 为“createWorkOrder”公共接口,添加客服人员业务凭证“cs”。 在接口列表中,单击“createWorkOrder”接口,进入接口详情。 在接口详情页面,单击“业务权限凭证”下的“编辑”。 图5 编辑业务权限凭证 在编辑业务权限凭证弹窗中,勾选“cs”,再单击,然后单击“保存”。 图6 选择客服人员业务凭证cs 参考6,给其他公共接口添加业务权限凭证,详细接口名及业务凭证如表1所示。 表1 需要添加业务凭证的公共接口 编号 公共接口名 需要添加的业务凭证 涉及业务用户 1 createWorkOrder(上一步已添加) cs 客服人员 2 equipmentSelectListQuery cs 客服人员 3 judgeNextStatus ms 维修人员 4 modifyOrderStatus ms 维修人员 5 queryWorkOrder cs、ds、ms 客服人员、派单人员、维修人员 6 queryWorker ds 派单人员 7 login Login 客服人员、派单人员、维修人员
  • 操作步骤 在经典版应用开发页面,单击左侧导航栏下方的“配置”。 图1 应用配置入口 在“导航条”页签单击“菜单树”右侧的“+”,选择“添加页签”。 图2 添加页签 定义“新增用户”页签。在“添加页签”弹窗中,设置以下信息,然后单击“保存”。 页面类型:设置为“标准页面页签”。 标签:设置为“新增用户”。 名称:设置为“addUser”。 页面:设置为“portalUserList”。 图3 添加“新增用户”页面 在应用左侧导航下,单击,进入应用预览页面。 图4 查看应用 在应用菜单上,单击“新增用户”,进入用户管理页面。 图5 新增用户 在用户管理页面,单击“新增用户”,在弹窗中设置用户名、密码及角色。 图6 添加新用户 创建完成后,在用户列表中,查看是否已存在刚刚添加的用户, 如果有,则说明页面及事件代码设置正确。如果页面有报错,请根据页面报错定位问题。
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“User”目录中,鼠标放在“Page”上,单击界面上出现的“+”,在弹出菜单中选择“标准页面”。 在“标签”和“名称”文本框中输入“registerPortalUser”,单击“添加”。 当编辑已有标准页面时,为防止编辑时多人篡改,编辑前请单击进行锁定。 定义模型“userInfo”。 在页面底部单击“模型视图”,然后在“模型视图”中,单击“新增模型”。 添加自定义模型,模型名称“userInfo”,单击“下一步”。 单击“新增节点”,为模型添加节点“username”、“password”、“role”字段,字段类型都采用默认的Text。单击“下一步”,再单击“确定”。 图2 新增节点 单击页面上方的,保存模型。 拖拽页面组件。 单击“设计视图”,从“模型视图”切换到“设计视图”。 从左侧基本组件列表区中,拖拽1个“表单”到“页面内容”中。 因为当前还没有定义数据源,在“元数据表单配置向导”弹窗底部,单击“取消”,创建一个空的表单控件。 图3 拖拽一个空表单 拖拽1个“容器”到“表单”。 拖拽1个“分栏”到“容器”。 修改“分栏”为1栏(1行1列)。 图4 设置分栏为1行1列 选择“分栏”下的2次,新增2个分栏。 向前两个分栏,分别拖拽1个“输入框”组件,向第三个分栏中,拖拽一个“下拉框”组件。 图5 拖拽输入框、下拉框 配置组件属性,及数据绑定。 设置第一个“输入框”属性。 添加值绑定。 选中“输入框”组件,单击“数据绑定”下“值绑定”的,在弹窗中选择“ userInfo”下的“username”字段。 修改“标签”为“用户名”,“占位符”为“请输入用户名”。 设置第二个“输入框”属性。 添加值绑定。 选中“输入框”组件,单击“数据绑定”下“值绑定”的,在弹窗中选择“ userInfo”下的“password”字段。 修改“标签”为“密码”,“占位符”为“请输入密码”。 设置“下拉框”属性。 添加值绑定。 单击“数据绑定”下“值绑定”的,在弹窗中选择“userInfo”下的“role”字段。 修改“标签”为“角色”,并设置“选项”为“cs,客服人员”,“ds,派单人员”、“ms,维修人员”。 图6 设置选项值 单击页面上方的,保存设置。 单击页面上方的,进入预览页面,查看页面是否符合预期,并单击查看是否有下拉框选项。 图7 页面预览
  • 创建公共接口 在经典版应用开发页面,单击左侧导航栏下方的“服务”,进入公共接口创建页面。 图1 服务入口 在公共接口中,单击“新建”。 图2 公共接口创建 创建“用户登录”、“用户注册”脚本对应的公共接口,详细接口信息如表1所示。 如果在“资源”下拉框中,未找到需要关联的脚本或服务编排,请检查相关脚本和服务编排是否已启用,加粗斜体内容以实际命名空间前缀为准。 表1 公共接口 设置操作 版本 URL 方法 类型 资源 login 1.0.0 /login POST 服务编排 HW__login registerPortalUser 1.0.0 /registerPortalUser POST 脚本 HW__registerPortalUser 父主题: 开发业务逻辑
  • 操作步骤 “用户登录”服务编排开发的大致过程:先拖拽1个脚本图元,3个决策图元以及3个赋值图元,再分别配置各个图元属性,然后配置各个图元之间连线类型,最后保存启用。 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“User”目录中,将鼠标放在“Flow”上,单击界面上出现的“+”,在弹出菜单中选择“服务编排”。 选中“创建一个新的服务编排”,在“标签”和“名称”文本框中输入“login”,并设置类型为“Autolaunched Flow”,单击“添加”。 定义服务编排用到的变量。 单击,展开全局上下文,再单击“变量”后的,设置参数名称为“username”,如图2所示。 图2 新增变量 重复上一步,定义其他变量。 需要定义的变量如表1所示。 表1 服务编排变量说明 变量名称(唯一标识) 数据类型 username(上一步已创建) 文本 password 文本 msg 文本 userId 文本 loginMsg 文本 captcha 文本 profile 文本 单击“公式”后的,在左侧公式弹窗中,设置“名称”为“portalUserLogin”,“表达式”为“PORTALUSER LOG IN({!username})”,单击“保存”。 图3 添加公式变量“portalUserLogin” 参考上一步,创建公式变量“verifyCode”,需要定义的变量如表2所示。 表2 公式变量说明 名称 表达式 verifyCode VERIFYCODEWITHTYPE({!captcha},"login") 拖拽图元到服务编排画布,并配置图元的基本属性。 从图元区分别拖拽脚本(1个)、决策(3个)、赋值(3个)图元到画布中,排列,如图4所示。 图4 拖拽脚本(1个)、决策(3个)、赋值(3个)图元 选中“Script0”图元,在右侧基本信息中,设置“标签”为“查询用户”。 参考5.b,设置其他图元的“标签”属性,具体值如表3所示。 表3 图元基本属性 名称(变量唯一标识,不需要修改) 标签 Script0(上一步已设置) 查询用户 Decision0 判断账号密码 Decision1 判断是否包含验证码 Decision2 校验验证码 Assignment0 账号密码错误 Assignment1 执行登录 Assignment2 验证失败 图5 修改后图元 配置“查询用户”脚本图元。 单击,指定图元对应的脚本名称 (HW__login),并配置脚本的输入输出参数。 单击“全局上下文”,显示变量列表,从“变量”中,拖拽“username”、“password”、“captcha”到“输入参数”下对应的“源”输入框中。 在“输出参数”下,单击5次“新增行”,依次添加下拉选项中的输出参数字段,并从“变量”中拖拽相应的字段到“目标”输入框下,字段与变量对应关系如图6所示。 请直接从全局上下文拖拽“变量”到对应的输入输出参数下,请勿手动输入,手动输入的值系统可能不识别。 图6 拖拽脚本的输入输出参数 配置“判断账号密码”决策图元。 选择“判断账号密码”图元,在右侧单击图标,修改“默认”的“名称”为“loginFail”。 图7 修改“默认”结果名称 单击“新增”,增加一个可编辑的结果,修改结果为“loginSuccess”,在“可视”下单击“新增行”,并拖拽变量中的“msg”到“资源”下,设置“比较符”为“==”,“值”为“"登录成功!"”。 请直接从全局上下文拖拽变量“msg”到“资源”下,请勿手动输入,手动输入的值系统可能不识别。 "登录成功!"需要与“login”脚本中的输出参数一致。 图8 修改可编辑的结果 配置“判断是否包含验证码”决策图元。 选择“判断是否包含验证码”图元,在右侧单击图标,修改“默认”的“名称”为“hasVerifyCode”。 图9 修改“默认”结果名称 单击“新增”,增加一个可编辑的结果,修改结果为“noVerifyCode”,在“可视”下单击“新增行”,并拖拽变量中的“captcha”到“资源”下,设置“比较符”为“==”,“值”为“""”。 图10 修改可编辑的结果 配置“校验验证码”决策图元。 选择“校验验证码”图元,在右侧单击图标,修改“默认”的“名称”为“verifyCodeFail”。 图11 修改“默认”名称 单击“新增”,增加一个可编辑的结果,修改结果为“verifyCodeSuccess”,在右侧选择“公式”,并从全局上下文中,拖拽“verifyCode”到“公式”下。 图12 修改可编辑的结果 配置“账号密码错误”赋值图元。 选择“账号密码错误”图元,在右侧单击图标,单击“新增行”,从全局上下文的“系统变量”中,拖拽“$Flow.ResMsg”到“赋值”下,并设置“操作符”为“=”,拖拽“msg”到“值”;然后再拖拽“系统变量”下的“$Flow.ResCode”到“赋值”的“变量”下,设置“操作符”为“=”,设置“值”为“"1"”。 请直接从全局上下文拖拽变量到“赋值”下的对应位置,请勿手动输入,手动输入的值系统可能不识账。 图13 配置“账号密码错误”图元 配置“执行登录”赋值图元。 选择“执行登录”图元,在右侧单击图标,单击5次“新增行”。 从全局上下文,拖拽“msg”等字段到“赋值”的“变量”下,并设置“操作符”为“=”,然后再拖拽“值”下的各个值,具体字段对应关系,如图14所示。 图14 拖拽“执行登录”赋值的变量及值 请直接从全局上下文拖拽变量到“值”下的对应位置,请勿手动输入,手动输入的值系统可能不识别。 表4 变量与值对应关系 变量 操作符 值 loginMsg = portalUserLogin msg = msg profile = profile username = username userId = userId 配置“验证失败”赋值图元。 选择“验证失败”图元,在右侧单击图标,单击“新增行”,从全局上下文“系统变量”,拖拽“$Flow.ResMsg”、“$Flow.ResCode”到“赋值”下,并设置操作符为“=”,分别设置“值”为“"验证码错误!"”、“"1"”。 表5 赋值 变量 操作符 值 $Flow.ResMsg = "验证码错误!" $Flow.ResCode = "1" 图15 配置“验证失败”赋值图元 拖拽图元连线,并配置连线属性。 在画布上,把鼠标放在起点图元图元上,从“+”拖动鼠标,在起点图元和“查询用户”图元间增加连线;即将当前脚本设置为服务编排的起始节点。 依次在“查询用户”、“判断账号密码”、“判断是否包含验证码”、“执行登录”图元直接拖拽连线。 图16 拖拽连线 单击“判断账号密码”与“判断是否包含验证码”图元之间的连线,再右侧属性单击,在“连线”中修改“连线类型”为“loginSuccess”。 图17 选中连线 图18 修改连线类型 单击“判断是否包含验证码”与“执行登录”图元之间的连线,再右侧属性单击,在“连线”中修改“连线类型”为“noVerifyCode” 从“判断账号密码”图元上拖拽一条连线到“账号密码错误”图元。 从“判断是否包含验证码”图元上拖拽一条连线到“校验验证码”图元。 从“校验验证码”图元上拖拽一条连线到“验证失败”图元。 从“校验验证码”图元上拖拽一条连线到“执行登录”图元,并设置该连线的“连线类型”为“verifyCodeSuccess”。 连线拖拽完成,如图19所示。 图19 拖拽图元连线 定义服务编排的输入、输出参数,并保存服务编排。 鼠标在画布空白处点一下,单击右侧,设置服务编排的输入输出参数,如图20所示。 图20 拖拽服务编排的输入输出参数 单击服务编排页面上方的,保存服务编排。 系统会弹出窗口,显示编译结果。 测试服务编排能否正常执行。 单击服务编排编辑器上方的,执行服务编排。 在“Flow Run”界面中输入测试数据,单击“运行”。其中,“test_cs”、“{XXXXXXXX}”为用户注册脚本中测试数据。 { "username": "test_cs", "password": "{XXXXXXXX}", "captcha": "" } 执行成功,界面上会返回设备对象中的全部信息,样例如下: { "interviewId": "002N000000jjQ95dKbCK", "outputs": { "loginMsg": "null", "msg": "登录成功!", "profile": "cs", "userId": "10gg0XXXXXXXXXXXXX", "username": "test_cs" } } (可选)在服务编排编辑器单击“跟踪”,可以查看到上一步的执行日志,方便定位错误。 测试成功,单击服务编排编辑器上方的,启用发布服务编排。
  • 实现原理 图1 用户登录服务编排大致设想 如图1所示,用户登录服务编排业务逻辑实现过程如下: 通过调用“用户登录”脚本,查询登录账户密码,然后使用“决策”图元进行判断,判断当前登录的账号密码是否正确。 如果判断账户密码错误,直接执行“账户密码错误”,判断账户密码正确,则使用“决策”图元,继续判断是否有验证码。 如果判断当前登录没有验证码,则直接执行登录,判断当前有验证码,则继续判断验证码是否正确。 如果判断验证码正确,则执行登录操作,判断验证码错误,则执行验证失败。
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“User”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“login”,单击“添加”。 在代码编辑器中,插入如下脚本代码。 import * as buffer from "buffer"; import * as crypto from "crypto"; import * as db from "db"; import * as context from 'context'; //定义入参结构,包括账号的用户名、密码为必填字段,验证码为非必填字段 @action.object({ type: "param" }) export class ActionInput { @action.param({ type: 'String', required: true, label: 'string' }) username: string; @action.param({ type: 'String', required: true, label: 'string' }) password: string; @action.param({ type: 'String', required: true, label: 'string' }) captcha: string; } //定义出参结构,出参包含5个参数,登录结果和用户角色 @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'String' }) msg: string; @action.param({ type: 'String' }) username: string; @action.param({ type: 'String' }) userId: string; @action.param({ type: 'String' }) captcha: string; @action.param({ type: 'String' }) profile: string; } //使用数据对象PortalUser @useObject(['PortalUser']) @action.object({ type: "method" }) export class Login { //定义接口类,接口的入参为ActionInput,出参为ActionOutput @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public login(input: ActionInput): ActionOutput { let out = new ActionOutput(); //新建出参ActionOutput类型的实例,作为返回值 let error = new Error(); //新建错误类型的实例,用于在发生错误时保存错误信息 try { out.captcha = input.captcha; let s = db.object('PortalUser'); let condition = { "conjunction": "AND", "conditions": [{ "field": "usrName", "operator": "eq", "value": input.username }] }; let user = s.queryByCondition(condition); if (user && user.length == 1) { if (validate(user[0].passwordSalt, user[0].userPassword, input.password)) { out.msg = "登录成功!"; out.username = user[0].usrName; out.userId = user[0].id; out.profile = user[0].userType; } else { out.msg = "密码错误!"; } } else { out.msg = "用户不存在!"; } } catch (error) { console.error(error.name, error.message); context.setError(error.name, error.message); out.msg = error.message; } return out; } } function _salt(password: string, saltBuf: buffer.Buffer, encoding: buffer.Encoding = buffer.Encoding.Base64): string { const passwordBuf = buffer.from(password) const crypt = crypto.pbkdf2(passwordBuf, saltBuf, 1000, 32, crypto.Hashs.SHA1) return crypt.toString(encoding) } function validate(salt: string, userSaltedPassword: string, password: string, encoding: buffer.Encoding = buffer.Encoding.Base64): boolean { const saltBuf = buffer.from(salt, encoding); const saltedPassword = _salt(password, saltBuf, encoding); return saltedPassword === userSaltedPassword } 单击编辑器上方的,保存脚本。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部输入测试数据,单击测试窗口右上角执行图标,其中“test_cs”、变量“{XXXXXXXX}”为用户注册脚本中测试数据。 { "username": "test_cs", "password": "{XXXXXXXX}", "captcha": "" } 执行成功,会在“输出”页签返回查询结果。 { "captcha": "", "msg": "登录成功!", "profile": "cs", "userId": "10gg0XXXXXXXXXXXXX", "username": "test_cs" } 测试成功,单击编辑器上方的,启动发布脚本。
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“User”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“registerPortalUser”,单击“添加”。 在代码编辑器中,插入如下脚本代码。 import * as buffer from "buffer"; import * as crypto from "crypto"; import * as db from "db"; import * as context from 'context'; import * as http from 'http'; import * as permission from 'permission'; //定义入参结构,包括注册账号的用户名、密码和角色,为必填字段 @action.object({ type: "param" }) export class ActionInput { @action.param({ type: 'String', required: true, label: 'string' }) username: string; @action.param({ type: 'String', required: true, label: 'string' }) password: string; @action.param({ type: 'String', required: true, label: 'string' }) role: string; } //定义出参结构,出参包含1个参数,portaluser的记录id @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'String' }) msg: string; } //使用数据对象PortalUser @useObject(['PortalUser']) @action.object({ type: "method" }) export class RegisterPortalUser { //定义接口类,接口的入参为ActionInput,出参为ActionOutput @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public registerPortalUser(input: ActionInput): ActionOutput { let out = new ActionOutput(); //新建出参ActionOutput类型的实例,作pu为返回值 let error = new Error(); //新建错误类型的实例,用于在发生错误时保存错误信息 try { let s = db.object('PortalUser'); let saltedPassword = salt(input.password); let userMsg = { "usrName": input.username, "name": input.username, "userPassword": saltedPassword['saltedPassword'], "passwordSalt": saltedPassword['salt'], "userType": input.role }; let userId = s.insert(userMsg); if (userId) { out.msg = "注册成功!"; } else { error.name = "USERERROR"; error.message = "注册失败!"; throw error; } } catch (error) { if (error.name == "405230618") { error.message = "该用户名已注册!" } console.error(error.name, error.message); context.setError(error.name, error.message); } return out; } } function _salt(password: string, saltBuf: buffer.Buffer, encoding: buffer.Encoding = buffer.Encoding.Base64): string { const passwordBuf = buffer.from(password) const crypt = crypto.pbkdf2(passwordBuf, saltBuf, 1000, 32, crypto.Hashs.SHA1) return crypt.toString(encoding) } function salt(password: string, encoding: buffer.Encoding = buffer.Encoding.Base64): object { const saltBuf = crypto.randomBytes(6) const saltedPassword = _salt(password, saltBuf, encoding) return { salt: saltBuf.toString(encoding), saltedPassword: saltedPassword } } 单击编辑器上方的,保存脚本。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部输入测试数据,单击测试窗口右上角执行图标。 { "username": "test_cs", "password": "***", "role": "cs" } 执行成功,会在“输出”页签返回查询结果。 { "msg": "注册成功!" } 测试成功,单击编辑器上方的,启用发布脚本。
  • 背景与知识 “用户管理”功能包括业务新增业务用户、查看删除业务用户、添加业务用户权限集三部分。 在业务场景中,会区分不同业务用户,业务用户对应了不同的用户权限,本示例应用中包含的业务用户,即是使用设备管理应用的用户,分别是客服人员、派单员及维修人员。 在AstroZero开发的应用的所有业务用户,最终都会存储到平台的业务用户表中,即PortalUser表。业务用户在登录应用后的访问权限是通过Profile进行控制管理的,可基于平台预置的Portal User Profile进行自定义业务用户权限。 图1 业务用户 父主题: 用户管理功能开发
  • 操作步骤 在经典版应用开发页面,单击左侧导航栏下方的,进入应用预览页面。 图1 查看应用 验证创建工单。 选择“工单列表(客服人员)”,然后在工单列表(客服人员)页面,单击“创建工单”,进入创建工单页面。 在“设备名称”下拉框中选择一个设备,检查“设备详情”区域显示了对应的设备详情。显示正确,则说明组件与模型的绑定,以及下拉框“数据改变”事件执行正确。 如果“设备名称”下,没有设备名,请先在“设备管理”页面,单击“新增行”进行添加。 检查是否正常提交工单。 填写工单信息, 单击“提交”。如果页面跳转到工单列表页面,且在查询结果中,显示新创建的工单,则说明提交按钮的“点击”事件执行正确。 如果页面跳转到工单列表页面,且在查询结果中显示新创建的工单,则说明验证成功。 图2 验证结果样例 验证派单功能。 单击“工单列表(派单员)”,进入“工单列表(派单员)”页面,查看页面是否显示上一步创建的工单,且每条记录后都有派单图标。 选择上一步新建的一条工单记录,并单击该记录的,弹出处理工单弹窗。 图3 状态为“待派单”工单记录 在处理工单弹窗中,设置下拉框“选择工程师”为当前租户账号,然后单击“确定”,返回“工单列表(派单员)”页面。 查看工单记录的“状态”、“当前处理人”是否已更新为“待接单”、当前租户名。如果已更新,说明派单流程正常。如未改变请检查“派单”按钮上事件代码以及“处理工单”弹窗中数据绑定及事件代码。 验证待接工单。 进入“工单列表(维修人员)”页面,检查系统显示派单员刚刚派的工单,如图4所示。 如未正常显示请检查当前页面标签组件的属性值绑定及页面事件代码。 图4 待处理工单 单击“处理”按钮,进入处理工单弹窗,“选择下一步操作”设置为“接单”,单击“提交”按钮。 处理完成后,返回“待处理工单”页面,查看“状态”是否已经更新为“处理中”。 如果有多条工单,“待处理”状态的工单,优先显示,“处理中”的工单可能会显示在页面的下面,工单状态改变后,可以拖动滚动条查找该工单。 如果在“选择下一步操作”中,选择了“拒单”,流程将返回“派单员”处,状态将变为“待派单”。 图5 处理工单-关单 图6 查看处理中的工单 单击“处理中”工单的“处理”按钮,选择“关单”,单击“提交”,返回页面后,查看该条工单的状态是否变成“关闭”,如果已关闭,则说明关单流程正常。 图7 关闭工单 参考以上步骤,验证工单管理页面。 在应用菜单中,选择“工单管理”页面,进入工单管理,查看页面工单列表中的工单信息。 进行“创建工单”、派单及删除工单操作,验证工单管理功能。
  • 操作步骤 在经典版应用开发页面,单击左侧导航栏下方的“配置”。 图1 应用配置入口 在“导航条”页签,单击“菜单树”右侧的“+”,选择“添加页签”。 图2 导航条添加页签 定义“设备管理”页签。 在“添加页签”弹窗中,设置以下信息,然后单击“保存”。 页面类型:设置为“标准页面页签”。 标签:设置为“设备管理”。 名称:设置为“equipmentManage”。 页面:设置为“HW__equipmentManage”。 图3 设备管理页签 请按照以上方式,创建表1的导航菜单。 表1 导航菜单 页签类型 标签 名称 页面 标准页面页签 工单管理 manageWorkOrderList HW__manageWorkOrder 标准页面页签 工单列表(客服人员) workOrderList HW__workOrderList 标准页面页签 工单列表(派单员) dispatchWorkOrder HW__dispatchWorkOrder 标准页面页签 工单列表(维修人员) workOrderListM HW__workOrderListM (可选)设置导航的布局及颜色。 您可以根据自己的喜好,设置导航的布局及颜色,默认导航菜单是靠左,蓝色。 如图4所示,单击红框中的布局,即可将导航菜单设置为横向菜单,然后单击“保存”。 图4 切换为横向导航
  • 操作步骤 创建流程大致是先创建3个泳道,再拖拽泳道图元,然后配置相关图元,保存并启用。 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”目录中,将鼠标放在“Bpm”上,单击界面上出现的“+”,在弹出菜单中选择“BPM”。 在弹窗中,设置“标签”、“名称”为“WorkOrderBpm”,单击“添加”。 图2 添加BPM 在设计区域,单击2次“AddLane”,为BPM添加2个角色泳道。 图3 添加泳道 修改泳道基础属性。 选中“Lane”,在右侧属性配置区域,设置泳道标签为“客服人员”,“工作队列”设置为创建工作队列中创建的“客服人员”。 图4 修改客服人员泳道基本信息 参考上一步,分别设置其他两个泳道的“标签”及“工作队列”。 表2 泳道标签及工作队列 泳道初始标签 泳道修改后标签 工作队列 Lane(上一步已配置) 客服人员 客服人员 lane1 派单员 派单员 lane2 维修人员 维修人员 创建BPM中用的变量及对象变量。 在右侧属性面板区域,单击,展开全局上下文。 图5 展开全局上下文 单击“变量”后的图标4次,分别创建以下变量,单击变量后的,可以修改字段类型,创建完成后,如图6所示。 表3 BPM变量 变量名 字段类型 id 文本 status 文本 assignedFme 文本 transInfo 任意 图6 创建变量 单击“对象变量”的,在弹窗中设置“名称”为“workOrderData”,“对象”设置为“HW__WorkOrder__ CS T”(工单对象),加粗斜体内容请以实际命名空间前缀为准,然后单击“保存”。 图7 新增对象变量 再次单击“对象变量”的,在弹窗中设置“名称”为“statusInfo”,“对象”设置为“HW__WorkOrder__CST”(工单对象),然后单击“保存”。 拖拽并配置“客服人员”泳道。 从左侧“活动”图元区域,拖拽一个“数据映射”图元到“客服人员”泳道中。 选中“Data Mapper”图元,然后在右侧导航菜单上单击,进入数据映射配置,再单击,展开全局上下文。 图8 拖拽并设置“数据映射”图元 分别从全局上下文的“对象变量”、“系统变量”中拖拽参数到数据映射配置下: 拖拽对象变量“workOrderData”下的“HW__instanceId__CST”字段到“变量”下,“操作符”为“=”,拖拽“系统变量”下的“{!$Flow.RootID}”做为“值”。 图9 拖拽赋值变量 从左侧“活动”图元区域,拖拽一个“调用脚本”图元到“客服人员”泳道中,并设置“标签”为“创建工单”、“名称”为“createWorkOrder”。 图10 设置创建工单图元 选中“创建工单”图元,单击,再单击“全局上下文”,配置“创建工单”图元绑定的脚本以及输入输出参数。 在“脚本配置”下选择“生成工单”脚本“HW__createWorkOrder”。 从全局上下文中拖拽对象变量“workOrderData”到“输入参数”的“源”输入框中,作为输入参数的值。 设置“输出参数”为“id”,并拖拽变量“id”作为“目标”输入框中的值。 图11 配置“创建工单”图元 从“Start”图元中拖拽一条连线到“Data Mapper”图元,然后从“Data Mapper”图元拖拽一条连线到“创建工单”图元,默认“连线类型”为“下一步”。 图12 拖拽连线 拖拽并配置“派单员”泳道。 从左侧“活动”图元区域,依次拖拽一个“用户任务”、“调用脚本”图标到“派单员”泳道中。 设置“用户任务”图元的“标签”为“派单员派单”、“名称”为“dispatchWorkOrderList”。 设置“调用脚本”图元的“标签”为“派单”、“名称”为“dispatch”。 选中“派单员派单”图元,单击,设置“任务标题”、“任务描述”为“派单员派单”,“渲染类型”为“标准页面”,“页面”设置为“HW__dispatchWorkOrder”。 图13 用户任务配置 选中“派单”图元,单击,再单击“全局上下文”,配置“派单”图元绑定的脚本以及输入输出参数。 在“脚本配置”下选择“生成工单”脚本“HW__dispatchWorkOrder”。 从全局上下文中,拖拽变量“transInfo”到“输入参数”的“源”输入框中,作为输入参数的值。 在“输出参数”下,单击“新增行”,设置“输入参数”为“id”、“assignedFme”,并从全局上下文中,拖拽变量“id”、“assignedFme”作为“目标”输入框中的值。 图14 配置“派单”图元 从“派单员派单”图元中拖拽一条连线到“派单”图元,然后再从“创建工单”图元中拖拽一条连线到“派单员派单”图元,默认“连线类型”均为“下一步”。 图15 拖拽连线 拖拽并配置“维修人员”泳道。 从左侧“活动”图标区域,拖拽2个“用户任务”、2个“调用脚本”、1个“排他网关”以及“终止”图元到“维修人员”泳道中,然后调整图元顺序。 图16 拖拽并调整图元顺序 从左到右,分别设置2个“用户任务”、2个“调用脚本”图元的基本属性,具体如表4所示,设置完成后如图17所示。 表4 图元基本属性设置 图元(从左向右) 标签 名称 用户任务1 维修人员接单 takeWorkOrder 调用脚本1 接单 takeWorkOrder1 用户任务2 维修人员关单 dealWorkOrder 调用脚本2 关闭工单 closeWorkOrder 终止 End end 图17 图元基本属性设置 配置“维修人员接单”图元。 选中“维修人员接单”图元,单击,并展开全局上下文,配置“维修人员接单”图元,详细配置如表5所示。 图18 用户任务配置 表5 用户任务配置 参数项 值 任务标题 维修人员接单 任务描述 维修人员任务列表 渲染类型 标准页面 页面 HW__workOrderListM 接收人下“类型” 名称和表达式 参与者下“类型” 表达式 参与者下“取值” “变量”下的“assignedFme” 说明: 请直接从全局上下文拖拽“assignedFme”到“取值”下,请勿手动输入,手动输入的值系统可能不识别。 配置“接单”图元。 选中“接单”图元,单击,再单击“全局上下文”,并展开全局上下文,配置“维修人员接单”图元,详细配置如表5所示。 请直接从全局上下文拖拽“statusInfo”、“id”、“status”到输入输出参数对应“源”或“目标”下,请勿手动输入,手动输入的值系统可能不识别。 图19 配置“接单”图元 表6 接单图元配置 参数项 值 脚本 HW__modifyOrderStatus 输入参数“statusInfo” 对象变量下“statusInfo” 输出参数“id” 变量下“id” 输出参数“status” 变量下“status” 配置“维修人员关单”图元。 选中“维修人员关单”图元,单击,设置“任务标题”为“维修人员关单”,“任务描述”为“维修人员任务列表”,“渲染类型”为“标准页面”,“页面”设置为“HW__workOrderListM”,并设置“当前泳道中的上一个任务被分配的人员”,如图20所示。 图20 配置“维修人员关单”图元 配置“关闭工单”图元。 选中“关闭工单”图元,单击,再单击“全局上下文”,并展开全局上下文,配置“关闭工单”图元,详细配置如表5所示。 请直接从全局上下文拖拽“statusInfo”、“id”、“status”到输入输出参数对应“源”或“目标”下,请勿手动输入,手动输入的值系统可能不识别。 图21 拖拽关闭工单输入输出值 表7 接单图元配置 参数项 值 脚本 HW__modifyOrderStatus 输入参数“statusInfo” 对象变量下“statusInfo” 输出参数“id” 变量下“id” 输出参数“status” 变量下“status” 拖拽图元直接的关系连线,具体如图22所示。 图22 添加图元之间连线 配置“排他网关”图元连线属性。 选中“派单员派单”与“排他网关”之间的连线,单击鼠标右键,选择“配置”,设置“标签”为“拒单”,再单击“新增行”,拖拽变量“status”到“资源”下,设置“比较符”为“==”,“值”为“"拒单"”。 图23 选中排他网关图元连线 图24 配置“拒单”连线 选择“排他网关”图元与“维修人员关单”图元之间的连线,参考上一步,设置连线,设置“标签”为“接单”,再单击“新增行”,拖拽变量“status”到“资源”下,设置“比较符”为“==”,“值”为“"接单"”。 图25 配置“接单”连线 单击页面上方的,再单击,启用BPM。
  • BPM能力 BPM可以提供如下能力,本示例中仅使用到前三种能力: 端到端页面流编排 将用户交互的前端页面与各种任务之间进行编排,形成一个完整的商业流。 支持长流程 步骤之间可以是立即执行,也可以是小时、天、甚至更长时间的间隔,支持SLA期限管理。 跨人员的工作流 支持每一步由不同的用户、组串行或并行处理。 BPM内部进行调用 BPM可以作为子BPM被其他BPM进行内部调用。在总的BPM中使用“调用活动”元素,可嵌套使用子BPM。
  • 了解BPM设计界面 图1 BPM设计界面 整体编辑器页面由上方按钮区域、左侧面板图元区域、中间画布工作区域、右侧属性配置区域四部分组成。 表1 BPM设计界面说明 编号区 域名 称 功能说明 1 功能按钮区域,包括锁定、解锁、启用(或者禁用)、保存、另存为新版本或者新BPM、运行、操作回退、撤销回退、启用流跟踪器以及切换版本的操作。支持快捷键操作,即可脱离鼠标直接用键盘操作。 2 BPM的组成图元,一个BPM业务流程由以下几个部分组成: 事件图元(Events):用来表明BPM的生命周期中发生的事件,例如开始、捕获信号等。 网关图元(Gateways):网关用来控制流程的执行流向,可理解为决策、判断。 活动图元(Activities):是BPM的核心图元,可理解为节点或者步骤,例如调用脚本、用户需要做的任务。 3 BPM设计操作区域。在该区域可对BPM进行具体流程设计、组件放置。 不同色块的表示不同的泳道,BPM由一个或多个泳道组成,泳道中包括了实现不同功能逻辑的图元。 选中泳道或者某个图元,可以在右侧属性配置区域进行各种配置操作。 4 整个BPM、泳道或者图元属性设置区域。 当选择BPM中图元时,右侧配置区域为该图元的属性设置区域。 当选择BPM中空白区域时,右侧配置区域为该BPM的设置区域。 当选择泳道左侧标签时,右侧配置区域为该泳道的属性设置区域。
  • 创建脚本 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“deleteWorkOrder”,单击“添加”。 当编辑已有脚本时,为防止编辑时多人篡改,编辑前请单击进行锁定。 在代码编辑器中插入如下脚本代码。 脚本中红色内容请替换为实际的对象名、字段名。 //本脚本用于删除工单 import * as db from 'db';//导入处理object相关的标准库 import * as context from 'context';//导入上下文相关的标准库 //定义入参结构,入参包含1个参数:workOrder对象,为必填字段 @action.object({ type: "param" }) export class ActionInput { @action.param({ type: 'String', required: true, label: 'String' }) id: string; } //定义出参结构,出参包含1个参数,workOrder的记录id @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'String' }) id: string; } //使用数据对象HW__WorkOrder__CST @useObject(['HW__WorkOrder__CST']) @action.object({ type: "method" }) export class DeleteWorkOrder { //定义接口类,接口的入参为ActionInput,出参为ActionOutput @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public deleteWorkOrder(input: ActionInput): ActionOutput { let out = new ActionOutput(); //新建出参ActionOutput类型的实例,作为返回值 let error = new Error(); //新建错误类型的实例,用于在发生错误时保存错误信息 try { let id = input.id; let s = db.object('HW__WorkOrder__CST'); //获取HW__WorkOrder__CST这个Object的操作实例 //查询条件 let condition = { "conjunction": "AND", "conditions": [{ "field": "id", "operator": "eq", "value": id }] }; let isDeleted = s.deleteByCondition(condition); if (isDeleted) { out.id = id; } else { error.name = "WOERROR"; error.message = "删除工单失败!"; throw error; } } catch (error) { console.error(error.name, error.message); context.setError(error.name, error.message); } return out; } } 单击编辑器上方的,保存脚本。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部,输入以下报文作为“输入参数”,然后单击测试窗口右上角执行图标。“ceHg000000e0glLbDQ2K”则是派单员操作的当前工单记录的工单id,您可以在派单功能脚本的测试结果中获取一个id值。 { "id":"ceHg000000e0glLbDQ2K" } 执行成功,会在“输出”页签返回查询结果。 测试成功,单击编辑器上方的,启用发布脚本。
  • 创建公共接口 参考之前创建公共接口的步骤,创建“删除工单”脚本对应的公共接口。 在设计视图下,单击下方“服务”,进入公共接口创建页面。 图1 创建公共接口入口 在公共接口中,单击“新建”。 图2 公共接口创建 创建“删除工单”脚本对应的公共接口,详细接口信息如表1所示。 表1 公共接口 设置操作 版本 URL 方法 类型 资源 deleteWorkOrder 1.0.0 /deleteWorkOrder DELETE 脚本 HW__deleteWorkOrder
  • 操作步骤 在经典版应用开发页面的设计视图下,单击“服务”,进入公共接口创建页面。 图1 服务入口 单击“新建”,如下图所示。 图2 公共接口创建 创建“处理工单”、“判断下一步状态”脚本对应的公共接口,详细接口信息如表1所示。 表1 公共接口 设置操作 版本 URL 方法 类型 资源 modifyOrderStatus 1.0.0 /modifyOrderStatus POST 脚本 HW__modifyOrderStatus judgeNextStatus 1.0.0 /judgeNextStatus POST 脚本 HW__judgeNextStatus
  • 创建“判断下一步状态”脚本 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“judgeNextStatus”,单击“添加”。 当编辑已有脚本时,为防止编辑时多人篡改,编辑前请单击进行锁定。 在代码编辑器中插入如下脚本代码。 脚本中红色内容请替换为实际的对象名、字段名。 //本脚本用于判断下一步状态变化 import * as db from 'db';//导入处理object相关的标准库 import * as context from 'context';//导入上下文相关的标准库 //定义入参结构,入参包含1个参数:workOrder对象,为必填字段 @action.object({ type: "param" }) export class ActionInput { @action.param({ type: 'String', required: true, label: 'String' }) id: string; } //定义出参结构,出参包含1个参数,workOrder的记录id @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'Any', label: 'Object', isCollection: true }) statusList: object[]; } //使用数据对象HW__WorkOrder__CST @useObject(['HW__WorkOrder__CST']) @action.object({ type: "method" }) export class JudgeNextStatus { //定义接口类,接口的入参为ActionInput,出参为ActionOutput @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public judgeNextStatus(input: ActionInput): ActionOutput { let out = new ActionOutput(); //新建出参ActionOutput类型的实例,作为返回值 let error = new Error(); //新建错误类型的实例,用于在发生错误时保存错误信息 try { let id = input.id; let s = db.object('HW__WorkOrder__CST'); //获取HW__WorkOrder__CST这个Object的操作实例 //查询条件 let condition = { "conjunction": "AND", "conditions": [{ "field": "id", "operator": "eq", "value": id }] }; let workOrder = s.queryByCondition(condition); if (workOrder) { if (workOrder[0].HW__status__CST == "待接单") { out.statusList = [ { 'value': "接单", 'display': "接单" }, { 'value': "拒单", 'display': "拒单" }]; } if (workOrder[0].HW__status__CST == "处理中") { out.statusList = [{ 'value': "关单", 'display': "关单" }]; } } } catch (error) { console.error(error.name, error.message); context.setError(error.name, error.message); } return out; } } 单击编辑器上方的,保存脚本。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部,输入如下输出参数报文,单击测试窗口右上角执行图标,“ceHg000000e0glLbDQ2K”则是派单员操作的当前工单记录的工单id,您可以在处理工单脚本的测试结果中获取一个id值。 { "id": "ceHg000000e0glLbDQ2K" } 执行成功,会在“输出”页签返回查询结果。 图1 返回下一步状态 测试成功,单击编辑器上方的,启用发布脚本。 父主题: 开发“维修工程师处理工单”功能
  • 验证 因当前还未创建工单状态流转的BPM,因此派单功能还不能正常测试运行。本节只验证页面显示及跳转相关内容。 在“HW__dispatchWorkOrder”页面中,单击界面上方的,进入页面预览,在页面预览中进行以下验证。 查看页面显示:正常情况下,系统会显示客服人员创建的工单,且每条记录后都有派单图标,如果工单状态为“待派单”,则派单按钮为高亮可用状态,如果不是“待派单”状态,则按钮灰度不可用。 如果当前工单列表中没有“待派单”状态的工单,可以在“生成工单”脚本中输入一条测试数据,生成一条工单。 图1 页面预览 查看页面跳转。 选择一条“工单状态”为“待派单”的工单记录,单击“派单”按钮,查看是否弹出“处理工单对话框”,如果未跳转,请检查操作列“派单”按钮上的事件。 在“处理工单对话框”中,查看是否显示“工单ID”,“选择工程师”下拉框是否显示正常,如果不正常,需要检查“派单”对话框相关事件代码及属性值绑定。 图2 处理工单对话框 父主题: 开发“派单员派发工单”功能
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”中,鼠标放在“Page”上,单击界面上出现的“+”,在弹出菜单中选择“标准页面”。 在“标签”和“名称”文本框中输入“workOrderDispatch”,单击“添加”。 当编辑已有标准页面时,为防止编辑时多人篡改,编辑前请单击进行锁定。 定义模型“transInfo”。 在“模型视图”中,单击“新增模型”。 添加自定义模型,模型名称“transInfo”,单击“下一步”。 为模型添加节点“HW__workOrderId__CST”(字段类型Text)、“HW__assignedFme__CST”(字段类型Any),单击“下一步”,再单击“确定”,加粗斜体内容请替换为实际命名空间前缀。 单击页面上方的,保存模型。 定义模型“workerOptions”。 在“模型视图”中,单击“新增模型”。 添加服务模型,模型名称“workerOptions”,单击“下一步”。 “项目”选择“设备维修管理系统”,并为模型关联API“queryWorker”,单击“下一步”,再单击“确定”。 单击页面上方的,保存模型。 拖拽页面组件。 单击“设计视图”,返回页面设计。 将左侧基本组件区的“表单”拖拽到右侧页面中。 因为当前还没有定义数据源,单击“取消”,创建一个空的表单控件。 拖拽一个“分栏”到表单中。 选中“分栏”,在右侧单击PC下的单行图标,修改分栏为1栏,再单击“新增行”的,修改为2个分栏,每个分栏中有1栏。 图2 设置分栏为1栏 在第1个分栏中拖入一个“输入框”,在第2个分栏中拖入一个“下拉框”。 图3 拖入输入框、下拉框到分栏 选中“输入框”,在右侧属性面板中,单击,在选择模型弹窗中,选择“transInfo”下的“HW__workOrderId__CST”字段,并修改其“标签”为“工单ID”。 选择下拉框进行以下设置。 在右侧属性面板中,单击,在选择模型弹窗中,选择“transInfo”下的“HW__assignedFme__CST”字段,修改“标题”为“选择工程师”。 单击“属性值绑定”后的“+”,设置“属性”为“选项”,“模型字段”为“workerOptions.outputParam.userList”,即绑定属性值为服务对象的返回值。 图4 绑定服务对象的返回值 开启“弹层独立”。 图5 启用弹层独立 单击页面上方的,保存设置。 定义页面事件代码。 在“设计视图”中选中最外层的“页面”,在右侧“事件”页签中,单击“加载”后的“+”,进入编辑动作页面。 在“自定义动作”中,输入如下脚本代码。 红色内容请替换为实际命名空间前缀。 let workOrderId = Page.params.workOrderId; $model.ref("transInfo").setData({ "HW__workOrderId__CST": workOrderId }); //查询维修人员列表,作为维修人员下拉框的可选值 $model.ref('workerOptions').setData({ inputParam: {} }); $model.ref('workerOptions').run(); 单击“创建”,关闭事件编排器,返回到页面。 单击页面上方的,保存页面。
  • 操作步骤 在设计视图下,单击下方的“服务”,进入公共接口创建页面。 图1 创建公共接口入口 在公共接口页面,单击“新建”。 图2 公共接口创建 创建“查询维修人员”、“派单功能”脚本对应的公共接口,详细接口信息如表1所示。 加粗斜体内容请替换为实际命名空间前缀。 表1 公共接口 设置操作 版本 URL 方法 类型 资源 queryWorker 1.0.0 /queryWorker GET 脚本 HW__queryWorker dispatchWorkOrder 1.0.0 /dispatchWorkOrder POST 脚本 HW__dispatchWorkOrder
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“dispatchWorkOrder”,单击“添加”。 当编辑已有脚本时,为防止编辑时多人篡改,编辑前请单击进行锁定。 在代码编辑器中,插入如下脚本代码。 脚本中红色内容请替换为实际的对象名、字段名。 //本脚本用于派发工单 import * as db from 'db';//导入处理object相关的标准库 import * as context from 'context';//导入上下文相关的标准库 import * as date from 'date'; //定义入参结构,入参包含1个参数:工单状态的修改信息,为必填字段 @action.object({ type: "param" }) export class ActionInput { @action.param({ type: 'Any', required: true, label: 'object' }) transInfo: any; } //定义出参结构,出参包含2个参数,workOrder的记录id和派发后的责任人 @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'String' }) id: string; @action.param({ type: 'String' }) assignedFme: string; } //使用数据对象HW__WorkOrder__CST @useObject(['HW__WorkOrder__CST']) @action.object({ type: "method" }) export class DispatchWorkOrder { //定义接口类,接口的入参为ActionInput,出参为ActionOutput @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public dispatchWorkOrder(input: ActionInput): ActionOutput { let out = new ActionOutput(); //新建出参ActionOutput类型的实例,作为返回值 let error = new Error(); //新建错误类型的实例,用于在发生错误时保存错误信息 try { let transInfo = input.transInfo; //将入参赋值给transInfo变量,方便后面使用 let s = db.object('HW__WorkOrder__CST'); //获取HW__WorkOrder__CST这个Object的操作实例 //查询条件 let condition = { "conjunction": "AND", "conditions": [{ "field": "HW__workOrderId__CST", "operator": "eq", "value": transInfo['HW__workOrderId__CST'] }] }; //查找workOrderId所代表的工单信息 let workOrder = s.queryByCondition(condition); workOrder[0]['HW__status__CST'] = '待接单'; workOrder[0]['HW__assignedFme__CST'] = transInfo["HW__assignedFme__CST"].name; let isUpdated = s.updateByCondition(condition, workOrder[0]); if (isUpdated) { out.id = workOrder[0]['id']; out.assignedFme = transInfo["HW__assignedFme__CST"].id; } else { error.name = "WOERROR"; error.message = "派发工单失败!"; throw error; } } catch (error) { console.error(error.name, error.message); context.setError(error.name, error.message); } return out; } } 单击编辑器上方的,保存脚本。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部输入测试数据,单击测试窗口右上角执行图标。 脚本中加粗斜体内容请替换为实际的对象名、字段名。 "name":"test"为当前租户名,可以在上一节的输出参数中查询。 { "transInfo": { "HW__workOrderId__CST": "WD0000123456", "HW__assignedFme__CST":{ "id":"", "name":"test" } } } 执行成功,会在“输出”页签返回查询结果。 图1 返回结果 测试成功,单击编辑器上方的,启用发布脚本。
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“queryWorker”,单击“添加”。 当编辑已有脚本时,为防止编辑时多人篡改,编辑前请单击进行锁定。 在代码编辑器中插入如下脚本代码。 import * as context from 'context'; import * as db from 'db'; //使用数据对象PortalUser(业务用户) @useObject(['PortalUser']) @action.object({ type: "param" }) export class ActionInput { } @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'Any', label: 'object', isCollection: true }) userList: object[]; } @action.object({ type: "method" }) export class QueryWorker { @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public queryWorker(input: ActionInput): ActionOutput { let out = new ActionOutput(); let portalUserObject = db.object('PortalUser'); //查询用户类型为ms(维修人员)的用户。(注册用户的脚本中设置了用户类型) let portalUsers = portalUserObject.queryByCondition({ "conjunction": "AND", "conditions": [{ "field": "userType", "operator": "eq", "value": "ms" }] }); //将查询结果转换为选项列表的形式(id和name)。 let selectValue = portalUsers.map(function (v, i, a) { return { 'value': { "id": v['id'], "name": v['usrName'] }, 'display': v['usrName'] } }); //当前登录的用户为平台用户(非业务用户),则加入到维修人员列表中,用于测试。 if (context.getUserType() == context.UserType.User) { selectValue.push({ 'value': { "id": context.getUserId(), "name": context.getUserName() }, 'display': context.getUserName() }); } out.userList = selectValue; return out; } } 单击编辑器上方的,保存脚本。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部,单击测试窗口右上角执行图标。 执行成功,会在“输出”页签返回查询结果,请记录“name”值,此参数在创建“派单功能”脚本会作为输入参数使用。 图1 输出查询出的维修人员信息 测试成功,单击编辑器上方的,启用发布脚本。
  • 操作步骤 在“HW__workOrderList”页面中,单击界面上方预览图标。 系统会弹出预览页面。 查看页面中页面布局、样式是否符合预期。 查看当前表格中的工单记录。当前表格中仅有一条测试数据,此数据是在生成工单脚本中输入的一条测试数据。 图1 查看工单记录 验证搜索功能。 在“工单标题”中,输入“电梯维修”,进行搜索,因为当前没有该标题的工单,因此搜索结果为空,然后再输入“电梯无法关门”,如果显示该工单记录,则说明搜索功能正确。 在“状态”中输入“待处理”,然后单击“搜索”,当前暂时没有“待处理”工单,因此搜索结果为空,再输入“待派单”后,单击“搜索”,则显示已存在工单,则说明搜索功能正常。 验证页面跳转事件。 单击“创建工单”,验证是否跳转到“生成工单”页面。如果页面跳转到工单列表页面,则说明验证成功。 因当前生成工单页面相关的BPM尚未创建,这里还无法验证创建工单功能。
  • 操作步骤 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”中,在鼠标放在“Page”上,单击界面上出现的“+”,在弹出菜单中选择“标准页面”。 在“标签”和“名称”文本框中输入“workOrderList”,单击“添加”。 当编辑已有标准页面时,为防止编辑时多人篡改,编辑前请单击进行锁定。 定义模型“queryWorkOrder”。 在“模型视图”中,单击“新增模型”。 添加服务模型,模型名称“queryWorkOrder”,单击“下一步”。 “选择服务类型”为“公共接口”,“项目”为“设备维修管理系统”,“选择服务”为“queryWorkOrder”,单击“下一步”,再单击“确定”。 单击页面上方的,保存模型。 定义模型“workOrderInstance”。 在“模型视图”中,单击“新增模型”。 来源选择“自定义”,模型名称“workOrderInstance”,单击“下一步”。 单击模型名后的“新增节点”,新增表1所示的节点,然后单击“下一步”,再单击“确定”。 以下字段要与“工单对象”中的字段一致,其中加粗斜体内容部分要替换为当前账号对应的命名空间前缀。 表1 新增节点 字段名称 字段类型 字段描述 id Text 记录ID HW__workOrderId__CST Text 工单Id HW__priority__CST Text 优先级 HW__title__CST Text 工单标题 HW__status__CST Text 状态 HW__assignedFme__CST Text 当前处理人 createdDate DataTime 创单时间 HW__createdBy__CST Text 创建人 单击页面上方的,保存模型。 单击“设计视图”,从“模型视图”切换到“设计视图”。 拖拽页面标题。 从基本组件列表区拖拽一个“标题”组件到“页面内容”中。 在右侧“属性”页签中,将“标题内容”修改为“现场工单列表”。 单击页面上方的,保存页面标题。 从组件列表区拖拽一个“表格”组件到“标题”的下方。 绑定表格数据模型,并设置查询结果区域。 在“设计视图”中,选中“表格”,单击右侧“属性”页签,如图2所示。 图2 为表格绑定数据模型 在“选择模型”对话框中,选中“workOrderInstance”模型,单击“确定”。绑定模型后,系统自动将模型的所有字段添加为查询结果列。 单击上图中每个字段后的,修改列标题等字段属性。 以“工单ID”为例,其属性配置如图3所示,各个字段及修改后的列名如表2所示。 图3 设置“工单ID”列的属性 表2 修改各字段的显示属性 字段名 列标题 备注 id 记录ID 启用“隐藏”属性,即设置为true HW__workOrderId__CST 工单ID - HW__priority__CST 优先级 - HW__title__CST 工单标题 - HW__status__CST 状态 - HW__assignedFme__CST 当前处理人 - createdDate 创单时间 - HW__createdBy__CST 创建人 - 单击页面上方的,保存设置。 添加“创建工单”按钮。 选中“表格”,单击右侧“属性”页签中“表格区块”中“工具栏”后的“添加”按钮。 图4 增加查询条件区域 删除工具栏中多余的按钮,只保留“新增行”。 修改“新增行”的“显示名称”为“创建工单”。 单击页面上方的,保存设置。 创建查询条件区域。 单击“模型视图”,切换到模型视图,在表格模型“table_0_condition”后,单击编辑图标。 表格组件拖入后,页面将自动生成一个表格模型。“table_0_condition”即是在前面拖入的表格对应的表格模型,模型名可能跟拖入顺序及个数有关,一般情况下模型名称为“table_0_condition”,如果名称不一致,请根据实际情况修改。 图5 编辑表格模型 在表格模型“table_0_condition”中,单击“新增节点”,添加一个“queryInfo”节点,“数据类型”为“Any”,然后在“queryInfo”下,再单击“新增节点”添加3个子节点“createdBy”、“ title”、“status”。 图6 创建完成后的模型节点 设置完成后,单击“下一步”,再单击“确定”,保存设置。 单击“设计视图”,切换到设计视图,从左侧组件列表中,拖一个“表单”组件到“表格容器”的最上部(表格容器内部最上部),在“元数据表单配置向导”弹窗中,单击“取消”。 图7 向表格容器拖入表单 选中表单,在属性中“数据绑定”下,单击,为表单绑定“table_0_condition”中的“queryInfo”节点,并在提示弹窗中,单击“绑定并生成表单”,单击“确定”。 在表单中,分别选中并删除“createdBy”、“重置”按钮。 调整“title”、“status”、“保存”为1行,并删除多余分栏及容器,调整后,如图8所示。 图8 调整后表单 修改表单中输入框属性。 修改“title”的“标签”为“工单标题”。 修改“status”的“标签”修改为“状态”。 选中“保存”按钮,修改“显示名称”为“搜索”,设置单击“事件”页签,再单击,删除“提交表单”事件,然后单击“点击”后的“+”,进入事件编排页面,在“自定义动作”中,输入以下事件代码,单击“创建”。 图9 修改按钮事件代码 脚本中红色内容请替换为实际的对象名、字段名、页面名、组件ID。其中“table_0_condition”为当前表格组件的ID号,中间数字默认为“0”,如果有多次修改或创建该ID号会变化,选中表格后,在组件树上可以查看实际组件ID。 let pageInfo = $model.ref('table_0_condition').getData().pageInfo; let queryInfo = $model.ref('table_0_condition').getData().queryInfo; if (!queryInfo) { queryInfo = {}; } let queryData = { "title": queryInfo.title, "status": queryInfo.status, "createdBy": queryInfo.createdBy, "start": 0, "limit": pageInfo.pageSize }; $model.ref('queryWorkOrder').setData({ inputParam: queryData }); $model.ref('queryWorkOrder').run().then(function (data) { $model.ref('workOrderInstance').setData(data.workOrderList); pageInfo.total = parseInt(data.total); $model.ref('table_0_condition').setData({ "pageInfo": pageInfo }); }).catch(function (error) { console.log('error is', error); }); 选中“搜索”按钮所在的栏,在右侧“样式”下的“布局”中,设置上方外边距为“30”,使“搜索”按钮上下居中显示。 图10 设置搜索按钮布局样式(位置) 查询条件区域创建后,如图11所示。 图11 查询区域 单击页面上方的,保存设置。 添加页面事件代码。 在“设计视图”中选中最外层的“页面”,在右侧“事件”页签中,单击“加载”后的“+”,进入编辑动作页面。 在“自定义动作”中,输入如下脚本代码。 let pageInfo = $model.ref('table_0_condition').getData().pageInfo; let queryData = { "start": (pageInfo.curPage - 1) * pageInfo.pageSize, "limit": pageInfo.pageSize }; $model.ref('queryWorkOrder').setData({ inputParam: queryData }); $model.ref('queryWorkOrder').run().then(function (data) { $model.ref('workOrderInstance').setData(data.workOrderList); pageInfo.total = parseInt(data.total); $model.ref('table_0_condition').setData({ "pageInfo": pageInfo }); }).catch(function (error) { console.log('error is', error); }); 单击“创建”,退出事件编排窗口。 添加“创建工单”按钮跳转事件,跳转事件功能是将页面跳转到“生成工单”页面。 选中“创建工单”按钮,在右侧“事件”页签中,单击“新增行”后的,进入事件编排页面。 在“自定义动作”中,输入以下事件代码。 //打开创建工单页面,需要根据实际页面名称修改 context.$page.load('/besBaas/page#/HW__createWorkOrder') 单击“创建”,退出事件编排窗口。 单击页面上的,保存页面。
  • 创建“查询工单”公共接口 在“我的应用”中,单击“设备维修管理系统”,进入应用。 单击页面下方的“服务”,进入公共接口创建页面。 单击“新建”,创建“查询工单”脚本“HW__queryWorkOrder”的公共接口。 设置接口参数信息:操作名称为“queryWorkOrder”,版本为“1.0.0”,URL为“/queryWorkOrder”,“类型”选择“脚本”,“资源”为“HW__queryWorkOrder”,方法为“POST”,然后单击“保存”。 其中,“HW__”前缀由租户命名空间namespace决定,请根据实际情况进行选择。 图2 新建queryWorkOrder接口
  • 创建“查询工单”脚本 在“我的应用”中,单击“设备维修管理系统”,进入应用。 在“WorkOrder”目录中,将鼠标放在“Script”上,单击界面上出现的“+”,在弹出菜单中选择“脚本”。 在弹窗中,选中“创建一个新脚本”,在“名称”文本框中输入“queryWorkOrder”,单击“添加”。 系统实际创建的脚本名称为“HW__queryWorkOrder”,“HW__”前缀由租户命名空间namespace决定。新建创建的脚本,默认是当前用户锁定状态,可以进行编辑保存等操作。 当编辑已有脚本时,为防止编辑时多人篡改,编辑前请单击进行锁定。 在代码编辑器中插入如下脚本代码。 脚本中红色内容请替换为实际的对象名、字段名。 import * as context from 'context'; import * as db from 'db'; import * as decimal from 'decimal';//导入decimal数据类型相关的标准库 @useObject(['HW__WorkOrder__CST']) @action.object({ type: "param" }) export class ActionInput { @action.param({ type: 'String' }) title: string; @action.param({ type: 'String' }) status: string; @action.param({ type: 'String' }) createdBy: string; @action.param({ type: 'Boolean' }) isFME: boolean; @action.param({ type: 'Number', min: 0 }) start: decimal.Decimal;//分页信息,表示从第几条数据开始查询 @action.param({ type: 'Number', min: 0 }) limit: decimal.Decimal;//分页信息,表示一次查询几条数据 } @action.object({ type: "param" }) export class ActionOutput { @action.param({ type: 'Any', label: 'object', isCollection: true }) workOrderList: object[]; @action.param({ type: 'String' }) total: string;//总共查到几条数据 } @action.object({ type: "method" }) export class QueryWorkOrder { @action.method({ input: 'ActionInput', output: 'ActionOutput' }) public queryWorkOrder(input: ActionInput): ActionOutput { let out = new ActionOutput(); //新建出参ActionOutput类型的实例,作为返回值 let error = new Error(); //新建错误类型的实例,用于在发生错误时保存错误信息 try { let s = db.object('HW__WorkOrder__CST'); //获取HW__WorkOrder__CST这个Object的操作实例 //condition是db标准库queryByCondition方法的入参(查询条件) let condition = { "conjunction": "AND", "conditions": [] }; //基本查询条件 condition.conditions.push({ "field": "id", "operator": "isnotnull", }); condition.conditions.push({ "field": "id", "operator": "ne", "value": "" }); //按title查询 if (input.title && input.title != "") { condition.conditions.push({ "field": "HW__title__CST",//与对象中的字段名保持一致 "operator": "contains", "value": input.title }); } //按status查询 if (input.status && input.status != "") { condition.conditions.push({ "field": "HW__status__CST",//与对象中的字段名保持一致 "operator": "eq", "value": input.status }); } //按title查询 if (input.createdBy && input.createdBy != "") { condition.conditions.push({ "field": "createdBy",//与对象中的字段名保持一致 "operator": "eq", "value": input.createdBy }); } if (input.isFME) { condition.conditions.push({ "field": "HW__assignedFme__CST", "operator": "eq", "value": context.getUserName() }); } let option = { "options": { "orderby": [{ "field": "createdDate", "order": "desc" }] } }; //如果有分页 if (input.start && input.limit) { let start = decimal.toNumber(input.start);//将decimal类型转换为接口需要的number类型 let limit = decimal.toNumber(input.limit); option.options['limit'] = limit; option.options['skip'] = start; } let workOrderList = s.queryByCondition(condition, option); for (let i in workOrderList) { if (workOrderList[i].HW__status__CST == "关闭") { workOrderList[i].isDeal = true; } } out.workOrderList = workOrderList; //调用查询符合condition条件的数据总数的接口 out.total = s.count(condition) + ""; } catch (error) { console.error(error.name, error.message); context.setError(error.name, error.message); } return out; } } 单击编辑器上方的,保存图标。 测试脚本能否正常执行。 单击编辑器上方的,执行脚本。 在界面底部,查询脚本可以不提供输入参数,直接单击测试窗口右上角执行图标。 执行成功,会在“输出”页签返回查询结果。 图1 输出结果示例 测试成功,单击编辑器上方的,启用发布脚本。
  • 实现“生成工单” 通过定义“提交”按钮的“点击”事件,实现生成工单的能力。定义“取消”按钮的“点击”事件,返回工单列表页面(客服人员)。 定义“提交”按钮“点击”事件。 在“HW__createWorkOrder”页面的“设计视图”下,选中“提交”按钮。 在右侧“事件”页签中,单击“点击”后的“+”。 在“添加动作”弹窗的“自定义动作”中,输入如下事件代码。 脚本中加粗斜体内容请替换为实际的命名空间前缀。 // 配置页面的bpm参数bp.name,通过submitTask方法启动BPM并提交工单数据workOrderData到BPM context.$page.params["bp.name"] = "HW__WorkOrderBpm"; let basicInfo = $model.get('basicInfo').getData(); basicInfo.HW__workOrderId__CST = basicInfo.HW__type__CST + "_" + new Date().getTime(); let workOrderData = { "workOrderData": basicInfo }; context.$bp.submitTask(workOrderData).then(function (resp) { context.$page.loadStdPage('HW__workOrderList'); }); 单击“创建”,退出事件编排窗口。 定义“取消”按钮的“点击”事件。 在“设计视图”中,选中“取消”按钮。 参考“提交”按钮,给“取消”按钮定义以下代码事件 //返回工单列表页面 context.$page.loadStdPage('HW__workOrderList'); 单击“创建”,退出事件编排窗口。
  • 验证 页面组装及事件添加完成后,需要在预览页面,初步检查页面预览效果,验证页面的数据绑定及事件代码正确性。当前工单流转相关的BPM及工单列表尚未创建,因此暂不验证“保存”、“取消”按钮。 在“HW__createWorkOrder”页面中,单击界面上方的,进入预览页面。 系统会弹出“HW__createWorkOrder”预览页面。 在“基本信息”区域的“设备名称”下拉框中,选中一个设备名称,检查“设备详情”区域是否显示了对应的设备详情。显示正确,则说明组件与模型的绑定,以及下拉框事件执行正确。如不显示,则需要检查相关事件代码。 检查“工单类型”、“优先级”下拉框中,是否有值,显示正确则说明下拉框属性设置正确。
共100000条