使用本示例需通过docker容器,请先下拉jxTMS的docker镜像并按说明启动tms容器,并从helloWorld开始尝试。
角色与权限
我们之前的演示中,包括流程在内,所有工作都是manager执行的,作为演示这是可以的。但实际工作中,工作都是按职能进行分配的,尤其是流程,是不同人员分工配合的。那么,我们该如何进行任务分配呢?
jxTMS中分工协作与权限控制的核心是:角色。
大家回顾一下,在我们前面的定义中,流程各节点、兴趣点的定义中,都有角色的定义,即将本节点的工作分配给哪个角色来执行。然后再动态的将任务指派给该角色所映射的具体人员。
我们先做些基本工作,然后尝试在之前的演示中如何通过角色来分配工作并控制权限。
增加人员
点击快捷栏中的【人员管理->新增人员】,然后在名称栏和别名栏中分别填入user1,登录名栏中不填,然后点击【增加】按钮;再在名称栏和别名栏中分别填入user2,登录名栏中不填,然后点击【增加】按钮。即,增加了两个用户:user1、user2。
注:登录名不用给出,系统会自动给出并避免重复
增加角色
点击快捷栏中的【角色管理->创建角色】,然后在名称栏中填入r1,【职级】随便填一个10,勾选【真实角色】,然后点击【增加】按钮;再在名称栏填入r2,然后点击【增加】按钮。即,增加了两个角色:r1、r2。
注:职级在jxTMS中尚未用到,大家根据自己的业务需要填写。真实角色的含义请参考:角色
为了让大家理解,然后在名称栏中填入r3,把【真实角色】勾掉,然后点击【增加】按钮。即,我们在r1、r2两个真实角色之外又增加了一个虚拟的角色。
角色和人员的映射
点击快捷栏中的【角色管理->角色列表】,大家可以看到我们刚才增加的三个角色,点击r1后面的【查看】,然后点击界面上方的【映射人员】工具条,然后在弹出的对话框中勾选user1后点击【确认】按钮,即将r1角色映射到了user1用户,然后按同样的操作,将r2映射到user2用户。
围绕角色调整权限
现在我们修改demo1中的sfDemo流程中的定义,将原本分配给manager的工作指派给其他人:
@myModule.simpleFlow('sfDemo')
def sfDemo():
'''
web sfDemo;
node demoApply 申请 web sfDemoApply ;
node demoConfirm 审核 web sfDemoConfirm needRole r1 notJump;
node demoApprove 审批 web sfDemoApprove needRole r2 notJump;
'''
pass
即将审核指派给角色r1来执行、将审批指派给角色r2来执行。
将capa.py文件件按用sftp管理jxTMS的代码所述更新到/home/tms/codeDefine/demo/demo/demo1目录中。
然后执行一次热机刷新后,点击快捷栏中的【演示->发起申请】,然后和之前的演示一样启动这个流程。这个时候,大家看看快捷栏中的消息那是否还有提示。
请点击快捷栏中的【人员管理->人员列表】,分别记住user1和user2的登录名。
然后请大家再打开一个新的页面访问本地的jxTMS,在弹出的登录对话框的名字那,将之前登录的manager改为user1的登录名后登录。
这时大家会看到,相比manager用户,快捷栏中少了很多项。点击【消息->我在做的任务】会看到刚发起的申请流程的审核工作,点击该任务,在弹出的流程界面中点击审核节点的【同意】按钮。
然后请大家刷新页面,在弹出的登录对话框的名字那,将之前登录的manager该为user2的登录名后登录。
同审核的操作一样,请大家自行完成审批工作。
大家请回想一下,刚才都发生了什么?
我们回顾一下:
-
manager和user1、user2看到的快捷栏是不一样的
-
sfDemo中将审核指派给r1执行,而我们在上面将r1映射给了user1,所以我们以user1登录时,确实从【消息->我在做的任务】中接收到了该任务并可以执行
-
同理,审批我们指派给了r2执行,所以我们用user2登录后,就可以执行审批工作
-
我们如果通过快捷栏【演示->demo简易流程查询】查看我们刚才执行的流程,会看到审核和审批节点的签发人确实是user1和user2
这里面涉及到了两个问题:
1、权限:对于信息系统来说,权限很简单,就是你能否看到、能否点击了执行。jxTMS的处理就非常简单:你有没有这个访问入口。你能从快捷栏中看到某入口,你就有相应的查看访问的权限,连带着你就有了所有未遮挡的界面中的各个按钮的点击执行权限。即在jxTMS中,能看就能点。如果你不想某人可以点击某个界面中的某个按钮,有两种解决办法:
- 做一个新的界面,分别放置不同的按钮,然后把这些放有不同按钮的界面在op.py中指派给不同的角色
注:参考入口中的示例,入口定义中使用role函数可以非常简单的将不同的入口授予不同的角色
- 将这个按钮所对应的功能做成一个工具条型的入口并使用role函数将该入口指派给相应的角色,然后为当前界面关联这个工具条型的入口【参考前面我们是如何给流程增加追溯的】
由于jxTMS也可以支持开发者自己开发静态的web界面,然后用jxTMS作为后台提供访问接口,所以jxTMS中的权限许可原则是:
-
op.py中定义的入口中如果用role指定了某角色,则该角色在jxTMS提供的动态界面中可以看到该入口。后台会根据op.py中的role来对访问者授权,未被许可的访问会被掷出无权执行的异常
-
role函数所指定的角色可以是真实角色也可以是虚拟角色
-
op.py中的入口如果未指定角色,如我们之前demo1中所添加的入口,则所有用户都可以看到并访问
-
动态界面中的按钮所对应的入口隐性的追随本界面的权限,即打开一个界面后,该界面上的所有按钮只要未被遮挡都有权访问。但如果是自己开发的静态界面自然没有这个能力,只能一一为静态前端的按钮定义入口并指派角色实现授权
2、任务指派:目前为止,任务指派一是流程节点中、二是兴趣点。其中兴趣点类似于一种授权,只要在定义时指定了角色,这些角色所对应的用户就可以在条件满足时看到相关的信息。但流程节点的任务指派则有所不同。
当任务流转到某流程节点时,该节点的任务指派具体过程为:
-
用户是否手动指定了具体的执行人,如果输入变量【executorID】中被指定了某用户的ID,则任务直接指派给该用户执行
-
如果本节点之前有人执行过【一般是被打回重新执行】,则任务被指派给该用户执行,这是为了提供工作效率,避免新人执行老任务导致执行人还得再去熟悉
-
我们是否在流程的节点定义中指定了由哪个角色来执行,如果指定了,则根据该角色所映射的人员进行指派
注:如果该角色有多人映射,则会随机确定一个
-
如果指派给了当前用户【如某人审批自己的申请】,同时该节点设置为canJump,则不会指派【即执行人未确定】
-
如果未确定执行人,则本节点被默认同意后流转到下一个节点执行
流程节点中的角色
流程节点的执行角色可以是:
-
真实角色。如果是真实角色,建议最好该角色只会映射给一个人,否则具体映射给哪个人是不明确的,可能会造成混乱
-
虚拟角色。为什么会有虚拟角色呢?很简单的原因,报销流程中,一般在申请后的节点就是部门经理审核,那么如果这一环节使用真实角色,难道技术部要做一个技术部报销流程、销售部再做一个销售部报销流程吗?如果一个公司有几十个部门,难道还要做几十个报销流程吗?所以这里显然就应该是虚拟角色:部门经理。然后根据申请人所在的部门,确定实际上应该是那个部门的部门经理
即,对于通用的流程,各部门都有的审核审批节点,应该用虚拟角色,jxTMS会根据部门-子部门关系所形成组织结构,自底向上来确定将虚拟角色转换为具体的真实角色。
那么,问题来了:报销流程中,如果是部门经理自己发起的申请呢?简单,上面说了,如果某节点【这里是部门经理审核节点】的执行人是当前用户,而该节点被设置为canJump,则该节点被默认同意后流转到下一个节点执行。即,部门经理自己提交的报销申请会自动跳过【部门经理审核】节点流转到下一个节点。
还有问题:部门经理的上级是总监,那如果总监提交了一个报销审批呢?难道还得由其下属审核后再提交给自己审批?!当然不会,因为总监所在的部门没有部门经理啊。大家仔细想一下,假设技术部下有软件部、测试部、集成部,那么软件部等有部门经理,技术部只有技术总监啊。所以,技术总监所对应的部门是技术部,而技术部没有部门经理,所以无法确定执行角色,就更不可能确定执行人了,所以本节点会被默认同意后流转到下一个节点执行,即流转给技术总监审批,而技术总监又是自己,所以如果审批节点也被设置为canJump的话,就会又被默认同意后流转到下一个节点执行。
嗯,还有一个问题:技术部是没有部门经理,但总归可能会有秘书等总监直属的下属,那么她们的申请会如何流转呢?因为技术部没有部门经理,所以【部门经理审核】节点就会被跳过,然后流转到总监审批。即恰好是给她们的直属上级进行审批。
注:如果需要在流程中用到虚拟角色,则必须通过部门形成组织结构
目前的jxTMS未提供关于部门的管理,创建角色时也没有关联所在部门的相关动作,但通过【人员管理->导入人员】可以将【importOrg.xls】文件整个导入,其中就包括了如何创建部门。对应的代码实现在codeDefine/manager/people中的importUser函数,大家可以对照该文件阅读笔者在importUser函数中所加的注释来理解如何导入人员。
注:大家在导入人员时,可以分别在导入角色的代码中以及在导入人员的代码中分别制造一个错误,如除零。看看会有何不同?
不同在于:
-
importUser函数中的异常,会导致数据库回滚,也就是说我们之前以及导入的部门信息也一并被撤销了,并未写入到数据库中;但myImportUser函数在delayImportUser函数中被延迟2000毫秒后在另一个线程中启动的,而随着importUser函数执行完毕,其所有的数据库操作都会被提交,所以myImportUser再出现异常也只会回滚myImportUser中的数据库操作,而无法回滚importUser中的数据库操作。这就会导致数据库事务的割裂。对于演示来说,这无所谓,但对于正常的业务,可能就是严重的问题
-
执行完毕后,importUser函数中的异常会在web端弹出错误提示;而myImportUser函数中的异常则不会在web端捕获,即大家看到的依然是正常的执行完毕的提示,myImportUser函数中的错误只能通过后台日志才能看到
所以大家在对复杂业务的处理中,应当注意不要如演示中所演示的:拿数据库来作中间数据的中转。这会导致如myImportUser函数一样被拆分到一个延迟执行的函数中执行,从而诱发上述的种种问题。