🆕 #2309 【企业微信】新增微信客服帐号管理部分接口

This commit is contained in:
孔明 2022-01-20 12:07:56 +08:00 committed by GitHub
parent 649af3e4bd
commit 487cc7f689
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 512 additions and 0 deletions

View File

@ -0,0 +1,70 @@
package me.chanjar.weixin.cp.api;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAdd;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAddResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountDel;
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;
/**
* 微信客服接口
*
* 微信客服由腾讯微信团队为企业打造用于满足企业的客服需求帮助企业做好客户服务企业可以在微信内外各个场景中接入微信客服
* 用户可以发起咨询企业可以进行回复
* 企业可在微信客服官网使用企业微信扫码开通微信客服开通后即可使用
*
* @author Fu
* @date 2022/1/19 19:25
*/
public interface WxCpKfService {
/**
* 添加客服帐号并可设置客服名称和头像目前一家企业最多可添加10个客服帐号
*
* @param add 客服帐号信息
* @return result-新创建的客服帐号ID
* @throws WxErrorException 异常
*/
WxCpKfAccountAddResp addAccount(WxCpKfAccountAdd add) throws WxErrorException;
/**
* 修改已有的客服帐号可修改客服名称和头像
*
* @param upd 新的客服账号信息
* @return result
* @throws WxErrorException 异常
*/
WxCpBaseResp updAccount(WxCpKfAccountUpd upd) throws WxErrorException;
/**
* 删除已有的客服帐号
*
* @param del 要删除的客服帐号
* @return result
* @throws WxErrorException 异常
*/
WxCpBaseResp delAccount(WxCpKfAccountDel del) throws WxErrorException;
/**
* 获取客服帐号列表包括所有的客服帐号的客服ID名称和头像
*
* @return 客服帐号列表
* @throws WxErrorException 异常
*/
WxCpKfAccountListResp listAccount() throws WxErrorException;
/**
* 企业可通过此接口获取带有不同参数的客服链接不同客服帐号对应不同的客服链接获取后企业可将链接嵌入到网页等场景中
* 微信用户点击链接即可向对应的客服帐号发起咨询企业可依据参数来识别用户的咨询来源等
*
* @param link 参数
* @return 链接
* @throws WxErrorException 异常
*/
WxCpKfAccountLinkResp getAccountLink(WxCpKfAccountLink link) throws WxErrorException;
}

View File

@ -427,6 +427,13 @@ public interface WxCpService extends WxService {
*/
WxCpAgentWorkBenchService getWorkBenchService();
/**
* 获取微信客服服务
*
* @return 微信客服服务
*/
WxCpKfService getKfService();
/**
* http请求对象
*
@ -476,4 +483,10 @@ public interface WxCpService extends WxService {
*/
void setTagService(WxCpTagService tagService);
/**
* Sets kf service.
*
* @param kfService the kf service
*/
void setKfService(WxCpKfService kfService);
}

View File

@ -57,6 +57,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
private WxCpOaCalendarService oaCalendarService = new WxCpOaCalendarServiceImpl(this);
private WxCpOaScheduleService oaScheduleService = new WxCpOaOaScheduleServiceImpl(this);
private WxCpAgentWorkBenchService workBenchService = new WxCpAgentWorkBenchServiceImpl(this);
private WxCpKfService kfService = new WxCpKfServiceImpl(this);
/**
* 全局的是否正在刷新access token的锁.
@ -556,4 +557,14 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
public WxCpOaScheduleService getOaScheduleService() {
return this.oaScheduleService;
}
@Override
public WxCpKfService getKfService() {
return kfService;
}
@Override
public void setKfService(WxCpKfService kfService) {
this.kfService = kfService;
}
}

View File

@ -0,0 +1,64 @@
package me.chanjar.weixin.cp.api.impl;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpKfService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAdd;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAddResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountDel;
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.util.json.WxCpGsonBuilder;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Kf.*;
/**
* 微信客服接口-服务实现
*
* @author Fu
* @date 2022/1/19 19:41
*/
@RequiredArgsConstructor
public class WxCpKfServiceImpl implements WxCpKfService {
private final WxCpService cpService;
@Override
public WxCpKfAccountAddResp addAccount(WxCpKfAccountAdd add) throws WxErrorException {
String url = cpService.getWxCpConfigStorage().getApiUrl(ACCOUNT_ADD);
String responseContent = cpService.post(url, WxCpGsonBuilder.create().toJson(add));
return WxCpKfAccountAddResp.fromJson(responseContent);
}
@Override
public WxCpBaseResp updAccount(WxCpKfAccountUpd upd) throws WxErrorException {
String url = cpService.getWxCpConfigStorage().getApiUrl(ACCOUNT_UPD);
String responseContent = cpService.post(url, WxCpGsonBuilder.create().toJson(upd));
return WxCpBaseResp.fromJson(responseContent);
}
@Override
public WxCpBaseResp delAccount(WxCpKfAccountDel del) throws WxErrorException {
String url = cpService.getWxCpConfigStorage().getApiUrl(ACCOUNT_DEL);
String responseContent = cpService.post(url, WxCpGsonBuilder.create().toJson(del));
return WxCpBaseResp.fromJson(responseContent);
}
@Override
public WxCpKfAccountListResp listAccount() throws WxErrorException {
String url = cpService.getWxCpConfigStorage().getApiUrl(ACCOUNT_LIST);
String responseContent = cpService.post(url, "{}");
return WxCpKfAccountListResp.fromJson(responseContent);
}
@Override
public WxCpKfAccountLinkResp getAccountLink(WxCpKfAccountLink link) throws WxErrorException {
String url = cpService.getWxCpConfigStorage().getApiUrl(ADD_CONTACT_WAY);
String responseContent = cpService.post(url, WxCpGsonBuilder.create().toJson(link));
return WxCpKfAccountLinkResp.fromJson(responseContent);
}
}

View File

@ -0,0 +1,33 @@
package me.chanjar.weixin.cp.bean.kf;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 添加客服帐号-请求参数
*
* @author Fu
* @date 2022/1/19 18:59
*/
@NoArgsConstructor
@Data
public class WxCpKfAccountAdd implements Serializable {
private static final long serialVersionUID = 3565729481246537411L;
/**
* 客服名称不多于16个字符
*/
@SerializedName("name")
private String name;
/**
* 客服头像临时素材可以调用上传临时素材接口获取
* 不多于128个字节
*/
@SerializedName("media_id")
private String mediaId;
}

View File

@ -0,0 +1,32 @@
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 Fu
* @date 2022/1/19 19:04
*/
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Data
public class WxCpKfAccountAddResp extends WxCpBaseResp {
private static final long serialVersionUID = -6649323005421772827L;
/**
* 新创建的客服帐号ID
*/
@SerializedName("open_kfid")
private String openKfid;
public static WxCpKfAccountAddResp fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpKfAccountAddResp.class);
}
}

View File

@ -0,0 +1,28 @@
package me.chanjar.weixin.cp.bean.kf;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 删除客服帐号-请求参数
*
* @author Fu
* @date 2022/1/19 19:09
*/
@NoArgsConstructor
@Data
public class WxCpKfAccountDel implements Serializable {
private static final long serialVersionUID = 1997221467585676772L;
/**
* 客服帐号ID
* 不多于64字节
*/
@SerializedName("open_kfid")
private String openKfid;
}

View File

@ -0,0 +1,40 @@
package me.chanjar.weixin.cp.bean.kf;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 获取客服帐号链接-请求参数
*
* @author Fu
* @date 2022/1/19 19:18
*/
@NoArgsConstructor
@Data
public class WxCpKfAccountLink implements Serializable {
private static final long serialVersionUID = -1920926948347984256L;
/**
* 客服帐号ID
*/
@SerializedName("open_kfid")
private String openKfid;
/**
* 场景值字符串类型由开发者自定义
* 不多于32字节
* 字符串取值范围(正则表达式)[0-9a-zA-Z_-]*
*
* 1. 若scene非空返回的客服链接开发者可拼接scene_param=SCENE_PARAM参数使用用户进入会话事件会将SCENE_PARAM原样返回
* 其中SCENE_PARAM需要urlencode且长度不能超过128字节
* https://work.weixin.qq.com/kf/kfcbf8f8d07ac7215f?enc_scene=ENCGFSDF567DF&scene_param=a%3D1%26b%3D2
* 2. 历史调用接口返回的客服链接包含encScene=XXX参数不支持scene_param参数
* 3. 返回的客服链接不能修改或复制参数到其他链接使用否则进入会话事件参数校验不通过导致无法回调
*/
@SerializedName("scene")
private String scene;
}

View File

@ -0,0 +1,32 @@
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 Fu
* @date 2022/1/19 19:18
*/
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Data
public class WxCpKfAccountLinkResp extends WxCpBaseResp {
private static final long serialVersionUID = 910205439597092481L;
/**
* 客服链接开发者可将该链接嵌入到H5页面中用户点击链接即可向对应的微信客服帐号发起咨询开发者也可根据该url自行生成需要的二维码图片
*/
@SerializedName("url")
private String url;
public static WxCpKfAccountLinkResp fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpKfAccountLinkResp.class);
}
}

View File

@ -0,0 +1,57 @@
package me.chanjar.weixin.cp.bean.kf;
import com.fasterxml.jackson.annotation.JsonProperty;
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;
import java.util.List;
/**
* 获取客服帐号列表-结果
*
* @author Fu
* @date 2022/1/19 19:13
*/
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Data
public class WxCpKfAccountListResp extends WxCpBaseResp {
private static final long serialVersionUID = -1317201649692262217L;
/**
* 帐号信息列表
*/
@JsonProperty("account_list")
private List<AccountListDTO> accountList;
@NoArgsConstructor
@Data
public static class AccountListDTO {
/**
* 客服帐号ID
*/
@SerializedName("open_kfid")
private String openKfid;
/**
* 客服名称
*/
@SerializedName("name")
private String name;
/**
* 客服头像URL
*/
@SerializedName("avatar")
private String avatar;
}
public static WxCpKfAccountListResp fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpKfAccountListResp.class);
}
}

View File

@ -0,0 +1,41 @@
package me.chanjar.weixin.cp.bean.kf;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 修改客服帐号-请求参数
*
* @author Fu
* @date 2022/1/19 19:10
*/
@NoArgsConstructor
@Data
public class WxCpKfAccountUpd implements Serializable {
private static final long serialVersionUID = -900712046553752529L;
/**
* 要修改的客服帐号ID
* 不多于64字节
*/
@SerializedName("open_kfid")
private String openKfid;
/**
* 新的客服名称如不需要修改可不填
* 不多于16个字符
*/
@SerializedName("name")
private String name;
/**
* 新的客服头像临时素材如不需要修改可不填可以调用上传临时素材接口获取
* 不多于128个字节
*/
@SerializedName("media_id")
private String mediaId;
}

View File

@ -244,4 +244,13 @@ public interface WxCpApiPathConsts {
String GROUP_WELCOME_TEMPLATE_DEL = "/cgi-bin/externalcontact/group_welcome_template/del";
}
interface Kf {
String ACCOUNT_ADD = "/cgi-bin/kf/account/add";
String ACCOUNT_UPD = "/cgi-bin/kf/account/update";
String ACCOUNT_DEL = "/cgi-bin/kf/account/del";
String ACCOUNT_LIST = "/cgi-bin/kf/account/list";
String ADD_CONTACT_WAY = "/cgi-bin/kf/add_contact_way";
}
}

View File

@ -0,0 +1,82 @@
package me.chanjar.weixin.cp.api.impl;
import com.google.inject.Inject;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAdd;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountAddResp;
import me.chanjar.weixin.cp.bean.kf.WxCpKfAccountDel;
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 org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.io.InputStream;
/**
* WxCpKfServiceImpl-测试类
* 需要用到专门的 secret https://kf.weixin.qq.com/api/doc/path/93304#secret
*
* @author Fu
* @date 2022/1/19 20:12
*/
@Guice(modules = ApiTestModule.class)
public class WxCpKfServiceImplTest {
@Inject
private WxCpService wxService;
private static String kfid = "wkPzhXVAAAJD9oR75LrO1DmURSOUFBIg";
@Test(priority = 1)
public void testAccountAdd() throws Exception {
try (InputStream in = ClassLoader.getSystemResourceAsStream("mm.jpeg")) {
WxMediaUploadResult result = this.wxService.getMediaService().upload(WxConsts.MediaFileType.IMAGE, "jpeg", in);
String mediaId = result.getMediaId();
WxCpKfAccountAdd add = new WxCpKfAccountAdd();
add.setMediaId(mediaId);
add.setName("kefu01");
WxCpKfAccountAddResp resp = this.wxService.getKfService().addAccount(add);
System.out.println(resp);
kfid = resp.getOpenKfid();
}
}
@Test(priority = 2)
public void testAccountUpd() throws Exception {
WxCpKfAccountUpd upd = new WxCpKfAccountUpd();
upd.setOpenKfid(kfid);
upd.setName("kefu01-upd");
WxCpBaseResp resp = this.wxService.getKfService().updAccount(upd);
System.out.println(resp);
}
@Test(priority = 3)
public void testAccountList() throws Exception {
WxCpKfAccountListResp resp = this.wxService.getKfService().listAccount();
System.out.println(resp);
}
@Test(priority = 4)
public void testAccountLink() throws Exception {
WxCpKfAccountLink link = new WxCpKfAccountLink();
link.setOpenKfid(kfid);
link.setScene("scene");
WxCpKfAccountLinkResp resp = this.wxService.getKfService().getAccountLink(link);
System.out.println(resp);
}
@Test(priority = 5)
public void testAccountDel() throws Exception {
WxCpKfAccountDel del = new WxCpKfAccountDel();
del.setOpenKfid(kfid);
WxCpBaseResp resp = this.wxService.getKfService().delAccount(del);
System.out.println(resp);
}
}