diff --git a/pom.xml b/pom.xml
index 2f1ddc2..a4bd74b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
xyz.playedu
playedu-api
- 0.1-beta.1
+ 1.0-beta.4
playedu-api
playedu-api
diff --git a/src/main/java/xyz/playedu/api/bus/UserBus.java b/src/main/java/xyz/playedu/api/bus/UserBus.java
index 8620c93..5df2956 100644
--- a/src/main/java/xyz/playedu/api/bus/UserBus.java
+++ b/src/main/java/xyz/playedu/api/bus/UserBus.java
@@ -60,6 +60,7 @@ public class UserBus {
return CollectionUtils.intersection(courseDepIds, userDepIds).size() > 0;
}
+ // 注意,调用该方法需要考虑到并发写入问题
public void userLearnDurationRecord(User user, Course course, CourseHour hour) {
Long curTime = System.currentTimeMillis();
diff --git a/src/main/java/xyz/playedu/api/checks/AdminPermissionCheck.java b/src/main/java/xyz/playedu/api/checks/AdminPermissionCheck.java
index 95d8951..ae5fcda 100644
--- a/src/main/java/xyz/playedu/api/checks/AdminPermissionCheck.java
+++ b/src/main/java/xyz/playedu/api/checks/AdminPermissionCheck.java
@@ -162,6 +162,15 @@ public class AdminPermissionCheck implements ApplicationRunner {
setSlug(BPermissionConstant.USER_LEARN);
}
},
+ new AdminPermission() {
+ {
+ setSort(50);
+ setName("学习-删除");
+ setSlug(
+ BPermissionConstant
+ .USER_LEARN_DESTROY);
+ }
+ },
});
// 线上课
put(
diff --git a/src/main/java/xyz/playedu/api/constant/BPermissionConstant.java b/src/main/java/xyz/playedu/api/constant/BPermissionConstant.java
index 332aed1..f49bc6d 100644
--- a/src/main/java/xyz/playedu/api/constant/BPermissionConstant.java
+++ b/src/main/java/xyz/playedu/api/constant/BPermissionConstant.java
@@ -42,6 +42,7 @@ public class BPermissionConstant {
public static final String USER_UPDATE = "user-update";
public static final String USER_DESTROY = "user-destroy";
public static final String USER_LEARN = "user-learn";
+ public static final String USER_LEARN_DESTROY = "user-learn-destroy";
public static final String COURSE = "course";
public static final String COURSE_USER = "course-user";
diff --git a/src/main/java/xyz/playedu/api/controller/backend/DepartmentController.java b/src/main/java/xyz/playedu/api/controller/backend/DepartmentController.java
index c66a3ab..16c7b2b 100644
--- a/src/main/java/xyz/playedu/api/controller/backend/DepartmentController.java
+++ b/src/main/java/xyz/playedu/api/controller/backend/DepartmentController.java
@@ -190,6 +190,9 @@ public class DepartmentController {
String idCard = MapUtils.getString(params, "id_card");
String depIds = String.valueOf(id);
+ String courseIdsStr = MapUtils.getString(params, "course_ids");
+ String showMode = MapUtils.getString(params, "show_mode");
+
UserPaginateFilter filter =
new UserPaginateFilter() {
{
@@ -204,21 +207,48 @@ public class DepartmentController {
PaginationResult users = userService.paginate(page, size, filter);
- // 部门关联线上课
- List courses =
- courseService.getDepCoursesAndShow(
- new ArrayList<>() {
- {
- add(id);
- }
- });
+ List courses;
+ if (courseIdsStr != null && courseIdsStr.trim().length() > 0) {
+ // 指定了需要显示的线上课
+ courses =
+ courseService.chunks(
+ Arrays.stream(courseIdsStr.split(",")).map(Integer::valueOf).toList());
+ } else {
+ if ("only_open".equals(showMode)) {
+ // 公开(无关联部门)线上课
+ courses = courseService.getOpenCoursesAndShow(10000);
+ } else if ("only_dep".equals(showMode)) {
+ // 部门关联线上课
+ courses =
+ courseService.getDepCoursesAndShow(
+ new ArrayList<>() {
+ {
+ add(id);
+ }
+ });
+ } else {
+ // 部门关联线上课
+ courses =
+ courseService.getDepCoursesAndShow(
+ new ArrayList<>() {
+ {
+ add(id);
+ }
+ });
+ List openCourses = courseService.getOpenCoursesAndShow(10000);
+ ;
+ if (openCourses != null) {
+ courses.addAll(openCourses);
+ }
+ }
+ }
+
+ List courseIds = courses.stream().map(Course::getId).toList();
// 学员的课程学习进度
Map> userCourseRecords =
userCourseRecordService
- .chunk(
- users.getData().stream().map(User::getId).toList(),
- courses.stream().map(Course::getId).toList())
+ .chunk(users.getData().stream().map(User::getId).toList(), courseIds)
.stream()
.collect(Collectors.groupingBy(UserCourseRecord::getUserId));
Map> userCourseRecordsMap = new HashMap<>();
diff --git a/src/main/java/xyz/playedu/api/controller/backend/UserController.java b/src/main/java/xyz/playedu/api/controller/backend/UserController.java
index a67ae9f..6ad3556 100644
--- a/src/main/java/xyz/playedu/api/controller/backend/UserController.java
+++ b/src/main/java/xyz/playedu/api/controller/backend/UserController.java
@@ -33,6 +33,8 @@ import xyz.playedu.api.constant.BPermissionConstant;
import xyz.playedu.api.constant.CConfig;
import xyz.playedu.api.constant.SystemConstant;
import xyz.playedu.api.domain.*;
+import xyz.playedu.api.event.UserCourseHourRecordDestroyEvent;
+import xyz.playedu.api.event.UserCourseRecordDestroyEvent;
import xyz.playedu.api.event.UserDestroyEvent;
import xyz.playedu.api.exception.NotFoundException;
import xyz.playedu.api.middleware.BackendPermissionMiddleware;
@@ -78,6 +80,8 @@ public class UserController {
@Autowired private UserLearnDurationStatsService userLearnDurationStatsService;
+ @Autowired private ApplicationContext ctx;
+
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_INDEX)
@GetMapping("/index")
public JsonResponse index(@RequestParam HashMap params) {
@@ -370,7 +374,7 @@ public class UserController {
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
@GetMapping("/{id}/learn-hours")
@SneakyThrows
- public JsonResponse latestLearnHours(
+ public JsonResponse learnHours(
@PathVariable(name = "id") Integer id, @RequestParam HashMap params) {
Integer page = MapUtils.getInteger(params, "page", 1);
Integer size = MapUtils.getInteger(params, "size", 10);
@@ -438,6 +442,79 @@ public class UserController {
return JsonResponse.data(data);
}
+ @BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
+ @GetMapping("/{id}/all-courses")
+ public JsonResponse allCourses(@PathVariable(name = "id") Integer id) {
+ // 读取学员关联的部门
+ List depIds = userService.getDepIdsByUserId(id);
+ List departments = new ArrayList<>();
+ HashMap> depCourses = new HashMap<>();
+ List courseIds = new ArrayList<>();
+
+ if (depIds != null && depIds.size() > 0) {
+ departments = departmentService.chunk(depIds);
+ depIds.forEach(
+ (depId) -> {
+ List tmpCourses =
+ courseService.getDepCoursesAndShow(
+ new ArrayList<>() {
+ {
+ add(depId);
+ }
+ });
+ depCourses.put(depId, tmpCourses);
+
+ if (tmpCourses != null && tmpCourses.size() > 0) {
+ courseIds.addAll(tmpCourses.stream().map(Course::getId).toList());
+ }
+ });
+ }
+
+ // 未关联部门课程
+ List openCourses = courseService.getOpenCoursesAndShow(1000);
+ if (openCourses != null && openCourses.size() > 0) {
+ courseIds.addAll(openCourses.stream().map(Course::getId).toList());
+ }
+
+ // 读取学员的线上课学习记录
+ List userCourseRecords = new ArrayList<>();
+ if (courseIds.size() > 0) {
+ userCourseRecords = userCourseRecordService.chunk(id, courseIds);
+ }
+
+ HashMap data = new HashMap<>();
+ data.put("open_courses", openCourses);
+ data.put("departments", departments);
+ data.put("dep_courses", depCourses);
+ data.put(
+ "user_course_records",
+ userCourseRecords.stream()
+ .collect(Collectors.toMap(UserCourseRecord::getCourseId, e -> e)));
+
+ return JsonResponse.data(data);
+ }
+
+ @BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
+ @GetMapping("/{id}/learn-course/{courseId}")
+ @SneakyThrows
+ public JsonResponse learnCourseDetail(
+ @PathVariable(name = "id") Integer id,
+ @PathVariable(name = "courseId") Integer courseId) {
+ // 读取线上课下的所有课时
+ List hours = courseHourService.getHoursByCourseId(courseId);
+ // 读取学员的课时学习记录
+ List records = userCourseHourRecordService.getRecords(id, courseId);
+
+ HashMap data = new HashMap<>();
+ data.put("hours", hours);
+ data.put(
+ "learn_records",
+ records.stream()
+ .collect(Collectors.toMap(UserCourseHourRecord::getHourId, e -> e)));
+
+ return JsonResponse.data(data);
+ }
+
@BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN)
@GetMapping("/{id}/learn-stats")
@SneakyThrows
@@ -484,4 +561,27 @@ public class UserController {
return JsonResponse.data(data);
}
+
+ @BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN_DESTROY)
+ @DeleteMapping("/{id}/learn-course/{courseId}")
+ @SneakyThrows
+ public JsonResponse destroyUserCourse(
+ @PathVariable(name = "id") Integer id,
+ @PathVariable(name = "courseId") Integer courseId) {
+ userCourseRecordService.destroy(id, courseId);
+ ctx.publishEvent(new UserCourseRecordDestroyEvent(this, id, courseId));
+ return JsonResponse.success();
+ }
+
+ @BackendPermissionMiddleware(slug = BPermissionConstant.USER_LEARN_DESTROY)
+ @DeleteMapping("/{id}/learn-course/{courseId}/hour/{hourId}")
+ @SneakyThrows
+ public JsonResponse destroyUserHour(
+ @PathVariable(name = "id") Integer id,
+ @PathVariable(name = "courseId") Integer courseId,
+ @PathVariable(name = "hourId") Integer hourId) {
+ userCourseHourRecordService.remove(id, courseId, hourId);
+ ctx.publishEvent(new UserCourseHourRecordDestroyEvent(this, id, courseId, hourId));
+ return JsonResponse.success();
+ }
}
diff --git a/src/main/java/xyz/playedu/api/controller/frontend/HourController.java b/src/main/java/xyz/playedu/api/controller/frontend/HourController.java
index f7b9b52..d46b770 100644
--- a/src/main/java/xyz/playedu/api/controller/frontend/HourController.java
+++ b/src/main/java/xyz/playedu/api/controller/frontend/HourController.java
@@ -28,11 +28,14 @@ import xyz.playedu.api.caches.UserCanSeeCourseCache;
import xyz.playedu.api.domain.*;
import xyz.playedu.api.request.frontend.CourseHourRecordRequest;
import xyz.playedu.api.service.CourseHourService;
+import xyz.playedu.api.service.CourseService;
import xyz.playedu.api.service.ResourceService;
import xyz.playedu.api.service.UserCourseHourRecordService;
import xyz.playedu.api.types.JsonResponse;
+import xyz.playedu.api.util.RedisDistributedLock;
import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
/**
* @Author 杭州白书科技有限公司
@@ -43,6 +46,8 @@ import java.util.HashMap;
@RequestMapping("/api/v1/course/{courseId}/hour")
public class HourController {
+ @Autowired private CourseService courseService;
+
@Autowired private CourseHourService hourService;
@Autowired private ResourceService resourceService;
@@ -55,6 +60,30 @@ public class HourController {
@Autowired private UserCanSeeCourseCache userCanSeeCourseCache;
@Autowired private CourseCache courseCache;
+ @Autowired private RedisDistributedLock redisDistributedLock;
+
+ @GetMapping("/{id}")
+ @SneakyThrows
+ public JsonResponse detail(
+ @PathVariable(name = "courseId") Integer courseId,
+ @PathVariable(name = "id") Integer id) {
+ Course course = courseService.findOrFail(courseId);
+ CourseHour courseHour = hourService.findOrFail(id, courseId);
+
+ UserCourseHourRecord userCourseHourRecord = null;
+ if (FCtx.getId() != null && FCtx.getId() > 0) {
+ // 学员已登录
+ userCourseHourRecord = userCourseHourRecordService.find(FCtx.getId(), courseId, id);
+ }
+
+ HashMap data = new HashMap<>();
+ data.put("course", course);
+ data.put("hour", courseHour);
+ data.put("user_hour_record", userCourseHourRecord);
+
+ return JsonResponse.data(data);
+ }
+
@GetMapping("/{id}/play")
@SneakyThrows
public JsonResponse play(
@@ -83,13 +112,23 @@ public class HourController {
if (duration <= 0) {
return JsonResponse.error("duration参数错误");
}
- User user = FCtx.getUser();
+
Course course = courseCache.findOrFail(courseId);
- userCanSeeCourseCache.check(user, course, true);
CourseHour hour = hourService.findOrFail(id, courseId);
+ userCanSeeCourseCache.check(FCtx.getUser(), course, true);
+
+ // 获取锁
+ String lockKey = String.format("record:%d", FCtx.getId());
+ boolean tryLock = redisDistributedLock.tryLock(lockKey, 5, TimeUnit.SECONDS);
+ if (!tryLock) {
+ return JsonResponse.error("请稍后再试");
+ }
userCourseHourRecordService.storeOrUpdate(
- user.getId(), course.getId(), hour.getId(), duration, hour.getDuration());
+ FCtx.getId(), course.getId(), hour.getId(), duration, hour.getDuration());
+
+ // 此处未考虑上面代码执行失败释放锁
+ redisDistributedLock.releaseLock(lockKey);
return JsonResponse.success();
}
@@ -102,7 +141,19 @@ public class HourController {
Course course = courseCache.findOrFail(courseId);
CourseHour hour = hourService.findOrFail(id, courseId);
userCanSeeCourseCache.check(FCtx.getUser(), course, true);
+
+ // 获取锁
+ String lockKey = String.format("ping:%d", FCtx.getId());
+ boolean tryLock = redisDistributedLock.tryLock(lockKey, 5, TimeUnit.SECONDS);
+ if (!tryLock) {
+ return JsonResponse.error("请稍后再试");
+ }
+
userBus.userLearnDurationRecord(FCtx.getUser(), course, hour);
+
+ // 此处未考虑上面代码执行失败释放锁
+ redisDistributedLock.releaseLock(lockKey);
+
return JsonResponse.success();
}
}
diff --git a/src/main/java/xyz/playedu/api/event/UserCourseHourRecordDestroyEvent.java b/src/main/java/xyz/playedu/api/event/UserCourseHourRecordDestroyEvent.java
new file mode 100644
index 0000000..29df33b
--- /dev/null
+++ b/src/main/java/xyz/playedu/api/event/UserCourseHourRecordDestroyEvent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 杭州白书科技有限公司
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package xyz.playedu.api.event;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import org.springframework.context.ApplicationEvent;
+
+import java.util.Date;
+
+/**
+ * @Author 杭州白书科技有限公司
+ *
+ * @create 2023/4/23 14:48
+ */
+@Getter
+@Setter
+public class UserCourseHourRecordDestroyEvent extends ApplicationEvent {
+
+ private Integer userId;
+ private Integer courseId;
+ private Integer hourId;
+ private Date at;
+
+ public UserCourseHourRecordDestroyEvent(
+ Object source, Integer userId, Integer courseId, Integer hourId) {
+ super(source);
+ this.userId = userId;
+ this.courseId = courseId;
+ this.hourId = hourId;
+ this.at = new Date();
+ }
+}
diff --git a/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java b/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java
index a1e1daf..7805098 100644
--- a/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java
+++ b/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java
@@ -15,11 +15,8 @@
*/
package xyz.playedu.api.listener;
-import lombok.extern.slf4j.Slf4j;
-
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;
@@ -33,7 +30,6 @@ import xyz.playedu.api.service.UserCourseRecordService;
* @create 2023/3/20 17:41
*/
@Component
-@Slf4j
public class UserCourseHourFinishedListener {
@Autowired private UserCourseRecordService userCourseRecordService;
@@ -42,20 +38,12 @@ public class UserCourseHourFinishedListener {
@Autowired private CourseHourService hourService;
- @Async
@EventListener
public void userCourseProgressUpdate(UserCourseHourFinishedEvent evt) {
Integer hourCount = hourService.getCountByCourseId(evt.getCourseId());
Integer finishedCount =
userCourseHourRecordService.getFinishedHourCount(
evt.getUserId(), evt.getCourseId());
- log.info(
- "UserCourseHourFinishedListener courseId={} userId={} hourCount={}"
- + " finishedCount={}",
- evt.getCourseId(),
- evt.getUserId(),
- hourCount,
- finishedCount);
userCourseRecordService.storeOrUpdate(
evt.getUserId(), evt.getCourseId(), hourCount, finishedCount);
}
diff --git a/src/main/java/xyz/playedu/api/listener/UserCourseHourRecordDestroyListener.java b/src/main/java/xyz/playedu/api/listener/UserCourseHourRecordDestroyListener.java
new file mode 100644
index 0000000..f3ce656
--- /dev/null
+++ b/src/main/java/xyz/playedu/api/listener/UserCourseHourRecordDestroyListener.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 杭州白书科技有限公司
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package xyz.playedu.api.listener;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import xyz.playedu.api.event.UserCourseHourRecordDestroyEvent;
+import xyz.playedu.api.service.UserCourseRecordService;
+
+/**
+ * @Author 杭州白书科技有限公司
+ *
+ * @create 2023/4/23 14:51
+ */
+@Component
+@Slf4j
+public class UserCourseHourRecordDestroyListener {
+
+ @Autowired private UserCourseRecordService userCourseRecordService;
+
+ @EventListener
+ public void updateUserCourseRecord(UserCourseHourRecordDestroyEvent e) {
+ userCourseRecordService.decrease(e.getUserId(), e.getCourseId(), 1);
+ }
+}
diff --git a/src/main/java/xyz/playedu/api/listener/UserLearnCourseUpdateListener.java b/src/main/java/xyz/playedu/api/listener/UserLearnCourseUpdateListener.java
index e94ed0f..6e379df 100644
--- a/src/main/java/xyz/playedu/api/listener/UserLearnCourseUpdateListener.java
+++ b/src/main/java/xyz/playedu/api/listener/UserLearnCourseUpdateListener.java
@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
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.UserLearnCourseUpdateEvent;
@@ -39,7 +38,6 @@ public class UserLearnCourseUpdateListener {
@Autowired private UserLearnDurationStatsService userLearnDurationStatsService;
- @Async
@EventListener
public void storeLearnDuration(UserLearnCourseUpdateEvent event) {
// 观看时长统计
diff --git a/src/main/java/xyz/playedu/api/service/DepartmentService.java b/src/main/java/xyz/playedu/api/service/DepartmentService.java
index be0b71d..d6ce589 100644
--- a/src/main/java/xyz/playedu/api/service/DepartmentService.java
+++ b/src/main/java/xyz/playedu/api/service/DepartmentService.java
@@ -64,4 +64,6 @@ public interface DepartmentService extends IService {
Long total();
Map getDepartmentsUserCount();
+
+ List chunk(List ids);
}
diff --git a/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java b/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java
index 91e59c9..1a61e59 100644
--- a/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java
+++ b/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java
@@ -49,6 +49,8 @@ public interface UserCourseHourRecordService extends IService getUserCourseHourCount(
Integer userId, List courseIds, Integer isFinished);
diff --git a/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java b/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java
index 83603fd..ed2e702 100644
--- a/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java
+++ b/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java
@@ -43,7 +43,11 @@ public interface UserCourseRecordService extends IService {
void destroy(Integer courseId, List ids);
+ void destroy(Integer userId, Integer courseId);
+
void removeByCourseId(Integer courseId);
List chunks(List ids, List fields);
+
+ void decrease(Integer userId, Integer courseId, int count);
}
diff --git a/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java
index 38faa5c..23225fc 100644
--- a/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java
+++ b/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java
@@ -214,6 +214,9 @@ public class CourseServiceImpl extends ServiceImpl impleme
@Override
public List getDepCoursesAndShow(List depIds) {
+ if (depIds == null || depIds.size() == 0) {
+ return new ArrayList<>();
+ }
List courseIds = courseDepartmentService.getCourseIdsByDepIds(depIds);
if (courseIds == null || courseIds.size() == 0) {
return new ArrayList<>();
diff --git a/src/main/java/xyz/playedu/api/service/impl/DepartmentServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/DepartmentServiceImpl.java
index ff74f3e..8b62a39 100644
--- a/src/main/java/xyz/playedu/api/service/impl/DepartmentServiceImpl.java
+++ b/src/main/java/xyz/playedu/api/service/impl/DepartmentServiceImpl.java
@@ -268,4 +268,12 @@ public class DepartmentServiceImpl extends ServiceImpl chunk(List ids) {
+ if (ids == null || ids.size() == 0) {
+ return new ArrayList<>();
+ }
+ return list(query().getWrapper().in("id", ids));
+ }
}
diff --git a/src/main/java/xyz/playedu/api/service/impl/ImageCaptchaServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/ImageCaptchaServiceImpl.java
index 7dfe8d6..662b6de 100644
--- a/src/main/java/xyz/playedu/api/service/impl/ImageCaptchaServiceImpl.java
+++ b/src/main/java/xyz/playedu/api/service/impl/ImageCaptchaServiceImpl.java
@@ -81,7 +81,7 @@ public class ImageCaptchaServiceImpl implements ImageCaptchaService {
return false;
}
String cacheValue = (String) queryResult;
- boolean verifyResult = cacheValue.equals(code);
+ boolean verifyResult = cacheValue.equalsIgnoreCase(code);
if (verifyResult) { // 验证成功删除缓存->防止多次使用
RedisUtil.del(cacheKey);
diff --git a/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java
index 1d8c46a..1743325 100644
--- a/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java
+++ b/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java
@@ -153,4 +153,13 @@ public class UserCourseHourRecordServiceImpl
return pageResult;
}
+
+ @Override
+ public void remove(Integer userId, Integer courseId, Integer hourId) {
+ remove(
+ query().getWrapper()
+ .eq("user_id", userId)
+ .eq("course_id", courseId)
+ .eq("hour_id", hourId));
+ }
}
diff --git a/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java
index 8047885..5c892b1 100644
--- a/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java
+++ b/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java
@@ -60,7 +60,7 @@ public class UserCourseRecordServiceImpl
boolean isFinished = finishedCount >= hourCount;
Date finishedAt = isFinished ? new Date() : null;
- Integer progress = finishedCount * 100 / hourCount * 100;
+ Integer progress = finishedCount * 10000 / hourCount;
if (record == null) {
UserCourseRecord insertRecord = new UserCourseRecord();
@@ -132,4 +132,28 @@ public class UserCourseRecordServiceImpl
public List chunks(List ids, List fields) {
return list(query().getWrapper().in("id", ids).select(fields));
}
+
+ @Override
+ public void destroy(Integer userId, Integer courseId) {
+ remove(query().getWrapper().in("user_id", userId).eq("course_id", courseId));
+ }
+
+ @Override
+ public void decrease(Integer userId, Integer courseId, int count) {
+ UserCourseRecord record = find(userId, courseId);
+ if (record == null) {
+ return;
+ }
+
+ int finishedCount = record.getFinishedCount() - count;
+
+ UserCourseRecord newRecord = new UserCourseRecord();
+ newRecord.setId(record.getId());
+ newRecord.setFinishedCount(finishedCount);
+ newRecord.setFinishedAt(null);
+ newRecord.setProgress(finishedCount * 10000 / record.getHourCount());
+ newRecord.setIsFinished(0);
+
+ updateById(newRecord);
+ }
}
diff --git a/src/main/java/xyz/playedu/api/service/impl/UserLearnDurationStatsServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/UserLearnDurationStatsServiceImpl.java
index c737d74..8b0b716 100644
--- a/src/main/java/xyz/playedu/api/service/impl/UserLearnDurationStatsServiceImpl.java
+++ b/src/main/java/xyz/playedu/api/service/impl/UserLearnDurationStatsServiceImpl.java
@@ -15,6 +15,8 @@
*/
package xyz.playedu.api.service.impl;
+import cn.hutool.core.date.DateTime;
+
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.SneakyThrows;
@@ -42,10 +44,7 @@ public class UserLearnDurationStatsServiceImpl
@Override
@SneakyThrows
public void storeOrUpdate(Integer userId, Long startTime, Long endTime) {
- // 处理日期
- SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
- String date = simpleDateFormat.format(new Date(endTime));
- // duration
+ String date = new DateTime().toDateStr();
Long duration = endTime - startTime;
UserLearnDurationStats stats =
@@ -54,7 +53,7 @@ public class UserLearnDurationStatsServiceImpl
UserLearnDurationStats newStats = new UserLearnDurationStats();
newStats.setUserId(userId);
newStats.setDuration(duration);
- newStats.setCreatedDate(simpleDateFormat.parse(date));
+ newStats.setCreatedDate(new DateTime(date));
save(newStats);
return;
}