AdvisorServer/src/main/java/com/syzb/course/service/CoursePackageService.java
2025-02-21 20:05:47 +08:00

489 lines
22 KiB
Java

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<CoursePackageStatus> 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<String, Object> 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<CoursePackageVO> 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<Integer> authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true);
if (authSet != null && authSet.isEmpty()) {
return null;
}
LambdaQueryWrapper<CoursePackage> wrapper = Wrappers.<CoursePackage>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<CoursePackage> page = coursePackageMapper.selectPage(query.toPage(), wrapper);
Map<Integer, String> advisorNameMap = advisorInfoService.getAdvisorMap().values().stream()
.collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName));
Map<Integer, String> userNameMap = userService.getUserMap().values().stream()
.collect(Collectors.toMap(UserDept::getUserId, UserDept::getName));
List<CoursePackageVO> 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<Integer, String> advisorNameMap = advisorInfoService.getAdvisorMap().values().stream()
.collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName));
Map<Integer, String> 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<CoursePackageContentVO> listContent(ListCoursePackageContentQuery query, BackendUserVO backendUserVO) {
// 不使用返回值,仅校验课程是否存在以及数据权限
if (getEntity(query.getCoursePackageId(), backendUserVO) == null) {
throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR);
}
Integer type = query.getType();
LambdaQueryWrapper<CoursePackageContent> wrapper = Wrappers.<CoursePackageContent>lambdaQuery()
.eq(CoursePackageContent::getCoursePackageId, query.getCoursePackageId())
.eq(type != null && type != 0, CoursePackageContent::getType, type)
.orderByDesc(CoursePackageContent::getIsRecommend, CoursePackageContent::getCreateTime);
Page<CoursePackageContent> page = coursePackageContentMapper.selectPage(query.toPage(), wrapper);
List<CoursePackageContentVO> 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<CoursePackageContent> wrapper = Wrappers.<CoursePackageContent>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<CoursePackageContentVO> 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<CoursePackageContentVO> 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<CoursePackageVO> listForApp(ListCourseAppQuery query) {
Integer id = query.getId();
Integer lastId = query.getLastId();
LocalDateTime lastPublishTime = query.getLastPublishTime();
Integer lastWeight = query.getLastWeight();
Integer size = query.getSize();
NavigableSet<CourseSortEntity> sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_COURSE_LIST + id, () -> {
LambdaQueryWrapper<CoursePackage> wrapper = Wrappers.<CoursePackage>lambdaQuery()
.eq(CoursePackage::getAdvisorId, id)
.eq(CoursePackage::getStatus, CoursePackageStatus.AUDITED.value)
.eq(CoursePackage::getIsDisplay, IsDisplay.YES.value)
.orderByDesc(CoursePackage::getIsRecommend, CoursePackage::getAuditTime);
List<CoursePackage> list = coursePackageMapper.selectList(wrapper);
NavigableSet<CourseSortEntity> 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<CoursePackageVO> voList = new ArrayList<>(size);
Iterator<CourseSortEntity> 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<CoursePackageContent> wrapper = Wrappers.<CoursePackageContent>lambdaQuery()
.eq(CoursePackageContent::getCoursePackageId, coursePackageId);
List<CoursePackageContent> 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<CoursePackageContent> contentListPO, UpdateContentEvent event) {
LambdaQueryWrapper<CoursePackageContent> wrapper = Wrappers.<CoursePackageContent>lambdaQuery()
.select(CoursePackageContent::getContentId)
.eq(CoursePackageContent::getCoursePackageId, coursePackageId)
.eq(CoursePackageContent::getType, contentType);
List<CoursePackageContent> existContentList = coursePackageContentMapper.selectList(wrapper);
Set<Integer> existContentIdSet = existContentList.stream().map(CoursePackageContent::getContentId).collect(Collectors.toSet());
if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) {
// 添加新增的
List<CoursePackageContent> 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<CoursePackageContent> contentStream = Stream.empty();
if (UpdateContentEvent.SAVE.equals(event)) {
// 删除多余的
Set<Integer> 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<CoursePackageContent> deleteWrapper = Wrappers.<CoursePackageContent>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);
}
}