From dacb5d04a4e70025b71eb5f3ac6c66d79be8f527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A6=85=E9=A5=BC?= <2815246336@qq.com> Date: Mon, 18 Aug 2025 14:56:22 +0800 Subject: [PATCH 01/14] =?UTF-8?q?1.AI=E6=8E=A7=E5=88=B6=E5=99=A8=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 6454c05b96b2e2ebada4255090c0b05b4dca30ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A6=85=E9=A5=BC?= <2815246336@qq.com> Date: Wed, 20 Aug 2025 17:01:28 +0800 Subject: [PATCH 02/14] =?UTF-8?q?AI=E6=8E=A7=E5=88=B6=E5=99=A8=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/aitutor/AiChatController.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java index 3556763..981a0b6 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java @@ -42,48 +42,50 @@ import java.util.concurrent.CompletableFuture; @RequestMapping("/aitutor/aichat") public class AiChatController extends BaseController { +// private static final String DIFY_BASE_URL = "http://172.16.129.101:6100"; + private static final String DIFY_BASE_URL = "http://47.112.118.149:8100"; /** * Dify API的访问密钥 * 用于身份验证,授权访问Dify服务 */ - private static final String DIFY_API_KEY = "app-BfPtBZDNBuHOS9K1PaZrxQYE"; - +// private static final String DIFY_API_KEY = "app-BfPtBZDNBuHOS9K1PaZrxQYE"; + private static final String DIFY_API_KEY = "app-2wjqcYI9n6igHTVHdH8qXlnh"; /** * Dify API的URL地址 * 用于发送聊天消息请求到Dify服务 */ - private static final String DIFY_API_URL = "http://172.16.129.101/v1:6100/v1/chat-messages"; + private static final String DIFY_API_URL = DIFY_BASE_URL+"/v1/chat-messages"; /** * Dify反馈API的基础URL * 用于提交消息反馈(点赞、点踩等) */ - private static final String DIFY_FEEDBACK_BASE_URL = "http://172.16.129.101/v1:6100/v1/messages"; + private static final String DIFY_FEEDBACK_BASE_URL = DIFY_BASE_URL+"/v1/messages"; /** * Dify获取反馈API的基础URL * 用于获取消息反馈(点赞、点踩等) */ - private static final String DIFY_API_FEEDBACK_URL = "http://172.16.129.101/v1:6100/v1/app/feedbacks?page="; + private static final String DIFY_API_FEEDBACK_URL = DIFY_BASE_URL+"/v1/app/feedbacks?page="; /** * Dify消息历史记录API的基础URL * 用于获取消息历史记录 */ - private static final String DIFY_API_HISTORY_URL = "http://172.16.129.101/v1:6100/v1/messages"; + private static final String DIFY_API_HISTORY_URL = DIFY_BASE_URL+"/v1/messages"; /** * Dify会话API的基础URL * 用于获取会话列表 */ - private static final String DIFY_CONVERSATIONS_URL = "http://172.16.129.101/v1:6100/v1/conversations"; + private static final String DIFY_CONVERSATIONS_URL = DIFY_BASE_URL+"/v1/conversations"; /** * Dify文件上传API的URL地址 * 用于上传文件到Dify服务,支持图文多模态理解 */ - private static final String DIFY_FILES_URL = "http://172.16.129.101/v1:6100/v1/files/upload"; + private static final String DIFY_FILES_URL = DIFY_BASE_URL+"/v1/files/upload"; /** * Redis中会话ID的key前缀 @@ -532,7 +534,7 @@ public class AiChatController extends BaseController { return successResult; } catch (IOException e) { e.printStackTrace(); - return AjaxResult.error("网络请求失败,请稍后重试"); + return AjaxResult.error("网络请求失败,请稍后重试getMessagesToAdmin"); } catch (Exception e) { e.printStackTrace(); return AjaxResult.error("请求处理失败: " + e.getMessage()); @@ -571,7 +573,7 @@ public class AiChatController extends BaseController { return successResult; } catch (IOException e) { e.printStackTrace(); - return AjaxResult.error("网络请求失败,请稍后重试"); + return AjaxResult.error("网络请求失败,请稍后重试getMessagesToUser"); } catch (Exception e) { e.printStackTrace(); return AjaxResult.error("请求处理失败: " + e.getMessage()); From 89176c8f329abb891f9608b174214ab1e22ac6e4 Mon Sep 17 00:00:00 2001 From: MDSMO Date: Wed, 20 Aug 2025 17:05:35 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AD=A6=E7=94=9F?= =?UTF-8?q?=E8=AF=81=E5=AE=8C=E6=88=90=E5=88=B6=E4=BD=9C=E5=8F=91=E9=80=81?= =?UTF-8?q?=E7=9A=84=E6=96=87=E6=A1=88=EF=BC=8C=E7=BB=99=E5=A4=84=E5=88=86?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=92=8C=E8=A7=A3=E9=99=A4=E5=A4=84=E5=88=86?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=94=BF=E6=B2=BB=E9=9D=A2=E8=B2=8C=E9=80=89?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/RtStuDisciplinaryApplication.java | 8 ++++ .../domain/RtStuDisciplinaryRelieve.java | 8 ++++ .../RtStuDisciplinaryRelieveServiceImpl.java | 47 +++++++++++++++++++ .../RtStuMultiLevelReviewServiceImpl.java | 2 +- .../RtStuDisciplinaryApplicationMapper.xml | 9 +++- .../RtStuDisciplinaryRelieveMapper.xml | 10 ++++ 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryApplication.java b/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryApplication.java index 1a179c0..039f39b 100644 --- a/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryApplication.java +++ b/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryApplication.java @@ -222,6 +222,14 @@ public class RtStuDisciplinaryApplication extends BaseEntity { @Excel(name = "籍贯") private String jg; + /** + * 政治面貌 + */ + @ApiModelProperty("政治面貌") + @TableField("political_status") + @Excel(name = "政治面貌") + private String politicalStatus; + /** * 市/县 */ diff --git a/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryRelieve.java b/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryRelieve.java index 13d42f0..f94c8e7 100644 --- a/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryRelieve.java +++ b/srs-routine/src/main/java/com/srs/routine/domain/RtStuDisciplinaryRelieve.java @@ -214,6 +214,14 @@ public class RtStuDisciplinaryRelieve extends BaseEntity { @Excel(name = "籍贯") private String jg; + /** + * 政治面貌 + */ + @ApiModelProperty("政治面貌") + @TableField("political_status") + @Excel(name = "政治面貌") + private String politicalStatus; + /** * 市/县 */ diff --git a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryRelieveServiceImpl.java b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryRelieveServiceImpl.java index 2eb7c4d..6ca8357 100644 --- a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryRelieveServiceImpl.java +++ b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryRelieveServiceImpl.java @@ -3,16 +3,20 @@ package com.srs.routine.service.impl; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.srs.common.core.domain.AjaxResult; +import com.srs.common.core.domain.entity.SysUser; import com.srs.common.doman.dto.ProcessResultDto; import com.srs.common.exception.ServiceException; import com.srs.common.utils.DateUtils; import com.srs.common.utils.SecurityUtils; +import com.srs.common.utils.WeChatUtil; import com.srs.flowable.service.IFlowDefinitionService; import com.srs.routine.domain.RtStuDisciplinaryApplication; import com.srs.routine.mapper.RtStuDisciplinaryApplicationMapper; +import com.srs.system.mapper.SysUserMapper; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.IdentityService; import org.flowable.engine.TaskService; @@ -40,6 +44,12 @@ public class RtStuDisciplinaryRelieveServiceImpl extends ServiceImpl sysUsers = sysUserMapper.selectAllocatedList(sysUser); + + // 提取二级学院的书记的账号 + List userNames = sysUsers.stream() + .map(SysUser::getUserName) + .collect(Collectors.toList()); + + // 只有政治面貌是团员时才发送企业微信消息 + if ("团员".equals(politicalStatus)) { + // 消息内容 + String messageContent = "【解除处分】" + applicantName + "的解除处分申请已通过审核。"; + int batchSize = 10; + for (int i = 0; i < userNames.size(); i += batchSize) { + List batch = userNames.subList(i, Math.min(i + batchSize, userNames.size())); + // 拼接成"user1|user2|user3"格式 + String toUser = String.join("|", batch); + // 调用企业微信发送消息方法 + weChatUtil.sendTextMessage(toUser, messageContent); + } + } + } catch (Exception e) { + log.error("发送企业微信消息失败:", e); } } return dto; diff --git a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuMultiLevelReviewServiceImpl.java b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuMultiLevelReviewServiceImpl.java index 2a381ec..b117b83 100644 --- a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuMultiLevelReviewServiceImpl.java +++ b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuMultiLevelReviewServiceImpl.java @@ -117,7 +117,7 @@ public class RtStuMultiLevelReviewServiceImpl extends ServiceImpl 0) { String messageContent = rtStuMultiLevelReview.getNotes(); if (messageContent == null || messageContent.trim().isEmpty()) { - messageContent = "你申请办理的学生证制作完成,长堽校区前往xxx领取,里建校区前往xxx领取"; + messageContent = "你申请办理的学生证制作完成,长堽校区前往经管楼学工处1-1办公室领取,里建校区前往“一站式”学生社区大厅领取"; } weChatUtil.sendTextMessage(rtStuMultiLevelReview.getStuNo(), messageContent); diff --git a/srs-routine/src/main/resources/mapper/routine/RtStuDisciplinaryApplicationMapper.xml b/srs-routine/src/main/resources/mapper/routine/RtStuDisciplinaryApplicationMapper.xml index ed4c2d0..6c710d0 100644 --- a/srs-routine/src/main/resources/mapper/routine/RtStuDisciplinaryApplicationMapper.xml +++ b/srs-routine/src/main/resources/mapper/routine/RtStuDisciplinaryApplicationMapper.xml @@ -34,6 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -44,7 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select application_id, applicant_id, applicant_name, penalty_number, stu_no, stu_name, stu_id, penalty_type, penalty_status, violation_date, expiration_date, evidence_upload, penalty_recommendation, violation_regulations, submission_status, process_instance_id, deploy_id, create_by, create_time, update_by, update_time, remark, gender, - department_Name, grade_name, class_name, mz, birthday, jg, hksz2,disposition_service,letter_service,disciplinary_date from rt_stu_disciplinary_application + department_Name, grade_name, class_name, mz, birthday, jg,political_status,hksz2,disposition_service,letter_service,disciplinary_date from rt_stu_disciplinary_application + + + \ No newline at end of file From 83bce533cc5a4962e6929fc0773d8c47f500b5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E6=97=A0=E6=B6=AF?= <2637171921@qq.com> Date: Thu, 21 Aug 2025 17:10:49 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E8=BF=9D=E7=BA=AA=E5=A4=84=E5=88=86?= =?UTF-8?q?=E7=94=B3=E6=8A=A5=E5=B7=A5=E4=BD=9C=E6=B5=81=E5=AE=8C=E5=85=A8?= =?UTF-8?q?=E6=89=93=E9=80=9A=E3=84=9F(=20=E2=96=94,=20=E2=96=94=20)?= =?UTF-8?q?=E3=84=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../disciplinary/ArchivingNotifyListener.java | 55 ++++++++++++ .../listener/disciplinary/EJXYSJListener.java | 2 +- .../disciplinary/InitiatorResultListener.java | 61 ++++++++++++++ .../SchoolLeaderApprovalListener.java | 55 ++++++++++++ .../disciplinary/StuInfoListener.java | 48 +++++++++-- .../disciplinary/XSJYGLKListener.java | 2 +- .../listener/disciplinary/XWGSListener.java | 2 +- .../disciplinary/XYWJCLWYHListener.java | 83 +++++++++++-------- .../flowable/mapper/DisciplinaryMapper.java | 2 +- ...StuDisciplinaryApplicationServiceImpl.java | 2 +- 10 files changed, 268 insertions(+), 44 deletions(-) create mode 100644 srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/ArchivingNotifyListener.java create mode 100644 srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/InitiatorResultListener.java create mode 100644 srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/SchoolLeaderApprovalListener.java diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/ArchivingNotifyListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/ArchivingNotifyListener.java new file mode 100644 index 0000000..3619a28 --- /dev/null +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/ArchivingNotifyListener.java @@ -0,0 +1,55 @@ +package com.srs.flowable.listener.disciplinary; + +import com.srs.common.utils.WeChatUtil; +import com.srs.common.utils.spring.SpringUtils; +import com.srs.flowable.mapper.DisciplinaryMapper; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.stereotype.Component; +import java.util.List; + +/** + * 执行监听器:在“学生教育管理科审批归档”节点开始时, 知无涯 + * 向负责归档的角色发送企业微信通知。 + */ +@Component +@Slf4j +public class ArchivingNotifyListener implements ExecutionListener { + + @Override + public void notify(DelegateExecution delegateExecution) { + log.info("流程实例 [{}]: 已进入学生教育管理科审批归档节点,准备发送通知。", delegateExecution.getProcessInstanceId()); + + try { + DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class); + + // 1. 【核心】定义负责归档的角色的 role_key。 + final String ARCHIVING_ROLE_KEY = "xsjyglkspgd"; + + // 2. 根据角色Key查询用户ID列表 + List userIdList = disciplinaryMapper.getApprovalByRoleKey(ARCHIVING_ROLE_KEY); + + if (userIdList == null || userIdList.isEmpty()) { + log.warn("根据角色Key '{}' 未找到任何归档人员,无法发送通知。", ARCHIVING_ROLE_KEY); + return; + } + + // 3. 批量查询 userName 并发送通知 + List userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList); + if (!userNameList.isEmpty()) { + String toUser = String.join("|", userNameList); + WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); + String content = "您有一条新的学生违纪归档任务待处理,请点击前往处理。"; + + weChatUtil.sendTextMessage(toUser, content); + log.info("已成功向归档角色 ({}) 发送通知。接收人: {}", ARCHIVING_ROLE_KEY, toUser); + } else { + log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", ARCHIVING_ROLE_KEY, userIdList.size()); + } + + } catch (Exception e) { + log.error("向归档角色发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/EJXYSJListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/EJXYSJListener.java index 28ab42a..8f48c95 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/EJXYSJListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/EJXYSJListener.java @@ -9,7 +9,7 @@ import org.flowable.engine.delegate.ExecutionListener; import org.springframework.stereotype.Component; /** - * 根据辅导员部门id获取二级学院书记 + * 根据辅导员部门id获取二级学院书记 知无涯 */ @Component @Slf4j diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/InitiatorResultListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/InitiatorResultListener.java new file mode 100644 index 0000000..0aede46 --- /dev/null +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/InitiatorResultListener.java @@ -0,0 +1,61 @@ +package com.srs.flowable.listener.disciplinary; + +import com.srs.common.utils.WeChatUtil; +import com.srs.common.utils.spring.SpringUtils; +import com.srs.flowable.mapper.DisciplinaryMapper; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.stereotype.Component; + +/** + * 执行监听器:在“申请人(辅导员)接收”节点开始时, 知无涯 + * 向流程发起人发送企业微信通知,告知其结果已出。 + */ +@Component +@Slf4j +public class InitiatorResultListener implements ExecutionListener { + + @Override + public void notify(DelegateExecution delegateExecution) { + log.info("流程实例 [{}]: 已进入辅导员接收结果节点,准备向发起人发送通知。", delegateExecution.getProcessInstanceId()); + + try { + DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class); + + // 1. 从流程变量中获取发起人的ID。Flowable会自动将发起人ID存入名为 "INITIATOR" 的变量中。 + // 这个变量通常是 String 类型。 + Object initiatorObj = delegateExecution.getVariable("INITIATOR"); + if (initiatorObj == null) { + log.warn("在流程实例 [{}] 中未找到发起人(INITIATOR)变量,无法发送通知。", delegateExecution.getProcessInstanceId()); + return; + } + + // 2. 将发起人ID转换为 Long 类型,以便查询数据库 + Long initiatorUserId; + try { + initiatorUserId = Long.parseLong(initiatorObj.toString()); + } catch (NumberFormatException e) { + log.error("发起人(INITIATOR)变量 '{}' 无法转换为Long类型,无法发送通知。", initiatorObj); + return; + } + + // 3. 使用 initiatorUserId 查询对应的企业微信 userName + String initiatorUserName = disciplinaryMapper.getUserNameByUserId(initiatorUserId); + + if (initiatorUserName != null && !initiatorUserName.isEmpty()) { + // 4. 发送通知 + WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); + String content = "您提交的学生违纪处分申请已有最终处理结果,请点击前往处理。\""; + + weChatUtil.sendTextMessage(initiatorUserName, content); + log.info("已成功向流程发起人 ({}) 发送结果通知。", initiatorUserName); + } else { + log.warn("找到了发起人(userId:{}),但其对应的企业微信账号(userName)为空,未发送通知。", initiatorUserId); + } + + } catch (Exception e) { + log.error("向流程发起人发送结果通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/SchoolLeaderApprovalListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/SchoolLeaderApprovalListener.java new file mode 100644 index 0000000..5bc4cfa --- /dev/null +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/SchoolLeaderApprovalListener.java @@ -0,0 +1,55 @@ +package com.srs.flowable.listener.disciplinary; + +import com.srs.common.utils.WeChatUtil; +import com.srs.common.utils.spring.SpringUtils; +import com.srs.flowable.mapper.DisciplinaryMapper; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.stereotype.Component; +import java.util.List; + +/** + * 执行监听器:在“校领导审批”节点开始时,向校领导发送企业微信通知。 知无涯 + * (简化版:因为流程能到达此节点,即表示前序节点已全票通过) + */ +@Component +@Slf4j +public class SchoolLeaderApprovalListener implements ExecutionListener { + + @Override + public void notify(DelegateExecution delegateExecution) { + log.info("流程实例 [{}]: 已进入校领导审批节点,准备发送通知。", delegateExecution.getProcessInstanceId()); + + try { + DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class); + + // 1. 【核心】定义“校领导”这个角色的 role_key + final String LEADER_ROLE_KEY = "xldsp"; + + // 2. 根据角色Key查询用户ID列表 + List userIdList = disciplinaryMapper.getApprovalByRoleKey(LEADER_ROLE_KEY); + + if (userIdList == null || userIdList.isEmpty()) { + log.warn("根据角色Key '{}' 未找到任何校领导用户,无法发送通知。", LEADER_ROLE_KEY); + return; + } + + // 3. 批量查询 userName 并发送通知 + List userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList); + if (!userNameList.isEmpty()) { + String toUser = String.join("|", userNameList); + WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); + String content = "校领导您有一条新的学生违纪审批任务待处理,请点击前往处理。"; + + weChatUtil.sendTextMessage(toUser, content); + log.info("已成功向校领导 (角色: {}) 发送通知。接收人: {}", LEADER_ROLE_KEY, toUser); + } else { + log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", LEADER_ROLE_KEY, userIdList.size()); + } + + } catch (Exception e) { + log.error("向校领导发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/StuInfoListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/StuInfoListener.java index cab8e3e..40c4281 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/StuInfoListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/StuInfoListener.java @@ -1,12 +1,17 @@ package com.srs.flowable.listener.disciplinary; +import com.srs.common.utils.WeChatUtil; +import com.srs.common.utils.spring.SpringUtils; +import com.srs.flowable.mapper.DisciplinaryMapper; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.ExecutionListener; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; /** - * 设置处分学生审批参数 + * 流程结束监听器。 + * 在流程的最终节点,向当事学生发送处理结果的通知。 知无涯 */ @Component @Slf4j @@ -14,10 +19,41 @@ public class StuInfoListener implements ExecutionListener { @Override public void notify(DelegateExecution delegateExecution) { - Long stuId = (Long)delegateExecution.getVariable("stuId"); + // 1. 从流程变量中获取学生ID + Object stuIdObj = delegateExecution.getVariable("stuId"); - log.info("学生信息:{}",stuId); - delegateExecution.setVariable("approval",stuId); - // todo 企业微信推送消息 + // 安全检查:确保stuId存在且类型正确 + if (!(stuIdObj instanceof Long)) { + log.error("流程实例 [{}] 在结束时未能获取到有效的 'stuId' 变量,无法发送最终通知。", delegateExecution.getProcessInstanceId()); + return; + } + Long stuId = (Long) stuIdObj; + log.info("流程实例 [{}] 即将结束,准备向学生ID: {} 发送最终通知。", delegateExecution.getProcessInstanceId(), stuId); + + // 2. 向该学生发送企业微信通知 + try { + DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class); + + // 根据学生ID查询其对应的企业微信账号(userName) + String userName = disciplinaryMapper.getUserNameByUserId(stuId); + + // 检查是否找到了对应的企业微信账号 + if (!StringUtils.hasText(userName)) { + log.warn("流程实例 [{}]: 根据学生ID '{}' 未找到对应的企业微信账号,无法发送最终通知。", delegateExecution.getProcessInstanceId(), stuId); + return; // 中止发送逻辑 + } + + // 3. 构建并发送通知内容 + WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); + String content = "您好,关于您的违纪处理流程已办结,最终结果已生成。请点击登录系统查看详情。"; + + weChatUtil.sendTextMessage(userName, content); + log.info("流程实例 [{}]: 已成功向学生ID '{}' (企业微信账号: {}) 发送了流程办结通知。", delegateExecution.getProcessInstanceId(), stuId, userName); + + } catch (Exception e) { + // 即使通知失败,也不应影响流程的正常结束 + log.error("流程实例 [{}]: 在向学生ID '{}' 发送最终通知时出现异常。错误详情: {}", + delegateExecution.getProcessInstanceId(), stuId, e.getMessage(), e); + } } -} +} \ No newline at end of file diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XSJYGLKListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XSJYGLKListener.java index 13a0cd1..16faf40 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XSJYGLKListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XSJYGLKListener.java @@ -10,7 +10,7 @@ import org.springframework.stereotype.Component; import java.util.List; /** - * 学生教育管理科审核节点的执行监听器。 + * 学生教育管理科审核节点的执行监听器。 知无涯 * 向“学生教育管理科”角色发送企业微信通知。 */ @Component diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XWGSListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XWGSListener.java index 4394ee1..5345fb0 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XWGSListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XWGSListener.java @@ -15,7 +15,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestBody; /** - * 根据辅导员的部门id,查询该部门的学无干事人员 + * 根据辅导员的部门id,查询该部门的学无干事人员 知无涯 */ @Component @Slf4j diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java index ce8ecea..6963493 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java @@ -1,55 +1,72 @@ package com.srs.flowable.listener.disciplinary; import com.srs.common.utils.WeChatUtil; -import com.srs.common.utils.spring.SpringUtils; import com.srs.flowable.mapper.DisciplinaryMapper; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; +import java.util.stream.Collectors; /** - * 学院违纪处理委员会审批 + * 【线上监听器】为“学院违纪处理委员会”多实例任务准备数据并发送通知 知无涯 */ -@Component +@Component("xywjclwyhListener") @Slf4j public class XYWJCLWYHListener implements ExecutionListener { + // 推荐:使用依赖注入,而不是SpringUtils + @Autowired + private DisciplinaryMapper disciplinaryMapper; + + @Autowired + private WeChatUtil weChatUtil; + @Override - public void notify(DelegateExecution delegateExecution) { - DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean("disciplinaryMapper"); - // 步骤 1: 根据角色Key获取审批人ID列表 (第1次DB查询) + public void notify(DelegateExecution execution) { + log.info("流程实例 [{}]: 在进入'学院违纪处理委员会'节点前,开始准备审批数据...", execution.getProcessInstanceId()); + + // 步骤 1: 单一数据库查询,获取所有需要的审批人信息 (ID和企微账号) + // List userInfos = disciplinaryMapper.getUserInfoByRoleKey("xywjclwyh"); + // 注意:如果您不方便修改Mapper,这里可以保持原来的两次查询,逻辑依然正确。 + // 我们先用原始的两次查询来演示,更具普适性。 + List userIdList = disciplinaryMapper.getApprovalByRoleKey("xywjclwyh"); - if (userIdList == null || userIdList.isEmpty()){ - log.error("未找到角色相关信息"); + + if (userIdList == null || userIdList.isEmpty()) { + log.error("角色 'xywjclwyh' 未配置或未找到任何有效用户,流程无法继续。"); throw new RuntimeException("学院违纪处理委员会审批人员未设置"); - }else{ - delegateExecution.setVariable("userList",userIdList); - // todo 企业微信推送消息 - // --- 企业微信推送消息模块 --- - try { - // 步骤 2: 一次性批量查询所有有效的userName (第2次DB查询,性能最优) - List userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList); - - if (!userNameList.isEmpty()) { - // 步骤 3: 将 userName 列表用 "|" 连接成一个字符串 - String toUser = String.join("|", userNameList); - - WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); - String content = "您有一条新的学生违纪审批任务待处理,请点击前往处理。"; - - weChatUtil.sendTextMessage(toUser, content); - log.info("已成功向学院违纪处理委员会发送群组通知。接收人: {}", toUser); - } else { - log.warn("角色 'xywjclwyh' 存在审批人,但无人配置企业微信账号,未发送任何通知。"); - } - } catch (Exception e) { - // 保证即使通知失败,流程也能继续 - log.error("向学院违纪处理委员会发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e); - } } + // 步骤 2: 设置多实例任务需要的流程变量 (这是“线上”为“节点”准备的核心数据) + execution.setVariable("userList", userIdList); + log.info("流程实例 [{}]: 已成功设置'userList'变量,包含 {} 个审批人。", execution.getProcessInstanceId(), userIdList.size()); + + // 步骤 3: 发送企业微信通知 + sendWeChatNotification(userIdList, execution.getProcessInstanceId()); } -} + + /** + * 封装并执行企业微信通知逻辑 + */ + private void sendWeChatNotification(List userIdList, String processInstanceId) { + try { + List userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList); + if (userNameList == null || userNameList.isEmpty()) { + log.warn("流程实例 [{}]: 角色'xywjclwyh'存在审批人ID,但无人配置企微账号,未发送通知。", processInstanceId); + return; + } + + String toUser = String.join("|", userNameList); + String content = "您有一条新的学生违纪审批任务待处理,请点击前往处理。"; + + weChatUtil.sendTextMessage(toUser, content); + log.info("流程实例 [{}]: 已成功向学院违纪处理委员会发送通知。接收人: {}", processInstanceId, toUser); + } catch (Exception e) { + log.error("流程实例 [{}]: 发送企微通知时出现异常,但不影响主流程。错误: {}", processInstanceId, e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/srs-flowable/src/main/java/com/srs/flowable/mapper/DisciplinaryMapper.java b/srs-flowable/src/main/java/com/srs/flowable/mapper/DisciplinaryMapper.java index 3b45c21..73cd76f 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/mapper/DisciplinaryMapper.java +++ b/srs-flowable/src/main/java/com/srs/flowable/mapper/DisciplinaryMapper.java @@ -23,7 +23,7 @@ public interface DisciplinaryMapper { */ String getUserNameByUserId(@Param("userId") Long userId); /** - * 知无涯新增:根据用户ID列表批量查询用户名列表 + * 知无涯 根据用户ID列表批量查询用户名列表 * @param userIdList 用户ID列表 * @return 用户的username列表 */ diff --git a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java index bb95bfe..89eb0f1 100644 --- a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java +++ b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java @@ -265,7 +265,7 @@ public class RtStuDisciplinaryApplicationServiceImpl extends ServiceImpl Date: Thu, 21 Aug 2025 17:27:23 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E7=BB=BC=E5=90=88=E7=B4=A0=E8=B4=A8-?= =?UTF-8?q?=E7=BB=BC=E5=90=88=E7=B4=A0=E8=B4=A8=E7=94=B3=E8=AF=B7=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8=E4=BB=A3=E5=8A=9E=E5=92=8C=E5=AD=A6=E7=94=9F=E5=A5=96?= =?UTF-8?q?=E6=83=A9-=E5=85=88=E8=BF=9B=E7=8F=AD=E9=9B=86=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../relieve/StuCounselorListener.java | 35 +++++++++++++++++++ .../srs/flowable/mapper/RelieveMapper.java | 4 +++ .../main/resources/mapper/RelieveMapper.xml | 6 ++++ 3 files changed, 45 insertions(+) diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/relieve/StuCounselorListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/relieve/StuCounselorListener.java index 075da46..4f9ddce 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/relieve/StuCounselorListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/relieve/StuCounselorListener.java @@ -1,11 +1,13 @@ package com.srs.flowable.listener.relieve; +import com.srs.common.utils.WeChatUtil; import com.srs.common.utils.spring.SpringUtils; import com.srs.flowable.mapper.LeaveMapper; import com.srs.flowable.mapper.RelieveMapper; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; @@ -17,6 +19,9 @@ import java.util.Map; @Slf4j public class StuCounselorListener implements ExecutionListener { + @Autowired + private WeChatUtil weChatUtil; + @Override public void notify(DelegateExecution delegateExecution) { RelieveMapper relieveMapper = (RelieveMapper) SpringUtils.getBean("relieveMapper"); @@ -31,6 +36,36 @@ public class StuCounselorListener implements ExecutionListener { delegateExecution.setVariable("deptId",map.get("deptId")); // todo 企业微信推送消息 + /** + * 庞世斌 + */ + try { + Long userId = map.get("userId"); + + // 使用 userId 查询对应的企业微信账号 + String userName = relieveMapper.getUserNameByUserId(userId); + + if (userName != null && !userName.isEmpty()) { + WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); + + // 构造包含超链接的消息内容 + String content = "您有一条新的学生违纪审批任务待处理," + + "点此查看"; + + // 发送企业微信消息 + weChatUtil.sendTextMessage(userName, content); + log.info("✅ 已成功向学务干事(userName:{})发送企业微信审批通知。", userName); + + } else { + // 如果找不到 userName,记录警告日志,但流程继续 + log.warn("⚠ 找到了审批人(userId:{}), 但其对应的企业微信账号(userName)为空,无法发送通知。", userId); + } + } catch (Exception e) { + Long userId = map.get("userId"); // 确保日志里带上 userId + log.error("❌ 向学务干事(userId:{})发送企业微信通知时出现异常,但流程将继续。错误详情:", userId, e); + } + + }else { throw new RuntimeException("获取辅导员信息失败"); diff --git a/srs-flowable/src/main/java/com/srs/flowable/mapper/RelieveMapper.java b/srs-flowable/src/main/java/com/srs/flowable/mapper/RelieveMapper.java index 76971ae..e354e3c 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/mapper/RelieveMapper.java +++ b/srs-flowable/src/main/java/com/srs/flowable/mapper/RelieveMapper.java @@ -11,6 +11,10 @@ public interface RelieveMapper { Map getCounselorInfo(Long stuUserId); + + + String getUserNameByUserId ( long userId); + /** * 查询学生解除处分申请 * diff --git a/srs-flowable/src/main/resources/mapper/RelieveMapper.xml b/srs-flowable/src/main/resources/mapper/RelieveMapper.xml index fbd358b..2978efc 100644 --- a/srs-flowable/src/main/resources/mapper/RelieveMapper.xml +++ b/srs-flowable/src/main/resources/mapper/RelieveMapper.xml @@ -113,6 +113,12 @@ where relieve_id = #{relieveId} + + \ No newline at end of file From 6adba8b355b51bd4d1694fdcd988342dd44cf032 Mon Sep 17 00:00:00 2001 From: firefly <1633489380@qq.com> Date: Thu, 21 Aug 2025 17:49:40 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E5=B0=86dify=E7=9A=84=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=B1=BB=E5=AD=98=E5=9C=A8=E9=85=8D=E7=BD=AE=E7=B1=BB=E9=87=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/aitutor/AiChatController.java | 93 ++++------------ .../com/srs/web/core/config/DifyConfig.java | 105 ++++++++++++++++++ srs-admin/src/main/resources/application.yml | 5 + 3 files changed, 133 insertions(+), 70 deletions(-) create mode 100644 srs-admin/src/main/java/com/srs/web/core/config/DifyConfig.java diff --git a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java index 981a0b6..1a1e902 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java @@ -10,6 +10,7 @@ import com.srs.common.core.controller.BaseController; import com.srs.common.exception.ServiceException; import com.srs.common.utils.SecurityUtils; import com.srs.teacher.domain.dto.ConversationDTO; +import com.srs.web.core.config.DifyConfig; import okhttp3.*; // Spring 显式导入(不要用 *) @@ -42,61 +43,6 @@ import java.util.concurrent.CompletableFuture; @RequestMapping("/aitutor/aichat") public class AiChatController extends BaseController { -// private static final String DIFY_BASE_URL = "http://172.16.129.101:6100"; - private static final String DIFY_BASE_URL = "http://47.112.118.149:8100"; - /** - * Dify API的访问密钥 - * 用于身份验证,授权访问Dify服务 - */ -// private static final String DIFY_API_KEY = "app-BfPtBZDNBuHOS9K1PaZrxQYE"; - private static final String DIFY_API_KEY = "app-2wjqcYI9n6igHTVHdH8qXlnh"; - /** - * Dify API的URL地址 - * 用于发送聊天消息请求到Dify服务 - */ - - private static final String DIFY_API_URL = DIFY_BASE_URL+"/v1/chat-messages"; - - /** - * Dify反馈API的基础URL - * 用于提交消息反馈(点赞、点踩等) - */ - private static final String DIFY_FEEDBACK_BASE_URL = DIFY_BASE_URL+"/v1/messages"; - - /** - * Dify获取反馈API的基础URL - * 用于获取消息反馈(点赞、点踩等) - */ - private static final String DIFY_API_FEEDBACK_URL = DIFY_BASE_URL+"/v1/app/feedbacks?page="; - - /** - * Dify消息历史记录API的基础URL - * 用于获取消息历史记录 - */ - private static final String DIFY_API_HISTORY_URL = DIFY_BASE_URL+"/v1/messages"; - - /** - * Dify会话API的基础URL - * 用于获取会话列表 - */ - private static final String DIFY_CONVERSATIONS_URL = DIFY_BASE_URL+"/v1/conversations"; - - /** - * Dify文件上传API的URL地址 - * 用于上传文件到Dify服务,支持图文多模态理解 - */ - private static final String DIFY_FILES_URL = DIFY_BASE_URL+"/v1/files/upload"; - - /** - * Redis中会话ID的key前缀 - */ - private static final String CONVERSATION_ID_CACHE_PREFIX = "dify:conversation:id:"; - - /** - * Redis中会话ID的过期时间(小时) - */ - private static final int CONVERSATION_ID_CACHE_EXPIRE_HOURS = 1; - /** * HTTP客户端实例 * 配置了5分钟的读取超时时间,用于与Dify API进行通信 @@ -114,6 +60,13 @@ public class AiChatController extends BaseController { @Autowired private StringRedisTemplate stringRedisTemplate; + /** + * Dify配置类 + * 用于获取Dify的API密钥和其他配置参数 + */ + @Autowired + private DifyConfig difyConfig; + /** 为本次请求设置 “总超时”(含连接/读写),避免无限挂起 */ private Response execWithTimeouts(Request req, int callSecs, int readSecs, int writeSecs) throws IOException { OkHttpClient shortClient = client.newBuilder() @@ -254,8 +207,8 @@ public class AiChatController extends BaseController { // 构建HTTP请求 Request httpRequest = new Request.Builder() - .url(DIFY_API_URL) // 设置请求URL - .addHeader("Authorization", "Bearer " + DIFY_API_KEY) // 添加认证头 + .url(difyConfig.getApiUrl()) // 设置请求URL + .addHeader("Authorization", "Bearer " + difyConfig.getApiKey()) // 添加认证头 .addHeader("Content-Type", "application/json") // 设置内容类型 .post(body) // 设置为POST请求 .build(); @@ -385,8 +338,8 @@ public class AiChatController extends BaseController { // 调用 Dify API Request request = new Request.Builder() - .url(DIFY_FEEDBACK_BASE_URL + "/" + messageId + "/feedbacks") - .addHeader("Authorization", "Bearer " + DIFY_API_KEY) + .url(difyConfig.getFeedbackBaseUrl() + "/" + messageId + "/feedbacks") + .addHeader("Authorization", "Bearer " + difyConfig.getApiKey()) .addHeader("Content-Type", "application/json") .post(body) .build(); @@ -432,8 +385,8 @@ public class AiChatController extends BaseController { // 构建请求 Request request = new Request.Builder() - .url(DIFY_API_FEEDBACK_URL + page + "&limit=" + limitValue) - .addHeader("Authorization", "Bearer " + DIFY_API_KEY) + .url(difyConfig.getApiFeedbackUrl() + page + "&limit=" + limitValue) + .addHeader("Authorization", "Bearer " + difyConfig.getApiKey()) .addHeader("Content-Type", "application/json") .get() .build(); @@ -594,7 +547,7 @@ public class AiChatController extends BaseController { } user = user.trim(); - String cacheKey = CONVERSATION_ID_CACHE_PREFIX + user; + String cacheKey = difyConfig.getConversationCachePrefix() + user; // 从Redis中获取会话ID String conversationId = stringRedisTemplate.opsForValue().get(cacheKey); @@ -626,11 +579,11 @@ public class AiChatController extends BaseController { conversationId = conversationId.trim(); // 将用户与会话ID绑定存储到Redis中 - String cacheKey = CONVERSATION_ID_CACHE_PREFIX + user; + String cacheKey = difyConfig.getConversationCachePrefix() + user; stringRedisTemplate.opsForValue().set( cacheKey, conversationId, - Duration.ofHours(CONVERSATION_ID_CACHE_EXPIRE_HOURS)); + Duration.ofHours(difyConfig.getConversationCacheExpireHours())); } catch (Exception e) { System.out.println("绑定会话ID时发生错误: " + e.getMessage()); } @@ -642,7 +595,7 @@ public class AiChatController extends BaseController { public List getConversations(String user, String lastId, int limit, String sortBy) throws IOException { // 构建带查询参数的 URL - HttpUrl.Builder urlBuilder = HttpUrl.parse(DIFY_CONVERSATIONS_URL).newBuilder(); + HttpUrl.Builder urlBuilder = HttpUrl.parse(difyConfig.getConversationsUrl()).newBuilder(); urlBuilder.addQueryParameter("user", user); if (lastId != null && !lastId.trim().isEmpty()) { urlBuilder.addQueryParameter("last_id", lastId); @@ -653,7 +606,7 @@ public class AiChatController extends BaseController { // 构建请求 Request request = new Request.Builder() .url(urlBuilder.build()) - .addHeader("Authorization", "Bearer " + DIFY_API_KEY) + .addHeader("Authorization", "Bearer " + difyConfig.getApiKey()) .get() .build(); @@ -725,7 +678,7 @@ public class AiChatController extends BaseController { int finalLimit = limit != null && limit > 0 ? Math.min(limit, 100) : 20; // 构建请求 URL - HttpUrl.Builder urlBuilder = HttpUrl.parse(DIFY_API_HISTORY_URL).newBuilder(); + HttpUrl.Builder urlBuilder = HttpUrl.parse(difyConfig.getApiHistoryUrl()).newBuilder(); urlBuilder.addQueryParameter("conversation_id", conversationId); urlBuilder.addQueryParameter("user", user); if (firstId != null && !firstId.trim().isEmpty()) { @@ -735,7 +688,7 @@ public class AiChatController extends BaseController { Request request = new Request.Builder() .url(urlBuilder.build()) - .addHeader("Authorization", "Bearer " + DIFY_API_KEY) + .addHeader("Authorization", "Bearer " + difyConfig.getApiKey()) .addHeader("Accept", "application/json") .get() .build(); @@ -823,8 +776,8 @@ public class AiChatController extends BaseController { // 构建请求 Request request = new Request.Builder() - .url(DIFY_FILES_URL) - .addHeader("Authorization", "Bearer " + DIFY_API_KEY) + .url(difyConfig.getFilesUrl()) + .addHeader("Authorization", "Bearer " + difyConfig.getApiKey()) .post(requestBody) .build(); diff --git a/srs-admin/src/main/java/com/srs/web/core/config/DifyConfig.java b/srs-admin/src/main/java/com/srs/web/core/config/DifyConfig.java new file mode 100644 index 0000000..da6cacd --- /dev/null +++ b/srs-admin/src/main/java/com/srs/web/core/config/DifyConfig.java @@ -0,0 +1,105 @@ +package com.srs.web.core.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +@Component // 让 Spring 扫描到 +@ConfigurationProperties(prefix = "dify") +public class DifyConfig { + + /** + * Dify 服务的基础 URL,例如:http://47.112.118.149:8100 + */ + private String baseUrl; + + /** + * Dify API 密钥 + */ + private String apiKey; + + /** + * 超时时间配置(可选) + */ + private Duration timeout = Duration.ofSeconds(30); + + // ================== API URLs ================== + // 这些 URL 基于 baseUrl 自动生成,不直接暴露在配置文件中 + private String apiUrl; + private String feedbackBaseUrl; + private String apiFeedbackUrl; + private String apiHistoryUrl; + private String conversationsUrl; + private String filesUrl; + + // ================== Redis 缓存配置 ================== + private String conversationCachePrefix = "dify:conversation:id:"; + private int conversationCacheExpireHours = 1; + + // -------------------- Getters and Setters -------------------- + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public Duration getTimeout() { + return timeout; + } + + public void setTimeout(Duration timeout) { + this.timeout = timeout; + } + + public String getApiUrl() { + return baseUrl + "/v1/chat-messages"; + } + + public String getFeedbackBaseUrl() { + return baseUrl + "/v1/messages"; + } + + public String getApiFeedbackUrl() { + return baseUrl + "/v1/app/feedbacks?page="; + } + + public String getApiHistoryUrl() { + return baseUrl + "/v1/messages"; + } + + public String getConversationsUrl() { + return baseUrl + "/v1/conversations"; + } + + public String getFilesUrl() { + return baseUrl + "/v1/files/upload"; + } + + public String getConversationCachePrefix() { + return conversationCachePrefix; + } + + public void setConversationCachePrefix(String conversationCachePrefix) { + this.conversationCachePrefix = conversationCachePrefix; + } + + public int getConversationCacheExpireHours() { + return conversationCacheExpireHours; + } + + public void setConversationCacheExpireHours(int conversationCacheExpireHours) { + this.conversationCacheExpireHours = conversationCacheExpireHours; + } +} diff --git a/srs-admin/src/main/resources/application.yml b/srs-admin/src/main/resources/application.yml index e3e763e..01f0640 100644 --- a/srs-admin/src/main/resources/application.yml +++ b/srs-admin/src/main/resources/application.yml @@ -42,6 +42,11 @@ logging: com.srs: debug org.springframework: warn +#dify配置 +dify: + base-url: http://47.112.118.149:8100 #http://172.16.129.101:6100 + api-key: app-2wjqcYI9n6igHTVHdH8qXlnh #app-BfPtBZDNBuHOS9K1PaZrxQYE + # 用户配置 user: password: From d02e4ca12d550bbcab7d73673e6b89048c862c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BA=9E?= <3154396966@qq.com> Date: Thu, 21 Aug 2025 18:05:55 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E7=BB=BC=E5=90=88=E7=B4=A0=E8=B4=A8-?= =?UTF-8?q?=E7=BB=BC=E5=90=88=E7=B4=A0=E8=B4=A8=E7=94=B3=E8=AF=B7=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8=E4=BB=A3=E5=8A=9E=E5=92=8C=E5=AD=A6=E7=94=9F=E5=A5=96?= =?UTF-8?q?=E6=83=A9-=E5=85=88=E8=BF=9B=E7=8F=AD=E9=9B=86=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/disciplinary/XGLDSHListener.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XGLDSHListener.java diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XGLDSHListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XGLDSHListener.java new file mode 100644 index 0000000..30580fb --- /dev/null +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XGLDSHListener.java @@ -0,0 +1,51 @@ +package com.srs.flowable.listener.disciplinary; + +import com.srs.common.utils.WeChatUtil; +import com.srs.common.utils.spring.SpringUtils; +import com.srs.flowable.mapper.DisciplinaryMapper; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; + +import java.util.List; + +public class XGLDSHListener implements ExecutionListener { + + @Override + public void notify(DelegateExecution delegateExecution) { + DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class); + + // 固定角色 Key + final String TARGET_ROLE_KEY = "xgldsp"; + + // 步骤 1: 查询角色下的所有审批人 userId + List userIdList = disciplinaryMapper.getApprovalByRoleKey(TARGET_ROLE_KEY); + + if (userIdList == null || userIdList.isEmpty()) { + throw new RuntimeException("未找到角色 '" + TARGET_ROLE_KEY + "' 的审批人员,无法发送通知。"); + } + + try { + // 步骤 2: 查询 userName 列表 + List userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList); + + if (userNameList != null && !userNameList.isEmpty()) { + String toUser = String.join("|", userNameList); + + WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class); + + String content = "您有一条新的学生违纪审批任务待处理," + + "请点击前往处理。"; + + // 步骤 3: 发送企业微信通知 + weChatUtil.sendTextMessage(toUser, content); +// log.info("已成功向角色 '{}' 的成员发送企业微信审批通知。接收人: {}", TARGET_ROLE_KEY, toUser); + + } else { +// log.warn("角色 '{}' 下找到 {} 个用户,但无对应的企业微信账号,无法发送通知。", TARGET_ROLE_KEY, userIdList.size()); + } + + } catch (Exception e) { +// log.error("向角色 '{}' 发送企业微信通知时出现异常,但流程将继续。错误详情: {}", TARGET_ROLE_KEY, e.getMessage(), e); + } + } +} From 5ca7473d6ae7103711d87221b44c96e3b9704705 Mon Sep 17 00:00:00 2001 From: s1431_z_w <15596413+s1431zw@user.noreply.gitee.com> Date: Thu, 21 Aug 2025 18:17:24 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E9=89=B4=E5=AE=9A=E8=AF=84=E8=AF=AD?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SrsIdentifytableController.java | 11 ++++++ .../mapper/SrsIdentifytableMapper.java | 11 ++++++ .../service/ISrsIdentifytableService.java | 10 ++++++ .../impl/SrsIdentifytableServiceImpl.java | 34 +++++++++++++++---- .../comprehensive/CphGoodApplyMapper.xml | 6 ++++ .../comprehensive/SrsIdentifytableMapper.xml | 9 +++++ 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/controller/SrsIdentifytableController.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/controller/SrsIdentifytableController.java index 177c8f1..8b02515 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/controller/SrsIdentifytableController.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/controller/SrsIdentifytableController.java @@ -126,4 +126,15 @@ public class SrsIdentifytableController extends BaseController { { return toAjax(srsIdentifytableService.deleteSrsIdentifytableByIds(ids)); } + + /** + * 班级信息 + */ + @Log(title = "学生鉴定信息", businessType = BusinessType.DELETE) + @GetMapping("/deptdata") + @ApiOperation("获取对应人的班级信息") + public AjaxResult deptData() + { + return success(srsIdentifytableService.deptDataLsit()); + } } diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/SrsIdentifytableMapper.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/SrsIdentifytableMapper.java index 15ecd27..fe99489 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/SrsIdentifytableMapper.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/SrsIdentifytableMapper.java @@ -2,6 +2,8 @@ package com.srs.comprehensive.mapper; import java.util.List; +import com.srs.common.core.domain.entity.SysDept; +import com.srs.comprehensive.domain.SrsClass; import com.srs.comprehensive.domain.SrsIdentifytable; import com.baomidou.mybatisplus.core.mapper.BaseMapper; @@ -107,4 +109,13 @@ public interface SrsIdentifytableMapper extends BaseMapper { * @return 结果 */ int deleteSrsGraduataByIds(Long[] ids); + + /** + * 获取对应人的班级信息 + * + * @param userName 用户名称 + * @return 结果 + */ + List selectDeptByDeptCodes(String userName); + } diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ISrsIdentifytableService.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ISrsIdentifytableService.java index d24ce27..5d548a2 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ISrsIdentifytableService.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ISrsIdentifytableService.java @@ -3,6 +3,8 @@ package com.srs.comprehensive.service; import java.util.List; import com.baomidou.mybatisplus.extension.service.IService; +import com.srs.comprehensive.domain.CascaderEntity; +import com.srs.comprehensive.domain.SrsClass; import com.srs.comprehensive.domain.SrsIdentifytable; /** @@ -59,4 +61,12 @@ public interface ISrsIdentifytableService extends IService { * @return 结果 */ int deleteSrsIdentifytableById(Long id); + + /** + * 获取对应人的班级信息 + * + * @param + * @return 集合结果 + */ + List deptDataLsit(); } diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/SrsIdentifytableServiceImpl.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/SrsIdentifytableServiceImpl.java index 494b65a..ec86368 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/SrsIdentifytableServiceImpl.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/SrsIdentifytableServiceImpl.java @@ -1,17 +1,20 @@ package com.srs.comprehensive.service.impl; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; + +import com.srs.common.core.domain.entity.SysDept; +import com.srs.common.core.domain.model.LoginUser; import com.srs.common.utils.DateUtils; -import com.srs.comprehensive.domain.GraduateStudentNews; -import com.srs.comprehensive.domain.SaveStudent; -import com.srs.comprehensive.mapper.GraduateTextMapper; -import com.srs.comprehensive.mapper.SrsGraduateStudentMapper; +import com.srs.common.utils.SecurityUtils; +import com.srs.comprehensive.domain.*; +import com.srs.comprehensive.mapper.*; +import com.srs.comprehensive.service.ICascaderDataStudentService; import com.srs.comprehensive.util.FileUploadUtil; import org.springframework.beans.factory.annotation.Autowired; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; -import com.srs.comprehensive.mapper.SrsIdentifytableMapper; -import com.srs.comprehensive.domain.SrsIdentifytable; import com.srs.comprehensive.service.ISrsIdentifytableService; /** @@ -156,4 +159,23 @@ public class SrsIdentifytableServiceImpl extends ServiceImpl deptDataLsit() { + //获取登录人的信息 + LoginUser loginUser = SecurityUtils.getLoginUser(); + List depts = srsIdentifytableMapper.selectDeptByDeptCodes(loginUser.getUsername()); + if(depts != null && depts.size() > 0) { + return depts; + } + return new ArrayList<>(); + } + } diff --git a/srs-comprehensive/src/main/resources/mapper/comprehensive/CphGoodApplyMapper.xml b/srs-comprehensive/src/main/resources/mapper/comprehensive/CphGoodApplyMapper.xml index c17a5f6..ab54c16 100644 --- a/srs-comprehensive/src/main/resources/mapper/comprehensive/CphGoodApplyMapper.xml +++ b/srs-comprehensive/src/main/resources/mapper/comprehensive/CphGoodApplyMapper.xml @@ -781,6 +781,12 @@ from sys_performance as a where (a.shstatus IS NOT NULL and a.ksstatus IS NULL) -- 科室复核待办 or (a.ksstatus IS NOT NULL and a.xgstatus IS NULL) -- 学工处长待办 + -- 邵政文-(宿舍管理-住宿费用-辅导员确认待办) + union + select concat('zsfy-',count(a.id)) as `all` + from dms_new_record as a + left join view_dms_record as d on a.stu_no = d.stu_no + where d.employee_id = #{tNo} and a.apply_status = 6 diff --git a/srs-comprehensive/src/main/resources/mapper/comprehensive/SrsIdentifytableMapper.xml b/srs-comprehensive/src/main/resources/mapper/comprehensive/SrsIdentifytableMapper.xml index 95af267..5ce6e37 100644 --- a/srs-comprehensive/src/main/resources/mapper/comprehensive/SrsIdentifytableMapper.xml +++ b/srs-comprehensive/src/main/resources/mapper/comprehensive/SrsIdentifytableMapper.xml @@ -54,6 +54,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where id = #{id} + + + + From fc6ed00a3e569cbe0571f303cfc527b47c364190 Mon Sep 17 00:00:00 2001 From: firefly <1633489380@qq.com> Date: Fri, 22 Aug 2025 10:22:24 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E5=B0=86=E5=89=8D=E7=AB=AF=E4=BC=A0?= =?UTF-8?q?=E5=85=A5=E7=9A=84token=E6=94=B9=E6=88=90=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=BD=93=E5=89=8D=E7=94=A8=E6=88=B7=E7=9A=84?= =?UTF-8?q?token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../srs/web/controller/aitutor/AiChatController.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java index 1a1e902..d33cbff 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java @@ -117,11 +117,11 @@ public class AiChatController extends BaseController { // 在主线程中获取当前用户名,避免在异步线程中获取安全上下文 String currentUsername = SecurityUtils.getLoginUser().getUsername(); - + String currentUserToken = SecurityUtils.getLoginUser().getToken(); // 异步执行请求处理,避免阻塞主线程 CompletableFuture.runAsync(() -> { try { - sendToDifyAndStream(requestData, emitter, currentUsername); + sendToDifyAndStream(requestData, emitter, currentUsername, currentUserToken); } catch (Exception e) { e.printStackTrace(); try { @@ -147,7 +147,7 @@ public class AiChatController extends BaseController { * @param currentUsername * @throws IOException 当网络请求或IO操作失败时抛出 */ - private void sendToDifyAndStream(Map requestData, SseEmitter emitter, String currentUsername) + private void sendToDifyAndStream(Map requestData, SseEmitter emitter, String currentUsername,String currentUserToken) throws IOException { // 构建请求体参数 @@ -184,9 +184,9 @@ public class AiChatController extends BaseController { inputs.put("user_name", userName); } - Object userToken = requestData.get("user_token"); - if (userToken != null) { - inputs.put("user_token", userToken); + //Object userToken = requestData.get("user_token"); + if (currentUserToken != null) { + inputs.put("user_token", currentUserToken); } Object userRole = requestData.get("user_role"); From e221e66dfb7dc5d73f863674a0573874753803c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A6=85=E9=A5=BC?= <2815246336@qq.com> Date: Fri, 22 Aug 2025 15:00:49 +0800 Subject: [PATCH 11/14] =?UTF-8?q?1.=E4=BF=AE=E6=94=B9=E5=8F=91=E9=80=81AI?= =?UTF-8?q?=E4=BF=A1=E6=81=AFtoken=E6=B2=A1=E6=9C=89=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/aitutor/AiChatController.java | 26 ++++++++++++------- .../framework/web/service/TokenService.java | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java index d33cbff..285bc44 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java @@ -9,6 +9,8 @@ import com.srs.common.core.controller.BaseController; // OkHttp 显式导入 import com.srs.common.exception.ServiceException; import com.srs.common.utils.SecurityUtils; +import com.srs.common.utils.ServletUtils; +import com.srs.framework.web.service.TokenService; import com.srs.teacher.domain.dto.ConversationDTO; import com.srs.web.core.config.DifyConfig; import okhttp3.*; @@ -42,7 +44,8 @@ import java.util.concurrent.CompletableFuture; @RestController @RequestMapping("/aitutor/aichat") public class AiChatController extends BaseController { - + @Autowired + private TokenService tokenService; /** * HTTP客户端实例 * 配置了5分钟的读取超时时间,用于与Dify API进行通信 @@ -117,7 +120,9 @@ public class AiChatController extends BaseController { // 在主线程中获取当前用户名,避免在异步线程中获取安全上下文 String currentUsername = SecurityUtils.getLoginUser().getUsername(); - String currentUserToken = SecurityUtils.getLoginUser().getToken(); + // 获取JWT token + String currentUserToken = tokenService.getToken(ServletUtils.getRequest()); +// String currentUserToken = SecurityUtils.getLoginUser().getToken(); // 异步执行请求处理,避免阻塞主线程 CompletableFuture.runAsync(() -> { try { @@ -147,7 +152,8 @@ public class AiChatController extends BaseController { * @param currentUsername * @throws IOException 当网络请求或IO操作失败时抛出 */ - private void sendToDifyAndStream(Map requestData, SseEmitter emitter, String currentUsername,String currentUserToken) + private void sendToDifyAndStream(Map requestData, SseEmitter emitter, String currentUsername, + String currentUserToken) throws IOException { // 构建请求体参数 @@ -184,7 +190,7 @@ public class AiChatController extends BaseController { inputs.put("user_name", userName); } - //Object userToken = requestData.get("user_token"); + // Object userToken = requestData.get("user_token"); if (currentUserToken != null) { inputs.put("user_token", currentUserToken); } @@ -459,9 +465,9 @@ public class AiChatController extends BaseController { @PreAuthorize("@ss.hasPermi('cph:teacher:list')") @GetMapping("/getMessagesToAdmin") public AjaxResult getMessagesToAdmin(@RequestParam String user, - @RequestParam(required = false) String firstId, - @RequestParam(defaultValue = "20") int limit, - @RequestParam(defaultValue = "-updated_at") String sortBy) { + @RequestParam(required = false) String firstId, + @RequestParam(defaultValue = "20") int limit, + @RequestParam(defaultValue = "-updated_at") String sortBy) { try { // 首先尝试从Redis缓存中获取会话ID @@ -497,8 +503,8 @@ public class AiChatController extends BaseController { // 权限标识为学生 @GetMapping("/getMessagesToUser") public AjaxResult getMessagesToUser(@RequestParam(required = false) String firstId, - @RequestParam(defaultValue = "20") int limit, - @RequestParam(defaultValue = "-updated_at") String sortBy) { + @RequestParam(defaultValue = "20") int limit, + @RequestParam(defaultValue = "-updated_at") String sortBy) { try { String user = SecurityUtils.getLoginUser().getUsername(); @@ -561,7 +567,7 @@ public class AiChatController extends BaseController { /** * 将会话ID与用户绑定并存储到Redis中 * - * @param user 用户名 + * @param user 用户名 * @param conversationId 会话ID */ private void cacheConversationId(String user, String conversationId) { diff --git a/srs-framework/src/main/java/com/srs/framework/web/service/TokenService.java b/srs-framework/src/main/java/com/srs/framework/web/service/TokenService.java index 9b7a59a..cf5d8e9 100644 --- a/srs-framework/src/main/java/com/srs/framework/web/service/TokenService.java +++ b/srs-framework/src/main/java/com/srs/framework/web/service/TokenService.java @@ -209,7 +209,7 @@ public class TokenService * @param request * @return token */ - private String getToken(HttpServletRequest request) + public String getToken(HttpServletRequest request) { String token = request.getHeader(header); if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) From 548189707699683e64b4da487ad1e5b8fdf7a49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E6=97=A0=E6=B6=AF?= <2637171921@qq.com> Date: Fri, 22 Aug 2025 17:24:04 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=A0=E5=86=85?= =?UTF-8?q?=E9=83=A8=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5=E5=B7=A5=E5=85=B7?= =?UTF-8?q?GenericMessageListener=E6=B5=8B=E8=AF=95=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E5=BE=85=E5=AE=8C=E6=95=B4=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/srs/common/utils/WeChatUtil.java | 2 +- .../disciplinary/GenericMessageListener.java | 124 ++++++++++++++++++ .../disciplinary/XYWJCLWYHListener.java | 2 + ...StuDisciplinaryApplicationServiceImpl.java | 2 +- 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java diff --git a/srs-common/src/main/java/com/srs/common/utils/WeChatUtil.java b/srs-common/src/main/java/com/srs/common/utils/WeChatUtil.java index 7a0a42b..b94a681 100644 --- a/srs-common/src/main/java/com/srs/common/utils/WeChatUtil.java +++ b/srs-common/src/main/java/com/srs/common/utils/WeChatUtil.java @@ -157,7 +157,7 @@ public class WeChatUtil { String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken; JSONObject msg = new JSONObject(); - msg.put("touser", "2023429229"); + msg.put("touser", toUser); msg.put("msgtype", "text"); msg.put("agentid", weChatConfig.getAgentId()); diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java new file mode 100644 index 0000000..3f0ad56 --- /dev/null +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java @@ -0,0 +1,124 @@ +package com.srs.flowable.listener.disciplinary; // 您可以根据需要调整包路径 + +import com.srs.common.utils.SecurityUtils; +import com.srs.comprehensive.domain.CphMsg; +import com.srs.comprehensive.service.ICphMsgService; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +/** + * 【通用线上监听器】为即将到来的任务创建内部“我的消息”记录。 + *

+ * 该监听器被设计为在SequenceFlow的'take'事件上触发。 + * 它会智能地从流程变量中读取单个接收人(变量名: approval)或多个接收人(变量名: userList), + * 然后为每一位接收人创建一条内部消息。 + *

+ */ +@Component("genericMessageListener") // 定义一个清晰、通用的Spring Bean名称 +@Slf4j +public class GenericMessageListener implements ExecutionListener { + + @Autowired + private ICphMsgService cphMsgService; + + @Override + public void notify(DelegateExecution execution) { + log.info("流程实例 [{}]: 触发通用消息监听器 (GenericMessageListener)...", execution.getProcessInstanceId()); + + // 步骤 1: 智能地从流程变量中获取接收人ID列表 + List receiverIdList = getReceiverIds(execution); + + // 如果没有找到任何接收人,则记录日志并直接返回 + if (receiverIdList.isEmpty()) { + log.warn("流程实例 [{}]: 未能从流程变量中找到任何有效的接收人 (未能解析 'approval' 或 'userList' 变量),已跳过创建内部消息。", execution.getProcessInstanceId()); + return; + } + + // 步骤 2: 准备消息内容和发送人 + // 您可以根据业务需求,让消息内容更具动态性,比如从流程变量中获取任务标题 + String taskName = execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getName() : "新"; + String messageContent = "您有一条新的【" + taskName + "】待办任务需要处理,请点击前往处理。"; + Long senderId = getSenderId(); + + // 步骤 3: 遍历所有接收人,并为每位用户创建一条内部消息 + for (Long receiverId : receiverIdList) { + try { + CphMsg cphMsg = new CphMsg(); + cphMsg.setReceiver(receiverId); + cphMsg.setSender(senderId); + cphMsg.setContent(messageContent); + + // 调用您已有的服务插入消息 + cphMsgService.insertCphMsg(cphMsg); + log.info("已成功为用户 [{}] 创建关于任务 [{}] 的内部消息。", receiverId, taskName); + + } catch (Exception e) { + // 捕获单个用户创建失败的异常,确保不影响其他人 + log.error("为用户 [{}] 创建内部消息时发生异常: {}", receiverId, e.getMessage(), e); + } + } + } + + /** + * 智能地从流程变量中解析出接收人ID列表。 + * 策略是: + * 1. 优先检查 'userList' 变量,这通常用于多实例任务。 + * 2. 如果 'userList' 不存在或无效,则检查 'approval' 变量,这通常用于单实例任务。 + * + * @param execution 当前的执行实例 + * @return 包含一个或多个用户ID的列表,如果都找不到则返回空列表。 + */ + @SuppressWarnings("unchecked") + private List getReceiverIds(DelegateExecution execution) { + // 优先检查 'userList' (用于多实例) + Object userListObj = execution.getVariable("userList"); + if (userListObj instanceof List && !((List) userListObj).isEmpty()) { + try { + // 确保列表内容是Long类型 + return (List) userListObj; + } catch (ClassCastException e) { + log.error("流程变量 'userList' 不是 Long 类型的列表。", e); + } + } + + // 其次检查 'approval' (用于单实例) + Object approvalObj = execution.getVariable("approval"); + if (approvalObj instanceof Number) { + return Collections.singletonList(((Number) approvalObj).longValue()); + } + // 兼容字符串形式的ID + if (approvalObj instanceof String) { + try { + return Collections.singletonList(Long.parseLong((String) approvalObj)); + } catch (NumberFormatException e) { + log.warn("流程变量 'approval' 的值 '{}' 无法转换为Long类型。", approvalObj); + } + } + + // 如果都找不到,返回一个不可变的空列表 + return Collections.emptyList(); + } + + /** + * 安全地获取当前操作的发送人ID。 + * 在异步执行的监听器中,可能无法获取到安全上下文,因此提供了默认值。 + * + * @return 发送人用户ID,默认为1L (系统管理员)。 + */ + private Long getSenderId() { + try { + Long userId = SecurityUtils.getUserId(); + // 如果SecurityUtils返回null,也使用默认值 + return userId != null ? userId : 1L; + } catch (Exception e) { + log.warn("在监听器中获取发送人ID时发生异常,将使用默认系统管理员ID(1L)。异常信息: {}", e.getMessage()); + return 1L; // 默认为系统管理员 + } + } +} \ No newline at end of file diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java index 6963493..a318bed 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/XYWJCLWYHListener.java @@ -5,6 +5,7 @@ import com.srs.flowable.mapper.DisciplinaryMapper; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.ExecutionListener; +import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -14,6 +15,7 @@ import java.util.stream.Collectors; /** * 【线上监听器】为“学院违纪处理委员会”多实例任务准备数据并发送通知 知无涯 */ +@MapperScan("com.srs.flowable.mapper") @Component("xywjclwyhListener") @Slf4j public class XYWJCLWYHListener implements ExecutionListener { diff --git a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java index 89eb0f1..66c2aaa 100644 --- a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java +++ b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java @@ -265,7 +265,7 @@ public class RtStuDisciplinaryApplicationServiceImpl extends ServiceImpl Date: Mon, 25 Aug 2025 14:50:39 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- srs-admin/src/main/resources/application.yml | 2 +- .../comprehensive/mapper/CphMsgMapper.java | 8 ++ .../comprehensive/service/ICphMsgService.java | 8 ++ .../service/impl/CphMsgServiceImpl.java | 10 ++ .../mapper/comprehensive/CphMsgMapper.xml | 12 +++ .../disciplinary/GenericMessageListener.java | 36 ++++--- .../MessageProcessorListener.java | 99 +++++++++++++++++++ ...StuDisciplinaryApplicationServiceImpl.java | 2 +- 8 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/MessageProcessorListener.java diff --git a/srs-admin/src/main/resources/application.yml b/srs-admin/src/main/resources/application.yml index 01f0640..afe0801 100644 --- a/srs-admin/src/main/resources/application.yml +++ b/srs-admin/src/main/resources/application.yml @@ -21,7 +21,7 @@ srs: # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 正式:8085 测试:8088 - port: 8085 + port: 8088 servlet: # 应用的访问路径 context-path: / diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/CphMsgMapper.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/CphMsgMapper.java index a18b327..50b6399 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/CphMsgMapper.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/mapper/CphMsgMapper.java @@ -55,6 +55,14 @@ public interface CphMsgMapper extends BaseMapper */ public int deleteCphMsgById(Long id); + /** + * 根据接收人和内容中的标识来查找流程消息 (使用LIKE查询) 知无涯 + * + * @param cphMsg 包含 receiver 和 content (作为模糊查询的标识) 的查询对象 + * @return 匹配的消息列表 + */ + public List selectCphMsgListForFlowable(CphMsg cphMsg); + /** * 批量删除消息 * diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ICphMsgService.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ICphMsgService.java index 6d9cf84..eae412d 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ICphMsgService.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/ICphMsgService.java @@ -59,6 +59,14 @@ public interface ICphMsgService */ public int deleteCphMsgById(Long id); + /** + * 删除消息信息 精准匹配版 + * + * @param cphMsg 消息 + * @return 列表 + */ + List selectCphMsgListForFlowable(CphMsg cphMsg); + /** * 根据学号查询用户ID * diff --git a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/CphMsgServiceImpl.java b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/CphMsgServiceImpl.java index d3a13e0..a739eb0 100644 --- a/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/CphMsgServiceImpl.java +++ b/srs-comprehensive/src/main/java/com/srs/comprehensive/service/impl/CphMsgServiceImpl.java @@ -95,6 +95,16 @@ public class CphMsgServiceImpl extends ServiceImpl implemen { return cphMsgMapper.deleteCphMsgById(id); } + /** + * 删除消息信息 + * + * @param cphMsg 消息 + * @return 结果 + */ + @Override + public List selectCphMsgListForFlowable(CphMsg cphMsg) { + return cphMsgMapper.selectCphMsgListForFlowable(cphMsg); + } /** * 根据学号查询用户ID diff --git a/srs-comprehensive/src/main/resources/mapper/comprehensive/CphMsgMapper.xml b/srs-comprehensive/src/main/resources/mapper/comprehensive/CphMsgMapper.xml index 8c6b99e..6ea5ee4 100644 --- a/srs-comprehensive/src/main/resources/mapper/comprehensive/CphMsgMapper.xml +++ b/srs-comprehensive/src/main/resources/mapper/comprehensive/CphMsgMapper.xml @@ -84,4 +84,16 @@ + + + diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java index 3f0ad56..50c1305 100644 --- a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/GenericMessageListener.java @@ -13,14 +13,14 @@ import java.util.Collections; import java.util.List; /** - * 【通用线上监听器】为即将到来的任务创建内部“我的消息”记录。 + * 【通用线上监听器】为即将到来的任务创建内部“我的消息”记录。 知无涯1 *

* 该监听器被设计为在SequenceFlow的'take'事件上触发。 * 它会智能地从流程变量中读取单个接收人(变量名: approval)或多个接收人(变量名: userList), * 然后为每一位接收人创建一条内部消息。 *

*/ -@Component("genericMessageListener") // 定义一个清晰、通用的Spring Bean名称 +@Component("genericMessageListener") @Slf4j public class GenericMessageListener implements ExecutionListener { @@ -29,37 +29,41 @@ public class GenericMessageListener implements ExecutionListener { @Override public void notify(DelegateExecution execution) { - log.info("流程实例 [{}]: 触发通用消息监听器 (GenericMessageListener)...", execution.getProcessInstanceId()); + log.info("流程实例 [{}]: 触发通用消息监听器...", execution.getProcessInstanceId()); - // 步骤 1: 智能地从流程变量中获取接收人ID列表 List receiverIdList = getReceiverIds(execution); - - // 如果没有找到任何接收人,则记录日志并直接返回 if (receiverIdList.isEmpty()) { - log.warn("流程实例 [{}]: 未能从流程变量中找到任何有效的接收人 (未能解析 'approval' 或 'userList' 变量),已跳过创建内部消息。", execution.getProcessInstanceId()); return; } - // 步骤 2: 准备消息内容和发送人 - // 您可以根据业务需求,让消息内容更具动态性,比如从流程变量中获取任务标题 + // --- 关键改动:获取下一个即将创建的任务ID --- + // 注意:在线上监听器中,任务尚未创建,所以我们无法直接获取任务ID。 + // 但我们可以获取到这个“活动”的定义ID,它在流程定义中是唯一的。 + String activityId = execution.getCurrentActivityId(); + String taskName = execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getName() : "新"; - String messageContent = "您有一条新的【" + taskName + "】待办任务需要处理,请点击前往处理。"; + + // --- 关键改动:构建带有隐藏标识的消息内容 --- + String messageText = "您有一条新的【" + taskName + "】待办任务需要处理,"; + // 我们嵌入一个隐藏的span,它包含了流程实例ID和活动ID作为唯一标识 + String hiddenIdentifier = String.format("", + execution.getProcessInstanceId(), + activityId); + + String finalContent = messageText + hiddenIdentifier; + Long senderId = getSenderId(); - // 步骤 3: 遍历所有接收人,并为每位用户创建一条内部消息 for (Long receiverId : receiverIdList) { try { CphMsg cphMsg = new CphMsg(); cphMsg.setReceiver(receiverId); cphMsg.setSender(senderId); - cphMsg.setContent(messageContent); + cphMsg.setContent(finalContent); // 使用包含隐藏标识的内容 - // 调用您已有的服务插入消息 cphMsgService.insertCphMsg(cphMsg); - log.info("已成功为用户 [{}] 创建关于任务 [{}] 的内部消息。", receiverId, taskName); - + log.info("已成功为用户 [{}] 创建内部消息 (关联 Activity ID: {})。", receiverId, activityId); } catch (Exception e) { - // 捕获单个用户创建失败的异常,确保不影响其他人 log.error("为用户 [{}] 创建内部消息时发生异常: {}", receiverId, e.getMessage(), e); } } diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/MessageProcessorListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/MessageProcessorListener.java new file mode 100644 index 0000000..4ebd9c7 --- /dev/null +++ b/srs-flowable/src/main/java/com/srs/flowable/listener/disciplinary/MessageProcessorListener.java @@ -0,0 +1,99 @@ +package com.srs.flowable.listener.disciplinary; // 您可以根据需要调整包路径 + +import com.srs.comprehensive.domain.CphMsg; +import com.srs.comprehensive.service.ICphMsgService; +import lombok.extern.slf4j.Slf4j; +import org.flowable.task.service.delegate.DelegateTask; +import org.flowable.task.service.delegate.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import javax.annotation.PostConstruct; +import java.util.List; + +/** + * 【任务监听器】在任务完成后,删除内部消息。 + *

+ * 该监听器被设计为在UserTask的'complete'事件上触发。 + * 它通过解析消息内容中的隐藏HTML标识来找到与当前已完成任务关联的消息, + * 并将其删除。 + *

+ */ +@Component("messageProcessorListener") // 定义一个清晰的Bean名称 +@Slf4j +public class MessageProcessorListener implements TaskListener { + + @Autowired + private ICphMsgService cphMsgService; + + /** + * 依赖检查方法,确保关键服务已注入。 + */ + @PostConstruct + public void checkDependencies() { + Assert.notNull(cphMsgService, "ICphMsgService dependency not injected for MessageProcessorListener!"); + } + + @Override + public void notify(DelegateTask delegateTask) { + // 步骤 1: 获取当前任务的办理人ID + String assigneeIdStr = delegateTask.getAssignee(); + if (assigneeIdStr == null || assigneeIdStr.isEmpty()) { + log.warn("任务 [ID: {}] 没有办理人,无法处理消息。", delegateTask.getId()); + return; + } + Long receiverId; + try { + receiverId = Long.parseLong(assigneeIdStr); + } catch (NumberFormatException e) { + log.error("任务办理人ID '{}' 无法转换为Long类型。", assigneeIdStr); + return; + } + + // 步骤 2: 获取用于查找消息的唯一标识 + String processInstanceId = delegateTask.getProcessInstanceId(); + // taskDefinitionKey 对应流程图中节点的ID,即我之前在 GenericMessageListener 中存入的 activityId + String activityId = delegateTask.getTaskDefinitionKey(); + + log.info("任务 [ID: {}, Name: {}] (办理人: {}) 已完成。开始查找并处理关联的内部消息...", + delegateTask.getId(), delegateTask.getName(), receiverId); + log.debug("用于查找的关联标识 -> ProcInst ID: [{}], Activity ID: [{}]", processInstanceId, activityId); + + try { + // 步骤 3: 构造用于模糊查询的、唯一的标识字符串 + // 这个字符串必须与 GenericMessageListener 中生成该标识的逻辑完全一致 + String searchIdentifier = String.format("data-proc-inst-id='%s' data-activity-id='%s'", + processInstanceId, + activityId); + + // 步骤 4: 创建查询参数并调用服务 + CphMsg queryParam = new CphMsg(); + queryParam.setReceiver(receiverId); + queryParam.setContent(searchIdentifier); // 将标识作为模糊查询的内容 + + // 注意:这一步要求 CphMsgMapper.xml 中的 selectCphMsgListForFlowable 方法支持对 content 字段的 LIKE 查询 + List messagesToProcess = cphMsgService.selectCphMsgListForFlowable(queryParam); + + if (messagesToProcess.isEmpty()) { + log.info("未找到需要为用户 [{}] 处理的、与当前任务关联的消息。", receiverId); + return; + } + + // 步骤 5: 遍历所有找到的消息,并进行处理(删除) + for (CphMsg msg : messagesToProcess) { + try { + cphMsgService.deleteCphMsgById(msg.getId()); + log.info("已成功删除与任务关联的消息 [ID: {}]。", msg.getId()); + } catch (Exception e) { + // 捕获单个消息删除失败的异常,确保不影响其他消息的处理 + log.error("删除消息 [ID: {}] 时发生异常: {}", msg.getId(), e.getMessage(), e); + } + } + + } catch (Exception e) { + // 捕获整个处理过程中的异常,确保不影响主流程的流转 + log.error("处理用户 [{}] 的内部消息时发生严重异常: {}", receiverId, e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java index 66c2aaa..95679a7 100644 --- a/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java +++ b/srs-routine/src/main/java/com/srs/routine/service/impl/RtStuDisciplinaryApplicationServiceImpl.java @@ -265,7 +265,7 @@ public class RtStuDisciplinaryApplicationServiceImpl extends ServiceImpl Date: Tue, 26 Aug 2025 09:09:46 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E4=B8=80=E7=BA=A7=E9=A3=8E=E9=99=A9?= =?UTF-8?q?=E6=89=8D=E5=8F=91=E9=80=81=E8=BE=85=E5=AF=BC=E5=91=98=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=EF=BC=8C=E5=B9=B6=E4=B8=94=E5=8F=91=E9=80=81=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D=E6=B6=88=E6=81=AF=E6=96=B0=E5=A2=9E=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/srs/web/controller/aitutor/AiChatController.java | 5 +++++ .../web/controller/common/WeChatMentalAlertController.java | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java index 285bc44..4452dbc 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java @@ -200,6 +200,11 @@ public class AiChatController extends BaseController { inputs.put("user_role", userRole); } + Object userPlatform = requestData.get("user_platform"); + if (userPlatform != null) { + inputs.put("user_platform", userPlatform); + } + bodyMap.put("inputs", inputs); // 自动为对话生成名称 diff --git a/srs-admin/src/main/java/com/srs/web/controller/common/WeChatMentalAlertController.java b/srs-admin/src/main/java/com/srs/web/controller/common/WeChatMentalAlertController.java index f7e6e35..774b72f 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/common/WeChatMentalAlertController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/common/WeChatMentalAlertController.java @@ -73,6 +73,11 @@ public class WeChatMentalAlertController extends BaseController { record.setRating(request.getRating()); studentMentalRatingMapper.insert(record); + // 只有评级为"一级风险"时才发送企业微信通知 陈冠元 + if (!"一级风险".equals(request.getRating())) { + return AjaxResult.success("预警已记录,因评级非一级风险未发送通知"); + } + // === 判断是否超过当日发送上限(3次)=== 陈冠元 if (todayCount > 3) { return AjaxResult.success("预警已记录,因当日已达上限未发送通知"); @@ -97,7 +102,7 @@ public class WeChatMentalAlertController extends BaseController { ? teacher.getNickName() : teacher.getUserName(); return String.format( - "【心理预警通知】\n" + + "【智水AI心理预警通知】\n" + "辅导员:%s(%s)\n" + "学生姓名:%s\n" + "学号:%s\n" +