本文是讲解如何用jxTMS来开发jxTMS示例之故障排查的系列文章中的第二篇。整个系列的文章请查看:如何用jxTMS开发一个功能

维修工程师的现场操作

上文讲过,维修工程师在服务现场有三种操作:

  • 如果对如何故障以及如何排查不是很清楚,可以通过微信机器人来查询类似案例或该型设备常见故障极其排查之类的支撑知识

  • 处置告一段落,不管是否修复,都应录入本次现场维护的记录。根据这一记录,可衍生出该工程师的工作日报、周报等;该设备的维修台账;以及相关的客户报告、故障案例等知识产品。所以维护记录是本功能的核心环节,在和客户沟通需求时,应考虑在管理制度方面加强考核

  • 不管是否修复,都需客户对本次服务的报告现场签名

由于这三种操作,都需要维修工程师在企业微信中进行操作,所以不但需要先注册到jxTMS并开通企业微信机器人。

故障Case查询

在上文的开Case中,将新开的Case指定给哪个维修工程师,该工程师就可以在微信机器人中查看到指派给自己来维护的这个故障Case。

当前,这里有一个缺漏:就是没有通知被指派的维修工程师有新的Case被指派给自己了。主要是,嗯,就是因为bugCase在开发时是笔者一个人操作的,自己指派给自己,所以自己当然会知道的,所以就忘了还需要通知相应的维修工程师:(

通知维修工程师也比较简单:

self.sendWXMsg(db,ctx,wxAppName,被指派者的简称,消息模板,参数s)
如,bugCase应是:
self.sendWXMsg(db,ctx,'tms',bugRepairor,'有新故障指派给你维修:{}'.decode('utf-8'),bugName)

但是,sendWXMsg如果人员不存在或微信消息发送过程中出现问题就会掷出异常,就会导致新开的Case被回滚,导致被撤销。

所以呢,要么是给本语句加个try来阻止异常时导致创建Case事务被回滚,导致用户辛苦敲了半天却啥都没了:( 但这可能导致业务停顿,即新的Case没人通知维修工程师去执行。

要么,就是失败就失败,弹窗告诉用户就好,但不能关闭开Case的界面,让用户再选一个新的工程师来派单,或干脆不指定维修工程师,等问题解决了再手工指派。

这些内容就是业务的复杂性所在,用户更可能根据自己顾客的反馈而不断的要进行业务操作细节的调整,而这种微小的调整恰好就是jxTMS低成本快速定制的优势了。

也就是说,传统的软件开发模式是一次开发成型,然后业务细节都被固化了。以后就只能依靠人来适应业务场景的细微变化,当这种变化过大,就会导致业务软件的不可用。而jxTMS的开发思路从一开始就是:业务想如何调就如何调,只要我成本够低、速度够快、业务够稳健就好。而能同时做到这些的,就是简单、简洁。

只有足够的简单,成本才会低;只有足够的简单,调整速度才会快;只有足够的简单,bug才不容易蔓延、才容易发现。

说完一个疏漏所引出的额外话,回到正题。我们还是从入口、界面、数据、业务逻辑四个方面来讲解如何开发本功能。

1、入口

想在企业微信中查看到一个已有的案例,和web端一样,都需要从一个列表查询开始,然后从列表中选择自己感兴趣的那一个进行查看。

微信机器人中添加一个列表查询的入口和web是不一样的,是通过对capa.py文件中的相应事件响应函数用wxDataTable修饰:

#安装一个故障管理->我的工单的微信机器人入口
@myModule.wxDataTable('tms','我的工单'.decode('utf-8'),'故障管理'.decode('utf-8'))
@myModule.event('prepareDisp', 'wxListMyCase')
def wxListMyCase(self, db, ctx):#和op.py中的定义基本一样,查看op.py中的注释就好self.setParam('resultType','json')self.setParam('listTable','wxListMyCaset1')self.setParam('dataSource','bugCase.sqlwxListMyBugCase')#web端每页默认是15行,微信机器人的信息密度受限,这里设置为了8行self.setParam('limit',8)#微信机器人没有分页控件的配合,所以是直接输出self.startSearch(db,ctx,True)

热机刷新后,该入口【故障管理->我的工单】就会出现在微信机器人的菜单中。

大家看一下web文件中wxListMyCase的定义,可以看到:

with wxListMyCaset1 col op1 head 操作 web n type a width=80,text='查看',ignoreCapaid=true,primary=true,capaname='bugCase.main',motion=disp,demand=wxDispCase,require=[{"paramName":"joID"}];

微信机器人在逐行显示分配给自己排查的故障时,当看到上述的type为a的控件后,就会自动为其动态生成一个入口,用户在列表完毕后,只要输入相应的行号,微信机器人就会调用这个入口,并用该行数据中的joID为参数,来显示该故障的详情。

大家再看下op.py,大家会发现其中有如下的设置:

#声明了一个名为【添加维修记录】的工具条
@biz.Demand('cmd','wxAddBugRepairOP')
@biz.OPDescr
def op(json):json.setA().text('添加维修记录'.decode('utf-8'))json.dispCondition('field.State!=已修复'.decode('utf-8'))#声明了一个名为【请求客户签名】的工具条
#该功能是专用于企业微信中请客户手签图片的上传的
@biz.Demand('cmd','requestCustomSign')
@biz.OPDescr
def op(json):json.setA().text('请求客户签名'.decode('utf-8'))json.dispCondition('field.Result==无'.decode('utf-8'))@biz.OPDescr
def oplink(json):#将【请求客户签名】链接给【微信查看bug】json.setBtnList('disp.wxDispCase', 'cmd.requestCustomSign')@biz.OPDescr
def oplink(json):#将【wx添加维修记录】链接给【微信查看bug】json.setBtnList('disp.wxDispCase', 'cmd.wxAddBugRepairOP')

这样在微信机器人中显示完故障详情后,就会提示这两个操作入口:

我们梳理一下,在微信机器人的故障工单这一部分,就有四个入口:

  • 在wxListMyCase的prepareDisp事件响应函数定义时,我们用wxDataTable给其声明了一个在tms机器人中【故障管理->我的工单】

  • 在列表我的工单时,给每一个故障Case,根据web文件中wxListMyCase界面的定义,都动态的添加了一个【查看故障详情】的入口:bugCase.main.disp.wxDispCase

  • 在op.py文件中,声明了一个【添加维修记录】的入口,并链接给【查看故障详情】

  • 在op.py文件中,声明了一个【请求客户签名】的入口,并链接给【查看故障详情】

由此,我们就根据在微信机器人中工单操作的动作序列,定义了相应的动作处理函数、进行了相应的入口设计并分配到相应的位置上。

2、web界面设计

微信机器人的界面设计就是直接将web端的界面转换过来的,所以并无区别,大家直接看web文件中的wxListMyCase、wxDispCase两界面的设计就好了。

大家可能要问:既然两端的界面可以通用,那为什么不共用呢?!

原因非常简单:受手机屏幕的制约,微信机器人的信息密度太低。所以大部分情况下,为了提高工作效率而特意加大了信息供给量的web界面如果直接显示到微信机器人中,就会导致一屏显示不下,而且一屏都是密密麻麻的文字,看起来太吃力了。

所以呢,一般来说,微信机器人的界面都应是web端界面的一个必要子集,但由于可能需要对其中的工具条等进行特定的设计,所以强行将两者公用反而会增加额外的麻烦。

3、数据

微信机器人和web端只是用户端不同,所以后台是通过不同的入口来调用同一个函数来处理。这里并没有特殊的设计需要做额外的说明。

4、业务逻辑

就业务逻辑来说,其它都和web相同,但需要针对微信机器人的特点进行针对性的准备和适配工作。我们主要讲解的就是这些工作。

首先,微信机器人在加载每个事件响应函数时,会调用wxDialogueInit函数,所以需要继承该函数,然后做相应的准备:

def wxDialogueInit(self,ctx,fullname):if fullname == 'bugCase.main.cmd.wxAddBugRepairOP':#因为有动态对话,所以cmd需反复执行self.wxSetActiveNotOver(True)

上述代码就是针对wxAddBugRepairOP操作【添加维修记录】要设置一个【本任务尚未执行完毕】的标记。为什么需要这么设置,继续看下去就明白了。

在该事件函数中,主要的工作都是在进行和用户通过微信机器人进行动态交互的适配:

#声明微信机器人中的故障排查操作
@myModule.wxOP('tms','故障排查操作'.decode('utf-8'),None)
@myModule.event('cmd', 'wxAddBugRepairOP')
def wxAddBugRepairOP(self, db, ctx):#现在是微信机器人和用户的对话式动态交互时间#本来微信机器人和用户的交互最好是搞成阻塞式的,这样逻辑比较顺而且简洁的多#但阻塞式会导致本函数挂起,而jxTMS当然担心开发者将程序挂起来了,如执行了死循环之类的#所以有一个死锁检测机制,一旦用户程序挂起,就会将其杀掉,所以最后只好采用了这种设计形式##首先检测用户是否输入了操作?op = self.getInputString('repairOP')if utils.isNull(op):#还没有输入,则通过机器人向用户提示:操作,还给了客户一个选择列表让客户来选:#检测调试、施工、拆卸设备待修、更换设备self.wxInteractive('repairOP','操作'.decode('utf-8'),'检测调试'.decode('utf-8'),'施工'.decode('utf-8'),'拆卸设备待修'.decode('utf-8'),'更换设备'.decode('utf-8'))#用户还没输入,当然要先结束掉了return#检测用户是否输入了操作结果?opResult = self.getInputString('opResult')if utils.isNull(opResult):#还没有输入,则通过机器人向用户提示:结果,还给了客户一个选择列表让客户来选:#未修复、新故障现象、部分修复、已修复self.wxInteractive('opResult','结果'.decode('utf-8'),'未修复'.decode('utf-8'),'新故障现象'.decode('utf-8'),'部分修复'.decode('utf-8'),'已修复'.decode('utf-8'))#用户还没输入,当然要先结束掉了return#检测用户是否输入了操作说明?opDescr = self.getInputString('opDescr')if utils.isNull(opDescr):#还没有输入,则通过机器人向用户提示:说明,这就不需要客户来选了self.wxInteractive('opDescr','说明'.decode('utf-8'))#用户还没输入,当然要先结束掉了return#微信机器人和web的数据要统一,而web中的opDescr是由textarea输入的,是base64编码后的#微信机器人则是用户输入什么就直接给到过来,#所以要用base64编码后再设置回去,才能统一用_addBugRepairOP函数来处理opDescr = self.getInput2Base64('opDescr')self.setValue('opDescr',opDescr)#操作、结果、说明这三项,用户都输入了则调用_addBugRepairOPself._addBugRepairOP(db,ctx)#本命令现在执行完了,就不再和交互过程中那样还需要留下来等待接收用户输入self.wxSetActiveNotOver(False)

大家看代码中的注释,解释了微信机器人的交互为什么会设计成了这个怪模样:由于jxTMS会检测事件响应函数是否锁死,所以就不能设计成阻塞模式。所以就只能是一个循环:检查当前状态、根据当前状态和用户动态互动,一直到状态满足。

也就是说,jxTMS的微信机器人交互,其实就是有一个状态变量表,然后不断循环查询该状态变量中的状态变量是否都已经有值了/满足状态要求了,不满足就请求用户输入。都满足了才能继续执行。

这就是在开始的初始化中,为什么要告诉jxTMS本事件响应函数未执行完,因为需要先动态收集所有的状态,在状态满足后/用户输入了所有需要的变量,才能真正开始执行。而执行完毕的最后一个语句,就是撤销这个为执行完的设置,以便于jxTMS将控制权转移给【查看故障详情】。

请求客户签名的业务逻辑

先上代码,我们对着代码来解释:

#声明微信机器人中的请求客户签名,其还带有一个提示:请上传用户签名后的截屏图片
@myModule.wxPrompt('signImgUri', '请上传用户签名后的截屏图片'.decode('utf-8'),None)
@myModule.wxOP('tms','请求客户签名'.decode('utf-8'),None)
@myModule.event('cmd', 'requestCustomSign')
def requestCustomSign(self, db, ctx):#wxPrompt会提示用户上传签名图片,用户上传的图片其文件名就会放到signImgUri#用户上传的文件有两个路径,一个是绝对路径,因为系统要保存图片#一个是相对web根目录的路径,因为还要将图片显示给用户看#这里直接给到用户的是相对web根目录的路径,因为故障查询列表时就可以直接看到图片uri = self.getInputString('signImgUri')if not utils.isNull(uri):self.receiverWXFile(ctx,'tms',uri,1)result = self.getInputBoolean('receivedFile')if result:wfn = self.getInputString('filePathFromWeb')t = self.currentAffairself.setFieldWithNameTrans(db,t,'customSign',"已签".decode('utf-8'))fg = fulltextTag.get(db.getDBConn(),t.ID,'custom')#将签名图片的相对路径保存到custom中self.setFieldWithNameTrans(db,fg,'customSignImg',wfn)return False

【请求客户签名】和【故障排查操作】相比,首先就是多了个wxPrompt,大家实际操作一下,就会看到jxTMS会提示:请上传用户签名后的截屏图片。

大家是否看明白了一点:【故障排查操作】和用户的交互是在代码中用wxInteractive动态指定的,而【请求客户签名】是用wxPrompt静态预定义的。所以【故障排查操作】需要在初始化时调用wxSetActiveNotOver设置需等待交互,而执行完毕再予以清除;而【请求客户签名】则不需要如此操作。

用户上传客户签名的截屏图片后,jxTMS会将图片url提交给wxPrompt所指定的数据名:signImgUri。所以,requestCustomSign第一步就是检测signImgUri是否有效,然后就尝试用receiverWXFile来尝试获取该图片:

#最后的参数是下载下来的文件保存几个月
self.receiverWXFile(ctx,'tms',uri,1)

receiverWXFile如果从url接收到了文件,会设置三个参数:

  • receivedFile:指示是否接收成功

  • filePath:接收到的文件所在的绝对路径

  • filePathFromWeb:接收到的文件相对web根目录的相对路径,这就可以通过web端直接看到用户在企业微信中上传的图片了

剩下的工作就比较简单了,大家看之前开Case时的代码与注释就可以理解了,这里就不复赘述了。

由于维修工程师通过微信机器人得到知识支撑的操作是比故障排查的操作简单的,所以就不再重复了。

如何用jxTMS开发一个功能(二)相关推荐

  1. php做网站步骤_新手如何用PHP开发一个完整的网站?

    1.PHPer应具备的知识 (1)PHP知识: 熟练掌握基础函数,PHP语句(条件.循环),数组(排序.读取),函数(内部 构造),运算(数学 逻辑),面向对象(继承 接口 封装 多态静态属性)等. ...

  2. 如何用java开发一个网站?

    问题:如何用java开发一个网站? 下载了最新的JDK软件.最新的Eclipse.数据库mysql以及tomcat.struts但是不知道怎么连接起来,在数据库连接的时候mysql-connector ...

  3. 国外大牛教你,如何用Python开发一个简单的区块链数据结构| 建议收藏

    来源 | Medium 作者 | arjuna sky kok 整理 / Aholiab 出品 | 区块链大本营(blockchain_camp) 根据IEEE此前的一项调查,Python已成为最受开 ...

  4. Android-如何开发一个功能强大的图片选择器

    图片选择器是Android开发中会经常用到的一个功能,特别对于社交类的应用,比如头像设置,比如发图片.自然ImagePicker的轮子很多,今天介绍一个功能强大的轮子SImagePicker 介绍 首 ...

  5. 如何用 Python开发一个简单的 Webkit 浏览器

    在这篇教程中,我们会用 Python 的 PyQt 框架编写一个简单的 web 浏览器.关于 PyQt ,你可能已经有所耳闻了,它是 Qt 框架下的一系列 Python 组件,而 Qt(发音类似&qu ...

  6. 合肥达内培训php,合肥达内PHP培训教你如何用PHP开发一个完整的网站

    一.PHPer应具备的知识 (1)PHP知识:熟练掌握基础函数,PHP语句(条件.循环),数组(排序.读取),函数(内部构造),运算(数学逻辑),面向对象(继承接口封装多态静态属性)等.了解Cooki ...

  7. 用php做一个网站,如何用PHP开发一个完整的网站

    互联网是顺应时代潮流出现的一个产物,他把地球带到了一个前所未有的是带他帮助世界各国完成了很多不能完成的科技项目,只有这样的互联网才能称之为一个完美的世界,也就有了php语言的诞生,php编程语言从诞生 ...

  8. 用java和mysql开发网站怎么实现_如何用java开发一个网站?

    java语言和类库:java语言是支持整个java技术的底层基础,java类库是随java语言 Java 运行系统:主要指java虚拟机,负责将java与平台无关的中间代码翻译成本机的 Java ap ...

  9. python广告营销平台_如何用 Python 开发一个【视频营销号】生成器?

    ​之前小帅b在网上看到一个营销号文案生成器,把我给乐的: 其实这个用 Python 实现非常简单,根据用户输入的内容,简单替换一下关键字就可以了,我随手写了一下生成方法: 调用一波: 是不是老小编了? ...

最新文章

  1. DPDK有关变量(二)
  2. hadoop学习--基于Hive的Hadoop日志分析
  3. Android 权限问题
  4. vi(vim)常用命令汇总
  5. Nginx+Php-fpm+MySQL+Redis源代码编译安装指南
  6. 素数环(nyoj488)
  7. azure云数据库_在Azure Cosmos DB中使用PowerShell创建和删除数据库
  8. Windows server 2003 DNS子域与委派管理配置指南
  9. 第二季-专题7-ARM跑快了---时钟初始化
  10. Zookeeeper开源客户端curator watcherAPI的使用
  11. ASP.NET实现PDF大文件的浏览
  12. 西门子S7-200SMART PLC视频教程(百度网盘)
  13. 解决MacOS系统字体不识别STXingkai问题
  14. 百度 UNIT 使用
  15. 多频子量子计算机,量子计算机研究:纠错和容错计算
  16. python numpy逆_Numpy 中的矩阵求逆实例
  17. 实验验证二项分布(Binomial)公式正确性
  18. 阿里云Nginx配置站点403Forbidden问题
  19. 最小二乘估计的Matlab仿真
  20. Vlan总结(Chinaitlab教程)

热门文章

  1. android 乱码问题
  2. [渝粤教育] 西华大学 模拟电子技术基础 参考 资料
  3. web页面-页面操作-窗口/iframe/alert切换
  4. 计算机绘画课程安排,电脑绘画计划及内容安排..doc
  5. dsge模型难做吗_DSGE模型到底有用吗?
  6. 手机语音翻译怎么做?分享一个简单办法,快速实现中英文语音对话
  7. 短视频APP源码直播APP源码什么样的好
  8. 剑指Offer66—构建乘积数组
  9. 微信小程序input禁止空格输入
  10. 实地探访:揭秘Waymo凤凰城的无人车大本营【附视频】