🆕 #4092 【企业微信】增加待办API的支持
This commit is contained in:
@@ -673,4 +673,11 @@ public interface WxCpService extends WxService {
|
||||
* @return 人事助手服务 hr service
|
||||
*/
|
||||
WxCpHrService getHrService();
|
||||
|
||||
/**
|
||||
* 获取待办服务
|
||||
*
|
||||
* @return 待办服务 todo service
|
||||
*/
|
||||
WxCpTodoService getTodoService();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package me.chanjar.weixin.cp.api;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.bean.todo.WxCpTodo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 企业微信待办接口.
|
||||
* <p>
|
||||
* 官方文档:
|
||||
* <a href="https://developer.work.weixin.qq.com/document/path/101524">获取待办详情</a>,
|
||||
* <a href="https://developer.work.weixin.qq.com/document/path/101534">更新待办状态</a>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> created on 2026-08-11
|
||||
*/
|
||||
public interface WxCpTodoService {
|
||||
/**
|
||||
* 获取待办详情.
|
||||
* <p>
|
||||
* 该接口用于获取指定的待办详情,请求参数仅包含必填的 todo_id,响应直接返回单个待办对象。
|
||||
* <p>
|
||||
* 请求方式: POST(HTTPS)
|
||||
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/todo/get?access_token=ACCESS_TOKEN
|
||||
*
|
||||
* @param todoId 待办ID
|
||||
* @return 待办详情 wx cp todo
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
WxCpTodo get(String todoId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 更新待办状态.
|
||||
* <p>
|
||||
* 该接口用于修改指定的待办信息,支持修改待办整体状态(status 字段)、待办参与人及其状态(attendees[].userid / status 字段)。
|
||||
* 仅允许修改当前应用创建的待办,不允许修改已删除的待办。
|
||||
* <p>
|
||||
* 请求方式: POST(HTTPS)
|
||||
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/todo/update?access_token=ACCESS_TOKEN
|
||||
*
|
||||
* @param todoId 待办ID
|
||||
* @param status 待办整体状态,可不传:0 - 完成;1 - 进行中。为 null 时不修改整体状态
|
||||
* @param attendees 待办参与人列表,最多支持20个参与人。为 null 或空时不修改参与人列表
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
void update(String todoId, Integer status, List<WxCpTodo.Attendee> attendees) throws WxErrorException;
|
||||
}
|
||||
@@ -77,6 +77,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
|
||||
private final WxCpCorpGroupService corpGroupService = new WxCpCorpGroupServiceImpl(this);
|
||||
private final WxCpIntelligentRobotService intelligentRobotService = new WxCpIntelligentRobotServiceImpl(this);
|
||||
private final WxCpHrService hrService = new WxCpHrServiceImpl(this);
|
||||
private final WxCpTodoService todoService = new WxCpTodoServiceImpl(this);
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新access token的锁.
|
||||
@@ -753,4 +754,9 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
|
||||
public WxCpHrService getHrService() {
|
||||
return this.hrService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpTodoService getTodoService() {
|
||||
return this.todoService;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.WxCpTodoService;
|
||||
import me.chanjar.weixin.cp.bean.todo.WxCpTodo;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Todo.*;
|
||||
|
||||
/**
|
||||
* 企业微信待办接口实现类.
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> created on 2026-08-11
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WxCpTodoServiceImpl implements WxCpTodoService {
|
||||
private final WxCpService cpService;
|
||||
|
||||
@Override
|
||||
public WxCpTodo get(String todoId) throws WxErrorException {
|
||||
final Map<String, Object> param = new HashMap<>(1);
|
||||
param.put("todo_id", todoId);
|
||||
final String response = this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(TODO_GET),
|
||||
WxCpGsonBuilder.create().toJson(param));
|
||||
return WxCpGsonBuilder.create().fromJson(response, WxCpTodo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String todoId, Integer status, List<WxCpTodo.Attendee> attendees) throws WxErrorException {
|
||||
final Map<String, Object> param = new HashMap<>(3);
|
||||
param.put("todo_id", todoId);
|
||||
if (status != null) {
|
||||
param.put("status", status);
|
||||
}
|
||||
if (attendees != null && !attendees.isEmpty()) {
|
||||
param.put("attendees", attendees);
|
||||
}
|
||||
|
||||
this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(TODO_UPDATE),
|
||||
WxCpGsonBuilder.create().toJson(param));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package me.chanjar.weixin.cp.bean.todo;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import me.chanjar.weixin.common.bean.ToJson;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 待办信息bean.
|
||||
* <p>
|
||||
* 官方文档:
|
||||
* <a href="https://developer.work.weixin.qq.com/document/path/101524">获取待办详情</a>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> created on 2026-08-11
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class WxCpTodo implements Serializable, ToJson {
|
||||
private static final long serialVersionUID = -1L;
|
||||
|
||||
/**
|
||||
* 待办ID
|
||||
*/
|
||||
@SerializedName("todo_id")
|
||||
private String todoId;
|
||||
/**
|
||||
* 待办内容
|
||||
*/
|
||||
@SerializedName("content")
|
||||
private String content;
|
||||
/**
|
||||
* 待办创建人ID
|
||||
*/
|
||||
@SerializedName("creator")
|
||||
private String creator;
|
||||
/**
|
||||
* 待办状态。
|
||||
* 0 - 已完成
|
||||
* 1 - 进行中
|
||||
* 2 - 已删除
|
||||
*/
|
||||
@SerializedName("status")
|
||||
private Integer status;
|
||||
/**
|
||||
* 待办创建时间戳(整型秒数)
|
||||
*/
|
||||
@SerializedName("create_time")
|
||||
private Long createTime;
|
||||
/**
|
||||
* 待办参与人列表
|
||||
*/
|
||||
@SerializedName("attendees")
|
||||
private List<Attendee> attendees;
|
||||
/**
|
||||
* 待办截止时间戳(整型秒数)
|
||||
*/
|
||||
@SerializedName("end_time")
|
||||
private Long endTime;
|
||||
/**
|
||||
* 提醒列表
|
||||
*/
|
||||
@SerializedName("reminders")
|
||||
private List<Reminder> reminders;
|
||||
|
||||
@Override
|
||||
public String toJson() {
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 待办参与人.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class Attendee implements Serializable {
|
||||
private static final long serialVersionUID = -1L;
|
||||
|
||||
/**
|
||||
* 待办参与人ID
|
||||
*/
|
||||
@SerializedName("userid")
|
||||
private String userid;
|
||||
/**
|
||||
* 参与人的待办状态。
|
||||
* 0 - 完成
|
||||
* 1 - 进行中
|
||||
*/
|
||||
@SerializedName("status")
|
||||
private Integer status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 待办提醒.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class Reminder implements Serializable {
|
||||
private static final long serialVersionUID = -1L;
|
||||
|
||||
/**
|
||||
* 提醒时间戳(整型秒数)
|
||||
*/
|
||||
@SerializedName("remind_time")
|
||||
private Long remindTime;
|
||||
}
|
||||
}
|
||||
@@ -1884,4 +1884,22 @@ public interface WxCpApiPathConsts {
|
||||
*/
|
||||
String UPDATE_EMPLOYEE_FIELD_INFO = "/cgi-bin/hr/update_staff_info";
|
||||
}
|
||||
|
||||
/**
|
||||
* 待办相关接口.
|
||||
* 官方文档:https://developer.work.weixin.qq.com/document/path/101524
|
||||
*/
|
||||
interface Todo {
|
||||
/**
|
||||
* 获取待办详情
|
||||
* https://developer.work.weixin.qq.com/document/path/101524
|
||||
*/
|
||||
String TODO_GET = "/cgi-bin/todo/get";
|
||||
|
||||
/**
|
||||
* 更新待办状态
|
||||
* https://developer.work.weixin.qq.com/document/path/101534
|
||||
*/
|
||||
String TODO_UPDATE = "/cgi-bin/todo/update";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.todo.WxCpTodo;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* 单元测试类.
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> created on 2026-08-11
|
||||
*/
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxCpTodoServiceImplTest {
|
||||
/**
|
||||
* The Wx service.
|
||||
*/
|
||||
@Inject
|
||||
protected WxCpService wxService;
|
||||
|
||||
private static final String TODO_ID = "17c7d2bd9f20d652840f72f59e796AAA";
|
||||
|
||||
/**
|
||||
* Test get.
|
||||
*
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
@Test
|
||||
public void testGet() throws WxErrorException {
|
||||
final WxCpTodo todo = this.wxService.getTodoService().get(TODO_ID);
|
||||
assertNotNull(todo, "get() 返回的待办对象不应为 null");
|
||||
assertEquals(todo.getTodoId(), TODO_ID, "返回的 todo_id 应与请求一致");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update status only.
|
||||
*
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateStatusOnly() throws WxErrorException {
|
||||
this.wxService.getTodoService().update(TODO_ID, 0, null);
|
||||
// 更新成功后通过 get() 回查,验证整体状态确实写入
|
||||
final WxCpTodo todo = this.wxService.getTodoService().get(TODO_ID);
|
||||
assertNotNull(todo, "回查待办不应为 null");
|
||||
assertEquals(todo.getStatus(), Integer.valueOf(0), "待办整体状态应为 0(完成)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update with attendees.
|
||||
*
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateWithAttendees() throws WxErrorException {
|
||||
this.wxService.getTodoService().update(TODO_ID, 1,
|
||||
Arrays.asList(
|
||||
new WxCpTodo.Attendee().setUserid("lisi").setStatus(0),
|
||||
new WxCpTodo.Attendee().setUserid("zhangsan").setStatus(1)
|
||||
));
|
||||
// 更新成功后通过 get() 回查,验证参与人列表确实写入
|
||||
final WxCpTodo todo = this.wxService.getTodoService().get(TODO_ID);
|
||||
assertNotNull(todo, "回查待办不应为 null");
|
||||
assertNotNull(todo.getAttendees(), "attendees 列表不应为 null");
|
||||
assertEquals(todo.getAttendees().size(), 2, "参与人数量应为 2");
|
||||
assertEquals(todo.getStatus(), Integer.valueOf(1), "待办整体状态应为 1(进行中)");
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
<class name="me.chanjar.weixin.cp.bean.message.WxCpXmlOutVideoMessageTest"/>
|
||||
<class name="me.chanjar.weixin.cp.bean.message.WxCpXmlOutVoiceMessageTest"/>
|
||||
<class name="me.chanjar.weixin.cp.bean.message.WxCpXmlOutTextMessageTest"/>
|
||||
<class name="me.chanjar.weixin.cp.bean.todo.WxCpTodoServiceMockTest"/>
|
||||
</classes>
|
||||
</test>
|
||||
</suite>
|
||||
|
||||
Reference in New Issue
Block a user