Jelajahi Sumber

:new: #2309 【企业微信】新增微信客服-接待人员管理、会话分配与消息收发、基础信息获取等相关接口

Boris 3 tahun lalu
induk
melakukan
438d5833f9
22 mengubah file dengan 1096 tambahan dan 0 penghapusan
  1. 34 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
  2. 121 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java
  3. 22 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
  4. 127 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpKfServiceImpl.java
  5. 3 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/ExternalContact.java
  6. 32 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfCustomerBatchGetResp.java
  7. 73 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfMsgListResp.java
  8. 151 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfMsgSendRequest.java
  9. 24 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfMsgSendResp.java
  10. 28 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServiceStateResp.java
  11. 27 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServiceStateTransResp.java
  12. 35 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServicerListResp.java
  13. 38 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServicerOpResp.java
  14. 16 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfBusinessCardMsg.java
  15. 40 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfEventMsg.java
  16. 53 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfLinkMsg.java
  17. 41 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfLocationMsg.java
  18. 128 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfMenuMsg.java
  19. 46 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfMiniProgramMsg.java
  20. 16 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfResourceMsg.java
  21. 26 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfTextMsg.java
  22. 15 0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java

+ 34 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java

@@ -1,6 +1,10 @@
 package me.chanjar.weixin.cp.api;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import lombok.NonNull;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
 import me.chanjar.weixin.cp.bean.external.*;
@@ -921,5 +925,35 @@ public interface WxCpExternalContactService {
    */
   WxCpProductAlbumResult getProductAlbum(String productId) throws WxErrorException;
 
+  /**
+   * <pre>
+   * 上传附件资源
+   * https://open.work.weixin.qq.com/api/doc/90001/90143/95178
+   * </pre>
+   * @param mediaType
+   * @param fileType
+   * @param attachmentType
+   * @param inputStream
+   * @return
+   * @throws WxErrorException
+   * @throws IOException
+   */
+  WxMediaUploadResult uploadAttachment(String mediaType, String fileType, Integer attachmentType,
+    InputStream inputStream) throws WxErrorException, IOException;
+
+  /**
+   * <pre>
+   * 上传附件资源
+   * https://open.work.weixin.qq.com/api/doc/90001/90143/95178
+   * </pre>
+   * @param mediaType
+   * @param attachmentType
+   * @param file
+   * @return
+   * @throws WxErrorException
+   */
+  WxMediaUploadResult uploadAttachment(String mediaType, Integer attachmentType, File file)
+    throws WxErrorException;
+
 
 }

+ 121 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java

@@ -1,5 +1,6 @@
 package me.chanjar.weixin.cp.api;
 
+import java.util.List;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAdd;
@@ -9,6 +10,14 @@ import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountLink;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountLinkResp;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountListResp;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountUpd;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfCustomerBatchGetResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgListResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgSendRequest;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgSendResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServiceStateResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServiceStateTransResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServicerListResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServicerOpResp;
 
 /**
  * 微信客服接口
@@ -67,4 +76,116 @@ public interface WxCpKfService {
    */
   WxCpKfAccountLinkResp getAccountLink(WxCpKfAccountLink link) throws WxErrorException;
 
+  /**
+   * 接待人员管理
+   * 添加指定客服帐号的接待人员,每个客服帐号目前最多可添加500个接待人员。
+   * @param openKfid 客服帐号ID
+   * @param userIdList 接待人员userid列表。第三方应用填密文userid,即open_userid
+   * 可填充个数:1 ~ 100。超过100个需分批调用。
+   * @return 添加客服账号结果
+   * @throws WxErrorException 异常
+   */
+  WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList) throws WxErrorException;
+
+  /**
+   * 接待人员管理
+   * 从客服帐号删除接待人员
+   * @param openKfid 客服帐号ID
+   * @param userIdList 接待人员userid列表。第三方应用填密文userid,即open_userid
+   * 可填充个数:1 ~ 100。超过100个需分批调用。
+   * @return 删除客服账号结果
+   * @throws WxErrorException 异常
+   */
+  WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList) throws WxErrorException;
+
+  /**
+   * 接待人员管理
+   * 获取某个客服帐号的接待人员列表
+   * @param openKfid 客服帐号ID
+   * @return 接待人员列表
+   * @throws WxErrorException 异常
+   */
+  WxCpKfServicerListResp listServicer(String openKfid) throws WxErrorException;
+
+  /**
+   * 分配客服会话
+   * 获取会话状态
+   * @param openKfid 客服帐号ID
+   * @param externalUserId 微信客户的external_userid
+   * @return
+   * @throws WxErrorException
+   */
+  WxCpKfServiceStateResp getServiceState(String openKfid, String externalUserId)
+    throws WxErrorException;
+
+  /**
+   * 分配客服会话
+   * 变更会话状态
+   * @param openKfid 客服帐号ID
+   * @param externalUserId 微信客户的external_userid
+   * @param serviceState 变更的目标状态,状态定义和所允许的变更可参考概述中的流程图和表格
+   * @param servicerUserId 接待人员的userid。第三方应用填密文userid,即open_userid。当state=3时要求必填,接待人员须处于“正在接待”中。
+   * @return 部分状态返回回复语code
+   * @throws WxErrorException
+   */
+  WxCpKfServiceStateTransResp transServiceState(String openKfid, String externalUserId,
+    Integer serviceState, String servicerUserId) throws WxErrorException;
+
+  /**
+   * 读取消息
+   * 微信客户发送的消息、接待人员在企业微信回复的消息、发送消息接口发送失败事件(如被用户拒收)、客户点击菜单消息的回复消息,
+   * 可以通过该接口获取具体的消息内容和事件。不支持读取通过发送消息接口发送的消息。
+   * 支持的消息类型:文本、图片、语音、视频、文件、位置、链接、名片、小程序、菜单、事件。
+   * @param cursor 上一次调用时返回的next_cursor,第一次拉取可以不填。不多于64字节
+   * @param token 回调事件返回的token字段,10分钟内有效;可不填,如果不填接口有严格的频率限制。不多于128字节
+   * @param limit 期望请求的数据量,默认值和最大值都为1000。
+   *              注意:可能会出现返回条数少于limit的情况,需结合返回的has_more字段判断是否继续请求。
+   * @param voiceFormat 语音消息类型,0-Amr 1-Silk,默认0。可通过该参数控制返回的语音格式
+   * @return 微信消息
+   * @throws WxErrorException 异常
+   */
+  WxCpKfMsgListResp syncMsg(String cursor, String token, Integer limit, Integer voiceFormat)
+    throws WxErrorException;
+
+  /**
+   * 发送消息
+   * 当微信客户处于“新接入待处理”或“由智能助手接待”状态下,可调用该接口给用户发送消息。
+   * 注意仅当微信客户在主动发送消息给客服后的48小时内,企业可发送消息给客户,最多可发送5条消息;若用户继续发送消息,企业可再次下发消息。
+   * 支持发送消息类型:文本、图片、语音、视频、文件、图文、小程序、菜单消息、地理位置。
+   * @param request 发送信息
+   * @return 发送结果
+   * @throws WxErrorException 异常
+   */
+  WxCpKfMsgSendResp sendMsg(WxCpKfMsgSendRequest request) throws WxErrorException;
+
+  /**
+   * 发送欢迎语等事件响应消息
+   * 当特定的事件回调消息包含code字段,或通过接口变更到特定的会话状态,会返回code字段。
+   * 开发者可以此code为凭证,调用该接口给用户发送相应事件场景下的消息,如客服欢迎语、客服提示语和会话结束语等。
+   * 除"用户进入会话事件"以外,响应消息仅支持会话处于获取该code的会话状态时发送,如将会话转入待接入池时获得的code仅能在会话状态为”待接入池排队中“时发送。
+   *
+   * 目前支持的事件场景和相关约束如下:
+   *
+   * 事件场景	                  允许下发条数	code有效期	  支持的消息类型	  获取code途径
+   * 用户进入会话,用于发送客服欢迎语	1条	        20秒	      文本、菜单	    事件回调
+   * 进入接待池,用于发送排队提示语等	1条	        48小时	      文本	          转接会话接口
+   * 从接待池接入会话,用于发送非工作
+   * 时间的提示语或超时未回复的提示语
+   * 等	                        1条	        48小时	      文本	          事件回调、转接会话接口
+   * 结束会话,用于发送结束会话提示语
+   * 或满意度评价等	              1条	        20秒	      文本、菜单	    事件回调、转接会话接口
+   * @param request
+   * @return
+   * @throws WxErrorException
+   */
+  WxCpKfMsgSendResp sendMsgOnEvent(WxCpKfMsgSendRequest request) throws WxErrorException;
+
+  /**
+   * 获取客户基础信息
+   * @param externalUserIdList
+   * @return
+   * @throws WxErrorException
+   */
+  WxCpKfCustomerBatchGetResp customerBatchGet(List<String> externalUserIdList)
+    throws WxErrorException;
 }

+ 22 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java

@@ -2,12 +2,19 @@ package me.chanjar.weixin.cp.api.impl;
 
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.UUID;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.BeanUtils;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.api.WxCpExternalContactService;
 import me.chanjar.weixin.cp.api.WxCpService;
@@ -814,4 +821,19 @@ public class WxCpExternalContactServiceImpl implements WxCpExternalContactServic
     return WxCpProductAlbumResult.fromJson(result);
   }
 
+  @Override
+  public WxMediaUploadResult uploadAttachment(String mediaType, String fileType, Integer attachmentType,
+    InputStream inputStream) throws WxErrorException, IOException {
+    return uploadAttachment(mediaType, attachmentType, FileUtils.createTmpFile(inputStream,
+      UUID.randomUUID().toString(), fileType));
+  }
+
+  @Override
+  public WxMediaUploadResult uploadAttachment(String mediaType, Integer attachmentType, File file)
+    throws WxErrorException {
+    String params = "?media_type=" + mediaType + "&attachment_type=" + attachmentType;
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPLOAD_ATTACHMENT + params);
+    return this.mainService.execute(MediaUploadRequestExecutor.create(
+      this.mainService.getRequestHttp()), url, file);
+  }
 }

+ 127 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpKfServiceImpl.java

@@ -1,5 +1,10 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.List;
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpKfService;
@@ -12,6 +17,14 @@ import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountLink;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountLinkResp;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountListResp;
 import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountUpd;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfCustomerBatchGetResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgListResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgSendRequest;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgSendResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServiceStateResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServiceStateTransResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServicerListResp;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServicerOpResp;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Kf.*;
@@ -25,6 +38,7 @@ import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Kf.*;
 @RequiredArgsConstructor
 public class WxCpKfServiceImpl implements WxCpKfService {
   private final WxCpService cpService;
+  private static final Gson GSON = new GsonBuilder().create();
 
   @Override
   public WxCpKfAccountAddResp addAccount(WxCpKfAccountAdd add) throws WxErrorException {
@@ -61,4 +75,117 @@ public class WxCpKfServiceImpl implements WxCpKfService {
     return WxCpKfAccountLinkResp.fromJson(responseContent);
   }
 
+  @Override
+  public WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList) throws WxErrorException {
+    return servicerOp(openKfid, userIdList, SERVICER_ADD);
+  }
+
+  @Override
+  public WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList) throws WxErrorException {
+    return servicerOp(openKfid, userIdList, SERVICER_DEL);
+  }
+
+  private WxCpKfServicerOpResp servicerOp(String openKfid, List<String> userIdList, String uri) throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(uri);
+
+    JsonObject json = new JsonObject();
+    json.addProperty("open_kfid", openKfid);
+    JsonArray userIdArray = new JsonArray();
+    userIdList.forEach(userIdArray::add);
+    json.add("userid_list", userIdArray);
+
+    String responseContent = cpService.post(url, json.toString());
+    return WxCpKfServicerOpResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfServicerListResp listServicer(String openKfid) throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(SERVICER_LIST + openKfid);
+    String responseContent = cpService.get(url, null);
+    return WxCpKfServicerListResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfServiceStateResp getServiceState(String openKfid, String externalUserId)
+    throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(SERVICE_STATE_GET);
+
+    JsonObject json = new JsonObject();
+    json.addProperty("open_kfid", openKfid);
+    json.addProperty("external_userid", externalUserId);
+
+    String responseContent = cpService.post(url, json.toString());
+    return WxCpKfServiceStateResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfServiceStateTransResp transServiceState(String openKfid, String externalUserId,
+    Integer serviceState, String servicerUserId) throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(SERVICE_STATE_TRANS);
+
+    JsonObject json = new JsonObject();
+    json.addProperty("open_kfid", openKfid);
+    json.addProperty("external_userid", externalUserId);
+    json.addProperty("service_state", serviceState);
+    json.addProperty("servicer_userid", servicerUserId);
+
+    String responseContent = cpService.post(url, json.toString());
+    return WxCpKfServiceStateTransResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfMsgListResp syncMsg(String cursor, String token, Integer limit, Integer voiceFormat)
+    throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(SYNC_MSG);
+
+    JsonObject json = new JsonObject();
+    if (cursor!=null) {
+      json.addProperty("cursor", cursor);
+    }
+    if (token!=null) {
+      json.addProperty("token", token);
+    }
+    if (limit!=null) {
+      json.addProperty("limit", limit);
+    }
+    if (voiceFormat!=null) {
+      json.addProperty("voice_format", voiceFormat);
+    }
+
+    String responseContent = cpService.post(url, json);
+    return WxCpKfMsgListResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfMsgSendResp sendMsg(WxCpKfMsgSendRequest request) throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(SEND_MSG);
+
+    String responseContent = cpService.post(url, GSON.toJson(request));
+
+    return WxCpKfMsgSendResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfMsgSendResp sendMsgOnEvent(WxCpKfMsgSendRequest request) throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(SEND_MSG_ON_EVENT);
+
+    String responseContent = cpService.post(url, GSON.toJson(request));
+
+    return WxCpKfMsgSendResp.fromJson(responseContent);
+  }
+
+  @Override
+  public WxCpKfCustomerBatchGetResp customerBatchGet(List<String> externalUserIdList)
+    throws WxErrorException {
+    String url = cpService.getWxCpConfigStorage().getApiUrl(CUSTOMER_BATCH_GET);
+
+    JsonArray array = new JsonArray();
+
+    externalUserIdList.forEach(array::add);
+    JsonObject json = new JsonObject();
+    json.add("external_userid_list", array);
+    String responseContent = cpService.post(url, json.toString());
+    return WxCpKfCustomerBatchGetResp.fromJson(responseContent);
+  }
+
 }

+ 3 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/ExternalContact.java

@@ -26,6 +26,9 @@ public class ExternalContact implements Serializable {
   @SerializedName("name")
   private String name;
 
+  @SerializedName("nickname")
+  private String nickname;
+
   @SerializedName("avatar")
   private String avatar;
 

+ 32 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfCustomerBatchGetResp.java

@@ -0,0 +1,32 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.bean.external.contact.ExternalContact;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 7:56 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfCustomerBatchGetResp extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -3697709507605389887L;
+
+  @SerializedName("customer_list")
+  private List<ExternalContact> customerList;
+
+  @SerializedName("invalid_external_userid")
+  private List<String> invalidExternalUserId;
+
+  public static WxCpKfCustomerBatchGetResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfCustomerBatchGetResp.class);
+  }
+}

+ 73 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfMsgListResp.java

@@ -0,0 +1,73 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfBusinessCardMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfEventMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfLinkMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfLocationMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfMenuMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfMiniProgramMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfResourceMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfTextMsg;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:24 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfMsgListResp extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -3115552079069452091L;
+  @SerializedName("next_cursor")
+  private String nextCursor;
+
+  @SerializedName("has_more")
+  private Integer hasMore;
+
+  @SerializedName("msg_list")
+  private List<WxCpKfMsgItem> msgList;
+
+  @NoArgsConstructor
+  @Data
+  public static class WxCpKfMsgItem {
+    @SerializedName("msgid")
+    private String msgId;
+    @SerializedName("open_kfid")
+    private String openKfid;
+    @SerializedName("external_userid")
+    private String externalUserId;
+    @SerializedName("send_time")
+    private Long sendTime;
+    private Integer origin;
+    @SerializedName("servicer_userid")
+    private String servicerUserId;
+    @SerializedName("msgtype")
+    private String msgType;
+    private WxCpKfTextMsg text;
+    private WxCpKfResourceMsg image;
+    private WxCpKfResourceMsg voice;
+    private WxCpKfResourceMsg video;
+    private WxCpKfResourceMsg file;
+    private WxCpKfLocationMsg location;
+    private WxCpKfLinkMsg link;
+    @SerializedName("business_card")
+    private WxCpKfBusinessCardMsg businessCard;
+    @SerializedName("miniprogram")
+    private WxCpKfMiniProgramMsg miniProgram;
+    @SerializedName("msgmenu")
+    private WxCpKfMenuMsg msgMenu;
+    private WxCpKfEventMsg event;
+  }
+
+  public static WxCpKfMsgListResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfMsgListResp.class);
+  }
+}

+ 151 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfMsgSendRequest.java

@@ -0,0 +1,151 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfLinkMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfLocationMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfMenuMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfMiniProgramMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfResourceMsg;
+import me.chanjar.weixin.cp.bean.kf.msg.WxCpKfTextMsg;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 7:00 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfMsgSendRequest {
+  /**
+   * (发送欢迎语等事件响应消息) 事件响应消息对应的code。通过事件回调下发,仅可使用一次。
+   */
+  private String code;
+  /**
+   * <pre>
+   *   参数:touser
+   *   是否必须:是
+   *   类型:string
+   *   说明:指定接收消息的客户UserID
+   * </pre>
+   */
+  @SerializedName("touser")
+  private String toUser;
+  /**
+   * <pre>
+   *   参数:open_kfid
+   *   是否必须:是
+   *   类型:string
+   *   说明:指定发送消息的客服帐号ID
+   * </pre>
+   */
+  @SerializedName("open_kfid")
+  private String openKfid;
+  /**
+   * <pre>
+   *   参数:msgid
+   *   是否必须:否
+   *   类型:string
+   *   说明:指定消息ID
+   * </pre>
+   */
+  @SerializedName("msgid")
+  private String msgId;
+  /**
+   * <pre>
+   *   参数:msgtype
+   *   是否必须:是
+   *   类型:string
+   *   说明:消息类型,(text,image,voice,video,file,link,miniprogram,msgmenu,location)
+   * </pre>
+   */
+  @SerializedName("msgtype")
+  private String msgType;
+  /**
+   * <pre>
+   *   参数:text
+   *   是否必须:是
+   *   类型:obj
+   *   说明:文本消息
+   * </pre>
+   */
+  private WxCpKfTextMsg text;
+
+  /**
+   * <pre>
+   *   参数:image
+   *   是否必须:是
+   *   类型:obj
+   *   说明:图片消息
+   * </pre>
+   */
+  private WxCpKfResourceMsg image;
+  /**
+   * <pre>
+   *   参数:voice
+   *   是否必须:是
+   *   类型:obj
+   *   说明:语音消息
+   * </pre>
+   */
+  private WxCpKfResourceMsg voice;
+  /**
+   * <pre>
+   *   参数:video
+   *   是否必须:是
+   *   类型:obj
+   *   说明:视频消息
+   * </pre>
+   */
+  private WxCpKfResourceMsg video;
+  /**
+   * <pre>
+   *   参数:file
+   *   是否必须:是
+   *   类型:obj
+   *   说明:文件消息
+   * </pre>
+   */
+  private WxCpKfResourceMsg file;
+  /**
+   * <pre>
+   *   参数:link
+   *   是否必须:是
+   *   类型:obj
+   *   说明:链接消息
+   * </pre>
+   */
+  private WxCpKfLinkMsg link;
+  /**
+   * <pre>
+   *   参数:miniprogram
+   *   是否必须:是
+   *   类型:obj
+   *   说明:小程序消息
+   * </pre>
+   */
+  @SerializedName("miniprogram")
+  private WxCpKfMiniProgramMsg miniProgram;
+
+  /**
+   * <pre>
+   *   参数:msgmenu
+   *   是否必须:是
+   *   类型:obj
+   *   说明:菜单消息
+   * </pre>
+   */
+  @SerializedName("msgmenu")
+  private WxCpKfMenuMsg msgMenu;
+
+  /**
+   * <pre>
+   *   参数:location
+   *   是否必须:是
+   *   类型:obj
+   *   说明:菜单消息
+   * </pre>
+   */
+  @SerializedName("location")
+  private WxCpKfLocationMsg location;
+}

+ 24 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfMsgSendResp.java

@@ -0,0 +1,24 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 7:41 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfMsgSendResp extends WxCpBaseResp {
+  @SerializedName("msgid")
+  private String msgId;
+
+  public static WxCpKfMsgSendResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfMsgSendResp.class);
+  }
+}

+ 28 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServiceStateResp.java

@@ -0,0 +1,28 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:00 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfServiceStateResp extends WxCpBaseResp {
+
+  private static final long serialVersionUID = 8077134413448067090L;
+  @SerializedName("service_state")
+  private Integer serviceState;
+  @SerializedName("servicer_userid")
+  private String servicerUserId;
+
+  public static WxCpKfServiceStateResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfServiceStateResp.class);
+  }
+}

+ 27 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServiceStateTransResp.java

@@ -0,0 +1,27 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:03 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfServiceStateTransResp extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -7874378445629022791L;
+
+  @SerializedName("msg_code")
+  private String msgCode;
+
+  public static WxCpKfServiceStateTransResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfServiceStateTransResp.class);
+  }
+}

+ 35 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServicerListResp.java

@@ -0,0 +1,35 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 4:29 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfServicerListResp extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -5079770046571012449L;
+  @SerializedName("servicer_list")
+  private List<WxCpKfServicerStatus> servicerList;
+
+  @NoArgsConstructor
+  @Data
+  public static class WxCpKfServicerStatus {
+    @SerializedName("userid")
+    private String userId;
+    private Integer status;
+  }
+
+  public static WxCpKfServicerListResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfServicerListResp.class);
+  }
+}

+ 38 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/WxCpKfServicerOpResp.java

@@ -0,0 +1,38 @@
+package me.chanjar.weixin.cp.bean.kf;
+
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 添加/删除客服接待人员返回结果
+ * @author leiin
+ * @date 2022/1/26 4:11 下午
+ */
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Data
+public class WxCpKfServicerOpResp extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -4082459764202987034L;
+
+  @SerializedName("result_list")
+  private List<WxCpKfServicerResp> resultList;
+
+  @Data
+  @NoArgsConstructor
+  public static class WxCpKfServicerResp extends WxCpBaseResp {
+
+    @SerializedName("userid")
+    private String userId;
+  }
+
+  public static WxCpKfServicerOpResp fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpKfServicerOpResp.class);
+  }
+}

+ 16 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfBusinessCardMsg.java

@@ -0,0 +1,16 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:35 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfBusinessCardMsg {
+  @SerializedName("userid")
+  private String userId;
+}

+ 40 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfEventMsg.java

@@ -0,0 +1,40 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 6:44 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfEventMsg {
+  @SerializedName("event_type")
+  private String eventType;
+  @SerializedName("open_kfid")
+  private String openKfid;
+  @SerializedName("external_userid")
+  private String externalUserId;
+  @SerializedName("servicer_userid")
+  private String servicerUserId;
+  @SerializedName("old_servicer_userid")
+  private String oldServicerUserId;
+  @SerializedName("new_servicer_userid")
+  private String newServicerUserId;
+  private String scene;
+  @SerializedName("scene_param")
+  private String sceneParam;
+  @SerializedName("welcome_code")
+  private String welcomeCode;
+  @SerializedName("fail_msgid")
+  private String failMsgId;
+  @SerializedName("fail_type")
+  private Integer failType;
+  private Integer status;
+  @SerializedName("change_type")
+  private Integer changeType;
+  @SerializedName("msg_code")
+  private String msgCode;
+}

+ 53 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfLinkMsg.java

@@ -0,0 +1,53 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:33 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfLinkMsg {
+
+  /**
+   * 参数:title
+   * 是否必须:是
+   * 类型:string
+   * 说明:标题,不超过128个字节,超过会自动截断
+   */
+  @SerializedName("title")
+  private String title;
+  /**
+   * 参数:desc
+   * 是否必须:否
+   * 类型:string
+   * 说明:描述,不超过512个字节,超过会自动截断
+   */
+  @SerializedName("desc")
+  private String desc;
+  /**
+   * 参数:url
+   * 是否必须:是
+   * 类型:string
+   * 说明:点击后跳转的链接。 最长2048字节,请确保包含了协议头(http/https)
+   */
+  @SerializedName("url")
+  private String url;
+  /**
+   * 参数:thumb_media_id
+   * 是否必须:是
+   * 类型:string
+   * 说明:发送消息参数,缩略图的media_id, 可以通过素材管理接口获得。此处thumb_media_id即上传接口返回的media_id
+   */
+  @SerializedName("thumb_media_id")
+  private String thumb_media_id;
+
+  /**
+   * 返回消息参数
+   */
+  @SerializedName("pic_url")
+  private String picUrl;
+}

+ 41 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfLocationMsg.java

@@ -0,0 +1,41 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:32 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfLocationMsg {
+  /**
+   * 参数:name
+   * 是否必须:否
+   * 类型:string
+   * 说明:位置名
+   */
+  private String name;
+  /**
+   * 参数:address
+   * 是否必须:否
+   * 类型:string
+   * 说明:地址详情说明
+   */
+  private String address;
+  /**
+   * 参数:latitude
+   * 是否必须:是
+   * 类型:float
+   * 说明:纬度,浮点数,范围为90 ~ -90
+   */
+  private Float latitude;
+  /**
+   * 参数:longitude
+   * 是否必须:是
+   * 类型:float
+   * 说明:经度,浮点数,范围为180 ~ -180
+   */
+  private Float longitude;
+}

+ 128 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfMenuMsg.java

@@ -0,0 +1,128 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 6:33 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfMenuMsg {
+
+  /**
+   * 参数:head_content
+   * 是否必须:否
+   * 类型:string
+   * 说明:起始文本 不多于1024字节
+   */
+  @SerializedName("head_content")
+  private String headContent;
+
+  private List<WxCpKfMenuItem> list;
+
+  /**
+   * 参数:tail_content
+   * 是否必须:否
+   * 类型:string
+   * 说明:结束文本 不多于1024字节
+   */
+  @SerializedName("tail_content")
+  private String tailContent;
+
+  @NoArgsConstructor
+  @Data
+  public static class WxCpKfMenuItem {
+    /**
+     * 参数:type
+     * 是否必须:是
+     * 类型:string
+     * 说明:菜单类型。click-回复菜单 view-超链接菜单 miniprogram-小程序菜单
+     */
+    private String type;
+
+    /**
+     * type为click的菜单项
+     */
+    private MenuClick click;
+    /**
+     * type为view的菜单项
+     */
+    private MenuView view;
+    /**
+     * type为miniprogram的菜单项
+     */
+    @SerializedName("miniprogram")
+    private MiniProgram miniProgram;
+  }
+
+  @Getter
+  @Setter
+  public static class MenuClick {
+
+    /**
+     * <pre>
+     *   是否必须:否
+     *   说明:菜单ID。不少于1字节 不多于128字节
+     * </pre>
+     */
+    private String id;
+    /**
+     * <pre>
+     *   是否必须:是
+     *   说明:菜单显示内容。不少于1字节 不多于128字节
+     * </pre>
+     */
+    private String content;
+  }
+
+  @Getter
+  @Setter
+  public static class MenuView {
+    /**
+     * <pre>
+     *   是否必须:是
+     *   说明:点击后跳转的链接。不少于1字节 不多于2048字节
+     * </pre>
+     */
+    private String url;
+    /**
+     * <pre>
+     *   是否必须:是
+     *   说明:菜单显示内容。不少于1字节 不多于1024字节
+     * </pre>
+     */
+    private String content;
+  }
+
+  @Getter
+  @Setter
+  public static class MiniProgram {
+    /**
+     * <pre>
+     *   是否必须:是
+     *   说明:小程序appid。
+     * </pre>
+     */
+    @SerializedName("appid")
+    private String appId;
+    /**
+     * <pre>
+     *   点击后进入的小程序页面。
+     * </pre>
+     */
+    @SerializedName("pagepath")
+    private String pagePath;
+    /**
+     * <pre>
+     *   菜单显示内容。不多于1024字节
+     * </pre>
+     */
+    private String content;
+  }
+}

+ 46 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfMiniProgramMsg.java

@@ -0,0 +1,46 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 6:22 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfMiniProgramMsg {
+  /**
+   * 参数:appid
+   * 是否必须:是
+   * 类型:string
+   * 说明:小程序appid
+   */
+  @SerializedName("appid")
+  private String appId;
+  /**
+   * 参数:title
+   * 是否必须:否
+   * 类型:string
+   * 说明:小程序消息标题,最多64个字节,超过会自动截断
+   */
+  @SerializedName("title")
+  private String title;
+  /**
+   * 参数:thumb_media_id
+   * 是否必须:是
+   * 类型:string
+   * 说明:小程序消息封面的mediaid,封面图建议尺寸为520*416
+   */
+  @SerializedName("thumb_media_id")
+  private String thumbMediaId;
+  /**
+   * 参数:pagepath
+   * 是否必须:是
+   * 类型:string
+   * 说明:点击消息卡片后进入的小程序页面路径。注意路径要以.html为后缀,否则在微信中打开会提示找不到页面
+   */
+  @SerializedName("pagepath")
+  private String pagePath;
+}

+ 16 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfResourceMsg.java

@@ -0,0 +1,16 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:31 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfResourceMsg {
+  @SerializedName("media_id")
+  private String mediaId;
+}

+ 26 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/kf/msg/WxCpKfTextMsg.java

@@ -0,0 +1,26 @@
+package me.chanjar.weixin.cp.bean.kf.msg;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leiin
+ * @date 2022/1/26 5:30 下午
+ */
+@NoArgsConstructor
+@Data
+public class WxCpKfTextMsg {
+
+  /**
+   * <pre>
+   *   参数:content
+   *   是否必须:是
+   *   类型:string
+   *   说明:消息内容,最长不超过2048个字节
+   * </pre>
+   */
+  private String content;
+  @SerializedName("menu_id")
+  private String menuId;
+}

+ 15 - 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java

@@ -249,6 +249,8 @@ public interface WxCpApiPathConsts {
     String GROUP_WELCOME_TEMPLATE_GET = "/cgi-bin/externalcontact/group_welcome_template/get";
     String GROUP_WELCOME_TEMPLATE_DEL = "/cgi-bin/externalcontact/group_welcome_template/del";
 
+    String UPLOAD_ATTACHMENT = "/cgi-bin/media/upload_attachment";
+
   }
 
   interface Kf {
@@ -258,5 +260,18 @@ public interface WxCpApiPathConsts {
     String ACCOUNT_LIST = "/cgi-bin/kf/account/list";
     String ADD_CONTACT_WAY = "/cgi-bin/kf/add_contact_way";
 
+    String SERVICER_ADD = "/cgi-bin/kf/servicer/add";
+    String SERVICER_DEL = "/cgi-bin/kf/servicer/del";
+    String SERVICER_LIST = "/cgi-bin/kf/servicer/list?open_kfid=";
+
+    String SERVICE_STATE_GET = "/cgi-bin/kf/service_state/get";
+    String SERVICE_STATE_TRANS = "/cgi-bin/kf/service_state/trans";
+
+    String SYNC_MSG = "/cgi-bin/kf/sync_msg";
+    String SEND_MSG = "/cgi-bin/kf/send_msg";
+
+    String SEND_MSG_ON_EVENT = "/cgi-bin/kf/send_msg_on_event";
+    String CUSTOMER_BATCH_GET = "/cgi-bin/kf/customer/batchget";
+
   }
 }