diff --git a/lib/casp-sdk-java_20260114.jar b/lib/casp-sdk-java_20260114.jar new file mode 100644 index 0000000..252126b Binary files /dev/null and b/lib/casp-sdk-java_20260114.jar differ diff --git a/pom.xml b/pom.xml index 6e1fd03..5be727c 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,14 @@ + + com.wisedu.casp + casp-sdk + latest + system + ${project.basedir}/lib/casp-sdk-java_20260114.jar + + com.github.javen205 IJPay-All diff --git a/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java b/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java index c5031ca..a81d466 100644 --- a/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java +++ b/src/main/java/com/budwk/app/flow/controller/FlowCommonController.java @@ -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(); } diff --git a/src/main/java/com/budwk/app/flow/listenter/ProcessTaskEndEventListener.java b/src/main/java/com/budwk/app/flow/listenter/ProcessTaskEndEventListener.java index 553c49f..4afc4e1 100644 --- a/src/main/java/com/budwk/app/flow/listenter/ProcessTaskEndEventListener.java +++ b/src/main/java/com/budwk/app/flow/listenter/ProcessTaskEndEventListener.java @@ -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()); } } diff --git a/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java b/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java index d030783..4291d95 100644 --- a/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java +++ b/src/main/java/com/budwk/app/flow/listenter/ProcessTaskStartEventListener.java @@ -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); } - } diff --git a/src/main/java/com/budwk/app/todo/callback/TodoCallbackController.java b/src/main/java/com/budwk/app/todo/callback/TodoCallbackController.java new file mode 100644 index 0000000..9fe9a7f --- /dev/null +++ b/src/main/java/com/budwk/app/todo/callback/TodoCallbackController.java @@ -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 { +} diff --git a/src/main/java/com/budwk/app/todo/platform/TodoPlatformClient.java b/src/main/java/com/budwk/app/todo/platform/TodoPlatformClient.java new file mode 100644 index 0000000..0202de2 --- /dev/null +++ b/src/main/java/com/budwk/app/todo/platform/TodoPlatformClient.java @@ -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 { +} diff --git a/src/main/java/com/budwk/app/todo/platform/TodoPlatformConfig.java b/src/main/java/com/budwk/app/todo/platform/TodoPlatformConfig.java new file mode 100644 index 0000000..f532ec5 --- /dev/null +++ b/src/main/java/com/budwk/app/todo/platform/TodoPlatformConfig.java @@ -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; + +} diff --git a/src/main/java/com/budwk/app/todo/service/TodoService.java b/src/main/java/com/budwk/app/todo/service/TodoService.java new file mode 100644 index 0000000..01058ed --- /dev/null +++ b/src/main/java/com/budwk/app/todo/service/TodoService.java @@ -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); +} diff --git a/src/main/java/com/budwk/app/todo/service/impl/TodoServiceImpl.java b/src/main/java/com/budwk/app/todo/service/impl/TodoServiceImpl.java new file mode 100644 index 0000000..636a093 --- /dev/null +++ b/src/main/java/com/budwk/app/todo/service/impl/TodoServiceImpl.java @@ -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 taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId())); + List 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 taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId())); + List 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); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java index 78e3834..380e42a 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java @@ -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 receiverIds, JSONObject config) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/WechatEnterpriseMessageSendStrategy.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/WechatEnterpriseMessageSendStrategy.java new file mode 100644 index 0000000..e591409 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/WechatEnterpriseMessageSendStrategy.java @@ -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 receiverIds, JSONObject config) { + try { + log.info("开始发送企业微信消息,标题:{},接收人数量:{}", title, receiverIds.size()); + + // 查询用户手机号 + List 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 receiverLoginNames, JSONObject config) { + try { + log.info("开始发送企业微信消息(按登录名),标题:{},接收人数量:{}", title, receiverLoginNames.size()); + + // 查询用户手机号 + List 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 users, JSONObject config) { + if(Lang.isEmpty(users)) { + return; + } + List list = users.stream().map(Sys_user::getLoginname).toList(); + smsService.massSend(list, title, content, ""); + } +}