ソースを参照

访问其他业务系统

sangwenwei 1 年間 前
コミット
0e4b3631b4
32 ファイル変更4072 行追加183 行削除
  1. 5 0
      jeeplus-modules/jeeplus-flowable/pom.xml
  2. 43 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/config/RestTemplateConfig.java
  3. 68 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/CcpmController.java
  4. 41 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/FlowController.java
  5. 92 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/ReimbursementController.java
  6. 54 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/TestController.java
  7. 85 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/InvoiceDto.java
  8. 41 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementAmountInfo.java
  9. 96 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfo.java
  10. 94 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfoContract.java
  11. 98 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfoOther.java
  12. 93 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfoProcured.java
  13. 94 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/SaveInfoDto.java
  14. 17 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/WorkAttachmentDto.java
  15. 74 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/WorkInvoiceDetail.java
  16. 72 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/enums/TaskAliasEnum.java
  17. 133 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/CcpmRequest.java
  18. 111 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/CcpmService.java
  19. 122 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/flow/FlowRequest.java
  20. 50 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/flow/FlowService.java
  21. 163 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/reimbursement/ReimbursementService.java
  22. 531 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/ConvertServiceUtil.java
  23. 544 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/GenerateFormUtil.java
  24. 483 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/Global.java
  25. 154 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/PropertiesLoader.java
  26. 266 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/RestTemplateService.java
  27. 422 180
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/controller/FlowableTaskController.java
  28. 3 3
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/service/FlowTaskService.java
  29. 4 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/vo/HisTaskVo.java
  30. 2 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/vo/ProcessVo.java
  31. 3 0
      jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/vo/TaskVo.java
  32. 14 0
      jeeplus-modules/jeeplus-flowable/src/main/resources/bootstrap.yml

+ 5 - 0
jeeplus-modules/jeeplus-flowable/pom.xml

@@ -151,6 +151,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 43 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/config/RestTemplateConfig.java

@@ -0,0 +1,43 @@
+package com.jeeplus.centerservice.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+public class RestTemplateConfig {
+
+    @Bean
+    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
+        RestTemplate restTemplate = new RestTemplate(factory);
+        restTemplate.getMessageConverters().add(new WxMappingJackson2HttpMessageConverter());
+        return restTemplate;
+    }
+
+    @Bean
+    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
+        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+        factory.setConnectTimeout(15000); // 连接超时时间 (两端连接时间) 15秒
+        factory.setReadTimeout(50000); // 访问超时时间 (建立连接后从另一端读取资源所用时间) 5秒
+        // 设置代理
+        //factory.setProxy(null);
+        return factory;
+    }
+
+    public class WxMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
+        public WxMappingJackson2HttpMessageConverter(){
+            List<MediaType> mediaTypes = new ArrayList<>();
+            mediaTypes.add(MediaType.TEXT_PLAIN);
+            mediaTypes.add(MediaType.TEXT_HTML);
+//            mediaTypes.add(new MediaType("text", "plain", StandardCharsets.UTF_8));
+            setSupportedMediaTypes(mediaTypes);
+        }
+    }
+}

+ 68 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/CcpmController.java

@@ -0,0 +1,68 @@
+package com.jeeplus.centerservice.controller.ccpm;
+
+import com.jeeplus.centerservice.service.ccpm.CcpmService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/ccpm_control")
+public class CcpmController {
+
+
+    @Resource
+    private CcpmService ccpmService;
+
+    /**
+     * 查询流程详情
+     * @param id
+     * @return
+     */
+    @GetMapping("getByIdGenerate")
+    public ResponseEntity getByIdGenerate(String id, String processDefKey) {
+        Map<String, Object> res = ccpmService.getByIdGenerate(id, processDefKey);
+        return ResponseEntity.ok (res);
+    }
+
+    /**
+     * 报销审核
+     * @param id
+     * @param flag yes 审核通过 no 审核失败
+     * @param comment 审批意见
+     * @param processDefKey 流程类型
+     * @return
+     */
+    @GetMapping("reimAudit")
+    public ResponseEntity reimAudit(String id, String flag, String comment, String processDefKey) {
+        Map<String, Object> resultMap = this.ccpmService.reimAudit(id, flag, comment, processDefKey);
+        return ResponseEntity.ok (resultMap);
+    }
+
+    /**
+     * 报销重新申请
+     * @param id
+     * @return
+     */
+    @GetMapping("reimReapply")
+    public ResponseEntity reimReapply(String id, String processDefKey) {
+        Map<String, Object> resultMap = this.ccpmService.reimAudit(id, "yes", null, processDefKey);
+        return ResponseEntity.ok (resultMap);
+    }
+
+    /**
+     * 报销申请删除
+     * @param id
+     * @return
+     */
+    @GetMapping("deleteReim")
+    public ResponseEntity deleteReim(String id) {
+        Map<String, Object> resultMap = this.ccpmService.deleteReim(id);
+        return ResponseEntity.ok (resultMap);
+    }
+
+
+}

+ 41 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/FlowController.java

@@ -0,0 +1,41 @@
+package com.jeeplus.centerservice.controller.ccpm;
+
+import com.jeeplus.centerservice.service.ccpm.flow.FlowService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("ccpm_flow")
+public class FlowController {
+
+    @Resource
+    private FlowService flowService;
+
+    /**
+     * 获取流程历史
+     * @param procInsId
+     * @return
+     */
+    @GetMapping("getHistoicFlowList")
+    public ResponseEntity getHistoicFlowList(String procInsId) {
+        List<Map<String, Object>> histoicFlowList = flowService.getHistoicFlowList(procInsId);
+        return ResponseEntity.ok (histoicFlowList);
+    }
+
+    /**
+     * 获取流程流向图
+     * @param procInsId
+     * @return
+     */
+    @GetMapping("getFlowChart")
+    public ResponseEntity getFlowChart(String procInsId) {
+        List<Map<String, Object>> flowChart = flowService.getFlowChart(procInsId);
+        return ResponseEntity.ok (flowChart);
+    }
+}

+ 92 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/ReimbursementController.java

@@ -0,0 +1,92 @@
+package com.jeeplus.centerservice.controller.ccpm;
+
+import com.jeeplus.centerservice.dto.SaveInfoDto;
+import com.jeeplus.centerservice.service.ccpm.reimbursement.ReimbursementService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/ccpm_reimbursement")
+public class ReimbursementController {
+
+
+    @Resource
+    private ReimbursementService reimbursementService;
+
+    /**
+     * 根据id查询报销详情
+     * @param id
+     * @return
+     */
+    @GetMapping("getReimbursementById")
+    public ResponseEntity getReimbursementById(String id, String processDefKey) {
+        SaveInfoDto saveInfoDto = reimbursementService.getReimbursementById(id, processDefKey);
+        return ResponseEntity.ok (saveInfoDto);
+    }
+
+    /**
+     * 报销审核
+     * @param id
+     * @param flag yes 审核通过 no 审核失败
+     * @param comment 审批意见
+     * @param processDefKey 流程类型
+     * @return
+     */
+    @GetMapping("reimAudit")
+    public ResponseEntity reimAudit(String id, String flag, String comment, String processDefKey) {
+        Map<String, Object> resultMap = this.reimbursementService.reimAudit(id, flag, comment, processDefKey);
+        return ResponseEntity.ok (resultMap);
+    }
+
+    /**
+     * 开票审核
+     * @param id
+     * @param flag yes 审核通过 no 审核失败
+     * @param comment 审批意见
+     * @param processDefKey 流程类型
+     * @return
+     */
+    @GetMapping("invoiceAudit")
+    public ResponseEntity invoiceAudit(String id, String flag, String comment, String processDefKey,String jsonData) {
+        Map<String, Object> resultMap = this.reimbursementService.invoiceAudit(id, flag, comment, processDefKey,jsonData);
+        return ResponseEntity.ok (resultMap);
+    }
+
+    /**
+     * 报销重新申请
+     * @param id
+     * @return
+     */
+    @GetMapping("reimReapply")
+    public ResponseEntity reimReapply(String id, String processDefKey) {
+        Map<String, Object> resultMap = this.reimbursementService.reimAudit(id, "yes", null, processDefKey);
+        return ResponseEntity.ok (resultMap);
+    }
+
+    /**
+     * 报销申请删除
+     * @param id
+     * @return
+     */
+    @GetMapping("deleteReim")
+    public ResponseEntity deleteReim(String id) {
+        Map<String, Object> resultMap = this.reimbursementService.deleteReim(id);
+        return ResponseEntity.ok (resultMap);
+    }
+
+    /**
+     * 查询发票号是否重复
+     */
+    @GetMapping("queryByNumber")
+    public boolean queryByNumber(String number) {
+        boolean data = this.reimbursementService.queryByNumber(number);
+        return data;
+    }
+
+
+}

+ 54 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/controller/ccpm/TestController.java

@@ -0,0 +1,54 @@
+package com.jeeplus.centerservice.controller.ccpm;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.jeeplus.aop.demo.annotation.DemoMode;
+import com.jeeplus.centerservice.utils.RestTemplateService;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.logging.annotation.ApiLog;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author: 王强
+ * @create: 2023-05-08 11:53
+ **/
+@RestController
+@RequestMapping("/test")
+public class TestController {
+
+    @Autowired
+    private RestTemplateService restTemplateService;
+
+    @DemoMode
+    @ApiLog("修改密码")
+    @RequestMapping("savePwd")
+    @ApiOperation(value = "修改密码")
+    public ResponseEntity savePwd(String newPassword) {
+        UserDTO userDTO = SpringUtil.getBean(IUserApi.class).getByToken(TokenProvider.getCurrentToken());
+        //调用服务端的修改密码接口
+//        User user = new User ( userDTO.getId ( ) );
+//        user.setPassword ( SecurityUtils.encryptPassword ( newPassword ) );
+//        user.setUpPassword("1"); // 密码修改状态改为”已修改“
+//        userService.updateById ( user );
+//        UserUtils.deleteCache ( userDTO );
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("name", userDTO.getName());
+        paramMap.put("password", newPassword);
+        paramMap.put("mobile", userDTO.getMobile());
+        String token = "";
+
+        Object res = restTemplateService.getCas("/test/update", token, null);
+
+
+        return ResponseEntity.ok ( "修改密码成功!" );
+
+    }
+}

+ 85 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/InvoiceDto.java

@@ -0,0 +1,85 @@
+package com.jeeplus.centerservice.dto;
+
+import com.google.common.collect.Lists;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class InvoiceDto extends BaseEntity {
+    private String number;		// 发票申请编号
+    private String processInstanceId; // 流程实例编号
+
+    private String projectName;		// 项目名称
+    private String reportNumber;		// 报告号
+    private Double money;		// 价税合计
+    private String moneyStr;		// 价税合计(String)
+    private String invoiceType;		// 发票类型
+    private String invoiceTypeStr;		// 发票类型Str
+    private String chargeType;		// 收款类型
+    private String billingContent;		// 开票内容
+    private String content;		// 开票内容要求
+    private Integer invoiceNumber;		// 发票编号(暂时弃用)
+    private Date invoiceDate;		// 开票日期
+    private Date takeDate;          //领票日期
+    private String drawerName;      //开票人(发票管理员名称)
+    private String invoiceRemarks;		// 开票备注
+    private String isInvoice;		// 是否开票
+    private String isCharge;		// 是否收款
+    private String isInvalid;		// 是否作废
+    private String invoiceState;    //发票状态
+    private String orUnicode;       //纳税人识别号
+    private String address;         //地址
+    private String telephone;        //电话
+    private String bank;              //开户银行
+    private String bankNumber;        //银行账号
+    private String cancleReason; //作废原因
+    private String companyId; //提交人的公司编号
+    private String officeId;
+    private String officeName;
+    private String submitterId;		// 发票登记人id
+    private String submitterName;		// 发票登记人名称
+    private String ext;//1总公司-上级公司0分公司-本公司
+    private String contractDate;
+    private String province; //省份
+    private String home;
+    private Date beginContractDate;		// 开始
+    private Date endContractDate;		// 结束
+    private Date receiptMoneyDate;		// 收款日期
+    private String receiptMoney;		// 是否收款
+    private String cancellation;		// 作废判断
+    private String adminFlag;		// 管理员判断
+    private String cancellationRemark;		// 作废原因
+    private List<WorkInvoiceDetail> workAccountList = Lists.newArrayList();//发票明细
+    private Integer notifyFlag; //代办判定条件
+    private String notifyId; //代办判定条件
+    private String widNumber; //发票号
+    private String widTotalMoney; //发票金额
+    private Double widTotalMoneyD; //发票金额
+
+
+    private String accountCheckingUserId; //对账人id
+    private String accountCheckingUserName; //对账人名称
+    private String accountCheckingArea; //对账地区
+    private List<WorkAttachmentDto> workAttachments;//附件
+
+    private Integer projectFlag ;	//1:项目,0:非项目
+    private Date receiptBeginDate ;	//收款开始时间
+    private Date receiptEndDate ;	//收款结束时间
+
+    private String newDrawer;    		//开票人状态
+    private String newDrawerId;    		//开票人id
+    private String newDrawerName;    	//开票人名称
+    private String actualDrawerId;    		//实际开票人id
+    private String actualDrawerEmailAddress;    		//实际开票人邮箱
+    private String actualDrawerName;    	//实际开票人名称
+    private String proceedsMoney;    	//收款总收入
+    private String noProceedsMoney;    	//剩余应收款费用
+    private Integer workReceiptCount;    	//收款数据量
+    private Double receiptMoneyD; //已收款金额
+    private Double notReceiptMoneyD; //未收款金额
+
+    private Integer electronicInvoiceFlag ;	//是否已经上传电子发票信息(0:未上传;1:已上传)
+}

+ 41 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementAmountInfo.java

@@ -0,0 +1,41 @@
+package com.jeeplus.centerservice.dto;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+@TableName(value = "reimbursement_amount_info")
+public class ReimbursementAmountInfo extends BaseEntity {
+
+    /**
+     * 关联id
+     */
+    private String infoId;
+
+    /**
+     * 发票代码
+     */
+    private String code;
+
+    /**
+     * 发票编号
+     */
+    private String number;
+
+    /**
+     * 金额
+     */
+    private String amount;
+
+    /**
+     * 税额
+     */
+    private String taxAmount;
+
+    /**
+     * 价税合计
+     */
+    private String count;
+
+}

+ 96 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfo.java

@@ -0,0 +1,96 @@
+package com.jeeplus.centerservice.dto;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+@TableName(value = "reimbursement_detail_info")
+public class ReimbursementDetailInfo extends BaseEntity {
+
+    /**
+     * 关联id
+     */
+    private String infoId;
+
+    /**
+     * 报销人
+     */
+    private String userId;
+
+    /**
+     * 报销人名称
+     */
+    private String userName;
+
+    /**
+     * 报销部门
+     */
+    private String deptId;
+
+    /**
+     * 报销部门名称
+     */
+    private String deptName;
+
+    /**
+     * 报销类型
+     */
+    private String typeId;
+
+    /**
+     * 报销类型名称
+     */
+    private String typeName;
+
+    /**
+     * 报销项目
+     */
+    private String projectId;
+
+    /**
+     * 报销项目名称
+     */
+    private String projectName;
+
+    /**
+     * 报告号
+     */
+    private String reportNumber;
+
+    /**
+     * 费用(元)
+     */
+    private String number;
+
+    /**
+     * 收据张数
+     */
+    private Integer receiptNumber;
+
+    /**
+     * 出差天数
+     */
+    private Integer days;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+    /**
+     * 排序
+     */
+    private String sort;
+
+    /**
+     * 出差天数ccpm
+     */
+    private String evectionNumber;
+
+    /**
+     * 收据张数ccpm
+     */
+    private String receiptNumbers;
+}
+

+ 94 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfoContract.java

@@ -0,0 +1,94 @@
+package com.jeeplus.centerservice.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 评估-报销详情信息表
+ * @TableName reimbursement_detail_info_contract
+ */
+@TableName(value ="reimbursement_detail_info_contract")
+@Data
+public class ReimbursementDetailInfoContract extends BaseEntity implements Serializable {
+
+    /**
+     * 基础表id
+     */
+    private String infoId;
+
+    /**
+     * 报销人
+     */
+    private String userId;
+
+    /**
+     * 报销人名称
+     */
+    @TableField(exist = false)
+    private String userName;
+
+    /**
+     * 报销部门
+     */
+    private String deptId;
+
+    /**
+     * 报销部门名称
+     */
+    @TableField(exist = false)
+    private String deptName;
+
+    /**
+     * 报销类型
+     */
+    private String typeId;
+
+    /**
+     * 报销类型名称
+     */
+    @TableField(exist = false)
+    private String typeName;
+
+    /**
+     * 报销合同
+     */
+    private String contractId;
+
+    /**
+     * 报销合同名称
+     */
+    @TableField(exist = false)
+    private String contractName;
+
+    /**
+     * 报告号
+     */
+    private String reportNumber;
+
+    /**
+     * 费用(元)
+     */
+    private String number;
+
+    /**
+     * 收据张数
+     */
+    private Integer receiptNumber;
+
+    /**
+     * 出差天数
+     */
+    private Integer days;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 98 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfoOther.java

@@ -0,0 +1,98 @@
+package com.jeeplus.centerservice.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 评估-报销详情信息表
+ * @TableName reimbursement_detail_info_other
+ */
+@TableName(value ="reimbursement_detail_info_other")
+@Data
+public class ReimbursementDetailInfoOther extends BaseEntity implements Serializable {
+
+    /**
+     * 基础表id
+     */
+    private String infoId;
+
+    /**
+     * 报销人
+     */
+    private String userId;
+
+    /**
+     * 报销人名称
+     */
+    @TableField(exist = false)
+    private String userName;
+
+    /**
+     * 报销部门
+     */
+    private String deptId;
+
+    /**
+     * 报销部门名称
+     */
+    @TableField(exist = false)
+    private String deptName;
+
+    /**
+     * 报销类型
+     */
+    private String typeId;
+
+    /**
+     * 报销类型名称
+     */
+    @TableField(exist = false)
+    private String typeName;
+
+    /**
+     * 报销项目
+     */
+    private String projectId;
+
+    /**
+     * 报销项目名称
+     */
+    private String projectName;
+
+    /**
+     * 报告号
+     */
+    private String reportNumber;
+
+    /**
+     * 费用(元)
+     */
+    private String number;
+
+    /**
+     * 收据张数
+     */
+    private Integer receiptNumber;
+
+    /**
+     * 出差天数
+     */
+    private Integer days;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+    /**
+     * 排序
+     */
+    private String sort;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 93 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/ReimbursementDetailInfoProcured.java

@@ -0,0 +1,93 @@
+package com.jeeplus.centerservice.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 评估-报销详情信息表
+ * @TableName reimbursement_detail_info_procured
+ */
+@TableName(value ="reimbursement_detail_info_procured")
+@Data
+public class ReimbursementDetailInfoProcured extends BaseEntity implements Serializable {
+
+    /**
+     * 基础表id
+     */
+    private String infoId;
+
+    /**
+     * 报销人
+     */
+    private String userId;
+
+    /**
+     * 报销人名称
+     */
+    @TableField(exist = false)
+    private String userName;
+
+    /**
+     * 报销部门
+     */
+    private String deptId;
+
+    /**
+     * 报销部门名称
+     */
+    @TableField(exist = false)
+    private String deptName;
+
+    /**
+     * 报销类型
+     */
+    private String typeId;
+
+    /**
+     * 报销类型名称
+     */
+    @TableField(exist = false)
+    private String typeName;
+
+    /**
+     * 报销项目
+     */
+    private String projectId;
+
+    /**
+     * 报销项目名称
+     */
+    private String projectName;
+
+    /**
+     * 报告号
+     */
+    private String reportNumber;
+
+    /**
+     * 费用(元)
+     */
+    private String number;
+
+    /**
+     * 收据张数
+     */
+    private Integer receiptNumber;
+
+    /**
+     * 出差天数
+     */
+    private Integer days;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 94 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/SaveInfoDto.java

@@ -0,0 +1,94 @@
+package com.jeeplus.centerservice.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class SaveInfoDto extends BaseEntity {
+
+    //合同编号类型(字典值)
+    public static final String BIZ_CODE = "5";
+
+    /**
+     * 经办人id
+     */
+    private String userId;
+
+    /**
+     * 经办人名称
+     */
+    private String userName;
+
+    /**
+     * 报销编号
+     */
+    private String no;
+
+    /**
+     * 所属部门
+     */
+    private String department;
+
+    /**
+     * 报销日期
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
+    private Date reimDate;
+
+    /**
+     * 备注
+     */
+    private String remarks;
+
+    /**
+     * 状态
+     */
+    private String type;
+
+    /**
+     * 流程id
+     */
+    private String procInsId;
+
+    /**
+     *
+     */
+    private String processInstanceId;
+
+    private List<ReimbursementDetailInfo> detailInfos;
+    private List<ReimbursementDetailInfoContract> detailInfoContracts;
+    private List<ReimbursementDetailInfoOther> detailInfoOthers;
+    private List<ReimbursementDetailInfoProcured> detailInfoProcured;
+
+    private List<ReimbursementAmountInfo> amountInfos;
+
+    private List<WorkAttachmentDto> files;
+    /**
+     * 报销类型
+     */
+    private String sourceType;
+
+    /**
+     * 采购编号
+     */
+    private String purchaseNo;
+
+    private String purchaseId;
+
+    private String departmentName;
+
+    // 流程历史
+    List<Map<String, Object>> histoicFlowList;
+
+    // 流程流向图
+    List<Map<String, Object>> flowChart;
+
+
+}

+ 17 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/WorkAttachmentDto.java

@@ -0,0 +1,17 @@
+package com.jeeplus.centerservice.dto;
+
+import com.jeeplus.core.service.dto.BaseDTO;
+import lombok.Data;
+
+@Data
+public class WorkAttachmentDto extends BaseDTO {
+
+    private String name;
+
+    private String size;
+
+    private String url;
+
+    private String lsUrl;
+
+}

+ 74 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/dto/WorkInvoiceDetail.java

@@ -0,0 +1,74 @@
+package com.jeeplus.centerservice.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.jeeplus.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.Map;
+
+@Data
+public class WorkInvoiceDetail extends BaseEntity {
+    private String number;		// 发票号
+    private String code;         //发票代码
+    private String totalMoney;		// 价税合计
+    @JsonIgnore
+    private String totalMoneyStr;		// 价税合计
+    private String tax;		// 税率
+    private String taxMoney;		// 金额 开票金额
+    @JsonIgnore
+    private String taxMoneyStr;		// 金额 开票金额
+    private String taxRate;		// 税额
+    @JsonIgnore
+    private String taxRateStr;		// 税额
+    private String incomeMoney;		// 登记金额 收款金额
+    @JsonIgnore
+    private String incomeMoneyStr;		// 登记金额 收款金额
+    private String state;		// 发票状态
+    private String backSign;		// 被退标记
+    private String backNumber;		// 被退票号
+    private String backCode;        //被退代码
+    private Date date;		// 开票日期
+    private String invoiceId;		// 发票主键
+    private String ainvoiceId;       //变更发票主键
+    private String sign;       //操作标记
+    private InvoiceDto workInvoice; //发票
+    private String[] exclusiveIds;
+    private String comId;
+    private String officeId;
+    private String home;
+    private String settleFlag;
+    private Date beginContractDate;		// 开始
+    private Date endContractDate;		// 结束
+    private String returnNumbers;       //作废-申请编号
+    private String returnId;             //作废-原明细Id
+    //导出功能-属性
+    private String invoiceExt;//0分公司开票 1总公司开票
+    private String invoiceInvoiceType;  //发票类型1专票2普票
+    private String invoiceClientName;   //实际开票单位
+    private String invoiceOrUnicode;    //纳税人识别号
+    private String invoiceContent;      //开票内容要求
+    private String invoiceRemarks;      //备注
+    private String invocieNumber;      //申请编号
+    private String invoiceDrawerName;  //开票人
+    private String invoiceOfficeName;  //所属部门
+    private String contractNum ;       //合同编号
+    private String contractName;       //合同名称
+    private String contractClientName; //主委托方
+
+    private Map<String, Object> variables;
+
+    /*暂弃*/
+    private String returnNumber;     //退票申请编号
+    private String returnReason;     //退票原因
+    private String returnCancle;     //作废退票(1退票2作废)
+    private String returnSign;      //原票是否退回(1是2否)
+    private Date returnDate;         //退票时间
+    private String returnUser;       //退票人
+    private String processInstanceId; // 流程实例编号
+    private String status;             //状态
+
+    private String account;
+    private String rate;
+    private String amount;
+}

+ 72 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/enums/TaskAliasEnum.java

@@ -0,0 +1,72 @@
+package com.jeeplus.centerservice.enums;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 流程枚举
+ */
+public enum TaskAliasEnum {
+
+    REIMBURSEMENT ("108,109", "Process_1665383385070");
+
+    /**
+     *  ccpm
+     */
+    private String ccpmTaskAlias;
+
+    /**
+     *  cpa
+     */
+    private String cpaTaskAlias;
+
+    TaskAliasEnum(String ccpmTaskAlias, String cpaTaskAlias) {
+        this.ccpmTaskAlias = ccpmTaskAlias;
+        this.cpaTaskAlias = cpaTaskAlias;
+    }
+
+    public String getCcpmTaskAlias() {
+        return ccpmTaskAlias;
+    }
+
+    public String getCpaTaskAlias() {
+        return cpaTaskAlias;
+    }
+
+    /**
+     * 根据ccpm流程key查询枚举
+     * @param value
+     * @return
+     */
+    public static TaskAliasEnum getByCcpmContains(String value) {
+        TaskAliasEnum result = null;
+        for (TaskAliasEnum s : values()) {
+            List<String> stringList = Arrays.asList(s.getCcpmTaskAlias().split(","));
+            if (stringList.contains(value)) {
+                result = s;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 根据cpa流程key查询枚举
+     * @param value
+     * @return
+     */
+    public static TaskAliasEnum getByCpa(String value) {
+        TaskAliasEnum result = null;
+        for (TaskAliasEnum s : values()) {
+            if (s.getCpaTaskAlias().equals(value)) {
+                result = s;
+                break;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ccpm:" + this.ccpmTaskAlias + ", cpa:" + this.cpaTaskAlias;
+    }
+}

+ 133 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/CcpmRequest.java

@@ -0,0 +1,133 @@
+package com.jeeplus.centerservice.service.ccpm;
+
+import com.jeeplus.centerservice.utils.RestTemplateService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class CcpmRequest {
+
+    @Resource
+    private RestTemplateService restTemplateService;
+
+    /**
+     * 根据数据id查询详情
+     * @param id
+     * @param processDefKey  流程key:例如 13、102...
+     * @return
+     */
+    public Object getById(String id, String processDefKey) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("id", id);
+        paramMap.put("processDefKey", processDefKey);
+        Object res = restTemplateService.getCCPM("/a/transpond/transpond/getById", token, paramMap);
+        return res;
+    }
+    /**
+     * 根据数据id查询发票详情
+     * @param id
+     * @param processDefKey  流程key:例如 21、213...
+     * @return
+     */
+    public Object getInvoiceById(String id, String processDefKey) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("id", id);
+        paramMap.put("processDefKey", processDefKey);
+        Object res = restTemplateService.getCCPM("/a/transpond/transpond/getInvoiceById", token, paramMap);
+        return res;
+    }
+
+    /**
+     * 查询报销数据详情  generateForm格式数据
+     * @param id
+     * @param processDefKey  流程key:例如 108、109...
+     * @return
+     */
+    public Object getByIdGenerate(String id, String processDefKey) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("id", id);
+        paramMap.put("processDefKey", processDefKey);
+        Object res = restTemplateService.getCCPM("/a/transpond/transpond/getByIdGenerate", token, paramMap);
+        return res;
+    }
+
+    /**
+     * 查询开票数据详情  generateForm格式数据
+     * @param id
+     * @param processDefKey  流程key:例如 21、213...
+     * @return
+     */
+    public Object getInvoiceByIdGenerate(String id, String processDefKey) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("id", id);
+        paramMap.put("processDefKey", processDefKey);
+        Object res = restTemplateService.getCCPM("/a/transpond/transpond/getInvoiceByIdGenerate", token, paramMap);
+        return res;
+    }
+
+    /**
+     * 报销审核 通过、驳回、重新发起
+     * @param resp 流程详情信息
+     * @param flag 通过或驳回标记:yes通过 no驳回
+     * @param comment 审核意见
+     * @param processDefKey 流程key:例如 13、102...
+     * @return
+     */
+    public Object saveAuditFunc(Map<String, Object> resp, String flag, String comment, String processDefKey) {
+        String token = "";
+        Map<String, Object> createBy = new HashMap<>();
+        createBy.put("id", resp.get("handleId").toString());
+        Map<String, Object> act = new HashMap<>();
+        act.put("flag", flag);
+        act.put("comment", comment);
+        resp.put("act", act);
+        resp.put("createBy", createBy);
+        resp.put("processDefKey", processDefKey);
+        Object res = restTemplateService.postCCPM("/a/transpond/transpond/auditReimDistribute", token, null, resp);
+        return res;
+    }
+
+    /**
+     * 发票审核 通过、驳回、重新发起
+     * @param resp 流程详情信息
+     * @param flag 通过或驳回标记:yes通过 no驳回
+     * @param comment 审核意见
+     * @param processDefKey 流程key:例如 13、102...
+     * @return
+     */
+    public Object saveInvoiceAuditFunc(Map<String, Object> resp, String flag, String comment, String processDefKey) {
+        String token = "";
+        Map<String, Object> createBy = new HashMap<>();
+        createBy.put("id", resp.get("accountCheckingUserId").toString());
+        Map<String, Object> act = new HashMap<>();
+        act.put("flag", flag);
+        act.put("comment", comment);
+        resp.put("act", act);
+        resp.put("createBy", createBy);
+        resp.put("processDefKey", processDefKey);
+        Object res = restTemplateService.postCCPM("/a/transpond/transpond/auditInvoiceDistribute", token, null, resp);
+        return res;
+    }
+
+    /**
+     * 查询发票号是否存在
+     * @param number
+     * @return
+     */
+    public boolean queryByNumber(String number) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("number", number);
+        boolean res =(Boolean) restTemplateService.getCCPM("/a/transpond/transpond/queryByNumber", token, paramMap);
+        return res;
+    }
+}

+ 111 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/CcpmService.java

@@ -0,0 +1,111 @@
+package com.jeeplus.centerservice.service.ccpm;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.jeeplus.centerservice.enums.TaskAliasEnum;
+import com.jeeplus.centerservice.service.ccpm.flow.FlowRequest;
+import com.jeeplus.centerservice.utils.ConvertServiceUtil;
+import com.jeeplus.centerservice.utils.GenerateFormUtil;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class CcpmService {
+
+    @Resource
+    private CcpmRequest ccpmRequest;
+
+    @Resource
+    private FlowRequest flowRequest;
+
+    /**
+     * 查询待办详情
+     * @param id 详情id
+     * @param processDefKey  流程key:例如 13、102...
+     * @return
+     */
+    public Map<String, Object> getByIdGenerate(String id, String processDefKey) {
+        LinkedHashMap<String, Object> reqMap = null;
+        Map<String, Object> respMap = null;
+        if ("13".equals(processDefKey) ||"102".equals(processDefKey) ||"108".equals(processDefKey) || "109".equals(processDefKey)){
+            Object response = ccpmRequest.getByIdGenerate(id, processDefKey); // 报销详情
+            reqMap = JSONObject.parseObject(JSON.toJSONString(response), LinkedHashMap.class, Feature.OrderedField);
+            respMap = GenerateFormUtil.convertToForm(reqMap);
+        }else { //发票详情
+            Object response = ccpmRequest.getInvoiceByIdGenerate(id, processDefKey);
+            String jsonString = JSON.toJSONString(response, SerializerFeature.WriteMapNullValue);
+            reqMap = JSONObject.parseObject(jsonString, LinkedHashMap.class, Feature.OrderedField);
+//            respMap = GenerateFormUtil.convertToForm(reqMap);
+            respMap = reqMap;
+        }
+        if (ObjectUtil.isNotEmpty(respMap) && ObjectUtil.isNotEmpty(respMap.get("processInstanceId"))) {
+            String processInstanceId = respMap.get("processInstanceId").toString();
+            // 流程流向图
+            Object flowChart = flowRequest.getFlowChart(processInstanceId);
+            if (Objects.nonNull(flowChart)) {
+                List<Map<String, Object>> flowCharts = (List)JSONArray.parseArray(JSON.toJSONString(flowChart)); // 格式转换
+                respMap.put("flowChart",flowCharts);
+            }
+            // 流程历史
+            Object histoicFlow = flowRequest.getHistoicFlowList(processInstanceId);
+            if (Objects.nonNull(histoicFlow)) {
+                List<Map<String, Object>> histoicFlows = (List)JSONArray.parseArray(JSON.toJSONString(histoicFlow));
+                List<Map<String, Object>> histoicFlowList = ConvertServiceUtil.convertHisFlowList(histoicFlows); // 格式转换
+                respMap.put("histoicFlow",histoicFlowList);
+            }
+        }
+
+        return respMap;
+    }
+
+    /**
+     * 报销审核通过、驳回
+     * @param id
+     * @param flag
+     * @return
+     */
+    public Map<String, Object> reimAudit(String id, String flag, String comment, String processDefKey) {
+        Map<String, Object> resultMap = new HashMap<>();
+        Object response = ccpmRequest.getById(id, processDefKey); // 报销详情
+        if (Objects.nonNull(response)) {
+            Map<String, Object> resp = JSONObject.parseObject(JSON.toJSONString(response));
+            Object result = ccpmRequest.saveAuditFunc(resp, flag, comment, processDefKey); // 审核通过、审核驳回
+            if (Objects.nonNull(result)) {
+                resultMap = JSONObject.parseObject(JSON.toJSONString(result));
+            } else {
+                resultMap.put("success", false);
+                resultMap.put("message","操作失败");
+            }
+        } else {
+            resultMap.put("success", false);
+            resultMap.put("message","操作失败");
+        }
+        return resultMap;
+
+    }
+
+    /**
+     * 删除报销待办
+     * @param id
+     * @return
+     */
+    public Map<String, Object> deleteReim(String id) {
+        Map<String, Object> resultMap = new HashMap<>();
+        Object result = flowRequest.deleteNotify(id, TaskAliasEnum.REIMBURSEMENT.getCcpmTaskAlias()); // 13代表报销模块
+        if (Objects.nonNull(result)) {
+            resultMap.putAll(JSONObject.parseObject(JSON.toJSONString(result)));
+        } else {
+            resultMap.put("code", 0);
+            resultMap.put("msg", "报销信息删除失败");
+        }
+        return resultMap;
+    }
+}

+ 122 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/flow/FlowRequest.java

@@ -0,0 +1,122 @@
+package com.jeeplus.centerservice.service.ccpm.flow;
+
+import cn.hutool.core.util.StrUtil;
+import com.jeeplus.centerservice.utils.RestTemplateService;
+import com.jeeplus.flowable.model.Flow;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.utils.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class FlowRequest {
+
+    @Resource
+    private RestTemplateService restTemplateService;
+
+    /**
+     * 根据procInsId查询流程流向图
+     * @param procInsId
+     * @return
+     */
+    public Object getFlowChart(String procInsId) {
+        String token = "";
+        Map<String, Object> param = new HashMap<>();
+        param.put("procInsId", procInsId);
+        Object flowChart = restTemplateService.getCCPM("/a/act/task/getFlowChart", token, param);
+        return flowChart;
+    }
+
+    /**
+     * 根据procInsId查询流程历史
+     * @param procInsId
+     * @return
+     */
+    public Object getHistoicFlowList(String procInsId) {
+        String token = "";
+        Map<String, Object> param = new HashMap<>();
+        param.put("procInsId", procInsId);
+        Object histoicFlow = restTemplateService.getCCPM("/a/act/task/getHistoicFlowList", token, param);
+        return histoicFlow;
+    }
+
+    /**
+     * 根据待办id及类型  删除待办信息
+     * @param notifyId
+     * @param type
+     * @return
+     */
+    public Object deleteNotify(String notifyId, String type) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("notifyId", notifyId);
+        paramMap.put("type", type);
+        Object result = restTemplateService.getCCPM("/a/workprojectnotify/workProjectNotify/deleteNotify", token, paramMap);
+        return result;
+    }
+
+    /**
+     * 查询待办信息
+     * @param flow
+     * @return
+     */
+    public Object getNotifyList(Flow flow, String belongProject, UserDTO userDTO) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        // 设置查询条件
+        if (flow.getBeginDate () != null) { // 创建时间
+            SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            paramMap.put("startDate", formatter.format(flow.getBeginDate ()));
+        }
+        if (flow.getEndDate () != null) { // 创建时间
+            SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            paramMap.put("endDate", formatter.format(flow.getEndDate ()));
+        }
+        if (StrUtil.isNotBlank (flow.getTitle ())) { // 标题
+            paramMap.put("title", flow.getTitle ());
+        }
+        if (StringUtils.isNotEmpty(flow.getAssigneeName())) { // 流程发起人
+            paramMap.put("userName", flow.getAssigneeName());
+        }
+        paramMap.put("belongProject", belongProject);
+        paramMap.put("size", -1);
+        paramMap.put("count", -1);
+        Object response = restTemplateService.getCCPMMultithreading("/a/workprojectnotify/workProjectNotify/getList", token, paramMap,userDTO);
+        return response;
+    }
+
+    /**
+     * 查询已办信息
+     * @param flow
+     * @return
+     */
+    public Object getHisTaskList(Flow flow, String belongProject) {
+        String token = "";
+        Map<String, Object> paramMap = new HashMap<>();
+        // 设置查询条件
+        if (flow.getBeginDate () != null) { // 创建时间
+            SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            paramMap.put("startOverDate", formatter.format(flow.getBeginDate ()));
+        }
+        if (flow.getEndDate () != null) { // 创建时间
+            SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            paramMap.put("endOverDate", formatter.format(flow.getEndDate ()));
+        }
+        if (StrUtil.isNotBlank (flow.getTitle ())) { // 标题
+            paramMap.put("title", flow.getTitle ());
+        }
+        if (StringUtils.isNotEmpty(flow.getAssigneeName())) { // 流程发起人
+            paramMap.put("userName", flow.getAssigneeName());
+        }
+        paramMap.put("belongProject", belongProject);
+        Object response = restTemplateService.getCCPM("/a/workprojectnotify/workProjectNotify/backlogListReadAll", token, paramMap);
+        return response;
+    }
+
+}

+ 50 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/flow/FlowService.java

@@ -0,0 +1,50 @@
+package com.jeeplus.centerservice.service.ccpm.flow;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.jeeplus.centerservice.utils.ConvertServiceUtil;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class FlowService {
+
+    @Resource
+    private FlowRequest flowRequest;
+
+    /**
+     * 获取流程历史
+     * @param procInsId
+     * @return
+     */
+    public List<Map<String, Object>> getHistoicFlowList(String procInsId) {
+        List<Map<String, Object>> histoicFlowList = new ArrayList<>();
+        Object histoicFlow = flowRequest.getHistoicFlowList(procInsId);
+        if (Objects.nonNull(histoicFlow)) {
+            List<Map<String, Object>> histoicFlows = (List)JSONArray.parseArray(JSON.toJSONString(histoicFlow));
+            histoicFlowList.addAll(ConvertServiceUtil.convertHisFlowList(histoicFlows));
+        }
+        return histoicFlowList;
+    }
+
+    /**
+     * 获取流程流向图
+     * @param procInsId
+     * @return
+     */
+    public List<Map<String, Object>> getFlowChart(String procInsId) {
+        List<Map<String, Object>> flowCharts = new ArrayList<>();
+        Object flowChart = flowRequest.getFlowChart(procInsId);
+        if (Objects.nonNull(flowChart)) {
+            flowCharts.addAll((List)JSONArray.parseArray(JSON.toJSONString(flowChart)));
+        }
+        return flowCharts;
+    }
+}

+ 163 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/service/ccpm/reimbursement/ReimbursementService.java

@@ -0,0 +1,163 @@
+package com.jeeplus.centerservice.service.ccpm.reimbursement;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.jeeplus.centerservice.dto.SaveInfoDto;
+import com.jeeplus.centerservice.dto.WorkInvoiceDetail;
+import com.jeeplus.centerservice.enums.TaskAliasEnum;
+import com.jeeplus.centerservice.service.ccpm.CcpmRequest;
+import com.jeeplus.centerservice.service.ccpm.flow.FlowRequest;
+import com.jeeplus.centerservice.utils.ConvertServiceUtil;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class ReimbursementService {
+
+    @Resource
+    private CcpmRequest ccpmRequest;
+
+    @Resource
+    private FlowRequest flowRequest;
+
+    /**
+     * 查询报销待办详情
+     * @param id
+     * @param processDefKey  流程key:例如 13、102...
+     * @return
+     */
+    public SaveInfoDto getReimbursementById(String id, String processDefKey) {
+        SaveInfoDto saveInfoDto = new SaveInfoDto();
+        Object response = ccpmRequest.getById(id, processDefKey); // 报销详情
+        if (Objects.nonNull(response)) {
+            saveInfoDto = ConvertServiceUtil.convertReim(response); // 格式转换
+            if (Objects.nonNull(saveInfoDto) && StringUtils.isNotBlank(saveInfoDto.getProcInsId())) {
+                // 流程流向图
+                Object flowChart = flowRequest.getFlowChart(saveInfoDto.getProcInsId());
+                if (Objects.nonNull(flowChart)) {
+                    List<Map<String, Object>> flowCharts = (List)JSONArray.parseArray(JSON.toJSONString(flowChart)); // 格式转换
+                    saveInfoDto.setFlowChart(flowCharts);
+                }
+                // 流程历史
+                Object histoicFlow = flowRequest.getHistoicFlowList(saveInfoDto.getProcInsId());
+                if (Objects.nonNull(histoicFlow)) {
+                    List<Map<String, Object>> histoicFlows = (List)JSONArray.parseArray(JSON.toJSONString(histoicFlow));
+                    List<Map<String, Object>> histoicFlowList = ConvertServiceUtil.convertHisFlowList(histoicFlows); // 格式转换
+                    saveInfoDto.setHistoicFlowList(histoicFlowList);
+                }
+            }
+        }
+        return saveInfoDto;
+    }
+
+    /**
+     * 报销审核通过、驳回
+     * @param id
+     * @param flag
+     * @return
+     */
+    public Map<String, Object> reimAudit(String id, String flag, String comment, String processDefKey) {
+        Map<String, Object> resultMap = new HashMap<>();
+        Object response = ccpmRequest.getById(id, processDefKey); // 报销详情
+        if (Objects.nonNull(response)) {
+            Map<String, Object> resp = JSONObject.parseObject(JSON.toJSONString(response));
+            Object result = ccpmRequest.saveAuditFunc(resp, flag, comment, processDefKey); // 审核通过、审核驳回
+            if (Objects.nonNull(result)) {
+                resultMap = JSONObject.parseObject(JSON.toJSONString(result));
+            } else {
+                resultMap.put("success", false);
+                resultMap.put("message","操作失败");
+            }
+        } else {
+            resultMap.put("success", false);
+            resultMap.put("message","操作失败");
+        }
+        return resultMap;
+
+    }
+
+    /**
+     * 删除报销待办
+     * @param id
+     * @return
+     */
+    public Map<String, Object> deleteReim(String id) {
+        Map<String, Object> resultMap = new HashMap<>();
+        Object result = flowRequest.deleteNotify(id, TaskAliasEnum.REIMBURSEMENT.getCcpmTaskAlias()); // 13代表报销模块
+        if (Objects.nonNull(result)) {
+            resultMap.putAll(JSONObject.parseObject(JSON.toJSONString(result)));
+        } else {
+            resultMap.put("code", 0);
+            resultMap.put("msg", "报销信息删除失败");
+        }
+        return resultMap;
+    }
+
+    /**
+     * 发票审核通过、驳回
+     * @param id
+     * @param flag
+     * @return
+     */
+    public Map<String, Object> invoiceAudit(String id, String flag, String comment, String processDefKey,String jsonData) {
+        Map<String, Object> resultMap = new HashMap<>();
+        Object response = ccpmRequest.getInvoiceById(id, processDefKey); // 发票详情
+        if (Objects.nonNull(response)) {
+            Map<String, Object> respMap = JSONObject.parseObject(JSON.toJSONString(response));
+            JSONObject resp = JSON.parseObject(jsonData);
+            //将发票详情转为ccpm系统中的字段
+            ArrayList<WorkInvoiceDetail> workInvoiceDetails = new ArrayList<>();
+            if ("yes".equals(flag) && StringUtils.isNotBlank(resp.getString("workAccountList"))){
+                List<WorkInvoiceDetail> workAccountList = JSON.parseArray(resp.getString("workAccountList"),WorkInvoiceDetail.class);
+                if (CollectionUtil.isNotEmpty(workAccountList)){
+                    for (WorkInvoiceDetail detail : workAccountList) {
+                        WorkInvoiceDetail workInvoiceDetail = new WorkInvoiceDetail();
+                        workInvoiceDetail.setCode(detail.getCode());//发票代码
+                        workInvoiceDetail.setNumber(detail.getNumber());//发票号
+                        workInvoiceDetail.setTotalMoney(detail.getAccount());//金额
+                        workInvoiceDetail.setTaxRate(detail.getTax());//税率
+                        workInvoiceDetail.setTax(detail.getAmount());//税额
+                        workInvoiceDetail.setId("");
+                        workInvoiceDetail.setState("正常");
+                        workInvoiceDetail.setBackSign("正常");
+                        workInvoiceDetails.add(workInvoiceDetail);
+                    }
+                }
+                respMap.put("workAccountList",workInvoiceDetails);
+                respMap.put("invoiceDate",resp.get("invoiceDate"));//开票时间
+                respMap.put("takeDate",resp.get("takeDate"));//领票时间
+                respMap.put("drawerName",resp.get("drawerName"));//开票人
+            }
+
+            Object result = ccpmRequest.saveInvoiceAuditFunc(respMap, flag, comment, processDefKey); // 审核通过、审核驳回
+            if (Objects.nonNull(result)) {
+                resultMap = JSONObject.parseObject(JSON.toJSONString(result));
+            } else {
+                resultMap.put("success", false);
+                resultMap.put("message","操作失败");
+            }
+        } else {
+            resultMap.put("success", false);
+            resultMap.put("message","操作失败");
+        }
+        return resultMap;
+
+    }
+
+    /**
+     * 查询发票号是否存在
+     * @param number
+     * @return
+     */
+    public boolean queryByNumber(String number) {
+        boolean response = ccpmRequest.queryByNumber(number); // 查询发票号是否存在
+        return response;
+    }
+}

+ 531 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/ConvertServiceUtil.java

@@ -0,0 +1,531 @@
+package com.jeeplus.centerservice.utils;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jeeplus.centerservice.dto.ReimbursementAmountInfo;
+import com.jeeplus.centerservice.dto.ReimbursementDetailInfo;
+import com.jeeplus.centerservice.dto.SaveInfoDto;
+import com.jeeplus.centerservice.dto.WorkAttachmentDto;
+import com.jeeplus.flowable.vo.HisTaskVo;
+import com.jeeplus.flowable.vo.ProcessVo;
+import com.jeeplus.flowable.vo.TaskVo;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.utils.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class ConvertServiceUtil {
+
+    /**
+     * 批量将ccpm系统待办返回的字段转换为当前系统待办需要的字段
+     * @param res
+     * @return
+     */
+    public static List<ProcessVo> convertProcessVoList(List<ProcessVo> res) throws Exception {
+        ArrayList<ProcessVo> processVoList = new ArrayList<>();
+        if (CollectionUtil.isNotEmpty(res)) {
+            List<ProcessVo> processVos = res;
+            String ccpm_task = Global.getConfig("CCPM_TASK"); // 获取ccpm可查看的待办数据
+            for (ProcessVo item : processVos) {
+                if ("cpa".equals(item.getBelongProject())) {
+                    processVoList.add(item);
+                } else if ("ccpm".equals(item.getBelongProject())) {
+                    TaskVo task = item.getTask();
+                    Map vars = item.getVars();
+                    if (Objects.nonNull(task) && Objects.nonNull(vars) && (vars.get("remarks").toString().contains("待审批") || vars.get("remarks").toString().contains("重新申请"))) {
+                        if(StringUtils.isNotBlank(ccpm_task)) {
+                            String[] split = ccpm_task.split(",");
+                            List<String> taskAliasList = Arrays.asList(split);
+                            if (taskAliasList.contains(task.getProcessDefKey())) {
+                                processVoList.add(item);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return processVoList;
+    }
+    /**
+     * 批量将ccpm系统待办返回的字段转换为当前系统已办
+     * @param res
+     * @return
+     */
+    public static List<HisTaskVo> convertHisTaskVoList(List<HisTaskVo> res) throws Exception {
+        List<HisTaskVo> hisTaskVoList = new ArrayList<>();
+        if (CollectionUtil.isNotEmpty(res)) {
+            List<HisTaskVo> hisTaskVos = res;
+            String ccpm_task = Global.getConfig("CCPM_TASK"); // 获取ccpm可查看的待办数据
+            for (HisTaskVo item : hisTaskVos) {
+                if ("cpa".equals(item.getBelongProject())) {
+                    hisTaskVoList.add(item);
+                } else if ("ccpm".equals(item.getBelongProject())) {
+                    if(StringUtils.isNotBlank(ccpm_task)) {
+                        String[] split = ccpm_task.split(",");
+                        List<String> taskAliasList = Arrays.asList(split);
+                        if (taskAliasList.contains(item.getProcessDefKey())) {
+                            hisTaskVoList.add(item);
+                        }
+                    }
+                }
+            }
+        }
+        return hisTaskVoList;
+    }
+
+    /**
+     * ccpm系统待办返回的字段转换为当前系统待办需要的字段
+     * @param map
+     * @return
+     */
+    public static ProcessVo convertProcessVo(Map<String, Object> map) throws Exception {
+        ProcessVo processVo = new ProcessVo();
+        Map<String, String> vars = new HashMap();
+        TaskVo task = new TaskVo();
+        if (CollectionUtil.isNotEmpty(map)) {
+            // 标题
+            if (Objects.nonNull(map.get("title"))){
+                vars.put("title", map.get("title").toString());
+            }
+            // 流程名称
+            if (Objects.nonNull(map.get("typeLabel"))){
+                processVo.setProcessDefinitionName(map.get("typeLabel").toString());
+            }
+            // 当前环节
+            if (Objects.nonNull(map.get("notifyRole"))){
+                task.setName(map.get("notifyRole").toString());
+            }
+            // 流程发起人
+            if (Objects.nonNull(map.get("createUserName"))){
+                vars.put("userName", map.get("createUserName").toString());
+            }
+            // 创建时间
+            if (Objects.nonNull(map.get("createDate"))){
+                task.setCreateTime((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).parse(map.get("createDate").toString()));
+            }
+            // 流程id
+            if (Objects.nonNull(map.get("id"))){
+                task.setId(map.get("id").toString());
+            }
+            // 数据id
+            if (Objects.nonNull(map.get("notifyId"))){
+                vars.put("notifyId", map.get("notifyId").toString());
+            }
+            // 审批状态
+            if (Objects.nonNull(map.get("remarks"))){
+                vars.put("remarks", map.get("remarks").toString());
+            }
+        }
+        processVo.setVars(vars);
+        processVo.setTask(task);
+        processVo.setBelongProject("ccpm");
+        processVo.setStatus ("todo");
+        return processVo;
+    }
+
+    /**
+     * 将结果排序后分页(已办)
+     * 由于是根据数据中的creaTime字段来进行排序,所以此字段不可以为空,否则会报空指针
+     * @param page
+     * @param list
+     * @return
+     */
+    public static Page getSortAndPagingHisTask(Page page, List<HisTaskVo> list) {
+        // 将数据按照creaTime倒序排序
+        CollectionUtil.sort(list, new Comparator<HisTaskVo>() {
+            @Override
+            public int compare(HisTaskVo o1, HisTaskVo o2) {
+                return o2.getCreateTime().compareTo(o1.getCreateTime());
+            }
+        });
+        // 将数据分页
+        page.setTotal(list.size());
+        List<HisTaskVo> records = new ArrayList<>();
+        int startIndex = (int) ((page.getCurrent() - 1) * page.getSize());
+        if (startIndex > list.size()) {
+            startIndex = 0;
+            page.setCurrent(1);
+        }
+        for (int i = 0; i < page.getSize() ; i ++) {
+            if (startIndex == list.size() || ObjectUtil.isEmpty(list.get(startIndex))) {
+                break;
+            }
+            records.add(list.get(startIndex));
+            startIndex++;
+        }
+        page.setRecords(records);
+        return page;
+    }
+
+    /**
+     * 将结果排序后分页(待办)
+     * 由于是根据数据中的creaTime字段来进行排序,所以此字段不可以为空,否则会报空指针
+     * @param page
+     * @param list
+     * @return
+     */
+    public static Page getSortAndPaging(Page page, List<ProcessVo> list) {
+        // 将数据按照creaTime倒序排序
+        CollectionUtil.sort(list, new Comparator<ProcessVo>() {
+            @Override
+            public int compare(ProcessVo o1, ProcessVo o2) {
+                return o2.getTask().getCreateTime().compareTo(o1.getTask().getCreateTime());
+            }
+        });
+        // 将数据分页
+        page.setTotal(list.size());
+        List<ProcessVo> records = new ArrayList<>();
+        int startIndex = (int) ((page.getCurrent() - 1) * page.getSize());
+        if (startIndex > list.size()) {
+            startIndex = 0;
+            page.setCurrent(1);
+        }
+        for (int i = 0; i < page.getSize() ; i ++) {
+            if (startIndex == list.size() || ObjectUtil.isEmpty(list.get(startIndex))) {
+                break;
+            }
+            records.add(list.get(startIndex));
+            startIndex++;
+        }
+        page.setRecords(records);
+        return page;
+    }
+
+    /**
+     * ccpm报销转换
+     * @param response
+     * @return
+     */
+    public static SaveInfoDto convertReim(Object response) {
+        SaveInfoDto result = new SaveInfoDto();
+        if (Objects.nonNull(response)) {
+            Map<String, Object> resp = JSONObject.parseObject(JSON.toJSONString(response));
+            if (CollectionUtil.isNotEmpty(resp)) {
+                // processInstanceId
+                if (ObjectUtil.isNotEmpty(resp.get("processInstanceId"))) {
+                    result.setProcInsId(resp.get("processInstanceId").toString());
+                }
+                // 经办人
+                if (ObjectUtil.isNotEmpty(resp.get("submitterName"))) { // 报销人
+                    result.setUserName(resp.get("submitterName").toString());
+                }
+                // 报销编号
+                if (ObjectUtil.isNotEmpty(resp.get("number"))) { // 报销编号
+                    result.setNo(resp.get("number").toString());
+                }
+                // 所属部门
+                if (ObjectUtil.isNotEmpty(resp.get("officeName"))) { // 所属部门
+                    result.setDepartmentName(resp.get("officeName").toString());
+                }
+                // 报销日期
+                if (ObjectUtil.isNotEmpty(resp.get("createDate"))) { // 报销日期、创建时间
+                    result.setReimDate(DateUtil.parse(resp.get("createDate").toString()));
+                }
+                // 备注
+                if (ObjectUtil.isNotEmpty(resp.get("remarks"))) { // 备注
+                    result.setRemarks(resp.get("remarks").toString());
+                }
+                // 附件
+                if (ObjectUtil.isNotEmpty(resp.get("workAttachments"))) {
+                    String jsonString = JSON.toJSONString(resp.get("workAttachments"));
+                    List<Object> attachmentList = JSON.parseArray(jsonString, Object.class);
+                    List<WorkAttachmentDto> attachments = new ArrayList<>();
+                    if (CollectionUtil.isNotEmpty(attachmentList)) {
+                        attachmentList.stream().forEach(attachment -> {
+                            WorkAttachmentDto attachmentDto = new WorkAttachmentDto();
+                            UserDTO userDTO = new UserDTO();
+                            Map<String, Object> fileMap = JSONObject.parseObject(JSON.toJSONString(attachment));
+                            if (ObjectUtil.isNotEmpty(fileMap.get("attachmentName"))) { // 附件名称
+                                attachmentDto.setName(fileMap.get("attachmentName").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("createName"))) { // 创建人
+                                userDTO.setName(fileMap.get("createName").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("createDate"))) { // 创建时间
+                                attachmentDto.setCreateTime(DateUtil.parse(fileMap.get("createDate").toString()));
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("url"))) { // 文件地址
+                                attachmentDto.setUrl(fileMap.get("url").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("temporaryUrl"))) { // 文件临时地址
+                                attachmentDto.setLsUrl(fileMap.get("temporaryUrl").toString());
+                            }
+                            attachmentDto.setCreateBy(userDTO);
+                            attachments.add(attachmentDto);
+                        });
+                    }
+                    result.setFiles(attachments);
+                }
+                // 专用发票信息
+                if (ObjectUtil.isNotEmpty(resp.get("reimbursementVATTaxes"))) {
+                    String jsonString = JSON.toJSONString(resp.get("reimbursementVATTaxes"));
+                    List<Object> reimVATTaxeList = JSON.parseArray(jsonString, Object.class);
+                    List<ReimbursementAmountInfo> reimbursementAmountInfoList = new ArrayList<>();
+                    if (CollectionUtil.isNotEmpty(reimVATTaxeList)) {
+                        reimVATTaxeList.stream().forEach(reim -> {
+                            ReimbursementAmountInfo reimbursementAmountInfo = new ReimbursementAmountInfo();
+                            Map<String, Object> vaTaxeMap = JSONObject.parseObject(JSON.toJSONString(reim));
+                            if (ObjectUtil.isNotEmpty(vaTaxeMap.get("invoiceCode"))) { // 发票代码
+                                reimbursementAmountInfo.setCode(vaTaxeMap.get("invoiceCode").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(vaTaxeMap.get("invoiceNumber"))) { // 发票号
+                                reimbursementAmountInfo.setNumber(vaTaxeMap.get("invoiceNumber").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(vaTaxeMap.get("money"))) { // 金额
+                                reimbursementAmountInfo.setAmount(vaTaxeMap.get("money").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(vaTaxeMap.get("taxAmount"))) { // 税额
+                                reimbursementAmountInfo.setTaxAmount(vaTaxeMap.get("taxAmount").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(vaTaxeMap.get("sumMoney"))) { // 价税合计
+                                reimbursementAmountInfo.setCount(vaTaxeMap.get("sumMoney").toString());
+                            }
+                            reimbursementAmountInfoList.add(reimbursementAmountInfo);
+                        });
+                    }
+                    result.setAmountInfos(reimbursementAmountInfoList);
+                }
+                // 报销详情
+                if (ObjectUtil.isNotEmpty(resp.get("workAccountList"))) {
+                    String jsonString = JSON.toJSONString(resp.get("workAccountList"));
+                    List<Object> workAccountList = JSON.parseArray(jsonString, Object.class);
+                    List<ReimbursementDetailInfo> reimbursementDetailInfos = new ArrayList<>();
+                    if (CollectionUtil.isNotEmpty(workAccountList)) {
+                        workAccountList.stream().forEach(detail -> {
+                            Map<String, Object> detailMap = JSONObject.parseObject(JSON.toJSONString(detail));
+                            ReimbursementDetailInfo detailInfo = new ReimbursementDetailInfo();
+                            if (ObjectUtil.isNotEmpty(detailMap.get("reimbursementName"))) { // 报销人
+                                detailInfo.setUserName(detailMap.get("reimbursementName").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("officeId"))) { // 报销部门
+                                detailInfo.setDeptName(detailMap.get("officeId").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("typeName"))) { // 报销类别
+                                detailInfo.setTypeName(detailMap.get("typeName").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("project"))) { // 报销项目
+                                Map<String, Object> projectMap = JSONObject.parseObject(JSON.toJSONString(detailMap.get("project")));
+                                if (ObjectUtil.isNotEmpty(projectMap.get("projectName"))) {
+                                    detailInfo.setProjectName(projectMap.get("projectName").toString());
+                                }
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("projectReportNumber"))) { // 报告号
+                                detailInfo.setReportNumber(detailMap.get("projectReportNumber").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("money"))) { // 费用(元)
+                                detailInfo.setNumber(detailMap.get("money").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("bills"))) { // 收据张数
+                                detailInfo.setReceiptNumbers(detailMap.get("bills").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("evectionNumber"))) { // 出差天数
+                                detailInfo.setEvectionNumber(detailMap.get("evectionNumber").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(detailMap.get("remarks"))) { // 内容
+                                detailInfo.setContent(detailMap.get("remarks").toString());
+                            }
+                            reimbursementDetailInfos.add(detailInfo);
+                        });
+                    }
+                    result.setDetailInfos(reimbursementDetailInfos);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * ccpm流程历史转换
+     * @param list
+     * @return
+     */
+    public static List<Map<String, Object>> convertHisFlowList(List<Map<String, Object>> list) {
+        if (CollectionUtil.isNotEmpty(list)) {
+            list.stream().forEach(item -> {
+                // beginDate日期格式化后重新赋值
+                if (Objects.nonNull(item.get("beginDate"))) {
+                    Long beginDate = Long.valueOf(String.valueOf(item.get("beginDate")));
+                    item.remove("beginDate");
+                    item.put("beginDate",formatLongDate(beginDate));
+                }
+                // endDate日期格式化后重新赋值
+                if (Objects.nonNull(item.get("endDate"))) {
+                    Long beginDate = Long.valueOf(String.valueOf(item.get("endDate")));
+                    item.remove("endDate");
+                    item.put("endDate",formatLongDate(beginDate));
+                }
+            });
+        }
+        return list;
+    }
+
+    /**
+     * 将Long类型时间转换为String时间格式
+     * @param date
+     * @return
+     */
+    public static String formatLongDate (Long date) {
+        Date dt=new Date(date);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
+        String format = sdf.format(dt);
+        return format;
+    }
+
+    /**
+     * 当前系统待办数据转换为ccpm待办 批量转换
+     * @param processVoList
+     * @return
+     */
+    public static List<Map<String, Object>> copyNotifyListToCcpm(List<ProcessVo> processVoList) throws Exception {
+        List<Map<String, Object>> res = new ArrayList<>();
+        for (ProcessVo processVo : processVoList) {
+            Map<String, Object> respMap = copyNotifyToCcpm(processVo);
+            if (MapUtil.isNotEmpty(respMap)) {
+                res.add(respMap);
+            }
+        }
+        return res;
+    }
+
+    /**
+     * 当前系统待办数据转换为ccpm待办
+     * @param processVo
+     * @return
+     * @throws Exception
+     */
+    public static Map<String, Object> copyNotifyToCcpm(ProcessVo processVo) throws Exception {
+        Map<String, Object> res = new HashMap<>();
+        Map<String, Object> vars = processVo.getVars();
+        TaskVo task = processVo.getTask();
+        // 只查询待审批状态的数据
+        // vars.get("agree") 的值为false时,此流程为驳回状态。值为null或其他时,此流程为待审批状态
+        if (Objects.nonNull(vars) && (Objects.isNull(vars.get("agree")) || Boolean.parseBoolean(vars.get("agree").toString()))) {
+            res.put("belongProject",processVo.getBelongProject());
+            // 流程名称
+            if (StringUtils.isNotBlank(processVo.getProcessDefinitionName())){
+                res.put("typeLabel", processVo.getProcessDefinitionName());
+            }
+            // 标题
+            if (Objects.nonNull(vars.get("title"))){
+                res.put("title", "cpa " + vars.get("title").toString()); // 标题
+                res.put("content", vars.get("title").toString()); // 内容
+            }
+            // 流程发起人
+            if (Objects.nonNull(vars.get("userName"))){
+                res.put("createUserName",vars.get("userName").toString());
+            }
+            // 数据id
+            if (Objects.nonNull(vars.get("id"))){
+                res.put("notifyId",vars.get("id").toString());
+            }
+            // 审批状态
+            res.put("remarks","待审批");
+            if (Objects.nonNull(vars.get("agree"))) {
+                if (!Boolean.parseBoolean(vars.get("agree").toString())) {
+                    res.put("remarks","重新发起"); // vars.get("agree")的值为false时,此流程为驳回状态,其他值为待审批状态
+                }
+            }
+            if (Objects.nonNull(task)) {
+                // 流程类型
+                if (StringUtils.isNotBlank(task.getProcessDefKey())){
+                    // Process_1665383385070 评估-报销审批
+//                    if ("Process_1665383385070".equals(task.getProcessDefKey())) {
+//                        res.put("type", "13");
+//                    }
+                    res.put("type", task.getProcessDefKey());
+                }
+                // 当前环节
+                if (Objects.nonNull(task.getName())){
+                    res.put("notifyRole", task.getName());
+                }
+                // 创建时间
+                if (Objects.nonNull(task.getCreateTime())){
+                    res.put("createDate", task.getCreateTime());
+                }
+                // 流程id
+                if (Objects.nonNull(task.getId())){
+                    res.put("id",task.getId());
+                }
+                // 审核人
+                if (Objects.nonNull(task.getAssignee())){
+                    res.put("auditUserName",task.getAssignee());
+                }
+            }
+        }
+        return res;
+    }
+
+    /**
+     * 当前系统待办数据转换为ccpm已办 批量转换
+     * @param hisTaskVoList
+     * @return
+     */
+    public static List<Map<String, Object>> copyHisTaskListToCcpm(List<HisTaskVo> hisTaskVoList) throws Exception {
+        List<Map<String, Object>> res = new ArrayList<>();
+        for (HisTaskVo hisTaskVo : hisTaskVoList) {
+            Map<String, Object> respMap = copyHisTaskToCcpm(hisTaskVo);
+            if (MapUtil.isNotEmpty(respMap)) {
+                res.add(respMap);
+            }
+        }
+        return res;
+    }
+
+    /**
+     * 当前系统待办数据转换为ccpm已办
+     * @param hisTaskVo
+     * @return
+     * @throws Exception
+     */
+    public static Map<String, Object> copyHisTaskToCcpm(HisTaskVo hisTaskVo) throws Exception {
+        Map<String, Object> res = new HashMap<>();
+        Map<String, Object> vars = hisTaskVo.getVars();
+        res.put("belongProject",hisTaskVo.getBelongProject());
+        // 流程名称
+        if (StringUtils.isNotBlank(hisTaskVo.getProcessDefinitionName())){
+            res.put("typeLabel", hisTaskVo.getProcessDefinitionName());
+        }
+        // 标题
+        if (Objects.nonNull(vars.get("title"))){
+            res.put("title", "cpa " + vars.get("title").toString()); // 标题
+            res.put("content", vars.get("title").toString()); // 内容
+        }
+        // 流程发起人
+        if (Objects.nonNull(vars.get("userName"))){
+            res.put("createUserName",vars.get("userName").toString());
+        }
+        // 数据id
+        if (Objects.nonNull(hisTaskVo.getBusinessId())){
+            res.put("notifyId",hisTaskVo.getBusinessId());
+        }
+        // 审批状态
+        if (Objects.nonNull(hisTaskVo.getStatus())){
+            res.put("remarks",hisTaskVo.getStatus());
+        }
+        // 流程类型
+        if (StringUtils.isNotBlank(hisTaskVo.getProcessDefKey())){
+            res.put("type", hisTaskVo.getProcessDefKey());
+        }
+        // 当前环节
+        if (Objects.nonNull(hisTaskVo.getName())){
+            res.put("notifyRole", hisTaskVo.getName());
+        }
+        // 创建时间
+        if (Objects.nonNull(hisTaskVo.getCreateTime())){
+            res.put("createDate", hisTaskVo.getCreateTime());
+        }
+        // 流程id
+        if (Objects.nonNull(hisTaskVo.getExecutionId())){
+            res.put("id",hisTaskVo.getExecutionId());
+        }
+        return res;
+    }
+}

+ 544 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/GenerateFormUtil.java

@@ -0,0 +1,544 @@
+package com.jeeplus.centerservice.utils;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
+import com.jeeplus.centerservice.dto.WorkAttachmentDto;
+import com.jeeplus.centerservice.service.ccpm.flow.FlowRequest;
+import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.utils.StringUtils;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class GenerateFormUtil {
+
+    @Resource
+    private FlowRequest flowRequest;
+
+    /**
+     * 创建栅栏
+     * @return
+     */
+    public static Map<String, Object> createGrid() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "grid");
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("model", "grid_" + key); // 字段标识
+        map.put("columns", new ArrayList<>()); // 包含字段
+        Map<String, Object> optionsMap = new HashMap<>();
+        optionsMap.put("gutter", 0); // 栅格间隔
+        optionsMap.put("justify", "start"); // 水平排列方式
+        optionsMap.put("align", "top"); // 垂直排列方式
+        optionsMap.put("hidden", false); // 是否隐藏
+        optionsMap.put("flex", true); // flex布局
+        optionsMap.put("customClass", ""); // 自定义样式类名
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建列 12
+     * @return
+     */
+    public static Map<String, Object> createCol_12() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "col");
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("list", new ArrayList<>()); // 包含字段
+        Map<String, Object> optionsMap = new HashMap<>();
+        optionsMap.put("span", 15); // 占位
+        optionsMap.put("offset", 0);
+        optionsMap.put("push", 0);
+        optionsMap.put("pull", 0);
+        optionsMap.put("xs", 12);
+        optionsMap.put("sm", 12);
+        optionsMap.put("md", 12);
+        optionsMap.put("lg", 12);
+        optionsMap.put("xl", 12);
+        optionsMap.put("customClass", "");
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建列 24
+     * @return
+     */
+    public static Map<String, Object> createCol_24() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "col");
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("list", new ArrayList<>()); // 包含字段
+        Map<String, Object> optionsMap = new HashMap<>();
+        optionsMap.put("span", 24); // 占位
+        optionsMap.put("offset", 0);
+        optionsMap.put("push", 0);
+        optionsMap.put("pull", 0);
+        optionsMap.put("xs", 24);
+        optionsMap.put("sm", 24);
+        optionsMap.put("md", 24);
+        optionsMap.put("lg", 24);
+        optionsMap.put("xl", 24);
+        optionsMap.put("customClass", "");
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建单行文本
+     * @return
+     */
+    public static Map<String, Object> createInput() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "input");
+        map.put("name", "单行文本"); // input表单label值
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("model", "input_" + key); // 字段标识
+        Map<String, Object> optionsMap = publicOptions();
+        optionsMap.put("defaultValue", ""); // 默认值
+        optionsMap.put("dataType", ""); // 数据类型
+        optionsMap.put("dataTypeCheck", false);// 是否启用数据类型验证
+        optionsMap.put("dataTypeMessage", "");// 数据类型验证错误信息
+        optionsMap.put("pattern", ""); // 正则表达式
+        optionsMap.put("patternCheck", false); // 是否启用正则表达式验证
+        optionsMap.put("patternMessage", "");// 正则表达式验证错误信息
+        optionsMap.put("validatorCheck", false);// 是否启用自定验证
+        optionsMap.put("validator", "");// 自定义验证函数
+        optionsMap.put("placeholder", "");// 占位内容
+        optionsMap.put("showPassword", false);// 显示密码
+        optionsMap.put("clearable", false); // 是否可清除
+        optionsMap.put("maxlength", ""); // 最大输入长度
+        optionsMap.put("showWordLimit", false); // 是否显示输入长度
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建多行文本
+     * @return
+     */
+    public static Map<String, Object> createTextarea() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "textarea");
+        map.put("name", "多行文本"); // textarea表单label值
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("model", "textarea_" + key); // 字段标识
+        Map<String, Object> optionsMap = publicOptions();
+        optionsMap.put("defaultValue", ""); // 默认值
+        optionsMap.put("pattern", ""); // 正则表达式
+        optionsMap.put("patternCheck", false); // 是否启用正则表达式验证
+        optionsMap.put("patternMessage", "");// 正则表达式验证错误信息
+        optionsMap.put("validatorCheck", false);// 是否启用自定验证
+        optionsMap.put("validator", "");// 自定义验证函数
+        optionsMap.put("placeholder", "");// 占位内容
+        optionsMap.put("maxlength", ""); // 最大输入长度
+        optionsMap.put("showWordLimit", false); // 是否显示输入长度
+        optionsMap.put("rows", 2); // 输入框行数
+        optionsMap.put("autosize", false); // 高度是否自适应
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建分割线
+     * @return
+     */
+    public static Map<String, Object> createDivider() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "divider");
+        map.put("name", "分割线"); // 分割线标题
+        map.put("icon", "el-icon-warning-outline"); // 图标
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("model", "divider_" + key); // 字段标识
+        Map<String, Object> optionsMap = new HashMap<>();
+        optionsMap.put("hidden", false); // 是否隐藏
+        optionsMap.put("contentPosition", "left"); // 标题位置
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建子表单
+     * @return
+     */
+    public static Map<String, Object> createTable() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "table");
+        map.put("tableColumns", new ArrayList<>()); // 多列字段数据
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("model", "table_" + key); // 字段标识
+        Map<String, Object> optionsMap = publicOptions();
+        optionsMap.put("isLabelWidth", true);// 标签宽度是否自定义
+        optionsMap.put("labelWidth", 0);// 标签宽度,isLabelWidth 为 true 时生效
+        optionsMap.put("disabled", true);// 是否禁用
+        optionsMap.put("defaultValue", new ArrayList<>()); // 默认值
+        optionsMap.put("validatorCheck", false); // 是否启用自定验证
+        optionsMap.put("validator", ""); // 自定义验证函数
+        optionsMap.put("paging", false); // 是否分页
+        optionsMap.put("pageSize", 10); // 每页显示数目
+        optionsMap.put("isAdd", false); // 是否可新增行
+        optionsMap.put("isDelete", false); // 是否可删除行
+        optionsMap.put("showControl", false); // 展示控制按钮
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 创建文字
+     * @return
+     */
+    public static Map<String, Object> createText() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("type", "text");
+        map.put("name", "文字"); // 标题/表头
+        String key = UUID.randomUUID().toString();
+        map.put("key", key); // key
+        map.put("model", "text_" + key); // 字段标识
+        Map<String, Object> optionsMap = new HashMap<>();
+        optionsMap.put("defaultValue", ""); // 默认值
+        optionsMap.put("customClass", ""); // 自定义样式类名
+        optionsMap.put("labelWidth", 0); // 标签宽度,isLabelWidth 为 true 时生效
+        optionsMap.put("isLabelWidth", false); // 标签宽度是否自定义
+        optionsMap.put("hidden", false); // 是否隐藏
+        optionsMap.put("dataBind", true); // 是否进行数据绑定
+        map.put("options", optionsMap); // 配置
+        return map;
+    }
+
+    /**
+     * 一些公共字段,不适用所有组件
+     * @return
+     */
+    public static Map<String, Object> publicOptions() {
+        Map<String, Object> optionsMap = new HashMap<>();
+        optionsMap.put("customClass", "");// 自定义样式类名
+        optionsMap.put("isLabelWidth", false);// 标签宽度是否自定义。值为false时,宽度跟随表单配置(config)中的labelWidth属性
+        optionsMap.put("labelWidth", 100);// 标签宽度,isLabelWidth 为 true 时生效
+        optionsMap.put("hidden", false);// 是否隐藏
+        optionsMap.put("disabled", false);// 是否禁用
+        optionsMap.put("dataBind", true);// 是否进行数据绑定
+        optionsMap.put("required", false); // 是否必填
+        optionsMap.put("requiredMessage", ""); // 必填验证错误信息
+        optionsMap.put("width", "100%"); // 宽度
+        return optionsMap;
+    }
+
+    /**
+     * 表单默认配置
+     * @return
+     */
+    public static Map<String, Object> defaultConfig() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("labelWidth", 80); // 表单标签(label)宽度
+        map.put("labelPosition", "right"); // 标签对齐方式
+        map.put("size", "default"); // 组件尺寸
+        map.put("customClass", ""); // 自定义样式表类名
+        map.put("customJs", ""); // 自定义JS
+        map.put("eventType", "1"); // 自定义JS执行时机  1:保存前执行 2:保存后执行
+        map.put("ui", "element"); // 表单使用的组件库 Element: "element", Ant Design: "antd"
+        map.put("layout", "horizontal");
+        map.put("labelCol", 3); // label所占比例
+        map.put("actions", new ArrayList<>());
+        map.put("width", "100%"); // 表单宽度
+        map.put("hideLabel", false); // 是否隐藏label
+        map.put("hideErrorMessage", false); // 是否隐藏error信息
+        return map;
+    }
+
+    // 将map数据转换为前端需要的json数据
+    public static Map<String, Object> convertToForm(Map<String, Object> req) {
+        /*Map<String,Object> req = new LinkedHashMap<>();
+        // input
+        Map<String,Object> key1 = new HashMap<String,Object>();
+        key1.put("type", "input");
+        key1.put("label", "创建人");
+        key1.put("disabled", "1"); // 1:禁用。其他或者不赋值则不禁用
+        req.put(JSON.toJSONString(key1),"测试人员");
+        // textarea
+        Map<String,Object> key4 = new HashMap<String,Object>();
+        key4.put("type", "textarea");
+        key4.put("label", "测试多行文本");
+        key4.put("disabled", "1");
+        req.put(JSON.toJSONString(key4),"测试多行文本");
+        // table
+        Map<String,Object> key6 = new HashMap<String,Object>();
+        key6.put("type", "table");
+        key6.put("label", "测试表格1");
+        Map<String,String> tableColumns2 = new LinkedHashMap<>();
+        tableColumns2.put("text1","字段011");
+        tableColumns2.put("text2","字段02");
+        tableColumns2.put("text3","字段03");
+        key6.put("tableColumns", tableColumns2);
+        List<Map<String,Object>> tableList2 = new ArrayList<>();
+        Map<String,Object> tableMap12 = new HashMap<>();
+        tableMap12.put("text1","测试数据1112");
+        tableMap12.put("text2","测试数据12");
+        tableMap12.put("text3","测试数据13");
+        tableList2.add(tableMap12);
+        Map<String,Object> tableMap22 = new HashMap<>();
+        tableMap22.put("text1","测试数据21");
+        tableMap22.put("text2","测试数据22");
+        tableMap22.put("text3","测试数据23");
+        tableList2.add(tableMap22);
+        req.put(JSON.toJSONString(key6),tableList2);*/
+        // 以上为测试数据
+
+        // 返回结果
+        Map<String, Object> respMap = new HashMap<>();
+        // 初始化表单配置
+        Map<String, Object> defaultConfig = defaultConfig();
+        // 根据参数生成表单数据
+        List<Map<String, Object>> formList = new ArrayList<>();
+
+        req.forEach((k,v)->{
+            // 注:LinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺序。但是因为中间将LinkedHashMap转成了json字符串,
+            // 然后用fastjson转json对像进一步处理数据。这里的底层会默认采用hashmap的那一套对map数据又重新排序一次
+            // 为防止数据又重新排序,所以在这里转换时使用Feature.OrderedField来解决此问题
+            LinkedHashMap<String, Object> key = JSONObject.parseObject(k, LinkedHashMap.class, Feature.OrderedField);
+            String type = key.get("type").toString(); // 表单类型
+            switch (type) {
+                case "input": // 单行文本
+                    boolean createNew = true; // 是否创建新的栅栏,放入col_12的input
+                    if (formList.size() > 0) { // 表单列表已经有表单,则进入如下操作
+                        // 获取表单列表中最后一个表单
+                        Map<String, Object> lastForm = formList.get(formList.size() - 1);
+                        // 判断最后一个表单是否为栅栏
+                        if ("grid".equals(lastForm.get("type").toString())) {
+                            int size = Integer.parseInt(lastForm.get("size").toString()); // 获取栅栏中元素的占位
+                            List<Object> gridColumns = JSONArray.parseArray(JSON.toJSONString(lastForm.get("columns")));
+                            if (size == 12) { // 元素的占位是12,则不创建新的栅栏,直接放入col_12的input
+                                Map<String, Object> newGrid = setCol_12_Input(lastForm,gridColumns,key,v);
+                                formList.set(formList.size() - 1, newGrid);
+                                createNew = false;
+                            }
+                        }
+                    }
+                    if (createNew) { // createNew为true,表示需要创建新的栅栏,放入col_12的input
+                        Map<String, Object> newGrid = setCol_12_Input(createGrid(),new ArrayList<>(),key,v);
+                        formList.add(newGrid);
+                    }
+                    break;
+                case "textarea": // 多行文本
+                    Map<String, Object> newGrid = setCol_24_Textarea(createGrid(), new ArrayList<>(), key, v);
+                    formList.add(newGrid);
+                    break;
+                case "table": // 子表单,也就是表格
+                    Map<String, Object> divider = createDivider(); // 开始创建分割线
+                    if (ObjectUtil.isNotEmpty(key.get("label"))) {
+                        divider.put("name", key.get("label").toString());
+                    } else {
+                        divider.put("name", "详情列表");
+                    }
+                    formList.add(divider); // 添加分割线
+                    Map<String, Object> table = createTable(); // 开始创建表格
+                    List<Map<String, Object>> tableColumnList = new ArrayList<>();
+                    // 表头获取
+                    LinkedHashMap<String, Object> tableColumnsMap = JSONObject.parseObject(JSON.toJSONString(key.get("tableColumns")), LinkedHashMap.class, Feature.OrderedField);
+                    tableColumnsMap.forEach((columnKey,columnValue) -> {
+                        Map<String, Object> text = createText();
+                        text.put("name",columnValue.toString()); // 列头的名称
+                        text.put("model",columnKey); // 列表数据绑定的字段
+                        String textWidth = getTextWidthByValue(columnKey,v); // 根据该列下的值来判断此列的宽度应该设置为多少
+                        if (StringUtils.isNotBlank(textWidth)) {
+                            Map<String, Object> textOptionsMap = JSONObject.parseObject(JSON.toJSONString(text.get("options")), Map.class);
+                            textOptionsMap.put("width",textWidth); // 设置当前列的宽度
+                            text.put("options",textOptionsMap);
+                        }
+                        tableColumnList.add(text);
+                    });
+                    table.put("tableColumns",tableColumnList);
+                    // 列表数据
+                    List<Map<String, Object>> defaultValues =(List) JSONArray.parseArray(JSON.toJSONString(v)); // 通过集合中map的key对应表头的model来进行数据的绑定
+                    Map<String, Object> optionsMap = JSONObject.parseObject(JSON.toJSONString(table.get("options")));
+                    optionsMap.put("defaultValue",defaultValues); // 绑定列表的数据
+                    table.put("options",optionsMap);
+                    // 表格
+                    formList.add(table);
+                    break;
+                case "files": // 附件
+                    if (ObjectUtil.isNotEmpty(key.get("label"))) {
+                        respMap.put("filesLabel",key.get("label").toString()); // 附件label
+                    } else {
+                        respMap.put("filesLabel","附件"); // 附件label
+                    }
+                    List<WorkAttachmentDto> files = new ArrayList<>();
+                    if (ObjectUtil.isNotEmpty(v)) {
+                        List<Map<String, Object>> fileList = (List)JSONArray.parseArray(JSON.toJSONString(v));
+                        for (Map<String, Object> fileMap : fileList) {
+                            WorkAttachmentDto attachmentDto = new WorkAttachmentDto();
+                            UserDTO userDTO = new UserDTO();
+                            if (ObjectUtil.isNotEmpty(fileMap.get("attachmentName"))) { // 附件名称
+                                attachmentDto.setName(fileMap.get("attachmentName").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("createName"))) { // 创建人
+                                userDTO.setName(fileMap.get("createName").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("createDate"))) { // 创建时间
+                                attachmentDto.setCreateTime(DateUtil.parse(fileMap.get("createDate").toString()));
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("url"))) { // 文件地址
+                                attachmentDto.setUrl(fileMap.get("url").toString());
+                            }
+                            if (ObjectUtil.isNotEmpty(fileMap.get("temporaryUrl"))) { // 文件临时地址
+                                attachmentDto.setLsUrl(fileMap.get("temporaryUrl").toString());
+                            }
+                            attachmentDto.setCreateBy(userDTO);
+                            files.add(attachmentDto);
+                        }
+                    }
+                    respMap.put("files",files); // 附件
+                    break;
+                case "processInstanceId":
+                    respMap.put("processInstanceId", v.toString()); // processInstanceId
+                    break;
+                default:
+                    break;
+            }
+        });
+        respMap.put("list",formList); // 表单数据
+        respMap.put("config",defaultConfig); // 表单配置
+        return respMap;
+    }
+
+    /**
+     * 根据该列下的值来判断此列的宽度应该设置为多少
+     * @param columnKey
+     * @param value
+     * @return
+     */
+    public static String getTextWidthByValue(Object columnKey, Object value) {
+        String column = columnKey.toString();
+        AtomicReference<String> width = new AtomicReference<>("");
+        List<Map<String, Object>> list = (List)JSONObject.parseArray(JSONObject.toJSONString(value));
+
+        for (Map<String, Object> map : list) {
+            map.forEach((k,v) -> {
+                if (k.equals(column)) {
+                    String columnValue = v.toString();
+                    if (StringUtils.isNotBlank(columnValue)) {
+                        if (columnValue.length() >= 7) {
+                            width.set("150px");
+                        }
+                        if (columnValue.length() >= 12) {
+                            width.set("200px");
+                        }
+                        if (columnValue.length() >= 18) {
+                            width.set("300px");
+                        }
+                        if (columnValue.length() >= 24) {
+                            width.set("400px");
+                        }
+                    }
+                }
+            });
+        }
+        return width.get();
+    }
+
+    /**
+     * 创建列col_12,将input放到列中
+     * 最后将列放到栅栏中返回
+     */
+    public static Map<String, Object> setCol_12_Input(Map<String, Object> grid, List<Object> gridColumns, Map<String, Object> key, Object value) {
+        Map<String, Object> newGrid = grid; // 栅栏
+        List<Object> newGridColumns = setColInput("15", gridColumns, key, value);
+        newGrid.put("columns", newGridColumns);
+        if (ObjectUtil.isNotEmpty(newGrid.get("size"))) { // 设置栅栏当前包含元素的占位
+            int size = Integer.parseInt(newGrid.get("size").toString());
+            newGrid.put("size",size + 12);
+        } else {
+            newGrid.put("size",12);
+        }
+        return newGrid;
+    }
+
+    /**
+     * 创建列col_24,将input放到列中
+     * 最后将列放到栅栏中返回
+     */
+    public static Map<String, Object> setCol_24_Input(Map<String, Object> grid, List<Object> gridColumns, Map<String, Object> key, Object value) {
+        Map<String, Object> newGrid = grid; // 栅栏
+        List<Object> newGridColumns = setColInput("24", gridColumns, key, value);
+        newGrid.put("columns", newGridColumns);
+        newGrid.put("size",24); // 设置栅栏当前包含元素的占位
+        return newGrid;
+    }
+
+    /**
+     * 创建列,将input放到列中
+     * @param size 值为“24”时创建col_24,其他默认为col_12
+     */
+    public static List<Object> setColInput(String size, List<Object> gridColumns, Map<String, Object> key, Object value) {
+        Map<String, Object> col = createCol_12(); // 列 12
+        if ("24".equals(size)) {
+            col = createCol_24(); // 列 24
+        }
+        Map<String, Object> input = createInput(); // input
+        Map<String, Object> optionsMap = JSONObject.parseObject(JSON.toJSONString(input.get("options"))); // 获取input的默认options
+        if (CollectionUtil.isEmpty(gridColumns)) {
+            gridColumns = new ArrayList<>();
+        }
+        List<Object> newGridColumns = gridColumns;
+        List<Map<String, Object>> colList = new ArrayList<>();
+        if (ObjectUtil.isEmpty(key.get("label"))) {
+            input.put("name", "单行文本");
+        } else {
+            input.put("name", key.get("label").toString()); // input表单的label值
+        }
+        if (ObjectUtil.isNotEmpty(key.get("disabled")) && "1".equals(key.get("disabled").toString())) {
+            optionsMap.put("disabled", true); // 禁用
+        }
+        optionsMap.put("defaultValue", value); // input表单的value值
+        input.put("options", optionsMap);
+        colList.add(input);
+        col.put("list", colList);
+        newGridColumns.add(col);
+        return newGridColumns;
+    }
+
+    /**
+     * 创建列col_24,将textarea放到列中
+     * 最后将列放到栅栏中返回
+     */
+    public static Map<String, Object> setCol_24_Textarea(Map<String, Object> grid, List<Object> gridColumns, Map<String, Object> key, Object value) {
+        Map<String, Object> newGrid = grid; // 栅栏
+        Map<String, Object> col = createCol_24(); // 列
+        Map<String, Object> textarea = createTextarea(); // textarea
+        Map<String, Object> optionsMap = JSONObject.parseObject(JSON.toJSONString(textarea.get("options"))); // 获取textarea的默认options
+        if (CollectionUtil.isEmpty(gridColumns)) {
+            gridColumns = new ArrayList<>();
+        }
+        List<Object> newGridColumns = gridColumns;
+        List<Map<String, Object>> colList = new ArrayList<>();
+        if (ObjectUtil.isEmpty(key.get("label"))) {
+            textarea.put("name", "多行文本");
+        } else {
+            textarea.put("name", key.get("label").toString()); // textarea表单的label值
+        }
+        if (ObjectUtil.isNotEmpty(key.get("disabled")) && "1".equals(key.get("disabled").toString())) {
+            optionsMap.put("disabled", true); // 禁用
+        }
+        optionsMap.put("defaultValue", value); // textarea表单的value值
+        textarea.put("options", optionsMap);
+        colList.add(textarea);
+        col.put("list", colList);
+        newGridColumns.add(col);
+        newGrid.put("columns", newGridColumns);
+        newGrid.put("size",24); // 设置栅栏当前包含元素的占位
+        return newGrid;
+    }
+
+}

+ 483 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/Global.java

@@ -0,0 +1,483 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.centerservice.utils;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.DefaultResourceLoader;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * 全局配置类
+ * @author jeeplus
+ * @version 2014-06-25
+ */
+public class Global {
+
+	/**
+	 * 当前对象实例
+	 */
+	private static Global global = new Global();
+
+	/**
+	 * 保存全局属性值
+	 */
+	private static Map<String, String> map = Maps.newHashMap();
+
+	/**
+	 * 属性文件加载对象
+	 */
+	private static PropertiesLoader loader = new PropertiesLoader("bootstrap.yml");
+
+
+	/**
+	 * 显示/隐藏
+	 */
+	public static final String SHOW = "1";
+	public static final String HIDE = "0";
+
+	/**
+	 * 是/否
+	 */
+	public static final String YES = "1";
+	public static final String NO = "0";
+
+	/**
+	 * 对/错
+	 */
+	public static final String TRUE = "true";
+	public static final String FALSE = "false";
+
+	/**
+	 * 上传文件基础虚拟路径
+	 */
+	public static final String USERFILES_BASE_URL = "/userfiles/";
+
+	/**
+	 * 获取当前对象实例
+	 */
+	public static Global getInstance() {
+		return global;
+	}
+
+	/**
+	 * 获取配置
+	 * @see {fns:getConfig('adminPath')}
+	 */
+	public static String getConfig(String key) {
+		String value = map.get(key);
+		if (value == null){
+			value = loader.getProperty(key);
+			map.put(key, value != null ? value : StringUtils.EMPTY);
+		}
+		return value;
+	}
+
+	/**
+	 * 获取管理端根路径
+	 */
+	public static String getAdminPath() {
+		return getConfig("adminPath");
+	}
+	/**
+	 */
+	public static String getAliyunUrl() {
+		return getConfig("aliyunDownloadUrl");
+	}
+	/**
+	 */
+	public static String getAliDownloadUrl() {
+		return getConfig("aliyunUrl");
+	}
+	/**
+	 */
+	public static String getEndpoint() {
+		return getConfig("endpoint");
+	}
+	/**
+	 */
+	public static String getAccessKeyId() {
+		return getConfig("accessKeyId");
+	}
+	/**
+	 */
+	public static String getAccessKeySecret() {
+		return getConfig("accessKeySecret");
+	}
+	/**
+	 */
+	public static String getBucketName() {
+		return getConfig("bucketName");
+	}
+	/**
+	 */
+	public static String getQzBucketName() {
+		return getConfig("qzBucketName");
+	}
+	/**
+	 */
+	public static String getAvatarDir() {
+		return getConfig("avatarDir");
+	}
+	/**
+	 */
+	public static String getNotifyDir() {
+		return getConfig("notifyDir");
+	}
+	/**
+	 */
+	public static String getReportDir() {
+		return getConfig("reportDir");
+	}
+	/**
+	 */
+	public static String getRqcode() {
+		return getConfig("rqcode");
+	}
+	/**
+	 */
+	public static String getGoout() {
+		return getConfig("goout");
+	}
+	/**
+	 */
+	public static String getLeave() {
+		return getConfig("leave");
+	}
+	/**
+	 */
+	public static String getOvertimeform() {
+		return getConfig("overtimeform");
+	}
+	/**
+	 */
+	public static String getSealform() {
+		return getConfig("sealform");
+	}
+	/**
+	 *
+	 */
+	public static String getWorkReimbur() {return getConfig("workReimbur");}
+	/**
+	 */
+	public static String getEvection() {
+		return getConfig("evection");
+	}
+	/**
+	 */
+	public static String getOaBuy() {
+		return getConfig("oaBuy");
+	}
+	/**
+	 */
+	public static String getOaAll() {
+		return getConfig("oaAll");
+	}
+	/**
+	 */
+	public static String getIm() {
+		return getConfig("im");
+	}/**
+	 */
+	public static String getWorkContractInfo() {
+		return getConfig("workContractInfo");
+	}
+	/**
+	 */
+	public static String getNotifyData() {
+		return getConfig("notifyData");
+	}
+    /**
+     */
+    public static String getAppData() {
+        return getConfig("appData");
+    }
+	/**
+	 */
+	public static String getLogo() {
+		return getConfig("logo");
+	}
+    /**
+     */
+	public static String getPhoto() {
+		return getConfig("photo");
+	}
+	/**
+	 *
+	 */
+	public static String getUserEvaluation(){return getConfig("userEvaluation");}
+	/**
+	 */
+	public static String getWorkBidingDocument() {return getConfig("workBidingDocument");}
+	/**
+	 */
+	public static String getWorkEngineeringProject() {return getConfig("workEngineeringProject");}
+
+	/**
+	 */
+	public static String getWorkFullExecute() {return getConfig("workFullExecute");}
+	/**
+	 */
+	public static String getWorkFullMeetingminutes() {return getConfig("workFullMeetingminutes");}
+	/**
+	 */
+	public static String getWorkFullDesignchange(){return getConfig("workFullDesignchange");}
+	/**
+	 */
+	public static String getWorkFullConstructsheet(){return getConfig("workFullConstructsheet");}
+	/**
+	 */
+	public static String getWorkFullProprietorsheet(){return getConfig("workFullProprietorsheet");}
+	/**
+	 */
+	public static String getWorkFullSupervisorsheet(){return getConfig("workFullSupervisorsheet");}
+	/**
+	 */
+	public static String getWorkProjectReport() {return getConfig("workProjectReport");}
+	/**
+	 */
+	public static String getWorkProjectBasis() {return getConfig("workProjectBasis");}
+	/**
+	 */
+	public static String getWorkProjectRemote() {return getConfig("workProjectRemote");}
+	/**
+	 */
+	public static String getWorkProjectSummary() {return getConfig("workProjectSummary");}
+	/**
+	 */
+	public static String getWorkProjectOther() {return getConfig("workProjectOther");}
+	/**
+	 */
+	public static String getWorkVisa() {return getConfig("workVisa");}
+	/**
+	 */
+	public static String getOfficehonor() {return getConfig("Officehonor");}
+	/**
+	 *
+	 */
+	public static String getJobResume() {return getConfig("jobResume");}
+	/**
+	 *
+	 */
+	public static String getSatisfaction() {return getConfig("satisfaction");}
+	/**
+	 *
+	 */
+	public static String getCertificate() {return getConfig("certificate");}
+	/**
+	 *
+	 */
+	public static String getJudgeAttachment() {return getConfig("judgeAttachment");}
+	/**
+	 * 获取前端根路径
+	 */
+	public static String getFrontPath() {
+		return getConfig("frontPath");
+	}
+
+	/**
+	 * 获取URL后缀
+	 */
+	public static String getUrlSuffix() {
+		return getConfig("urlSuffix");
+	}
+
+	/**
+	 * 获取电子签章文件路径
+	 */
+	public static String getISignature() {
+		return getConfig("iSignature");
+	}
+
+	/**
+	 * 获取公共密码
+	 */
+	public static String getPublicPassword() {
+		return getConfig("publicPassword");
+	}
+
+	/**
+	 */
+	public static String getOSSUrl() {
+		return getConfig("oSSUrl");
+	}
+	public static String getContractNumPath() {
+		return getConfig("contract_num_path");
+	}
+	/**
+	 * 是否是演示模式,演示模式下不能修改用户、岗位、密码、菜单、授权
+	 */
+	public static Boolean isDemoMode() {
+		String dm = getConfig("demoMode");
+		return "true".equals(dm) || "1".equals(dm);
+	}
+
+	/**
+	 * 在修改系统用户和岗位时是否同步到Activiti
+	 */
+	public static Boolean isSynActivitiIndetity() {
+		String dm = getConfig("activiti.isSynActivitiIndetity");
+		return "true".equals(dm) || "1".equals(dm);
+	}
+
+	/**
+	 * 页面获取常量
+	 * @see {fns:getConst('YES')}
+	 */
+	public static Object getConst(String field) {
+		try {
+			return Global.class.getField(field).get(null);
+		} catch (Exception e) {
+			// 异常代表无配置,这里什么也不做
+		}
+		return null;
+	}
+
+    /**
+     * 获取工程路径
+     * @return
+     */
+    public static String getProjectPath(){
+    	// 如果配置了工程路径,则直接返回,否则自动获取。
+		String projectPath = Global.getConfig("projectPath");
+		if (StringUtils.isNotBlank(projectPath)){
+			return projectPath;
+		}
+		try {
+			File file = new DefaultResourceLoader().getResource("").getFile();
+			if (file != null){
+				while(true){
+					File f = new File(file.getPath() + File.separator + "src" + File.separator + "main");
+					if (f == null || f.exists()){
+						break;
+					}
+					if (file.getParentFile() != null){
+						file = file.getParentFile();
+					}else{
+						break;
+					}
+				}
+				projectPath = file.toString();
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return projectPath;
+    }
+
+    /**
+     * 获取短信SMS信息
+     */
+    public static String getSmsUserid() {
+        return getConfig("sms_userid");
+    }
+    public static String getSmsAccount() {
+        return getConfig("sms_account");
+    }
+    public static String getSmsPassword() {
+        return getConfig("sms_password");
+    }
+    public static String getSmsMobile() {
+        return getConfig("sms_mobile");
+    }
+    public static String getSmsContent() {
+        return getConfig("sms_content");
+    }
+    public static String getSmsSendTime() {
+        return getConfig("sms_sendTime");
+    }
+    public static String getSmsAction() {
+        return getConfig("sms_action");
+    }
+    public static String getSmsCheckcontent() {
+        return getConfig("sms_checkcontent");
+    }
+
+	/**
+	 * 获取数据库连接信息
+	 */
+	public static String getJdbcUserName() {
+		return getConfig("jdbc.username");
+	}
+	public static String getJdbcPassword() {
+		return getConfig("jdbc.password");
+	}
+	public static String getJdbcUrl() {
+		return getConfig("jdbc.url");
+	}
+	public static String getJdbcDriver() {
+		return getConfig("jdbc.driver");
+	}
+
+	/**
+	 * 获取容联云账户信息
+	 */
+	public static String getRongUserid() {
+		return getConfig("rong_userid");
+	}
+	public static String getRongToken() {
+		return getConfig("rong_token");
+	}
+	//应用id
+	public static String getAppId() {
+		return getConfig("app_id");
+	}
+	//模板id
+	public static String getTemplateId() {
+		return getConfig("template_id");
+	}
+	//短信发送方式(1:旧的 2:容联云通讯)
+	public static String getCodeType() {
+		return getConfig("code_type");
+	}
+
+    public static String getOpenOfficeAddr() {
+        return getConfig("open_office_addr");
+    }
+
+    public static int getOpenOfficePort() {
+        String openOfficePort = getConfig("open_office_port");
+        return StringUtils.isBlank(openOfficePort)?8100:Integer.valueOf(openOfficePort);
+    }
+    public static String getOpenfireServer() {
+        String openOfficePort = getConfig("openfire.server");
+        return StringUtils.isBlank(openOfficePort)?"oa-pre.ssruihua.com":openOfficePort;
+    }
+    public static String getSysNotify() {
+        String sysNotify = getConfig("sys.notify");
+        return StringUtils.isBlank(sysNotify)?"http://cdn.gangwaninfo.com/jeeplus-resource-data/static/sys/notify.png":sysNotify;
+    }
+
+    public static String getStaffBasicFilePath() {
+        return getConfig("staff_basic_file_path");
+    }
+	public static String getDbName() {
+		return getConfig("db.name");
+	}
+	public static String getVersion() {
+		return getConfig("app_version");
+	}
+	public static String getTestVersion() {
+		return getConfig("app_version_test");
+	}
+
+    public static String getProjectTemplatePath() {
+        return getConfig("project.plan.template.path");
+    }
+
+    public static String getYyApiCode(){
+		return getConfig("yy_apicode");
+	}
+
+	public static String getYyMhUrl(){
+		return getConfig("yy_mhcxurl");
+	}
+
+	public static String getYyShUrl(){
+		return getConfig("yy_shcxurl");
+	}
+}

+ 154 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/PropertiesLoader.java

@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2005-2011 springside.org.cn
+ * 
+ * $Id: PropertiesLoader.java 1690 2012-02-22 13:42:00Z calvinxiu $
+ */
+package com.jeeplus.centerservice.utils;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+
+/**
+ * Properties文件载入工具类. 可载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的值,但以System的Property优先.
+ * @author calvin
+ * @version 2013-05-15
+ */
+public class PropertiesLoader {
+
+	private static Logger logger = LoggerFactory.getLogger(PropertiesLoader.class);
+
+	private static ResourceLoader resourceLoader = new DefaultResourceLoader();
+
+	private final Properties properties;
+
+	public PropertiesLoader(String... resourcesPaths) {
+		properties = loadProperties(resourcesPaths);
+	}
+
+	public Properties getProperties() {
+		return properties;
+	}
+
+	/**
+	 * 取出Property,但以System的Property优先,取不到返回空字符串.
+	 */
+	private String getValue(String key) {
+		String systemProperty = System.getProperty(key);
+		if (systemProperty != null) {
+			return systemProperty;
+		}
+		if (properties.containsKey(key)) {
+	        return properties.getProperty(key);
+	    }
+	    return "";
+	}
+
+	/**
+	 * 取出String类型的Property,但以System的Property优先,如果都为Null则抛出异常.
+	 */
+	public String getProperty(String key) {
+		String value = getValue(key);
+		if (value == null) {
+			throw new NoSuchElementException();
+		}
+		return value;
+	}
+
+	/**
+	 * 取出String类型的Property,但以System的Property优先.如果都为Null则返回Default值.
+	 */
+	public String getProperty(String key, String defaultValue) {
+		String value = getValue(key);
+		return value != null ? value : defaultValue;
+	}
+
+	/**
+	 * 取出Integer类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常.
+	 */
+	public Integer getInteger(String key) {
+		String value = getValue(key);
+		if (value == null) {
+			throw new NoSuchElementException();
+		}
+		return Integer.valueOf(value);
+	}
+
+	/**
+	 * 取出Integer类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常
+	 */
+	public Integer getInteger(String key, Integer defaultValue) {
+		String value = getValue(key);
+		return value != null ? Integer.valueOf(value) : defaultValue;
+	}
+
+	/**
+	 * 取出Double类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常.
+	 */
+	public Double getDouble(String key) {
+		String value = getValue(key);
+		if (value == null) {
+			throw new NoSuchElementException();
+		}
+		return Double.valueOf(value);
+	}
+
+	/**
+	 * 取出Double类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常
+	 */
+	public Double getDouble(String key, Integer defaultValue) {
+		String value = getValue(key);
+		return value != null ? Double.valueOf(value) : defaultValue;
+	}
+
+	/**
+	 * 取出Boolean类型的Property,但以System的Property优先.如果都为Null抛出异常,如果内容不是true/false则返回false.
+	 */
+	public Boolean getBoolean(String key) {
+		String value = getValue(key);
+		if (value == null) {
+			throw new NoSuchElementException();
+		}
+		return Boolean.valueOf(value);
+	}
+
+	/**
+	 * 取出Boolean类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容不为true/false则返回false.
+	 */
+	public Boolean getBoolean(String key, boolean defaultValue) {
+		String value = getValue(key);
+		return value != null ? Boolean.valueOf(value) : defaultValue;
+	}
+
+	/**
+	 * 载入多个文件, 文件路径使用Spring Resource格式.
+	 */
+	private Properties loadProperties(String... resourcesPaths) {
+		Properties props = new Properties();
+
+		for (String location : resourcesPaths) {
+
+//			logger.debug("Loading properties file from:" + location);
+
+			InputStream is = null;
+			try {
+				Resource resource = resourceLoader.getResource(location);
+				is = resource.getInputStream();
+				props.load(is);
+			} catch (IOException ex) {
+				logger.info("Could not load properties from path:" + location + ", " + ex.getMessage());
+			} finally {
+				IOUtils.closeQuietly(is);
+			}
+		}
+		return props;
+	}
+}

+ 266 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/centerservice/utils/RestTemplateService.java

@@ -0,0 +1,266 @@
+package com.jeeplus.centerservice.utils;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.jeeplus.common.TokenProvider;
+import com.jeeplus.sys.feign.IUserApi;
+import com.jeeplus.sys.service.dto.UserDTO;
+
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringTokenizer;
+
+@Component
+public class RestTemplateService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    /**
+     * 访问get接口 - CAS 系统
+     * @param path 接口路径
+     * @param token token
+     * @param paramMap 请求参数-路径后
+     * @return
+     */
+    public Object getCas(String path, String token, Map<String, Object> paramMap) {
+        return httpRequest(HttpMethod.GET, token, paramMap, null, Global.getConfig("CAS_PATH"), path,"cas");
+    }
+
+    /**
+     * 访问post接口 - CCPM 系统
+     * @param path 接口路径
+     * @param token token
+     * @param paramMap 请求参数-路径后
+     * @param bodyMap 请求参数-请求体
+     * @return
+     */
+    public Object postCCPM(String path, String token, Map<String, Object> paramMap, Map<String, Object> bodyMap) {
+        return httpRequest(HttpMethod.POST, token, paramMap, bodyMap, Global.getConfig("CCPM_PATH"), path, "ccpm");
+    }
+
+    /**
+     * 访问get接口 - CCPM 系统
+     * @param path 接口路径
+     * @param token token
+     * @param paramMap 请求参数-路径后
+     * @return
+     */
+    public Object getCCPM(String path, String token, Map<String, Object> paramMap) {
+        return httpRequest(HttpMethod.GET, token, paramMap, null, Global.getConfig("CCPM_PATH"), path,"ccpm");
+    }
+
+    /**
+     * 访问get接口 - CCPM 系统
+     * @param path 接口路径
+     * @param token token
+     * @param paramMap 请求参数-路径后
+     * @return
+     */
+    public Object getCCPMMultithreading(String path, String token, Map<String, Object> paramMap, UserDTO userDTO) {
+        return httpRequestMultithreading(HttpMethod.GET, token, paramMap, null, Global.getConfig("CCPM_PATH"), path,"ccpm",userDTO);
+    }
+
+    /**
+     * 访问远程接口方法
+     * @param method 请求类型
+     * @param token token
+     * @param paramMap 请求参数-路径后
+     * @param bodyMap 请求参数-请求体
+     * @param hostAddress 服务host地址
+     * @param path 接口路径
+     * @param flag 接口路径
+     * @return
+     */
+    public Object httpRequest(HttpMethod method, String token, Map<String, Object> paramMap, Map<String, Object> bodyMap, String hostAddress, String path, String flag) {
+        Object res = null;
+        //获取当前登陆人的信息
+        UserDTO currentUserDTO = SpringUtil.getBean(IUserApi.class).getByToken(TokenProvider.getCurrentToken());
+        try {
+            JSONObject jsonObject = new JSONObject();
+            if (CollectionUtil.isNotEmpty(bodyMap)) {
+                jsonObject = new JSONObject(bodyMap); // 另一端接口需要使用@RequestBody来接收此参数
+            }
+            String url = getUrl(hostAddress, path, paramMap);
+            HttpHeaders httpHeaders = new HttpHeaders();
+            if("ccpm".equals(flag)){
+                String cookie = ccpmValidatePassword(currentUserDTO);
+                httpHeaders.add("cookie", cookie);
+            }else{
+    //        httpHeaders.add("token",token);
+            }
+            httpHeaders.add("Accept", MediaType.ALL_VALUE);
+            httpHeaders.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
+            HttpEntity<Object> entity = new HttpEntity<>(jsonObject, httpHeaders);
+            ResponseEntity<Object> responseEntity = restTemplate.exchange(url, method, entity, Object.class);
+            res = responseEntity.getBody();
+        } catch (Exception e) {
+            System.out.println("远程调用失败");
+            e.printStackTrace();
+        }
+        return res;
+    }
+
+    /**
+     * 访问远程接口方法
+     * @param method 请求类型
+     * @param token token
+     * @param paramMap 请求参数-路径后
+     * @param bodyMap 请求参数-请求体
+     * @param hostAddress 服务host地址
+     * @param path 接口路径
+     * @param flag 接口路径
+     * @return
+     */
+    public Object httpRequestMultithreading(HttpMethod method, String token, Map<String, Object> paramMap, Map<String, Object> bodyMap, String hostAddress, String path, String flag, UserDTO userDTO) {
+        Object res = null;
+        try {
+            JSONObject jsonObject = new JSONObject();
+            if (CollectionUtil.isNotEmpty(bodyMap)) {
+                jsonObject = new JSONObject(bodyMap); // 另一端接口需要使用@RequestBody来接收此参数
+            }
+            String url = getUrl(hostAddress, path, paramMap);
+            HttpHeaders httpHeaders = new HttpHeaders();
+            if("ccpm".equals(flag)){
+                String cookie = ccpmValidatePassword(userDTO);
+                httpHeaders.add("cookie", cookie);
+            }else{
+    //        httpHeaders.add("token",token);
+            }
+            httpHeaders.add("Accept", MediaType.ALL_VALUE);
+            httpHeaders.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
+            HttpEntity<Object> entity = new HttpEntity<>(jsonObject, httpHeaders);
+            ResponseEntity<Object> responseEntity = restTemplate.exchange(url, method, entity, Object.class);
+            res = responseEntity.getBody();
+        } catch (Exception e) {
+            System.out.println("远程调用失败");
+            e.printStackTrace();
+        }
+        return res;
+    }
+
+    /**
+     * 判定人员信息是否有效
+     * @param user
+     * @return
+     * @throws IOException
+     */
+    public String ccpmValidatePassword(UserDTO user) {
+        StringBuffer response = new StringBuffer();
+        //请求地址
+        String url = Global.getConfig("CCPM_PATH") + "/a/sys/register/validatePasswordPublic";
+        HttpClient client = new HttpClient();
+        //post请求方式
+        PostMethod postMethod = new PostMethod(url);
+        //推荐的数据存储方式,类似key-value形式
+        Map telPair = new HashMap();
+        telPair.put("loginName",user.getLoginName());
+        telPair.put("password", Global.getPublicPassword());
+        //封装请求参数
+        postMethod.setRequestBody(telPair.toString());
+        //这里是设置请求内容为json格式,根据站点的格式决定
+        //因为这个网站会将账号密码转为json格式,所以需要这一步
+        postMethod.setRequestHeader("Content-Type","application/json; charset=UTF-8;");
+        //执行请求
+        try {
+            client.executeMethod(postMethod);
+            // 读取为 InputStream
+            BufferedReader reader = new BufferedReader(new InputStreamReader(postMethod.getResponseBodyAsStream()));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                response.append(line);
+            }
+            reader.close();
+        } catch (IOException e) {
+            System.out.println("远程调用失败");
+        } finally {
+            postMethod.releaseConnection();
+        }
+        if("true".equals(response.toString())){
+            String cookie = getCcpmCookie(user);
+            return cookie;
+        }
+        return null;
+    }
+
+    /**
+     * 获取ccpm登录用户cookie信息
+     * @param user
+     * @return
+     * @throws IOException
+     */
+    public String getCcpmCookie(UserDTO user) {
+        //请求地址
+        String url = Global.getConfig("CCPM_PATH") + "/a/login";
+        HttpClient client = new HttpClient();
+        //post请求方式
+        PostMethod postMethod = new PostMethod(url);
+        //封装请求参数
+        postMethod.setParameter("username",user.getName());
+        postMethod.setParameter("password", Global.getPublicPassword());
+        //这里是设置请求内容为json格式,根据站点的格式决定
+        //因为这个网站会将账号密码转为json格式,所以需要这一步
+        postMethod.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8;");
+        //执行请求
+        try {
+            client.executeMethod(postMethod);
+            //通过Post/GetMethod对象获取响应头信息
+            String cookies = postMethod.getResponseHeader("Set-Cookie").getValue();
+            if(StringUtils.isNotBlank(cookies)){
+                StringTokenizer result = new StringTokenizer(cookies,";");   // 实例化对象,并指向以 - 对 a 进行分割
+                while(result.hasMoreTokens()){ // 对 result 遍历并打印子字符串;
+                    String cookie = result.nextToken();
+                    if(StringUtils.isNotBlank(cookie) && cookie.contains("jeeplus.session.id")){
+                        return cookie;
+                    }
+                }
+            }
+        } catch (IOException e) {
+            System.out.println("远程调用失败");
+        } finally {
+            postMethod.releaseConnection();
+        }
+        return null;
+    }
+
+    /**
+     * 将参数拼接到请求路径中
+     * @param hostAddress 服务host地址
+     * @param path 接口路径
+     * @param map 请求参数
+     * @return
+     */
+    public String getUrl(String hostAddress, String path, Map<String, Object> map) {
+        String url = hostAddress + path;
+        StringBuilder paramStr = new StringBuilder();
+        if (CollectionUtil.isNotEmpty(map)) {
+            for (String key : map.keySet()) {
+                Object o = map.get(key);
+                if (Objects.nonNull(o)) {
+//                    String value = URLEncoder.encode(o.toString(), "utf-8");
+                    paramStr.append("&").append(key).append("=").append(o);
+                }
+            }
+        }
+        if (StringUtils.isNotBlank(paramStr.toString())){
+            String param = paramStr.substring(1).toString(); // 去掉第一个&
+            url = url + "?" + param;
+        }
+        return url;
+    }
+}

ファイルの差分が大きいため隠しています
+ 422 - 180
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/controller/FlowableTaskController.java


+ 3 - 3
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/service/FlowTaskService.java

@@ -352,11 +352,11 @@ public class FlowTaskService {
      *
      * @return
      */
-    public Page <ProcessVo> todoList(Page <ProcessVo> page, Flow flow, String type) {
+    public Page <ProcessVo> todoList(Page <ProcessVo> page, Flow flow, String type,String id) {
         List <HashMap <String, String>> result = new ArrayList <HashMap <String, String>> ( );
-        String userId = userApi.getByToken ( TokenProvider.getCurrentToken ( ) ).getId ( );//ObjectUtils.toString(UserUtils.getUser().getId());
+//        String userId = userApi.getByToken ( TokenProvider.getCurrentToken ( ) ).getId ( );//ObjectUtils.toString(UserUtils.getUser().getId());
         // =============== 已经签收或者等待签收的任务  ===============
-        TaskQuery todoTaskQuery = taskService.createTaskQuery ( ).taskCandidateOrAssigned ( userId ).active ( )
+        TaskQuery todoTaskQuery = taskService.createTaskQuery ( ).taskCandidateOrAssigned ( id ).active ( )
                 .includeProcessVariables ( ).orderByTaskCreateTime ( ).desc ( );
 
         // 设置查询条件

+ 4 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/vo/HisTaskVo.java

@@ -31,6 +31,10 @@ public class HisTaskVo {
 
     private TaskVo currentTask; // 当前流程节点
 
+    private String belongProject; // 所属系统
+    private String processDefKey; // 流程key
+    private String businessId; // 数据详情id
+
     public HisTaskVo(HistoricTaskInstance task) {
         this.id = task.getId ( );
         this.name = task.getName ( );

+ 2 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/vo/ProcessVo.java

@@ -25,6 +25,8 @@ public class ProcessVo {
     private String status; //流程状态
     private String level; //状态级别,用于控制在前台显示的颜色
 
+    private String belongProject; // 所属系统 ccpm cpa ...
+
     public String getId() { // 流程实例id 作为列表的id
         return processInstanceId;
     }

+ 3 - 0
jeeplus-modules/jeeplus-flowable/src/main/java/com/jeeplus/flowable/vo/TaskVo.java

@@ -31,4 +31,7 @@ public class TaskVo {
         this.processDefinitionId = task.getProcessDefinitionId ( );
         this.processInstanceId = task.getProcessInstanceId ( );
     }
+
+    public TaskVo() {
+    }
 }

+ 14 - 0
jeeplus-modules/jeeplus-flowable/src/main/resources/bootstrap.yml

@@ -60,3 +60,17 @@ management:
     web:
       exposure:
         include: "*"
+
+#其他系统的地址
+CCPM_PATH:  http://localhost:8888
+#待办中展示其他系统的流程
+#ccpm =》 39 项目登记,13,102 报销,  108 电子发票报销,  109 普通报销,  21 213 发票
+CCPM_TASK: 13,102,39,108,109,21,213
+
+#各服务引用状态 =》 (若包含,则进行获取该服务的流程信息)
+INQUIRE_STATUS: ccpm
+
+CAS_PATH: http://www.casserver.com:8443
+
+# 公共密码
+publicPassword: jsxgpassword