工作流使用
工作流使用
1. 设置详情、审批界面
注:这里的配置是针对,走统一的消息待办,移动端的实现是靠消息待办实现
模型下设置 业务表详情界面
- formPage:PC端的路由path (需要注意的是,如果是三级菜单需要带入二级菜单路径,例如:
ocdetail/ocBargainingForm) - appFormPage: APP 端的路由path
- approvalPage:自定义的审批界面(针对驳回的场景,目前一般都是跳转到添加界面)如果都是跳转到详情界面操作则不用指定这个字段 PC端
- appApprovalPage:自定义的审批界面(针对驳回的场景,目前一般都是跳转到添加界面)如果都是跳转到详情界面操作则不用指定这个字段 app端
- formPopupPage:
popup考虑某些页面是用弹窗的方式进行操作
注:目前考虑到如果跳转的是页面(不是tab页面),这样就会出现缓存问题,这里,需要使用自定义的手动刷新功能
所以 设置 formPage/appFormPage 就不建议是path,因为如果是三级菜单,需要带上二级路径才能正常跳转,同时 手动刷新功能需要的是组件name,
这里需要保证,几个名称一致
- 菜单设置path
- 组件名称
- 路由对应的实际name(目前代码中会强行将首字母改为大写)


2. 设置自定义表单
点击 任务节点,选择自定义的表单
目前至少要有 (字段尽量和我的保持一直,后期会取这2个变量,展示在流转记录中)
审批描述:comment
审批意见:commentType


3. 流转条件
取消:
${commentType=='cancel'}通过:
${commentType=='y'}驳回:
${commentType=='n'}撤回:
${commentType=='recall'}
4. 业务表数据状态变更的处理
对于涉及到业务表状态变革的,通过自定义变量实现
目前考虑了2个场景:
businessStatus:针对的是 主表记录
参数说明 :
status:1status: 表示主表状态对于的字段1:表示当前状态对于的数值
subsidiaryTableStatus: 针对的是附属表
参数说明:
status:3:apply_id:zjjc_person总共记录4个参数status: 表示附属表状态对于的字段1:表示附属表状态对于的数值apply_id: 附属表的外键(关联主表的字段)zjjc_person: 附属表表名

5. 代办列表
代办列表现在封装在 actTaskList.vue 中需要指定 流程定义的keyprocDefKey ,不指定表示查询全部
6. 流转记录
流转记录也封装出去了,需要指定 流程实例id即可


7. 自定义表单的渲染
saveForm () {
// this.$refs.formLayoutRef.taskAudit(this.form); // 方式1 用弹窗的形式,把 审批嵌入到 form-head-layout.vue 组件中,作为公共方法
if (!this.form.taskId) {
this.$message.error('流程异常,无法审批!')
return
}
const res = this.$refs.wfFormPageRef.getVFormData()
deepCopy(this.form, res)// js 深拷贝。直接赋值 可能会覆盖数据
this.submitForm();
},

8. 调用工作流
taskContent:作为 代办内容,后期计划和消息绑定,需要在启动时指定一个默认的(目前还不完善)

@Override
@Transactional(readOnly = false)
public void saveData(ZjjcPersonApply zjjcPersonApply) {
// 1. 业务表保存
Long businessId = zjjcPersonApply.getId();
if(zjjcPersonApply.getId()==null){
// 需要验证人员 编号是否在系统人员表中存在,因为后期计划是将其作为登录账号的
//checkUserName(zjjcPersonApply);
checkUserIdCard(zjjcPersonApply); // 验证身份证号是否存在
insertZjjcPersonApply(zjjcPersonApply);
}else{
updateZjjcPersonApply(zjjcPersonApply);
}
// zj_user_audit 角色
// 2. 人员附属表保存
zjjcPersonService.saveUser(zjjcPersonApply);
// 3. 流程 handleType 操作类型 START_FLOW:启动流程
if(START_FLOW.equals(zjjcPersonApply.getHandleType())){
Map<String, Object> vars = Maps.newHashMap();
getPushMess(zjjcPersonApply,vars);
vars.put("business_dept",zjjcPersonApply.getUnitId());// 审批需要对 审批单位进行限定,需要指定单位下的指定角色才能审批
if(businessId==null){ // 表示 添加,执行启动流程
actTaskService.startProcess(FLOW[0],FLOW[1],zjjcPersonApply.getId().toString(),"桩基检测人员审核01",vars);
}else{
vars.put("commentType",zjjcPersonApply.getCommentType()); // 操作类型 y n 目前只要用于 流转记录中 打标签
Task task = actTaskService.completeForBusinessStatus(FLOW[1], zjjcPersonApply.getId().toString(), zjjcPersonApply.getProcInsId(), zjjcPersonApply.getComment(), vars);// zjjcPersonApply.getTaskId(),
// 审批通过后,需要讲人员往 系统用户表中创建,并且需要验证人员编号是否重复
if (zjjcPersonApply.getCommentType()!=null && "Y".equals(zjjcPersonApply.getCommentType().toUpperCase()) && task==null) {
saveSysUser(zjjcPersonApply); // 人员添加
}
}
}
}
@Autowired
private RemotePushService remotePushService;
// 推送附加信息
public void getPushMess(ZjjcPersonApply zjjcPersonApply, Map<String, Object> vars){
JSONObject jsonData= new JSONObject(new LinkedHashMap());
jsonData.put("basic_info",getPushBasicInfo(zjjcPersonApply));// 基本信息,主要是针对 消息
// jsonData.put("extra_info",getPushExtraInfo(zjjcPersonApply));
vars.put("push_mess",jsonData);
// 更新上个环节发送的消息 置为 已操作
remotePushService.updateMessPushStatus(null,zjjcPersonApply.getId(),zjjcPersonApply.getTaskId(),null,zjjcPersonApply.getCommentType());
}
/**
* 针对需要 拓展消息显示字段的场景
* @param zjjcPersonApply
* @return
*/
public JSONObject getPushExtraInfo(ZjjcPersonApply zjjcPersonApply){
SysUser applyUser = utils.getSysUser(zjjcPersonApply.getCreateBy());
JSONObject jsonObject= new JSONObject(new LinkedHashMap());
jsonObject.put("title","桩基人员申请");
jsonObject.put("sub_title","");// 副标题
// jsonObject.put("level","");//等级 jsonObject.put("level_name","");//等级name
jsonObject.put("type","zj_user_flow");
// 附加信息
JSONObject sonNode= new JSONObject(new LinkedHashMap());
sonNode.put("申请人员",applyUser.getNickName());
sonNode.put("申请开始",DateUtils.formatDate(zjjcPersonApply.getCreateTime() ,"yyyy.MM.dd"));
jsonObject.put("data",sonNode);
return jsonObject;
}
// 基本信息 主要是针对 消息模板中需要自定义参数的场景
public JSONArray getPushBasicInfo(ZjjcPersonApply zjjcPersonApply){
JSONArray array=new JSONArray();
SysUser applyUser = utils.getSysUser(); // zjjcPersonApply.getCreateBy()
array.add(zjjcPersonApply.getApplyNo()); // 单号
array.add(applyUser.getDept().getDeptName()); // 目前检测公司是人员所在部门
// array.add(applyUser.getCompanyName()); // 公司
array.add(applyUser.getNickName()); // 当前登陆人
return array;
}
/**
* 流程提供 删除和撤回功能
* @param zjjcPersonApply
* @return
*/
@Override
@Transactional(readOnly = false)
public void withdrawAndDele(ZjjcPersonApply zjjcPersonApply) {
if("chehui".equals(zjjcPersonApply.getHandleType())){ // 撤回
Map<String, Object> vars = Maps.newHashMap();
// getPushMess(zjjcPersonApply,vars);
// 更新上个环节发送的消息 置为 已操作
remotePushService.updateMessPushStatus(null,zjjcPersonApply.getId(),zjjcPersonApply.getTaskId(),null,"recall"); // 给上一个消息进行回执-标记为 撤回
actTaskService.withdraw(FLOW[1],zjjcPersonApply.getId().toString(),zjjcPersonApply.getProcInsId(),"uzer_edit", "申请人撤回申请", vars);
} else { // 删除
deleteApply(zjjcPersonApply);
actTaskService.deleteProcessInstance(zjjcPersonApply.getProcInsId(),"删除");
}
}
9. 监听
监听目前总共2个目的
- 考虑到审批需要指定角色+ 部门来筛选数据,所以指定 businessDept
- 配置消息,同时消息会重写代办的描述/内容

- 指定需要过滤的部门 businessDept 表达式 参数
${business_dept} - pushCode : 对应消息的code,用来推送消息的
- pushMess:消息推送内容 表达式 参数
${push_mess} - businessDept: 指定部门+岗位进行审批 参数:
${business_dept} - isNeedSms: 用来控制是否发送短信,1:表示发送,0:表示不发送(结合系统管理-参数设置中的开关)
如果想实现,指定部门+岗位进行审批,指定流程变量 business_dept -- 这个字段对应的是 监听器中配置的

10. 消息配置
// 工作流业务
public void saveActTask(ZjjcPersonApply zjjcPersonApply){
if(START_FLOW.equals(zjjcPersonApply.getHandleType())){
Map<String, Object> vars = Maps.newHashMap();
getPushMess(zjjcPersonApply,vars); // 推送消息
vars.put("business_dept",zjjcPersonApply.getUnitId());// 审批需要对 审批单位进行限定,需要指定单位下的指定角色才能审批
if(businessId==null){ // 表示 添加,执行启动流程
actTaskService.startProcess(FLOW[0],FLOW[1],zjjcPersonApply.getId().toString(),"桩基检测人员审核01",vars);
}else{
vars.put("commentType",zjjcPersonApply.getCommentType()); // 操作类型 y n 目前只要用于 流转记录中 打标签
Task task = actTaskService.completeForBusinessStatus(FLOW[1], zjjcPersonApply.getId().toString(), zjjcPersonApply.getProcInsId(), zjjcPersonApply.getComment(), vars);// zjjcPersonApply.getTaskId(),
// 审批通过后,需要讲人员往 系统用户表中创建,并且需要验证人员编号是否重复
if (zjjcPersonApply.getCommentType()!=null && "Y".equals(zjjcPersonApply.getCommentType().toUpperCase()) && task==null) {
saveSysUser(zjjcPersonApply); // 人员添加
}
}
}
}
@Autowired
private RemotePushService remotePushService;
// 推送附加信息
public void getPushMess(ZjjcPersonApply zjjcPersonApply, Map<String, Object> vars){
JSONObject jsonData= new JSONObject(new LinkedHashMap());
jsonData.put("basic_info",getPushBasicInfo(zjjcPersonApply));// 基本信息,主要是针对 消息
// jsonData.put("extra_info",getPushExtraInfo(zjjcPersonApply));
vars.put("push_mess",jsonData);
// 更新上个环节发送的消息 置为 已操作
remotePushService.updateMessPushStatus(null,zjjcPersonApply.getId(),zjjcPersonApply.getTaskId(),null,zjjcPersonApply.getCommentType());
}
/**
* 针对需要 拓展消息显示字段的场景
* @param zjjcPersonApply
* @return
*/
public JSONObject getPushExtraInfo(ZjjcPersonApply zjjcPersonApply){
SysUser applyUser = utils.getSysUser(zjjcPersonApply.getCreateBy());
JSONObject jsonObject= new JSONObject(new LinkedHashMap());
jsonObject.put("title","桩基人员申请");
jsonObject.put("sub_title","");// 副标题
// jsonObject.put("level","");//等级 jsonObject.put("level_name","");//等级name
jsonObject.put("type","zj_user_flow");
// 附加信息
JSONObject sonNode= new JSONObject(new LinkedHashMap());
sonNode.put("申请人员",applyUser.getNickName());
sonNode.put("申请开始",DateUtils.formatDate(zjjcPersonApply.getCreateTime() ,"yyyy.MM.dd"));
jsonObject.put("data",sonNode);
return jsonObject;
}
// 基本信息 主要是针对 消息模板中需要自定义参数的场景
public JSONArray getPushBasicInfo(ZjjcPersonApply zjjcPersonApply){
JSONArray array=new JSONArray();
SysUser applyUser = utils.getSysUser(); // zjjcPersonApply.getCreateBy()
array.add(zjjcPersonApply.getApplyNo()); // 单号
array.add(applyUser.getCompanyName()); // 公司
array.add(applyUser.getNickName()); // 当前登陆人
return array;
}

11. 待办列表处理按钮的名称
支持通过连线来获取
12. 消息
INSERT INTO sys_push_modules(`name`, `title`, `code`, `type_id`, `msg_type`, `opt_type`, `msg_url`, `data_scope`, `user_posts`, `object_ids`, `template`, `param_num`, `sort`, `remarks`, `del_flag`, `create_by`, `create_date`, `update_by`, `update_date`) VALUES ( '补偿协议审批单.审核', '补偿协议审批单.审核', 'oc_bcxyspd_push', 8, '1', '2', 'OcCompensationApprovalForm', '9', '', '', '{0}提交了{1},待您审批', 2, 1, 'xxx提交了2024年补偿协议审批单申请', '0', '1', '2023-04-17 00:00:00', '1', '2024-09-06 12:11:41');
INSERT INTO sys_push_modules(`name`, `title`, `code`, `type_id`, `msg_type`, `opt_type`, `msg_url`, `data_scope`, `user_posts`, `object_ids`, `template`, `param_num`, `sort`, `remarks`, `del_flag`, `create_by`, `create_date`, `update_by`, `update_date`) VALUES ( '补偿协议审批单审批.驳回', '补偿协议审批单审批.驳回', 'oc_bcxyspd_push:reject', 8, '1', '2', 'AddOcCompensationApproval', '9', NULL, '', '{0} 驳回您的{1},待您处理', 2, 20, NULL, '0', '1', '2023-04-17 00:00:00', '1', '2024-09-06 14:54:38');
INSERT INTO sys_push_modules(`name`, `title`, `code`, `type_id`, `msg_type`, `opt_type`, `msg_url`, `data_scope`, `user_posts`, `object_ids`, `template`, `param_num`, `sort`, `remarks`, `del_flag`, `create_by`, `create_date`, `update_by`, `update_date`) VALUES ('补偿协议审批单审批申请', '补偿协议审批单审批.申请', 'oc_bcxyspd_add_push', 8, '1', '2', 'AddOcCompensationApproval', '9', '', '', '{0}已经审批通过补偿协议审批单,待您提交{1}', 2, 1, '', '0', '1', '2023-04-17 00:00:00', '1', '2024-09-09 19:55:23');
其他
1. 控制是否签收
考虑到有限虚拟的节点不能进行签收,这个场景通过
isNotClaim来控制 0:需要签收,1:不需要签收场景: 清障管理中,年计划分为主流程和子流程,需要讲2个流程串联起来,所有需要在子流程中添加一个虚拟节点,但是如果进行签收,则这个虚拟节点就会变成主流程的最后一个审批人的已办任务,显然不合理
if(ocDeptApply.getIsNotClaim()!=null){
vars.put("isNotClaim", ocDeptApply.getIsNotClaim());
}
Act act = actTaskService.completeForBusinessStatus(BUSINESS_TABLE, ocDeptApply.getId().toString(), ocDeptApply.getProcInsId(), ocDeptApply.getComment(), vars, ocDeptApply.getTaskId());// ocDeptApply.getTaskId(),