This commit is contained in:
@jyuhsin
2026-02-27 15:48:25 +08:00
parent 983a9edfce
commit ad70a0c4d8
12 changed files with 427 additions and 11 deletions
Binary file not shown.
+8
View File
@@ -26,6 +26,14 @@
</properties>
<dependencies>
<dependency>
<groupId>com.wisedu.casp</groupId>
<artifactId>casp-sdk</artifactId>
<version>latest</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/casp-sdk-java_20260114.jar</systemPath>
</dependency>
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-All</artifactId>
@@ -24,6 +24,7 @@ import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.flow.vo.HighLightVO;
import com.budwk.app.flow.vo.ProcessInstanceVO;
import com.budwk.app.flow.vo.ProcessTaskVO;
import com.budwk.app.todo.service.TodoService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -53,6 +54,8 @@ public class FlowCommonController {
private Dao dao;
@Inject
private FlowCommonService flowCommonService;
@Inject
private TodoService todoService;
@At("/approval/form")
@SaCheckLogin
@@ -277,7 +280,8 @@ public class FlowCommonController {
// 发送任务撤回事件 确保上面执行成功
for (ProcessTask task : taskList) {
ProcessPublisher.notify(ProcessEvent.builder().eventType(ProcessEventTypeEnum.PROCESS_TASK_REVOKE).sourceId(task.getId()).build());
}
todoService.deleteTask(task.getId().toString());
}
return Result.success();
}
@@ -4,6 +4,7 @@ import com.budwk.app.flow.engine.event.ProcessEvent;
import com.budwk.app.flow.engine.event.ProcessEventListener;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
import com.budwk.app.todo.service.TodoService;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -16,12 +17,17 @@ public class ProcessTaskEndEventListener implements ProcessEventListener {
@Inject
private Dao dao;
@Inject
private TodoService todoService;
@Override
public void onEvent(ProcessEvent event) {
if (event.getEventType() == ProcessEventTypeEnum.PROCESS_TASK_END) {
Long sourceId = event.getSourceId();
ProcessTask task = dao.fetch(ProcessTask.class, sourceId);
// 好了,任务完成,就可以调接口完成待办了
todoService.updateTask(task);
System.out.println("流程任务完成事件:" + task.getDisplayName());
}
}
@@ -8,6 +8,7 @@ import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
import com.budwk.app.todo.service.TodoService;
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
@@ -30,18 +31,19 @@ public class ProcessTaskStartEventListener implements ProcessEventListener {
private Dao dao;
@Inject
private GlobalMessageSendService globalMessageSendService;
@Inject
private TodoService todoService;
@Override
public void onEvent(ProcessEvent event) {
if (event.getEventType() == ProcessEventTypeEnum.PROCESS_TASK_START) {
Long sourceId = event.getSourceId();
ProcessTask task = dao.fetch(ProcessTask.class, sourceId);
sendMessage(task);
sendMessageAndTodo(task);
}
}
private void sendMessage(ProcessTask task) {
private void sendMessageAndTodo(ProcessTask task) {
// 说明是流程开始 用户首次完成任务
if (task.getTaskParentId() == 0 && task.getTaskName().equals("startTask")) {
return;
@@ -62,9 +64,8 @@ public class ProcessTaskStartEventListener implements ProcessEventListener {
String message = StrUtil.format("您有一条待办任务,实例:{},处理环节:{}", taskActor.getActorName(), instanceName, taskDisplayName);
log.info(message);
globalMessageSendService.sendMessage(taskDisplayName, message, 2, List.of(taskActor.getActorId()), null);
}
}
todoService.saveTask(task);
}
}
@@ -0,0 +1,11 @@
package com.budwk.app.todo.callback;
/**
* @ClassName TodoCallbackController
* @Author JyuHsin
* @Date 2026/2/25 16:30
* @Version 1.0
* @Description 回调处理类,有可能有的学校待办平台是传一个地址,然后回调我们
*/
public class TodoCallbackController {
}
@@ -0,0 +1,16 @@
package com.budwk.app.todo.platform;
import lombok.extern.slf4j.Slf4j;
import org.nutz.ioc.loader.annotation.IocBean;
/**
* @ClassName TodoPlatformClient
* @Author JyuHsin
* @Date 2026/2/25 16:25
* @Version 1.0
* @Description TODO
*/
@Slf4j
@IocBean
public class TodoPlatformClient {
}
@@ -0,0 +1,28 @@
package com.budwk.app.todo.platform;
/**
* @ClassName TodoPlatformConfig
* @Author JyuHsin
* @Date 2026/2/25 16:26
* @Version 1.0
* @Description TODO
*/
public class TodoPlatformConfig {
// token 获取
public static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken";
// 待办平台基础地址
public static final String TODO_PLATFORM_BASE_URL = "https://gateway.jshvc.edu.cn/casp-tdc/task/saveOrUpdate";
// 待办平台修改地址
public static final String TODO_PLATFORM_MODIFY_URL = "https://gateway.jshvc.edu.cn/casp-tdc/task/modifyInfo";
// 待办平台删除任务地址
public static final String TODO_PLATFORM_DELETE_TASK_URL = "https://gateway.jshvc.edu.cn/casp-tdc/task/delete";
// 待办平台删除实例地址
public static final String TODO_PLATFORM_DELETE_INSTANCE_URL = "https://gateway.jshvc.edu.cn/casp-tdc/processInstance/realDelete";
public static final String TODO_APP_ID = "1430576717768122368";
public static final String TODO_APP_SECRET = "19A0ACB03FBQHL4R4XQD";
public static final String REDIS_KEY_TODO_ACCESS_TOKEN = "todo:token:";
public static final Long TODO_REQUEST_TIMEOUT = 5000L;
}
@@ -0,0 +1,54 @@
package com.budwk.app.todo.service;
import com.budwk.app.flow.entity.ProcessTask;
import com.wisedu.casp.sdk.api.BaseResponse;
/**
* @ClassName TodoService
* @Author JyuHsin
* @Date 2026/2/25 16:29
* @Version 1.0
* @Description TODO
*/
public interface TodoService {
/**
* 新增待办任务
*
* @param task
*/
void saveTask(ProcessTask task);
/**
* 修改待办任务
*
* @param task
* @return BaseResponse
*/
void updateTask(ProcessTask task);
/**
* 修改待办任务
* 用于更新任务的字段内容,如任务名称、任务处理人等字段,不涉及状态变更
*
* @param task
* @return BaseResponse
*/
void modifyInfo(ProcessTask task);
/**
* 删除待办任务(物理删除)
*
* @param taskId 任务ID,不是我们系统的,是传给学校待办平台的任务ID
* @return BaseResponse
*/
void deleteTask(String taskId);
/**
* 删除流程实例(物理删除)
*
* @param processInstanceId 流程实例ID,不是我们系统的,是传给学校待办平台的流程实例ID
* @return BaseResponse
*/
void deleteProcessInstance(String processInstanceId);
}
@@ -0,0 +1,201 @@
package com.budwk.app.todo.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.vo.ProcessTaskVO;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.todo.platform.TodoPlatformConfig;
import com.budwk.app.todo.service.TodoService;
import com.wisedu.casp.sdk.api.BaseResponse;
import com.wisedu.casp.sdk.api.tdc.constants.*;
import com.wisedu.casp.sdk.api.tdc.model.*;
import com.wisedu.casp.sdk.api.tdc.pushtask.ProcessInstanceRealDeleteRequest;
import com.wisedu.casp.sdk.api.tdc.pushtask.SaveOrUpdateRequest;
import com.wisedu.casp.sdk.api.tdc.pushtask.TaskModifyInfoRequest;
import com.wisedu.casp.sdk.api.tdc.pushtask.TaskRealDeleteRequest;
import com.wisedu.casp.sdk.core.Client;
import com.wisedu.casp.sdk.core.DefaultClient;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* @ClassName TodoServiceImpl
* @Author JyuHsin
* @Date 2026/2/25 16:29
* @Version 1.0
* @Description TODO
*/
@Slf4j
@IocBean
public class TodoServiceImpl implements TodoService {
@Inject
private Dao dao;
@Inject
private RedisService redisService;
@Inject
private FlowEngine flowEngine;
@Override
public void saveTask(ProcessTask task) {
log.info("新增待办任务,任务数据:{}", Json.toJson(task));
try {
// 获取待办实例
ProcessInstance instance = dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
// 获取流程定义
ProcessDefine define = dao.fetch(ProcessDefine.class, instance.getProcessDefineId());
// 获取流程发起人
String initiatorAccount = Json.fromJson(NutMap.class, instance.getVariable()).getString(FlowConst.INITIATOR_ACCOUNT);
// 获取任务执行人
List<ProcessTaskActor> taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
List<Processor> processorList = taskActors.stream().map(o -> new Processor(o.getActorAccount())).toList();
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_BASE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
SaveOrUpdateRequest request = new SaveOrUpdateRequest();
// 发起任务
InsertModel insertModel = new InsertModel();
insertModel.setTaskId(task.getId().toString());
insertModel.setInitiatorId(initiatorAccount);
insertModel.setInitiatorType(ProcessorType.USER_ACCOUNT);
insertModel.setSubject(define.getDisplayName());
insertModel.setPriority(PriorityType.COMMON);
insertModel.setTaskType(TaskType.COMMON);
insertModel.setProcessors(processorList);
insertModel.setProcessType(ProcessType.OR_SIGN);
insertModel.setNodeId(task.getId().toString());
insertModel.setNodeName(task.getTaskName());
insertModel.setPcViewUrl(task.getFormKey());
insertModel.setH5ViewUrl(task.getH5FormKey());
// insertModel.setServiceId("xxx");
// insertModel.setServiceName("xxx");
// 任务关联的申请信息
ApplicationModel applicationModel = new ApplicationModel();
applicationModel.setProcessInstanceId(instance.getId().toString());
insertModel.setApplicationModel(applicationModel);
request.setInsertModel(Collections.singletonList(insertModel));
BaseResponse response = client.execute(request);
log.info("新增待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
log.error("新增待办任务失败", e);
}
}
@Override
public void updateTask(ProcessTask task) {
log.info("更新待办任务,任务数据:{}", Json.toJson(task));
try {
// 获取待办实例
ProcessInstance instance = dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
// 查询任务处理人
Sys_user user = dao.fetch(Sys_user.class, task.getOperator());
// 获取已经处理的人
List<ProcessTaskActor> taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
List<Processor> processorList = taskActors.stream().map(o -> new Processor(o.getActorAccount())).toList();
//获取审批意见
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_MODIFY_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
SaveOrUpdateRequest request = new SaveOrUpdateRequest();
SaveOrUpdateRequest.UpdateModel updateModel = new SaveOrUpdateRequest.UpdateModel();
TaskModel taskModel = new TaskModel();
taskModel.setTaskId(task.getId().toString());
taskModel.setProcessorId(user.getLoginname());
taskModel.setProcessorType(ProcessorType.USER_ACCOUNT);
taskModel.setTaskComment(ObjectUtil.defaultIfNull(taskVO.getTaskFormData().getStr("tf_opinion"), ""));
taskModel.setStatus(TaskStatusType.COMPLETE);
updateModel.setTaskModels(Collections.singletonList(taskModel));
// 更新申请节点信息、处理人信息
ApplyModel applyModel = new ApplyModel();
applyModel.setProcessInstanceId(instance.getId().toString());
applyModel.setProcessInstanceStatus(ProcessInstanceStatusType.RUNNING);
applyModel.setNodeId(task.getId().toString());
applyModel.setNodeName(task.getTaskName());
applyModel.setProcessors(processorList);
updateModel.setApplyModels(Collections.singletonList(applyModel));
request.setUpdateModel(updateModel);
BaseResponse response = client.execute(request);
log.info("更新待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
log.error("更新待办任务失败", e);
}
}
@Override
public void modifyInfo(ProcessTask task) {
log.info("修改待办任务,任务数据:{}", Json.toJson(task));
try {
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_MODIFY_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
TaskModifyInfoRequest request = new TaskModifyInfoRequest();
// 需要修改什么后面扩展吧
request.setTaskId("xxx");
request.setSubject("test");
request.setProcessors(Arrays.asList(new Processor("user01"), new Processor("user02")));
BaseResponse response = client.execute(request);
log.info("修改待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
log.error("修改待办任务失败", e);
}
}
@Override
public void deleteTask(String taskId) {
log.info("删除待办任务,任务ID{}", taskId);
try {
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_DELETE_TASK_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
TaskRealDeleteRequest request = new TaskRealDeleteRequest();
request.setTaskId(taskId);
BaseResponse response = client.execute(request);
log.info("删除待办任务,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
log.error("删除待办任务失败", e);
}
}
@Override
public void deleteProcessInstance(String processInstanceId) {
log.info("删除待办流程,实例ID{}", processInstanceId);
try {
// 创建客户端
Client client = new DefaultClient(TodoPlatformConfig.TODO_PLATFORM_DELETE_INSTANCE_URL, TodoPlatformConfig.TODO_APP_ID, TodoPlatformConfig.TODO_APP_SECRET);
// 创建请求对象
ProcessInstanceRealDeleteRequest request = new ProcessInstanceRealDeleteRequest();
request.setProcessInstanceId(processInstanceId);
BaseResponse response = client.execute(request);
log.info("删除待办流程,接口响应数据:{}", Json.toJson(response));
} catch (Exception e) {
log.error("删除流程实例失败", e);
}
}
}
@@ -32,10 +32,10 @@ public class SmsMessageSendStrategy implements GlobalMessageSendStrategy {
return true; // 短信发送支持异步
}
// @Override
// public boolean isEnabled() {
// return true;
// }
@Override
public boolean isEnabled() {
return false;
}
@Override
public void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
@@ -0,0 +1,87 @@
package com.budwk.app.zhgh.dayofficework.message.strategy.impl;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.sms.SmsService;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import java.util.List;
/**
* @ClassName WechatEnterpriseMessageSendStrategy
* @Author JyuHsin
* @Date 2026/2/27 15:42
* @Version 1.0
* @Description TODO
*/
@IocBean
@Slf4j
public class WechatEnterpriseMessageSendStrategy implements GlobalMessageSendStrategy {
@Inject
private Dao dao;
@Inject
private SmsService smsService;
@Override
public GlobalMessageChannel getChannel() {
return GlobalMessageChannel.WECHAT_ENTERPRISE;
}
@Override
public boolean supportAsync() {
return GlobalMessageSendStrategy.super.supportAsync();
}
@Override
public boolean isEnabled() {
return GlobalMessageSendStrategy.super.isEnabled();
}
@Override
public void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
try {
log.info("开始发送企业微信消息,标题:{},接收人数量:{}", title, receiverIds.size());
// 查询用户手机号
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where(Sys_user::getId, "in", receiverIds));
sendMessage(title, content, type, users, config);
log.info("企业微信消息发送完成,标题:{},接收人数量:{}", title, users.size());
} catch (Exception e) {
log.error("企业微信消息发送失败,标题:{},错误:{}", title, e.getMessage(), e);
throw new RuntimeException("企业微信消息发送失败:" + e.getMessage(), e);
}
}
@Override
public void sendByLoginName(String title, String content, Integer type, List<String> receiverLoginNames, JSONObject config) {
try {
log.info("开始发送企业微信消息(按登录名),标题:{},接收人数量:{}", title, receiverLoginNames.size());
// 查询用户手机号
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where(Sys_user::getLoginname, "in", receiverLoginNames));
sendMessage(title, content, type, users, config);
log.info("企业微信消息发送完成(按登录名),标题:{},接收人数量:{}", title, users.size());
} catch (Exception e) {
log.error("企业微信消息发送失败(按登录名),标题:{},错误:{}", title, e.getMessage(), e);
throw new RuntimeException("企业微信消息发送失败:" + e.getMessage(), e);
}
}
private void sendMessage(String title, String content, Integer type, List<Sys_user> users, JSONObject config) {
if(Lang.isEmpty(users)) {
return;
}
List<String> list = users.stream().map(Sys_user::getLoginname).toList();
smsService.massSend(list, title, content, "");
}
}