Browse Source

Merge remote-tracking branch 'origin/master'

liuwj 2 years ago
parent
commit
e4645aa38e
82 changed files with 21970 additions and 0 deletions
  1. 74 0
      itdmServer/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/RoleVO.java
  2. 168 0
      itdmServer/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/UserVO.java
  3. 5 0
      itdmServer/jeecg-module-system/jeecg-system-start/pom.xml
  4. 93 0
      itdmServer/module-ACTIVITI/pom.xml
  5. 143 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/Constant.java
  6. 71 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/entity/BaseAuditStatisticsEntity.java
  7. 102 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/entity/BaseTaskEntity.java
  8. 102 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/entity/FlowCondition.java
  9. 70 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/vo/BaseVO.java
  10. 18 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/vo/DeleteBatchVO.java
  11. 169 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/config/ActivitiConfig.java
  12. 1338 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/config/CustomProcessDiagramCanvas.java
  13. 1055 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/config/CustomProcessDiagramGenerator.java
  14. 61 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/exception/CustomException.java
  15. 53 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/exception/ExceptionCode.java
  16. 130 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/utils/DictEnum.java
  17. 134 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/utils/DictModelConstant.java
  18. 417 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/utils/StringUtils.java
  19. 113 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/controller/ReModelController.java
  20. 180 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/controller/ReProcdefController.java
  21. 149 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/controller/ServiceController.java
  22. 120 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/manage/CustomGroupEntityManager.java
  23. 147 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/manage/CustomUserEntityManager.java
  24. 17 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/ReModelMapper.java
  25. 17 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/ReProcdefMapper.java
  26. 6 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/xml/ReModelMapper.xml
  27. 6 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/xml/ReProcdefMapper.xml
  28. 60 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/model/converter/ActivitiConverter.java
  29. 81 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/model/entity/ReModelEntity.java
  30. 93 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/model/entity/ReProcdefEntity.java
  31. 69 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/ReModelService.java
  32. 119 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/ReProcdefService.java
  33. 183 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/impl/ReModelServiceImpl.java
  34. 275 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/impl/ReProcdefServiceImpl.java
  35. 159 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/controller/ApplyLeaveController.java
  36. 64 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/entity/ApplyLeave.java
  37. 27 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/ContactResultListener.java
  38. 73 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/CustomEventListener.java
  39. 27 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/ProblemResultListener.java
  40. 27 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/ProcessResultListener.java
  41. 14 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/ApplyLeaveMapper.java
  42. 39 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/ApplyProcessMapper.java
  43. 5 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/xml/mysql/ApplyLeaveMapper.xml
  44. 58 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/xml/mysql/ApplyProcessMapper.xml
  45. 47 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/xml/oracle/ApplyProcessMapper.xml
  46. 40 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/ApplyProcessService.java
  47. 17 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/IApplyLeaveService.java
  48. 76 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/impl/ApplyLeaveServiceImpl.java
  49. 157 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/impl/ApplyProcessServiceImpl.java
  50. 170 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/controller/ApplyFormController.java
  51. 79 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/entity/ApplyForm.java
  52. 14 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/mapper/ApplyFormMapper.java
  53. 5 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/mapper/xml/ApplyFormMapper.xml
  54. 19 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/service/IApplyFormService.java
  55. 31 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/service/impl/ApplyFormServiceImpl.java
  56. 83 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/controller/ApprovalController.java
  57. 126 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/controller/ApprovalTaskController.java
  58. 83 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/dto/ApprovalOpinionDTO.java
  59. 38 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/dto/CurrTaskNodeInfoDTO.java
  60. 52 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/dto/DynamicFormConf.java
  61. 74 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/ApprovalOpinionVO.java
  62. 29 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/ApprovalTaskQueryVo.java
  63. 68 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/ApprovalVO.java
  64. 113 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/HistoryTaskVO.java
  65. 45 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/TaskCountDataVO.java
  66. 102 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/TaskVO.java
  67. 124 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/ApprovalService.java
  68. 111 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/ApprovalTaskService.java
  69. 766 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/impl/ApprovalServiceImpl.java
  70. 708 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/impl/ApprovalTaskServiceImpl.java
  71. 33 0
      itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/system/controller/SystemController.java
  72. 76 0
      itdmServer/module-ACTIVITI/src/main/resources/processes/会议室预约申请bak20200914.bpmn20.xml
  73. 1080 0
      itdmServer/module-ACTIVITI/src/main/resources/processes/投稿bak20200915.bpmn20.xml
  74. 165 0
      itdmServer/module-ACTIVITI/src/main/resources/processes/报修bak20200914.bpmn20.xml
  75. 208 0
      itdmServer/module-ACTIVITI/src/main/resources/processes/物品领用bak20200914.bpmn20.xml
  76. 191 0
      itdmServer/module-ACTIVITI/src/main/resources/processes/财务预算bak20200914.bpmn20.xml
  77. 803 0
      itdmServer/module-ACTIVITI/src/main/resources/processes/采购验收bak20200914.bpmn20.xml
  78. 2677 0
      itdmServer/module-ACTIVITI/src/main/resources/static/stencilset.json
  79. 1 0
      itdmServer/pom.xml
  80. 253 0
      logs/error-log.html
  81. 6115 0
      logs/jeecgboot-2023-05-19.0.html
  82. 860 0
      logs/jeecgboot-2023-05-19.0.log

+ 74 - 0
itdmServer/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/RoleVO.java

@@ -0,0 +1,74 @@
+package org.jeecg.common.system.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 角色信息
+ * </p>
+ *
+ * @Author scott
+ * @since 2018-12-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class RoleVO {
+
+
+      /**
+       * id
+       */
+      private String id;
+
+      /**
+       * 角色名称
+       */
+      private String roleName;
+
+      /**
+       * 角色编码
+       */
+      private String roleCode;
+
+      /**
+       * 描述
+       */
+      private String description;
+
+      /**
+       * 创建人
+       */
+      private String createBy;
+
+      /**
+       * 创建时间
+       */
+      @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+      @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+      private Date createTime;
+
+      /**
+       * 更新人
+       */
+      private String updateBy;
+
+      /**
+       * 更新时间
+       */
+      @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+      @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+      private Date updateTime;
+
+
+   }
+

+ 168 - 0
itdmServer/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/UserVO.java

@@ -0,0 +1,168 @@
+package org.jeecg.common.system.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 用户信息
+ * @author czm
+ * @date 2021/8/14 20:56
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class UserVO {
+
+
+      /**
+       * id
+       */
+      private String id;
+
+      /**
+       * 登录账号
+       */
+      private String username;
+
+      /**
+       * 真实姓名
+       */
+      private String realname;
+
+      /**
+       * 密码
+       */
+      private String password;
+
+      /**
+       * md5密码盐
+       */
+      private String salt;
+
+      /**
+       * 头像
+       */
+      private String avatar;
+
+      /**
+       * 生日
+       */
+      @Excel(name = "生日", width = 15, format = "yyyy-MM-dd")
+      @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+      @DateTimeFormat(pattern = "yyyy-MM-dd")
+      private Date birthday;
+
+      /**
+       * 性别(1:男 2:女)
+       */
+      @Excel(name = "性别", width = 15,dicCode="sex")
+      @Dict(dicCode = "sex")
+      private Integer sex;
+
+      /**
+       * 电子邮件
+       */
+      private String email;
+
+      /**
+       * 电话
+       */
+      private String phone;
+
+      /**
+       * 部门code(当前选择登录部门)
+       */
+      private String orgCode;
+
+      /**部门名称*/
+      @Excel(name="部门",width = 15 )
+      private transient String orgCodeTxt;
+
+      /**
+       * 负责部门
+       */
+      @Dict(dictTable ="sys_depart",dicText = "depart_name",dicCode = "id")
+      private String departIds;
+
+      /**
+       * 状态(1:正常  2:冻结 )
+       */
+      @Dict(dicCode = "user_status")
+      private Integer status;
+
+      /**
+       * 删除状态(0,正常,1已删除)
+       */
+//    @Excel(name = "删除状态", width = 15,dicCode="del_flag")
+      @TableLogic
+      private Integer delFlag;
+
+      /**
+       * 工号,唯一键
+       */
+//    @Excel(name = "工号", width = 15)
+      private String workNo;
+
+      /**
+       * 职务,关联职务表
+       */
+//    @Excel(name = "职务", width = 15)
+      @Dict(dictTable ="sys_position",dicText = "name",dicCode = "code")
+      private String post;
+
+      /**
+       * 座机号
+       */
+//    @Excel(name = "座机号", width = 15)
+      private String telephone;
+
+      /**
+       * 创建人
+       */
+      private String createBy;
+
+      /**
+       * 创建时间
+       */
+      private Date createTime;
+
+      /**
+       * 更新人
+       */
+      private String updateBy;
+
+      /**
+       * 更新时间
+       */
+      private Date updateTime;
+      /**
+       * 同步工作流引擎1同步0不同步
+       */
+      private Integer activitiSync;
+
+      /**
+       * 身份(0 普通成员 1 上级)
+       */
+//    @Excel(name="(1普通成员 2上级)",width = 15)
+      private Integer userIdentity;
+
+      /**
+       * 多租户id配置,编辑用户的时候设置
+       */
+      private String relTenantIds;
+
+      /**设备id uniapp推送用*/
+      private String clientId;
+   }
+

+ 5 - 0
itdmServer/jeecg-module-system/jeecg-system-start/pom.xml

@@ -24,6 +24,11 @@
             <artifactId>module-iTDM</artifactId>
             <version>${jeecgboot.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>module-ACTIVITI</artifactId>
+            <version>${jeecgboot.version}</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 93 - 0
itdmServer/module-ACTIVITI/pom.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jeecg-boot-parent</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.4.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>module-ACTIVITI</artifactId>
+    <properties>
+        <activiti.version>6.0.0</activiti.version>
+        <batik.version>1.7</batik.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-boot-base-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-system-local-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+        </dependency>
+        <!--        activiti-->
+
+        <dependency>
+            <groupId>org.activiti</groupId>
+            <artifactId>activiti-spring</artifactId>
+            <version>${activiti.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-security</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.activiti</groupId>
+            <artifactId>activiti-json-converter</artifactId>
+            <version>${activiti.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.activiti</groupId>
+            <artifactId>activiti-image-generator</artifactId>
+            <version>${activiti.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.xmlgraphics</groupId>
+            <artifactId>batik-transcoder</artifactId>
+            <version>${batik.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.xmlgraphics</groupId>
+            <artifactId>batik-codec</artifactId>
+            <version>${batik.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-system-local-api</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>false</filtering>
+                <includes>
+                    <include>static/**</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                    <include>**/*.json</include>
+                    <include>**/*.ftl</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+</project>

+ 143 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/Constant.java

@@ -0,0 +1,143 @@
+package org.jeecg.common;
+
+/**
+ * 系统常量
+ *
+ * @author yao.sun
+ * @data 2018-01-14
+ */
+public class Constant {
+
+    /**
+     * 超级管理员ID
+     */
+    public static final String SUPER_ADMIN = "admin";
+
+
+    /*********************** 工作流 start *******************************/
+
+    public static final String ACT_BPMN20 = ".bpmn20.xml";
+    public static final String ACT_IMAGE = "image";
+    public static final String ACT_XML = "xml";
+    public static final String ACT_PNG = "png";
+    public static final String ACT_BAR = "bar";
+    public static final String ACT_ZIP = "zip";
+    public static final String ACT_BPMN = "bpmn";
+
+    public static final int ACT_ONE = 1;
+    public static final int ACT_TWO = 2;
+    public static final int ACT_THREE = 3;
+
+    public static final String ACT_ASSIGNEE = "assignee";
+    public static final String ACT_CANDIDATE = "candidate";
+    public static final String ACT_CANDIDATE_GROUP = "group";
+
+
+
+    /**
+     * UTF-8 字符集
+     */
+    public static final String UTF8 = "UTF-8";
+
+    /**
+     * GBK 字符集
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * 工作流 审批记录
+     */
+    public static final String ACT_APPLY_OPINION_LIST = "applyOpinionList";
+
+    /**
+     * 工作流 审批任务实例
+     */
+    public static final String ACT_BASE_TASK = "baseTask";
+    /**
+     * 工作流 业务键
+     */
+    public static final String ACT_BUSINESS_KEY = "businessKey";
+
+    /**
+     * 工作流  发起审批人
+     */
+    public static final String ACT_APPLY_USER = "applyUser";
+
+    /**
+     * 工作流会签人员列表
+     */
+    public static final String ACT_APPLY_ASSIGNEE_LIST = "assigneeList";
+
+    /**
+     * 工作流  审批标识
+     */
+    public static final String ACT_TASK_FLAG = "flag";
+
+    /**
+     * 工作流 项目经理
+     */
+    public static final String ACT_PRIJECT_MANAGER_USER = "projectManager";
+
+
+
+
+
+    /**
+     * 工作流 流转条件
+     */
+    public static final String ACT_FLOW_TOTAL = "total";
+    public static final String ACT_FLOW_BUDGET_DEPT_DTO = "budgetDeptDto";  //多实例预算部门信息
+    public static final String ACT_FLOW_DEPT_DTOS = "deptDtos";  //多实例预算部门信息集合
+
+    /**
+     * 工作流 流程状态 0进行中,1已结束
+     */
+    public static final String ACT_TASK_QUERY_STATUS_RUN = "0";
+    public static final String ACT_TASK_STATUS_END = "1";
+
+    /**
+     * 是否
+     */
+    public static final String YES = "1";
+    public static final String NO = "0";
+
+
+    /**
+     * 流程表单可操作状态 1 是,其余否
+     */
+    //可否被撤回
+    public static final String APPROVAL_HANDLE_WITHDRAW = "canWithdraw";
+    //可否被修改
+    public static final String APPROVAL_HANDLE_MODIFY = "canModify";
+    //可否重新申请
+    public static final String APPROVAL_HANDLE_REAPPLY = "canReapply";
+    /**
+     * 流程审批结果最终状态
+     */
+    public static final String APPROVAL_RESULT_STATUS  = "finalState";
+
+    /**
+     * 删除状态
+     */
+    public enum DelFlag {
+        /**
+         * 删除
+         */
+        DELETE(-1),
+        /**
+         * 正常
+         */
+        NORMAL(0);
+
+        private int value;
+
+        DelFlag(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+}

+ 71 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/entity/BaseAuditStatisticsEntity.java

@@ -0,0 +1,71 @@
+package org.jeecg.common.base.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 基础审核统计实体类
+ *
+ * @author Create by YLL
+ * @date 2020/4/27 14:55
+ */
+@Data
+public class BaseAuditStatisticsEntity implements Serializable {
+    /**
+     * 单位ID
+     */
+
+    private String tenantId;
+    /**
+     * 操作ID
+     */
+
+    private String opId;
+    /**
+     * 模块对应的formkey
+     */
+
+    private String moduleKey;
+    /**
+     * 业务ID
+     */
+
+    private String businessId;
+    /**
+     * 部门ID
+     */
+
+    private String deptId;
+    /**
+     * 流程节点ID
+     */
+
+    private String taskId;
+    /**
+     * 流程节点名称
+     */
+
+    private String taskNodeName;
+    /**
+     * 审核人id
+     */
+
+    private String opAssignee;
+    /**
+     * 审核人姓名
+     */
+
+    private String opAssigneeName;
+    /**
+     * 审批选项
+     */
+
+    private String opFlag;
+    /**
+     * 审核或确认时间
+     */
+
+    private Date opTime;
+}

+ 102 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/entity/BaseTaskEntity.java

@@ -0,0 +1,102 @@
+package org.jeecg.common.base.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 扩展基础实体
+ * 审批
+ * @author yao
+ * @since 2019/1/23 10:04
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BaseTaskEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 发起审批id
+     */
+    //@TableId(type = IdType.INPUT)
+    protected String id;
+
+    /**
+     * 部门id
+     */
+
+    private String deptId;
+
+    /**
+     * 流程实例id
+     */
+    private String processInstanceId;
+
+    /**
+     * 流程名称
+     */
+    private String processInstanceName;
+
+    /**
+     * 流程key
+     */
+    private String processKey;
+
+    /**
+     * 审配表单Key
+     */
+    private String formKey;
+
+    /**
+     * 申请人用户id
+     */
+    private String userId;
+
+    /**
+     * 申请人姓名
+     */
+    private String userName;
+
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 审批记录
+     */
+    private String opinionStr;
+
+    /**
+     * 流程结束时间
+     */
+    private Date completeTime;
+
+    /**
+     * 审批状态 0未开始,1进行中,2已结束
+     */
+    private String applyStatus;
+
+    /**
+     * 最终审批结果 0未通过 1通过, 2审批中,3申请取消
+     */
+    private String result;
+
+
+    /**
+     * 存放流程变量
+     */
+    @TableField(exist = false)
+    private Map<String, Object> param;
+
+}

+ 102 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/entity/FlowCondition.java

@@ -0,0 +1,102 @@
+package org.jeecg.common.base.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 流转条件
+ *
+ * @Author: yll
+ * @Date: 2019/8/23 15:39
+ */
+@Data
+public class FlowCondition implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 天数
+     */
+    private Integer days;
+    /**
+     * 金额
+     */
+    private BigDecimal money;
+    /**
+     * 人数
+     */
+    private Integer peopleNum;
+
+    /**
+     * 预算 0预算内,1预算外
+     */
+    private String budget;
+
+    /**
+     * 固定资产 0非固定资产 ,1固定资产
+     */
+    private String fixAsset;
+
+    /**
+     * 单价超出限制 0未超出限制
+     */
+    private Integer unitPriceLimit;
+    /**
+     * 文稿类型
+     */
+    private String noticeType;
+
+    /**
+     * 发布端口
+     */
+    private String noticePlatform;
+
+    /**
+     * 维修人
+     */
+    private String repairsUser;
+
+    /**
+     * 维修部门
+     */
+    private String repairsDept;
+
+    /**
+     * 参会员工
+     */
+    private List eParticipates;
+
+    /**
+     * 采购人
+     */
+    private String purchaser;
+
+    /**
+     * 采购部门主任
+     */
+    private String purchasingDirector;
+
+    /**
+     * 采购部分管领导
+     */
+    private String procurementLeader;
+
+    /**
+     * 领取的物品的状态
+     */
+    private String goodsStatus;
+
+    /**
+     * 采购单价是否大于预算单价
+     * 1 是
+     *  2 否
+     */
+    private Integer purunitByBudPrice;
+
+    /**
+     * 部门集合
+     */
+//    private List<BudgetDeptDto> deptDtos;
+
+}

+ 70 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/vo/BaseVO.java

@@ -0,0 +1,70 @@
+package org.jeecg.common.base.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 系统用户
+ *
+ * @author yao.sun
+ * @data 2018-01-14
+ */
+@Data
+public class BaseVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 单位id
+     */
+    private String tenantId;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date modifyTime;
+
+    /**
+     * 创建人
+     */
+    private BaseUserVO createUser;
+
+    /**
+     * 修改人
+     */
+    private BaseUserVO modifyUser;
+
+    @Data
+    public class BaseUserVO {
+        /**
+         * 用户名
+         */
+        private String username;
+
+        /**
+         * 姓名
+         */
+        private String name;
+
+        /**
+         * 部门id
+         */
+        private String deptId;
+
+        /**
+         * 部门名称
+         */
+        private String deptName;
+    }
+
+}

+ 18 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/base/vo/DeleteBatchVO.java

@@ -0,0 +1,18 @@
+package org.jeecg.common.base.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 批量删除vo
+ *
+ * @author yao.sun
+ * @data 2018-01-14
+ */
+@Data
+public class DeleteBatchVO {
+
+    private List<String> ids;
+
+}

+ 169 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/config/ActivitiConfig.java

@@ -0,0 +1,169 @@
+package org.jeecg.common.config;
+
+import com.google.common.collect.Lists;
+
+import org.activiti.engine.*;
+import org.activiti.spring.ProcessEngineFactoryBean;
+import org.activiti.spring.SpringProcessEngineConfiguration;
+import org.jeecg.modules.activiti.manage.CustomGroupEntityManager;
+import org.jeecg.modules.activiti.manage.CustomUserEntityManager;
+import org.jeecg.modules.apply.lisener.CustomEventListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import javax.sql.DataSource;
+import java.io.IOException;
+
+/**
+ * 工作流配置
+ *
+ * @author yao
+ * @date 2019/06/13
+ */
+@Configuration
+public class ActivitiConfig {
+
+    @Autowired
+    private CustomUserEntityManager customUserEntityManager;
+
+    @Autowired
+    private CustomGroupEntityManager customGroupEntityManager;
+
+    @Autowired
+    private CustomEventListener customEventListener;
+
+
+    /**
+     * 核心流程引擎类
+     *
+     * @param transactionManager transactionManager
+     * @param dataSource         dataSource
+     * @return ProcessEngine
+     */
+    @Bean
+    public ProcessEngine processEngine(PlatformTransactionManager transactionManager, DataSource dataSource)
+            throws IOException {
+        SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
+        // 自动部署已有的流程文件
+//        Resource[] resources = new PathMatchingResourcePatternResolver()
+//                .getResources(ResourceLoader.CLASSPATH_URL_PREFIX + "processes/*.bpmn");
+//        Resource[] resources2 = new PathMatchingResourcePatternResolver()
+//                .getResources(ResourceLoader.CLASSPATH_URL_PREFIX + "processes/*.bpmn20.xml");
+//        ArrayList<Resource> arrayList = new ArrayList(Arrays.asList(resources));
+//        arrayList.addAll(Arrays.asList(resources2));
+//        Resource[] arr =new Resource[arrayList.size()];
+//        Resource[] resources1 = arrayList.toArray(arr);
+//        processEngineConfiguration.setDeploymentResources(resources1);
+//        processEngineConfiguration.setDeploymentName("系统自动部署流程");
+
+        processEngineConfiguration.setTransactionManager(transactionManager);
+        processEngineConfiguration.setDataSource(dataSource);
+        processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE);
+//        processEngineConfiguration.setDatabaseSchema("tcore_dev");
+//        processEngineConfiguration.setDatabaseTablePrefix("ACT");
+        // 自定义用户和组
+        processEngineConfiguration.setUserEntityManager(customUserEntityManager);
+        processEngineConfiguration.setGroupEntityManager(customGroupEntityManager);
+
+        processEngineConfiguration.setActivityFontName("SimHei");
+        processEngineConfiguration.setAnnotationFontName("SimHei");
+        processEngineConfiguration.setLabelFontName("SimHei");
+
+
+        //自定义事件监听配置
+        processEngineConfiguration.setEventListeners(Lists.newArrayList(customEventListener));
+        return processEngineConfiguration.buildProcessEngine();
+
+    }
+
+    /**
+     * 流程仓库Service,用于管理流程仓库,例如部署、删除、读取流程资源
+     *
+     * @param processEngine processEngine
+     * @return RepositoryService
+     */
+    @Bean
+    public RepositoryService repositoryService(ProcessEngine processEngine) {
+        return processEngine.getRepositoryService();
+    }
+
+    /**
+     * 运行时Service,可以也拿过来处理所有正在运行状态的流程实例、任务等
+     *
+     * @param processEngine processEngine
+     * @return RuntimeService
+     */
+    @Bean
+    public RuntimeService runtimeService(ProcessEngine processEngine) {
+        return processEngine.getRuntimeService();
+    }
+
+    /**
+     * 任务Service,用于管理和查询任务,例如签收、办理、指派等
+     *
+     * @param processEngine processEngine
+     * @return ApprovalTaskService
+     */
+    @Bean
+    public TaskService taskService(ProcessEngine processEngine) {
+        return processEngine.getTaskService();
+    }
+
+    /**
+     * 历史Service,用于查询所有历史数据,例如流程实例、任务、活动、变量、附件
+     *
+     * @param processEngine processEngine
+     * @return HistoryService
+     */
+    @Bean
+    public HistoryService historyService(ProcessEngine processEngine) {
+        return processEngine.getHistoryService();
+    }
+
+    /**
+     * 引擎管理Service,和具体业务无关,主要可以查询引擎配置、数据库、作业等
+     *
+     * @param processEngine processEngine
+     * @return ManagementService
+     */
+    @Bean
+    public ManagementService managementService(ProcessEngine processEngine) {
+        return processEngine.getManagementService();
+    }
+
+    /**
+     * 身份Service,用于管理和查询用户、组之间的关系
+     *
+     * @param processEngine processEngine
+     * @return IdentityService
+     */
+    @Bean
+    public IdentityService identityService(ProcessEngine processEngine) {
+        return processEngine.getIdentityService();
+    }
+
+    /**
+     * 表单Service,用于读取流程、任务相关的表单数据
+     *
+     * @param processEngine processEngine
+     * @return FormService
+     */
+    @Bean
+    public FormService formService(ProcessEngine processEngine) {
+        return processEngine.getFormService();
+    }
+
+    /**
+     * 一个新增的服务,用于动态修改流程中的一些参数信息等,是引擎中的一个辅助的服务
+     *
+     * @param processEngine processEngine
+     * @return DynamicBpmnService
+     */
+    @Bean
+    public DynamicBpmnService dynamicBpmnService(ProcessEngine processEngine) {
+        return processEngine.getDynamicBpmnService();
+    }
+}

File diff suppressed because it is too large
+ 1338 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/config/CustomProcessDiagramCanvas.java


File diff suppressed because it is too large
+ 1055 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/config/CustomProcessDiagramGenerator.java


+ 61 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/exception/CustomException.java

@@ -0,0 +1,61 @@
+package org.jeecg.common.exception;
+
+/**
+ * 自定义异常
+ *
+ * @author yao.sun
+ * @data 2018-01-14
+ */
+public class CustomException extends RuntimeException {
+	private static final long serialVersionUID = 1L;
+
+
+    private String msg;
+    private int code = 500;
+
+    public CustomException(String msg) {
+		super(msg);
+		this.msg = msg;
+	}
+
+	public CustomException(String msg, Throwable e) {
+		super(msg, e);
+		this.msg = msg;
+	}
+
+	public CustomException(String msg, int code) {
+		super(msg);
+		this.msg = msg;
+		this.code = code;
+	}
+
+	public CustomException(String msg, int code, Throwable e) {
+		super(msg, e);
+		this.msg = msg;
+		this.code = code;
+	}
+
+	public CustomException(ExceptionCode exceptionCode) {
+		super(exceptionCode.getMsg());
+		this.msg = exceptionCode.getMsg();
+		this.code = exceptionCode.getCode();
+	}
+
+	public String getMsg() {
+		return msg;
+	}
+
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public void setCode(int code) {
+		this.code = code;
+	}
+
+
+}

+ 53 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/exception/ExceptionCode.java

@@ -0,0 +1,53 @@
+package org.jeecg.common.exception;
+
+/**
+ * 常量
+ *
+ * @author yao.sun
+ * @data 2018-01-14
+ */
+
+public enum ExceptionCode {
+
+    RQ_SUCCESS(20100, "请求成功!"),
+    RQ_UNAUTHORIZED(20101, "未授权登录!"),
+    RQ_TOKEN_INVALID(20102, "登录失效,请重新登录!"),
+    RQ_FORBIDDEN(20103, "未授权资源,禁止访问!"),
+
+    ACTIVITI_DESIGN_ERROR(20200, "设计模型图不正确,检查模型正确性!"),
+    ACTIVITI_DEPLOY_ERROR(20201, "流程部署异常!"),
+    ACTIVITI_HANG_UP(20202, "流程已挂起!"),
+    ACTIVITI_ACTIVATED(20203, "流程已激活!"),
+    ACTIVITI_PROCESS_KEY_EMPRTY(20204, "审批参数缺少processKey属性!"),
+
+    FILE_TYPE_ERROR(20300, "不支持的文件类型!"),
+
+    BUSINESS_USER_NOT_EXIST(30100, "用户不存在!"),
+
+    SYSTEM_ERROR(50100, "系统内部错误");
+
+
+    private int code;
+    private String msg;
+
+    ExceptionCode(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 130 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/utils/DictEnum.java

@@ -0,0 +1,130 @@
+package org.jeecg.common.utils;
+
+import com.google.common.collect.Lists;
+import lombok.Data;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * 字典枚举
+ */
+@Getter
+public enum DictEnum {
+
+    /*********************** 公共模块 *************************/
+    // 星期
+    BASE_WEEKS_SUNDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "1", "星期日"),
+    BASE_WEEKS_MONDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "2", "星期一"),
+    BASE_WEEKS_TUESDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "3", "星期二"),
+    BASE_WEEKS_WEDNESDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "4", "星期三"),
+    BASE_WEEKS_THURSDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "5", "星期四"),
+    BASE_WEEKS_FRIDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "6", "星期五"),
+    BASE_WEEKS_SATURDAY(DictModelConstant.MODEL_BASE, DictModelConstant.MODEL_BASE_WEEK, "7", "星期六"),
+
+
+    /*********************** 任务申请模块 *************************/
+
+    // 流程状态
+    APPLY_STATUS_NOT_START(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_STATUS, "0", "未开始"),
+    APPLY_STATUS_PROCESSING(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_STATUS, "1", "进行中"),
+    APPLY_STATUS_FINISH(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_STATUS, "2", "已结束"),
+
+    //流程审批结果
+    APPLY_RESULT_REFUSE(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_RESULT,"0","未通过"),
+    APPLY_RESULT_AGREE(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_RESULT,"1","通过"),
+    APPLY_RESULT_PROCESSING(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_RESULT,"2","审批中"),
+    APPLY_RESULT_CANCEL(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_RESULT,"3","申请取消"),
+
+    //流程审批操作类型
+    Apply_APPROVAL_OPINION_REFUSE(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"0","拒绝"),
+    Apply_APPROVAL_OPINION_AGREE(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"1","同意"),
+    APPLY_APPROVAL_OPINION_REJECT(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"2","驳回"),
+    APPLY_APPROVAL_OPINION_CONFIRM(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"3","确认"),
+    APPLY_APPROVAL_OPINION_REAPPLY(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"4","继续申请"),
+    APPLY_APPROVAL_OPINION_ABANDON(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"5","取消申请"),
+    APPLY_APPROVAL_OPINION_ASSIGN(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,"6","撤回到指定节点"),
+
+
+    /*********************** 流程审批表单配置模块 *************************/
+    //zshb_contact 表名
+    FORMKEY_APPLY(DictModelConstant.MODEL_APPLY_CONFIG, DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, "leave", "请假"),
+    FORMKEY_RECTIFY(DictModelConstant.MODEL_APPLY_CONFIG, DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, "zshb_contact", "工作联系单"),
+    FORMKEY_PROBLEM(DictModelConstant.MODEL_APPLY_CONFIG, DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, "zshb_contact_problem", "问题跟踪"),
+    ;
+
+
+    DictEnum(String model, String code, String key, String value) {
+        this.model = model;
+        this.code = code;
+        this.key = key;
+        this.value = value;
+    }
+
+    private String model;
+    private String code;
+    private String key;
+    private String value;
+
+    /**
+     * 返回字典值
+     *
+     * @param model
+     * @param code
+     * @param key
+     * @return
+     */
+    public static String getValue(String model, String code, String key) {
+        for (DictEnum dictEnum : DictEnum.values()) {
+            if (dictEnum.getModel().equals(model) && dictEnum.getCode().equals(code) && dictEnum.getKey().equals(key)) {
+                return dictEnum.getValue();
+            }
+        }
+        return "其他";
+    }
+
+    /**
+     * 返回模块枚举集合
+     *
+     * @param model
+     * @param code
+     * @return
+     */
+    public static List<DictEnum> getEnumList(String model, String code) {
+        List<DictEnum> result = Arrays.stream(DictEnum.values())
+                .filter(dictEnum -> dictEnum.getModel().equals(model) && dictEnum.getCode().equals(code))
+                .collect(Collectors.toList());
+
+        return result;
+    }
+
+    /**
+     * 获取 数据字典 集合
+     *
+     * @param model
+     * @param code
+     * @return
+     */
+    public static List<DictVO> getDictVOList(String model, String code) {
+        List<DictVO> list = Lists.newArrayList();
+        for (DictEnum dictEnum : DictEnum.values()) {
+            if (dictEnum.getModel().equals(model) && dictEnum.getCode().equals(code)) {
+                DictVO vo = new DictVO();
+                vo.setKey(dictEnum.getKey());
+                vo.setValue(dictEnum.getValue());
+                list.add(vo);
+            }
+        }
+        return list;
+    }
+
+    @Data
+    static class DictVO {
+        private String key;
+        private String value;
+    }
+
+}

+ 134 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/utils/DictModelConstant.java

@@ -0,0 +1,134 @@
+package org.jeecg.common.utils;
+
+/**
+ * @Auther guwenbo
+ * @Date 2019/6/5
+ */
+public class DictModelConstant {
+
+    /*********************** 公共模块 *************************/
+    // 模块名称
+    public static final String MODEL_BASE = "base";
+    // 星期
+    public static final String MODEL_BASE_WEEK = "weeks";
+
+    /*********************** 日程模块 *************************/
+    // 模块名称
+    public static final String MODEL_SCHEDULE = "schedule";
+    // 状态
+    public static final String MODEL_SCHEDULE_STATUS = "schedule_status";
+    // 是否开启提醒
+    public static final String MODEL_SCHEDULE_ALARM = "alarm";
+    // 日程类型
+    public static final String MODEL_SCHEDULE_TYPE = "schedule_type";
+
+    /*********************** 考勤组模块 *************************/
+    // 模块名称
+    public static final String MODEL_ATTEND_GROUP = "attend_group";
+    // 考勤组排班类型
+    public static final String MODEL_ATTEND_GROUP_TYPE = "group_type";
+
+    /*********************** 考勤记录模块 *************************/
+    // 模块名称
+    public static final String MODEL_ATTEND_RECORD = "attend_record";
+    // 考勤班次
+    public static final String MODEL_ATTEND_RECORD_ATTEND_SHIFT = "attend_shift";
+    // 打卡节点
+    public static final String MODEL_ATTEND_RECORD_CLOCK_NODE = "clock_node";
+    // 打卡结果
+    public static final String MODEL_ATTEND_RECORD_CLOCK_RESULT = "clock_result";
+    //是否外勤
+    public static final String MODEL_ATTEND_RECORD_OUTSIDE = "clock_outside";
+
+
+    /*********************** 公告模块 *************************/
+    // 模块名称
+    public static final String MODEL_NOTICE = "notice";
+    // 状态
+    public static final String MODEL_NOTICE_STATUS = "noticeStatus";
+    // 稿件状态
+    public static final String MODEL_NOTICE_MANUSCRIPT_STATUS = "manuscriptStatus";
+    //端口类型
+    public static final String MODEL_NOTICE_PORT = "port";
+    // 类型
+    public static final String MODEL_NOTICE_TYPE = "type";
+
+    /*********************** 任务申请模块 *************************/
+    // 申请状态
+    public static final String MODEL_APPLY = "apply";
+
+    public static final String MODEL_APPLY_STATUS = "apply_status";
+
+    public static final String MODEL_APPLY_RESULT = "result";
+
+    public static final String MODEL_APPLY_APPROVAL_OPINION_FLAG = "flag";
+
+    public static final String MODEL_APPLY_OUTSIDE_DETAIL = "transportation";
+
+    public static final String MODEL_APPLY_LEAVE_DETAIL = "leaveType";
+
+    public static final String MODEL_REIMBURSE_TYPE = "reimburse_type";
+    //当前任务下表单是否可编辑
+    public static final String MODEL_APPLY_TASK_FORM_WRITABLE = "writable";
+    //核稿模式
+    public static final String MODEL_APPLY_DOC_FINALIZE_EDIT = "finalizeEdit";
+    //流程中控制字段是否可编辑(批量控制)
+    public static final String MODEL_APPLY_TASK_FORM_FIELD_WRITABLE = "fieldWritable";
+    //会议确认用户任务
+    public static final String MODEL_APPLY_MEET_CONFIRM_TASK = "meetConfirmTask";
+    //信息发布
+    public static final String MODEL_APPLY_NOTICE_APPLY_USER_COMMIT_TASK="noticeApplyUserCommitTask";
+    //是否可以指定指定下一步办理人
+    public static final String MODEL_APPLY_NEXT_ASSIGN = "nextAssign";
+    //当前节点
+    public static final String MODEL_APPLY_NEXT_ISNODES = "isNodes";
+
+    /*********************** 流程审批表单配置 *************************/
+    public static final String MODEL_APPLY_CONFIG = "applyConfig";
+    public static final String MODEL_APPLY_CONFIG_FORMKEY = "formKey";
+    /***********************会议模块*************************/
+    //会议室状态
+    public static final String MODEL_MEET_ROOM = "meet_room";
+    public static final String MODEL_MEET_ROOM_STATUS = "status";
+    //会议状态
+    public static final String MODEL_MEET_TASK = "meet_task";
+    public static final String MODEL_MEET_TASK_STATUS = "status";
+    //参会人员
+    public static final String MODEL_MEET_TASK_PERSON = "meet_task_person";
+    public static final String MODEL_MEET_TASK_PERSON_staff_flag = "staff_flag";
+    /*********************** 报表 *************************/
+    public static final String MODEL_REPORT = "report";
+    public static final String MODEL_REPORT_STATUS = "apply_status";
+    /*********************** 物品 *************************/
+    public static final String MODEL_GOODS = "goods";
+    public static final String MODEL_GOODS_TYPE = "goods_type";
+    public static final String MODEL_GOODS_PAYWAY = "goods_pay_way";
+    public static final String MODEL_GOODS_STATUS = "goods_status";
+
+    /*********************** 预算 *************************/
+    public static final String MODEL_BUDGET = "budget";
+    public static final String MODEL_BUDGET_TYPE = "budget_type";
+    public static final String MODEL_BUDGET_YEAR = "year";
+    public static final String MODEL_BUDGET_PROJECT = "budget_project";
+    public static final String MODEL_BUDGET_CURRENCY = "currency";
+
+    /***********************用印 *************************/
+    public static final String MODEL_IMPRESS = "impress";
+    public static final String MODEL_MODEL_IMPRESS_TYPE = "impress_type";
+    public static final String MODEL_MODEL_IMPRESS_CHAPTER = "impress_chapter";
+
+    /***********************补卡 *************************/
+    public static final String MODEL_CARD_REPALCE = "card_replace";
+    public static final String MODEL_MODEL_CARD_REPLACE_TYPE = "card_replace_type";
+
+
+    /***********************资源 *************************/
+    public static final String MODEL_RESOURCE = "resource";
+    public static final String MODEL_MODEL_RESOURCE_SUBJECT = "subject";
+    public static final String MODEL_MODEL_RESOURCE_LANGUAGE = "language";
+    public static final String MODEL_MODEL_RESOURCE_BUY_STATUS = "buy_status";
+
+    /***********************维修部门和人员配置 *************************/
+    public static final String MODEL_MODEL_REPAIRS_MANAGE = "repairs_manage";
+    public static final String MODEL_MODEL_REPAIRS_ACCEPTER_TYPE = "accepter_type";
+}

+ 417 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/common/utils/StringUtils.java

@@ -0,0 +1,417 @@
+package org.jeecg.common.utils;
+
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 字符串工具类
+ *
+ * @author yao.sun
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+    /**
+     * 空字符串
+     */
+    private static final String NULLSTR = "";
+
+    /**
+     * 下划线
+     */
+    private static final char SEPARATOR = '_';
+
+    /**
+     * 获取参数不为空值
+     *
+     * @param value defaultValue 要判断的value
+     * @return value 返回值
+     */
+    public static <T> T nvl(T value, T defaultValue) {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 判断一个Collection是否为空, 包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Collection<?> coll) {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 判断一个Collection是否非空,包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Collection<?> coll) {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 判断一个对象数组是否为空
+     *
+     * @param objects 要判断的对象数组
+     *                * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Object[] objects) {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 判断一个对象数组是否非空
+     *
+     * @param objects 要判断的对象数组
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Object[] objects) {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Map<?, ?> map) {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Map<?, ?> map) {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 判断一个字符串是否为空串
+     *
+     * @param str String
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(String str) {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 判断一个字符串是否为非空串
+     *
+     * @param str String
+     * @return true:非空串 false:空串
+     */
+    public static boolean isNotEmpty(String str) {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 判断一个对象是否为空
+     *
+     * @param object Object
+     * @return true:为空 false:非空
+     */
+    public static boolean isNull(Object object) {
+        return object == null;
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object) {
+        return !isNull(object);
+    }
+
+    /**
+     * * 判断一个对象是否是数组类型(Java基本型别的数组)
+     *
+     * @param object 对象
+     * @return true:是数组 false:不是数组
+     */
+    public static boolean isArray(Object object) {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 去掉收尾的空格
+     */
+    public static String trim(String str) {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 去掉所有的空格
+     */
+    public static String trimAll(String str) {
+        return str == null ? "" : str.replace(" ", "");
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @return 结果
+     */
+    public static String substring(final String str, int start) {
+        if (str == null) {
+            return NULLSTR;
+        }
+
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (start > str.length()) {
+            return NULLSTR;
+        }
+
+        return str.substring(start);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @param end   结束
+     * @return 结果
+     */
+    public static String substring(final String str, int start, int end) {
+        if (str == null) {
+            return NULLSTR;
+        }
+
+        if (end < 0) {
+            end = str.length() + end;
+        }
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (end > str.length()) {
+            end = str.length();
+        }
+
+        if (start > end) {
+            return NULLSTR;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (end < 0) {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+
+
+    /**
+     * 驼峰首字符小写
+     */
+    public static String uncapitalize(String str) {
+        int strLen;
+        if (str == null || (strLen = str.length()) == 0) {
+            return str;
+        }
+        return new StringBuilder().append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
+    }
+
+    /**
+     * 下划线转驼峰命名
+     */
+    public static String toUnderScoreCase(String s) {
+        if (s == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+
+            boolean nextUpperCase = true;
+
+            if (i < (s.length() - 1)) {
+                nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
+            }
+
+            if ((i > 0) && Character.isUpperCase(c)) {
+                if (!upperCase || !nextUpperCase) {
+                    sb.append(SEPARATOR);
+                }
+                upperCase = true;
+            } else {
+                upperCase = false;
+            }
+
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 驼峰 转下划线 命名 不转大小写
+     */
+    public static String toUnderScoreCaseUnchange(String s) {
+        if (s == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+
+            boolean nextUpperCase = true;
+
+            if (i < (s.length() - 1)) {
+                nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
+            }
+
+            if ((i > 0) && Character.isUpperCase(c)) {
+                if (!upperCase || !nextUpperCase) {
+                    sb.append(SEPARATOR);
+                }
+                upperCase = true;
+            } else {
+                upperCase = false;
+            }
+
+            sb.append(c);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 是否包含字符串
+     *
+     * @param str  验证字符串
+     * @param strs 字符串组
+     * @return 包含返回true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs) {
+        if (str != null && strs != null) {
+            for (String s : strs) {
+                if (str.equalsIgnoreCase(trim(s))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+     *
+     * @param name 转换前的下划线大写方式命名的字符串
+     * @return 转换后的驼峰式命名的字符串
+     */
+    public static String convertToCamelCase(String name) {
+        StringBuilder result = new StringBuilder();
+        // 快速检查
+        if (name == null || name.isEmpty()) {
+            // 没必要转换
+            return "";
+        } else if (!name.contains("_")) {
+            // 不含下划线,仅将首字母大写
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 用下划线将原始字符串分割
+        String[] camels = name.split("_");
+        for (String camel : camels) {
+            // 跳过原始字符串中开头、结尾的下换线或双重下划线
+            if (camel.isEmpty()) {
+                continue;
+            }
+            // 首字母大写
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    // 首字母转小写
+    public static String toLowerCaseFirstOne(String s) {
+        if (Character.isLowerCase(s.charAt(0))) {
+            return s;
+        } else {
+            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
+        }
+    }
+
+    // 首字母转大写
+    public static String toUpperCaseFirstOne(String s) {
+
+        if (Character.isUpperCase(s.charAt(0))) {
+            return s;
+        } else {
+            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
+        }
+    }
+
+    public static String toUnicode(String text) {
+        StringBuffer sb = new StringBuffer();
+        char[] source_char = text.toCharArray();
+        String unicode = null;
+        for (int i = 0; i < source_char.length; i++) {
+            unicode = Integer.toHexString(source_char[i]);
+            if (unicode.length() <= 2) {
+                unicode = "00" + unicode;
+            }
+            sb.append("\\u" + unicode);
+        }
+        return sb.toString();
+    }
+
+    public static String fromUnicode(String unicode) {
+        StringBuffer sb = new StringBuffer();
+
+        String[] hex = unicode.split("\\\\u");
+
+        for (int i = 1; i < hex.length; i++) {
+            int data = Integer.parseInt(hex[i], 16);
+            sb.append((char) data);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 判断字符串是否为中文
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isChinese(String str) {
+        String regEx = "[\\u4e00-\\u9fa5]+";
+        Pattern p = Pattern.compile(regEx);
+        Matcher m = p.matcher(str);
+        if (m.find()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    public static void main(String[] args) {
+        String s = "CatalogDetailDivisionNumber";
+        String s1 = toUnderScoreCaseUnchange(s);
+        System.out.println(s1);
+    }
+}

+ 113 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/controller/ReModelController.java

@@ -0,0 +1,113 @@
+package org.jeecg.modules.activiti.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.activiti.engine.repository.Model;
+import org.jeecg.modules.activiti.model.entity.ReModelEntity;
+import org.jeecg.modules.activiti.service.ReModelService;
+import org.jeecg.common.api.vo.Result;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+/**
+ * 模型管理
+ *
+ * @author yao
+ * @date 2019/06/13
+ */
+@RestController
+@RequestMapping("/act/remodel")
+public class ReModelController {
+
+    @Autowired
+    private ReModelService actReModelService;
+
+    /**
+     * 分页查询
+     *
+     * @param req
+     *            查询参数
+     * @return RestResponse
+     */
+    @GetMapping("/list")
+    public Result list(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+                       HttpServletRequest req) {
+        IPage page = actReModelService.queryPage( pageNo, pageSize, req);
+
+        return Result.OK(page);
+    }
+
+    /**
+     * 新增
+     *
+     * @param actReModel
+     *            actReModel
+     * @return RestResponse
+     */
+    @PostMapping("/save")
+    public Result save(@RequestBody  ReModelEntity actReModel,HttpServletRequest req) {
+        String modelId = "";
+        try {
+            String tenantId = req.getHeader("tenant-id");
+            actReModel.setTenantId(tenantId);
+            Model model = actReModelService.add(actReModel);
+            modelId = model.getId();
+        } catch (Exception e) {
+            Result.error(e.getMessage());
+        }
+        return Result.OK(modelId);
+    }
+
+    /**
+     * 根据Model部署流程
+     *
+     * @param id
+     *            标识
+     * @return RestResponse
+     */
+    @RequestMapping("/deploy")
+    public Result deploy(String id,HttpServletRequest request) {
+
+        return actReModelService.deploy(id,request);
+    }
+
+    /**
+     * 导出model的xml文件
+     *
+     * @param id
+     *            model标识
+     * @param response
+     *            响应
+     */
+    @GetMapping(value = "export")
+    public void export(String id, HttpServletResponse response) {
+        actReModelService.export(id, response);
+    }
+
+    /**
+     * 根据主键批量删除
+     * @param ids
+     * @return RestResponse
+     */
+    @RequestMapping("/deleteBatchByIds")
+    public Result deleteBatchByIds(@RequestParam("ids[]") String[] ids) {
+        actReModelService.deleteBatch(ids);
+        return Result.OK();
+    }
+
+    /**
+     * 根据主键删除
+     * @param id
+     * @return RestResponse
+     */
+    @RequestMapping("/deleteById")
+    public Result deleteById(@RequestParam("id") String id) {
+        actReModelService.delete(id);
+        return Result.OK();
+    }
+
+}

+ 180 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/controller/ReProcdefController.java

@@ -0,0 +1,180 @@
+package org.jeecg.modules.activiti.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.activiti.engine.repository.Model;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.activiti.service.ReProcdefService;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.exception.JeecgBootException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * 流程管理
+ *
+ * @author yao
+ * @date 2019/06/13
+ */
+@RestController
+@RequestMapping("act/reprocdef")
+public class ReProcdefController {
+    @Autowired
+    private ReProcdefService reProcdefService;
+
+    /**
+     * 分页查询
+     *
+     * @param req
+     *            查询参数
+     * @return RestResponse
+     */
+    @GetMapping("/list")
+    public Result list(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+                       HttpServletRequest req) {
+        IPage page = reProcdefService.queryPage( pageNo,pageSize,req);
+        return Result.OK(page);
+    }
+
+    /**
+     * 获取激活的流程
+     *
+     * @return RestResponse
+     */
+    @GetMapping("/list/active")
+    public Result listActive(HttpServletRequest request) {
+        return Result.OK(reProcdefService.listActive(request));
+    }
+
+    /**
+     * 读取资源,通过部署ID
+     *
+     * @param id
+     *            流程定义ID
+     * @param proInsId
+     *            流程实例ID
+     * @param resType
+     *            资源类型(xml|image)
+     * @param response
+     *            响应
+     * @throws Exception
+     *             读写流异常
+     */
+    @RequestMapping("/read")
+    public void resourceRead(String id, String proInsId, String resType, HttpServletResponse response)
+        throws Exception {
+        InputStream resourceAsStream = reProcdefService.resourceRead(id, proInsId, resType);
+        byte[] b = new byte[1024];
+        int len = -1;
+        int lenEnd = 1024;
+        while ((len = resourceAsStream.read(b, 0, lenEnd)) != -1) {
+            response.getOutputStream().write(b, 0, len);
+        }
+    }
+
+    /**
+     * 部署流程文件
+     *
+     * @param file
+     *            file
+     * @return RestResponse
+     */
+    @RequestMapping("/deploy")
+    public Result deploy(MultipartFile file,HttpServletRequest request) {
+        String exportDir = this.getClass().getResource("/").getPath();
+        String fileName = file.getOriginalFilename();
+        String msg = "";
+        if (StringUtils.isBlank(fileName)) {
+            throw new JeecgBootException("请选择要部署的流程文件");
+        } else {
+            try {
+                msg = reProcdefService.deploy(exportDir, file, request);
+            } catch (Exception e) {
+                return Result.error(e.getMessage());
+            }
+        }
+        return Result.OK(msg);
+    }
+
+    /**
+     * 转为模型
+     *
+     * @param id
+     *            id
+     * @return RestResponse
+     */
+    @GetMapping("/convertToModel")
+    public Result convertToModel(String id,HttpServletRequest request) {
+        Model model = null;
+        try {
+             model = reProcdefService.convertToModel(id,request);
+
+        } catch (Exception e) {
+            return Result.error(e.getMessage());
+        }
+        return Result.OK(model);
+    }
+
+    /**
+     * 启动流程实例,通过processDefinitionId
+     *
+     * @param processDefinitionId
+     *            processDefinitionId
+     * @return RestResponse
+     */
+    @RequestMapping("/startProcessInstanceById")
+    public Result startProcessInstanceById(String processDefinitionId) {
+        try {
+            reProcdefService.startProcessInstanceById(processDefinitionId);
+        } catch (Exception e) {
+            return Result.error(e.getMessage());
+        }
+        return Result.OK();
+    }
+
+    /**
+     * 激活 / 挂起
+     *
+     * @param state
+     * @param id
+     * @return
+     */
+    @GetMapping("/update")
+    public Result update(String id,int state) {
+        String msg = reProcdefService.updateState(state, id);
+        return Result.OK(msg);
+    }
+
+    /**
+     * 批量删除部署的流程,级联删除流程实例
+     *
+     * @param ids
+     *            流程部署标识
+     * @return RestResponse
+     */
+    @RequestMapping("/deleteBatchByIds")
+    public Result deleteBatchByIds(@RequestParam("ids[]") String[] ids) {
+        reProcdefService.deleteBatch(ids);
+        return Result.OK();
+    }
+
+    /**
+     * 删除部署的流程,级联删除流程实例
+     *
+     * @param deploymentId
+     *            流程部署标识
+     * @return RestResponse
+     */
+    @DeleteMapping("/deleteByDeploymentId")
+    public Result deleteByDeploymentId(String deploymentId) {
+        reProcdefService.deleteByDeploymentId(deploymentId);
+        return Result.OK();
+    }
+
+}

+ 149 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/controller/ServiceController.java

@@ -0,0 +1,149 @@
+package org.jeecg.modules.activiti.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.activiti.engine.*;
+import org.activiti.engine.identity.User;
+import org.activiti.engine.repository.Model;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 模型控制
+ *
+ * @author yao
+ * @date 2019/06/13
+ */
+@RestController
+@RequestMapping("/service")
+public class ServiceController {
+    @Autowired
+    ObjectMapper objectMapper;
+    @Autowired
+    private RepositoryService repositoryService;
+
+
+    /**
+     * stencilset
+     *
+     * @return stencilset.json
+     */
+    @RequestMapping(value="/act/userSyn", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
+    public Result<LoginUser> actUserSyn(HttpServletRequest request) {
+        LoginUser sysUser         = (LoginUser) request.getAttribute("user");
+        String    selectedRoles   =  request.getAttribute("selectedRoles").toString();
+        String    selectedDeparts =  request.getAttribute("selectedDeparts").toString();
+        Result<LoginUser> result  = (Result<LoginUser>) request.getAttribute("result");
+
+        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
+        IdentityService identityService = engine.getIdentityService();
+        User user = identityService.newUser(sysUser.getId());
+        user.setFirstName(sysUser.getUsername());
+        user.setLastName(sysUser.getRealname());
+        user.setEmail(sysUser.getEmail());
+        user.setPassword(sysUser.getPassword());
+        identityService.saveUser(user);
+        
+
+        return result;
+    }
+    /**
+     * stencilset
+     *
+     * @return stencilset.json
+     */
+    @RequestMapping(value="/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
+    public String getStencilset() {
+        InputStream stencilsetStream = this.getClass().getResourceAsStream("/static/stencilset.json");
+        try {
+            return IOUtils.toString(stencilsetStream, "utf-8");
+        } catch (Exception e) {
+            throw new ActivitiException("Error while loading stencil set", e);
+        }
+    }
+
+    /**
+     * 模型详情
+     *
+     * @param modelId
+     * @return
+     */
+    @RequestMapping(value="/model/{modelId}/json", method = RequestMethod.GET)
+    public ObjectNode getEditorJson(@PathVariable String modelId) {
+        ObjectNode modelNode = null;
+
+        Model model = repositoryService.getModel(modelId);
+
+        if (model != null) {
+            try {
+                if (StringUtils.isNotEmpty(model.getMetaInfo())) {
+                    modelNode = (ObjectNode)objectMapper.readTree(model.getMetaInfo());
+                } else {
+                    modelNode = objectMapper.createObjectNode();
+                    modelNode.put("name", model.getName());
+                }
+                modelNode.put("modelId", model.getId());
+                ObjectNode editorJsonNode = (ObjectNode)objectMapper
+                    .readTree(new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"));
+                modelNode.set("model", editorJsonNode);
+
+            } catch (Exception e) {
+                throw new ActivitiException("Error creating model JSON", e);
+            }
+        }
+        return modelNode;
+    }
+
+    /**
+     * 保存
+     *
+     * @param modelId
+     * @param name
+     * @param jsonXml
+     * @param svgXml
+     * @param description
+     */
+    @RequestMapping(value = "/model/{modelId}/save", method=RequestMethod.PUT)
+    public void saveModel(@PathVariable String modelId, @RequestParam("name") String name,
+                          @RequestParam("json_xml") String jsonXml, @RequestParam("svg_xml") String svgXml,
+                          @RequestParam("description") String description,HttpServletRequest req) {
+        try {
+            String tenantId = req.getHeader("tenant-id");
+            Model model = repositoryService.getModel(modelId);
+            ObjectNode modelJson = (ObjectNode)objectMapper.readTree(model.getMetaInfo());
+            modelJson.put("name", name);
+            modelJson.put("description", description);
+            model.setMetaInfo(modelJson.toString());
+            model.setName(name);
+            model.setVersion(model.getVersion()+1);
+            model.setTenantId(tenantId);
+            repositoryService.saveModel(model);
+            repositoryService.addModelEditorSource(model.getId(), jsonXml.getBytes(StandardCharsets.UTF_8));
+
+            InputStream svgStream = new ByteArrayInputStream(svgXml.getBytes(StandardCharsets.UTF_8));
+            TranscoderInput input = new TranscoderInput(svgStream);
+            PNGTranscoder transcoder = new PNGTranscoder();
+            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+            TranscoderOutput output = new TranscoderOutput(outStream);
+            transcoder.transcode(input, output);
+            final byte[] result = outStream.toByteArray();
+            repositoryService.addModelEditorSourceExtra(model.getId(), result);
+            outStream.close();
+        } catch (Exception e) {
+            throw new ActivitiException("Error saving model", e);
+        }
+    }
+}

+ 120 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/manage/CustomGroupEntityManager.java

@@ -0,0 +1,120 @@
+package org.jeecg.modules.activiti.manage;
+
+
+import org.activiti.engine.identity.Group;
+import org.activiti.engine.identity.GroupQuery;
+import org.activiti.engine.impl.GroupQueryImpl;
+import org.activiti.engine.impl.Page;
+import org.activiti.engine.impl.persistence.entity.GroupEntity;
+import org.activiti.engine.impl.persistence.entity.GroupEntityManager;
+import org.jeecg.common.system.api.ISysBaseAPI;
+//import org.jeecg.common.system.vo.RoleVO;
+import org.jeecg.modules.activiti.model.converter.ActivitiConverter;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * activiti用户组业务实现
+ *
+ * @author LEN
+ * @since 2019/6/14 18:28
+ */
+
+@Component
+public class CustomGroupEntityManager implements GroupEntityManager {
+
+    @Autowired
+    private ISysBaseAPI iSysBaseAPI;
+
+    @Override
+    public Group createNewGroup(String s) {
+        return null;
+    }
+
+    @Override
+    public GroupQuery createNewGroupQuery() {
+        return null;
+    }
+
+    @Override
+    public List<Group> findGroupByQueryCriteria(GroupQueryImpl groupQuery, Page page) {
+        return null;
+    }
+
+    @Override
+    public long findGroupCountByQueryCriteria(GroupQueryImpl groupQuery) {
+        return 0;
+    }
+
+
+    public List<Group> findGroupsByUser(String userId) {
+       // List<RoleVO> userRoles = iSysBaseAPI.getRolesByUserId(userId);
+        // ActivitiConverter.toActivitiGroups(userRoles);
+        return null;
+
+    }
+
+    @Override
+    public List<Group> findGroupsByNativeQuery(Map<String, Object> map, int i, int i1) {
+        return null;
+    }
+
+    @Override
+    public long findGroupCountByNativeQuery(Map<String, Object> map) {
+        return 0;
+    }
+
+    @Override
+    public boolean isNewGroup(Group group) {
+        return false;
+    }
+
+    @Override
+    public GroupEntity create() {
+        return null;
+    }
+
+    @Override
+    public GroupEntity findById(String s) {
+        return null;
+    }
+
+    @Override
+    public void insert(GroupEntity entity) {
+
+    }
+
+    @Override
+    public void insert(GroupEntity entity, boolean b) {
+
+    }
+
+    @Override
+    public GroupEntity update(GroupEntity entity) {
+        return null;
+    }
+
+    @Override
+    public GroupEntity update(GroupEntity entity, boolean b) {
+        return null;
+    }
+
+    @Override
+    public void delete(String s) {
+
+    }
+
+    @Override
+    public void delete(GroupEntity entity) {
+
+    }
+
+    @Override
+    public void delete(GroupEntity entity, boolean b) {
+
+    }
+}

+ 147 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/manage/CustomUserEntityManager.java

@@ -0,0 +1,147 @@
+package org.jeecg.modules.activiti.manage;
+
+import org.activiti.engine.identity.Group;
+import org.activiti.engine.identity.Picture;
+import org.activiti.engine.identity.User;
+import org.activiti.engine.identity.UserQuery;
+import org.activiti.engine.impl.Page;
+import org.activiti.engine.impl.UserQueryImpl;
+import org.activiti.engine.impl.persistence.entity.UserEntity;
+import org.activiti.engine.impl.persistence.entity.UserEntityManager;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.system.vo.UserVO;
+import org.jeecg.modules.activiti.model.converter.ActivitiConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * activiti用户业务实现
+ *
+ * @author LEN
+ * @since 2019/6/14 18:16
+ */
+
+@Component
+public class CustomUserEntityManager implements UserEntityManager {
+    @Autowired
+    private ISysBaseAPI iSysBaseAPI;
+
+    @Override
+    public User createNewUser(String s) {
+        return null;
+    }
+
+    @Override
+    public void updateUser(User user) {
+
+    }
+
+    @Override
+    public List<User> findUserByQueryCriteria(UserQueryImpl userQuery, Page page) {
+        System.out.println("***************1************");
+        return null;
+    }
+
+    @Override
+    public long findUserCountByQueryCriteria(UserQueryImpl userQuery) {
+        System.out.println("***************2************");
+        return 0;
+    }
+
+    @Override
+    public List<Group> findGroupsByUser(String s) {
+        System.out.println("***************3************");
+        return null;
+    }
+
+    @Override
+    public UserQuery createNewUserQuery() {
+        return null;
+    }
+
+    @Override
+    public Boolean checkPassword(String s, String s1) {
+        return null;
+    }
+
+    @Override
+    public List<User> findUsersByNativeQuery(Map<String, Object> map, int i, int i1) {
+        return null;
+    }
+
+    @Override
+    public long findUserCountByNativeQuery(Map<String, Object> map) {
+        return 0;
+    }
+
+    @Override
+    public boolean isNewUser(User user) {
+        return false;
+    }
+
+    @Override
+    public Picture getUserPicture(String s) {
+        return null;
+    }
+
+    @Override
+    public void setUserPicture(String s, Picture picture) {
+
+    }
+
+    @Override
+    public void deletePicture(User user) {
+
+    }
+
+    @Override
+    public UserEntity create() {
+        return null;
+    }
+
+    @Override
+    public UserEntity findById(String userId) {
+        //UserVO result = iSysBaseAPI.getUserVOById(userId);
+        return null;
+
+    }
+
+    @Override
+    public void insert(UserEntity entity) {
+
+    }
+
+    @Override
+    public void insert(UserEntity entity, boolean b) {
+
+    }
+
+    @Override
+    public UserEntity update(UserEntity entity) {
+        return null;
+    }
+
+    @Override
+    public UserEntity update(UserEntity entity, boolean b) {
+        return null;
+    }
+
+    @Override
+    public void delete(String s) {
+
+    }
+
+    @Override
+    public void delete(UserEntity entity) {
+
+    }
+
+    @Override
+    public void delete(UserEntity entity, boolean b) {
+
+    }
+}

+ 17 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/ReModelMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.activiti.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.activiti.model.entity.ReModelEntity;
+
+/**
+ * 模型管理
+ *
+ * @author yao
+ * @date 2019/06/13
+ */
+@Mapper
+public interface ReModelMapper extends BaseMapper<ReModelEntity> {
+
+}

+ 17 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/ReProcdefMapper.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.activiti.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.activiti.model.entity.ReProcdefEntity;
+
+/**
+ * 流程管理
+ *
+ * @author yao
+ * @date 2019/06/13
+ */
+@Mapper
+public interface ReProcdefMapper extends BaseMapper<ReProcdefEntity> {
+
+}

+ 6 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/xml/ReModelMapper.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.jeecg.modules.activiti.mapper.ReModelMapper">
+
+</mapper>

+ 6 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/mapper/xml/ReProcdefMapper.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.jeecg.modules.activiti.mapper.ReProcdefMapper">
+
+</mapper>

+ 60 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/model/converter/ActivitiConverter.java

@@ -0,0 +1,60 @@
+package org.jeecg.modules.activiti.model.converter;
+
+
+import org.activiti.engine.identity.Group;
+import org.activiti.engine.impl.persistence.entity.GroupEntity;
+import org.activiti.engine.impl.persistence.entity.GroupEntityImpl;
+import org.activiti.engine.impl.persistence.entity.UserEntity;
+import org.activiti.engine.impl.persistence.entity.UserEntityImpl;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.system.vo.RoleVO;
+import org.jeecg.common.system.vo.UserVO;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * 工作流用户转换
+ *
+ * @author LEN
+ * @since 2019/6/14 18:17
+ */
+
+public class ActivitiConverter {
+
+    public static UserEntity toActivitiUser(UserVO UserVO) {
+        UserEntity userEntity = new UserEntityImpl();
+        userEntity.setId(UserVO.getId());
+        userEntity.setFirstName(UserVO.getRealname());
+        userEntity.setLastName(UserVO.getRealname());
+        userEntity.setPassword(UserVO.getPassword());
+        userEntity.setEmail(UserVO.getEmail());
+        userEntity.setRevision(1);
+        return userEntity;
+    }
+
+    /**
+     * 通过角色
+     * @param roleDTO
+     * @return
+     */
+    public static GroupEntity toActivitiGroup(RoleVO roleDTO) {
+        GroupEntity groupEntity = new GroupEntityImpl();
+        groupEntity.setRevision(1);
+        groupEntity.setType("assignment");
+        groupEntity.setName(roleDTO.getRoleName());
+        groupEntity.setId(roleDTO.getId());
+        return groupEntity;
+    }
+
+    public static List<Group> toActivitiGroups(List<RoleVO> roleCodeList) {
+        List<Group> groups = new ArrayList<>();
+        for (RoleVO roleDTO : roleCodeList) {
+            GroupEntity groupEntity = toActivitiGroup(roleDTO);
+            groups.add(groupEntity);
+        }
+        return groups;
+    }
+
+}

+ 81 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/model/entity/ReModelEntity.java

@@ -0,0 +1,81 @@
+package org.jeecg.modules.activiti.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 模型
+ *
+ * @author yao
+ * @date 2019/06/12
+ */
+@Data
+@TableName("ACT_RE_MODEL")
+public class ReModelEntity implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     *
+     */
+    @TableId
+    private String id;
+    /**
+     * 乐观锁版本号
+     */
+    private Integer rev;
+    /**
+     * 模型的名称
+     */
+    private String name;
+    /**
+     * 模型的关键字,流程引擎用到。
+     */
+    private String key;
+    /**
+     * 类型,用户自己对流程模型的分类。
+     */
+    private String category;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+    /**
+     * 最后修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date lastUpdateTime;
+    /**
+     * 版本,从1开始。
+     */
+    private Integer version;
+    /**
+     * 数据源信息,以json格式保存流程定义的信息
+     */
+    private String metaInfo;
+    /**
+     * 部署ID
+     */
+    private String deploymentId;
+    /**
+     * 编辑源值ID,是 ACT_GE_BYTEARRAY 表中的ID_值。
+     */
+    private String editorSourceValueId;
+    /**
+     * 编辑源额外值ID,是 ACT_GE_BYTEARRAY 表中的ID_值。
+     */
+    private String editorSourceExtraValueId;
+    /**
+     * TENANT_ID_
+     * 租户
+     */
+    private String tenantId;
+
+    @TableField(exist = false)
+    private String description;
+}

+ 93 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/model/entity/ReProcdefEntity.java

@@ -0,0 +1,93 @@
+package org.jeecg.modules.activiti.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 流程控制
+ *
+ * @author yao
+ * @date 2019/06/12
+ */
+@Data
+@TableName("ACT_RE_PROCDEF")
+public class ReProcdefEntity implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 流程ID,由“流程编号:流程版本号:自增长ID”组成
+     */
+    @TableId
+    private String id;
+    /**
+     * 乐观锁版本号
+     */
+    private Integer rev;
+    /**
+     * 流程命名空间(该编号就是流程文件targetNamespace的属性值)
+     */
+    private String category;
+    /**
+     * 流程名称(该编号就是流程文件process元素的name属性值)
+     */
+    private String name;
+    /**
+     * 流程编号(该编号就是流程文件process元素的id属性值)
+     */
+    private String key;
+    /**
+     * 流程版本号(由程序控制,新增即为1,修改后依次加1来完成的)
+     */
+    private Integer version;
+    /**
+     * 部署编号
+     */
+    private String deploymentId;
+    /**
+     * 资源文件名称
+     */
+    private String resourceName;
+    /**
+     * 图片资源文件名称
+     */
+    private String dgrmResourceName;
+    /**
+     * 描述信息
+     */
+    private String description;
+    /**
+     * 是否从key启动 start节点是否存在formKey
+     * <p>
+     * 0否 1是
+     */
+    private Integer hasStartFormKey;
+    /**
+     * 是否有图片预览
+     */
+    private Integer hasGraphicalNotation;
+    /**
+     * 是否挂起
+     * <p>
+     * 1激活 2挂起
+     */
+    private Integer suspensionState;
+    /**
+     * 所属系统
+     */
+    private String tenantId;
+    /**
+     * 工作流引擎
+     */
+    private String engineVersion;
+
+    /**
+     * 部署时间
+     */
+    @TableField(exist = false)
+    private Date deployTime;
+}

+ 69 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/ReModelService.java

@@ -0,0 +1,69 @@
+package org.jeecg.modules.activiti.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.activiti.engine.repository.Model;
+import org.jeecg.modules.activiti.model.entity.ReModelEntity;
+import org.jeecg.common.api.vo.Result;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+/**
+ * 模型接口
+ *
+ * @author yao
+ * @date 2019/06/12
+ */
+public interface ReModelService extends IService<ReModelEntity> {
+
+    /**
+     * 分页查询
+     *
+     * @param  req 查询参数
+     * @return Page
+     */
+    IPage queryPage(Integer pageNo, Integer pageSize, HttpServletRequest req);
+
+    /**
+     * 新增
+     *
+     * @param actReModel
+     * @return 新增结果
+     * @throws UnsupportedEncodingException
+     */
+    Model add(ReModelEntity actReModel) throws UnsupportedEncodingException;
+
+    /**
+     * 部署工作流模型
+     *
+     * @param id 模型标识
+     * @return 部署信息
+     */
+    Result deploy(String id,HttpServletRequest request);
+
+    /**
+     * 导出XML
+     *
+     * @param id       流程模型标识
+     * @param response 响应
+     */
+    void export(String id, HttpServletResponse response);
+
+    /**
+     * 根据主键删除
+     *
+     * @param id id
+     */
+    void delete(String id);
+
+    /**
+     * 根据主键批量删除
+     *
+     * @param ids ids
+     */
+    void deleteBatch(String[] ids);
+}

+ 119 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/ReProcdefService.java

@@ -0,0 +1,119 @@
+package org.jeecg.modules.activiti.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.activiti.engine.repository.Model;
+import org.jeecg.modules.activiti.model.entity.ReProcdefEntity;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 流程接口
+ *
+ * @author yao
+ * @date 2019/06/12
+ */
+public interface ReProcdefService extends IService<ReProcdefEntity> {
+    /**
+     * 通过部署ID读取资源
+     *
+     * @param id
+     *            流程部署标识
+     * @param proInsId
+     *            流程实例表示
+     * @param resType
+     *            部署文件类型
+     * @return 文件流
+     */
+    InputStream resourceRead(String id, String proInsId, String resType);
+
+    /**
+     * 启动流程实例,通过processDefinitionId
+     *
+     * @param processDefinitionId
+     */
+    void startProcessInstanceById(String processDefinitionId);
+
+    /**
+     * 分页查询
+     *
+     * @param req
+     *            查询参数
+     * @return Page
+     */
+    IPage queryPage(Integer pageNo,Integer pageSize,HttpServletRequest req);
+
+    /**
+     * 删除部署流程
+     *
+     * @param deploymentId
+     *            流程部署标识
+     */
+    void delete(String deploymentId);
+
+    /**
+     * 删除部署流程
+     *
+     * @param deploymentIds
+     *            流程部署标识
+     */
+    void deleteBatch(String[] deploymentIds);
+
+    /**
+     * 删除部署流程
+     *
+     * @param deploymentId
+     *            流程部署标识
+     */
+    void deleteByDeploymentId(String deploymentId);
+
+    /**
+     * 根据文件部署工作流
+     *
+     * @param exportDir
+     *            文件地址
+     * @param file
+     *            上传文件
+     * @return 部署信息
+     * @throws IOException
+     */
+    String deploy(String exportDir, MultipartFile file,HttpServletRequest request) throws IOException;
+
+    /**
+     * 转为模型
+     *
+     * @param id
+     *            id
+     * @return Model
+     * @throws UnsupportedEncodingException
+     * @throws XMLStreamException
+     */
+    Model convertToModel(String id,HttpServletRequest request) throws UnsupportedEncodingException, XMLStreamException;
+
+    /**
+     * 流程挂起和激活
+     *
+     * @param state
+     *            流程状态
+     * @param id
+     *            流程部署标识
+     * @return 操作信息
+     */
+    String updateState(int state, String id);
+
+    /**
+     * 获取激活的流程
+     *
+     * @return
+     */
+    List<ReProcdefEntity> listActive(HttpServletRequest request);
+}

+ 183 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/impl/ReModelServiceImpl.java

@@ -0,0 +1,183 @@
+package org.jeecg.modules.activiti.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.activiti.bpmn.converter.BpmnXMLConverter;
+import org.activiti.bpmn.model.BpmnModel;
+import org.activiti.editor.constants.ModelDataJsonConstants;
+import org.activiti.editor.language.json.converter.BpmnJsonConverter;
+import org.activiti.engine.RepositoryService;
+import org.activiti.engine.repository.Deployment;
+import org.activiti.engine.repository.Model;
+import org.activiti.engine.repository.ModelQuery;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.activiti.mapper.ReModelMapper;
+import org.jeecg.modules.activiti.model.entity.ReModelEntity;
+import org.jeecg.modules.activiti.service.ReModelService;
+import org.jeecg.common.Constant;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.exception.CustomException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 模型实现类
+ *
+ * @author yao
+ * @date 2019/06/12
+ */
+@Service
+public class ReModelServiceImpl extends ServiceImpl<ReModelMapper, ReModelEntity> implements ReModelService {
+    @Autowired
+    private RepositoryService repositoryService;
+
+    @Override
+    public IPage queryPage(Integer pageNo, Integer pageSize, HttpServletRequest req) {
+
+//        String tenantId = req.getHeader("tenant-id");
+//        .modelTenantId(tenantId)
+        ModelQuery modelQuery = repositoryService.createModelQuery()
+                .orderByLastUpdateTime()
+                .desc()
+                .orderByModelVersion().desc();
+        String[] keys = req.getParameterMap().get("key");
+        if (!"".equals(keys) && keys != null) {
+            String key = keys[0];
+            modelQuery.modelKey(key);
+        }
+        String[] names = req.getParameterMap().get("name");
+        if (!"".equals(names) && names != null) {
+            String name = names[0];
+            modelQuery.modelName(name);
+        }
+        List<Model> list = modelQuery.listPage((pageNo - 1) * pageSize, pageSize);
+        IPage<Model> page = new Page<>(pageNo, pageSize);
+        page.setTotal((int) modelQuery.count());
+
+        return page.setRecords(list);
+    }
+
+    @Override
+    public Model add(ReModelEntity actReModel) throws UnsupportedEncodingException {
+        String description = actReModel.getDescription();
+        String key = actReModel.getKey();
+        String name = actReModel.getName();
+        String tenantId = actReModel.getTenantId();
+        ObjectMapper objectMapper = new ObjectMapper();
+        ObjectNode editorNode = objectMapper.createObjectNode();
+        editorNode.put("id", "canvas");
+        editorNode.put("resourceId", "canvas");
+        ObjectNode stencilSetNode = objectMapper.createObjectNode();
+        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
+        editorNode.set("stencilset", stencilSetNode);
+        Model modelData = repositoryService.newModel();
+
+        description = StringUtils.defaultString(description);
+        modelData.setKey(StringUtils.defaultString(key));
+        modelData.setName(name);
+        modelData.setVersion(Integer
+                .parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count() + 1)));
+
+        ObjectNode modelObjectNode = objectMapper.createObjectNode();
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
+        modelData.setMetaInfo(modelObjectNode.toString());
+        modelData.setTenantId(tenantId);
+        repositoryService.saveModel(modelData);
+        repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
+
+        return modelData;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result deploy(String id,HttpServletRequest request) {
+        String message = "";
+        try {
+            Model modelData = repositoryService.getModel(id);
+            if(StringUtils.isEmpty(modelData.getTenantId())){
+                String tenantId = request.getHeader("tenant-id");
+                modelData.setTenantId(tenantId);
+            }
+            byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
+            if (bytes == null) {
+                return Result.error("模型为空");
+            }
+            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
+            JsonNode editor = new ObjectMapper().readTree(bytes);
+            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editor);
+            if (bpmnModel.getProcesses().size() == 0) {
+                return Result.error("部署失败,没有设计流程");
+            }
+            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
+            byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
+
+            String processName = modelData.getName();
+            if (!StringUtils.endsWith(processName, Constant.ACT_BPMN20)) {
+                processName += Constant.ACT_BPMN20;
+            }
+            ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
+            Deployment deployment =
+                    repositoryService.createDeployment()
+                       .name(modelData.getName())
+                       .addInputStream(processName, in)
+                       .tenantId(modelData.getTenantId())
+                       .deploy();
+            // 设置流程分类
+            modelData.setDeploymentId(deployment.getId());
+            repositoryService.saveModel(modelData);
+            return Result.OK("部署成功,流程ID=" + modelData.getId());
+        } catch (Exception e) {
+            throw new CustomException("部署失败", e);
+        }
+    }
+
+    @Override
+    public void export(String id, HttpServletResponse response) {
+        try {
+            Model modelData = repositoryService.getModel(id);
+            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
+            JsonNode editor = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
+            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editor);
+            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
+            byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
+
+            ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
+            IOUtils.copy(in, response.getOutputStream());
+            String filename = URLEncoder.encode(modelData.getName() + ".bpmn20.xml", "UTF-8");
+            response.setHeader("Content-Disposition", "attachment; filename=" + filename);
+            response.flushBuffer();
+        } catch (Exception e) {
+            throw new CustomException("导出model的xml文件失败,模型ID=" + id, e);
+        }
+
+    }
+
+    @Override
+    public void delete(String id) {
+        repositoryService.deleteModel(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteBatch(String[] ids) {
+        for (String id : ids) {
+            repositoryService.deleteModel(id);
+        }
+    }
+}

+ 275 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/activiti/service/impl/ReProcdefServiceImpl.java

@@ -0,0 +1,275 @@
+package org.jeecg.modules.activiti.service.impl;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
+import org.activiti.bpmn.converter.BpmnXMLConverter;
+import org.activiti.bpmn.model.BpmnModel;
+import org.activiti.editor.constants.ModelDataJsonConstants;
+import org.activiti.editor.language.json.converter.BpmnJsonConverter;
+import org.activiti.engine.RepositoryService;
+import org.activiti.engine.RuntimeService;
+import org.activiti.engine.repository.*;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.activiti.mapper.ReProcdefMapper;
+import org.jeecg.modules.activiti.model.entity.ReProcdefEntity;
+import org.jeecg.modules.activiti.service.ReProcdefService;
+import org.jeecg.common.Constant;
+import org.jeecg.common.exception.CustomException;
+import org.jeecg.common.exception.ExceptionCode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipInputStream;
+
+/**
+ * 流程实现类
+ *
+ * @author yao
+ * @date 2019/06/12
+ */
+@Service("reProcdefService")
+public class ReProcdefServiceImpl extends ServiceImpl<ReProcdefMapper, ReProcdefEntity> implements ReProcdefService {
+
+    @Autowired
+    private RuntimeService runtimeService;
+    @Autowired
+    private RepositoryService repositoryService;
+
+    @Override
+    public InputStream resourceRead(String id, String proInsId, String resType) {
+        if (StringUtils.isBlank(id)) {
+            ProcessInstance processInstance =
+                    runtimeService.createProcessInstanceQuery().processInstanceId(proInsId).singleResult();
+            id = processInstance.getProcessDefinitionId();
+        }
+        ProcessDefinition processDefinition =
+                repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
+
+        String resourceName = "";
+        if (Constant.ACT_IMAGE.equals(resType)) {
+            resourceName = processDefinition.getDiagramResourceName();
+        } else if (Constant.ACT_XML.equals(resType)) {
+            resourceName = processDefinition.getResourceName();
+        }
+
+        InputStream resourceAsStream =
+                repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
+        return resourceAsStream;
+    }
+
+    @Override
+    public void startProcessInstanceById(String processDefinitionId) {
+        runtimeService.startProcessInstanceById(processDefinitionId);
+    }
+
+    @Override
+    public IPage queryPage( Integer pageNo, Integer pageSize,HttpServletRequest req) {
+
+//        String tenantId = req.getHeader("tenant-id");
+//         .processDefinitionTenantId(tenantId)
+        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
+                .latestVersion()
+                .orderByProcessDefinitionKey()
+                .asc();
+        //processDefinitionQuery.processDefinitionTenantId(UserUtils.getTenantId());
+        String[] categories = req.getParameterMap().get("category");
+        if (!"".equals(categories) && categories !=null) {
+            String category = categories[0];
+            processDefinitionQuery.processDefinitionCategory(category);
+        }
+
+        String[] keys = req.getParameterMap().get("key");
+        if (!"".equals(keys) && keys != null ) {
+            String key = keys[0];
+            processDefinitionQuery.processDefinitionKey(key);
+        }
+        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage((pageNo - 1) * pageSize, pageSize);
+
+        List<ReProcdefEntity> list = this.definitionToReprocess(processDefinitionList);
+
+        IPage<ReProcdefEntity> page = new Page<>(pageNo, pageSize);
+        page.setTotal((int) processDefinitionQuery.count());
+        return page.setRecords(list);
+    }
+
+    @Override
+    public void delete(String id) {
+        repositoryService.deleteDeployment(id, false);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteBatch(String[] deploymentIds) {
+        for (String deploymentId : deploymentIds) {
+            repositoryService.deleteDeployment(deploymentId, false);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteByDeploymentId(String deploymentId) {
+            repositoryService.deleteDeployment(deploymentId, false);
+
+    }
+
+    @Override
+    public String deploy(String exportDir, MultipartFile file,HttpServletRequest request) throws IOException {
+
+        String tenantId = request.getHeader("tenant-id");
+        StringBuilder message = new StringBuilder();
+        String fileName = file.getOriginalFilename();
+        InputStream fileInputStream = file.getInputStream();
+        Deployment deployment = null;
+        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
+        deploymentBuilder.tenantId(tenantId);
+        String extension = FilenameUtils.getExtension(fileName);
+        if (Constant.ACT_ZIP.equals(extension) || Constant.ACT_BAR.equals(extension)) {
+            ZipInputStream zip = new ZipInputStream(fileInputStream);
+            deployment = deploymentBuilder.addZipInputStream(zip).deploy();
+        } else if (Constant.ACT_PNG.equals(extension)) {
+            deployment = deploymentBuilder.addInputStream(fileName, fileInputStream).deploy();
+        } else if (fileName.indexOf(Constant.ACT_BPMN20) != -1) {
+            deployment = deploymentBuilder.addInputStream(fileName, fileInputStream).deploy();
+        } else if (Constant.ACT_BPMN.equals(extension)) {
+            deployment = deploymentBuilder.addInputStream(fileName, fileInputStream).deploy();
+        } else {
+            throw new CustomException(ExceptionCode.FILE_TYPE_ERROR);
+        }
+
+        List<ProcessDefinition> list =
+                repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
+
+        // 设置流程分类
+        for (ProcessDefinition processDefinition : list) {
+            repositoryService.setProcessDefinitionCategory(
+               processDefinition.getId(),
+               processDefinition.getCategory());
+            message.append("部署成功,流程ID:").append(processDefinition.getId());
+        }
+
+        if (list.size() == 0) {
+            throw new CustomException(ExceptionCode.ACTIVITI_DESIGN_ERROR);
+        }
+        return message.toString();
+    }
+
+    @Override
+    public Model convertToModel(String id,HttpServletRequest request) throws UnsupportedEncodingException, XMLStreamException {
+        String tenantId = request.getHeader("tenant-id");
+        ProcessDefinition processDefinition =
+                repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
+        InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
+                processDefinition.getResourceName());
+        XMLInputFactory xif = XMLInputFactory.newInstance();
+        InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
+        XMLStreamReader xtr = xif.createXMLStreamReader(in);
+        BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
+
+        BpmnJsonConverter converter = new BpmnJsonConverter();
+        ObjectNode modelNode = converter.convertToJson(bpmnModel);
+        Model modelData = repositoryService.newModel();
+        modelData.setKey(processDefinition.getKey());
+        modelData.setName(processDefinition.getResourceName());
+        modelData.setCategory(processDefinition.getCategory());
+        modelData.setDeploymentId(processDefinition.getDeploymentId());
+        modelData.setVersion(Integer
+                .parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count() + 1)));
+
+        ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
+        modelData.setMetaInfo(modelObjectNode.toString());
+        modelData.setTenantId(tenantId);
+        repositoryService.saveModel(modelData);
+
+        repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
+        return modelData;
+    }
+
+    @Override
+    public String updateState(int state, String id) {
+        String msg = "无操作";
+        if (state == Constant.ACT_ONE) {
+            try {
+                repositoryService.activateProcessDefinitionById(id, true, null);
+            } catch (Exception e) {
+                throw new CustomException(ExceptionCode.ACTIVITI_ACTIVATED);
+            }
+            msg = "已激活ID为[" + id + "]的流程定义。";
+        } else if (state == Constant.ACT_TWO) {
+            try {
+                repositoryService.suspendProcessDefinitionById(id, true, null);
+            } catch (Exception e) {
+                throw new CustomException(ExceptionCode.ACTIVITI_HANG_UP);
+            }
+            msg = "已挂起ID为[" + id + "]的流程定义。";
+        }
+        return msg;
+    }
+
+    @Override
+    public List<ReProcdefEntity> listActive(HttpServletRequest request) {
+//        String tenantId = request.getHeader("tenant-id");
+//        .processDefinitionTenantId(tenantId)
+        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
+                .latestVersion()
+                .orderByProcessDefinitionKey()
+                .asc();
+        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.active().list();
+        List<ReProcdefEntity> list = this.definitionToReprocess(processDefinitionList);
+        return list;
+    }
+
+    /**
+     * activti 流程转化成自定义流程
+     *
+     * @param processDefinitionList
+     * @return
+     */
+    private List<ReProcdefEntity> definitionToReprocess(List<ProcessDefinition> processDefinitionList) {
+        List<ReProcdefEntity> list = Lists.newArrayList();
+        for (ProcessDefinition processDefinition : processDefinitionList) {
+            ReProcdefEntity entity = new ReProcdefEntity();
+            String deploymentId = processDefinition.getDeploymentId();
+            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
+            entity.setId(processDefinition.getId());
+            entity.setKey(processDefinition.getKey());
+            entity.setName(deployment == null ? ""
+                    : StringUtils.isBlank(deployment.getName()) ? processDefinition.getName() : deployment.getName());
+            entity.setDeployTime(deployment == null ? null : deployment.getDeploymentTime());
+            entity.setDeploymentId(processDefinition.getDeploymentId());
+            entity.setSuspensionState(processDefinition.isSuspended() ? Constant.ACT_TWO : Constant.ACT_ONE);
+            entity.setResourceName(processDefinition.getResourceName());
+            entity.setDgrmResourceName(processDefinition.getDiagramResourceName());
+            entity.setCategory(processDefinition.getCategory());
+            entity.setVersion(processDefinition.getVersion());
+            entity.setDescription(processDefinition.getDescription());
+            entity.setEngineVersion(processDefinition.getVersion() + "");
+            entity.setTenantId(processDefinition.getTenantId());
+            list.add(entity);
+        }
+        return list;
+    }
+
+}

+ 159 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/controller/ApplyLeaveController.java

@@ -0,0 +1,159 @@
+package org.jeecg.modules.apply.controller;
+
+import java.util.Arrays;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.apply.entity.ApplyLeave;
+import org.jeecg.modules.apply.service.IApplyLeaveService;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.jeecg.common.aspect.annotation.AutoLog;
+
+ /**
+ * @Description: apply_leave
+ * @Author: jeecg-boot
+ * @Date:   2021-08-18
+ * @Version: V1.0
+ */
+@Api(tags="apply_leave")
+@RestController
+@RequestMapping("/apply/applyLeave")
+@Slf4j
+public class ApplyLeaveController extends JeecgController<ApplyLeave, IApplyLeaveService> {
+	@Autowired
+	private IApplyLeaveService applyLeaveService;
+	
+	/**
+	 * 分页列表查询
+	 *
+	 * @param applyLeave
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	@AutoLog(value = "apply_leave-分页列表查询")
+	@ApiOperation(value="apply_leave-分页列表查询", notes="apply_leave-分页列表查询")
+	@GetMapping(value = "/list")
+	public Result<?> queryPageList(ApplyLeave applyLeave,
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+		QueryWrapper<ApplyLeave> queryWrapper = QueryGenerator.initQueryWrapper(applyLeave, req.getParameterMap());
+		Page<ApplyLeave> page = new Page<ApplyLeave>(pageNo, pageSize);
+		IPage<ApplyLeave> pageList = applyLeaveService.page(page, queryWrapper);
+		return Result.OK(pageList);
+	}
+	
+	/**
+	 *   添加
+	 *
+	 * @param applyLeave
+	 * @return
+	 */
+	@AutoLog(value = "apply_leave-添加")
+	@ApiOperation(value="apply_leave-添加", notes="apply_leave-添加")
+	@PostMapping(value = "/add")
+	public Result<?> add(@RequestBody ApplyLeave applyLeave) {
+
+		boolean b = applyLeaveService.saveLeave(applyLeave);
+
+		return Result.OK("添加成功!");
+	}
+	
+	/**
+	 *  编辑
+	 *
+	 * @param applyLeave
+	 * @return
+	 */
+	@AutoLog(value = "apply_leave-编辑")
+	@ApiOperation(value="apply_leave-编辑", notes="apply_leave-编辑")
+	@PutMapping(value = "/edit")
+	public Result<?> edit(@RequestBody ApplyLeave applyLeave) {
+		applyLeaveService.updateById(applyLeave);
+		return Result.OK("编辑成功!");
+	}
+	
+	/**
+	 *   通过id删除
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "apply_leave-通过id删除")
+	@ApiOperation(value="apply_leave-通过id删除", notes="apply_leave-通过id删除")
+	@DeleteMapping(value = "/delete")
+	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
+		applyLeaveService.removeById(id);
+		return Result.OK("删除成功!");
+	}
+	
+	/**
+	 *  批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "apply_leave-批量删除")
+	@ApiOperation(value="apply_leave-批量删除", notes="apply_leave-批量删除")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.applyLeaveService.removeByIds(Arrays.asList(ids.split(",")));
+		return Result.OK("批量删除成功!");
+	}
+	
+	/**
+	 * 通过id查询
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "apply_leave-通过id查询")
+	@ApiOperation(value="apply_leave-通过id查询", notes="apply_leave-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
+		ApplyLeave applyLeave = applyLeaveService.getById(id);
+		if(applyLeave==null) {
+			return Result.error("未找到对应数据");
+		}
+		return Result.OK(applyLeave);
+	}
+
+    /**
+    * 导出excel
+    *
+    * @param request
+    * @param applyLeave
+    */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, ApplyLeave applyLeave) {
+        return super.exportXls(request, applyLeave, ApplyLeave.class, "apply_leave");
+    }
+
+    /**
+      * 通过excel导入数据
+    *
+    * @param request
+    * @param response
+    * @return
+    */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        return super.importExcel(request, response, ApplyLeave.class);
+    }
+
+}

+ 64 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/entity/ApplyLeave.java

@@ -0,0 +1,64 @@
+package org.jeecg.modules.apply.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.jeecg.common.base.entity.BaseTaskEntity;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.jeecg.common.aspect.annotation.Dict;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @Description: apply_leave
+ * @Author: jeecg-boot
+ * @Date:   2021-08-18
+ * @Version: V1.0
+ */
+@Data
+@TableName("apply_leave")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="apply_leave对象", description="apply_leave")
+public class ApplyLeave extends BaseTaskEntity{
+
+
+   /**部门名称*/
+   @Excel(name = "部门名称")
+   @ApiModelProperty(value = "部门名称")
+   private String deptName;
+
+   /**是否删除*/
+   @Excel(name = "是否删除")
+   @ApiModelProperty(value = "是否删除")
+   @TableField(fill = FieldFill.INSERT)
+   private String delFlag;
+   /**天数*/
+   @Excel(name = "天数")
+   @ApiModelProperty(value = "天数")
+   private Integer total;
+
+   /**创建人*/
+   @ApiModelProperty(value = "创建人")
+   private String createBy;
+   /**创建时间 */
+   @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+   @DateTimeFormat(pattern="yyyy-MM-dd")
+   @ApiModelProperty(value = "创建时间 ")
+   private Date createTime;
+   /**更新人*/
+   @ApiModelProperty(value = "更新人")
+   private String updateBy;
+   /**更新时间*/
+   @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+   @DateTimeFormat(pattern="yyyy-MM-dd")
+   @ApiModelProperty(value = "更新时间")
+   private Date updateTime;
+
+}

+ 27 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/ContactResultListener.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.apply.lisener;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.delegate.ExecutionListener;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.modules.apply.service.ApplyProcessService;
+
+/**
+ * 更改工作联系单主表
+ * 监听:审批结束,更改表单状态和审批状态,保存审批记录
+ * @Author: yll
+ * @Date: 2019/7/23 18:34
+ */
+
+public class ContactResultListener implements ExecutionListener {
+
+    @Override
+    public void notify(DelegateExecution delegateExecution) {
+
+        if (!"end".equals(delegateExecution.getEventName())) {
+            return;
+        }
+        ApplyProcessService processService = SpringContextUtils.getBean(ApplyProcessService.class);
+        processService.updateContactProcessResult(delegateExecution);
+    }
+
+}

+ 73 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/CustomEventListener.java

@@ -0,0 +1,73 @@
+package org.jeecg.modules.apply.lisener;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.engine.RepositoryService;
+import org.activiti.engine.delegate.event.ActivitiEntityEvent;
+import org.activiti.engine.delegate.event.ActivitiEvent;
+import org.activiti.engine.delegate.event.ActivitiEventListener;
+import org.activiti.engine.delegate.event.ActivitiEventType;
+import org.activiti.engine.impl.persistence.entity.TaskEntity;
+import org.jeecg.common.Constant;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.common.utils.StringUtils;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.service.ApprovalService;
+
+import org.springframework.stereotype.Component;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 全局事件监听
+ * <p>
+ * Create by YLL on 2020/1/2
+ */
+@Component
+@Slf4j
+public class CustomEventListener implements ActivitiEventListener, Serializable {
+    @Override
+    public void onEvent(ActivitiEvent event) {
+
+//         TODO: 2020/4/15 这段代码发布时需要注释掉!!
+        //测试,将所有流程审核人设成admin;
+//        if (event.getType().equals(ActivitiEventType.TASK_ASSIGNED)) {
+//            ActivitiEntityEvent entityEvent = (ActivitiEntityEvent) event;
+//            TaskEntity entity = (TaskEntity) entityEvent.getEntity();
+//            entity.setAssignee("e9ca23d68d884d4ebb19d07889727dae");
+//        }
+
+        if (event.getType().equals(ActivitiEventType.TASK_CREATED)) {
+            ActivitiEntityEvent entityEvent = (ActivitiEntityEvent) event;
+            TaskEntity entity = (TaskEntity) entityEvent.getEntity();
+
+            RepositoryService repositoryService = SpringContextUtils.getBean(RepositoryService.class);
+            Set<String> userIds = new HashSet<>();
+
+            //是否自己指定的办理人
+            Object opinionObject = entity.getVariable(Constant.ACT_APPLY_OPINION_LIST);
+            if (opinionObject != null) {
+                List<ApprovalOpinionDTO> approvalOpinionDTOS = JSONObject.parseArray(opinionObject.toString(), ApprovalOpinionDTO.class);
+                ApprovalOpinionDTO approvalOpinionDTO = approvalOpinionDTOS.get(approvalOpinionDTOS.size() - 1);
+                if (Constant.YES.equals(approvalOpinionDTO.getDefNextAssignee()) && approvalOpinionDTO.getNextAssignee() != null) {
+                    entity.setAssignee(approvalOpinionDTO.getNextAssignee().getId());
+                }
+            }
+
+            if (StringUtils.isNotEmpty(entity.getAssignee())) {
+                userIds.add(entity.getAssignee());
+            } else if (StringUtils.isNotEmpty(entity.getCandidates())) {
+                ApprovalService approvalService = SpringContextUtils.getBean(ApprovalService.class);
+                userIds = approvalService.getCandiates(entity.getId());
+            }
+        }
+    }
+
+    @Override
+    public boolean isFailOnException() {
+        return false;
+    }
+}

+ 27 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/ProblemResultListener.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.apply.lisener;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.delegate.ExecutionListener;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.modules.apply.service.ApplyProcessService;
+
+/**
+ * 问题跟追
+ * 监听:审批结束,更改表单状态和审批状态,保存审批记录
+ * @Author: yll
+ * @Date: 2019/7/23 18:34
+ */
+
+public class ProblemResultListener implements ExecutionListener {
+
+    @Override
+    public void notify(DelegateExecution delegateExecution) {
+
+        if (!"end".equals(delegateExecution.getEventName())) {
+            return;
+        }
+        ApplyProcessService processService = SpringContextUtils.getBean(ApplyProcessService.class);
+        processService.updateProblemProcessResult(delegateExecution);
+    }
+
+}

+ 27 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/lisener/ProcessResultListener.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.apply.lisener;
+
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.delegate.ExecutionListener;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.modules.apply.service.ApplyProcessService;
+
+/**
+ * 监听:审批结束,更改表单状态和审批状态,保存审批记录
+ * @Author: yll
+ * @Date: 2019/7/23 18:34
+ */
+
+public class ProcessResultListener implements ExecutionListener {
+
+    @Override
+    public void notify(DelegateExecution delegateExecution) {
+
+        if (!"end".equals(delegateExecution.getEventName())) {
+            return;
+        }
+        ApplyProcessService processService = SpringContextUtils.getBean(ApplyProcessService.class);
+
+        processService.updateProcessResult(delegateExecution);
+    }
+
+}

+ 14 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/ApplyLeaveMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.apply.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.apply.entity.ApplyLeave;
+
+/**
+ * @Description: apply_leave
+ * @Author: jeecg-boot
+ * @Date:   2021-08-18
+ * @Version: V1.0
+ */
+public interface ApplyLeaveMapper extends BaseMapper<ApplyLeave> {
+
+}

+ 39 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/ApplyProcessMapper.java

@@ -0,0 +1,39 @@
+package org.jeecg.modules.apply.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.common.base.entity.BaseTaskEntity;
+
+import java.util.Date;
+
+/**
+ * @Author: yll
+ * @Date: 2019/7/24 11:07
+ */
+@Mapper
+public interface ApplyProcessMapper extends BaseMapper<BaseTaskEntity> {
+
+    int updateProcessResult(@Param("tableName") String tableName,
+                             @Param("id") String id,
+                             @Param("applyStatus") String applyStatus,
+                             @Param("result") String result,
+                             @Param("completeTime") Date completeTime,
+                             @Param("opinionStr") String opinionStr);
+
+    int updateContactProcessResult(@Param("tableName") String tableName,
+                            @Param("id") String id,
+                            @Param("state") int state,
+                            @Param("applyStatus") String applyStatus,
+                            @Param("result") String result,
+                            @Param("completeTime") Date completeTime,
+                            @Param("opinionStr") String opinionStr);
+
+    /**
+     * 根据问题状态修改主表状态
+     * @param state
+     * @param id
+     * @return
+     */
+    int updateContactState(@Param("state") int state,  @Param("id") String id);
+}

+ 5 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/xml/mysql/ApplyLeaveMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.apply.mapper.ApplyLeaveMapper">
+
+</mapper>

+ 58 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/xml/mysql/ApplyProcessMapper.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.apply.mapper.ApplyProcessMapper">
+
+    <resultMap type="org.jeecg.common.base.entity.BaseTaskEntity" id="BaseResult">
+<!--        <result property="tenantId" column="tenant_id" jdbcType="VARCHAR"/>-->
+        <result property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="deptId" column="dept_id" jdbcType="VARCHAR"/>
+        <result property="processKey" column="process_key" jdbcType="VARCHAR"/>
+        <result property="processInstanceId" column="process_instance_id" jdbcType="VARCHAR"/>
+        <result property="processInstanceName" column="process_instance_name" jdbcType="VARCHAR"/>
+        <result property="userId" column="user_id" jdbcType="VARCHAR"/>
+        <result property="userName" column="user_name" jdbcType="VARCHAR"/>
+        <result property="remarks" column="remarks" jdbcType="VARCHAR"/>
+<!--        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>-->
+<!--        <result property="createBy" column="create_by" jdbcType="VARCHAR"/>-->
+<!--        <result property="modifyBy" column="modify_by" jdbcType="VARCHAR"/>-->
+<!--        <result property="modifyTime" column="modify_time" jdbcType="TIMESTAMP"/>-->
+<!--        <result property="delFlag" column="del_flag" jdbcType="INTEGER"/>-->
+    </resultMap>
+
+    <update id="updateProcessResult">
+        update ${tableName}
+        set apply_status = #{applyStatus},
+        result = #{result},
+        complete_time = #{completeTime}
+        <if test="opinionStr != '' and opinionStr != null">
+            , opinion_str = #{opinionStr}
+        </if>
+        where
+        id = #{id}
+    </update>
+
+    <update id="updateContactProcessResult">
+        update ${tableName}
+        set apply_status = #{applyStatus},
+        state = #{state},
+        result = #{result},
+        complete_time = #{completeTime}
+        <if test="opinionStr != '' and opinionStr != null">
+            , opinion_str = #{opinionStr}
+        </if>
+        where
+        id = #{id}
+    </update>
+
+    <update id="updateContactState">
+        update zshb_contact
+        set state = #{state}
+        where
+        id = #{id}
+        and
+        (select count(0) from zshb_contact_problem  WHERE PARENT_ID = #{id})
+	    =
+        (select count(0) from zshb_contact_problem  WHERE PARENT_ID = #{id} and STATE =#{state})
+    </update>
+
+</mapper>

+ 47 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/mapper/xml/oracle/ApplyProcessMapper.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.apply.mapper.ApplyProcessMapper">
+
+    <resultMap type="org.jeecg.common.base.entity.BaseTaskEntity" id="BaseResult">
+<!--        <result property="tenantId" column="tenant_id" jdbcType="VARCHAR"/>-->
+        <result property="id" column="id" jdbcType="VARCHAR"/>
+        <result property="deptId" column="dept_id" jdbcType="VARCHAR"/>
+        <result property="processKey" column="process_key" jdbcType="VARCHAR"/>
+        <result property="processInstanceId" column="process_instance_id" jdbcType="VARCHAR"/>
+        <result property="processInstanceName" column="process_instance_name" jdbcType="VARCHAR"/>
+        <result property="userId" column="user_id" jdbcType="VARCHAR"/>
+        <result property="userName" column="user_name" jdbcType="VARCHAR"/>
+        <result property="remarks" column="remarks" jdbcType="VARCHAR"/>
+<!--        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>-->
+<!--        <result property="createBy" column="create_by" jdbcType="VARCHAR"/>-->
+<!--        <result property="modifyBy" column="modify_by" jdbcType="VARCHAR"/>-->
+<!--        <result property="modifyTime" column="modify_time" jdbcType="TIMESTAMP"/>-->
+<!--        <result property="delFlag" column="del_flag" jdbcType="INTEGER"/>-->
+    </resultMap>
+
+    <update id="updateProcessResult">
+        update ${tableName}
+        set apply_status = #{applyStatus},
+        result = #{result},
+        complete_time = #{completeTime}
+        <if test="opinionStr != '' and opinionStr != null">
+            , opinion_str = #{opinionStr}
+        </if>
+        where
+        id = #{id}
+    </update>
+
+    <update id="updateContactProcessResult">
+        update ${tableName}
+        set apply_status = #{applyStatus},
+        state = #{state},
+        result = #{result},
+        complete_time = #{completeTime}
+        <if test="opinionStr != '' and opinionStr != null">
+            , opinion_str = #{opinionStr}
+        </if>
+        where
+        id = #{id}
+    </update>
+
+</mapper>

+ 40 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/ApplyProcessService.java

@@ -0,0 +1,40 @@
+package org.jeecg.modules.apply.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.delegate.DelegateTask;
+import org.jeecg.common.base.entity.BaseTaskEntity;
+
+/**
+ * 流程信息
+ *
+ * @Author: yll
+ * @Date: 2019/7/24 11:02
+ */
+public interface ApplyProcessService extends IService<BaseTaskEntity> {
+    /**
+     * 跟新审批结果
+     *
+     * @param delegateExecution
+     * @return
+     */
+    void updateProcessResult(DelegateExecution delegateExecution);
+
+    /**
+     * 跟新工作联系单审批结果
+     *
+     * @param delegateExecution
+     * @return
+     */
+    void updateContactProcessResult(DelegateExecution delegateExecution);
+
+    /**
+     * 跟新问题回复审批结果
+     *
+     * @param delegateExecution
+     * @return
+     */
+    void updateProblemProcessResult(DelegateExecution delegateExecution);
+
+
+}

+ 17 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/IApplyLeaveService.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.apply.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.apply.entity.ApplyLeave;
+
+/**
+ * @Description: apply_leave
+ * @Author: jeecg-boot
+ * @Date:   2021-08-18
+ * @Version: V1.0
+ */
+public interface IApplyLeaveService extends IService<ApplyLeave> {
+
+
+   boolean saveLeave (ApplyLeave applyLeave);
+
+}

+ 76 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/impl/ApplyLeaveServiceImpl.java

@@ -0,0 +1,76 @@
+package org.jeecg.modules.apply.service.impl;
+
+import org.activiti.engine.runtime.ProcessInstance;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.Constant;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.system.vo.SysDepartModel;
+import org.jeecg.common.utils.DictEnum;
+import org.jeecg.modules.apply.entity.ApplyLeave;
+import org.jeecg.modules.apply.mapper.ApplyLeaveMapper;
+import org.jeecg.modules.apply.service.IApplyLeaveService;
+import org.jeecg.modules.applyForm.entity.ApplyForm;
+import org.jeecg.modules.applyForm.service.IApplyFormService;
+import org.jeecg.modules.approval.model.vo.ApprovalVO;
+import org.jeecg.modules.approval.service.ApprovalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: apply_leave
+ * @Author: jeecg-boot
+ * @Date:   2021-08-18
+ * @Version: V1.0
+ */
+@Service
+public class ApplyLeaveServiceImpl extends ServiceImpl<ApplyLeaveMapper, ApplyLeave> implements IApplyLeaveService {
+
+   @Autowired
+   private ApprovalService approvalService;
+   @Autowired
+   private ISysBaseAPI iSysBaseAPI;
+   @Autowired
+   private IApplyFormService applyFormService;
+
+   @Override
+   public boolean saveLeave(ApplyLeave applyLeave) {
+
+      //据request中的token获取用户账号
+      //String userName = JwtUtil.getUserNameByToken(request);
+      //直接获取当前用户不适用前端token
+      LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+      //获取部门信息
+      SysDepartModel sysDepartModel = (SysDepartModel) iSysBaseAPI.getAllSysDepart().stream()
+              .filter(s -> s.getId().equals(iSysBaseAPI.getDepartIdsByOrgCode(loginUser.getOrgCode()))).collect(Collectors.toList());
+
+     // applyLeave.setId(IdWorker.getIdStr());
+      applyLeave.setUserId(loginUser.getId());
+      applyLeave.setUserName(loginUser.getRealname());
+      applyLeave.setDeptId(sysDepartModel.getId());
+      applyLeave.setDeptName(sysDepartModel.getDepartName());
+      //DictEnum.FORMKEY_APPLY.getKey() 获取表单key
+      applyLeave.setFormKey(DictEnum.FORMKEY_APPLY.getKey());
+      //获取流程 获取已启用的流程
+      ApplyForm formByFormKey = applyFormService.getAppleyFormByFormKey(DictEnum.FORMKEY_APPLY.getKey());
+      applyLeave.setProcessKey(formByFormKey.getProcessKey());
+      applyLeave.setApplyStatus(DictEnum.APPLY_STATUS_PROCESSING.getKey());
+      //添加流转条件
+      Map<String, Object> map = new HashMap<>();
+      map.put(Constant.ACT_FLOW_TOTAL, applyLeave.getTotal());
+      applyLeave.setParam(map);
+      // 发起审批流程
+      ProcessInstance processInstance = approvalService.addApproval(new ApprovalVO<ApplyLeave>(applyLeave));
+      applyLeave.setProcessInstanceId(processInstance.getId());
+      applyLeave.setProcessInstanceName(processInstance.getName());
+      boolean result = save(applyLeave);
+
+      return result;
+   }
+}

+ 157 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/apply/service/impl/ApplyProcessServiceImpl.java

@@ -0,0 +1,157 @@
+package org.jeecg.modules.apply.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.jeecg.common.Constant;
+import org.jeecg.common.base.entity.BaseTaskEntity;
+import org.jeecg.common.exception.CustomException;
+import org.jeecg.common.util.DateUtils;
+import org.jeecg.common.utils.DictEnum;
+import org.jeecg.modules.apply.mapper.ApplyProcessMapper;
+import org.jeecg.modules.apply.service.ApplyProcessService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @Author: yll
+ * @Date: 2019/7/24 11:06
+ */
+@Service
+@Slf4j
+public class ApplyProcessServiceImpl extends ServiceImpl<ApplyProcessMapper, BaseTaskEntity> implements ApplyProcessService {
+
+    @Autowired
+    private ApplyProcessMapper applyProcessMapper;
+
+
+    @Override
+    public void updateProcessResult(DelegateExecution delegateExecution) {
+        try {
+            Object variable = delegateExecution.getVariable(Constant.ACT_BASE_TASK);
+            BaseTaskEntity taskEntity = JSONObject.parseObject(variable.toString(), BaseTaskEntity.class);
+
+            String opinionStr = delegateExecution.getVariable(Constant.ACT_APPLY_OPINION_LIST).toString();
+            String tableName = taskEntity.getFormKey();
+
+            //审批最终结果
+            Object flagObj = delegateExecution.getVariable(Constant.ACT_TASK_FLAG);
+
+            String flag = "";
+            String result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            if (null == flagObj) {
+                result = DictEnum.APPLY_RESULT_CANCEL.getKey();
+            } else {
+                flag = flagObj.toString();
+            }
+
+            if (DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey().equals(flag)) {
+                //拒绝
+                result = DictEnum.APPLY_RESULT_REFUSE.getKey();
+            }
+            if (DictEnum.Apply_APPROVAL_OPINION_AGREE.getKey().equals(flag)) {
+                //同意
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+//            if (DictEnum.APPLY_APPROVAL_OPINION_ABANDON.getKey().equals(flag)) {
+//                //取消申请
+//                result = DictEnum.APPLY_RESULT_CANCEL.getKey();
+//            }
+            if ( DictEnum.APPLY_APPROVAL_OPINION_CONFIRM.getKey().equals(flag)) {
+                //确认即为审批通过
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+
+            applyProcessMapper.updateProcessResult(tableName, taskEntity.getId(), DictEnum.APPLY_STATUS_FINISH.getKey(), result, DateUtils.getDate(), opinionStr);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new CustomException("保存审批结果失败!", e);
+        }
+    }
+
+    @Override
+    public void updateContactProcessResult(DelegateExecution delegateExecution) {
+        try {
+            Object variable = delegateExecution.getVariable(Constant.ACT_BASE_TASK);
+            BaseTaskEntity taskEntity = JSONObject.parseObject(variable.toString(), BaseTaskEntity.class);
+
+            String opinionStr = delegateExecution.getVariable(Constant.ACT_APPLY_OPINION_LIST).toString();
+            String tableName = taskEntity.getFormKey();
+
+            //审批最终结果
+            Object flagObj = delegateExecution.getVariable(Constant.ACT_TASK_FLAG);
+
+            String flag = "";
+            String result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            if (null == flagObj) {
+                result = DictEnum.APPLY_RESULT_CANCEL.getKey();
+            } else {
+                flag = flagObj.toString();
+            }
+
+            if (DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey().equals(flag)) {
+                //拒绝
+                result = DictEnum.APPLY_RESULT_REFUSE.getKey();
+            }
+            if (DictEnum.Apply_APPROVAL_OPINION_AGREE.getKey().equals(flag)) {
+                //同意
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+
+            if ( DictEnum.APPLY_APPROVAL_OPINION_CONFIRM.getKey().equals(flag)) {
+                //确认即为审批通过
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+
+            applyProcessMapper.updateContactProcessResult(tableName, taskEntity.getId(),2,DictEnum.APPLY_STATUS_FINISH.getKey(), result, DateUtils.getDate(), opinionStr);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new CustomException("保存审批结果失败!", e);
+        }
+    }
+
+    @Override
+    public void updateProblemProcessResult(DelegateExecution delegateExecution) {
+        try {
+            Object variable = delegateExecution.getVariable(Constant.ACT_BASE_TASK);
+            BaseTaskEntity taskEntity = JSONObject.parseObject(variable.toString(), BaseTaskEntity.class);
+
+            String opinionStr = delegateExecution.getVariable(Constant.ACT_APPLY_OPINION_LIST).toString();
+            String tableName = taskEntity.getFormKey();
+
+            //审批最终结果
+            Object flagObj = delegateExecution.getVariable(Constant.ACT_TASK_FLAG);
+
+            String flag = "";
+            String result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            if (null == flagObj) {
+                result = DictEnum.APPLY_RESULT_CANCEL.getKey();
+            } else {
+                flag = flagObj.toString();
+            }
+            if (DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey().equals(flag)) {
+                //拒绝
+                result = DictEnum.APPLY_RESULT_REFUSE.getKey();
+            }
+            if (DictEnum.Apply_APPROVAL_OPINION_AGREE.getKey().equals(flag)) {
+                //同意
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+            if ( DictEnum.APPLY_APPROVAL_OPINION_CONFIRM.getKey().equals(flag)) {
+                //确认即为审批通过
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+            applyProcessMapper.updateContactProcessResult(tableName, taskEntity.getId(),3,DictEnum.APPLY_STATUS_FINISH.getKey(), result, DateUtils.getDate(), opinionStr);
+            //判断明细是否都审核
+            Map<String, Object> param = taskEntity.getParam();
+            applyProcessMapper.updateContactState(3,param.get("parentId").toString());
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new CustomException("保存审批结果失败!", e);
+        }
+    }
+
+}

+ 170 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/controller/ApplyFormController.java

@@ -0,0 +1,170 @@
+package org.jeecg.modules.applyForm.controller;
+
+import java.util.Arrays;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.utils.DictEnum;
+import org.jeecg.common.utils.DictModelConstant;
+import org.jeecg.modules.applyForm.entity.ApplyForm;
+import org.jeecg.modules.applyForm.service.IApplyFormService;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.jeecg.common.aspect.annotation.AutoLog;
+
+ /**
+ * @Description: apply_form
+ * @Author: jeecg-boot
+ * @Date:   2021-08-23
+ * @Version: V1.0
+ */
+@Api(tags="apply_form")
+@RestController
+@RequestMapping("/applyform")
+@Slf4j
+public class ApplyFormController extends JeecgController<ApplyForm, IApplyFormService> {
+	@Autowired
+	private IApplyFormService applyFormService;
+	
+	/**
+	 * 分页列表查询
+	 *
+	 * @param applyForm
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	@AutoLog(value = "apply_form-分页列表查询")
+	@ApiOperation(value="apply_form-分页列表查询", notes="apply_form-分页列表查询")
+	@GetMapping(value = "/list")
+	public Result<?> queryPageList(ApplyForm applyForm,
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+		QueryWrapper<ApplyForm> queryWrapper = QueryGenerator.initQueryWrapper(applyForm, req.getParameterMap());
+		Page<ApplyForm> page = new Page<ApplyForm>(pageNo, pageSize);
+		IPage<ApplyForm> pageList = applyFormService.page(page, queryWrapper);
+		return Result.OK(pageList);
+	}
+
+	 /**
+	  *  获取表单keys
+	  */
+	 @AutoLog(value = "apply_form-获取表单keys")
+	 @ApiOperation(value="apply_form-获取表单keys", notes="apply_form-获取表单keys")
+	 @GetMapping(value = "/formKeys")
+	 public Result<?> listFormKeys() {
+		 return Result.OK(DictEnum.getDictVOList(DictModelConstant.MODEL_APPLY_CONFIG, DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY));
+	 }
+
+
+	/**
+	 *   添加
+	 *
+	 * @param applyForm
+	 * @return
+	 */
+	@AutoLog(value = "apply_form-添加")
+	@ApiOperation(value="apply_form-添加", notes="apply_form-添加")
+	@PostMapping(value = "/add")
+	public Result<?> add(@RequestBody ApplyForm applyForm) {
+		applyFormService.save(applyForm);
+		return Result.OK("添加成功!");
+	}
+	
+	/**
+	 *  编辑
+	 *
+	 * @param applyForm
+	 * @return
+	 */
+	@AutoLog(value = "apply_form-编辑")
+	@ApiOperation(value="apply_form-编辑", notes="apply_form-编辑")
+	@PutMapping(value = "/edit")
+	public Result<?> edit(@RequestBody ApplyForm applyForm) {
+		applyFormService.updateById(applyForm);
+		return Result.OK("编辑成功!");
+	}
+	
+	/**
+	 *   通过id删除
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "apply_form-通过id删除")
+	@ApiOperation(value="apply_form-通过id删除", notes="apply_form-通过id删除")
+	@DeleteMapping(value = "/delete")
+	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
+		applyFormService.removeById(id);
+		return Result.OK("删除成功!");
+	}
+	
+	/**
+	 *  批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "apply_form-批量删除")
+	@ApiOperation(value="apply_form-批量删除", notes="apply_form-批量删除")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.applyFormService.removeByIds(Arrays.asList(ids.split(",")));
+		return Result.OK("批量删除成功!");
+	}
+	
+	/**
+	 * 通过id查询
+	 *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "apply_form-通过id查询")
+	@ApiOperation(value="apply_form-通过id查询", notes="apply_form-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
+		ApplyForm applyForm = applyFormService.getById(id);
+		if(applyForm == null) {
+			return Result.error("未找到对应数据");
+		}
+		return Result.OK(applyForm);
+	}
+
+    /**
+    * 导出excel
+    *
+    * @param request
+    * @param applyForm
+    */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, ApplyForm applyForm) {
+        return super.exportXls(request, applyForm, ApplyForm.class, "apply_form");
+    }
+
+    /**
+      * 通过excel导入数据
+    *
+    * @param request
+    * @param response
+    * @return
+    */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        return super.importExcel(request, response, ApplyForm.class);
+    }
+
+ }

+ 79 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/entity/ApplyForm.java

@@ -0,0 +1,79 @@
+package org.jeecg.modules.applyForm.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @Description: apply_form
+ * @Author: jeecg-boot
+ * @Date:   2021-08-23
+ * @Version: V1.0
+ */
+@Data
+@TableName("act_form")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="apply_form对象", description="apply_form")
+public class ApplyForm implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "主键")
+    private String id;
+	/**名称*/
+	@Excel(name = "名称", width = 15)
+    @ApiModelProperty(value = "名称")
+    private String name;
+	/**图标*/
+	@Excel(name = "图标", width = 15)
+    @ApiModelProperty(value = "图标")
+    private String icon;
+	/**绑定流程key*/
+	@Excel(name = "绑定流程key", width = 15)
+    @ApiModelProperty(value = "绑定流程key")
+    private String processKey;
+	/**绑定表单key*/
+	@Excel(name = "绑定表单key", width = 15)
+    @ApiModelProperty(value = "绑定表单key")
+    private String formKey;
+	/**启用状态*/
+	@Excel(name = "启用状态", width = 15)
+    @ApiModelProperty(value = "启用状态")
+    private String status;
+	/**选择使用范围*/
+	@Excel(name = "选择使用范围", width = 15)
+    @ApiModelProperty(value = "选择使用范围")
+    private String rangeuse;
+	/**创建人*/
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+	/**创建时间*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+	/**更新人*/
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+	/**更新时间*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "更新时间")
+    private Date updateTime;
+	/**删除状态(0-正常,1-已删除)*/
+	@Excel(name = "删除状态(0-正常,1-已删除)", width = 15)
+    @ApiModelProperty(value = "删除状态(0-正常,1-已删除)")
+      @TableField(fill = FieldFill.INSERT)
+      private String delFlag;
+}

+ 14 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/mapper/ApplyFormMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.applyForm.mapper;
+
+import org.jeecg.modules.applyForm.entity.ApplyForm;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * @Description: apply_form
+ * @Author: jeecg-boot
+ * @Date:   2021-08-23
+ * @Version: V1.0
+ */
+public interface ApplyFormMapper extends BaseMapper<ApplyForm> {
+
+}

+ 5 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/mapper/xml/ApplyFormMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.demo.applyform.mapper.ApplyFormMapper">
+
+</mapper>

+ 19 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/service/IApplyFormService.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.applyForm.service;
+
+import org.jeecg.modules.applyForm.entity.ApplyForm;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @Description: apply_form
+ * @Author: jeecg-boot
+ * @Date:   2021-08-23
+ * @Version: V1.0
+ */
+public interface IApplyFormService extends IService<ApplyForm> {
+
+   /**
+    * 通过表单key查询启用的流程key
+    */
+   ApplyForm getAppleyFormByFormKey(String formKey);
+
+}

+ 31 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/applyForm/service/impl/ApplyFormServiceImpl.java

@@ -0,0 +1,31 @@
+package org.jeecg.modules.applyForm.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.jeecg.common.utils.StringUtils;
+import org.jeecg.modules.applyForm.entity.ApplyForm;
+import org.jeecg.modules.applyForm.mapper.ApplyFormMapper;
+import org.jeecg.modules.applyForm.service.IApplyFormService;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * @Description: apply_form
+ * @Author: jeecg-boot
+ * @Date:   2021-08-23
+ * @Version: V1.0
+ */
+@Service
+public class ApplyFormServiceImpl extends ServiceImpl<ApplyFormMapper, ApplyForm> implements IApplyFormService {
+
+   @Override
+   public ApplyForm getAppleyFormByFormKey(String formKey) {
+
+      LambdaQueryWrapper<ApplyForm> wa = new LambdaQueryWrapper<>();
+      wa.eq(StringUtils.isNotEmpty(formKey), ApplyForm::getFormKey,formKey)
+      .eq(ApplyForm::getStatus,1);
+      ApplyForm applyForm = getOne(wa);
+
+      return applyForm;
+   }
+}

+ 83 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/controller/ApprovalController.java

@@ -0,0 +1,83 @@
+package org.jeecg.modules.approval.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.model.dto.DynamicFormConf;
+import org.jeecg.modules.approval.model.vo.ApprovalOpinionVO;
+import org.jeecg.modules.approval.service.ApprovalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 申请管理
+ *
+ * @author yao.sun
+ * @data 2018/06/04
+ */
+@RestController
+@Slf4j
+@RequestMapping("/approval")
+public class ApprovalController {
+
+    @Autowired
+    private ApprovalService approvalService;
+
+    /**
+     * 流程环节审批信息
+     */
+    @GetMapping("/detail")
+    public Result detail(@RequestParam String processId) {
+        List<ApprovalOpinionDTO> list = approvalService.listApprovalDetail(processId);
+        return Result.OK(list);
+    }
+
+    /**
+     * 流程审批
+     */
+    @PostMapping("/handle")
+    public Result handleApproval(@RequestBody ApprovalOpinionVO approvalOpinionVO) {
+        boolean success = approvalService.handleApproval(approvalOpinionVO);
+        return success ? Result.OK() : Result.error("审批失败");
+    }
+
+    /**
+     * 获取流程状态(能否撤销,能否修改)
+     * pid 实例id
+     * tid 任务id
+     */
+    @GetMapping("/getProcessStatus")
+    public Result getProcessStatus(@RequestParam String processInstanceId) {
+        Map map = approvalService.getProcessStatus(processInstanceId);
+        return Result.OK(map);
+    }
+
+    /**
+     * 撤销申请
+     *
+     * @param processId
+     * @return
+     */
+    @GetMapping("/withdraw")
+    public Result withdraw(@RequestParam String processId) {
+        boolean flag = approvalService.withdrawProcess(processId);
+        return Result.OK(true);
+    }
+
+    /**
+     * 根据任务id获取动态表单属性配置
+     *
+     * @param taskId
+     * @return
+     */
+    @GetMapping("/taskDynamicConf")
+    public Result taskDynamicParams(@RequestParam String taskId) {
+        DynamicFormConf dynamicFormConf = approvalService.taskDynamicParams(taskId);
+        return Result.OK(dynamicFormConf);
+    }
+
+
+}

+ 126 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/controller/ApprovalTaskController.java

@@ -0,0 +1,126 @@
+package org.jeecg.modules.approval.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.model.vo.TaskVO;
+import org.jeecg.modules.approval.service.ApprovalTaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 任务控制层
+ *
+ * @Author: len.sun
+ * @Date: 2019/6/15
+ */
+@Slf4j
+@RestController
+@RequestMapping("/approval/task")
+public class ApprovalTaskController {
+
+    @Autowired
+    private ApprovalTaskService approvalTaskService;
+
+
+
+    /**
+     * 待处理任务列表
+     */
+    @GetMapping("/list")
+    public Result list(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+                       HttpServletRequest req) {
+
+        IPage page = approvalTaskService.listMyTask( pageNo, pageSize,req);
+        return Result.OK(page);
+    }
+
+    /**
+     * 已处理任务列表
+     */
+    @GetMapping("/list/processed")
+    public Result listProcessed(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                                @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+                                HttpServletRequest req) {
+
+        return Result.OK(approvalTaskService.listMyProcessedTask(pageNo, pageSize,req));
+    }
+
+    /**
+     * 任务明细
+     *
+     * @param taskId
+     * @return
+     */
+    @GetMapping("detail/{id}")
+    public Result agent(@PathVariable("id") String taskId) {
+        return Result.OK(approvalTaskService.getTask(taskId));
+    }
+
+    /**
+     * 获取流程图片
+     *
+     * @param processId
+     * @param response
+     */
+    @RequestMapping("processImg/{processId}")
+    public void viewProcessImg(@PathVariable String processId, HttpServletResponse response) {
+        try {
+            byte[] processImage = approvalTaskService.getProcessImage(processId);
+            OutputStream outputStream = response.getOutputStream();
+            InputStream in = new ByteArrayInputStream(processImage);
+            IOUtils.copy(in, outputStream);
+        } catch (Exception e) {
+            log.error("viewProcessImg---- {}", e);
+        }
+
+    }
+
+    /**
+     * 获取当前用户发起的流程
+     *
+     * @return
+     */
+    @PostMapping("/myStarted")
+    public Result listApprovalMyStarted(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                                        @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+                                        HttpServletRequest req) {
+
+        return Result.OK(approvalTaskService.listApprovalMyStarted(pageNo, pageSize,req));
+    }
+
+
+    /**
+     * 根据流程id获取待我审批的流程
+     *
+     * @param processInstanceId
+     * @return
+     */
+    @GetMapping("/getMyApprovalTask")
+    public Result<TaskVO> getMyApprovalTask(@RequestParam String processInstanceId) {
+        TaskVO myApprovalTask = approvalTaskService.getMyApprovalTask(processInstanceId);
+        return Result.OK(myApprovalTask);
+    }
+
+    /**
+     * 根据流程id获取审批记录
+     * @param processInstanceId
+     * @return
+     */
+    @GetMapping("/listOpinionsByPId")
+    public Result listOpinionsByPId(@RequestParam String processInstanceId){
+        List<ApprovalOpinionDTO> opinions = approvalTaskService.listOpinionsByPId(processInstanceId);
+        return Result.OK(opinions);
+    }
+}

+ 83 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/dto/ApprovalOpinionDTO.java

@@ -0,0 +1,83 @@
+package org.jeecg.modules.approval.model.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.activiti.engine.impl.persistence.entity.AttachmentEntityImpl;
+import org.jeecg.common.system.vo.LoginUser;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 申请流程 审批信息
+ *
+ * @author yao
+ */
+@Data
+public class ApprovalOpinionDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 审批人id
+     */
+    private String opId;
+    /**
+     * 审批人姓名
+     */
+    private String opName;
+    /**
+     * 审批意见
+     */
+    private String opinion;
+    /**
+     * 审批时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+    /**
+     * DIctEnum  流程审批操作类型:
+     * 是否通过 0拒绝,1同意,2驳回。。。
+     */
+    private String flag;
+
+    /**
+     * 审批结果对应的字典值
+     */
+    private String flagStr;
+    /**
+     * 流程id
+     */
+    private String taskId;
+    /**
+     * 当前节点名称
+     */
+    private String taskNodeName;
+
+    /**
+     * 附件
+     */
+    private List<AttachmentEntityImpl> attachments;
+
+    /**
+     * 下一步审核人是否默认 0 默认,1 审批人指定
+     */
+    private String defNextAssignee;
+
+    /**
+     * 指定的下一步审核人
+     */
+    private LoginUser nextAssignee;
+
+    /**
+     * 驳回到指定节点id
+     */
+    private String runNodeId;
+
+    /**
+     * 节点样式
+     */
+    private String style;
+
+}

+ 38 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/dto/CurrTaskNodeInfoDTO.java

@@ -0,0 +1,38 @@
+package org.jeecg.modules.approval.model.dto;
+
+import lombok.Data;
+import org.jeecg.common.system.vo.LoginUser;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 当前流程任务节点信息
+ *
+ * @author Create by YLL
+ * @date 2020/4/9 9:55
+ */
+@Data
+public class CurrTaskNodeInfoDTO {
+    /**
+     * 当前任务id
+     */
+    private String taskId;
+    /**
+     * 当前任务节点名称
+     */
+    private String taskName;
+    /**
+     * 当前节点开始时间
+     */
+    private Date startTime;
+    /**
+     * 当前任务审批人
+     */
+    private LoginUser assignee;
+    /**
+     * 当前任务审批人候选组
+     */
+    private List<LoginUser> candidates;
+
+}

+ 52 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/dto/DynamicFormConf.java

@@ -0,0 +1,52 @@
+package org.jeecg.modules.approval.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * 动态表单配置
+ *
+ * @author Create by YLL
+ * @date 2020/4/1 14:37
+ */
+@Data
+public class DynamicFormConf implements Serializable {
+    /**
+     * 审批操作类型
+     */
+    private Map<String, String> approvalTypeFlag;
+
+    /**
+     * 是否可以修改表单
+     */
+    private boolean writable;
+
+
+    /**
+     * 字段是否可编辑(批量控制)
+     */
+    private boolean fieldWritable;
+
+    /**
+     * 是否可以指定下一步办理人
+     */
+    private boolean nextAssign;
+
+    /**
+     * 存放已经执行的节点信息
+     */
+    private Map<String,String> runNodes;
+
+    /**
+     *判断节点
+     */
+    private String isNodes;
+
+    /**
+     * 自定义参数
+     */
+    private Map<String, Object> params;
+
+}

+ 74 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/ApprovalOpinionVO.java

@@ -0,0 +1,74 @@
+package org.jeecg.modules.approval.model.vo;
+
+import lombok.Data;
+import org.activiti.engine.impl.persistence.entity.AttachmentEntityImpl;
+import org.jeecg.common.system.vo.LoginUser;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 申请流程 审批信息
+ *
+ * @author yao
+ */
+@Data
+public class ApprovalOpinionVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 审批人id
+     */
+    private String opId;
+    /**
+     * 审批人姓名
+     */
+    private String opName;
+    /**
+     * 审批意见
+     */
+    private String opinion;
+    /**
+     * 审批时间
+     */
+    private Date createTime;
+    /**
+     * 是否通过 0拒绝,1同意,2驳回
+     */
+    private String flag;
+    /**
+     * 流程任务id
+     */
+    private String taskId;
+    /**
+     * 当前节点名称
+     */
+    private String taskNodeName;
+
+    /**
+     * 附件
+     */
+    private List<AttachmentEntityImpl> attachments;
+
+    /**
+     * 下一步审核人是否默认 0 默认,1 审批人指定
+     */
+    private String defNextAssignee;
+
+    /**
+     * 指定的下一步审核人
+     */
+    private LoginUser nextAssignee;
+
+    /**
+     * 驳回到指定节点id
+     */
+    private String runNodeId;
+
+    /**
+     * id
+     */
+    private String id;
+}

+ 29 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/ApprovalTaskQueryVo.java

@@ -0,0 +1,29 @@
+package org.jeecg.modules.approval.model.vo;
+
+import lombok.Data;
+
+/**
+ * @Author: yll
+ * @Date: 2019/8/15 17:25
+ */
+@Data
+public class ApprovalTaskQueryVo {
+    /**
+     * 流程状态 0进行中,1已完成
+     */
+    private String status;
+    /**
+     * 业务类
+     */
+    private String formType;
+
+    /**
+     * 是否待处理 true已处理,false待处理
+     */
+    private boolean processed;
+
+    /**
+     * 是否我发起的
+     */
+    private boolean myStarted;
+}

+ 68 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/ApprovalVO.java

@@ -0,0 +1,68 @@
+package org.jeecg.modules.approval.model.vo;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Maps;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.Constant;
+import org.jeecg.common.base.entity.BaseTaskEntity;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.common.utils.StringUtils;
+import org.jeecg.modules.apply.service.ApplyProcessService;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 发起审批
+ *
+ * @author yao
+ * @since 2019/7/2 14:50
+ */
+@Slf4j
+@Data
+public class ApprovalVO<T> {
+
+    /**
+     * 当前任务实例
+     */
+    private T t;
+
+    public ApprovalVO(T t) {
+        this.t = t;
+    }
+
+    public Map getBaseTaskVariables() {
+
+        BaseTaskEntity baseTaskEntity = getBaseTask();
+        Map<String, Object> taskMap = Maps.newHashMap();
+
+        taskMap.put(Constant.ACT_BASE_TASK, JSONObject.toJSONString(baseTaskEntity));
+        taskMap.put(Constant.ACT_APPLY_USER, baseTaskEntity.getUserId());
+        //保存变量
+        if(StringUtils.isNotEmpty(baseTaskEntity.getParam())){
+            Map<String, Object> param = baseTaskEntity.getParam();
+            for (Map.Entry<String, Object> m : param.entrySet()) {
+                taskMap.put(m.getKey(),m.getValue());
+                System.out.println("key:" + m.getKey() + " value:" + m.getValue());
+            }
+        }
+
+        //根据表单发起人动态保存部门领导
+
+        return taskMap;
+    }
+
+    public BaseTaskEntity getBaseTask() {
+        ObjectMapper objectMapper = new ObjectMapper();
+        return objectMapper.convertValue(this.t, BaseTaskEntity.class);
+    }
+
+    public String getBusinessKey() {
+        return String.format("%s/%s", getBaseTask().getFormKey(), getBaseTask().getId());
+    }
+
+}

+ 113 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/HistoryTaskVO.java

@@ -0,0 +1,113 @@
+package org.jeecg.modules.approval.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.activiti.engine.history.HistoricTaskInstance;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 任务VO
+ *
+ * @author yao
+ * @since 2019/6/15 15:19
+ */
+@Data
+public class HistoryTaskVO {
+    /**
+     * 任务id
+     */
+    private String id;
+
+    /**
+     * 审批名称
+     */
+    private String approveName;
+
+    /**
+     * 任务节点名称
+     */
+    private String taskNodeName;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    /**
+     * 代理人
+     */
+    private String assignee;
+    /**
+     * 流程实例id
+     */
+    private String processInstanceId;
+    /**
+     * 流程定义id
+     */
+    private String processDefinitionId;
+
+    /**
+     * 流程定义key
+     */
+    private String processDefinitionKey;
+    /**
+     * 流程定义key
+     */
+    private String processDefinitionName;
+
+    /**
+     * 描述
+     */
+    private String description;
+    /**
+     * 命令空间
+     */
+    private String category;
+
+    /**
+     * 用户名
+     */
+    private String userName;
+    /**
+     * 理由
+     */
+    private String remarks;
+    /**
+     * 地址
+     */
+    private String taskUrl;
+
+    /**
+     * 审批结果 0拒绝 1同意 2进行中,3已取消
+     *
+     */
+    private String result;
+
+    private String resultStr;
+
+    /**
+     * 流程是否结束 true结束,false未结束
+     */
+    private Boolean finished;
+
+    /**
+     * 其他参数
+     */
+    private Map<String,Object> param;
+
+    public HistoryTaskVO() {
+    }
+
+    public HistoryTaskVO(HistoricTaskInstance t) {
+            this.id = t.getId();
+            this.taskNodeName = t.getName();
+            this.createTime = t.getCreateTime();
+            this.assignee = t.getAssignee();
+            this.processInstanceId = t.getProcessInstanceId();
+            this.processDefinitionId = t.getProcessDefinitionId();
+            this.description = t.getDescription();
+            this.category = t.getCategory();
+    }
+}

+ 45 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/TaskCountDataVO.java

@@ -0,0 +1,45 @@
+package org.jeecg.modules.approval.model.vo;
+
+import lombok.Data;
+
+/**
+ * 任务统计VO
+ *
+ * @author yao
+ * @since 2019/6/15 15:19
+ */
+@Data
+public class TaskCountDataVO {
+
+    /**
+     * 统计名称
+     */
+    private String name;
+    /**
+     * 图表
+     */
+    private String icon;
+
+    /**
+     * 任务数
+     */
+    private int count;
+
+    /**
+     * 选中
+     */
+    private boolean selected;
+
+    /**
+     * 统计code
+     */
+    private String code;
+
+    public TaskCountDataVO(String name, String icon, int count, boolean selected, String code) {
+        this.name = name;
+        this.icon = icon;
+        this.count = count;
+        this.selected = selected;
+        this.code = code;
+    }
+}

+ 102 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/model/vo/TaskVO.java

@@ -0,0 +1,102 @@
+package org.jeecg.modules.approval.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 任务VO
+ *
+ * @author yao
+ * @since 2019/6/15 15:19
+ */
+@Data
+public class TaskVO {
+    /**
+     * 任务id
+     */
+    private String id;
+
+    /**
+     * 审批名称
+     */
+    private String approveName;
+
+    /**
+     * 任务节点名称
+     */
+    private String taskNodeName;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    /**
+     * 代理人
+     */
+    private String assignee;
+    /**
+     * 流程实例id
+     */
+    private String processInstanceId;
+    /**
+     * 流程定义id
+     */
+    private String processDefinitionId;
+
+    /**
+     * 流程定义key
+     */
+    private String processDefinitionKey;
+    /**
+     * 流程定义key
+     */
+    private String processDefinitionName;
+
+    /**
+     * 描述
+     */
+    private String description;
+    /**
+     * 命令空间
+     */
+    private String category;
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+    /**
+     * 理由
+     */
+    private String remarks;
+    /**
+     * 地址
+     */
+    private String taskUrl;
+
+    /**
+     * 摘要
+     */
+    private String summary;
+    /**
+     * 其他参数
+     */
+    private Map<String,Object> param;
+
+    public TaskVO() {}
+
+    public TaskVO(org.activiti.engine.task.Task t) {
+        this.id = t.getId();
+        this.taskNodeName = t.getName();
+        this.createTime = t.getCreateTime();
+        this.assignee = t.getAssignee();
+        this.processInstanceId = t.getProcessInstanceId();
+        this.processDefinitionId = t.getProcessDefinitionId();
+        this.description = t.getDescription();
+        this.category = t.getCategory();
+    }
+}

+ 124 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/ApprovalService.java

@@ -0,0 +1,124 @@
+package org.jeecg.modules.approval.service;
+
+import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.task.Task;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.model.dto.DynamicFormConf;
+import org.jeecg.modules.approval.model.vo.ApprovalOpinionVO;
+import org.jeecg.modules.approval.model.vo.ApprovalVO;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 任务接口
+ *
+ * @author yao
+ */
+public interface ApprovalService {
+
+    /**
+     * 发起审批流程
+     *
+     * @param applyTaskVO
+     * @return
+     */
+    ProcessInstance addApproval(ApprovalVO applyTaskVO);
+
+    /**
+     * tenantId 项目id
+     * 发起审批流程
+     * @param applyTaskVO
+     * @return
+     */
+    ProcessInstance addApprovalTenantId(ApprovalVO applyTaskVO,String tenantId);
+
+
+    /**
+     * 获取流程状态
+     *
+     * @param processInstanceId
+     * @return 进行中 true 完成 false
+     */
+    boolean getApprovalStatus(String processInstanceId);
+
+    /**
+     * 审批
+     *
+     * @param approvalOpinionVO
+     * @return
+     */
+    boolean handleApproval(ApprovalOpinionVO approvalOpinionVO);
+
+    /**
+     * 流程环节 审批信息
+     *
+     * @param processId
+     * @return
+     */
+    List<ApprovalOpinionDTO> listApprovalDetail(String processId);
+
+    /**
+     * 驳回到上一步
+     *
+     * @param approvalOpinionVO
+     * @param task
+     * @param map
+     * @return
+     */
+    boolean rejected(ApprovalOpinionVO approvalOpinionVO, Task task, Map<String, Object> map);
+
+    /**
+     * 驳回到指定节点
+     *
+     * @param approvalOpinionVO
+     * @param task
+     * @param map
+     * @return
+     */
+    boolean runNodes(ApprovalOpinionVO approvalOpinionVO, Task task, Map<String, Object> map);
+
+
+    /**
+     * 撤销申请
+     *
+     * @param processInstanceId
+     * @return
+     */
+    boolean withdrawProcess(String processInstanceId);
+
+    /**
+     * 获取流程状态(能否撤销,能否修改) 1可以
+     *
+     * @param processInstanceId
+     * @return
+     */
+    Map getProcessStatus(String processInstanceId);
+
+    /**
+     * 获取用户任务的动态表单的配置
+     *
+     * @param taskId
+     * @return
+     */
+    DynamicFormConf taskDynamicParams(String taskId);
+
+    /**
+     *获取当前任务下的候选人
+     * 候选人>候选组 : 没有候选人时,再从候选组中查找
+     * @param taskId
+     * @return
+     */
+    Set<String> getCandiates(String taskId);
+
+    /**
+     *获取已经执行的节点信息
+     */
+    Map<String,String> getRunNodes(String processInstanceId);
+
+    /**
+     * 自动审批
+     */
+    boolean autoHandleApproval(ApprovalOpinionVO approvalOpinionVO);
+}

+ 111 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/ApprovalTaskService.java

@@ -0,0 +1,111 @@
+package org.jeecg.modules.approval.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.model.vo.ApprovalTaskQueryVo;
+import org.jeecg.modules.approval.model.vo.TaskVO;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 任务接口
+ *
+ * @author yao
+ */
+public interface ApprovalTaskService {
+
+    /**
+     * 待处理任务
+     *
+     * @return
+     */
+    IPage listMyTask(Integer pageNo,Integer pageSize,HttpServletRequest req);
+
+
+    /**
+     * 已处理任务列表
+     *
+     * @param req
+     * @return
+     */
+    IPage listMyProcessedTask( Integer pageNo,Integer pageSize,HttpServletRequest req);
+
+
+    /**
+     * 任务明细
+     *
+     * @param taskId
+     * @return
+     */
+    Object getTask(String taskId);
+
+    /**
+     * 追踪流程图片
+     *
+     * @param processInstanceId
+     * @return
+     * @throws Exception
+     */
+    byte[] getProcessImage(String processInstanceId) throws Exception;
+
+
+
+    /**
+     * 我发起的流程
+     *
+     * @param
+     * @return
+     */
+    IPage listApprovalMyStarted(Integer pageNo,Integer pageSize,HttpServletRequest req);
+
+    /**
+     * 待处理任务数量
+     *
+     * @return
+     */
+    long countUnprocessed();
+
+    /**
+     * 我发起的任务数量
+     *
+     * @return
+     */
+    long countMyStarted();
+
+    /**
+     * 我审批的任务列表
+     *
+     * @param
+     * @param param
+     * @return
+     */
+    IPage listApiMyApproval(Map<String, String> params, ApprovalTaskQueryVo param);
+
+    /**
+     * 我发起的任务列表
+     *
+     * @param
+     * @param param
+     * @return
+     */
+    IPage listApiMyStarted(Map<String, String> params, ApprovalTaskQueryVo param);
+
+
+    /**
+     * 根据流程id获取待我审批的流程
+     *
+     * @param processInstanceId
+     * @return
+     */
+    TaskVO getMyApprovalTask(String processInstanceId);
+
+    /**
+     * 根据流程id获取审批记录
+     * @param processInstanceId
+     * @return
+     */
+    List<ApprovalOpinionDTO> listOpinionsByPId(String processInstanceId);
+}

+ 766 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/impl/ApprovalServiceImpl.java

@@ -0,0 +1,766 @@
+package org.jeecg.modules.approval.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.bpmn.model.*;
+import org.activiti.engine.*;
+import org.activiti.engine.form.FormProperty;
+import org.activiti.engine.form.TaskFormData;
+import org.activiti.engine.history.HistoricActivityInstance;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.history.HistoricVariableInstance;
+import org.activiti.engine.impl.identity.Authentication;
+import org.activiti.engine.runtime.Execution;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.runtime.ProcessInstanceBuilder;
+import org.activiti.engine.task.IdentityLink;
+import org.activiti.engine.task.Task;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.Constant;
+import org.jeecg.common.exception.CustomException;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.common.utils.DictEnum;
+import org.jeecg.common.utils.DictModelConstant;
+import org.jeecg.common.utils.StringUtils;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.model.dto.DynamicFormConf;
+import org.jeecg.modules.approval.model.vo.ApprovalOpinionVO;
+import org.jeecg.modules.approval.model.vo.ApprovalVO;
+import org.jeecg.modules.approval.service.ApprovalService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+/**
+ * 审批业务实现
+ *
+ * @author yao
+ */
+@Slf4j
+@Service("approvalService")
+public class ApprovalServiceImpl implements ApprovalService {
+    /**
+     * 当前流程节点集合
+     */
+    public static final String CURR_TASK_NODES = "currTaskNodes";
+    @Autowired
+    private RuntimeService runtimeService;
+    @Autowired
+    private TaskService taskService;
+    @Autowired
+    private HistoryService historyService;
+    @Autowired
+    private RepositoryService repositoryService;
+    @Autowired
+    private FormService formService;
+
+
+    /**
+     *
+     *  发起审批流程
+     * @param approvalVO
+     * @return
+     */
+    @Override
+    public ProcessInstance addApproval(ApprovalVO approvalVO) {
+        // 发起审批流程
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        Authentication.setAuthenticatedUserId(sysUser.getId());
+        ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
+        processInstanceBuilder.processDefinitionKey(approvalVO.getBaseTask().getProcessKey());
+        processInstanceBuilder.businessKey(approvalVO.getBusinessKey());
+        processInstanceBuilder.variables(approvalVO.getBaseTaskVariables());
+        ProcessInstance processInstance = processInstanceBuilder.start();
+        return processInstance;
+    }
+
+    /**
+     * 发起审批流程
+     *tenantId 项目id
+     * @param approvalVO
+     * @return
+     */
+    @Override
+    public ProcessInstance addApprovalTenantId(ApprovalVO approvalVO,String tenantId) {
+
+        // 发起审批流程
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        Authentication.setAuthenticatedUserId(sysUser.getId());
+        ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
+        processInstanceBuilder.tenantId(tenantId);
+        processInstanceBuilder.processDefinitionKey(approvalVO.getBaseTask().getProcessKey());
+        processInstanceBuilder.businessKey(approvalVO.getBusinessKey());
+        processInstanceBuilder.variables(approvalVO.getBaseTaskVariables());
+        ProcessInstance processInstance = processInstanceBuilder.start();
+        return processInstance;
+    }
+
+    /**
+     * 获取流程状态,已结束或不存在false, 存在true
+     *
+     * @param processInstanceId
+     * @return
+     */
+    @Override
+    public boolean getApprovalStatus(String processInstanceId) {
+
+        ProcessInstance processInstance =
+                runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+        return processInstance != null;
+    }
+
+    /**
+     * 审批处理
+     *
+     * @param approvalOpinionVO
+     * @return
+     */
+    @Override
+    public boolean handleApproval(ApprovalOpinionVO approvalOpinionVO) {
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+        Task task = taskService.createTaskQuery()
+                .taskId(approvalOpinionVO.getTaskId())
+                .includeProcessVariables()    //定义参数
+                .singleResult();  //单个结果
+        if (task == null) {
+            throw new CustomException("流程未启动或已执行完成");
+        }
+        if (StringUtils.isNotEmpty(task.getAssignee()) && !sysUser.getId().equals(task.getAssignee())) {
+            throw new CustomException("当前用户不是审核人,无法进行审核");
+        }
+
+
+        if (StringUtils.isEmpty(task.getAssignee())) {
+            Set<String> candidates = getCandiates(task.getId());
+            if (candidates.isEmpty()) {
+                throw new CustomException("当前用户不是审核人,无法进行审核");
+            }
+            if (candidates.contains(sysUser.getId())) {
+                taskService.claim(task.getId(),sysUser.getId());
+            }
+        }
+
+        Map<String, Object> processVariables = task.getProcessVariables();
+        approvalOpinionVO.setCreateTime(new Date());
+        approvalOpinionVO.setOpId(sysUser.getId());
+        approvalOpinionVO.setOpName(sysUser.getRealname());
+        approvalOpinionVO.setTaskNodeName(task.getName());
+        Map<String, Object> map = Maps.newHashMap();
+        map.put(Constant.ACT_TASK_FLAG, approvalOpinionVO.getFlag());
+
+        //驳回操作
+        if (DictEnum.APPLY_APPROVAL_OPINION_REJECT.getKey().equals(approvalOpinionVO.getFlag())) {
+            return rejected(approvalOpinionVO, task, map);
+        }
+        //撤回到指定节点
+        if (DictEnum.APPLY_APPROVAL_OPINION_ASSIGN.getKey().equals(approvalOpinionVO.getFlag())) {
+            return runNodes(approvalOpinionVO, task, map);
+        }
+        // 审批信息叠加
+        List<ApprovalOpinionDTO> opinionDTOS = new ArrayList<>();
+        Object options = processVariables.get(Constant.ACT_APPLY_OPINION_LIST);
+        if (options != null) {
+            opinionDTOS = JSONObject.parseArray(options.toString(), ApprovalOpinionDTO.class);
+        }
+        ApprovalOpinionDTO applyOpinionDTO = new ApprovalOpinionDTO();
+        //VO转为dto
+        BeanUtils.copyProperties(approvalOpinionVO, applyOpinionDTO);
+
+        opinionDTOS.add(applyOpinionDTO);
+        map.put(Constant.ACT_APPLY_OPINION_LIST, JSONObject.toJSONString(opinionDTOS));
+        taskService.complete(applyOpinionDTO.getTaskId(), map);
+        return true;
+    }
+
+    /**
+     * 获取当前任务下的候选人
+     * 候选人>候选组 : 没有候选人时,再从候选组中查找
+     *
+     * @param taskId
+     * @return
+     */
+    @Override
+    public Set<String> getCandiates(String taskId) {
+        Set<String> candiates = Sets.newHashSet();
+        Set<String> groupIds = Sets.newHashSet();
+        List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(taskId);
+        for (IdentityLink identityLink : identityLinks) {
+            if (Constant.ACT_CANDIDATE.equals(identityLink.getType())) {
+                candiates.add(identityLink.getUserId());
+            }
+            if (StringUtils.isNotEmpty(identityLink.getGroupId())) {
+                groupIds.add(identityLink.getGroupId());
+            }
+        }
+        if (candiates.isEmpty()) {
+            // TODO: 2020/5/19 候选人为空时,查询候选组中的人
+        }
+        return candiates;
+    }
+
+    @Override
+    public  Map<String,String> getRunNodes(String processInstanceId) {
+
+        Map<String, String> map = new LinkedHashMap<String, String>();
+        // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
+        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .activityType("userTask")
+                .finished()
+                .orderByHistoricActivityInstanceEndTime()
+                .asc()
+                .list();
+
+        // 已执行的节点ID集合
+        if (StringUtils.isNotEmpty(historicActivityInstanceList)) {
+            // map = historicActivityInstanceList.stream().collect(Collectors.toMap(HistoricActivityInstance::getActivityId,HistoricActivityInstance::getActivityName,(k1,k2)->k1));
+            for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
+                if (!map.containsKey(historicActivityInstance.getActivityId())) {
+                    map.put(historicActivityInstance.getActivityId(), historicActivityInstance.getActivityName());
+                }
+            }
+        }
+
+        return map;
+    }
+
+    @Override
+    public boolean autoHandleApproval(ApprovalOpinionVO approvalOpinionVO) {
+        Task task = taskService.createTaskQuery()
+                .taskId(approvalOpinionVO.getTaskId())
+                // .executionId(approvalOpinionVO.getTaskId())
+                .includeProcessVariables()
+                .singleResult();
+        if (task == null) {
+            throw new CustomException("流程未启动或已执行完成");
+        }
+
+        Map<String, Object> processVariables = task.getProcessVariables();
+        approvalOpinionVO.setCreateTime(new Date());
+        approvalOpinionVO.setTaskNodeName(task.getName());
+        Map<String, Object> map = Maps.newHashMap();
+        map.put(Constant.ACT_TASK_FLAG, approvalOpinionVO.getFlag());
+        // 审批信息叠加
+        List<ApprovalOpinionDTO> opinionDTOS = new ArrayList<>();
+        Object options = processVariables.get(Constant.ACT_APPLY_OPINION_LIST);
+        if (options != null) {
+            opinionDTOS = JSONObject.parseArray(options.toString(), ApprovalOpinionDTO.class);
+        }
+        ApprovalOpinionDTO applyOpinionDTO = new ApprovalOpinionDTO();
+        //VO转为dto
+        BeanUtils.copyProperties(approvalOpinionVO, applyOpinionDTO);
+        opinionDTOS.add(applyOpinionDTO);
+        map.put(Constant.ACT_APPLY_OPINION_LIST, JSONObject.toJSONString(opinionDTOS));
+        taskService.complete(applyOpinionDTO.getTaskId(), map);
+        return true;
+    }
+
+    /**
+     * 根据 执行对象id获取审批信息
+     *
+     * @param processId
+     * @return
+     */
+    @Override
+    public List<ApprovalOpinionDTO> listApprovalDetail(String processId) {
+        if (!StringUtils.isNotEmpty(processId)) {
+            return Lists.newArrayList();
+        }
+        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
+                .processInstanceId(processId)
+                .includeProcessVariables()
+                .singleResult();
+        // 保证运行ing
+        List<ApprovalOpinionDTO> leaveList = Lists.newArrayList();
+        if (instance != null) {
+            Map<String, Object> variables = instance.getProcessVariables();
+            if (StringUtils.isNotEmpty(variables) && variables.containsKey(Constant.ACT_APPLY_OPINION_LIST)) {
+                Object obj = variables.get(Constant.ACT_APPLY_OPINION_LIST);
+                if (StringUtils.isNotNull(obj)) {
+                    leaveList = JSONObject.parseArray(obj.toString(), ApprovalOpinionDTO.class);
+                }
+            }
+        } else {
+            HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery()
+                    .processInstanceId(processId)
+                    .variableName(Constant.ACT_APPLY_OPINION_LIST)
+                    .singleResult();
+            if (null != historicVariableInstance) {
+                leaveList = JSONObject.parseArray(historicVariableInstance.getValue().toString(), ApprovalOpinionDTO.class);
+            }
+        }
+
+        for (ApprovalOpinionDTO approvalOpinionDTO : leaveList) {
+            if (StringUtils.isEmpty(approvalOpinionDTO.getFlagStr())) {
+                approvalOpinionDTO.setFlagStr(DictEnum.getValue(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG, approvalOpinionDTO.getFlag()));
+            }
+
+            List<String> rejectStyle = Lists.newArrayList(DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey(),
+                    DictEnum.APPLY_APPROVAL_OPINION_REJECT.getKey(),
+                    DictEnum.APPLY_APPROVAL_OPINION_ABANDON.getKey(),
+                    DictEnum.APPLY_APPROVAL_OPINION_ASSIGN.getKey());
+            String style = rejectStyle.contains(approvalOpinionDTO.getFlag()) ? "error" : "success";
+            approvalOpinionDTO.setStyle(style);
+        }
+        //按时间倒叙
+        if (leaveList.size() > 0) {
+            leaveList.sort(Comparator.comparing(ApprovalOpinionDTO::getCreateTime).reversed());
+        }
+
+        return leaveList;
+    }
+
+    /**
+     * 驳回到上一步
+     *
+     * @param approvalOpinionVO
+     * @return
+     */
+    @Override
+    public boolean rejected(ApprovalOpinionVO approvalOpinionVO, Task task, Map<String, Object> map) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String myTaskId = null;
+        if (user.getId().equals(task.getAssignee())) {
+            myTaskId = task.getId();
+        }
+
+        if (null == myTaskId) {
+            throw new CustomException("当前用户无法驳回");
+        }
+        //获取当前节点
+        String currActivityId = task.getTaskDefinitionKey();
+        String processDefinitionId = task.getProcessDefinitionId();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId);
+
+        if (null == currFlow) {
+            List<SubProcess> subProcessList = bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class, true);
+            for (SubProcess subProcess : subProcessList) {
+                FlowElement flowElement = subProcess.getFlowElement(currActivityId);
+                if (flowElement != null) {
+                    currFlow = (FlowNode) flowElement;
+                    break;
+                }
+            }
+        }
+
+        //审批意见叠加
+        Map<String, Object> variables = task.getProcessVariables();
+        //拒绝,通过,驳回
+        List<ApprovalOpinionDTO> approvalOpinionDTOs = new ArrayList<>();
+        Object options = variables.get(Constant.ACT_APPLY_OPINION_LIST);
+        if (null != options) {
+            approvalOpinionDTOs = JSONObject.parseArray(options.toString(), ApprovalOpinionDTO.class);
+        }
+        ApprovalOpinionDTO applyOpinionDTO = new ApprovalOpinionDTO();
+        //VO转为dto
+        BeanUtils.copyProperties(approvalOpinionVO, applyOpinionDTO);
+        approvalOpinionDTOs.add(applyOpinionDTO);
+        map.put(Constant.ACT_APPLY_OPINION_LIST, JSONObject.toJSONString(approvalOpinionDTOs));
+
+        //判断是否已指定驳回目标任务
+        boolean hasTarget = false;
+        List<SequenceFlow> outgoingFlows = currFlow.getOutgoingFlows();
+        loop1:
+        for (SequenceFlow outgoingFlow : outgoingFlows) {
+            if ("${flag==2}".equals(StringUtils.trimAll(outgoingFlow.getConditionExpression()))) {
+                hasTarget = true;
+                break;
+            } else {
+                FlowNode targetFlowElement = (FlowNode) outgoingFlow.getTargetFlowElement();
+                if (targetFlowElement.isExclusive()) {
+                    List<SequenceFlow> subOutgoingFlows = targetFlowElement.getOutgoingFlows();
+                    loop2:
+                    for (SequenceFlow subOutgoingFlow : subOutgoingFlows) {
+                        if ("${flag==2}".equals(StringUtils.trimAll(subOutgoingFlow.getConditionExpression()))) {
+                            hasTarget = true;
+                            break loop1;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (hasTarget) {
+            taskService.complete(task.getId(), map);
+            return true;
+        }
+
+        //获取目标节点
+        List<HistoricActivityInstance> userTasks = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .activityType("userTask")
+                .finished()
+                .orderByHistoricActivityInstanceEndTime()
+                .desc()
+                .list();
+
+        if (StringUtils.isEmpty(userTasks)) {
+            throw new CustomException("此处无法进行驳回操作");
+        }
+
+        //判断目标节点是否是下一步的节点
+        if (options != null) {
+            for (ApprovalOpinionDTO approvalOpinionDTO : approvalOpinionDTOs) {
+                if (userTasks.get(0).getTaskId().equals(approvalOpinionDTO.getTaskId())) {
+                    if (DictEnum.APPLY_APPROVAL_OPINION_REJECT.getKey().equals(approvalOpinionDTO.getFlag())) {
+                        throw new CustomException("此处无法进行驳回操作");
+                    }
+                }
+            }
+        }
+
+        String activityId = userTasks.get(0).getActivityId();
+        FlowNode targetFlow = (FlowNode) bpmnModel.getFlowElement(activityId);
+
+        //如果不是同一个流程(子流程)不能驳回
+        if (!(currFlow.getParentContainer().equals(targetFlow.getParentContainer()))) {
+            throw new CustomException("此处无法进行驳回操作");
+        }
+
+        //记录原活动方向
+        List<SequenceFlow> oriSequenceFlows = Lists.newArrayList();
+        oriSequenceFlows.addAll(currFlow.getOutgoingFlows());
+
+        //清理活动方向
+        currFlow.getOutgoingFlows().clear();
+
+        //建立新的方向
+        List<SequenceFlow> newSequenceFlows = Lists.newArrayList();
+        SequenceFlow newSequenceFlow = new SequenceFlow();
+        String uuid = UUID.randomUUID().toString().replace("-", "");
+        newSequenceFlow.setId(uuid);
+        newSequenceFlow.setSourceFlowElement(currFlow);
+        newSequenceFlow.setTargetFlowElement(targetFlow);
+        newSequenceFlows.add(newSequenceFlow);
+
+        currFlow.setOutgoingFlows(newSequenceFlows);
+        taskService.complete(task.getId(), map);
+
+        //恢复原方向
+        currFlow.setOutgoingFlows(oriSequenceFlows);
+        return true;
+    }
+
+    /**
+     * 驳回到指定节点
+     *
+     * @param approvalOpinionVO
+     * @param task
+     * @param map
+     * @return
+     */
+    @Override
+    public boolean runNodes(ApprovalOpinionVO approvalOpinionVO, Task task, Map<String, Object> map) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String myTaskId = null;
+        if (user.getId().equals(task.getAssignee())) {
+            myTaskId = task.getId();
+        }
+        if (null == myTaskId) {
+            throw new CustomException("当前用户无法驳回");
+        }
+        //获取当前节点
+        String currActivityId = task.getTaskDefinitionKey();
+        String processDefinitionId = task.getProcessDefinitionId();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId);
+
+        if (null == currFlow) {
+            List<SubProcess> subProcessList = bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class, true);
+            for (SubProcess subProcess : subProcessList) {
+                FlowElement flowElement = subProcess.getFlowElement(currActivityId);
+                if (flowElement != null) {
+                    currFlow = (FlowNode) flowElement;
+                    break;
+                }
+            }
+        }
+
+        FlowNode targetFlow = (FlowNode) bpmnModel.getFlowElement(approvalOpinionVO.getRunNodeId());
+
+        //如果不是同一个流程(子流程)不能驳回
+        if (!(currFlow.getParentContainer().equals(targetFlow.getParentContainer()))) {
+            throw new CustomException("此处无法进行驳回操作");
+        }
+
+        //记录原活动方向
+        List<SequenceFlow> oriSequenceFlows = Lists.newArrayList();
+        oriSequenceFlows.addAll(currFlow.getOutgoingFlows());
+
+        //清理活动方向
+        currFlow.getOutgoingFlows().clear();
+
+        //建立新的方向
+        List<SequenceFlow> newSequenceFlows = Lists.newArrayList();
+        SequenceFlow newSequenceFlow = new SequenceFlow();
+        String uuid = UUID.randomUUID().toString().replace("-", "");
+        newSequenceFlow.setId(uuid);
+        newSequenceFlow.setSourceFlowElement(currFlow);
+        newSequenceFlow.setTargetFlowElement(targetFlow);
+        newSequenceFlows.add(newSequenceFlow);
+        currFlow.setOutgoingFlows(newSequenceFlows);
+
+        //审批意见叠加
+        Map<String, Object> variables = task.getProcessVariables();
+        //拒绝,通过,驳回
+        List<ApprovalOpinionDTO> approvalOpinionDTOs = new ArrayList<>();
+        Object options = variables.get(Constant.ACT_APPLY_OPINION_LIST);
+        if (null != options) {
+            approvalOpinionDTOs = JSONObject.parseArray(options.toString(), ApprovalOpinionDTO.class);
+        }
+        ApprovalOpinionDTO applyOpinionDTO = new ApprovalOpinionDTO();
+        //VO转为dto
+        BeanUtils.copyProperties(approvalOpinionVO, applyOpinionDTO);
+        applyOpinionDTO.setFlagStr(applyOpinionDTO.getTaskNodeName() + "撤回到" + targetFlow.getName());
+        approvalOpinionDTOs.add(applyOpinionDTO);
+        map.put(Constant.ACT_APPLY_OPINION_LIST, JSONObject.toJSONString(approvalOpinionDTOs));
+
+        //判断是否已指定驳回目标任务
+        if (StringUtils.isEmpty(approvalOpinionVO.getRunNodeId())) {
+            boolean hasTarget = false;
+            List<SequenceFlow> outgoingFlows = currFlow.getOutgoingFlows();
+            loop1:
+            for (SequenceFlow outgoingFlow : outgoingFlows) {
+                if ("${flag==2}".equals(StringUtils.trimAll(outgoingFlow.getConditionExpression()))) {
+                    hasTarget = true;
+                    break;
+                } else {
+                    FlowNode targetFlowElement = (FlowNode) outgoingFlow.getTargetFlowElement();
+                    if (targetFlowElement.isExclusive()) {
+                        List<SequenceFlow> subOutgoingFlows = targetFlowElement.getOutgoingFlows();
+                        loop2:
+                        for (SequenceFlow subOutgoingFlow : subOutgoingFlows) {
+                            if ("${flag==2}".equals(StringUtils.trimAll(subOutgoingFlow.getConditionExpression()))) {
+                                hasTarget = true;
+                                break loop1;
+                            }
+                        }
+                    }
+                }
+            }
+            if (hasTarget) {
+                taskService.complete(task.getId(), map);
+                return true;
+            }
+        }
+
+        taskService.complete(task.getId(), map);
+
+        //恢复原方向
+        currFlow.setOutgoingFlows(oriSequenceFlows);
+        return true;
+    }
+
+    /**
+     * 取消申请
+     *
+     * @param processInstanceId
+     * @return
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean withdrawProcess(String processInstanceId) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .startedBy(user.getId())
+                .singleResult();
+
+        if (processInstance != null) {
+
+            Execution execution = runtimeService.createExecutionQuery()
+                    .processInstanceId(processInstanceId)
+                    .startedBy(user.getId())
+                    .singleResult();
+
+            String businessKey = processInstance.getBusinessKey();
+            String[] split = businessKey.split("/");
+            String module = split[0];
+            String taskId = split[1];
+
+            Map<String, Object> variables = processInstance.getProcessVariables();
+            runtimeService.setVariable(execution.getId(), Constant.ACT_TASK_FLAG, DictEnum.APPLY_APPROVAL_OPINION_ABANDON.getKey());
+            runtimeService.deleteProcessInstance(processInstanceId, "取消申请");
+
+            //领用模块
+
+            //采购模块
+
+            return true;
+        }
+            return false;
+    }
+
+
+    /**
+     * 获取流程状态 是否可撤销,可修改,可重新提交
+     *
+     * @param processInstanceId
+     * @return
+     */
+    @Override
+    public Map getProcessStatus(String processInstanceId) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        Map map = Maps.newHashMap();
+        map.put(Constant.APPROVAL_HANDLE_WITHDRAW, Constant.NO);
+        map.put(Constant.APPROVAL_HANDLE_MODIFY, Constant.NO);
+        map.put(Constant.APPROVAL_HANDLE_REAPPLY, Constant.NO);
+        //存放最终审批结果
+        map.put(Constant.APPROVAL_RESULT_STATUS, "");
+
+        ProcessInstance runtimeProcessInstance = runtimeService.createProcessInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .includeProcessVariables()
+                .singleResult();
+        if (runtimeProcessInstance != null) {
+            map.put(Constant.APPROVAL_HANDLE_WITHDRAW, Constant.YES);
+
+            List<Task> list = taskService.createTaskQuery()
+                    .processInstanceId(processInstanceId)
+                    .list();
+
+            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
+                    .startedBy(user.getId())
+                    .processInstanceId(processInstanceId)
+                    .finished()
+                    .includeProcessVariables()
+                    .singleResult();
+
+            if (historicProcessInstance != null) {
+
+                String deleteReason = historicProcessInstance.getDeleteReason();
+                //申请人取消或是被拒绝的,可以编辑后再次申请
+                if (StringUtils.isNotEmpty(deleteReason)) {
+                    map.put(Constant.APPROVAL_HANDLE_REAPPLY, Constant.YES);
+                }
+                //获取结束的审批流程最后一个节点的审批结果
+                Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
+                Object object = processVariables.get(Constant.ACT_TASK_FLAG);
+                if (object != null && object != "") {
+                    //根据审批结果进行显示
+                    //未通过
+                    if (DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey().equals(object.toString())) {
+                        map.put(Constant.APPROVAL_RESULT_STATUS, DictEnum.APPLY_RESULT_REFUSE.getValue());
+                        //判断是否可重新提交申请
+                        map.put(Constant.APPROVAL_HANDLE_REAPPLY, Constant.YES);
+                    }
+
+                    //通过
+                    if (DictEnum.Apply_APPROVAL_OPINION_AGREE.getKey().equals(object.toString()) || DictEnum.APPLY_APPROVAL_OPINION_CONFIRM.getKey().equals(object.toString())) {
+                        map.put(Constant.APPROVAL_RESULT_STATUS, DictEnum.APPLY_RESULT_AGREE.getValue());
+                    }
+
+                    //取消申请
+                    if (DictEnum.APPLY_APPROVAL_OPINION_ABANDON.getKey().equals(object.toString())) {
+                        map.put(Constant.APPROVAL_RESULT_STATUS, DictEnum.APPLY_RESULT_CANCEL.getValue());
+                    }
+                }
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public DynamicFormConf taskDynamicParams(String taskId) {
+        DynamicFormConf dynamicFormConf = new DynamicFormConf();
+        Map<String, String> map = Maps.newHashMap();
+        List<DictEnum> enumList = DictEnum.getEnumList(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG);
+        TaskFormData taskFormData = formService.getTaskFormData(taskId);
+        if (null != taskFormData && StringUtils.isNotEmpty(taskFormData.getFormProperties())) {
+            Task task = taskService.createTaskQuery()
+                    .taskId(taskId)
+                    .singleResult();
+            //.taskTenantId(UserUtils.getTenantId())
+
+            List<FormProperty> formProperties = taskFormData.getFormProperties();
+            for (FormProperty formProperty : formProperties) {
+                //有自定义的操作选项
+                if (formProperty.getId().equals(DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG)) {
+                    String name = formProperty.getName();
+                    if (StringUtils.isNotEmpty(name)) {
+                        String[] split = name.split(",");
+                        for (String s : split) {
+                            for (DictEnum dictEnum : enumList) {
+                                if (s.equals(dictEnum.getKey())) {
+                                    map.put(dictEnum.getKey(), dictEnum.getValue());
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+                //修改表单
+                if (formProperty.getId().equals(DictModelConstant.MODEL_APPLY_TASK_FORM_WRITABLE)) {
+                        dynamicFormConf.setWritable(true);
+                }
+                //批量控制字段是否可编辑
+                if (formProperty.getId().equals(DictModelConstant.MODEL_APPLY_TASK_FORM_FIELD_WRITABLE)) {
+                        dynamicFormConf.setFieldWritable(true);
+                }
+
+                //是否可以指定下一步办理人
+                if (formProperty.getId().equals(DictModelConstant.MODEL_APPLY_NEXT_ASSIGN)) {
+                    //if (isAssigneeOrCandiate(task, UserUtils.getUserId())) {
+                        dynamicFormConf.setNextAssign(true);
+                    //}
+                }
+                //判断当前节点
+                if (formProperty.getId().equals(DictModelConstant.MODEL_APPLY_NEXT_ISNODES)) {
+                    //if (isAssigneeOrCandiate(task, UserUtils.getUserId())) {
+                    dynamicFormConf.setIsNodes(formProperty.getName());
+                    //}
+                }
+//                Map<String, Object> params = new HashMap<>();
+//                params.put(formProperty.getId(), formProperty.getName());
+//                dynamicFormConf.setParams(params);
+            }
+        }
+
+        //使用默认的操作选项
+        if (map.isEmpty()) {
+            map.put(DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey(), DictEnum.Apply_APPROVAL_OPINION_REFUSE.getValue());
+            map.put(DictEnum.Apply_APPROVAL_OPINION_AGREE.getKey(), DictEnum.Apply_APPROVAL_OPINION_AGREE.getValue());
+            map.put(DictEnum.APPLY_APPROVAL_OPINION_REJECT.getKey(), DictEnum.APPLY_APPROVAL_OPINION_REJECT.getValue());
+        }
+        //判断是否有撤回到指定节点
+        if(StringUtils.isNotEmpty(map.get(DictEnum.APPLY_APPROVAL_OPINION_ASSIGN.getKey()))){
+            String processInstanceId = taskFormData.getTask().getProcessInstanceId();
+            Map<String, String> runNodes = getRunNodes(processInstanceId);
+            if(StringUtils.isNotEmpty(runNodes)){
+                dynamicFormConf.setRunNodes(runNodes);
+            }
+        }
+
+        dynamicFormConf.setApprovalTypeFlag(map);
+        return dynamicFormConf;
+    }
+
+    /**
+     * 判断用户是否为任务的办理人或候选人
+     *
+     * @param task
+     * @return
+     */
+    private boolean isAssigneeOrCandiate(Task task, String userId) {
+        if (StringUtils.isNull(task)) {
+            return false;
+        }
+        String assignee = task.getAssignee();
+        if (StringUtils.isNotEmpty(assignee)) {
+            return assignee.equals(userId);
+        } else {
+            Set<String> candiates = getCandiates(task.getId());
+            return candiates.contains(userId);
+        }
+    }
+}

+ 708 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/approval/service/impl/ApprovalTaskServiceImpl.java

@@ -0,0 +1,708 @@
+package org.jeecg.modules.approval.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.bpmn.model.BpmnModel;
+import org.activiti.bpmn.model.FlowNode;
+import org.activiti.bpmn.model.SequenceFlow;
+import org.activiti.engine.*;
+import org.activiti.engine.history.*;
+import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.activiti.engine.runtime.Execution;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.task.Task;
+import org.activiti.engine.task.TaskInfo;
+import org.activiti.engine.task.TaskQuery;
+import org.activiti.image.ProcessDiagramGenerator;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.Constant;
+import org.jeecg.common.base.entity.BaseTaskEntity;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.utils.DictEnum;
+import org.jeecg.common.utils.DictModelConstant;
+import org.jeecg.common.utils.StringUtils;
+import org.jeecg.common.config.CustomProcessDiagramGenerator;
+import org.jeecg.modules.approval.model.dto.ApprovalOpinionDTO;
+import org.jeecg.modules.approval.model.vo.*;
+import org.jeecg.modules.approval.service.ApprovalService;
+import org.jeecg.modules.approval.service.ApprovalTaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.yaml.snakeyaml.Yaml;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.InputStream;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 任务处理实现
+ *
+ * @author yao
+ */
+@Service("actTaskService")
+@Slf4j
+public class ApprovalTaskServiceImpl implements ApprovalTaskService {
+
+    @Autowired
+    private RuntimeService runtimeService;
+
+    @Autowired
+    private TaskService taskService;
+
+    @Autowired
+    private RepositoryService repositoryService;
+
+    @Autowired
+    private HistoryService historyService;
+
+    @Autowired
+    private ProcessEngine processEngine;
+
+    @Autowired
+    private ApprovalService approvalService;
+
+
+
+
+    /**
+     * 待处理任务
+     *
+     * @return
+     * @param
+     */
+    @Override
+    public IPage listMyTask(Integer pageNo, Integer pageSize,HttpServletRequest req) {
+        Map<String, String[]> parms = req.getParameterMap();
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String tenantId = req.getHeader("tenant-id");
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .taskCandidateOrAssigned(sysUser.getId())
+                .includeProcessVariables()
+                .orderByTaskCreateTime()
+                .taskTenantId(tenantId)
+                .desc();
+        if(parms !=null){
+            String[] keys = parms.get("approveName");
+            if (!"".equals(keys) && keys != null) {
+                String key = keys[0];
+                //taskQuery.taskName(key);
+                taskQuery.processDefinitionName(key);
+            }
+        }
+
+        List<Task> taskList = taskQuery.listPage((pageNo - 1) * pageSize, pageSize);
+
+        List<TaskVO> tasks = new ArrayList<>();
+        for (Task task : taskList) {
+
+            Map<String, Object> map = task.getProcessVariables();
+            BaseTaskEntity baseTaskEntity =
+                    JSON.parseObject(map.get(Constant.ACT_BASE_TASK).toString(), BaseTaskEntity.class);
+            TaskVO taskVO = new TaskVO(task);
+            taskVO.setUserName(baseTaskEntity.getUserName());
+            taskVO.setRemarks(baseTaskEntity.getRemarks());
+            taskVO.setTaskUrl(String.format("%s/%s", baseTaskEntity.getFormKey(), baseTaskEntity.getId()));
+            taskVO.setProcessDefinitionKey(baseTaskEntity.getProcessKey());
+            taskVO.setProcessDefinitionName(baseTaskEntity.getProcessInstanceName());
+            taskVO.setApproveName(DictEnum.getValue(DictModelConstant.MODEL_APPLY_CONFIG,
+                    DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, baseTaskEntity.getFormKey()));
+            taskVO.setCreateTime(task.getCreateTime());
+            Map<String, Object> param = baseTaskEntity.getParam();
+
+            if (StringUtils.isNotEmpty(param)) {
+                taskVO.setParam(param);
+            }
+            tasks.add(taskVO);
+        }
+
+        IPage<TaskVO> page = new Page<>(pageNo, pageSize);
+        page.setTotal((int) taskQuery.count());
+        return page.setRecords(tasks);
+    }
+
+    /**
+     * 已处理任务列表
+     *
+     * @param
+     * @return
+     */
+    @Override
+    public IPage listMyProcessedTask(Integer pageNo,Integer pageSize,HttpServletRequest req) {
+        String tenantId = req.getHeader("tenant-id");
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String userId = sysUser.getId();
+        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
+                .taskAssignee(userId)
+                .finished()
+                .taskTenantId(tenantId)
+                .includeProcessVariables()
+                .orderByTaskCreateTime()
+                .desc();
+        String[] keys = req.getParameterMap().get("approveName");
+        if (!"".equals(keys) && keys != null) {
+            String key = keys[0];
+            historicTaskInstanceQuery.processDefinitionName(key);
+        }
+        List<HistoricTaskInstance> taskList = historicTaskInstanceQuery.listPage((pageNo - 1) * pageSize, pageSize);
+
+        List<HistoryTaskVO> tasks = new ArrayList<>();
+        for (HistoricTaskInstance task : taskList) {
+            Map<String, Object> variables = task.getProcessVariables();
+            BaseTaskEntity baseTaskEntity = JSONObject
+                    .parseObject(variables.get(Constant.ACT_BASE_TASK).toString(), BaseTaskEntity.class);
+            HistoryTaskVO taskVO = new HistoryTaskVO(task);
+            taskVO.setUserName(baseTaskEntity.getUserName());
+            taskVO.setRemarks(baseTaskEntity.getRemarks());
+            taskVO.setTaskUrl(String.format("%s/%s", baseTaskEntity.getFormKey(), baseTaskEntity.getId()));
+            taskVO.setProcessDefinitionKey(baseTaskEntity.getProcessKey());
+            taskVO.setProcessDefinitionName(baseTaskEntity.getProcessInstanceName());
+            taskVO.setApproveName(DictEnum.getValue(DictModelConstant.MODEL_APPLY_CONFIG,
+                    DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, baseTaskEntity.getFormKey()));
+            if (StringUtils.isNotEmpty(baseTaskEntity.getResult())) {
+                taskVO.setResultStr(DictEnum.getValue(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_RESULT, baseTaskEntity.getResult()));
+            }
+            Map<String, Object> param = baseTaskEntity.getParam();
+            if (StringUtils.isNotEmpty(param)) {
+                taskVO.setParam(param);
+            }
+            //我审批的结果
+            Object opinionStr = variables.get(Constant.ACT_APPLY_OPINION_LIST);
+            if (null != opinionStr) {
+                List<ApprovalOpinionVO> approvalOpinionVOS = JSONArray
+                        .parseArray(opinionStr.toString(), ApprovalOpinionVO.class);
+                for (ApprovalOpinionVO approvalOpinionVO : approvalOpinionVOS) {
+                    if (task.getId().equals(approvalOpinionVO.getTaskId()) && approvalOpinionVO.getOpId().equals(userId)) {
+                        taskVO.setResult(approvalOpinionVO.getFlag());
+                    }
+                }
+            }
+            tasks.add(taskVO);
+        }
+
+        IPage<HistoryTaskVO> page = new Page<>(pageNo,pageSize);
+        page.setTotal((int) historicTaskInstanceQuery.count());
+
+        return page.setRecords(tasks);
+    }
+
+    /**
+     * 我发起的流程
+     *
+     * @return
+     * processInstanceTenantId(UserUtils.getTenantId())
+     */
+
+    @Override
+    public IPage listApprovalMyStarted(Integer pageNo, Integer pageSize, HttpServletRequest req) {
+
+        //获取当前登录人
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String tenantId = req.getHeader("tenant-id");
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
+                .startedBy(sysUser.getId())
+                .orderByProcessInstanceStartTime()
+                .processInstanceTenantId(tenantId)
+                .desc()
+                .includeProcessVariables();
+        List<HistoricProcessInstance> processInstances = historicProcessInstanceQuery.listPage((pageNo - 1) * pageSize, pageSize);
+
+        List<HistoryTaskVO> tasks = Lists.newArrayList();
+        for (HistoricProcessInstance processInstance : processInstances) {
+
+            BaseTaskEntity baseTaskEntity = JSONObject
+                    .parseObject(processInstance.getProcessVariables().get(Constant.ACT_BASE_TASK).toString(), BaseTaskEntity.class);
+
+            HistoryTaskVO taskVO = new HistoryTaskVO();
+            taskVO.setId(processInstance.getId());
+            taskVO.setProcessInstanceId(processInstance.getId());
+            taskVO.setTaskNodeName("");
+            taskVO.setCreateTime(processInstance.getStartTime());
+            taskVO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
+            taskVO.setProcessDefinitionKey(baseTaskEntity.getProcessKey());
+            taskVO.setProcessDefinitionName(baseTaskEntity.getProcessInstanceName());
+            taskVO.setUserName(baseTaskEntity.getUserName());
+            taskVO.setRemarks(baseTaskEntity.getRemarks());
+            taskVO.setTaskUrl(String.format("%s/%s", baseTaskEntity.getFormKey(), baseTaskEntity.getId()));
+            taskVO.setApproveName(DictEnum.getValue(DictModelConstant.MODEL_APPLY_CONFIG,
+                    DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, baseTaskEntity.getFormKey()));
+            Map<String, Object> param = baseTaskEntity.getParam();
+            if (StringUtils.isNotEmpty(param)) {
+                taskVO.setParam(param);
+            }
+            //判断流程是否结束
+            wrapperInfoByProcessStatus(processInstance, taskVO);
+            tasks.add(taskVO);
+        }
+        IPage<HistoryTaskVO> page = new Page<>(pageNo,pageSize);
+        page.setTotal(historicProcessInstanceQuery.count());
+        page.setRecords(tasks);
+        return page;
+    }
+
+    private void wrapperInfoByProcessStatus(HistoricProcessInstance processInstance, HistoryTaskVO taskVO) {
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+        ProcessInstance pi = runtimeService.createProcessInstanceQuery()
+                .processInstanceId(processInstance.getId())
+                .processInstanceTenantId(processInstance.getTenantId())
+                .singleResult();
+        if (null == pi) {
+            Object flagObj = processInstance.getProcessVariables().get(Constant.ACT_TASK_FLAG);
+            String flag = "";
+            String result = DictEnum.APPLY_RESULT_PROCESSING.getKey();
+            if (null == flagObj) {
+                result = DictEnum.APPLY_RESULT_CANCEL.getKey();
+            } else {
+                flag = flagObj.toString();
+            }
+            if (DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey().equals(flag)) {
+                result = DictEnum.APPLY_RESULT_REFUSE.getKey();
+            } else if (DictEnum.Apply_APPROVAL_OPINION_AGREE.getKey().equals(flag)) {
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            } else if (DictEnum.APPLY_APPROVAL_OPINION_ABANDON.getKey().equals(flag)) {
+                result = DictEnum.APPLY_RESULT_CANCEL.getKey();
+            } else if (DictEnum.APPLY_APPROVAL_OPINION_CONFIRM.getKey().equals(flag)) {
+                result = DictEnum.APPLY_RESULT_AGREE.getKey();
+            }
+            taskVO.setResult(result);
+            if (StringUtils.isNotEmpty(result)) {
+                taskVO.setResultStr(DictEnum.getValue(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_RESULT, result));
+            }
+            taskVO.setId("");
+            taskVO.setFinished(true);
+        } else {
+            taskVO.setFinished(false);
+            TaskQuery taskQuery = taskService.createTaskQuery()
+                    .processInstanceId(processInstance.getId());
+            List<Task> list = taskQuery.list();
+
+            for (Task task : list) {
+                if (null != task) {
+                    taskVO.setId(task.getId());
+                    taskVO.setTaskNodeName(task.getName());
+                    taskVO.setAssignee(task.getAssignee());
+                }
+            }
+        }
+    }
+
+    /**
+     * 任务明细
+     *
+     * @param taskId
+     * @return
+     */
+    @Override
+    public Object getTask(String taskId) {
+        Map<String, Object> variables = taskService.getVariables(taskId);
+        BaseTaskEntity baseTask = (BaseTaskEntity) variables.get(Constant.ACT_BASE_TASK);
+        return baseTask;
+    }
+
+    /**
+     * 追踪流程图片
+     *
+     * @param processInstanceId
+     * @return
+     * @throws Exception
+     */
+    @Override
+    public byte[] getProcessImage(String processInstanceId) throws Exception {
+        // 获取历史流程实例
+        HistoricProcessInstance historicProcessInstance =
+                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+        if (historicProcessInstance == null) {
+            throw new Exception();
+        } else {
+            // 获取流程定义
+            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
+                    .getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
+
+            // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
+            List<HistoricActivityInstance> historicActivityInstanceList =
+                    historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
+                            .orderByHistoricActivityInstanceId().desc().list();
+            // 已执行的节点ID集合
+            List<String> executedActivityIdList = new ArrayList<>();
+            for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
+                if ("userTask".equals(activityInstance.getActivityType()) && StringUtils.isNull(activityInstance.getEndTime())) {
+                    executedActivityIdList.add(activityInstance.getActivityId() + "#");
+                } else {
+                    executedActivityIdList.add(activityInstance.getActivityId());
+                }
+            }
+            // 获取流程图图像字符流
+            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
+
+            // 通过流程实例ID获取流程中 正在执行的节点
+            List<String> runningActivitiIdList = new ArrayList<String>();
+            List<Execution> runningActivityInstanceList = getRunningActivityInst(processInstanceId);
+            for (Execution execution : runningActivityInstanceList) {
+                if (StringUtils.isNotEmpty(execution.getActivityId())) {
+                    runningActivitiIdList.add(execution.getActivityId());
+                }
+            }
+
+            // 已执行flow的集和
+            List<String> executedFlowIdList = getHighLightedFlows(bpmnModel, historicActivityInstanceList);
+
+            // 定义流程画布生成器
+            // 如果完成,流程图高亮颜色为绿色,如果没有已经完成为红色
+            ProcessDiagramGenerator processDiagramGenerator = new CustomProcessDiagramGenerator();
+
+            // 使用默认配置获得流程图表生成器,并生成追踪图片字符流
+            InputStream imageStream = ((CustomProcessDiagramGenerator) processDiagramGenerator)
+               .generateDiagramCustom(bpmnModel, "png",
+                  executedActivityIdList, runningActivitiIdList, executedFlowIdList,
+                  "宋体", "微软雅黑", "黑体",
+                  null, 2.0);
+            // 将InputStream数据流转换为byte[]
+            byte[] buffer = new byte[imageStream.available()];
+            imageStream.read(buffer);
+            imageStream.close();
+            return buffer;
+        }
+    }
+
+    /**
+     * Desc: 通过流程实例ID获取流程中正在执行的节点
+     *
+     * @param procInstId
+     * @return
+     * @author liuxz
+     */
+    public List<Execution> getRunningActivityInst(String procInstId) {
+        return runtimeService.createExecutionQuery().processInstanceId(procInstId).list();
+    }
+
+    /**
+     * 获取已经流转的线
+     *
+     * @param bpmnModel
+     * @param historicActivityInstances
+     * @return
+     */
+    private static List<String> getHighLightedFlows(BpmnModel bpmnModel,
+                                                    List<HistoricActivityInstance> historicActivityInstances) {
+        // 高亮流程已发生流转的线id集合
+        List<String> highLightedFlowIds = new ArrayList<>();
+        // 全部活动节点
+        List<FlowNode> historicActivityNodes = new ArrayList<>();
+        // 已完成的历史活动节点
+        List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();
+
+        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
+            FlowNode flowNode =
+               (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
+            historicActivityNodes.add(flowNode);
+            if (historicActivityInstance.getEndTime() != null) {
+                finishedActivityInstances.add(historicActivityInstance);
+            }
+        }
+
+        FlowNode currentFlowNode = null;
+        FlowNode targetFlowNode = null;
+        // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
+        for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
+            // 获得当前活动对应的节点信息及outgoingFlows信息
+            currentFlowNode =
+               (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
+            List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
+
+            /**
+             * 遍历outgoingFlows并找到已已流转的 满足如下条件认为已已流转: 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
+             * 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
+             */
+            if ("parallelGateway".equals(currentActivityInstance.getActivityType())
+               || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
+                // 遍历历史活动节点,找到匹配流程目标节点的
+                for (SequenceFlow sequenceFlow : sequenceFlows) {
+                    targetFlowNode =
+                       (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
+                    if (historicActivityNodes.contains(targetFlowNode)) {
+                        highLightedFlowIds.add(targetFlowNode.getId());
+                    }
+                }
+            } else {
+                List<Map<String, Object>> tempMapList = new ArrayList<>();
+                for (SequenceFlow sequenceFlow : sequenceFlows) {
+                    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
+                        if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
+                            Map<String, Object> map = new HashMap<>();
+                            map.put("highLightedFlowId", sequenceFlow.getId());
+                            map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
+                            tempMapList.add(map);
+                        }
+                    }
+                }
+
+                if (!CollectionUtils.isEmpty(tempMapList)) {
+                    // 遍历匹配的集合,取得开始时间最早的一个
+                    long earliestStamp = 0L;
+                    String highLightedFlowId = null;
+                    for (Map<String, Object> map : tempMapList) {
+                        long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
+                        if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
+                            highLightedFlowId = map.get("highLightedFlowId").toString();
+                            earliestStamp = highLightedFlowStartTime;
+                        }
+                    }
+
+                    highLightedFlowIds.add(highLightedFlowId);
+                }
+
+            }
+
+        }
+        return highLightedFlowIds;
+    }
+
+
+    @Override
+    public long countUnprocessed() {
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        return taskService.createTaskQuery().
+                taskCandidateOrAssigned(sysUser.getId())
+                .count();
+    }
+
+    @Override
+    public long countMyStarted() {
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        return historyService.createHistoricProcessInstanceQuery()
+                .startedBy(sysUser.getId())
+                .count();
+    }
+
+    /**
+     * 我审批的
+     *
+     * @param
+     * @param param
+     * @return
+     */
+    @Override
+    public IPage listApiMyApproval(Map<String, String> params, ApprovalTaskQueryVo param) {
+
+        int pageNo = Integer.parseInt( params.get("pageNo"));
+        int pageSize = Integer.parseInt( params.get("pageSize"));
+
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+        String formType = param.getFormType();
+        String status = param.getStatus();
+        boolean processed = param.isProcessed();
+
+        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
+        historicTaskInstanceQuery
+                .includeProcessVariables()
+                .taskAssignee(sysUser.getId())
+                .orderByTaskCreateTime()
+                .desc();
+
+        if (StringUtils.isNotEmpty(formType)) {
+            historicTaskInstanceQuery.processInstanceBusinessKeyLikeIgnoreCase(formType + "/%");
+        }
+
+        if (processed) {
+            historicTaskInstanceQuery.finished();
+            //流程状态
+            if (StringUtils.isNotEmpty(status)) {
+                if (Constant.ACT_TASK_QUERY_STATUS_RUN.equals(status)) {
+                    historicTaskInstanceQuery.processUnfinished();
+                } else if (Constant.ACT_TASK_STATUS_END.equals(status)) {
+                    historicTaskInstanceQuery.processFinished();
+                }
+            }
+        } else {
+            historicTaskInstanceQuery.unfinished();
+        }
+
+        List<HistoricTaskInstance> taskList = historicTaskInstanceQuery
+                .listPage( (pageNo - 1) * pageSize, pageSize);
+
+        List<HistoryTaskVO> tasks = new ArrayList<>();
+        HistoryTaskVO taskVO = null;
+        for (HistoricTaskInstance task : taskList) {
+            BaseTaskEntity baseTaskEntity = JSONObject
+                    .parseObject(task.getProcessVariables().get(Constant.ACT_BASE_TASK).toString(), BaseTaskEntity.class);
+            taskVO = new HistoryTaskVO(task);
+            taskVO.setUserName(baseTaskEntity.getUserName());
+            taskVO.setRemarks(baseTaskEntity.getRemarks());
+            taskVO.setTaskUrl(String.format("%s/%s", baseTaskEntity.getFormKey(), baseTaskEntity.getId()));
+            taskVO.setProcessDefinitionKey(baseTaskEntity.getProcessKey());
+            taskVO.setProcessDefinitionName(baseTaskEntity.getProcessInstanceName());
+            taskVO.setApproveName(DictEnum.getValue(DictModelConstant.MODEL_APPLY_CONFIG,
+                    DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, baseTaskEntity.getFormKey()));
+
+            //我审批的结果
+            Object o = task.getProcessVariables().get(Constant.ACT_APPLY_OPINION_LIST);
+            if (null != o) {
+                List<ApprovalOpinionVO> approvalOpinionVOS = JSONArray
+                        .parseArray(o.toString(), ApprovalOpinionVO.class);
+                for (ApprovalOpinionVO approvalOpinionVO : approvalOpinionVOS) {
+                    if (task.getId().equals(approvalOpinionVO.getTaskId()) && approvalOpinionVO.getOpId().equals(sysUser.getId())) {
+                        taskVO.setResult(approvalOpinionVO.getFlag());
+                        taskVO.setResultStr(DictEnum.getValue(DictModelConstant.MODEL_APPLY,DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG,approvalOpinionVO.getFlag()));
+                    }
+                }
+            }
+            //流程是否结束标识
+            taskVO.setFinished(!approvalService.getApprovalStatus(task.getProcessInstanceId()));
+            tasks.add(taskVO);
+        }
+
+        IPage<HistoryTaskVO> page = new Page(pageNo, pageSize);
+        page.setTotal(historicTaskInstanceQuery.count());
+        return page.setRecords(tasks);
+    }
+
+    /**
+     * 我发起的
+     *
+     * @param
+     * @param param
+     * @return
+     */
+    @Override
+    public IPage listApiMyStarted(Map<String, String> params, ApprovalTaskQueryVo param) {
+
+        int pageNo = Integer.parseInt( params.get("pageNo"));
+        int pageSize = Integer.parseInt( params.get("pageSize"));
+
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String status = param.getStatus();
+        String formType = param.getFormType();
+
+        //我发起的
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
+        historicProcessInstanceQuery
+                .includeProcessVariables()
+                .startedBy(sysUser.getId())
+                .orderByProcessInstanceStartTime()
+                .desc();
+
+        List<HistoryTaskVO> tasks = new ArrayList<>();
+        if (StringUtils.isNotEmpty(formType)) {
+            List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
+                    .processInstanceBusinessKeyLike(formType + "/%")
+                    .list();
+            Set<String> collect = list.stream().map(TaskInfo::getProcessInstanceId).collect(Collectors.toSet());
+            if (StringUtils.isNotEmpty(collect)) {
+                historicProcessInstanceQuery.processInstanceIds(collect);
+            } else {
+                IPage<HistoryTaskVO> page = new Page(pageNo, pageSize);
+                page.setTotal(0);
+            }
+        }
+
+        if (StringUtils.isNotEmpty(status)) {
+            if (status.equals(Constant.ACT_TASK_STATUS_END)) {
+                historicProcessInstanceQuery.finished();
+            } else if (status.equals(Constant.ACT_TASK_QUERY_STATUS_RUN)) {
+                historicProcessInstanceQuery.unfinished();
+            }
+        }
+
+        List<HistoricProcessInstance> processInstances = historicProcessInstanceQuery
+                .listPage((pageNo - 1) * pageSize, pageSize);
+
+        for (HistoricProcessInstance processInstance : processInstances) {
+            BaseTaskEntity baseTaskEntity = JSONObject
+                    .parseObject(processInstance.getProcessVariables().get(Constant.ACT_BASE_TASK).toString(), BaseTaskEntity.class);
+
+            HistoryTaskVO taskVO = new HistoryTaskVO();
+            taskVO.setId(processInstance.getId());
+            taskVO.setProcessInstanceId(processInstance.getId());
+
+            taskVO.setTaskNodeName("");
+            taskVO.setCreateTime(processInstance.getStartTime());
+            taskVO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
+            taskVO.setProcessDefinitionKey(baseTaskEntity.getProcessKey());
+            taskVO.setProcessDefinitionName(baseTaskEntity.getProcessInstanceName());
+            taskVO.setUserName(baseTaskEntity.getUserName());
+            taskVO.setRemarks(baseTaskEntity.getRemarks());
+            taskVO.setTaskUrl(String.format("%s/%s", baseTaskEntity.getFormKey(), baseTaskEntity.getId()));
+            taskVO.setApproveName(DictEnum.getValue(DictModelConstant.MODEL_APPLY_CONFIG,
+                    DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, baseTaskEntity.getFormKey()));
+
+            //我发起的流程审批结果
+            if (status.equals(Constant.ACT_TASK_STATUS_END)) {
+                taskVO.setResult(processInstance.getProcessVariables().get(Constant.ACT_TASK_FLAG).toString());
+                taskVO.setFinished(true);
+            } else {
+                wrapperInfoByProcessStatus(processInstance, taskVO);
+            }
+            tasks.add(taskVO);
+        }
+
+        IPage<HistoryTaskVO> page = new Page(pageNo, pageSize);
+        page.setTotal(historicProcessInstanceQuery.count());
+        return page.setRecords(tasks);
+    }
+
+
+    @Override
+    public TaskVO getMyApprovalTask(String processInstanceId) {
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        Task task = taskService.createTaskQuery()
+                .processInstanceId(processInstanceId)
+                .taskCandidateOrAssigned(sysUser.getId())
+                .includeProcessVariables()
+                .singleResult();
+        if (task == null) {
+            return null;
+        }
+
+        TaskVO taskVO = new TaskVO(task);
+        Map<String, Object> processVariableMap = task.getProcessVariables();
+        BaseTaskEntity baseTaskEntity = JSONObject.parseObject(processVariableMap.get(Constant.ACT_BASE_TASK).toString(), BaseTaskEntity.class);
+        taskVO.setTaskUrl(String.format("%s/%s", baseTaskEntity.getFormKey(), baseTaskEntity.getId()));
+        taskVO.setProcessDefinitionKey(baseTaskEntity.getProcessKey());
+        taskVO.setProcessDefinitionName(baseTaskEntity.getProcessInstanceName());
+        taskVO.setApproveName(DictEnum.getValue(DictModelConstant.MODEL_APPLY_CONFIG,
+                DictModelConstant.MODEL_APPLY_CONFIG_FORMKEY, baseTaskEntity.getFormKey()));
+        return taskVO;
+    }
+
+    @Override
+    public List<ApprovalOpinionDTO> listOpinionsByPId(String processInstanceId) {
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .includeProcessVariables()
+                .singleResult();
+        if (historicProcessInstance == null) {
+            return Lists.newArrayList();
+        }
+        Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
+        Object obj = processVariables.get(Constant.ACT_APPLY_OPINION_LIST);
+        if (StringUtils.isNull(obj)) {
+            return Lists.newArrayList();
+        }
+        List<ApprovalOpinionDTO> approvalOpinionDTOS = JSONArray.parseArray(obj.toString(), ApprovalOpinionDTO.class);
+
+        for (ApprovalOpinionDTO approvalOpinionDTO : approvalOpinionDTOS) {
+            approvalOpinionDTO.setFlagStr(DictEnum.getValue(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG, approvalOpinionDTO.getFlag()));
+        }
+        //获取审批结果 并修改样式
+        for (ApprovalOpinionDTO approvalOpinionDTO : approvalOpinionDTOS) {
+            if (StringUtils.isEmpty(approvalOpinionDTO.getFlagStr())) {
+                approvalOpinionDTO.setFlagStr(DictEnum.getValue(DictModelConstant.MODEL_APPLY, DictModelConstant.MODEL_APPLY_APPROVAL_OPINION_FLAG, approvalOpinionDTO.getFlag()));
+            }
+            List<String> rejectStyle = Lists.newArrayList(DictEnum.Apply_APPROVAL_OPINION_REFUSE.getKey(),
+                    DictEnum.APPLY_APPROVAL_OPINION_REJECT.getKey(),
+                    DictEnum.APPLY_APPROVAL_OPINION_ABANDON.getKey());
+            String style= rejectStyle.contains(approvalOpinionDTO.getFlag())?"error":"success";
+            approvalOpinionDTO.setStyle(style);
+        }
+
+        return approvalOpinionDTOS;
+    }
+}

+ 33 - 0
itdmServer/module-ACTIVITI/src/main/java/org/jeecg/modules/system/controller/SystemController.java

@@ -0,0 +1,33 @@
+package org.jeecg.modules.system.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 工作流查询
+ * 查询系统信息
+ * @author czm
+ * @date 2021/8/17 16:24
+ */
+@RestController
+@Slf4j
+@RequestMapping("/actSystem")
+public class SystemController {
+
+   @Autowired
+   private ISysBaseAPI iSysBaseAPI;
+
+   /**
+    * 查询当前系统的用户
+    */
+   public Result getSysUserList(String keyword,Integer page,Integer limit){
+
+      return Result.OK();
+   }
+
+}

File diff suppressed because it is too large
+ 76 - 0
itdmServer/module-ACTIVITI/src/main/resources/processes/会议室预约申请bak20200914.bpmn20.xml


File diff suppressed because it is too large
+ 1080 - 0
itdmServer/module-ACTIVITI/src/main/resources/processes/投稿bak20200915.bpmn20.xml


File diff suppressed because it is too large
+ 165 - 0
itdmServer/module-ACTIVITI/src/main/resources/processes/报修bak20200914.bpmn20.xml


File diff suppressed because it is too large
+ 208 - 0
itdmServer/module-ACTIVITI/src/main/resources/processes/物品领用bak20200914.bpmn20.xml


File diff suppressed because it is too large
+ 191 - 0
itdmServer/module-ACTIVITI/src/main/resources/processes/财务预算bak20200914.bpmn20.xml


File diff suppressed because it is too large
+ 803 - 0
itdmServer/module-ACTIVITI/src/main/resources/processes/采购验收bak20200914.bpmn20.xml


File diff suppressed because it is too large
+ 2677 - 0
itdmServer/module-ACTIVITI/src/main/resources/static/stencilset.json


+ 1 - 0
itdmServer/pom.xml

@@ -69,6 +69,7 @@
 	<modules>
         <module>jeecg-boot-base-core</module>
         <module>module-iTDM</module>
+        <module>module-ACTIVITI</module>
         <module>jeecg-module-system</module>
 	</modules>
 

+ 253 - 0
logs/error-log.html

@@ -0,0 +1,253 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+  <head>
+    <title>Logback Log Messages</title>
+<style  type="text/css">
+table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }
+TR.even { background: #FFFFFF; }
+TR.odd { background: #EAEAEA; }
+TR.warn TD.Level, TR.error TD.Level, TR.fatal TD.Level {font-weight: bold; color: #FF4040 }
+TD { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }
+TD.Time, TD.Date { text-align: right; font-family: courier, monospace; font-size: smaller; }
+TD.Thread { text-align: left; }
+TD.Level { text-align: right; }
+TD.Logger { text-align: left; }
+TR.header { background: #596ED5; color: #FFF; font-weight: bold; font-size: larger; }
+TD.Exception { background: #A2AEE8; font-family: courier, monospace;}
+</style>
+
+  </head>
+<body>
+<hr/>
+<p>Log session start time Fri May 19 13:22:23 CST 2023</p><p></p>
+
+<table cellspacing="0">
+<tr class="header">
+<td class="Level">Level</td>
+<td class="Date">Date</td>
+<td class="Message">Message</td>
+<td class="MethodOfCaller">MethodOfCaller</td>
+<td class="FileOfCaller">FileOfCaller</td>
+<td class="LineOfCaller">LineOfCaller</td>
+</tr>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+  <head>
+    <title>Logback Log Messages</title>
+<style  type="text/css">
+table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }
+TR.even { background: #FFFFFF; }
+TR.odd { background: #EAEAEA; }
+TR.warn TD.Level, TR.error TD.Level, TR.fatal TD.Level {font-weight: bold; color: #FF4040 }
+TD { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }
+TD.Time, TD.Date { text-align: right; font-family: courier, monospace; font-size: smaller; }
+TD.Thread { text-align: left; }
+TD.Level { text-align: right; }
+TD.Logger { text-align: left; }
+TR.header { background: #596ED5; color: #FFF; font-weight: bold; font-size: larger; }
+TD.Exception { background: #A2AEE8; font-family: courier, monospace;}
+</style>
+
+  </head>
+<body>
+<hr/>
+<p>Log session start time Fri May 19 13:31:24 CST 2023</p><p></p>
+
+<table cellspacing="0">
+<tr class="header">
+<td class="Level">Level</td>
+<td class="Date">Date</td>
+<td class="Message">Message</td>
+<td class="MethodOfCaller">MethodOfCaller</td>
+<td class="FileOfCaller">FileOfCaller</td>
+<td class="LineOfCaller">LineOfCaller</td>
+</tr>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+  <head>
+    <title>Logback Log Messages</title>
+<style  type="text/css">
+table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }
+TR.even { background: #FFFFFF; }
+TR.odd { background: #EAEAEA; }
+TR.warn TD.Level, TR.error TD.Level, TR.fatal TD.Level {font-weight: bold; color: #FF4040 }
+TD { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }
+TD.Time, TD.Date { text-align: right; font-family: courier, monospace; font-size: smaller; }
+TD.Thread { text-align: left; }
+TD.Level { text-align: right; }
+TD.Logger { text-align: left; }
+TR.header { background: #596ED5; color: #FFF; font-weight: bold; font-size: larger; }
+TD.Exception { background: #A2AEE8; font-family: courier, monospace;}
+</style>
+
+  </head>
+<body>
+<hr/>
+<p>Log session start time Fri May 19 13:45:28 CST 2023</p><p></p>
+
+<table cellspacing="0">
+<tr class="header">
+<td class="Level">Level</td>
+<td class="Date">Date</td>
+<td class="Message">Message</td>
+<td class="MethodOfCaller">MethodOfCaller</td>
+<td class="FileOfCaller">FileOfCaller</td>
+<td class="LineOfCaller">LineOfCaller</td>
+</tr>
+
+</table>
+</body></html><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+  <head>
+    <title>Logback Log Messages</title>
+<style  type="text/css">
+table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }
+TR.even { background: #FFFFFF; }
+TR.odd { background: #EAEAEA; }
+TR.warn TD.Level, TR.error TD.Level, TR.fatal TD.Level {font-weight: bold; color: #FF4040 }
+TD { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }
+TD.Time, TD.Date { text-align: right; font-family: courier, monospace; font-size: smaller; }
+TD.Thread { text-align: left; }
+TD.Level { text-align: right; }
+TD.Logger { text-align: left; }
+TR.header { background: #596ED5; color: #FFF; font-weight: bold; font-size: larger; }
+TD.Exception { background: #A2AEE8; font-family: courier, monospace;}
+</style>
+
+  </head>
+<body>
+<hr/>
+<p>Log session start time Fri May 19 14:12:36 CST 2023</p><p></p>
+
+<table cellspacing="0">
+<tr class="header">
+<td class="Level">Level</td>
+<td class="Date">Date</td>
+<td class="Message">Message</td>
+<td class="MethodOfCaller">MethodOfCaller</td>
+<td class="FileOfCaller">FileOfCaller</td>
+<td class="LineOfCaller">LineOfCaller</td>
+</tr>
+
+
+<tr class="error even">
+<td class="Level">ERROR</td>
+<td class="Date">2023-05-19 14:37:49,554</td>
+<td class="Message">文件[temp/海检版报告温度试验中文_1684472826828.docx]不存在..</td>
+<td class="MethodOfCaller">handleException</td>
+<td class="FileOfCaller">JeecgBootExceptionHandler.java</td>
+<td class="LineOfCaller">79</td>
+</tr>
+<tr><td class="Exception" colspan="6">java.lang.RuntimeException: 文件[temp/海检版报告温度试验中文_1684472826828.docx]不存在..
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.jeecg.modules.system.controller.CommonController.view(CommonController.java:229)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.jeecg.modules.system.controller.CommonController$$FastClassBySpringCGLIB$$669ac3eb.invoke(&lt;generated&gt;)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.jeecg.common.aspect.DictAspect.doAround(DictAspect.java:62)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at sun.reflect.GeneratedMethodAccessor271.invoke(Unknown Source)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at java.lang.reflect.Method.invoke(Method.java:498)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.jeecg.modules.system.controller.CommonController$$EnhancerBySpringCGLIB$$29b36005.view(&lt;generated&gt;)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at java.lang.reflect.Method.invoke(Method.java:498)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.jeecg.modules.online.low.aspect.a.doFilterInternal(LowAppFilter.java:50)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:458)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:373)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:370)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
+<br />&nbsp;&nbsp;&nbsp;&nbsp;at java.lang.Thread.run(Thread.java:750)
+</td></tr></table>
+</body></html>

File diff suppressed because it is too large
+ 6115 - 0
logs/jeecgboot-2023-05-19.0.html


File diff suppressed because it is too large
+ 860 - 0
logs/jeecgboot-2023-05-19.0.log