diff --git a/MINIAPP_KEFU_SERVICE.md b/MINIAPP_KEFU_SERVICE.md new file mode 100644 index 0000000000..96cf4c3831 --- /dev/null +++ b/MINIAPP_KEFU_SERVICE.md @@ -0,0 +1,80 @@ +# WeChat Mini Program Customer Service Management + +This document describes the new customer service management functionality added to the WxJava Mini Program SDK. + +## Overview + +Previously, the mini program module only had: +- `WxMaCustomserviceWorkService` - For binding mini programs to enterprise WeChat customer service +- `WxMaMsgService.sendKefuMsg()` - For sending customer service messages + +The new `WxMaKefuService` adds comprehensive customer service management capabilities: + +## Features + +### Customer Service Account Management +- `kfList()` - Get list of customer service accounts +- `kfAccountAdd()` - Add new customer service account +- `kfAccountUpdate()` - Update customer service account +- `kfAccountDel()` - Delete customer service account + +### Session Management +- `kfSessionCreate()` - Create customer service session +- `kfSessionClose()` - Close customer service session +- `kfSessionGet()` - Get customer session status +- `kfSessionList()` - Get customer service session list + +## Usage Example + +```java +// Get the customer service management service +WxMaKefuService kefuService = wxMaService.getKefuService(); + +// Add a new customer service account +WxMaKfAccountRequest request = WxMaKfAccountRequest.builder() + .kfAccount("service001@example") + .kfNick("Customer Service 001") + .kfPwd("password123") + .build(); +boolean result = kefuService.kfAccountAdd(request); + +// Create a session between user and customer service +boolean sessionResult = kefuService.kfSessionCreate("user_openid", "service001@example"); + +// Get customer service list +WxMaKfList kfList = kefuService.kfList(); +``` + +## Bean Classes + +### Request Objects +- `WxMaKfAccountRequest` - For customer service account operations +- `WxMaKfSessionRequest` - For session operations + +### Response Objects +- `WxMaKfInfo` - Customer service account information +- `WxMaKfList` - List of customer service accounts +- `WxMaKfSession` - Session information +- `WxMaKfSessionList` - List of sessions + +## API Endpoints + +The service uses the following WeChat Mini Program API endpoints: +- `https://api.weixin.qq.com/cgi-bin/customservice/getkflist` - Get customer service list +- `https://api.weixin.qq.com/customservice/kfaccount/add` - Add customer service account +- `https://api.weixin.qq.com/customservice/kfaccount/update` - Update customer service account +- `https://api.weixin.qq.com/customservice/kfaccount/del` - Delete customer service account +- `https://api.weixin.qq.com/customservice/kfsession/create` - Create session +- `https://api.weixin.qq.com/customservice/kfsession/close` - Close session +- `https://api.weixin.qq.com/customservice/kfsession/getsession` - Get session +- `https://api.weixin.qq.com/customservice/kfsession/getsessionlist` - Get session list + +## Integration + +The service is automatically available through the main `WxMaService` interface: + +```java +WxMaKefuService kefuService = wxMaService.getKefuService(); +``` + +This fills the gap mentioned in the original issue and provides full customer service management capabilities for WeChat Mini Programs. \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaKefuService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaKefuService.java new file mode 100644 index 0000000000..b8b5a03809 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaKefuService.java @@ -0,0 +1,128 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfInfo; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfList; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSession; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSessionList; +import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfAccountRequest; +import me.chanjar.weixin.common.error.WxErrorException; + +/** + *
+ * 小程序客服管理接口.
+ * 不同于 WxMaCustomserviceWorkService (企业微信客服绑定) 和 WxMaMsgService.sendKefuMsg (发送客服消息),
+ * 此接口专门处理小程序客服账号管理、会话管理等功能。
+ * 
+ * 注意:小程序客服管理接口与公众号客服管理接口在API端点和功能上有所不同。
+ * 
+ * + * @author Binary Wang + */ +public interface WxMaKefuService { + + /** + *
+   * 获取客服基本信息
+   * 详情请见:获取客服基本信息
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
+   * 
+ * + * @return 客服列表 + * @throws WxErrorException 异常 + */ + WxMaKfList kfList() throws WxErrorException; + + /** + *
+   * 添加客服账号
+   * 详情请见:添加客服账号
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
+   * 
+ * + * @param request 客服账号信息 + * @return 是否成功 + * @throws WxErrorException 异常 + */ + boolean kfAccountAdd(WxMaKfAccountRequest request) throws WxErrorException; + + /** + *
+   * 修改客服账号
+   * 详情请见:修改客服账号
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
+   * 
+ * + * @param request 客服账号信息 + * @return 是否成功 + * @throws WxErrorException 异常 + */ + boolean kfAccountUpdate(WxMaKfAccountRequest request) throws WxErrorException; + + /** + *
+   * 删除客服账号
+   * 详情请见:删除客服账号
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+   * 
+ * + * @param kfAccount 客服账号 + * @return 是否成功 + * @throws WxErrorException 异常 + */ + boolean kfAccountDel(String kfAccount) throws WxErrorException; + + /** + *
+   * 创建会话
+   * 详情请见:创建会话
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN
+   * 
+ * + * @param openid 用户openid + * @param kfAccount 客服账号 + * @return 是否成功 + * @throws WxErrorException 异常 + */ + boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException; + + /** + *
+   * 关闭会话
+   * 详情请见:关闭会话
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN
+   * 
+ * + * @param openid 用户openid + * @param kfAccount 客服账号 + * @return 是否成功 + * @throws WxErrorException 异常 + */ + boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException; + + /** + *
+   * 获取客户的会话状态
+   * 详情请见:获取客户的会话状态
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID
+   * 
+ * + * @param openid 用户openid + * @return 会话信息 + * @throws WxErrorException 异常 + */ + WxMaKfSession kfSessionGet(String openid) throws WxErrorException; + + /** + *
+   * 获取客服的会话列表
+   * 详情请见:获取客服的会话列表
+   * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+   * 
+ * + * @param kfAccount 客服账号 + * @return 会话列表 + * @throws WxErrorException 异常 + */ + WxMaKfSessionList kfSessionList(String kfAccount) throws WxErrorException; + +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index ef3a46bad9..cadff9564f 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -285,6 +285,13 @@ WxMaApiResponse execute( */ WxMaCustomserviceWorkService getCustomserviceWorkService(); + /** + * 获取小程序客服管理服务。 + * + * @return 客服管理服务对象WxMaKefuService + */ + WxMaKefuService getKefuService(); + /** * 获取jsapi操作相关服务对象。 * diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java index ec33dede0c..c7e9f56873 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java @@ -113,6 +113,7 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH private final WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this); private final WxMaCodeService codeService = new WxMaCodeServiceImpl(this); private final WxMaCustomserviceWorkService customserviceWorkService = new WxMaCustomserviceWorkServiceImpl(this); + private final WxMaKefuService maKefuService = new WxMaKefuServiceImpl(this); private final WxMaInternetService internetService = new WxMaInternetServiceImpl(this); private final WxMaSettingService settingService = new WxMaSettingServiceImpl(this); private final WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this); @@ -657,6 +658,11 @@ public WxMaCustomserviceWorkService getCustomserviceWorkService() { return this.customserviceWorkService; } + @Override + public WxMaKefuService getKefuService() { + return this.maKefuService; + } + @Override public WxMaJsapiService getJsapiService() { return this.jsapiService; diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImpl.java new file mode 100644 index 0000000000..2fa39603a0 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImpl.java @@ -0,0 +1,92 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaKefuService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfInfo; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfList; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSession; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSessionList; +import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfAccountRequest; +import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfSessionRequest; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; + +/** + * 小程序客服管理服务实现. + * + * @author Binary Wang + */ +@RequiredArgsConstructor +public class WxMaKefuServiceImpl implements WxMaKefuService { + + // 小程序客服管理接口URL + private static final String KFLIST_GET_URL = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist"; + private static final String KFACCOUNT_ADD_URL = "https://api.weixin.qq.com/customservice/kfaccount/add"; + private static final String KFACCOUNT_UPDATE_URL = "https://api.weixin.qq.com/customservice/kfaccount/update"; + private static final String KFACCOUNT_DEL_URL = "https://api.weixin.qq.com/customservice/kfaccount/del?kf_account=%s"; + private static final String KFSESSION_CREATE_URL = "https://api.weixin.qq.com/customservice/kfsession/create"; + private static final String KFSESSION_CLOSE_URL = "https://api.weixin.qq.com/customservice/kfsession/close"; + private static final String KFSESSION_GET_URL = "https://api.weixin.qq.com/customservice/kfsession/getsession?openid=%s"; + private static final String KFSESSION_LIST_URL = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?kf_account=%s"; + + private final WxMaService service; + + @Override + public WxMaKfList kfList() throws WxErrorException { + String responseContent = this.service.get(KFLIST_GET_URL, null); + return WxMaKfList.fromJson(responseContent); + } + + @Override + public boolean kfAccountAdd(WxMaKfAccountRequest request) throws WxErrorException { + String responseContent = this.service.post(KFACCOUNT_ADD_URL, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfAccountUpdate(WxMaKfAccountRequest request) throws WxErrorException { + String responseContent = this.service.post(KFACCOUNT_UPDATE_URL, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfAccountDel(String kfAccount) throws WxErrorException { + String url = String.format(KFACCOUNT_DEL_URL, kfAccount); + String responseContent = this.service.get(url, null); + return responseContent != null; + } + + @Override + public boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException { + WxMaKfSessionRequest request = WxMaKfSessionRequest.builder() + .kfAccount(kfAccount) + .openid(openid) + .build(); + String responseContent = this.service.post(KFSESSION_CREATE_URL, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException { + WxMaKfSessionRequest request = WxMaKfSessionRequest.builder() + .kfAccount(kfAccount) + .openid(openid) + .build(); + String responseContent = this.service.post(KFSESSION_CLOSE_URL, request.toJson()); + return responseContent != null; + } + + @Override + public WxMaKfSession kfSessionGet(String openid) throws WxErrorException { + String url = String.format(KFSESSION_GET_URL, openid); + String responseContent = this.service.get(url, null); + return WxMaKfSession.fromJson(responseContent); + } + + @Override + public WxMaKfSessionList kfSessionList(String kfAccount) throws WxErrorException { + String url = String.format(KFSESSION_LIST_URL, kfAccount); + String responseContent = this.service.get(url, null); + return WxMaKfSessionList.fromJson(responseContent); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfInfo.java new file mode 100644 index 0000000000..476056d518 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfInfo.java @@ -0,0 +1,79 @@ +package cn.binarywang.wx.miniapp.bean.kefu; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 小程序客服信息. + * + * @author Binary Wang + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaKfInfo implements Serializable { + private static final long serialVersionUID = -7916302137791763175L; + + /** + * 客服账号. + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * 客服昵称. + */ + @SerializedName("kf_nick") + private String kfNick; + + /** + * 客服密码. + */ + @SerializedName("kf_id") + private String kfId; + + /** + * 客服头像. + */ + @SerializedName("kf_headimgurl") + private String kfHeadImgUrl; + + /** + * 如果客服帐号已绑定了客服人员微信号,则此处显示微信号. + */ + @SerializedName("kf_wx") + private String kfWx; + + /** + * 如果客服帐号尚未绑定微信号,但是已经发起了一个绑定邀请,则此处显示绑定邀请的微信号. + */ + @SerializedName("invite_wx") + private String inviteWx; + + /** + * 邀请的状态,有等待确认"waiting",被拒绝"rejected",过期"expired". + */ + @SerializedName("invite_expire_time") + private Long inviteExpireTime; + + /** + * 邀请的过期时间,为unix时间戳. + */ + @SerializedName("invite_status") + private String inviteStatus; + + public static WxMaKfInfo fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaKfInfo.class); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfList.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfList.java new file mode 100644 index 0000000000..8dd87a1728 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfList.java @@ -0,0 +1,35 @@ +package cn.binarywang.wx.miniapp.bean.kefu; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 小程序客服列表. + * + * @author Binary Wang + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaKfList implements Serializable { + private static final long serialVersionUID = 6416633293297389972L; + + @SerializedName("kf_list") + private List kfList; + + public static WxMaKfList fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaKfList.class); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSession.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSession.java new file mode 100644 index 0000000000..60c010499c --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSession.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.bean.kefu; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 小程序客服会话. + * + * @author Binary Wang + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaKfSession implements Serializable { + private static final long serialVersionUID = -6987567952389036965L; + + /** + * 正在接待的客服,为空表示没有人在接待. + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * 会话接入的时间. + */ + @SerializedName("createtime") + private Long createTime; + + public static WxMaKfSession fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaKfSession.class); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSessionList.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSessionList.java new file mode 100644 index 0000000000..e172e2e4e5 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSessionList.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.bean.kefu; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 小程序客服会话列表. + * + * @author Binary Wang + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaKfSessionList implements Serializable { + private static final long serialVersionUID = -1538600729426188776L; + + @SerializedName("sessionlist") + private List sessionList; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SessionInfo implements Serializable { + private static final long serialVersionUID = -2077261313274513580L; + + /** + * 粉丝的openid. + */ + @SerializedName("openid") + private String openid; + + /** + * 会话创建时间,UNIX时间戳. + */ + @SerializedName("createtime") + private Long createTime; + + /** + * 粉丝的最后一条消息的时间,UNIX时间戳. + */ + @SerializedName("latest_time") + private Long latestTime; + } + + public static WxMaKfSessionList fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaKfSessionList.class); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfAccountRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfAccountRequest.java new file mode 100644 index 0000000000..0ad8913639 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfAccountRequest.java @@ -0,0 +1,49 @@ +package cn.binarywang.wx.miniapp.bean.kefu.request; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 小程序客服账号操作请求. + * + * @author Binary Wang + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaKfAccountRequest implements Serializable { + private static final long serialVersionUID = -4953504451749066635L; + + /** + * 客服账号. + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * 客服昵称. + */ + @SerializedName("kf_nick") + private String kfNick; + + /** + * 客服密码. + */ + @SerializedName("kf_pwd") + private String kfPwd; + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + public static WxMaKfAccountRequest fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaKfAccountRequest.class); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfSessionRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfSessionRequest.java new file mode 100644 index 0000000000..f8180f926a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfSessionRequest.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.bean.kefu.request; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 小程序客服会话操作请求. + * + * @author Binary Wang + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaKfSessionRequest implements Serializable { + private static final long serialVersionUID = -3278295399203344398L; + + /** + * 客服账号. + */ + @SerializedName("kf_account") + private String kfAccount; + + /** + * 用户openid. + */ + @SerializedName("openid") + private String openid; + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + public static WxMaKfSessionRequest fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaKfSessionRequest.class); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImplTest.java new file mode 100644 index 0000000000..456aca93f2 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImplTest.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaKefuService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfList; +import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfAccountRequest; +import me.chanjar.weixin.common.error.WxErrorException; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * 小程序客服管理服务测试. + * + * @author Binary Wang + */ +public class WxMaKefuServiceImplTest { + + @Test + public void testKfList() throws WxErrorException { + WxMaService service = mock(WxMaService.class); + when(service.get(anyString(), any())).thenReturn("{\"kf_list\":[]}"); + + WxMaKefuService kefuService = new WxMaKefuServiceImpl(service); + WxMaKfList result = kefuService.kfList(); + + Assert.assertNotNull(result); + Assert.assertNotNull(result.getKfList()); + Assert.assertEquals(result.getKfList().size(), 0); + } + + @Test + public void testKfAccountAdd() throws WxErrorException { + WxMaService service = mock(WxMaService.class); + when(service.post(anyString(), anyString())).thenReturn("{\"errcode\":0}"); + + WxMaKefuService kefuService = new WxMaKefuServiceImpl(service); + WxMaKfAccountRequest request = WxMaKfAccountRequest.builder() + .kfAccount("test@kfaccount") + .kfNick("测试客服") + .kfPwd("password") + .build(); + + boolean result = kefuService.kfAccountAdd(request); + Assert.assertTrue(result); + } + + @Test + public void testKfSessionCreate() throws WxErrorException { + WxMaService service = mock(WxMaService.class); + when(service.post(anyString(), anyString())).thenReturn("{\"errcode\":0}"); + + WxMaKefuService kefuService = new WxMaKefuServiceImpl(service); + boolean result = kefuService.kfSessionCreate("test_openid", "test@kfaccount"); + Assert.assertTrue(result); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaKefuServiceDemo.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaKefuServiceDemo.java new file mode 100644 index 0000000000..1d62fd9be9 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaKefuServiceDemo.java @@ -0,0 +1,84 @@ +package cn.binarywang.wx.miniapp.demo; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfList; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSession; +import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSessionList; +import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfAccountRequest; +import me.chanjar.weixin.common.error.WxErrorException; + +/** + * 小程序客服管理功能使用示例. + * + * @author Binary Wang + */ +public class WxMaKefuServiceDemo { + + private final WxMaService wxMaService; + + public WxMaKefuServiceDemo(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + /** + * 演示客服账号管理功能 + */ + public void demonstrateCustomerServiceManagement() throws WxErrorException { + // 1. 获取客服列表 + WxMaKfList kfList = wxMaService.getKefuService().kfList(); + System.out.println("当前客服数量: " + kfList.getKfList().size()); + + // 2. 添加新客服账号 + WxMaKfAccountRequest addRequest = WxMaKfAccountRequest.builder() + .kfAccount("service001@example") + .kfNick("客服001") + .kfPwd("password123") + .build(); + + boolean addResult = wxMaService.getKefuService().kfAccountAdd(addRequest); + System.out.println("添加客服账号结果: " + addResult); + + // 3. 更新客服账号信息 + WxMaKfAccountRequest updateRequest = WxMaKfAccountRequest.builder() + .kfAccount("service001@example") + .kfNick("高级客服001") + .build(); + + boolean updateResult = wxMaService.getKefuService().kfAccountUpdate(updateRequest); + System.out.println("更新客服账号结果: " + updateResult); + } + + /** + * 演示客服会话管理功能 + */ + public void demonstrateSessionManagement() throws WxErrorException { + String userOpenid = "user_openid_example"; + String kfAccount = "service001@example"; + + // 1. 创建客服会话 + boolean createResult = wxMaService.getKefuService().kfSessionCreate(userOpenid, kfAccount); + System.out.println("创建会话结果: " + createResult); + + // 2. 获取用户会话状态 + WxMaKfSession session = wxMaService.getKefuService().kfSessionGet(userOpenid); + System.out.println("用户当前会话客服: " + session.getKfAccount()); + + // 3. 获取客服的会话列表 + WxMaKfSessionList sessionList = wxMaService.getKefuService().kfSessionList(kfAccount); + System.out.println("客服当前会话数量: " + sessionList.getSessionList().size()); + + // 4. 关闭客服会话 + boolean closeResult = wxMaService.getKefuService().kfSessionClose(userOpenid, kfAccount); + System.out.println("关闭会话结果: " + closeResult); + } + + /** + * 演示客服账号删除功能 + */ + public void demonstrateAccountDeletion() throws WxErrorException { + String kfAccount = "service001@example"; + + boolean deleteResult = wxMaService.getKefuService().kfAccountDel(kfAccount); + System.out.println("删除客服账号结果: " + deleteResult); + } +} \ No newline at end of file