mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-06-24 21:32:43 +08:00
增加课时观看进度记录
This commit is contained in:
parent
84bd4fdb55
commit
efb3a69498
@ -1,17 +1,18 @@
|
|||||||
package xyz.playedu.api.controller.frontend;
|
package xyz.playedu.api.controller.frontend;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import xyz.playedu.api.PlayEduFCtx;
|
import xyz.playedu.api.PlayEduFCtx;
|
||||||
import xyz.playedu.api.caches.UserCanSeeCourseCache;
|
import xyz.playedu.api.caches.UserCanSeeCourseCache;
|
||||||
import xyz.playedu.api.domain.Course;
|
import xyz.playedu.api.domain.*;
|
||||||
import xyz.playedu.api.domain.CourseHour;
|
|
||||||
import xyz.playedu.api.domain.Resource;
|
|
||||||
import xyz.playedu.api.exception.NotFoundException;
|
import xyz.playedu.api.exception.NotFoundException;
|
||||||
import xyz.playedu.api.exception.ServiceException;
|
import xyz.playedu.api.exception.ServiceException;
|
||||||
|
import xyz.playedu.api.request.frontend.CourseHourRecordRequest;
|
||||||
import xyz.playedu.api.service.CourseHourService;
|
import xyz.playedu.api.service.CourseHourService;
|
||||||
import xyz.playedu.api.service.CourseService;
|
import xyz.playedu.api.service.CourseService;
|
||||||
import xyz.playedu.api.service.ResourceService;
|
import xyz.playedu.api.service.ResourceService;
|
||||||
|
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||||
import xyz.playedu.api.types.JsonResponse;
|
import xyz.playedu.api.types.JsonResponse;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -36,6 +37,9 @@ public class HourController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ResourceService resourceService;
|
private ResourceService resourceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserCourseHourRecordService userCourseHourRecordService;
|
||||||
|
|
||||||
@GetMapping("/{id}/play")
|
@GetMapping("/{id}/play")
|
||||||
public JsonResponse play(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException {
|
public JsonResponse play(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException {
|
||||||
Course course = courseService.findOrFail(courseId);
|
Course course = courseService.findOrFail(courseId);
|
||||||
@ -52,10 +56,28 @@ public class HourController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/record")
|
@PostMapping("/{id}/record")
|
||||||
public JsonResponse record(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException {
|
public JsonResponse record(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id, @RequestBody @Validated CourseHourRecordRequest req) throws NotFoundException, ServiceException {
|
||||||
|
Integer duration = req.getDuration();
|
||||||
|
if (duration <= 0) {
|
||||||
|
return JsonResponse.error("duration参数错误");
|
||||||
|
}
|
||||||
|
User user = PlayEduFCtx.getUser();
|
||||||
|
// 线上课检测
|
||||||
|
Course course = courseService.findOrFail(courseId);
|
||||||
|
// 权限校验
|
||||||
|
userCanSeeCourseCache.check(user, course, true);
|
||||||
|
// 课时检测
|
||||||
|
CourseHour hour = hourService.findOrFail(id, courseId);
|
||||||
|
|
||||||
|
userCourseHourRecordService.storeOrUpdate(user.getId(), course.getId(), hour.getId(), duration, hour.getDuration());
|
||||||
|
|
||||||
|
return JsonResponse.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{id}/ping")
|
||||||
|
public JsonResponse ping(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException {
|
||||||
Course course = courseService.findOrFail(courseId);
|
Course course = courseService.findOrFail(courseId);
|
||||||
userCanSeeCourseCache.check(PlayEduFCtx.getUser(), course, true);
|
userCanSeeCourseCache.check(PlayEduFCtx.getUser(), course, true);
|
||||||
CourseHour hour = hourService.findOrFail(id, courseId);
|
|
||||||
return JsonResponse.success();
|
return JsonResponse.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package xyz.playedu.api.event;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author 杭州白书科技有限公司
|
||||||
|
* @create 2023/3/20 17:32
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class UserCourseHourFinishedEvent extends ApplicationEvent {
|
||||||
|
private Integer userId;
|
||||||
|
private Integer courseId;
|
||||||
|
private Integer hourId;
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
public UserCourseHourFinishedEvent(Object source, Integer userId, Integer courseId, Integer hourId) {
|
||||||
|
super(source);
|
||||||
|
this.userId = userId;
|
||||||
|
this.courseId = courseId;
|
||||||
|
this.hourId = hourId;
|
||||||
|
this.createdAt = new Date();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package xyz.playedu.api.listener;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import xyz.playedu.api.event.UserCourseHourFinishedEvent;
|
||||||
|
import xyz.playedu.api.service.CourseHourService;
|
||||||
|
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||||
|
import xyz.playedu.api.service.UserCourseRecordService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author 杭州白书科技有限公司
|
||||||
|
* @create 2023/3/20 17:41
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UserCourseHourFinishedListener {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserCourseRecordService userCourseRecordService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserCourseHourRecordService userCourseHourRecordService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CourseHourService hourService;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
@Async
|
||||||
|
public void userCourseProgressUpdate(UserCourseHourFinishedEvent evt) {
|
||||||
|
Integer hourCount = hourService.getCountByCourseId(evt.getCourseId());
|
||||||
|
Integer finishedCount = userCourseHourRecordService.getFinishedHourCount(evt.getUserId(), evt.getCourseId());
|
||||||
|
userCourseRecordService.storeOrUpdate(evt.getUserId(), evt.getCourseId(), hourCount, finishedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package xyz.playedu.api.request.frontend;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author 杭州白书科技有限公司
|
||||||
|
* @create 2023/3/20 17:12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CourseHourRecordRequest {
|
||||||
|
@NotNull(message = "duration参数不存在")
|
||||||
|
private Integer duration;
|
||||||
|
}
|
@ -9,5 +9,9 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
* @createDate 2023-03-20 16:41:08
|
* @createDate 2023-03-20 16:41:08
|
||||||
*/
|
*/
|
||||||
public interface UserCourseHourRecordService extends IService<UserCourseHourRecord> {
|
public interface UserCourseHourRecordService extends IService<UserCourseHourRecord> {
|
||||||
|
UserCourseHourRecord find(Integer userId, Integer courseId, Integer hourId);
|
||||||
|
|
||||||
|
UserCourseHourRecord storeOrUpdate(Integer userId, Integer courseId, Integer hourId, Integer duration, Integer totalDuration);
|
||||||
|
|
||||||
|
Integer getFinishedHourCount(Integer userId, Integer courseId);
|
||||||
}
|
}
|
||||||
|
@ -10,4 +10,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
*/
|
*/
|
||||||
public interface UserCourseRecordService extends IService<UserCourseRecord> {
|
public interface UserCourseRecordService extends IService<UserCourseRecord> {
|
||||||
|
|
||||||
|
UserCourseRecord find(Integer userId, Integer courseId);
|
||||||
|
|
||||||
|
void storeOrUpdate(Integer userId, Integer courseId, Integer hourCount, Integer finishedCount);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,86 @@
|
|||||||
package xyz.playedu.api.service.impl;
|
package xyz.playedu.api.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import xyz.playedu.api.domain.UserCourseHourRecord;
|
import xyz.playedu.api.domain.UserCourseHourRecord;
|
||||||
|
import xyz.playedu.api.event.UserCourseHourFinishedEvent;
|
||||||
import xyz.playedu.api.service.UserCourseHourRecordService;
|
import xyz.playedu.api.service.UserCourseHourRecordService;
|
||||||
import xyz.playedu.api.mapper.UserCourseHourRecordMapper;
|
import xyz.playedu.api.mapper.UserCourseHourRecordMapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tengteng
|
* @author tengteng
|
||||||
* @description 针对表【user_course_hour_records】的数据库操作Service实现
|
* @description 针对表【user_course_hour_records】的数据库操作Service实现
|
||||||
* @createDate 2023-03-20 16:41:08
|
* @createDate 2023-03-20 16:41:08
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class UserCourseHourRecordServiceImpl extends ServiceImpl<UserCourseHourRecordMapper, UserCourseHourRecord>
|
public class UserCourseHourRecordServiceImpl extends ServiceImpl<UserCourseHourRecordMapper, UserCourseHourRecord> implements UserCourseHourRecordService {
|
||||||
implements UserCourseHourRecordService{
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext ctx;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserCourseHourRecord find(Integer userId, Integer courseId, Integer hourId) {
|
||||||
|
return getOne(query().getWrapper().eq("user_id", userId).eq("course_id", courseId).eq("hour_id", hourId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserCourseHourRecord storeOrUpdate(Integer userId, Integer courseId, Integer hourId, Integer duration, Integer totalDuration) {
|
||||||
|
UserCourseHourRecord record = find(userId, courseId, hourId);
|
||||||
|
|
||||||
|
// 已看完
|
||||||
|
if (record != null && record.getIsFinished() == 1) {
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否看完
|
||||||
|
boolean isFinished = duration >= totalDuration;
|
||||||
|
Date finishedAt = isFinished ? new Date() : null;
|
||||||
|
|
||||||
|
if (record == null) {
|
||||||
|
UserCourseHourRecord insertRecord = new UserCourseHourRecord();
|
||||||
|
insertRecord.setUserId(userId);
|
||||||
|
insertRecord.setCourseId(courseId);
|
||||||
|
insertRecord.setHourId(hourId);
|
||||||
|
insertRecord.setTotalDuration(totalDuration);
|
||||||
|
insertRecord.setFinishedDuration(duration);
|
||||||
|
insertRecord.setIsFinished(isFinished ? 1 : 0);
|
||||||
|
insertRecord.setFinishedAt(finishedAt);
|
||||||
|
insertRecord.setCreatedAt(new Date());
|
||||||
|
insertRecord.setUpdatedAt(new Date());
|
||||||
|
|
||||||
|
save(insertRecord);
|
||||||
|
|
||||||
|
record = insertRecord;
|
||||||
|
} else {
|
||||||
|
// 未看完 && 大于存在的观看记录时长
|
||||||
|
if (record.getFinishedDuration() < duration) {
|
||||||
|
UserCourseHourRecord updateRecord = new UserCourseHourRecord();
|
||||||
|
updateRecord.setId(record.getId());
|
||||||
|
updateRecord.setTotalDuration(totalDuration);
|
||||||
|
updateRecord.setFinishedDuration(duration);
|
||||||
|
updateRecord.setIsFinished(isFinished ? 1 : 0);
|
||||||
|
updateRecord.setFinishedAt(finishedAt);
|
||||||
|
|
||||||
|
updateById(updateRecord);
|
||||||
|
record = updateRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinished) {
|
||||||
|
ctx.publishEvent(new UserCourseHourFinishedEvent(this, record.getUserId(), record.getCourseId(), record.getHourId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getFinishedHourCount(Integer userId, Integer courseId) {
|
||||||
|
return Math.toIntExact(count(query().getWrapper().eq("user_id", userId).eq("course_id", courseId).eq("is_finished", 1)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import xyz.playedu.api.service.UserCourseRecordService;
|
|||||||
import xyz.playedu.api.mapper.UserCourseRecordMapper;
|
import xyz.playedu.api.mapper.UserCourseRecordMapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tengteng
|
* @author tengteng
|
||||||
* @description 针对表【user_course_records】的数据库操作Service实现
|
* @description 针对表【user_course_records】的数据库操作Service实现
|
||||||
@ -15,6 +17,53 @@ import org.springframework.stereotype.Service;
|
|||||||
public class UserCourseRecordServiceImpl extends ServiceImpl<UserCourseRecordMapper, UserCourseRecord>
|
public class UserCourseRecordServiceImpl extends ServiceImpl<UserCourseRecordMapper, UserCourseRecord>
|
||||||
implements UserCourseRecordService {
|
implements UserCourseRecordService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserCourseRecord find(Integer userId, Integer courseId) {
|
||||||
|
return getOne(query().getWrapper().eq("user_id", userId).eq("course_id", courseId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeOrUpdate(Integer userId, Integer courseId, Integer hourCount, Integer finishedCount) {
|
||||||
|
if (hourCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserCourseRecord record = find(userId, courseId);
|
||||||
|
|
||||||
|
// 已看完
|
||||||
|
if (record != null && record.getIsFinished() == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFinished = finishedCount >= hourCount;
|
||||||
|
Date finishedAt = isFinished ? new Date() : null;
|
||||||
|
Integer progress = finishedCount * 100 / hourCount * 100;
|
||||||
|
|
||||||
|
if (record == null) {
|
||||||
|
UserCourseRecord insertRecord = new UserCourseRecord();
|
||||||
|
insertRecord.setUserId(userId);
|
||||||
|
insertRecord.setCourseId(courseId);
|
||||||
|
insertRecord.setHourCount(hourCount);
|
||||||
|
insertRecord.setFinishedCount(finishedCount);
|
||||||
|
insertRecord.setFinishedAt(finishedAt);
|
||||||
|
insertRecord.setIsFinished(isFinished ? 1 : 0);
|
||||||
|
insertRecord.setProgress(progress);
|
||||||
|
insertRecord.setCreatedAt(new Date());
|
||||||
|
insertRecord.setUpdatedAt(new Date());
|
||||||
|
|
||||||
|
save(insertRecord);
|
||||||
|
} else {
|
||||||
|
UserCourseRecord updateRecord = new UserCourseRecord();
|
||||||
|
updateRecord.setId(record.getId());
|
||||||
|
updateRecord.setHourCount(hourCount);
|
||||||
|
updateRecord.setFinishedCount(finishedCount);
|
||||||
|
updateRecord.setFinishedAt(finishedAt);
|
||||||
|
updateRecord.setIsFinished(isFinished ? 1 : 0);
|
||||||
|
updateRecord.setProgress(progress);
|
||||||
|
|
||||||
|
updateById(updateRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user