云尚办公项目学习

完整的笔记可以参考这个专栏,写的挺详细的:云尚办公课件笔记,come on boy

form-create前端组件
formProps记录了表单有哪些表单项,分别是哪些类型(下拉,单选,输入框)
formOptions记录了表单的一些配置项,比如label-width等

在这里插入图片描述
mybatisplus生成代码

oa_process_type 审批类型
oa_process_template 审批模板

oa_prcess 审批列表(关联审批流流程实例id)

1,创建审批类型
2,创建审批类型下的审批模板
3,为指定的审批模板设置模板名称,表单项,
4,为指定的审批模板上传流程定义文件,将该文件保存到指定的目录下,并保存到审批模板的流程定义path字段,流程定义文件的文件名(不包括后缀名)作为审批模板的流程定义key字段
5,发布该审批模板,就是将此审批模板流程定义path字段所指定的路径所对应的文件读取成流,部署到activiti中,修改审批模板为已发布状态

6,发起审批,首先获取审批模板对应的表单,申请人填写表单内容,表单内容会转换为json数据传给后台,后台根据审批模板将数据保存到业务审批表,申请人填写的表单内容就保存在业务审批表的form_values字段中,这样就可以得到业务id了,然后activiti使用审批模板所保存的流程定义key启动流程实例,并传入业务id,同时传入将申请人填写的表单内容json数据转为的map存入到key为data的map中,这样流程实例就启动了,并且和业务id绑定了,并且也有了申请人填写的表单内容作为流程变量。

在流程实例启动后,立即查询当前流程实例的下一个节点的审批人(有可能有多个),取到这些审批人的assignee,给这些审批人推送消息以便于提醒他们尽快去审批。

推送完消息之后,将流程实例id保存到业务审批表的流程实例id字段。

//启动流程
@Override
public void startUp(ProcessFormVo processFormVo) {
    //1 根据当前用户id获取用户信息
    SysUser sysUser = sysUserService.getById(LoginUserInfoHelper.getUserId());

    //2 根据审批模板id把模板信息查询
    ProcessTemplate processTemplate = processTemplateService.getById(processFormVo.getProcessTemplateId());

    //3 保存提交审批信息到业务表,oa_process
    Process process = new Process();
    //processFormVo复制到process对象里面
    BeanUtils.copyProperties(processFormVo,process);
    //其他值
    process.setStatus(1); //审批中
    String workNo = System.currentTimeMillis() + "";
    process.setProcessCode(workNo);
    process.setUserId(LoginUserInfoHelper.getUserId());
    process.setFormValues(processFormVo.getFormValues());
    process.setTitle(sysUser.getName() + "发起" + processTemplate.getName() + "申请");
    baseMapper.insert(process);

    //4 启动流程实例 - RuntimeService
    //4.1 流程定义key
    String processDefinitionKey = processTemplate.getProcessDefinitionKey();
    
    //4.2 业务key  processId
    String businessKey = String.valueOf(process.getId());

    //4.3 流程参数 form表单json数据,转换map集合
    String formValues = processFormVo.getFormValues();
    //formData
    JSONObject jsonObject = JSON.parseObject(formValues);
    JSONObject formData = jsonObject.getJSONObject("formData");
    //遍历formData得到内容,封装map集合
    Map<String,Object> map = new HashMap<>();
    for(Map.Entry<String,Object> entry:formData.entrySet()) {
        map.put(entry.getKey(),entry.getValue());
    }
    Map<String,Object> variables = new HashMap<>();
    variables.put("data",map);
    //启动流程实例
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,
            businessKey, variables);

    //5 查询下一个审批人
    //审批人可能多个
    List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
    List<String> nameList = new ArrayList<>();
    for(Task task : taskList) {
        String assigneeName = task.getAssignee();
        SysUser user = sysUserService.getUserByUserName(assigneeName);
        String name = user.getName();
        nameList.add(name);
        //推送消息
        messageService.pushPendingMessage(process.getId(),user.getId(),task.getId());
    }
    process.setProcessInstanceId(processInstance.getId());
    process.setDescription("等待"+ StringUtils.join(nameList.toArray(), ",")+"审批");
    //7 业务和流程关联  更新oa_process数据
    baseMapper.updateById(process);

    //记录操作审批信息记录
    processRecordService.record(process.getId(),1,"发起申请");
}


7、审批记录
用来记录1个审批所走过的轨迹,首先添加审批记录表,如下
在这里插入图片描述
在开启流程实例的方法中,生成一条审批记录存入到审批记录表当中(调用处在上面)

@Override
public void record(Long processId, Integer status, String description) {
    Long userId = LoginUserInfoHelper.getUserId();
    SysUser sysUser = sysUserService.getById(userId);
    ProcessRecord processRecord = new ProcessRecord();
    processRecord.setProcessId(processId);
    processRecord.setStatus(status);
    processRecord.setDescription(description);
    processRecord.setOperateUser(sysUser.getName());
    processRecord.setOperateUserId(userId);
    baseMapper.insert(processRecord);
}

8,审批人查询待办任务

使用activiti工作流提供的taskService根据当前用户作为assignee查询当前用户的的任务列表(并且使用了分页),遍历这个任务列表,可以拿到每个任务对应的流程实例,然后拿到流程实例对应的业务key(其实,通过task就可以直接拿到businessKey),拿到businessKey之后,就可以查询业务审批表,来获取到申请人所填写的申请表单内容了。这样当前审批人就可以根据申请人提交的表单内容做审批了。注意,工作流的taskId也带上去了。

//查询待处理任务列表
@Override
 public IPage<ProcessVo> findfindPending(Page<Process> pageParam) {
     //1 封装查询条件,根据当前登录的用户名称
     TaskQuery query = taskService.createTaskQuery()
             .taskAssignee(LoginUserInfoHelper.getUsername())
             .orderByTaskCreateTime()
             .desc();

     //2 调用方法分页条件查询,返回list集合,待办任务集合
     //listPage方法有两个参数
     //第一个参数:开始位置  第二个参数:每页显示记录数
     int begin = (int)((pageParam.getCurrent()-1)*pageParam.getSize());
     int size = (int)pageParam.getSize();
     List<Task> taskList = query.listPage(begin, size);
     long totalCount = query.count();

     //3 封装返回list集合数据 到 List<ProcessVo>里面
     //List<Task> -- List<ProcessVo>
     List<ProcessVo> processVoList = new ArrayList<>();
     for(Task task : taskList) {
         //从task获取流程实例id
         String processInstanceId = task.getProcessInstanceId();
         //根据流程实例id获取实例对象
         ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                                                         .processInstanceId(processInstanceId)
                                                         .singleResult();
         //从流程实例对象获取业务key---processId
         String businessKey = processInstance.getBusinessKey();
         if(businessKey == null) {
             continue;
         }
         //根据业务key获取Process对象
         long processId = Long.parseLong(businessKey);
         Process process = baseMapper.selectById(processId);
         //Process对象 复制 ProcessVo对象
         ProcessVo processVo = new ProcessVo();
         BeanUtils.copyProperties(process,processVo);
         processVo.setTaskId(task.getId());
         //放到最终list集合processVoList
         processVoList.add(processVo);
     }

     //4 封装返回IPage对象
     IPage<ProcessVo> page = new Page<ProcessVo>(pageParam.getCurrent(),
                              pageParam.getSize(),totalCount);
     page.setRecords(processVoList);
     return page;
 }

9,发起审批测试
测试步骤如下,

先添加审批模板,然后发布,使用admin填写审批表单发起1个审批,然后下一节点审批人zhangsan查看自己的待办任务
在这里插入图片描述
张三查看自己的待办任务列表如下
在这里插入图片描述
10,审批人查看审批单的审批详情信息

前面张三查看到了自己的待办任务列表,待办任务列表数据的id是业务表的id,因此前端将此id传进来,来查询审批详情信息(比如用户什么时间提的申请,填写的表单内容)。

接着,继续使用业务表的id查询审批记录表中的审批记录(前面发起审批时,记录了,当前自己审批时,也须往这个表中记录)

接着,根据审批业务表的id得到审批模板信息

接着,查询当前人是否可以审批该审批流程实例(这里要推敲下)

下面这个代码感觉有点问题:上面查询待办的时候,拿的就是当前人作为assignee查询的任务,那么查到的审批单对应的审批人是一定包括当前人的(可能有多个审批人),并且,也是有查询到对应的taskId的,我觉得这里应该让前端把taskId传过来,就可以得到这个taskId对应的assignee是不是当前人。但是好好想想,他这样做也没啥问题,他其实就是在判断当前人是否是这个流程实例的当前所在节点的审批人,如果是的话,那就可以审批,不是的话,就不可以审批

//查看审批详情信息
@Override
public Map<String, Object> show(Long id) {

    //1 根据流程id获取流程信息Process
    Process process = baseMapper.selectById(id);

    //2 根据流程id获取流程记录信息
    LambdaQueryWrapper<ProcessRecord> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(ProcessRecord::getProcessId,id);
    List<ProcessRecord> processRecordList = processRecordService.list(wrapper);

    //3 根据模板id查询模板信息
    ProcessTemplate processTemplate = processTemplateService.getById(process.getProcessTemplateId());

    //4 判断当前用户是否可以审批
    //可以看到信息不一定能审批,不能重复审批
    boolean isApprove = false;
    List<Task> taskList = this.getCurrentTaskList(process.getProcessInstanceId());
    for(Task task : taskList) {
        //判断任务审批人是否是当前用户
        String username = LoginUserInfoHelper.getUsername();
        if(task.getAssignee().equals(username)) {
            isApprove = true;
        }
    }

    //5 查询数据封装到map集合,返回
    Map<String,Object> map = new HashMap<>();
    map.put("process", process);
    map.put("processRecordList", processRecordList);
    map.put("processTemplate", processTemplate);
    map.put("isApprove", isApprove);
    return map;
}

张三点击审批详情后,进入到如下页面

在这里插入图片描述
11,最重要的一步来了,审批人对当前审批单进行审批(同意or驳回)。驳回即审批不通过,流程结束。
如果当前审批人 对 此审批单 审批通过,那么流程引擎会自动将任务流转到下1个审批人那里(如果还有下一个任务节点的话),并通知下一个审批人(可能是多个人),下一个人就可以查询到自己的待办任务。

如果当前审批人 对 此审批单 驳回,那么流程结束。结束流程的代码是固定模式的。

不管当前审批人 对 此审批单 是审批通过 还是驳回,都要记录到审批记录表,并且更新审批的业务表。

//审批
@Override
public void approve(ApprovalVo approvalVo) {

    //1 从approvalVo获取任务id,根据任务id获取流程变量
    String taskId = approvalVo.getTaskId();
    Map<String, Object> variables = taskService.getVariables(taskId);
    for(Map.Entry<String,Object> entry:variables.entrySet()) {
        System.out.println(entry.getKey());
        System.out.println(entry.getValue());
    }

    //2 判断审批状态值
    if(approvalVo.getStatus() == 1) {
        //2.1 状态值 =1  审批通过
        Map<String, Object> variable = new HashMap<>();
        taskService.complete(taskId,variable);
    } else {
        //2.2 状态值 = -1 驳回,流程直接结束
        this.endTask(taskId);
    }

    //3 记录审批相关过程信息 oa_process_record
    String description = approvalVo.getStatus().intValue() ==1 ? "已通过" : "驳回";
    processRecordService.record(approvalVo.getProcessId(),approvalVo.getStatus(),description);

    //4 查询下一个审批人,更新流程表记录 process表记录
    Process process = baseMapper.selectById(approvalVo.getProcessId());
    //查询任务
    List<Task> taskList = this.getCurrentTaskList(process.getProcessInstanceId());
    if(!CollectionUtils.isEmpty(taskList)) {
        List<String> assignList = new ArrayList<>();
        for(Task task : taskList) {
            String assignee = task.getAssignee();
            SysUser sysUser = sysUserService.getUserByUserName(assignee);
            assignList.add(sysUser.getName());

            //TODO 公众号消息推送
        }
        //更新process流程信息
        process.setDescription("等待" + StringUtils.join(assignList.toArray(), ",") + "审批");
        process.setStatus(1);
    } else {
        if(approvalVo.getStatus().intValue() == 1) {
            process.setDescription("审批完成(通过)");
            process.setStatus(2);
        } else {
            process.setDescription("审批完成(驳回)");
            process.setStatus(-1);
        }
    }
    baseMapper.updateById(process);
}
//结束流程
private void endTask(String taskId) {
    //1 根据任务id获取任务对象 Task
    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

    //2 获取流程定义模型 BpmnModel
    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

    //3 获取结束流向节点
    List<EndEvent> endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
    if(CollectionUtils.isEmpty(endEventList)) {
        return;
    }
    FlowNode endFlowNode = (FlowNode)endEventList.get(0);

    //4 当前流向节点
    FlowNode currentFlowNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());

    //  临时保存当前活动的原始方向
    List originalSequenceFlowList = new ArrayList<>();
    originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
    //5 清理当前流动方向
    currentFlowNode.getOutgoingFlows().clear();

    //6 创建新流向
    SequenceFlow newSequenceFlow = new SequenceFlow();
    newSequenceFlow.setId("newSequenceFlow");
    newSequenceFlow.setSourceFlowElement(currentFlowNode);
    newSequenceFlow.setTargetFlowElement(endFlowNode);

    //7 当前节点指向新方向
    List newSequenceFlowList = new ArrayList();
    newSequenceFlowList.add(newSequenceFlow);
    currentFlowNode.setOutgoingFlows(newSequenceFlowList);

    //8 完成当前任务
    taskService.complete(task.getId());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/295309.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

周鸿祎分享大模型十大趋势:2024将出现杀手级应用

1月5日&#xff0c;“2023年风马牛年终秀”上&#xff0c;三六零&#xff08;601360.SH&#xff0c;下称“360”&#xff09;集团创始人周鸿祎分享了对2024年大模型发展趋势的十大预测&#xff0c;呼吁企业树立AI信仰&#xff0c;All in AI。他认为&#xff0c;创新才能破局&am…

shell脚本实现九九乘法表

9*9乘法表 判断服务是否开启 1.查看80端口是否被监听 [rootlocalhost ~]# ss -an | grep 80 tcp LISTEN 0 128 *:80 *:* 2.查看80端口/httpd服务是否开启 [rootlocalhost ~]# n…

【Python学习】Python学习2

目录 【Python学习】Python学习2 1.前言2.基本语法2.1标识符2.2保留字2.3行和缩进2.4多行语句2.5 Python 引号2.6 Python注释2.7 Python空行2.8 等待用户输入2.9 print 输出2.10 多个语句构成代码组2.11 命令行参数 参考 文章所属专区 Python学习 1.前言 主要是Python基本语…

《Python自动化测试九章经》

Python是当前非常流行的一门编程语言&#xff0c;它除了在人工智能、数据处理、Web开发、网络爬虫等领域得到广泛使用之外&#xff0c;他也非常适合软件测试人员使用&#xff0c;但是&#xff0c;对于刚入行的测试小白来说&#xff0c;并不知道学习Python语言可以用来完成哪些测…

kali-Linux安装ARL灯塔教程以及timeout of 20000ms exceeded 的解决方法

FLAG&#xff1a;别和妈妈诉苦&#xff0c;她帮不上&#xff0c;也睡不着。 专研方向: docker&#xff0c;ARL资产灯塔系统 每日emo&#xff1a;天冷了&#xff0c;你还在坚持吗&#xff1f; 欢迎各位与我这个菜鸟交流学习 kali安装ARL灯塔教程 1.安装docker环境&#xff0c;…

使用爬虫爬取热门电影

文章目录 网站存储视频的原理M3U8文件解读网站分析代码实现 网站存储视频的原理 首先我们来了解一下网站存储视频的原理。 一般情况下&#xff0c;一个网页里想要显示出一个视频资源&#xff0c;必须有一个<video>标签&#xff0c; <video src"xxx.mp4"&…

win7系统报错msvcp140.dll丢失的多种解决方法分享

在Windows 7操作系统中&#xff0c;msvcp140.dll是一个非常重要的动态链接库文件&#xff0c;它负责许多应用程序的正常运行。然而&#xff0c;由于各种原因&#xff0c;我们可能会遇到丢失msvcp140.dll的问题。当msvcp140.dll文件丢失或损坏时&#xff0c;可能会导致程序无法启…

Go语言中的HTTP请求和响应处理

在Web开发中&#xff0c;HTTP请求和响应是核心的交互方式。Go语言&#xff0c;作为一种高效且现代的编程语言&#xff0c;为开发者提供了简洁、强大的工具来处理HTTP请求和响应。本文将简要介绍在Go语言中如何处理HTTP请求和响应。 在Go语言中&#xff0c;HTTP请求和响应的处理…

c语言-函数指针

目录 前言一、函数指针1.1 函数指针定义1.2 函数指针调用函数1.3 函数指针代码分析 总结 前言 本篇文章介绍c语言中的函数指针以及函数指针的应用。 一、函数指针 函数指针&#xff1a;指向函数的指针。 函数在编译时分配地址。 &函数名 和 函数名代表的意义相同&#xf…

Linux下从sqlite3源码编译出sqlite3库及相关可执行程序

目录 1. 下载sqlite3源码并编译 2. 下载Tcl库并编译 3. 再次编译sqlite源码 1. 下载sqlite3源码并编译 打开SQLite Download Page&#xff0c;滚动到页面的下面&#xff0c;找到源码量最大的那个&#xff08;其它的估计也行&#xff0c;但源码最大的本人感觉功能最全&#…

Java集合框架深度解析-ArrayList

Java的集合框架提供了一组实现常用数据结构的类和接口。理解集合框架对于Java程序员来说至关重要&#xff0c;因为它们在日常编程中广泛应用。 为什么需要集合框架&#xff1f; 在编程中&#xff0c;我们经常需要存储和操作一组对象。集合框架提供了用于表示和操作对象组的通…

需方管理运维运营服务的心得

在确保供应商提供的运营维护服务达到需方质量标准&#xff0c;并保障供应商具备相应的服务条件与能力方面&#xff0c;需方必须采纳一整套综合性的管理措施。这包括但不限于方法论、技术工具、制度化流程、以及完备的文档记录等。以下是一份精炼的方案&#xff0c;涉及至关重要…

Dockerfile - 工作流程、构建镜像、文件语法

目录 一、Dockerfile 1.1、简介 1.2、Dockerfile 构建镜像的流程 1.3、Dockerfile 文件语法 1.3.1、注意事项 1.3.2、FROM 1.3.3、MAINTAINER&#xff08;官方已废弃&#xff09; 1.3.4、RUN 1.3.5、EXPOSE 1.3.6、WORKDIR 1.3.7、ADD 和 COPY 1.3.8、ENV 1.3.9、…

详解bookkeeper AutoRecovery机制

引言小故事 张三在一家小型互联网公司上班&#xff0c;由于公司实行的996&#xff0c;因此经常有同事“不辞而别”&#xff0c;为了工作的正常推进&#xff0c;团队内达成了某种默契&#xff0c;这种默契就是通过某个规则来选出一个同事&#xff0c;这个同事除了工作之余还有额…

【排序算法总结】

目录 1. 稳点与非稳定排序2. 冒泡排序3. 简单选择排序4. 直接插入排序5. 快排6. 堆排7. 归并 1. 稳点与非稳定排序 不稳定的&#xff1a;快排、堆排、选择原地排序&#xff1a;快排也是非原地排序&#xff1a;归并 和三个线性时间排序&#xff1a;桶排序 &#xff0c;计数&…

前缀和算法模板

一维前缀和 算法用途&#xff1a;快速求出数组中某一连续区间的和 一维前缀和算法模板 1、预处理出一个 dp 数组 要求原数组存储在 n 1 的空间大小中&#xff0c;其中后 n 个空间存数据。 dp数组&#xff0c;数组开 n 1个空间&#xff0c;dp[i] 表示 [ 1, i ] 区间内所有…

从Spring Cloud Alibaba开始聊架构

作为SpringCloudAlibaba微服务架构实战派上下册和RocketMQ消息中间件实战派上下册的作者胡弦。 另外我的新书RocketMQ消息中间件实战派上下册&#xff0c;在京东已经上架啦&#xff0c;目前都是5折&#xff0c;非常的实惠。 https://item.jd.com/14337086.htmlhttps://item.jd…

【UnityShader入门精要学习笔记】(3)章节答疑

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 复习&#xff08;阶段性总结…

NLP one-hot编码

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客\n&#x1f366; 参考文章&#xff1a;365天深度学习训练营\n&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制]\n&#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.co…