package com.syzb.course.service; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.hazelcast.map.IMap; import com.syzb.advisor.entity.AdvisorBasic; import com.syzb.advisor.service.AdvisorInfoService; import com.syzb.common.config.cache.CacheKey; import com.syzb.common.constant.IsDisplay; import com.syzb.common.constant.IsRecommend; import com.syzb.common.handler.BizException; import com.syzb.common.query.OnlyIdQuery; import com.syzb.common.result.AppPager; import com.syzb.common.result.Pager; import com.syzb.common.result.ResponseStatus; import com.syzb.common.service.AppUserService; import com.syzb.common.service.CacheService; import com.syzb.common.service.SensitiveWordService; import com.syzb.common.state.StateMachine; import com.syzb.common.vo.BackendUserVO; import com.syzb.common.vo.FrontUserVO; import com.syzb.common.vo.InsertIdVO; import com.syzb.course.constant.*; import com.syzb.course.entity.CoursePackage; import com.syzb.course.entity.CoursePackageContent; import com.syzb.course.entity.CourseSortEntity; import com.syzb.course.mapper.CoursePackageContentMapper; import com.syzb.course.mapper.CoursePackageMapper; import com.syzb.course.query.*; import com.syzb.course.vo.CoursePackageContentVO; import com.syzb.course.vo.CoursePackageVO; import com.syzb.course.vo.CourseVO; import com.syzb.course.vo.SerialVO; import com.syzb.rbac.entity.UserDept; import com.syzb.rbac.service.AuthService; import com.syzb.rbac.service.UserService; import com.syzb.video.constant.VideoUserType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; // 课程Service @Service public class CoursePackageService { @Resource private CoursePackageMapper coursePackageMapper; @Resource private SensitiveWordService sensitiveWordService; @Resource private StateMachine coursePackageSM; @Resource private AdvisorInfoService advisorInfoService; @Resource private UserService userService; @Resource private CoursePackageContentMapper coursePackageContentMapper; @Resource private SerialService serialService; @Resource private CourseService courseService; @Resource private CacheService cacheService; @Resource private AuthService authService; @Resource private PageService pageService; @Resource private CourseCommonService courseCommonService; @Resource private AppUserService appUserService; @Resource private IMap courseCache; /** * 保存课程 * * @param query 保存课程参数 * @param backendUserVO 后台用户 * @return 课程ID */ @Transactional(rollbackFor = Exception.class) public InsertIdVO save(SaveCoursePackageQuery query, BackendUserVO backendUserVO) { sensitiveWordService.check(query.getName(), query.getRemark()); Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); CoursePackage coursePackage = query.toPO(backendUserVO, advisorId); coursePackageMapper.insert(coursePackage); return new InsertIdVO(coursePackage.getId()); } /** * 更新课程 * * @param query 更新课程参数 * @param backendUserVO 后台用户 */ @Transactional(rollbackFor = Exception.class) public void update(UpdateCoursePackageQuery query, BackendUserVO backendUserVO) { sensitiveWordService.check(query.getName(), query.getRemark()); CoursePackage coursePackageInDB = coursePackageMapper.selectById(query.getId()); if (coursePackageInDB == null) { throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); } // 状态机扭转,判断是否能够编辑 CoursePackageStatus dbStatus = CoursePackageStatus.fromValue(coursePackageInDB.getStatus()); coursePackageSM.send(dbStatus, CoursePackageStatus.EVENT_UPDATE); CoursePackage coursePackage = query.toPO(backendUserVO); coursePackageMapper.updateById(coursePackage); clearCache(query.getId()); } /** * 更新课程状态 * * @param query 更新课程状态参数 * @param backendUserVO 后台用户 */ @Transactional(rollbackFor = Exception.class) public void updateStatus(UpdateCoursePackageStatusQuery query, BackendUserVO backendUserVO) { CoursePackage coursePackageInDB = coursePackageMapper.selectById(query.getId()); if (coursePackageInDB == null) { throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); } // 状态机扭转 CoursePackageStatus dbStatus = CoursePackageStatus.fromValue(coursePackageInDB.getStatus()); CoursePackageStatus targetStatus = coursePackageSM.send(dbStatus, CoursePackageStatus.fromValue(query.getEvent())); CoursePackage coursePackage = query.toPO(targetStatus, backendUserVO); coursePackageMapper.updateById(coursePackage); clearCache(query.getId()); } /** * 查询课程列表 * * @param query 查询参数 * @param backendUserVO 后台用户 * @return 课程列表 */ public Pager list(ListCoursePackageQuery query, BackendUserVO backendUserVO) { String name = query.getName(); Integer status = query.getStatus(); Integer userType = query.getUserType(); Integer contentType = query.getContentType(); Integer contentId = query.getContentId(); Integer advisorId = query.getAdvisorId(); Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); if (authSet != null && authSet.isEmpty()) { return null; } LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .in(CollUtil.isNotEmpty(authSet), CoursePackage::getAdvisorId, authSet) .eq(advisorId != null && advisorId != 0, CoursePackage::getAdvisorId, advisorId) .like(StrUtil.isNotEmpty(name), CoursePackage::getName, name) .eq(status != null && status != 0, CoursePackage::getStatus, status) .exists(contentType != null && contentId != null, "select 0 from course_package_content where course_package_content.course_package_id = course_package.id and course_package_content.type = {0} and course_package_content.content_id = {1}", contentType, contentId) .ne(!VideoUserType.MANAGER_USER.value.equals(userType), CoursePackage::getStatus, CoursePackageStatus.DELETED.value) .orderByDesc(CoursePackage::getId); Page page = coursePackageMapper.selectPage(query.toPage(), wrapper); Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); Map userNameMap = userService.getUserMap().values().stream() .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); List list = page.getRecords().stream().map(coursePackage -> new CoursePackageVO( coursePackage, advisorNameMap.get(coursePackage.getAdvisorId()), userNameMap.get(coursePackage.getCreateUserId()), userNameMap.get(coursePackage.getAuditUserId()), pageService.getForApp(coursePackage.getPageId()), getContentCount(coursePackage.getId()) )).collect(Collectors.toList()); return new Pager<>(list, page.getTotal()); } /** * 查询课程详情 * * @param query 查询参数 * @param backendUserVO 后台用户 * @return 课程详情 */ public CoursePackageVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { Integer id = query.getId(); CoursePackage coursePackage = getEntity(id, backendUserVO); if (coursePackage == null) { return null; } Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); Map userNameMap = userService.getUserMap().values().stream() .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); return new CoursePackageVO( coursePackage, advisorNameMap.get(coursePackage.getAdvisorId()), userNameMap.get(coursePackage.getCreateUserId()), userNameMap.get(coursePackage.getAuditUserId()), coursePackage.getPageId() == null ? null : pageService.get(new OnlyIdQuery(coursePackage.getPageId()), null), getContentCount(id)); } /** * 查询课程内容列表 * * @param query 查询参数 * @param backendUserVO 后台用户 */ public Pager listContent(ListCoursePackageContentQuery query, BackendUserVO backendUserVO) { // 不使用返回值,仅校验课程是否存在以及数据权限 if (getEntity(query.getCoursePackageId(), backendUserVO) == null) { throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); } Integer type = query.getType(); LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .eq(CoursePackageContent::getCoursePackageId, query.getCoursePackageId()) .eq(type != null && type != 0, CoursePackageContent::getType, type) .orderByDesc(CoursePackageContent::getIsRecommend, CoursePackageContent::getCreateTime); Page page = coursePackageContentMapper.selectPage(query.toPage(), wrapper); List list = page.getRecords().stream().map(content -> { if (CoursePackageContentType.SERIAL.value.equals(content.getType())) { SerialVO serial = serialService.get(new OnlyIdQuery(content.getContentId()), null); return new CoursePackageContentVO(content, serial); } else if (CoursePackageContentType.COURSE.value.equals(content.getType())) { CourseVO course = courseService.get(new OnlyIdQuery(content.getContentId()), null); return new CoursePackageContentVO(content, course); } return null; }).filter(Objects::nonNull).collect(Collectors.toList()); return new Pager<>(list, page.getTotal()); } /** * 更新课程内容 * * @param query 更新课程内容参数 * @param backendUserVO 后台用户 */ @Transactional(rollbackFor = Exception.class) public void updateContent(UpdateCoursePackageContentQuery query, BackendUserVO backendUserVO) { // 不使用返回值,仅校验课程是否存在以及数据权限 if (getEntity(query.getCoursePackageId(), backendUserVO) == null) { throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); } // 构造查询条件 LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .eq(CoursePackageContent::getCoursePackageId, query.getCoursePackageId()) .eq(CoursePackageContent::getType, query.getType()) .eq(CoursePackageContent::getContentId, query.getContentId()); UpdateContentEvent event = UpdateContentEvent.fromValue(query.getEvent()); switch (event) { case SAVE: saveContentList(query.getCoursePackageId(), query.getType(), query.toContentListPO(), event); break; case RECOMMEND: if (query.getIsRecommend() == null || IsRecommend.NO.value.equals(query.getIsRecommend())) { throw new BizException(ResponseStatus.PARM_ERROR, "权重值错误"); } CoursePackageContent recommendContent = new CoursePackageContent(); recommendContent.setIsRecommend(query.getIsRecommend()); coursePackageContentMapper.update(recommendContent, wrapper); break; case UN_RECOMMEND: CoursePackageContent unRecommendContent = new CoursePackageContent(); unRecommendContent.setIsRecommend(IsRecommend.NO.value); coursePackageContentMapper.update(unRecommendContent, wrapper); break; case ADD: saveContentList(query.getCoursePackageId(), query.getType(), query.toContentListPO(), event); break; case DELETE: saveContentList(query.getCoursePackageId(), query.getType(), Collections.singletonList(query.toContentPO()), event); break; } clearCache(query.getCoursePackageId()); } /** * APP端查询课程详情 * * @param query 查询参数 * @param frontUserVO 前台用户 * @return 课程详情 */ public CoursePackageVO getForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { CoursePackageVO vo = cacheService.get(courseCache, CacheKey.CourseKey.COURSE_PACKAGE + query.getId(), () -> get(query, null)); if (vo == null) { return null; } // 防止落地页修改后,未更新缓存 if (vo.getPage() != null) { vo.setPage(pageService.getForApp(vo.getPage().getId())); } if (frontUserVO != null) { vo.setAuthResult(appUserService.checkAuth(vo.getAuthorityId(), frontUserVO)); } return vo; } /** * APP端查询课程内容列表 * * @param query 查询参数 * @param frontUserVO 前台用户 * @return 课程内容列表 */ public List listContentForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { if (frontUserVO != null) { CoursePackageVO vo = getForApp(query, frontUserVO); if (vo == null) { throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); } if (vo.getAuthResult() != null && !vo.getAuthResult().getAuth()) { throw new BizException(ResponseStatus.NOT_PRODUCT_AUTH); } } return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.COURSE_PACKAGE_CONTENT + query.getId(), () -> { ListCoursePackageContentQuery contentQuery = new ListCoursePackageContentQuery(); contentQuery.setCoursePackageId(query.getId()); contentQuery.setCurrent(1); contentQuery.setSize(10000); List list = listContent(contentQuery, null).getList(); // 过滤合集状态 return list.stream() .filter(content -> (content.getSerial() != null && SerialStatus.AUDITED.value.equals(content.getSerial().getStatus())) || (content.getCourse() != null && CourseStatus.AUDITED.value.equals(content.getCourse().getStatus()))) .collect(Collectors.toList()); }); } /** * APP端查询课程列表 * * @param query 查询参数 * @return 课程列表 */ public AppPager listForApp(ListCourseAppQuery query) { Integer id = query.getId(); Integer lastId = query.getLastId(); LocalDateTime lastPublishTime = query.getLastPublishTime(); Integer lastWeight = query.getLastWeight(); Integer size = query.getSize(); NavigableSet sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_COURSE_LIST + id, () -> { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .eq(CoursePackage::getAdvisorId, id) .eq(CoursePackage::getStatus, CoursePackageStatus.AUDITED.value) .eq(CoursePackage::getIsDisplay, IsDisplay.YES.value) .orderByDesc(CoursePackage::getIsRecommend, CoursePackage::getAuditTime); List list = coursePackageMapper.selectList(wrapper); NavigableSet set = new TreeSet<>(); list.stream().map(CourseSortEntity::new).forEach(set::add); return set; }); CourseSortEntity lastEntity = lastId == null || lastWeight == null || lastPublishTime == null ? null : new CourseSortEntity(lastId, lastWeight, lastPublishTime); if (lastEntity != null) { sortedSet = sortedSet.tailSet(lastEntity, false); } List voList = new ArrayList<>(size); Iterator iterator = sortedSet.iterator(); while (iterator.hasNext() && voList.size() < size) { CourseSortEntity entity = iterator.next(); CoursePackageVO vo = getForApp(new OnlyIdQuery(entity.getId()), null); if (vo != null) { voList.add(vo); } } return new AppPager<>(voList, iterator.hasNext()); } /** * 设置首页权重 * * @param query 查询参数 * @param backendUserVO 后台用户 */ public void setMainPageParam(SetMainPageQuery query, BackendUserVO backendUserVO) { // 不使用返回值,仅校验课程是否存在以及数据权限 if (getEntity(query.getId(), backendUserVO) == null) { throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); } CoursePackage coursePackage = query.toCoursePackagePO(); coursePackageMapper.updateById(coursePackage); } /** * 清除缓存 * * @param id 课程ID */ private void clearCache(Integer id) { courseCache.delete(CacheKey.CourseKey.COURSE_PACKAGE + id); courseCache.delete(CacheKey.CourseKey.COURSE_PACKAGE_CONTENT + id); } private CoursePackage getEntity(Integer id, BackendUserVO backendUserVO) { CoursePackage coursePackage = coursePackageMapper.selectById(id); if (coursePackage == null) { return null; } courseCommonService.checkAdvisorId(coursePackage.getAdvisorId(), backendUserVO); return coursePackage; } private Integer getContentCount(Integer coursePackageId) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .eq(CoursePackageContent::getCoursePackageId, coursePackageId); List list = coursePackageContentMapper.selectList(wrapper); return list.stream().mapToInt(content -> { if (CoursePackageContentType.SERIAL.value.equals(content.getType())) { return serialService.getContentCount(content.getContentId()); } else if (CoursePackageContentType.COURSE.value.equals(content.getType())) { return courseService.getContentCount(content.getContentId()); } else { return 0; } }).sum(); } private void saveContentList(Integer coursePackageId, Integer contentType, List contentListPO, UpdateContentEvent event) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() .select(CoursePackageContent::getContentId) .eq(CoursePackageContent::getCoursePackageId, coursePackageId) .eq(CoursePackageContent::getType, contentType); List existContentList = coursePackageContentMapper.selectList(wrapper); Set existContentIdSet = existContentList.stream().map(CoursePackageContent::getContentId).collect(Collectors.toSet()); if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) { // 添加新增的 List contentList = contentListPO.stream().filter(content -> !existContentIdSet.contains(content.getContentId())).collect(Collectors.toList()); if (CollUtil.isNotEmpty(contentList)) { coursePackageContentMapper.insertBatchSomeColumn(contentList); } } if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.DELETE.equals(event)) { Stream contentStream = Stream.empty(); if (UpdateContentEvent.SAVE.equals(event)) { // 删除多余的 Set contentIdSet = contentListPO.stream().map(CoursePackageContent::getContentId).collect(Collectors.toSet()); contentStream = existContentList.stream().filter(content -> !contentIdSet.contains(content.getContentId())); } else if (UpdateContentEvent.DELETE.equals(event)) { // 删除传入的 contentStream = contentListPO.stream(); } contentStream.forEach(content -> { LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() .eq(CoursePackageContent::getCoursePackageId, coursePackageId) .eq(CoursePackageContent::getContentId, content.getContentId()) .eq(CoursePackageContent::getType, contentType); coursePackageContentMapper.delete(deleteWrapper); }); } refreshUpdateTime(coursePackageId); } public void refreshUpdateTime(Integer coursePackageId) { CoursePackage coursePackage = new CoursePackage(); coursePackage.setId(coursePackageId); coursePackage.setUpdateTime(LocalDateTime.now()); coursePackageMapper.updateById(coursePackage); } }