# 流程推送开发指南

# 1.功能介绍

七巧Plus低码开发平台面向第三方统一待办类产品,提供了流程引擎数据的主动推送机制,满足待办、已办、已阅等数据实时集成场景。

# 2.使用教程

# 2.1.流程推送配置

配置新增待办URL:用于新增待办、待阅;

配置修改待办URL:用于待办转已办,待阅转已阅,更新单据内容(例如:标题、当前节点、流程状态);

配置删除待办URL:用于删除待办、删除已办、删除待阅、删除已阅;

Token:为以上3个接口的请求数据的AES的密钥;

流程数据推送范围:勾选流程后,对应流程的变更后将会主动推送到第三方服务;

image.png

# 2.2流程推送接口说明

# 2.2.1.查询租户内流程推送数据接口说明

1).开发平台公共API管理处勾选查询租户内流程推送数据权限后,才能通过OpenApi的方式调用查询查询租户内流程推送数据接口。

image.png

2).获取OpenApi接口的token,参考文档https://qiqiao.do1.com.cn/help/develop_manual/%E9%9B%86%E6%88%90%E4%B8%AD%E5%BF%83/AccessToken%E6%8E%A5%E5%8F%A3.html

3).调用OpenApi调用查询租户内流程推送数据接口

功能描述

查询租户内流程推送数据

请求说明

请求方式:Get

请求URL :https://qiqiao.do1.com.cn/plus/cgi-bin/open/third/process/todo/record

请求参数

参数 数据类型 必须 说明
page int 是 页码
pageSize int 是 页数大小(默认10)
workId String 否 工单id
startTime long 否 开始时间(yyyy-MM-dd HH:mm:ss)
endTime long 否 结束时间(yyyy-MM-dd HH:mm:ss)

返回结果

参数 数据类型 必须 说明
code int 是 0为成功,其他失败
msg string 是
data Object 是

返回结果Data说明

参数 数据类型 必须 说明
currPage int 是 当前页
pageSize int 是 每页条数
totalCount int 是 总数
totalPage int 是 总页数
list Array 是 数据集合

返回结果list说明

参数 数据类型 必须 说明
tenantId string 是 租户id
applicationId string 是 应用id
processModelId string 是 流程模型id
processDefinitionId string 是 流程定义id
processInstanceId string 是 流程实例id
taskId string 是 节点任务id
userId string 是 用户id
workId string 是 单据id
processName string 是 流程名称
workTitle string 是 流程标题
workUrl string 是 流程跳转url
workType int 是 单据类型:0待办、1待阅、2已办、3已阅
workStatus string 是 流程状态(中文)
workCreator string 是 发起人id
workName string 是 发起人名称
currentNodeId string 是 当前节点定义Id
currentNodeName string 是 当前节点名称
workCreateTime string 是 工单创建时间
workDealTime string 是 工单处理时间
createTime string 是 创建时间
updateTime string 是 更新时间
{
    "msg": "执行成功",
    "traceId": "10ce053eb4910e9f92c4d2495da84cd8",
    "code": 0,
    "data": {
        "currPage": 1,
        "pageSize": 10,
        "totalCount": 2,
        "totalPage": 1,
        "list": [
            {
                "applicationId": "60b9fdeec4a88332821818e6",
                "createTime": 1659077738180,
                "currentNodeId": "obj_03",
                "currentNodeName": "人工任务1",
                "processDefinitionId": "6691261217077854209",
                "processInstanceId": "6714034989108953088",
                "processModelId": "6691261217077854208",
                "processName": "统一待办推送测试",
                "taskId": "6714034989108953094",
                "tenantId": "2efc32ee89074e919afa2219e3cace53",
                "updateTime": 1658977911786,
                "userId": "3534b08f0ca503a2dca7bf0ff691dff4",
                "workCreateTime": 1659077737201,
                "workCreator": "b2c26e0438a654765d932c510d071eb8",
                "workDealTime": 1658977909708,
                "workId": "6714035057828397056",
                "workName": "刘言",
                "workStatus": "已完成",
                "workTitle": "刘言的统一待办推送测试_2022072914",
                "workType": "2",
                "workUrl": "https://xxxx/mruntime/?agentCode=qiqiao2dev&corp_id=ww4852f35d45307a6f#/admin/workflow/detail/6714034989108953088?applicationId=60b9fdeec4a88332821818e6&activityDefinitionId=obj_03&scope=TODO&taskId=6714034989108953094&sourceType=YBG_TODO"
            },
            {
                "applicationId": "60b882a10cf2ab377c02a757",
                "createTime": 1658989010000,
                "currentNodeId": "obj_03",
                "currentNodeName": "人工任务",
                "processDefinitionId": "6257ebddcf588d42b3c7ed95",
                "processInstanceId": "0aeb1e6cf272463dbc1e65e6b76c8db6",
                "processModelId": "6257eba2cf588d42b3c7ed94",
                "processName": "流程名称很长流程名称很长流程名称很长流程",
                "taskId": "f68e9fadb0e24d99a8e7a4981c28efbf",
                "tenantId": "2efc32ee89074e919afa2219e3cace53",
                "updateTime": 1658989010000,
                "userId": "56e9f9b4851dd08259fb16a271864663",
                "workCreateTime": 1654753971413,
                "workCreator": "baff3ca77b70b703ec28a01afee81ba6",
                "workDealTime": null,
                "workId": "001bd5bde0a647e1a75f8af8391be7b5",
                "workName": "殷素云",
                "workStatus": "审批中",
                "workTitle": "殷素云的流程名称很长流程名称很长流程名称很长流程_2022060913",
                "workType": "0",
                "workUrl": "https://xxxx/mruntime/?agentCode=xxx2dev&corp_id=#/admin/workflow/detail/0aeb1e6cf272463dbc1e65e6b76c8db6?applicationId=60b882a10cf2ab377c02a757&activityDefinitionId=obj_03&scope=TODO&taskId=f68e9fadb0e24d99a8e7a4981c28efbf&sourceType=YBG_TODO"
            }
        ]
    }
}

# 2.2.2.推送方式及加密说明

新增待办推送接口、更新待办推送接口、删除待办推送接口均采用Post请求,由七巧plus推送至第三方配置的地址

1) AES对称加密

· AES对称加密

  • 加密模式:ECB
  • 填充:pkcs7
  • 数据块:128位
  • 密钥:用户设置的token字符串
  • 字符集:utf8

· 加密内容输出方式

将加密后的内容通过base64字符串方式输出

· 加密算法示例

**· 添加依赖**
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

​ · 加密工具类

public final class EncryptUtils {
    /**
     * 加密算法
     */
    private static final String ENCRY_ALGORITHM = "AES";

    /**
     * 加密算法/加密模式/填充类型
     * 采用AES加密,ECB加密模式,PKCS7Padding填充
     */
    private static final String CIPHER_MODE = "AES/ECB/PKCS7Padding";

    /**
     * 设置加密字符集
     * 采用 UTF-8 字符集
     */
    private static final String CHARACTER = "UTF-8";

    private EncryptUtils() {
    }

    /**
     * AES加密
     *
     * @param content    加密内容
     * @param encryptKey 加密密钥
     * @return
     */
    private static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        if (StringUtils.isEmpty(content)) {
            log.error("The encrypted content must not be null!");
            throw new EncryptContentNullException("The encrypted content must not be null!");
        }
        SecretKey key = getKey(encryptKey);
        log.info("密钥:{}", cn.com.do1.qiqiao.webhook.encrypt.utils.Base64.encode(key.getEncoded()));

        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(content.getBytes(CHARACTER));
    }

    /**
     * 生成密钥
     *
     * @param strKey
     * @return
     */
    public static SecretKey getKey(String strKey) {
        try {
            KeyGenerator generator = KeyGenerator.getInstance(ENCRY_ALGORITHM);
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(strKey.getBytes());
            generator.init(128, secureRandom);
            return generator.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(" 初始化密钥出现异常 ");
        }
    }

    /**
     * AES解密
     *
     * @param encryptBytes 待解密的byte[]
     * @param decryptKey   解密密钥
     * @return 解密后的String
     * @throws Exception
     */
    private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        SecretKey key = getKey(decryptKey);
        log.info("密钥:{}", cn.com.do1.qiqiao.webhook.encrypt.utils.Base64.encode(key.getEncoded()));
        // 添加加密模式
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return new String(cipher.doFinal(encryptBytes), CHARACTER);
    }

    /**
     * base 64 encode
     *
     * @param bytes 待编码的byte[]
     * @return 编码后的base 64 code
     */
    private static String base64Encode(byte[] bytes) {
        try {
            log.info("加密后的内容:{}", bytes);
            return new String(Base64.encode(bytes), CHARACTER);//   new BASE64Encoder().encode(bytes);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * base 64 decode
     *
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    private static byte[] base64Decode(String base64Code) throws Exception {
        return Base64.decode(base64Code.getBytes(CHARACTER));
    }

    /**
     * AES加密为base 64 code
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的base 64 code
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    }

    /**
     * 将base 64 code AES解密
     *
     * @param encryptStr 待解密的base 64 code
     * @param decryptKey 解密密钥
     * @return 解密后的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return StringUtils.isBlank(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    }
}

2)url有效性鉴权

POST http://example.com/qiqiao/hook?timestamp=1498586609

Headers:{
    "Content-type":"application/json",
    "X-Auth0-DeliverId":"31a2ae17-2661-4234-8d79-f62f3175fd75",
}

Body:{
    "eventType":"URL_VERIFY",
    "data": "随机字符串"
}

Response: {
    "msg":"执行成功",
    "code": 0,
    "data": {
       "token" : "zvmPTQAcEmxGbMoOLPjpoCPk/Oh096ZaORQ8o2iu8Cg="
    }
}

校验流程如下:

image.png

接受到body里面的一个随机字符串,使用上述设置的token进行加密并生成的Base64的签名,直接返回;当系统用同样条件生成的签名与第三方系统生成的签名一致时,表示url校验通过;

# 2.2.3.新增待办推送接口说明

接口含义 批量新增待办/待阅
请求地址 Post /batchAddReceiptTodo
请求体参数 addList List 新增待办/待阅集合
orgId String 机构id
返回值 无

UpdateTodoDTO详细说明:

字段 类型 允许为空 描述
receiptDTO object 否 单据实体类DTO
addWaitUserIds List 是 新增待办用户userId集合
addReadUserIds List 是 新增待阅用户userId集合
orgId String 否 机构id

receiptDTO参数详细说明:

字段 类型 允许为空 描述
workId String 否 工单id,即一张待办单据的主键
workTitle String 否 工单标题(流程标题)
workUrl String 否 工单url的全路径,用于点击跳转
workCreateTime String 否 工单创建时间yyyy-MM-dd HH:mm:ss
workCreator String 否 工单创建人id(发起人id)
workName String 否 工单创建人姓名(发起人姓名)
workStatus String 是 工单状态中文(流转状态)
currentNodeName String 是 工单当前节点中文(当前节点名称)
customList MytodoCustomDTO 是 自定义参数

MytodoCustomDTO参数

字段 类型 允许为空 描述
customName String 否 自定义字段名
customValue String 否 自定义字段值
POST 
https://第三方域名/batchAddReceiptTodo?timestamp=1498586609

Headers:{
    "Content-type":"application/json",
    "X-Auth0-DeliverId":"31a2ae17-2661-4234-8d79-f62f3175fd75",
}
Body:{
    "eventType":"PROCESS_ADD_TODO",
    "applicationId":"应用Id",
    "eventBusinessId":"",
    "data": "zvmPTQAcEmxGbMoOLPjpoCPk/Oh096ZaORQ8o2iu8Cg="
}
Response: {
    "msg":"执行成功",
    "code": 0,
    "data": {}
}
加密结构:
[{
    addList:[
       {
          "receiptDTO":{
                //工单id,即第三方一张待办单据的主键
                "workId":"work123",
                //流程标题
                "workTitle":"流程标题",
                //第三方统一待办系统跳转七巧plus流程详情的url
                "workUrl":"https://qiqiao-tcb-qa.qiweioa.cn/qiqiao2/mruntime/?agentCode=qiqiao2qa&corp_id=ww4852f35d45307a6f#/admin/workflow/detail/6538414979086811136?applicationId=60c35cc2efc18e0216665c2b&activityDefinitionId=obj_02&scope=TODO&taskId=6538427486031577089&sourceType=YBG_TODO",
                //待办创建时间
                "workCreateTime":"2020-01-01 00:00:00",
                //发起人id
                "workCreator":"zhangsan",
                //发起人名称
                "workName":"张三",
                //流转审批状态
                "workStatus":"审批中",
                //当前节点名称
                "currentNodeName":"节点1",
                "customList":[{
                   //当前节点定义id
                   "customName":"currentNodeId",
                   "customValue":"obj1"
                  },{
                    //流程模型id
                   "customName":"processModelId",
                   "customValue":"6538427486031577089"
                  },{
                   //流程名称
                   "customName":"processName",
                   "customValue":"流程名称"
                  },{
                    //流程实例id
                   "customName":"processInstanceId",
                   "customValue":"6538414979086811136"
                  },{
                   //应用id
                   "customName":"applicationId",
                   "customValue":"60c35cc2efc18e0216665c2b"
                  },{
                    //任务id
                   "customName":"taskId",
                   "customValue":"6538427486031577089"
                  }]
            },
            "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4",
            //待办用户集合(一条待办对应一条待办工单)
            "addWaitUserIds":[
                "204dcac59b288a1731b81e6e8ac6822e"
            ],
            "addReadUserIds":[]
        }
    ],
    orgId:"b17efb43-292e-4cc9-ac5d-0b46bce059c4"
}]

# 2.2.4.更新待办推送接口说明

接口含义 批量更新待办/待阅,待办转已办,待阅转已阅
请求地址 Post /batchUpdateReceiptTodo
请求体参数 updateList List 更新对象集合
orgId String 机构id
返回值 无

UpdateTodoDTO详细说明:

字段 类型 允许为空 描述
receiptDTO object 否 单据实体类DTO
updateWaitUserIds List 是 需要变成已办状态的用户userId集合
updateReadUserIds List 是 需要变成已办状态的用户userId集合
updateReceipt Boolean 是 是否需要更新单据(不需要更新单据dto可只传workId)更新待办时不能为空

receiptDTO参数详细说明:

字段 类型 允许为空 描述
workId String 否 工单id,即一张待办单据的主键
workTitle String 否 工单标题(流程标题)
workUrl String 否 工单url的全路径,用于点击跳转
workCreateTime String 否 工单创建时间yyyy-MM-dd HH:mm:ss
workCreator String 否 工单创建人id(发起人id)
workName String 否 工单创建人姓名(发起人姓名)
workStatus String 是 工单状态中文(流转状态)
currentNodeName String 是 工单当前节点中文(当前节点名称)

请求MytodoCustomDTO参数

字段 类型 允许为空 最大长度 描述
customName String 否 自定义字段名
customValue String 否 自定义字段值
POST 
https://第三方域名/batchUpdateReceiptTodo?timestamp=1498586609

Headers:{
    "Content-type":"application/json",
    "X-Auth0-DeliverId":"31a2ae17-2661-4234-8d79-f62f3175fd75",
}
Body:{
    "eventType":"PROCESS_UPDATE_TODO",
    "applicationId":"应用Id",
    "eventBusinessId":"",
    "data": "zvmPTQAcEmxGbMoOLPjpoCPk/Oh096ZaORQ8o2iu8Cg="
}
Response: {
    "msg":"执行成功",
    "code": 0,
    "data": {}
}

传参示例(加密结构):

//更新已办
[{
    "updateList":[
        {
            "receiptDTO":{
                "workId":"work123"
            },
            "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4",
            //更新用户单据为已办
            "updateWaitUserIds":[
                "204dcac59b288a1731b81e6e8ac6822e"
            ],
            "updateReceipt":true
        }
    ],
    "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4"
}]
//更新已阅
[{
    "updateList":[
        {
            "receiptDTO":{
                "workId":"work1234"
            },
            "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4",
            //更新用户单据为已阅
             "updateReadUserIds":[
                "204dcac59b288a1731b81e6e8ac6822e"
            ],
            "updateReceipt":true
        }
    ],
    "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4"
}]
//更新单据内容
[{
    "updateList":[
        {
            "receiptDTO":{
                //工单id,即第三方一张待办单据的主键
                "workId":"work1234",
                //流程标题
                "workTitle":"流程标题",
                //第三方统一待办系统跳转七巧plus流程详情的url
                "workUrl":"https://qiqiao-tcb-qa.qiweioa.cn/qiqiao2/mruntime/?agentCode=qiqiao2qa&corp_id=ww4852f35d45307a6f#/admin/workflow/detail/6538414979086811136?applicationId=60c35cc2efc18e0216665c2b&activityDefinitionId=obj_02&scope=TODO&taskId=6538427486031577089&sourceType=YBG_TODO",
                //待办创建时间
                "workCreateTime":"2020-01-01 00:00:00",
                //发起人id
                "workCreator":"lisi",
                //发起人名称
                "workName":"李四",
                //流转审批状态
                "workStatus":"完成",
                //当前节点名称
                "currentNodeName":"节点1",
                "customList":[{
                   //当前节点定义id
                   "customName":"currentNodeId",
                   "customValue":"obj1"
                  },{
                    //流程模型id
                   "customName":"processModelId",
                   "customValue":"6538427486031577089"
                  },{
                   //流程名称
                   "customName":"processName",
                   "customValue":"流程名称"
                  },{
                    //流程实例id
                   "customName":"processInstanceId",
                   "customValue":"6538414979086811136"
                  },{
                   //应用id
                   "customName":"applicationId",
                   "customValue":"60c35cc2efc18e0216665c2b"
                  },{
                    //任务id
                   "customName":"taskId",
                   "customValue":"6538427486031577089"
                  }]
            },
            "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4",
            "updateReceipt":true
        }
    ],
    "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4"
}]

# 2.2.5.删除待办推送接口说明

接口含义 批量删除待办或者待阅
请求地址 Post /batchDeleteReceiptTodo
请求体参数 deleteReceiptTodoDTO object 删除待办/待办对象
返回值 无

deleteReceiptTodoDTO参数详细说明:

字段 类型 允许为空 描述
orgId String 否 机构id
workIds List 否 需要删除的工单id集合
POST 
https://第三方域名/batchDeleteReceiptTodo?timestamp=1498586609

Headers:{
    "Content-type":"application/json",
    "X-Auth0-DeliverId":"31a2ae17-2661-4234-8d79-f62f3175fd75",
}
Body:{
    "eventType":"PROCESS_DELETE_TODO",
    "applicationId":"应用Id",
    "eventBusinessId":"",
    "data": "zvmPTQAcEmxGbMoOLPjpoCPk/Oh096ZaORQ8o2iu8Cg="
}
Response: {
    "msg":"执行成功",
    "code": 0,
    "data": {}
}
//删除单据加密结构
[{
    "deleteReceiptTodoDTO":{
        "orgId":"b17efb43-292e-4cc9-ac5d-0b46bce059c4",
        "workIds":[
            "work8c10327e0c3a42a3bb1f7a92c06619ae"
        ]
    }
}]
1 / 0