From ed527bae283588de0a9848390348e93c3820fef9 Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期一, 20 四月 2026 17:07:49 +0800
Subject: [PATCH] feat:通知功能完善

---
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthCourseAppService.java |   66 ++++++++++++++++++++++++++++++++
 1 files changed, 65 insertions(+), 1 deletions(-)

diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthCourseAppService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthCourseAppService.java
index a878260..743ff41 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthCourseAppService.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthCourseAppService.java
@@ -4,19 +4,26 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.tcm.training.admin.app.notice.service.AppSystemNoticeDispatchCommand;
+import com.tcm.training.admin.app.notice.service.AppSystemNoticeDispatchService;
+import com.tcm.training.admin.app.notice.service.AppSystemNoticeType;
 import com.tcm.training.admin.common.Jsons;
 import com.tcm.training.admin.common.PageResponse;
 import com.tcm.training.admin.live.dto.HealthCourseSaveRequest;
 import com.tcm.training.admin.live.dto.HealthCourseStatusRequest;
 import com.tcm.training.admin.live.dto.HealthCourseVideoSaveRequest;
 import com.tcm.training.admin.live.entity.Expert;
+import com.tcm.training.admin.live.entity.CoursePurchaseOrder;
 import com.tcm.training.admin.live.entity.HealthCourse;
+import com.tcm.training.admin.live.entity.HealthCourseMemberJoinRecord;
 import com.tcm.training.admin.live.entity.HealthCourseVideo;
 import com.tcm.training.admin.live.entity.LiveCourseCategory;
 import com.tcm.training.admin.live.excel.HealthCourseExportRow;
 import com.tcm.training.admin.live.excel.HealthCourseVideoImportRow;
 import com.tcm.training.admin.live.mapper.ExpertMapper;
 import com.tcm.training.admin.live.mapper.HealthCourseMapper;
+import com.tcm.training.admin.live.mapper.CoursePurchaseOrderMapper;
+import com.tcm.training.admin.live.mapper.HealthCourseMemberJoinRecordMapper;
 import com.tcm.training.admin.live.mapper.HealthCourseVideoMapper;
 import com.tcm.training.admin.live.mapper.LiveCourseCategoryMapper;
 import com.tcm.training.admin.live.vo.ExpertVO;
@@ -53,15 +60,24 @@
     private final HealthCourseVideoMapper healthCourseVideoMapper;
     private final LiveCourseCategoryMapper liveCourseCategoryMapper;
     private final ExpertMapper expertMapper;
+    private final CoursePurchaseOrderMapper coursePurchaseOrderMapper;
+    private final HealthCourseMemberJoinRecordMapper healthCourseMemberJoinRecordMapper;
+    private final AppSystemNoticeDispatchService appSystemNoticeDispatchService;
 
     public HealthCourseAppService(HealthCourseMapper healthCourseMapper,
                                   HealthCourseVideoMapper healthCourseVideoMapper,
                                   LiveCourseCategoryMapper liveCourseCategoryMapper,
-                                  ExpertMapper expertMapper) {
+                                  ExpertMapper expertMapper,
+                                  CoursePurchaseOrderMapper coursePurchaseOrderMapper,
+                                  HealthCourseMemberJoinRecordMapper healthCourseMemberJoinRecordMapper,
+                                  AppSystemNoticeDispatchService appSystemNoticeDispatchService) {
         this.healthCourseMapper = healthCourseMapper;
         this.healthCourseVideoMapper = healthCourseVideoMapper;
         this.liveCourseCategoryMapper = liveCourseCategoryMapper;
         this.expertMapper = expertMapper;
+        this.coursePurchaseOrderMapper = coursePurchaseOrderMapper;
+        this.healthCourseMemberJoinRecordMapper = healthCourseMemberJoinRecordMapper;
+        this.appSystemNoticeDispatchService = appSystemNoticeDispatchService;
     }
 
     public PageResponse<HealthCourseListItemVO> page(int page,
@@ -297,6 +313,7 @@
         next.setDeleted(0);
         healthCourseVideoMapper.insert(next);
         refreshCourseStats(courseId);
+        dispatchCourseUpdateNotice(courseId, next);
         return detailVideoResource(next.getId());
     }
 
@@ -380,6 +397,7 @@
             video.setDeleted(0);
             healthCourseVideoMapper.insert(video);
             touchedCourseIds.add(course.getId());
+            dispatchCourseUpdateNotice(course.getId(), video);
         }
         if (touchedCourseIds.isEmpty()) {
             throw new IllegalArgumentException("导入文件没有可用数据");
@@ -500,6 +518,52 @@
         healthCourseMapper.updateById(course);
     }
 
+    /**
+     * 在课程新增章节后通知已购课或已加入学习的用户。
+     */
+    private void dispatchCourseUpdateNotice(Long courseId, HealthCourseVideo video) {
+        if (courseId == null || video == null || video.getId() == null) {
+            return;
+        }
+        HealthCourse course = requireCourse(courseId);
+        Set<Long> appUserIds = new LinkedHashSet<Long>();
+        List<CoursePurchaseOrder> orders = coursePurchaseOrderMapper.selectList(new LambdaQueryWrapper<CoursePurchaseOrder>()
+                .eq(CoursePurchaseOrder::getDeleted, 0)
+                .eq(CoursePurchaseOrder::getStatus, "PAID")
+                .eq(CoursePurchaseOrder::getCourseId, courseId));
+        for (CoursePurchaseOrder order : orders) {
+            if (order.getAppUserId() != null) {
+                appUserIds.add(order.getAppUserId());
+            }
+        }
+        List<HealthCourseMemberJoinRecord> joinRecords = healthCourseMemberJoinRecordMapper.selectList(new LambdaQueryWrapper<HealthCourseMemberJoinRecord>()
+                .eq(HealthCourseMemberJoinRecord::getDeleted, 0)
+                .eq(HealthCourseMemberJoinRecord::getCourseId, courseId));
+        for (HealthCourseMemberJoinRecord joinRecord : joinRecords) {
+            if (joinRecord.getAppUserId() != null) {
+                appUserIds.add(joinRecord.getAppUserId());
+            }
+        }
+        for (Long appUserId : appUserIds) {
+            AppSystemNoticeDispatchCommand command = new AppSystemNoticeDispatchCommand();
+            command.setAppUserId(appUserId);
+            command.setNoticeTypeCode(AppSystemNoticeType.COURSE_UPDATE_NOTICE);
+            command.setTitle("课程更新通知");
+            command.setContent(course.getTitle() + " 已更新新章节");
+            // 使用章节主键作为引用,保证同一章节对同一用户只发一次。
+            command.setReferenceType("HEALTH_COURSE_VIDEO");
+            command.setReferenceId(video.getId());
+            command.setRequireUserSetting(Boolean.TRUE);
+            Map<String, String> payload = new LinkedHashMap<String, String>();
+            payload.put("courseId", String.valueOf(courseId));
+            payload.put("courseTitle", course.getTitle());
+            payload.put("videoId", String.valueOf(video.getId()));
+            payload.put("chapterName", defaultText(video.getChapterName()));
+            command.setPayload(payload);
+            appSystemNoticeDispatchService.createAndPush(command);
+        }
+    }
+
     private HealthCourse requireCourse(Long id) {
         HealthCourse course = healthCourseMapper.selectById(id);
         if (course == null) {

--
Gitblit v1.7.1