zjk
2026-09-29 54dcf0a82e7490fa58b1c056d5c0b9cb739c2931
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/LiveCourseAppService.java
@@ -27,6 +27,7 @@
import org.springframework.stereotype.Service;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import com.tcm.training.admin.common.enums.EnabledStatusEnum;
import java.util.ArrayList;
import java.util.List;
@@ -35,25 +36,30 @@
public class LiveCourseAppService {
    private static final int LIVE_ROOM_PASSWORD_TYPE = 1;
    private static final int PROJECT_INTRODUCTION_PASSWORD_TYPE = 2;
    private final LiveCourseMapper liveCourseMapper;
    private final ExpertMapper expertMapper;
    private final LiveSessionMapper liveSessionMapper;
    private final LiveSessionQuestionMapper liveSessionQuestionMapper;
    private final BCryptPasswordEncoder passwordEncoder;
    private final ProjectIntroductionPasswordService projectIntroductionPasswordService;
    public LiveCourseAppService(LiveCourseMapper liveCourseMapper,
                                ExpertMapper expertMapper,
                                LiveSessionMapper liveSessionMapper,
                                LiveSessionQuestionMapper liveSessionQuestionMapper,
                                BCryptPasswordEncoder passwordEncoder) {
                                BCryptPasswordEncoder passwordEncoder,
                                ProjectIntroductionPasswordService projectIntroductionPasswordService) {
        this.liveCourseMapper = liveCourseMapper;
        this.expertMapper = expertMapper;
        this.liveSessionMapper = liveSessionMapper;
        this.liveSessionQuestionMapper = liveSessionQuestionMapper;
        this.passwordEncoder = passwordEncoder;
        this.projectIntroductionPasswordService = projectIntroductionPasswordService;
    }
    /** 分页查询直播课程。 */
    public PageResponse<LiveCourseListItemVO> page(int page, int pageSize, String keyword, Long expertId, Integer status, Integer liveStatus) {
        IPage<LiveCourseListRow> p = liveCourseMapper.selectCoursePage(new Page<LiveCourseListRow>(page, pageSize),
                keyword, expertId, status, liveStatus);
@@ -79,7 +85,8 @@
        return PageResponse.of(list, p.getTotal(), p.getCurrent(), p.getSize());
    }
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    /** 创建直播课程。 */
    public LiveCourseDetailVO create(LiveCourseUpsertRequest req) {
        throw new IllegalArgumentException("直播课程为初始化数据,禁止新增");
        /*
@@ -102,6 +109,7 @@
        */
    }
    /** 查询直播课程详情。 */
    public LiveCourseDetailVO detail(Long id) {
        LiveCourseDetailRow row = liveCourseMapper.selectCourseDetail(id);
        if (row == null) {
@@ -130,7 +138,8 @@
        return vo;
    }
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    /** 更新直播课程。 */
    public LiveCourseDetailVO update(Long id, LiveCourseUpsertRequest req) {
        validateExpert(req.getExpertId());
@@ -154,7 +163,8 @@
        return detail(id);
    }
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    /** 修改直播课程状态。 */
    public LiveCourseStatusVO patchStatus(Long id, LiveCourseStatusRequest req) {
        LiveCourse course = liveCourseMapper.selectById(id);
        if (course == null) {
@@ -165,7 +175,8 @@
        return new LiveCourseStatusVO(id, req.getStatus());
    }
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    /** 更新直播课程密码。 */
    public void updatePassword(Long id, LiveCoursePasswordRequest req) {
        String password = req.getPassword();
        if (StrUtil.isNotBlank(password)) {
@@ -185,21 +196,28 @@
        liveCourseMapper.updatePasswordById(id, course.getPassword());
    }
    /** 校验直播课程访问密码。 */
    public boolean verifyPassword(LiveCoursePasswordVerifyRequest req) {
        if (req.getType() != LIVE_ROOM_PASSWORD_TYPE) {
        if (req.getType() == LIVE_ROOM_PASSWORD_TYPE) {
            // 直播间密码验证
            LiveCourse course = liveCourseMapper.selectOne(new LambdaQueryWrapper<LiveCourse>()
                    .isNotNull(LiveCourse::getPassword)
                    .orderByAsc(LiveCourse::getId)
                    .last("limit 1"));
            return course != null
                    && course.getPassword() != null
                    && !course.getPassword().isEmpty()
                    && passwordEncoder.matches(req.getPassword(), course.getPassword());
        } else if (req.getType() == PROJECT_INTRODUCTION_PASSWORD_TYPE) {
            // 项目介绍密码验证
            return projectIntroductionPasswordService.verifyPassword(req.getPassword());
        } else {
            throw new IllegalArgumentException("不支持的密码类型");
        }
        LiveCourse course = liveCourseMapper.selectOne(new LambdaQueryWrapper<LiveCourse>()
                .isNotNull(LiveCourse::getPassword)
                .orderByAsc(LiveCourse::getId)
                .last("limit 1"));
        return course != null
                && course.getPassword() != null
                && !course.getPassword().isEmpty()
                && passwordEncoder.matches(req.getPassword(), course.getPassword());
    }
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    /** 删除直播课程。 */
    public void delete(Long id) {
        throw new IllegalArgumentException("直播课程为初始化数据,禁止删除");
    }
@@ -209,7 +227,7 @@
        if (expert == null) {
            throw new IllegalArgumentException("授课专家不存在");
        }
        if (expert.getStatus() != null && expert.getStatus() != 1) {
        if (expert.getStatus() != null && expert.getStatus() != EnabledStatusEnum.ENABLED.getValue()) {
            throw new IllegalArgumentException("授课专家已禁用");
        }
    }